0c8278e95593c37ebd2475fe4b0b81b5e5311861
[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
21 #include <Zend/zend_interfaces.h>
22
23 #include <libpq-fe.h>
24
25 #include "php_pq.h"
26 #include "php_pq_params.h"
27
28 void php_pq_params_set_type_conv(php_pq_params_t *p, HashTable *conv)
29 {
30 zend_hash_clean(&p->type.conv);
31 zend_hash_copy(&p->type.conv, conv, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
32 }
33
34 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
35 {
36 Oid **types = arg;
37 zval **ztype = p;
38
39 if (Z_TYPE_PP(ztype) != IS_LONG) {
40 convert_to_long_ex(ztype);
41 }
42
43 **types = Z_LVAL_PP(ztype);
44 ++*types;
45
46 if (*ztype != *(zval **)p) {
47 zval_ptr_dtor(ztype);
48 }
49 return ZEND_HASH_APPLY_KEEP;
50 }
51
52 unsigned php_pq_params_set_type_oids(php_pq_params_t *p, HashTable *oids)
53 {
54 p->type.count = oids ? zend_hash_num_elements(oids) : 0;
55 TSRMLS_DF(p);
56
57 if (p->type.oids) {
58 efree(p->type.oids);
59 p->type.oids = NULL;
60 }
61 if (p->type.count) {
62 Oid *ptr = ecalloc(p->type.count + 1, sizeof(*p->type.oids));
63 /* +1 for when less types than params are specified */
64 p->type.oids = ptr;
65 zend_hash_apply_with_argument(oids, apply_to_oid, &ptr TSRMLS_CC);
66 }
67 return p->type.count;
68 }
69
70 unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type)
71 {
72 p->type.oids = safe_erealloc(p->type.oids, ++p->type.count, sizeof(*p->type.oids), sizeof(*p->type.oids));
73 p->type.oids[p->type.count] = 0;
74 p->type.oids[p->type.count-1] = type;
75 return p->type.count;
76 }
77
78 static int apply_to_param_from_array(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
79 {
80 zval **zparam = p;
81 unsigned j, *i = va_arg(argv, unsigned *);
82 smart_str *s = va_arg(argv, smart_str *);
83 zval **zconv = va_arg(argv, zval **);
84 char *tmp;
85 size_t len;
86 int tmp_len;
87
88 if ((*i)++) {
89 smart_str_appendc(s, ',');
90 }
91
92 if (zconv) {
93 zval *rv = NULL;
94
95 zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zparam);
96 convert_to_string(rv);
97 smart_str_appendl(s, Z_STRVAL_P(rv), Z_STRLEN_P(rv));
98 zval_ptr_dtor(&rv);
99 } else {
100 switch (Z_TYPE_PP(zparam)) {
101 case IS_NULL:
102 smart_str_appends(s, "NULL");
103 break;
104
105 case IS_BOOL:
106 smart_str_appends(s, Z_BVAL_PP(zparam) ? "t" : "f");
107 break;
108
109 case IS_LONG:
110 smart_str_append_long(s, Z_LVAL_PP(zparam));
111 break;
112
113 case IS_DOUBLE:
114 len = spprintf(&tmp, 0, "%F", Z_DVAL_PP(zparam));
115 smart_str_appendl(s, tmp, len);
116 efree(tmp);
117 break;
118
119 case IS_ARRAY:
120 j = 0;
121 smart_str_appendc(s, '{');
122 zend_hash_apply_with_arguments(Z_ARRVAL_PP(zparam) TSRMLS_CC, apply_to_param_from_array, 2, &j, s, zconv);
123 smart_str_appendc(s, '}');
124 break;
125
126 default:
127 SEPARATE_ZVAL(zparam);
128 if (Z_TYPE_PP(zparam) != IS_STRING) {
129 convert_to_string(*zparam);
130 }
131
132 tmp = php_addslashes(Z_STRVAL_PP(zparam), Z_STRLEN_PP(zparam), &tmp_len, 0 TSRMLS_CC);
133 smart_str_appendc(s, '"');
134 smart_str_appendl(s, tmp, tmp_len);
135 smart_str_appendc(s, '"');
136
137 if (*zparam != *((zval **) p)) {
138 zval_ptr_dtor(zparam);
139 }
140 break;
141 }
142 }
143 ++(*i);
144 return ZEND_HASH_APPLY_KEEP;
145 }
146
147 static void array_param_to_string(zval **zconv, HashTable *ht, char **str, int *len TSRMLS_DC)
148 {
149 smart_str s = {0};
150 unsigned i = 0;
151
152 smart_str_appendc(&s, '{');
153 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param_from_array, 3, &i, &s, zconv);
154 smart_str_appendc(&s, '}');
155
156 smart_str_0(&s);
157 *str = s.c;
158 *len = s.len;
159 }
160
161 static void php_pq_params_set_param(php_pq_params_t *p, unsigned index, zval **zp)
162 {
163 zval **zconv = NULL;
164 Oid type = p->type.count > index ? p->type.oids[index] : 0;
165 TSRMLS_DF(p);
166
167 if (type && SUCCESS == zend_hash_index_find(&p->type.conv, type, (void *) &zconv)) {
168 zval *rv = NULL;
169
170 zend_call_method_with_1_params(zconv, NULL, NULL, "converttostring", &rv, *zp);
171 convert_to_string(rv);
172 p->param.strings[index] = Z_STRVAL_P(rv);
173 zend_hash_next_index_insert(&p->param.dtor, (void *) &rv, sizeof(zval *), NULL);
174 } else {
175 zval **zpp = zp;
176
177 switch (Z_TYPE_PP(zp)) {
178 case IS_NULL:
179 p->param.strings[index] = NULL;
180 return;
181
182 case IS_BOOL:
183 p->param.strings[index] = Z_BVAL_PP(zp) ? "t" : "f";
184 return;
185
186 case IS_DOUBLE:
187 SEPARATE_ZVAL(zp);
188 Z_TYPE_PP(zp) = IS_STRING;
189 Z_STRLEN_PP(zp) = spprintf(&Z_STRVAL_PP(zp), 0, "%F", Z_DVAL_PP((zval **)p));
190 break;
191
192 case IS_ARRAY:
193 {
194
195 #if HAVE_PHP_PQ_TYPE_H
196 # undef PHP_PQ_TYPE
197 # include "php_pq_type.h"
198 #else
199 # define PHP_PQ_TYPE_OF_ARRAY(oid) 0
200 #endif
201
202 zval *tmp;
203 MAKE_STD_ZVAL(tmp);
204 Z_TYPE_P(tmp) = IS_STRING;
205 zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &zconv);
206 array_param_to_string(zconv, Z_ARRVAL_PP(zp), &Z_STRVAL_P(tmp), &Z_STRLEN_P(tmp) TSRMLS_CC);
207 zp = &tmp;
208 break;
209 }
210
211 default:
212 convert_to_string_ex(zp);
213 break;
214 }
215
216 p->param.strings[index] = Z_STRVAL_PP(zp);
217
218 if (*zp != *zpp) {
219 zend_hash_next_index_insert(&p->param.dtor, zp, sizeof(zval *), NULL);
220 }
221 }
222 }
223
224 static int apply_to_params(void *zp TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
225 {
226 php_pq_params_t *p = (php_pq_params_t *) va_arg(argv, php_pq_params_t *);
227 unsigned *index = (unsigned *) va_arg(argv, unsigned *);
228
229 php_pq_params_set_param(p, (*index)++, zp);
230 return ZEND_HASH_APPLY_KEEP;
231 }
232
233 unsigned php_pq_params_add_param(php_pq_params_t *p, zval *param)
234 {
235 p->param.strings = safe_erealloc(p->param.strings, ++p->param.count, sizeof(*p->param.strings), 0);
236 php_pq_params_set_param(p, p->param.count-1, &param);
237 return p->type.count;
238 }
239
240 unsigned php_pq_params_set_params(php_pq_params_t *p, HashTable *params)
241 {
242 p->param.count = params ? zend_hash_num_elements(params) : 0;
243 TSRMLS_DF(p);
244
245 if (p->param.strings) {
246 efree(p->param.strings);
247 p->param.strings = NULL;
248 }
249 zend_hash_clean(&p->param.dtor);
250 if (p->param.count) {
251 unsigned index = 0;
252 p->param.strings = ecalloc(p->param.count, sizeof(*p->param.strings));
253 zend_hash_apply_with_arguments(params TSRMLS_CC, apply_to_params, 2, p, &index);
254 }
255 return p->param.count;
256 }
257
258 void php_pq_params_free(php_pq_params_t **p)
259 {
260 if (*p) {
261 php_pq_params_set_type_oids(*p, NULL);
262 php_pq_params_set_params(*p, NULL);
263
264 zend_hash_destroy(&(*p)->param.dtor);
265 zend_hash_destroy(&(*p)->type.conv);
266
267 efree(*p);
268 *p = NULL;
269 }
270 }
271
272 php_pq_params_t *php_pq_params_init(HashTable *conv, HashTable *oids, HashTable *params TSRMLS_DC)
273 {
274 php_pq_params_t *p = ecalloc(1, sizeof(*p));
275
276 TSRMLS_CF(p);
277 zend_hash_init(&p->type.conv, 0, NULL, ZVAL_PTR_DTOR, 0);
278 zend_hash_init(&p->param.dtor, 0, NULL, ZVAL_PTR_DTOR, 0);
279
280 if (conv) {
281 php_pq_params_set_type_conv(p, conv);
282 }
283 if (oids) {
284 php_pq_params_set_type_oids(p, oids);
285 }
286 if (params) {
287 php_pq_params_set_params(p, params);
288 }
289
290 return p;
291 }
292
293 /*
294 * Local variables:
295 * tab-width: 4
296 * c-basic-offset: 4
297 * End:
298 * vim600: noet sw=4 ts=4 fdm=marker
299 * vim<600: noet sw=4 ts=4
300 */