upgrade pq\Types
[m6w6/ext-pq] / src / php_pq_params.c
index 0c8278e95593c37ebd2475fe4b0b81b5e5311861..a691eebd62464efbe897c2f91533c064b7f85961 100644 (file)
 
 #include <php.h>
 #include <ext/standard/php_string.h>
-#include <ext/standard/php_smart_str.h>
+#if PHP_PQ_HAVE_PHP_JSON_H
+#include <php_json.h> /* we've added the include directory to INCLUDES */
+#endif
 
+#include <Zend/zend_smart_str.h>
 #include <Zend/zend_interfaces.h>
 
 #include <libpq-fe.h>
 
 #include "php_pq.h"
 #include "php_pq_params.h"
+#include "php_pq_misc.h"
+#undef PHP_PQ_TYPE
+#include "php_pq_type.h"
 
 void php_pq_params_set_type_conv(php_pq_params_t *p, HashTable *conv)
 {
        zend_hash_clean(&p->type.conv);
-       zend_hash_copy(&p->type.conv, conv, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+       zend_hash_copy(&p->type.conv, conv, (copy_ctor_func_t) zval_add_ref);
 }
 
-static int apply_to_oid(void *p, void *arg TSRMLS_DC)
+static int apply_to_oid(zval *ztype, void *arg)
 {
        Oid **types = arg;
-       zval **ztype = p;
-
-       if (Z_TYPE_PP(ztype) != IS_LONG) {
-               convert_to_long_ex(ztype);
-       }
 
-       **types = Z_LVAL_PP(ztype);
+       **types = zval_get_long(ztype);
        ++*types;
 
-       if (*ztype != *(zval **)p) {
-               zval_ptr_dtor(ztype);
-       }
        return ZEND_HASH_APPLY_KEEP;
 }
 
 unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids)
 {
        p->type.count = oids ? zend_hash_num_elements(oids) : 0;
-       TSRMLS_DF(p);
 
        if (p->type.oids) {
                efree(p->type.oids);
@@ -62,7 +59,7 @@ unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids)
                Oid *ptr = ecalloc(p->type.count + 1, sizeof(*p->type.oids));
                /* +1 for when less types than params are specified */
                p->type.oids = ptr;
-               zend_hash_apply_with_argument(oids, apply_to_oid, &ptr TSRMLS_CC);
+               zend_hash_apply_with_argument(oids, apply_to_oid, &ptr);
        }
        return p->type.count;
 }
