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