X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-pq;a=blobdiff_plain;f=src%2Fphp_pq_params.c;h=0cc370d36a6654db5261d6edc8602a0deec6eec8;hp=149da750ede70bf98224196e8b7564e8b54690ed;hb=da7b5981c5ae28504434c492d468913645111d66;hpb=359b3471d6ed843d8ecf9d5fb0b85f06af446800 diff --git a/src/php_pq_params.c b/src/php_pq_params.c index 149da75..0cc370d 100644 --- a/src/php_pq_params.c +++ b/src/php_pq_params.c @@ -17,6 +17,9 @@ #include #include #include +#if PHP_PQ_HAVE_PHP_JSON_H +#include /* we've added the include directory to INCLUDES */ +#endif #include @@ -24,6 +27,7 @@ #include "php_pq.h" #include "php_pq_params.h" +#include "php_pq_misc.h" #undef PHP_PQ_TYPE #include "php_pq_type.h" @@ -77,151 +81,265 @@ unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type) return p->type.count; } -static int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) + +static zval *object_param_to_string(php_pq_params_t *p, zval *zobj, Oid type TSRMLS_DC) { - zval **zparam = p; - unsigned j, *i = va_arg(argv, unsigned *); - smart_str *s = va_arg(argv, smart_str *); - zval **zconv = va_arg(argv, zval **); + zval *return_value = NULL; + smart_str str = {0}; + + switch (type) { +#if HAVE_JSON && defined(PHP_PQ_OID_JSON) +# ifdef PHP_PQ_OID_JSONB + case PHP_PQ_OID_JSONB: +# endif + case PHP_PQ_OID_JSON: + php_json_encode(&str, zobj, PHP_JSON_UNESCAPED_UNICODE TSRMLS_CC); + smart_str_0(&str); + break; +#endif + + case PHP_PQ_OID_DATE: + php_pqdt_to_string(zobj, "Y-m-d", &str.c, &str.len TSRMLS_CC); + break; + + case PHP_PQ_OID_ABSTIME: + php_pqdt_to_string(zobj, "Y-m-d H:i:s", &str.c, &str.len TSRMLS_CC); + break; + + case PHP_PQ_OID_TIMESTAMP: + php_pqdt_to_string(zobj, "Y-m-d H:i:s.u", &str.c, &str.len TSRMLS_CC); + break; + + case PHP_PQ_OID_TIMESTAMPTZ: + php_pqdt_to_string(zobj, "Y-m-d H:i:s.uO", &str.c, &str.len TSRMLS_CC); + break; + + default: + MAKE_STD_ZVAL(return_value); + MAKE_COPY_ZVAL(&zobj, return_value); + convert_to_string(return_value); + break; + } + + if (str.c) { + MAKE_STD_ZVAL(return_value); + RETVAL_STRINGL(str.c, str.len, 0); + } + + return return_value; +} + +struct apply_to_param_from_array_arg { + php_pq_params_t *params; + unsigned index; + smart_str *buffer; + Oid type; + zval **zconv; +}; + +static int apply_to_param_from_array(void *ptr, void *arg_ptr TSRMLS_DC) +{ + struct apply_to_param_from_array_arg subarg, *arg = arg_ptr; + zval *ztmp, **zparam = ptr, *zcopy = *zparam; char *tmp; size_t len; int tmp_len; - if ((*i)++) { - smart_str_appendc(s, ','); + if (arg->index++) { + smart_str_appendc(arg->buffer, ','); } - if (zconv) { - zval *rv = NULL; + if (arg->zconv) { + zval *ztype, *rv = NULL; + + MAKE_STD_ZVAL(ztype); + ZVAL_LONG(ztype, arg->type); + zend_call_method_with_2_params(arg->zconv, NULL, NULL, "converttostring", &rv, zcopy, ztype); + zval_ptr_dtor(&ztype); + + if (rv) { + convert_to_string(rv); + zcopy = rv; + } else { + return ZEND_HASH_APPLY_STOP; + } + + goto append_string; - zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zparam); - convert_to_string(rv); - smart_str_appendl(s, Z_STRVAL_P(rv), Z_STRLEN_P(rv)); - zval_ptr_dtor(&rv); } else { - switch (Z_TYPE_PP(zparam)) { + switch (Z_TYPE_P(zcopy)) { case IS_NULL: - smart_str_appends(s, "NULL"); + smart_str_appends(arg->buffer, "NULL"); break; case IS_BOOL: - smart_str_appends(s, Z_BVAL_PP(zparam) ? "t" : "f"); + smart_str_appends(arg->buffer, Z_BVAL_P(zcopy) ? "t" : "f"); break; case IS_LONG: - smart_str_append_long(s, Z_LVAL_PP(zparam)); + smart_str_append_long(arg->buffer, Z_LVAL_P(zcopy)); break; case IS_DOUBLE: - len = spprintf(&tmp, 0, "%F", Z_DVAL_PP(zparam)); - smart_str_appendl(s, tmp, len); + len = spprintf(&tmp, 0, "%F", Z_DVAL_P(zcopy)); + smart_str_appendl(arg->buffer, tmp, len); efree(tmp); break; case IS_ARRAY: - j = 0; - smart_str_appendc(s, '{'); - zend_hash_apply_with_arguments(Z_ARRVAL_PP(zparam) TSRMLS_CC, apply_to_param_from_array, 2, &j, s, zconv); - smart_str_appendc(s, '}'); + subarg = *arg; + subarg.index = 0; + smart_str_appendc(arg->buffer, '{'); + zend_hash_apply_with_argument(Z_ARRVAL_P(zcopy), apply_to_param_from_array, &subarg TSRMLS_CC); + smart_str_appendc(arg->buffer, '}'); break; - default: - SEPARATE_ZVAL(zparam); - if (Z_TYPE_PP(zparam) != IS_STRING) { - convert_to_string(*zparam); + case IS_OBJECT: + if ((ztmp = object_param_to_string(arg->params, zcopy, arg->type TSRMLS_CC))) { + zcopy = ztmp; } + /* no break */ + default: + SEPARATE_ZVAL(&zcopy); + convert_to_string(zcopy); - tmp = php_addslashes(Z_STRVAL_PP(zparam), Z_STRLEN_PP(zparam), &tmp_len, 0 TSRMLS_CC); - smart_str_appendc(s, '"'); - smart_str_appendl(s, tmp, tmp_len); - smart_str_appendc(s, '"'); + append_string: + tmp = php_addslashes(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy), &tmp_len, 0 TSRMLS_CC); + smart_str_appendc(arg->buffer, '"'); + smart_str_appendl(arg->buffer, tmp, tmp_len); + smart_str_appendc(arg->buffer, '"'); - if (*zparam != *((zval **) p)) { - zval_ptr_dtor(zparam); + if (zcopy != *zparam) { + zval_ptr_dtor(&zcopy); } efree(tmp); break; } } - ++(*i); + ++arg->index; return ZEND_HASH_APPLY_KEEP; } -static void array_param_to_string(zval **zconv, HashTable *ht, char **str, int *len TSRMLS_DC) +static zval *array_param_to_string(php_pq_params_t *p, zval *zarr, Oid type TSRMLS_DC) { + zval *zcopy, *return_value; smart_str s = {0}; - unsigned i = 0; + struct apply_to_param_from_array_arg arg = {NULL}; + + switch (type) { +#if HAVE_JSON && defined(PHP_PQ_OID_JSON) +# ifdef PHP_PQ_OID_JSONB + case PHP_PQ_OID_JSONB: +# endif + case PHP_PQ_OID_JSON: + php_json_encode(&s, zarr, PHP_JSON_UNESCAPED_UNICODE TSRMLS_CC); + smart_str_0(&s); + break; +#endif + + default: + arg.params = p; + arg.buffer = &s; + arg.type = PHP_PQ_TYPE_OF_ARRAY(type); + zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &arg.zconv); + smart_str_appendc(arg.buffer, '{'); + MAKE_STD_ZVAL(zcopy); + MAKE_COPY_ZVAL(&zarr, zcopy); + zend_hash_apply_with_argument(Z_ARRVAL_P(zcopy), apply_to_param_from_array, &arg TSRMLS_CC); + zval_ptr_dtor(&zcopy); + smart_str_appendc(arg.buffer, '}'); + smart_str_0(&s); + break; + } - smart_str_appendc(&s, '{'); - zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param_from_array, 3, &i, &s, zconv); - smart_str_appendc(&s, '}'); + /* must not return NULL */ + MAKE_STD_ZVAL(return_value); - smart_str_0(&s); - *str = s.c; - *len = s.len; + if (s.c) { + RETVAL_STRINGL(s.c, s.len, 0); + } else { + RETVAL_EMPTY_STRING(); + } + + return return_value; } -static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval **zp) +static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval **zpp) { zval **zconv = NULL; Oid type = p->type.count > index ? p->type.oids[index] : 0; TSRMLS_DF(p); if (type && SUCCESS == zend_hash_index_find(&p->type.conv, type, (void *) &zconv)) { - zval *rv = NULL; - - zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zp); - convert_to_string(rv); - p->param.strings[index] = Z_STRVAL_P(rv); - zend_hash_next_index_insert(&p->param.dtor, (void *) &rv, sizeof(zval *), NULL); + zval *ztype, *rv = NULL; + + MAKE_STD_ZVAL(ztype); + ZVAL_LONG(ztype, type); + zend_call_method_with_2_params(zconv, NULL, NULL, "converttostring", &rv, *zpp, ztype); + zval_ptr_dtor(&ztype); + if (rv) { + convert_to_string(rv); + p->param.strings[index] = Z_STRVAL_P(rv); + zend_hash_next_index_insert(&p->param.dtor, (void *) &rv, sizeof(zval *), NULL); + } } else { - zval **zpp = zp; + zval *tmp, *zcopy = *zpp; - switch (Z_TYPE_PP(zp)) { + switch (Z_TYPE_P(zcopy)) { case IS_NULL: p->param.strings[index] = NULL; return; case IS_BOOL: - p->param.strings[index] = Z_BVAL_PP(zp) ? "t" : "f"; + p->param.strings[index] = Z_BVAL_P(zcopy) ? "t" : "f"; return; case IS_DOUBLE: - SEPARATE_ZVAL(zp); - Z_TYPE_PP(zp) = IS_STRING; - Z_STRLEN_PP(zp) = spprintf(&Z_STRVAL_PP(zp), 0, "%F", Z_DVAL_PP(zpp)); + MAKE_STD_ZVAL(zcopy); + MAKE_COPY_ZVAL(zpp, zcopy); + Z_TYPE_P(zcopy) = IS_STRING; + Z_STRLEN_P(zcopy) = spprintf(&Z_STRVAL_P(zcopy), 0, "%F", Z_DVAL_PP(zpp)); break; case IS_ARRAY: - { - zval *tmp; - MAKE_STD_ZVAL(tmp); - Z_TYPE_P(tmp) = IS_STRING; - zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &zconv); - array_param_to_string(zconv, Z_ARRVAL_PP(zp), &Z_STRVAL_P(tmp), &Z_STRLEN_P(tmp) TSRMLS_CC); - zp = &tmp; + MAKE_STD_ZVAL(zcopy); + MAKE_COPY_ZVAL(zpp, zcopy); + tmp = array_param_to_string(p, zcopy, type TSRMLS_CC); + zval_ptr_dtor(&zcopy); + zcopy = tmp; break; - } + + case IS_OBJECT: + if ((tmp = object_param_to_string(p, zcopy, type TSRMLS_CC))) { + zcopy = tmp; + break; + } + /* no break */ default: - convert_to_string_ex(zp); + convert_to_string_ex(&zcopy); break; } - p->param.strings[index] = Z_STRVAL_PP(zp); + p->param.strings[index] = Z_STRVAL_P(zcopy); - if (*zp != *zpp) { - zend_hash_next_index_insert(&p->param.dtor, zp, sizeof(zval *), NULL); + if (zcopy != *zpp) { + zend_hash_next_index_insert(&p->param.dtor, (void *) &zcopy, sizeof(zval *), NULL); } } } -static int apply_to_params(void *zp TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +struct apply_to_params_arg { + php_pq_params_t *params; + unsigned index; +}; + +static int apply_to_params(void *zp, void *arg_ptr TSRMLS_DC) { - php_pq_params_t *p = (php_pq_params_t *) va_arg(argv, php_pq_params_t *); - unsigned *index = (unsigned *) va_arg(argv, unsigned *); + struct apply_to_params_arg *arg = arg_ptr; - php_pq_params_set_param(p, (*index)++, zp); + SEPARATE_ZVAL_IF_NOT_REF((zval **) zp); + php_pq_params_set_param(arg->params, arg->index++, zp); return ZEND_HASH_APPLY_KEEP; } @@ -243,9 +361,9 @@ unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params) } zend_hash_clean(&p->param.dtor); if (p->param.count) { - unsigned index = 0; + struct apply_to_params_arg arg = {p, 0}; p->param.strings = ecalloc(p->param.count, sizeof(*p->param.strings)); - zend_hash_apply_with_arguments(params TSRMLS_CC, apply_to_params, 2, p, &index); + zend_hash_apply_with_argument(params, apply_to_params, &arg TSRMLS_CC); } return p->param.count; }