@@ -75,172 +72,256 @@ 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 zend_string *object_param_to_string(php_pq_params_t *p, zval *zobj, Oid type)
+{
+#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
+       smart_str str = {0};
+#endif
+
+       switch (type) {
+#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
+# ifdef PHP_PQ_OID_JSONB
+       case PHP_PQ_OID_JSONB:
+# endif
+       case PHP_PQ_OID_JSON:
+# if PHP_VERSION_ID >= 70100
+               JSON_G(encode_max_depth) = PHP_JSON_PARSER_DEFAULT_DEPTH;
+# endif
+               php_json_encode(&str, zobj, PHP_JSON_UNESCAPED_UNICODE);
+               smart_str_0(&str);
+               return str.s;
+#endif
+
+       case PHP_PQ_OID_DATE:
+               return php_pqdt_to_string(zobj, "Y-m-d");
+#ifdef PHP_PQ_OID_ABSTIME
+       case PHP_PQ_OID_ABSTIME:
+               return php_pqdt_to_string(zobj, "Y-m-d H:i:s");
+#endif
+       case PHP_PQ_OID_TIMESTAMP:
+               return php_pqdt_to_string(zobj, "Y-m-d H:i:s.u");
+
+       case PHP_PQ_OID_TIMESTAMPTZ:
+               return php_pqdt_to_string(zobj, "Y-m-d H:i:s.uO");
+       }
+
+       return zval_get_string(zobj);
+}
+
+struct apply_to_param_from_array_arg {
+       php_pq_params_t *params;
+       unsigned index;
+       smart_str *buffer;
+       Oid type;
+       char delim;
+       zval *zconv;
+};
+
+static int apply_to_param_from_array(zval *zparam, void *arg_ptr)
 {
-       zval **zparam = p;
-       unsigned j, *i = va_arg(argv, unsigned *);
-       smart_str *s = va_arg(argv, smart_str *);
-       zval **zconv = va_arg(argv, zval **);
+       struct apply_to_param_from_array_arg subarg, *arg = arg_ptr;
        char *tmp;
        size_t len;
-       int tmp_len;
+       zend_string *str, *tmpstr;
 
-       if ((*i)++) {
-               smart_str_appendc(s, ',');
+       if (arg->index++) {
+               smart_str_appendc(arg->buffer, arg->delim);
        }
 
-       if (zconv) {
-               zval *rv = NULL;
+       if (arg->zconv) {
+               zval ztype, rv;
 
-               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_LONG(&ztype, arg->type);
+               zend_call_method_with_2_params(arg->zconv, NULL, NULL, "converttostring", &rv, zparam, &ztype);
+               tmpstr = zval_get_string(&rv);
                zval_ptr_dtor(&rv);
+               goto append_string;
+
        } else {
-               switch (Z_TYPE_PP(zparam)) {
+               again:
+               switch (Z_TYPE_P(zparam)) {
+               case IS_REFERENCE:
+                       ZVAL_DEREF(zparam);
+                       goto again;
+
                case IS_NULL:
-                       smart_str_appends(s, "NULL");
+                       smart_str_appends(arg->buffer, "NULL");
+                       break;
+
+               case IS_TRUE:
+                       smart_str_appends(arg->buffer, "t");
                        break;
 
-               case IS_BOOL:
-                       smart_str_appends(s, Z_BVAL_PP(zparam) ? "t" : "f");
+               case IS_FALSE:
+                       smart_str_appends(arg->buffer, "f");
                        break;
 
                case IS_LONG:
-                       smart_str_append_long(s, Z_LVAL_PP(zparam));
+                       smart_str_append_long(arg->buffer, Z_LVAL_P(zparam));
                        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(zparam));
+                       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(zparam), apply_to_param_from_array, &subarg);
+                       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 ((tmpstr = object_param_to_string(arg->params, zparam, arg->type))) {
+                               goto append_string;
                        }
+                       /* no break */
+               default:
+                       tmpstr = zval_get_string(zparam);
 
-                       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, '"');
-
-                       if (*zparam != *((zval **) p)) {
-                               zval_ptr_dtor(zparam);
-                       }
+                       append_string:
+#if PHP_VERSION_ID < 70300
+                       str = php_addslashes(tmpstr, 1);
+#else
+                       str = php_addslashes(tmpstr);
+                       zend_string_release(tmpstr);
+#endif
+                       smart_str_appendc(arg->buffer, '"');
+                       smart_str_appendl(arg->buffer, str->val, str->len);
+                       smart_str_appendc(arg->buffer, '"');
+                       zend_string_release(str);
                        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 zend_string *array_param_to_string(php_pq_params_t *p, zval *zarr, Oid type)
 {
        smart_str s = {0};
-       unsigned i = 0;
+       struct apply_to_param_from_array_arg arg = {NULL};
+
+       switch (type) {
+#if PHP_PQ_HAVE_PHP_JSON_H && 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);
+               break;
+#endif
 
-       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, '}');
+       default:
+               arg.params = p;
+               arg.buffer = &s;
+               arg.type = PHP_PQ_TYPE_OF_ARRAY(type);
+               arg.delim = PHP_PQ_DELIM_OF_ARRAY(type);
+               arg.zconv = zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type));
+               smart_str_appendc(arg.buffer, '{');
+               SEPARATE_ZVAL(zarr);
+               zend_hash_apply_with_argument(Z_ARRVAL_P(zarr), apply_to_param_from_array, &arg);
+               smart_str_appendc(arg.buffer, '}');
+               break;
+       }
 
        smart_str_0(&s);
-       *str = s.c;
-       *len = s.len;
+       return s.s;
 }
 
