get rid of remaining HAVE_JSON, use PHP_PQ_HAVE_PHP_JSON_H everywhere
[m6w6/ext-pq] / src / php_pq_params.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: pq |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <php.h>
18 #include <ext/standard/php_string.h>
19 #include <ext/standard/php_smart_str.h>
20 #if PHP_PQ_HAVE_PHP_JSON_H
21 #include <php_json.h> /* we've added the include directory to INCLUDES */
22 #endif
23
24 #include <Zend/zend_interfaces.h>
25
26 #include <libpq-fe.h>
27
28 #include "php_pq.h"
29 #include "php_pq_params.h"
30 #include "php_pq_misc.h"
31 #undef PHP_PQ_TYPE
32 #include "php_pq_type.h"
33
34 void php_pq_params_set_type_conv(php_pq_params_t *p, HashTable *conv)
35 {
36 zend_hash_clean(&p->type.conv);
37 zend_hash_copy(&p->type.conv, conv, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
38 }
39
40 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
41 {
42 Oid **types = arg;
43 zval **ztype = p;
44
45 if (Z_TYPE_PP(ztype) != IS_LONG) {
46 convert_to_long_ex(ztype);
47 }
48
49 **types = Z_LVAL_PP(ztype);
50 ++*types;
51
52 if (*ztype != *(zval **)p) {
53 zval_ptr_dtor(ztype);
54 }
55 return ZEND_HASH_APPLY_KEEP;
56 }
57
58 unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids)
59 {
60 p->type.count = oids ? zend_hash_num_elements(oids) : 0;
61 TSRMLS_DF(p);
62
63 if (p->type.oids) {
64 efree(p->type.oids);
65 p->type.oids = NULL;
66 }
67 if (p->type.count) {
68 Oid *ptr = ecalloc(p->type.count + 1, sizeof(*p->type.oids));
69 /* +1 for when less types than params are specified */
70 p->type.oids = ptr;
71 zend_hash_apply_with_argument(oids, apply_to_oid, &ptr TSRMLS_CC);
72 }
73 return p->type.count;
74 }
75
76 unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type)
77 {
78 p->type.oids = safe_erealloc(p->type.oids, ++p->type.count, sizeof(*p->type.oids), sizeof(*p->type.oids));
79 p->type.oids[p->type.count] = 0;
80 p->type.oids[p->type.count-1] = type;
81 return p->type.count;
82 }
83
84
85 static zval *object_param_to_string(php_pq_params_t *p, zval *zobj, Oid type TSRMLS_DC)
86 {
87 zval *return_value = NULL;
88 smart_str str = {0};
89
90 switch (type) {
91 #if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
92 # ifdef PHP_PQ_OID_JSONB
93 case PHP_PQ_OID_JSONB:
94 # endif
95 case PHP_PQ_OID_JSON:
96 php_json_encode(&str, zobj, PHP_JSON_UNESCAPED_UNICODE TSRMLS_CC);
97 smart_str_0(&str);
98 break;
99 #endif
100
101 case PHP_PQ_OID_DATE:
102 php_pqdt_to_string(zobj, "Y-m-d", &str.c, &str.len TSRMLS_CC);
103 break;
104
105 case PHP_PQ_OID_ABSTIME:
106 php_pqdt_to_string(zobj, "Y-m-d H:i:s", &str.c, &str.len TSRMLS_CC);
107 break;
108
109 case PHP_PQ_OID_TIMESTAMP:
110 php_pqdt_to_string(zobj, "Y-m-d H:i:s.u", &str.c, &str.len TSRMLS_CC);
111 break;
112
113 case PHP_PQ_OID_TIMESTAMPTZ:
114 php_pqdt_to_string(zobj, "Y-m-d H:i:s.uO", &str.c, &str.len TSRMLS_CC);
115 break;
116
117 default:
118 MAKE_STD_ZVAL(return_value);
119 MAKE_COPY_ZVAL(&zobj, return_value);
120 convert_to_string(return_value);
121 break;
122 }
123
124 if (str.c) {
125 MAKE_STD_ZVAL(return_value);
126 RETVAL_STRINGL(str.c, str.len, 0);
127 }
128
129 return return_value;
130 }
131
132 struct apply_to_param_from_array_arg {
133 php_pq_params_t *params;
134 unsigned index;
135 smart_str *buffer;
136 Oid type;
137 zval **zconv;
138 };
139
140 static int apply_to_param_from_array(void *ptr, void *arg_ptr TSRMLS_DC)
141 {
142 struct apply_to_param_from_array_arg subarg, *arg = arg_ptr;
143 zval *ztmp, **zparam = ptr, *zcopy = *zparam;
144 char *tmp;
145 size_t len;
146 int tmp_len;
147
148 if (arg->index++) {
149 smart_str_appendc(arg->buffer, ',');
150 }
151
152 if (arg->zconv) {
153 zval *ztype, *rv = NULL;
154
155 MAKE_STD_ZVAL(ztype);
156 ZVAL_LONG(ztype, arg->type);
157 zend_call_method_with_2_params(arg->zconv, NULL, NULL, "converttostring", &rv, zcopy, ztype);
158 zval_ptr_dtor(&ztype);
159
160 if (rv) {
161 convert_to_string(rv);
162 zcopy = rv;
163 } else {
164 return ZEND_HASH_APPLY_STOP;
165 }
166
167 goto append_string;
168
169 } else {
170 switch (Z_TYPE_P(zcopy)) {
171 case IS_NULL:
172 smart_str_appends(arg->buffer, "NULL");
173 break;
174
175 case IS_BOOL:
176 smart_str_appends(arg->buffer, Z_BVAL_P(zcopy) ? "t" : "f");
177 break;
178
179 case IS_LONG:
180 smart_str_append_long(arg->buffer, Z_LVAL_P(zcopy));
181 break;
182
183 case IS_DOUBLE:
184 len = spprintf(&tmp, 0, "%F", Z_DVAL_P(zcopy));
185 smart_str_appendl(arg->buffer, tmp, len);
186 efree(tmp);
187 break;
188
189 case IS_ARRAY:
190 subarg = *arg;
191 subarg.index = 0;
192 smart_str_appendc(arg->buffer, '{');
193 zend_hash_apply_with_argument(Z_ARRVAL_P(zcopy), apply_to_param_from_array, &subarg TSRMLS_CC);
194 smart_str_appendc(arg->buffer, '}');
195 break;
196
197 case IS_OBJECT:
198 if ((ztmp = object_param_to_string(arg->params, zcopy, arg->type TSRMLS_CC))) {
199 zcopy = ztmp;
200 }
201 /* no break */
202 default:
203 SEPARATE_ZVAL(&zcopy);
204 convert_to_string(zcopy);
205
206 append_string:
207 tmp = php_addslashes(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy), &tmp_len, 0 TSRMLS_CC);
208 smart_str_appendc(arg->buffer, '"');
209 smart_str_appendl(arg->buffer, tmp, tmp_len);
210 smart_str_appendc(arg->buffer, '"');
211
212 if (zcopy != *zparam) {
213 zval_ptr_dtor(&zcopy);
214 }
215 efree(tmp);
216 break;
217 }
218 }
219 ++arg->index;
220 return ZEND_HASH_APPLY_KEEP;
221 }
222
223 static zval *array_param_to_string(php_pq_params_t *p, zval *zarr, Oid type TSRMLS_DC)
224 {
225 zval *zcopy, *return_value;
226 smart_str s = {0};
227 struct apply_to_param_from_array_arg arg = {NULL};
228
229 switch (type) {
230 #if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
231 # ifdef PHP_PQ_OID_JSONB
232 case PHP_PQ_OID_JSONB:
233 # endif
234 case PHP_PQ_OID_JSON:
235 php_json_encode(&s, zarr, PHP_JSON_UNESCAPED_UNICODE TSRMLS_CC);
236 smart_str_0(&s);
237 break;
238 #endif
239
240 default:
241 arg.params = p;
242 arg.buffer = &s;
243 arg.type = PHP_PQ_TYPE_OF_ARRAY(type);
244 zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &arg.zconv);
245 smart_str_appendc(arg.buffer, '{');
246 MAKE_STD_ZVAL(zcopy);
247 MAKE_COPY_ZVAL(&zarr, zcopy);
248 zend_hash_apply_with_argument(Z_ARRVAL_P(zcopy), apply_to_param_from_array, &arg TSRMLS_CC);
249 zval_ptr_dtor(&zcopy);
250 smart_str_appendc(arg.buffer, '}');
251 smart_str_0(&s);
252 break;
253 }
254
255 /* must not return NULL */
256 MAKE_STD_ZVAL(return_value);
257
258 if (s.c) {
259 RETVAL_STRINGL(s.c, s.len, 0);
260 } else {
261 RETVAL_EMPTY_STRING();
262 }
263
264 return return_value;
265 }
266
267 static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval **zpp)
268 {
269 zval **zconv = NULL;
270 Oid type = p->type.count > index ? p->type.oids[index] : 0;
271 TSRMLS_DF(p);
272
273 if (type && SUCCESS == zend_hash_index_find(&p->type.conv, type, (void *) &zconv)) {
274 zval *ztype, *rv = NULL;
275
276 MAKE_STD_ZVAL(ztype);
277 ZVAL_LONG(ztype, type);
278 zend_call_method_with_2_params(zconv, NULL, NULL, "converttostring", &rv, *zpp, ztype);
279 zval_ptr_dtor(&ztype);
280 if (rv) {
281 convert_to_string(rv);
282 p->param.strings[index] = Z_STRVAL_P(rv);
283 zend_hash_next_index_insert(&p->param.dtor, (void *) &rv, sizeof(zval *), NULL);
284 }
285 } else {
286 zval *tmp, *zcopy = *zpp;
287
288 switch (Z_TYPE_P(zcopy)) {
289 case IS_NULL:
290 p->param.strings[index] = NULL;
291 return;
292
293 case IS_BOOL:
294 p->param.strings[index] = Z_BVAL_P(zcopy) ? "t" : "f";
295 return;
296
297 case IS_DOUBLE:
298 MAKE_STD_ZVAL(zcopy);
299 MAKE_COPY_ZVAL(zpp, zcopy);
300 Z_TYPE_P(zcopy) = IS_STRING;
301 Z_STRLEN_P(zcopy) = spprintf(&Z_STRVAL_P(zcopy), 0, "%F", Z_DVAL_PP(zpp));
302 break;
303
304 case IS_ARRAY:
305 MAKE_STD_ZVAL(zcopy);
306 MAKE_COPY_ZVAL(zpp, zcopy);
307 tmp = array_param_to_string(p, zcopy, type TSRMLS_CC);
308 zval_ptr_dtor(&zcopy);
309 zcopy = tmp;
310 break;
311
312 case IS_OBJECT:
313 if ((tmp = object_param_to_string(p, zcopy, type TSRMLS_CC))) {
314 zcopy = tmp;
315 break;
316 }
317 /* no break */
318
319 default:
320 convert_to_string_ex(&zcopy);
321 break;
322 }
323
324 p->param.strings[index] = Z_STRVAL_P(zcopy);
325
326 if (zcopy != *zpp) {
327 zend_hash_next_index_insert(&p->param.dtor, (void *) &zcopy, sizeof(zval *), NULL);
328 }
329 }
330 }
331
332 struct apply_to_params_arg {
333 php_pq_params_t *params;
334 unsigned index;
335 };
336
337 static int apply_to_params(void *zp, void *arg_ptr TSRMLS_DC)
338 {
339 struct apply_to_params_arg *arg = arg_ptr;
340
341 SEPARATE_ZVAL_IF_NOT_REF((zval **) zp);
342 php_pq_params_set_param(arg->params, arg->index++, zp);
343 return ZEND_HASH_APPLY_KEEP;
344 }
345
346 unsigned php_pq_params_add_param(php_pq_params_t *p, zval *param)
347 {
348 p->param.strings = safe_erealloc(p->param.strings, ++p->param.count, sizeof(*p->param.strings), 0);
349 php_pq_params_set_param(p, p->param.count-1, &param);
350 return p->type.count;
351 }
352
353 unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params)
354 {
355 p->param.count = params ? zend_hash_num_elements(params) : 0;
356 TSRMLS_DF(p);
357
358 if (p->param.strings) {
359 efree(p->param.strings);
360 p->param.strings = NULL;
361 }
362 zend_hash_clean(&p->param.dtor);
363 if (p->param.count) {
364 struct apply_to_params_arg arg = {p, 0};
365 p->param.strings = ecalloc(p->param.count, sizeof(*p->param.strings));
366 zend_hash_apply_with_argument(params, apply_to_params, &arg TSRMLS_CC);
367 }
368 return p->param.count;
369 }
370
371 void php_pq_params_free(php_pq_params_t **p)
372 {
373 if (*p) {
374 php_pq_params_set_type_oids(*p, NULL);
375 php_pq_params_set_params(*p, NULL);
376
377 zend_hash_destroy(&(*p)->param.dtor);
378 zend_hash_destroy(&(*p)->type.conv);
379
380 efree(*p);
381 *p = NULL;
382 }
383 }
384
385 php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params TSRMLS_DC)
386 {
387 php_pq_params_t *p = ecalloc(1, sizeof(*p));
388
389 TSRMLS_CF(p);
390 zend_hash_init(&p->type.conv, 0, NULL, ZVAL_PTR_DTOR, 0);
391 zend_hash_init(&p->param.dtor, 0, NULL, ZVAL_PTR_DTOR, 0);
392
393 if (conv) {
394 php_pq_params_set_type_conv(p, conv);
395 }
396 if (oids) {
397 php_pq_params_set_type_oids(p, oids);
398 }
399 if (params) {
400 php_pq_params_set_params(p, params);
401 }
402
403 return p;
404 }
405
406 /*
407 * Local variables:
408 * tab-width: 4
409 * c-basic-offset: 4
410 * End:
411 * vim600: noet sw=4 ts=4 fdm=marker
412 * vim<600: noet sw=4 ts=4
413 */