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