-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;
+       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;
+       if (type && (zconv = zend_hash_index_find(&p->type.conv, type))) {
+               zval ztype, rv;
 
-               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_NULL(&rv);
+               ZVAL_LONG(&ztype, type);
+               zend_call_method_with_2_params(zconv, NULL, NULL, "converttostring", &rv, zpp, &ztype);
+               convert_to_string(&rv);
+               p->param.strings[index] = Z_STRVAL_P(&rv);
+               zend_hash_next_index_insert(&p->param.dtor, &rv);
        } else {
-               zval **zpp = zp;
+               zval tmp;
+               zend_string *str = NULL;
+               char tmp_str[64];
+               size_t tmp_len = 0;
+
+               again:
+               switch (Z_TYPE_P(zpp)) {
+               case IS_REFERENCE:
+                       ZVAL_DEREF(zpp);
+                       goto again;
 
-               switch (Z_TYPE_PP(zp)) {
                case IS_NULL:
                        p->param.strings[index] = NULL;
                        return;
 
-               case IS_BOOL:
-                       p->param.strings[index] = Z_BVAL_PP(zp) ? "t" : "f";
+               case IS_TRUE:
+                       p->param.strings[index] = "t";
+                       break;
+
+               case IS_FALSE:
+                       p->param.strings[index] = "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((zval **)p));
+                       tmp_len = slprintf(tmp_str, sizeof(tmp_str), "%F", Z_DVAL_P(zpp));
+                       str = zend_string_init(tmp_str, tmp_len, 0);
                        break;
 
                case IS_ARRAY:
-               {
-
-#if HAVE_PHP_PQ_TYPE_H
-#      undef PHP_PQ_TYPE
-#      include "php_pq_type.h"
-#else
-#      define PHP_PQ_TYPE_OF_ARRAY(oid) 0
-#endif
-
-                       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;
+                       str = array_param_to_string(p, zpp, type);
                        break;
-               }
 
+               case IS_OBJECT:
+                       if ((str = object_param_to_string(p, zpp, type))) {
+                               break;
+                       }
+                       /* no break */
                default:
-                       convert_to_string_ex(zp);
+                       str = zval_get_string(zpp);
                        break;
                }
 
-               p->param.strings[index] = Z_STRVAL_PP(zp);
-
-               if (*zp != *zpp) {
-                       zend_hash_next_index_insert(&p->param.dtor, zp, sizeof(zval *), NULL);
+               if (str) {
+                       ZVAL_STR(&tmp, str);
+                       p->param.strings[index] = Z_STRVAL(tmp);
+                       zend_hash_next_index_insert(&p->param.dtor, &tmp);
                }
        }
 }
 
-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(zval *zp, void *arg_ptr)
 {
-       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(zp);
+       php_pq_params_set_param(arg->params, arg->index++, zp);
        return ZEND_HASH_APPLY_KEEP;
 }
 
 unsigned php_pq_params_add_param(php_pq_params_t *p, zval *param)
 {
        p->param.strings = safe_erealloc(p->param.strings, ++p->param.count, sizeof(*p->param.strings), 0);
-       php_pq_params_set_param(p, p->param.count-1, &param);
+       php_pq_params_set_param(p, p->param.count-1, param);
        return p->type.count;
 }
 
 unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params)
 {
        p->param.count = params ? zend_hash_num_elements(params) : 0;
-       TSRMLS_DF(p);
 
        if (p->param.strings) {
                efree(p->param.strings);
@@ -248,9 +329,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);
        }
        return p->param.count;
 }
@@ -269,11 +350,10 @@ void php_pq_params_free(php_pq_params_t **p)
        }
 }
 
-php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params TSRMLS_DC)
+php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params)
 {
        php_pq_params_t *p = ecalloc(1, sizeof(*p));
 
-       TSRMLS_CF(p);
        zend_hash_init(&p->type.conv, 0, NULL, ZVAL_PTR_DTOR, 0);
        zend_hash_init(&p->param.dtor, 0, NULL, ZVAL_PTR_DTOR, 0);