#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_interfaces.h>
#include "php_pq.h"
#include "php_pq_params.h"
+#include "php_pq_misc.h"
#undef PHP_PQ_TYPE
#include "php_pq_type.h"
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 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(&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;
+ char delim;
+ 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, arg->delim);
}
- 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 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 TSRMLS_CC);
+ smart_str_0(&s);
+ break;
+#endif
+
+ default:
+ arg.params = p;
+ arg.buffer = &s;
+ arg.type = PHP_PQ_TYPE_OF_ARRAY(type);
+ arg.delim = PHP_PQ_DELIM_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;
}
}
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;
}