more internal conversions
[m6w6/ext-pq] / src / php_pq_params.c
index 149da750ede70bf98224196e8b7564e8b54690ed..ffe5e70ba7b06b6d13fd72134c462c4a456b6c79 100644 (file)
@@ -17,6 +17,7 @@
 #include <php.h>
 #include <ext/standard/php_string.h>
 #include <ext/standard/php_smart_str.h>
+#include <ext/json/php_json.h>
 
 #include <Zend/zend_interfaces.h>
 
@@ -24,6 +25,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,12 +79,61 @@ 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 *return_value = NULL;
+       smart_str str = {0};
+
+       switch (type) {
+#ifdef 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:
+               SEPARATE_ZVAL(&zobj);
+               convert_to_string(zobj);
+               return_value = zobj;
+               break;
+       }
+
+       if (str.c) {
+               MAKE_STD_ZVAL(return_value);
+               RETVAL_STRINGL(str.c, str.len, 0);
+       }
+
+       return return_value;
+}
+
+static int apply_to_param_from_array(void *ptr TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
 {
-       zval **zparam = p;
+       php_pq_params_t *p = va_arg(argv, php_pq_params_t *);
        unsigned j, *i = va_arg(argv, unsigned *);
        smart_str *s = va_arg(argv, smart_str *);
-       zval **zconv = va_arg(argv, zval **);
+       Oid type = va_arg(argv, Oid);
+       zval *ztmp, **zparam = ptr, *zcopy = *zparam, **zconv = va_arg(argv, zval **);
        char *tmp;
        size_t len;
        int tmp_len;
@@ -94,26 +145,26 @@ static int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv,
        if (zconv) {
                zval *rv = NULL;
 
-               zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zparam);
+               zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, zcopy);
                convert_to_string(rv);
-               smart_str_appendl(s, Z_STRVAL_P(rv), Z_STRLEN_P(rv));
-               zval_ptr_dtor(&rv);
+               zcopy = rv;
+               goto append_string;
        } else {
-               switch (Z_TYPE_PP(zparam)) {
+               switch (Z_TYPE_P(zcopy)) {
                case IS_NULL:
                        smart_str_appends(s, "NULL");
                        break;
 
                case IS_BOOL:
-                       smart_str_appends(s, Z_BVAL_PP(zparam) ? "t" : "f");
+                       smart_str_appends(s, Z_BVAL_P(zcopy) ? "t" : "f");
                        break;
 
                case IS_LONG:
-                       smart_str_append_long(s, Z_LVAL_PP(zparam));
+                       smart_str_append_long(s, Z_LVAL_P(zcopy));
                        break;
 
                case IS_DOUBLE:
-                       len = spprintf(&tmp, 0, "%F", Z_DVAL_PP(zparam));
+                       len = spprintf(&tmp, 0, "%F", Z_DVAL_P(zcopy));
                        smart_str_appendl(s, tmp, len);
                        efree(tmp);
                        break;
@@ -121,23 +172,27 @@ static int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv,
                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);
+                       zend_hash_apply_with_arguments(Z_ARRVAL_P(zcopy) TSRMLS_CC, apply_to_param_from_array, 5, p, &j, s, type, zconv);
                        smart_str_appendc(s, '}');
                        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(p, zcopy, 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);
+                       append_string:
+                       tmp = php_addslashes(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy), &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);
+                       if (zcopy != *zparam) {
+                               zval_ptr_dtor(&zcopy);
                        }
                        efree(tmp);
                        break;
@@ -147,21 +202,46 @@ static int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv,
        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 *return_value, **zconv = NULL;
        smart_str s = {0};
        unsigned i = 0;
 
-       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, '}');
+       switch (type) {
+#ifdef 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:
+               zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &zconv);
+
+               smart_str_appendc(&s, '{');
+               zend_hash_apply_with_arguments(Z_ARRVAL_P(zarr) TSRMLS_CC, apply_to_param_from_array, 5, p, &i, &s, (Oid) PHP_PQ_TYPE_OF_ARRAY(type), zconv);
+               smart_str_appendc(&s, '}');
+               smart_str_0(&s);
+               break;
+       }
+
+       /* 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;
@@ -170,48 +250,48 @@ static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval **z
        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);
+               zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zpp);
                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));
+                       SEPARATE_ZVAL(&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;
+                       zcopy = array_param_to_string(p, zcopy, type TSRMLS_CC);
                        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);
                }
        }
 }