prepare v2.2.3
[m6w6/ext-pq] / src / php_pqres.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
19 #include <ext/spl/spl_iterators.h>
20 #include <ext/json/php_json.h>
21
22 #include <libpq-events.h>
23
24 #include "php_pq.h"
25 #include "php_pq_misc.h"
26 #include "php_pq_object.h"
27 #include "php_pqexc.h"
28 #include "php_pqres.h"
29 #undef PHP_PQ_TYPE
30 #include "php_pq_type.h"
31
32 zend_class_entry *php_pqres_class_entry;
33 static zend_object_handlers php_pqres_object_handlers;
34 static HashTable php_pqres_object_prophandlers;
35 static zend_object_iterator_funcs php_pqres_iterator_funcs;
36
37 static inline zend_object_iterator *php_pqres_iterator_init_ex(zend_class_entry *ce, zval *object, int by_ref)
38 {
39 php_pqres_iterator_t *iter;
40 zval tmp, *zfetch_type;
41
42 iter = ecalloc(1, sizeof(*iter));
43 iter->zi.funcs = &php_pqres_iterator_funcs;
44 ZVAL_COPY_VALUE(&iter->zi.data, object);
45
46 zfetch_type = php_pq_read_property(object, "fetchType", &tmp);
47 iter->fetch_type = zval_get_long(zfetch_type);
48 #if DBG_GC
49 fprintf(stderr, "INIT iter(#%d) %p res(#%d) %p\n", iter->zi.std.handle, iter, Z_OBJ_HANDLE_P(object), PHP_PQ_OBJ(object, NULL));
50 #endif
51 return (zend_object_iterator *) iter;
52 }
53
54 static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref)
55 {
56 zend_object_iterator *iter = php_pqres_iterator_init_ex(ce, object, by_ref);
57
58 zend_iterator_init(iter);
59 Z_ADDREF_P(object);
60
61 return iter;
62 }
63 static void php_pqres_internal_iterator_init(zval *zobj)
64 {
65 php_pqres_object_t *obj = PHP_PQ_OBJ(zobj, NULL);
66
67 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init_ex(Z_OBJCE_P(zobj), zobj, 0);
68 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter);
69
70 }
71
72 static inline void php_pqres_iterator_dtor_ex(zend_object_iterator *i)
73 {
74 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
75
76 #if DBG_GC
77 fprintf(stderr, "FREE iter(#%d) rc=%d %p\n", iter->zi.std.handle, GC_REFCOUNT(&iter->zi.std), iter);
78 #endif
79 if (!Z_ISUNDEF(iter->current_val)) {
80 zval_ptr_dtor(&iter->current_val);
81 ZVAL_UNDEF(&iter->current_val);
82 }
83 }
84
85 static void php_pqres_iterator_dtor(zend_object_iterator *i)
86 {
87 php_pqres_iterator_dtor_ex(i);
88 zval_ptr_dtor(&i->data);
89 }
90
91 static void php_pqres_internal_iterator_dtor(php_pqres_object_t *obj)
92 {
93 if (obj->intern && obj->intern->iter) {
94 php_pqres_iterator_dtor_ex((zend_object_iterator *) obj->intern->iter);
95 efree(obj->intern->iter);
96 obj->intern->iter = NULL;
97 }
98 }
99
100 static ZEND_RESULT_CODE php_pqres_iterator_valid(zend_object_iterator *i)
101 {
102 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
103 php_pqres_object_t *obj = PHP_PQ_OBJ(&i->data, NULL);
104
105 switch (PQresultStatus(obj->intern->res)) {
106 case PGRES_TUPLES_OK:
107 #ifdef HAVE_PGRES_SINGLE_TUPLE
108 case PGRES_SINGLE_TUPLE:
109 #endif
110 if (PQntuples(obj->intern->res) <= iter->index) {
111 return FAILURE;
112 }
113 break;
114 default:
115 return FAILURE;
116 }
117
118 return SUCCESS;
119 }
120
121 #define PHP_PQRES_JSON_OPTIONS(res) \
122 (php_pqres_fetch_type(res) != PHP_PQRES_FETCH_OBJECT ? PHP_JSON_OBJECT_AS_ARRAY:0)
123
124 zval *php_pqres_typed_zval(php_pqres_t *res, Oid typ, zval *zv)
125 {
126 zval *zconv;
127 HashTable *ht;
128 zend_string *str;
129
130 if ((zconv = zend_hash_index_find(&res->converters, typ))) {
131 zval ztype, rv;
132
133 ZVAL_NULL(&rv);
134 ZVAL_LONG(&ztype, typ);
135 php_pq_call_method(zconv, "convertfromstring", 2, &rv, zv, &ztype);
136
137 zval_ptr_dtor(zv);
138 ZVAL_ZVAL(zv, &rv, 0, 0);
139
140 return zv;
141 }
142
143 str = zval_get_string(zv);
144 zval_ptr_dtor(zv);
145
146 switch (typ) {
147 case PHP_PQ_OID_BOOL:
148 if (!(res->auto_convert & PHP_PQRES_CONV_BOOL)) {
149 goto noconversion;
150 }
151 ZVAL_BOOL(zv, *str->val == 't');
152 break;
153
154 case PHP_PQ_OID_INT8:
155 case PHP_PQ_OID_TID:
156 case PHP_PQ_OID_INT4:
157 case PHP_PQ_OID_INT2:
158 case PHP_PQ_OID_XID:
159 case PHP_PQ_OID_OID:
160 if (!(res->auto_convert & PHP_PQRES_CONV_INT)) {
161 goto noconversion;
162 }
163 {
164 zend_long lval;
165 double dval;
166
167 switch (is_numeric_str_function(str, &lval, &dval)) {
168 case IS_LONG:
169 ZVAL_LONG(zv, lval);
170 break;
171 case IS_DOUBLE:
172 ZVAL_DOUBLE(zv, dval);
173 break;
174 default:
175 goto noconversion;
176 }
177 }
178 break;
179
180 case PHP_PQ_OID_FLOAT4:
181 case PHP_PQ_OID_FLOAT8:
182 if (!(res->auto_convert & PHP_PQRES_CONV_FLOAT)) {
183 goto noconversion;
184 }
185 ZVAL_DOUBLE(zv, zend_strtod(str->val, NULL));
186 break;
187
188 case PHP_PQ_OID_DATE:
189 if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
190 goto noconversion;
191 }
192 php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d", NULL);
193 break;
194 #ifdef PHP_PQ_OID_ABSTIME
195 case PHP_PQ_OID_ABSTIME:
196 if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
197 goto noconversion;
198 }
199 php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s", NULL);
200 break;
201 #endif
202 case PHP_PQ_OID_TIMESTAMP:
203 if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
204 goto noconversion;
205 }
206 php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.u", NULL);
207 break;
208
209 case PHP_PQ_OID_TIMESTAMPTZ:
210 if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
211 goto noconversion;
212 }
213 php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.uO", NULL);
214 break;
215
216 #ifdef PHP_PQ_OID_JSON
217 # ifdef PHP_PQ_OID_JSONB
218 case PHP_PQ_OID_JSONB:
219 # endif
220 case PHP_PQ_OID_JSON:
221 if (!(res->auto_convert & PHP_PQRES_CONV_JSON)) {
222 goto noconversion;
223 }
224 php_json_decode_ex(zv, str->val, str->len, PHP_PQRES_JSON_OPTIONS(res), 512 /* PHP_JSON_DEFAULT_DEPTH */);
225 break;
226 #endif
227
228 case PHP_PQ_OID_BYTEA:
229 if (!(res->auto_convert & PHP_PQRES_CONV_BYTEA)) {
230 goto noconversion;
231 } else {
232 size_t to_len;
233 char *to_str = (char *) PQunescapeBytea((unsigned char *) str->val, &to_len);
234
235 if (!to_str) {
236 ZVAL_NULL(zv);
237 php_error_docref(NULL, E_WARNING, "Failed to unsescape BYTEA: '%s'", str->val);
238 } else {
239 ZVAL_STRINGL(zv, to_str, to_len);
240 PQfreemem(to_str);
241 }
242 }
243 break;
244
245 default:
246 if (!(res->auto_convert & PHP_PQRES_CONV_ARRAY)) {
247 goto noconversion;
248 }
249 if (PHP_PQ_TYPE_IS_ARRAY(typ) && (ht = php_pq_parse_array(res, str->val, str->len, PHP_PQ_TYPE_OF_ARRAY(typ)))) {
250 ZVAL_ARR(zv, ht);
251 } else {
252 goto noconversion;
253 }
254 break;
255 }
256
257 zend_string_release(str);
258 return zv;
259
260 noconversion:
261 ZVAL_STR(zv, str);
262 return zv;
263 }
264
265 static inline zval *php_pqres_get_col(php_pqres_t *r, unsigned row, unsigned col, zval *zv)
266 {
267 if (PQgetisnull(r->res, row, col)) {
268 ZVAL_NULL(zv);
269 } else {
270 ZVAL_STRINGL(zv, PQgetvalue(r->res, row, col), PQgetlength(r->res, row, col));
271 zv = php_pqres_typed_zval(r, PQftype(r->res, col), zv);
272 }
273
274 return zv;
275 }
276
277 static inline void php_pqres_add_col_to_zval(php_pqres_t *r, unsigned row, unsigned col, php_pqres_fetch_t fetch_type, zval *data)
278 {
279 if (PQgetisnull(r->res, row, col)) {
280 switch (fetch_type) {
281 case PHP_PQRES_FETCH_OBJECT:
282 add_property_null(data, PQfname(r->res, col));
283 break;
284
285 case PHP_PQRES_FETCH_ASSOC:
286 add_assoc_null(data, PQfname(r->res, col));
287 break;
288
289 case PHP_PQRES_FETCH_ARRAY:
290 add_index_null(data, col);
291 break;
292 }
293 } else {
294 zval zv;
295
296 ZVAL_STRINGL(&zv, PQgetvalue(r->res, row, col), PQgetlength(r->res, row, col));
297 php_pqres_typed_zval(r, PQftype(r->res, col), &zv);
298
299 switch (fetch_type) {
300 case PHP_PQRES_FETCH_OBJECT:
301 add_property_zval(data, PQfname(r->res, col), &zv);
302 zval_ptr_dtor(&zv);
303 break;
304
305 case PHP_PQRES_FETCH_ASSOC:
306 add_assoc_zval(data, PQfname(r->res, col), &zv);
307 break;
308
309 case PHP_PQRES_FETCH_ARRAY:
310 add_index_zval(data, col, &zv);
311 break;
312 }
313 }
314 }
315
316 zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval *data)
317 {
318 int c, cols = PQnfields(res);
319 php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event);
320
321 if (Z_TYPE_P(data) != IS_OBJECT && Z_TYPE_P(data) != IS_ARRAY) {
322 if (PHP_PQRES_FETCH_OBJECT == fetch_type) {
323 object_init(data);
324 } else {
325 array_init_size(data, cols);
326 }
327 }
328
329 if (PQntuples(res) > row) {
330 for (c = 0; c < cols; ++c) {
331 php_pqres_add_col_to_zval(res_obj->intern, row, c, fetch_type, data);
332 }
333 }
334
335 return data;
336 }
337
338 static zval *php_pqres_iterator_current(zend_object_iterator *i)
339 {
340 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
341 php_pqres_object_t *obj = PHP_PQ_OBJ(&i->data, NULL);
342
343 if (Z_ISUNDEF(iter->current_val)) {
344 php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, &iter->current_val);
345 }
346 return &iter->current_val;
347 }
348
349 static void php_pqres_iterator_key(zend_object_iterator *i, zval *key)
350 {
351 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
352
353 ZVAL_LONG(key, iter->index);
354 }
355
356 static void php_pqres_iterator_invalidate(zend_object_iterator *i)
357 {
358 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
359
360 if (!Z_ISUNDEF(iter->current_val)) {
361 zval_ptr_dtor(&iter->current_val);
362 ZVAL_UNDEF(&iter->current_val);
363 }
364 }
365
366 static void php_pqres_iterator_next(zend_object_iterator *i)
367 {
368 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
369
370 php_pqres_iterator_invalidate(i);
371 ++iter->index;
372 }
373
374 static void php_pqres_iterator_rewind(zend_object_iterator *i)
375 {
376 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
377
378 php_pqres_iterator_invalidate(i);
379 iter->index = 0;
380 }
381
382 static zend_object_iterator_funcs php_pqres_iterator_funcs = {
383 php_pqres_iterator_dtor,
384 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
385 php_pqres_iterator_valid,
386 /* fetch the item data for the current element */
387 php_pqres_iterator_current,
388 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
389 php_pqres_iterator_key,
390 /* step forwards to next element */
391 php_pqres_iterator_next,
392 /* rewind to start of data (optional, may be NULL) */
393 php_pqres_iterator_rewind,
394 /* invalidate current value/key (optional, may be NULL) */
395 php_pqres_iterator_invalidate
396 #if PHP_VERSION_ID >= 80000
397 , NULL
398 #endif
399 };
400
401 static inline ZEND_RESULT_CODE php_pqres_count_elements_ex(zend_object *object, zend_long *count)
402 {
403 php_pqres_object_t *obj = PHP_PQ_OBJ(NULL, object);
404
405 if (!obj->intern) {
406 return FAILURE;
407 } else {
408 *count = (zend_long) PQntuples(obj->intern->res);
409 return SUCCESS;
410 }
411 }
412 #if PHP_VERSION_ID >= 80000
413 static ZEND_RESULT_CODE php_pqres_count_elements(zend_object *object, zend_long *count)
414 {
415 return php_pqres_count_elements_ex(object, count);
416 }
417 #else
418 static ZEND_RESULT_CODE php_pqres_count_elements(zval *object, zend_long *count)
419 {
420 return php_pqres_count_elements_ex(Z_OBJ_P(object), count);
421 }
422 #endif
423
424 ZEND_RESULT_CODE php_pqres_success(PGresult *res)
425 {
426 zval zexc, zsqlstate;
427
428 switch (PQresultStatus(res)) {
429 case PGRES_BAD_RESPONSE:
430 case PGRES_NONFATAL_ERROR:
431 case PGRES_FATAL_ERROR:
432 ZVAL_OBJ(&zexc, throw_exce(EX_SQL, "%s", PHP_PQresultErrorMessage(res)));
433 ZVAL_STRING(&zsqlstate, PQresultErrorField(res, PG_DIAG_SQLSTATE));
434 php_pq_update_property(&zexc, "sqlstate", &zsqlstate);
435 zval_ptr_dtor(&zsqlstate);
436 return FAILURE;
437 default:
438 return SUCCESS;
439 }
440 }
441
442 php_pqres_object_t *php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *conn_obj)
443 {
444 php_pqres_object_t *obj;
445 php_pqres_t *r = ecalloc(1, sizeof(*r));
446
447 r->res = res;
448 zend_hash_init(&r->bound, 0, 0, ZVAL_PTR_DTOR, 0);
449 zend_hash_init(&r->converters, zend_hash_num_elements(&conn_obj->intern->converters), 0, ZVAL_PTR_DTOR, 0);
450 zend_hash_copy(&r->converters, &conn_obj->intern->converters, (copy_ctor_func_t) zval_add_ref);
451
452 r->auto_convert = conn_obj->intern->default_auto_convert;
453 r->default_fetch_type = conn_obj->intern->default_fetch_type;
454
455 obj = php_pqres_create_object_ex(php_pqres_class_entry, r);
456 PQresultSetInstanceData(res, php_pqconn_event, obj);
457
458 return obj;
459 }
460
461 php_pqres_fetch_t php_pqres_fetch_type(php_pqres_t *res)
462 {
463 return res->iter ? res->iter->fetch_type : res->default_fetch_type;
464 }
465
466 static void php_pqres_object_free(zend_object *o)
467 {
468 php_pqres_object_t *obj = PHP_PQ_OBJ(NULL, o);
469
470 if (obj->intern) {
471 if (obj->intern->res) {
472 PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL);
473 PQclear(obj->intern->res);
474 obj->intern->res = NULL;
475 }
476
477 php_pqres_internal_iterator_dtor(obj);
478
479 zend_hash_destroy(&obj->intern->bound);
480 zend_hash_destroy(&obj->intern->converters);
481
482 efree(obj->intern);
483 obj->intern = NULL;
484 }
485 php_pq_object_dtor(o);
486 }
487
488 php_pqres_object_t *php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern)
489 {
490 return php_pq_object_create(ce, intern, sizeof(php_pqres_object_t),
491 &php_pqres_object_handlers, &php_pqres_object_prophandlers);
492 }
493
494 static zend_object *php_pqres_create_object(zend_class_entry *class_type)
495 {
496 return &php_pqres_create_object_ex(class_type, NULL)->zo;
497 }
498
499 static void php_pqres_object_read_status(void *o, zval *return_value)
500 {
501 php_pqres_object_t *obj = o;
502
503 RETVAL_LONG(PQresultStatus(obj->intern->res));
504 }
505
506 static void php_pqres_object_read_status_message(void *o, zval *return_value)
507 {
508 php_pqres_object_t *obj = o;
509
510 RETVAL_STRING(PQresStatus(PQresultStatus(obj->intern->res))+sizeof("PGRES"));
511 }
512
513 static void php_pqres_object_read_error_message(void *o, zval *return_value)
514 {
515 php_pqres_object_t *obj = o;
516 char *error = PHP_PQresultErrorMessage(obj->intern->res);
517
518 if (error) {
519 RETVAL_STRING(error);
520 } else {
521 RETVAL_NULL();
522 }
523 }
524
525 #ifndef PG_DIAG_SEVERITY
526 # define PG_DIAG_SEVERITY 'S'
527 #endif
528 #ifndef PG_DIAG_SQLSTATE
529 # define PG_DIAG_SQLSTATE 'C'
530 #endif
531 #ifndef PG_DIAG_MESSAGE_PRIMARY
532 # define PG_DIAG_MESSAGE_PRIMARY 'M'
533 #endif
534 #ifndef PG_DIAG_MESSAGE_DETAIL
535 # define PG_DIAG_MESSAGE_DETAIL 'D'
536 #endif
537 #ifndef PG_DIAG_MESSAGE_HINT
538 # define PG_DIAG_MESSAGE_HINT 'H'
539 #endif
540 #ifndef PG_DIAG_STATEMENT_POSITION
541 # define PG_DIAG_STATEMENT_POSITION 'P'
542 #endif
543 #ifndef PG_DIAG_INTERNAL_POSITION
544 # define PG_DIAG_INTERNAL_POSITION 'p'
545 #endif
546 #ifndef PG_DIAG_INTERNAL_QUERY
547 # define PG_DIAG_INTERNAL_QUERY 'q'
548 #endif
549 #ifndef PG_DIAG_CONTEXT
550 # define PG_DIAG_CONTEXT 'W'
551 #endif
552 #ifndef PG_DIAG_SCHEMA_NAME
553 # define PG_DIAG_SCHEMA_NAME 's'
554 #endif
555 #ifndef PG_DIAG_TABLE_NAME
556 # define PG_DIAG_TABLE_NAME 't'
557 #endif
558 #ifndef PG_DIAG_COLUMN_NAME
559 # define PG_DIAG_COLUMN_NAME 'c'
560 #endif
561 #ifndef PG_DIAG_DATATYPE_NAME
562 # define PG_DIAG_DATATYPE_NAME 'd'
563 #endif
564 #ifndef PG_DIAG_CONSTRAINT_NAME
565 # define PG_DIAG_CONSTRAINT_NAME 'n'
566 #endif
567 #ifndef PG_DIAG_SOURCE_FILE
568 # define PG_DIAG_SOURCE_FILE 'F'
569 #endif
570 #ifndef PG_DIAG_SOURCE_LINE
571 # define PG_DIAG_SOURCE_LINE 'L'
572 #endif
573 #ifndef PG_DIAG_SOURCE_FUNCTION
574 # define PG_DIAG_SOURCE_FUNCTION 'R'
575 #endif
576
577 static void php_pqres_object_read_diag(void *o, zval *return_value)
578 {
579 php_pqres_object_t *obj = o;
580 int i;
581 struct {
582 char code;
583 const char *const name;
584 } diag[] = {
585 {PG_DIAG_SEVERITY, "severity"},
586 {PG_DIAG_SQLSTATE, "sqlstate"},
587 {PG_DIAG_MESSAGE_PRIMARY, "message_primary"},
588 {PG_DIAG_MESSAGE_DETAIL, "message_detail"},
589 {PG_DIAG_MESSAGE_HINT, "message_hint"},
590 {PG_DIAG_STATEMENT_POSITION,"statement_position"},
591 {PG_DIAG_INTERNAL_POSITION, "internal_position"},
592 {PG_DIAG_INTERNAL_QUERY, "internal_query"},
593 {PG_DIAG_CONTEXT, "context"},
594 {PG_DIAG_SCHEMA_NAME, "schema_name"},
595 {PG_DIAG_TABLE_NAME, "table_name"},
596 {PG_DIAG_COLUMN_NAME, "column_name"},
597 {PG_DIAG_DATATYPE_NAME, "datatype_name"},
598 {PG_DIAG_CONSTRAINT_NAME, "constraint_name"},
599 {PG_DIAG_SOURCE_FILE, "source_file"},
600 {PG_DIAG_SOURCE_LINE, "source_line"},
601 {PG_DIAG_SOURCE_FUNCTION, "source_function"},
602 };
603
604 array_init_size(return_value, 32);
605 for (i = 0; i < sizeof(diag)/sizeof(diag[0]); ++i) {
606 char *value = PQresultErrorField(obj->intern->res, diag[i].code);
607
608 if (value) {
609 add_assoc_string(return_value, diag[i].name, value);
610 } else {
611 add_assoc_null(return_value, diag[i].name);
612 }
613 }
614 }
615
616 static void php_pqres_object_read_num_rows(void *o, zval *return_value)
617 {
618 php_pqres_object_t *obj = o;
619
620 RETVAL_LONG(PQntuples(obj->intern->res));
621 }
622
623 static void php_pqres_object_read_num_cols(void *o, zval *return_value)
624 {
625 php_pqres_object_t *obj = o;
626
627 RETVAL_LONG(PQnfields(obj->intern->res));
628 }
629
630 static void php_pqres_object_read_affected_rows(void *o, zval *return_value)
631 {
632 php_pqres_object_t *obj = o;
633
634 RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res)));
635 }
636
637 static void php_pqres_object_read_fetch_type(void *o, zval *return_value)
638 {
639 php_pqres_object_t *obj = o;
640
641 RETVAL_LONG(php_pqres_fetch_type(obj->intern));
642 }
643
644 static void php_pqres_object_write_fetch_type(void *o, zval *value)
645 {
646 php_pqres_object_t *obj = o;
647
648 if (!obj->intern->iter) {
649 zval object;
650
651 ZVAL_OBJ(&object, &obj->zo);
652 php_pqres_internal_iterator_init(&object);
653 }
654 obj->intern->iter->fetch_type = zval_get_long(value);
655 }
656
657 static void php_pqres_object_read_auto_conv(void *o, zval *return_value)
658 {
659 php_pqres_object_t *obj = o;
660
661 RETVAL_LONG(obj->intern->auto_convert);
662 }
663
664 static void php_pqres_object_write_auto_conv(void *o, zval *value)
665 {
666 php_pqres_object_t *obj = o;
667
668 obj->intern->auto_convert = zval_get_long(value);
669 }
670
671 static ZEND_RESULT_CODE php_pqres_iteration(zval *zobj, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval *row)
672 {
673 ZEND_RESULT_CODE rv;
674 php_pqres_fetch_t orig_fetch;
675
676 if (!obj) {
677 obj = PHP_PQ_OBJ(zobj, NULL);
678 }
679
680 if (obj->intern->iter) {
681 obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter);
682 } else {
683 php_pqres_internal_iterator_init(zobj);
684 }
685 orig_fetch = obj->intern->iter->fetch_type;
686 obj->intern->iter->fetch_type = fetch_type;
687 if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter))) {
688 zval *tmp = obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter);
689 ZVAL_COPY_VALUE(row, tmp);
690 }
691 obj->intern->iter->fetch_type = orig_fetch;
692
693 return rv;
694 }
695
696 typedef struct php_pqres_col {
697 char *name;
698 int num;
699 } php_pqres_col_t;
700
701 static ZEND_RESULT_CODE column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *col)
702 {
703 zend_long index = -1;
704 char *name = NULL;
705
706 if (!zcol) {
707 index = 0;
708 } else {
709 switch (Z_TYPE_P(zcol)) {
710 case IS_NULL:
711 index = 0;
712 break;
713
714 case IS_LONG:
715 index = Z_LVAL_P(zcol);
716 break;
717
718 default:
719 convert_to_string(zcol);
720 /* no break */
721
722 case IS_STRING:
723 if (!is_numeric_string(Z_STRVAL_P(zcol), Z_STRLEN_P(zcol), &index, NULL, 0)) {
724 name = Z_STRVAL_P(zcol);
725 }
726 break;
727 }
728 }
729
730 if (name) {
731 col->name = name;
732 col->num = PQfnumber(obj->intern->res, name);
733 } else {
734 col->name = PQfname(obj->intern->res, index);
735 col->num = index;
736 }
737
738 if (!col->name) {
739 php_error_docref(NULL, E_WARNING, "Failed to find column at index " ZEND_LONG_FMT, index);
740 return FAILURE;
741 }
742 if (col->num == -1) {
743 php_error_docref(NULL, E_WARNING, "Failed to find column with name '%s'", name);
744 return FAILURE;
745 }
746 return SUCCESS;
747 }
748
749 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind, 0, 0, 2)
750 ZEND_ARG_INFO(0, col)
751 ZEND_ARG_INFO(1, ref)
752 ZEND_END_ARG_INFO();
753 static PHP_METHOD(pqres, bind) {
754 zval *zcol, *zref;
755 zend_error_handling zeh;
756 ZEND_RESULT_CODE rv;
757
758 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
759 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z/z", &zcol, &zref);
760 zend_restore_error_handling(&zeh);
761
762 if (SUCCESS == rv) {
763 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
764
765 if (!obj->intern) {
766 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
767 } else {
768 php_pqres_col_t col;
769
770 if (SUCCESS != column_nn(obj, zcol, &col)) {
771 RETVAL_FALSE;
772 } else {
773 Z_TRY_ADDREF_P(zref);
774
775 if (!zend_hash_index_update(&obj->intern->bound, col.num, zref)) {
776 php_error_docref(NULL, E_WARNING, "Failed to bind column %s@%d", col.name, col.num);
777 RETVAL_FALSE;
778 } else {
779 zend_hash_sort(&obj->intern->bound, php_pq_compare_index, 0);
780 RETVAL_TRUE;
781 }
782 }
783 }
784 }
785 }
786
787 static int apply_bound(zval *zbound, int argc, va_list argv, zend_hash_key *key)
788 {
789 zval *zvalue;
790 zval *zrow = va_arg(argv, zval *);
791 ZEND_RESULT_CODE *rv = va_arg(argv, ZEND_RESULT_CODE *);
792
793 if (!(zvalue = zend_hash_index_find(Z_ARRVAL_P(zrow), key->h))) {
794 php_error_docref(NULL, E_WARNING, "Failed to find column ad index " ZEND_ULONG_FMT, key->h);
795 *rv = FAILURE;
796 return ZEND_HASH_APPLY_STOP;
797 } else {
798 ZVAL_DEREF(zbound);
799 zval_dtor(zbound);
800 ZVAL_COPY(zbound, zvalue);
801 *rv = SUCCESS;
802 return ZEND_HASH_APPLY_KEEP;
803 }
804 }
805
806 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound, 0, 0, 0)
807 ZEND_END_ARG_INFO();
808 static PHP_METHOD(pqres, fetchBound) {
809 zend_error_handling zeh;
810 ZEND_RESULT_CODE rv;
811
812 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
813 rv = zend_parse_parameters_none();
814 zend_restore_error_handling(&zeh);
815
816 if (SUCCESS == rv) {
817 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
818
819 if (!obj->intern) {
820 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
821 } else {
822 zval row;
823
824 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh);
825 if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row)) {
826 zend_hash_apply_with_arguments(&obj->intern->bound, apply_bound, 2, &row, &rv);
827
828 if (SUCCESS == rv) {
829 RETVAL_ZVAL(&row, 1, 0);
830 }
831 }
832 zend_restore_error_handling(&zeh);
833 }
834 }
835 }
836
837 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
838 ZEND_ARG_INFO(0, fetch_type)
839 ZEND_END_ARG_INFO();
840 static PHP_METHOD(pqres, fetchRow) {
841 zend_error_handling zeh;
842 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
843 zend_long fetch_type = -1;
844 ZEND_RESULT_CODE rv;
845
846 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
847 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type);
848 zend_restore_error_handling(&zeh);
849
850 if (SUCCESS == rv) {
851 if (!obj->intern) {
852 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
853 } else {
854 zval row;
855
856 if (fetch_type == -1) {
857 fetch_type = php_pqres_fetch_type(obj->intern);
858 }
859
860 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh);
861 if (SUCCESS == php_pqres_iteration(getThis(), obj, fetch_type, &row)) {
862 RETVAL_ZVAL(&row, 1, 0);
863 }
864 zend_restore_error_handling(&zeh);
865 }
866 }
867 }
868
869 static zval *column_at(zval *row, int col)
870 {
871 zval *data = NULL;
872 HashTable *ht = HASH_OF(row);
873 int count = zend_hash_num_elements(ht);
874
875 if (col >= count) {
876 php_error_docref(NULL, E_WARNING, "Column index %d exceeds column count %d", col, count);
877 } else {
878 zend_hash_internal_pointer_reset(ht);
879 while (col-- > 0) {
880 zend_hash_move_forward(ht);
881 }
882 data = zend_hash_get_current_data(ht);
883 }
884 return data;
885 }
886
887 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 1)
888 ZEND_ARG_INFO(1, ref)
889 ZEND_ARG_INFO(0, col)
890 ZEND_END_ARG_INFO();
891 static PHP_METHOD(pqres, fetchCol) {
892 zend_error_handling zeh;
893 zval *zcol = NULL, *zref;
894 ZEND_RESULT_CODE rv;
895
896 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
897 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z|z/!", &zref, &zcol);
898 zend_restore_error_handling(&zeh);
899
900 if (SUCCESS == rv) {
901 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
902
903 if (!obj->intern) {
904 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
905 } else {
906 zval row;
907
908 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh);
909 if (SUCCESS == php_pqres_iteration(getThis(), obj, php_pqres_fetch_type(obj->intern), &row)) {
910 php_pqres_col_t col;
911
912 if (SUCCESS != column_nn(obj, zcol, &col)) {
913 RETVAL_FALSE;
914 } else {
915 zval *zres = column_at(&row, col.num);
916
917 if (!zres) {
918 RETVAL_FALSE;
919 } else {
920 ZVAL_DEREF(zref);
921 zval_dtor(zref);
922 ZVAL_ZVAL(zref, zres, 1, 0);
923 RETVAL_TRUE;
924 }
925 }
926 }
927 zend_restore_error_handling(&zeh);
928 }
929 }
930 }
931
932 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all_cols, 0, 0, 0)
933 ZEND_ARG_INFO(0, col)
934 ZEND_END_ARG_INFO();
935 static PHP_METHOD(pqres, fetchAllCols) {
936 zend_error_handling zeh;
937 zval *zcol = NULL;
938 ZEND_RESULT_CODE rv;
939
940 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
941 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zcol);
942 zend_restore_error_handling(&zeh);
943
944 if (SUCCESS == rv) {
945 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
946
947 if (!obj->intern) {
948 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
949 } else {
950 php_pqres_col_t col;
951
952 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh);
953 if (SUCCESS == column_nn(obj, zcol, &col)) {
954 int r, rows = PQntuples(obj->intern->res);
955 zval tmp;
956
957 array_init(return_value);
958 for (r = 0; r < rows; ++r) {
959 add_next_index_zval(return_value, php_pqres_get_col(obj->intern, r, col.num, &tmp));
960 }
961 }
962 zend_restore_error_handling(&zeh);
963 }
964 }
965 }
966
967 struct apply_to_col_arg {
968 php_pqres_object_t *obj;
969 php_pqres_col_t *cols;
970 ZEND_RESULT_CODE status;
971 };
972
973 static int apply_to_col(zval *c, void *a)
974 {
975 struct apply_to_col_arg *arg = a;
976
977 if (SUCCESS != column_nn(arg->obj, c, arg->cols)) {
978 arg->status = FAILURE;
979 return ZEND_HASH_APPLY_STOP;
980 } else {
981 arg->status = SUCCESS;
982 ++arg->cols;
983 return ZEND_HASH_APPLY_KEEP;
984 }
985 }
986
987 static php_pqres_col_t *php_pqres_convert_to_cols(php_pqres_object_t *obj, HashTable *ht)
988 {
989 struct apply_to_col_arg arg = {NULL};
990 php_pqres_col_t *tmp;
991
992 arg.obj = obj;
993 arg.cols = ecalloc(zend_hash_num_elements(ht), sizeof(*tmp));
994 tmp = arg.cols;
995 zend_hash_apply_with_argument(ht, apply_to_col, &arg);
996
997 if (SUCCESS == arg.status) {
998 return tmp;
999 } else {
1000 efree(tmp);
1001 return NULL;
1002 }
1003 }
1004
1005 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_map, 0, 0, 0)
1006 ZEND_ARG_INFO(0, keys)
1007 ZEND_ARG_INFO(0, vals)
1008 ZEND_ARG_INFO(0, fetch_type)
1009 ZEND_END_ARG_INFO();
1010 static PHP_METHOD(pqres, map) {
1011 zend_error_handling zeh;
1012 zval *zkeys = 0, *zvals = 0;
1013 zend_long fetch_type = -1;
1014 ZEND_RESULT_CODE rv;
1015
1016 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1017 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|z/!z/!l", &zkeys, &zvals, &fetch_type);
1018 zend_restore_error_handling(&zeh);
1019
1020 if (SUCCESS == rv) {
1021 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1022
1023 if (!obj->intern) {
1024 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
1025 } else {
1026 int ks = 0, vs = 0;
1027 php_pqres_col_t def = {PQfname(obj->intern->res, 0), 0}, *keys = NULL, *vals = NULL;
1028
1029 if (zkeys) {
1030 convert_to_array(zkeys);
1031
1032 if ((ks = zend_hash_num_elements(Z_ARRVAL_P(zkeys)))) {
1033 keys = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zkeys));
1034 } else {
1035 ks = 1;
1036 keys = &def;
1037 }
1038 } else {
1039 ks = 1;
1040 keys = &def;
1041 }
1042 if (zvals) {
1043 convert_to_array(zvals);
1044
1045 if ((vs = zend_hash_num_elements(Z_ARRVAL_P(zvals)))) {
1046 vals = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zvals));
1047 }
1048 }
1049
1050 if (fetch_type == -1) {
1051 fetch_type = php_pqres_fetch_type(obj->intern);
1052 }
1053
1054 if (keys) {
1055 int rows, r;
1056 zval *cur;
1057
1058 switch (fetch_type) {
1059 case PHP_PQRES_FETCH_ARRAY:
1060 case PHP_PQRES_FETCH_ASSOC:
1061 array_init(return_value);
1062 break;
1063 case PHP_PQRES_FETCH_OBJECT:
1064 object_init(return_value);
1065 break;
1066 }
1067 for (r = 0, rows = PQntuples(obj->intern->res); r < rows; ++r) {
1068 int k, v;
1069 zval *ptr;
1070
1071 cur = return_value;
1072 for (k = 0; k < ks; ++k) {
1073 char *key = PQgetvalue(obj->intern->res, r, keys[k].num);
1074 int len = PQgetlength(obj->intern->res, r, keys[k].num);
1075
1076 if (!(ptr = zend_symtable_str_find(HASH_OF(cur), key, len))) {
1077 zval tmp;
1078
1079 switch (fetch_type) {
1080 case PHP_PQRES_FETCH_ARRAY:
1081 case PHP_PQRES_FETCH_ASSOC:
1082 array_init(&tmp);
1083 break;
1084 case PHP_PQRES_FETCH_OBJECT:
1085 object_init(&tmp);
1086 break;
1087 }
1088 if (!(ptr = zend_symtable_str_update(HASH_OF(cur), key, len, &tmp))) {
1089 throw_exce(EX_RUNTIME, "Failed to create map");
1090 goto err;
1091 }
1092 cur = ptr;
1093 }
1094 cur = ptr;
1095 }
1096 if (vals && vs) {
1097 for (v = 0; v < vs; ++v) {
1098 char *val = PQgetvalue(obj->intern->res, r, vals[v].num);
1099 int len = PQgetlength(obj->intern->res, r, vals[v].num);
1100
1101 switch (fetch_type) {
1102 case PHP_PQRES_FETCH_ARRAY:
1103 add_index_stringl(cur, vals[v].num, val, len);
1104 break;
1105 case PHP_PQRES_FETCH_ASSOC:
1106 add_assoc_stringl(cur, vals[v].name, val, len);
1107 break;
1108 case PHP_PQRES_FETCH_OBJECT:
1109 add_property_stringl(cur, vals[v].name, val, len);
1110 break;
1111 }
1112 }
1113 } else {
1114 php_pqres_row_to_zval(obj->intern->res, r, fetch_type, cur);
1115 }
1116 }
1117 }
1118
1119 err:
1120 if (keys && keys != &def) {
1121 efree(keys);
1122 }
1123 if (vals) {
1124 efree(vals);
1125 }
1126 }
1127 }
1128 }
1129
1130 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all, 0, 0, 0)
1131 ZEND_ARG_INFO(0, fetch_type)
1132 ZEND_END_ARG_INFO();
1133 static PHP_METHOD(pqres, fetchAll) {
1134 zend_error_handling zeh;
1135 zend_long fetch_type = -1;
1136 ZEND_RESULT_CODE rv;
1137
1138 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1139 rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type);
1140 zend_restore_error_handling(&zeh);
1141
1142 if (SUCCESS == rv) {
1143 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1144
1145 if (!obj->intern) {
1146 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
1147 } else {
1148 int r, rows = PQntuples(obj->intern->res);
1149 zval tmp;
1150
1151 if (fetch_type == -1) {
1152 fetch_type = php_pqres_fetch_type(obj->intern);
1153 }
1154
1155 array_init(return_value);
1156 for (r = 0; r < rows; ++r) {
1157 ZVAL_NULL(&tmp);
1158 add_next_index_zval(return_value, php_pqres_row_to_zval(obj->intern->res, r, fetch_type, &tmp));
1159 }
1160 }
1161 }
1162 }
1163
1164 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_pqres_count, 0, 0, IS_LONG, 0)
1165 ZEND_END_ARG_INFO();
1166 static PHP_METHOD(pqres, count) {
1167 zend_error_handling zeh;
1168 ZEND_RESULT_CODE rv;
1169
1170 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1171 rv = zend_parse_parameters_none();
1172 zend_restore_error_handling(&zeh);
1173
1174 if (SUCCESS == rv) {
1175 zend_long count;
1176
1177 if (SUCCESS != php_pqres_count_elements_ex(Z_OBJ_P(getThis()), &count)) {
1178 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
1179 } else {
1180 RETVAL_LONG(count);
1181 }
1182 }
1183 }
1184
1185 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_desc, 0, 0, 0)
1186 ZEND_END_ARG_INFO();
1187 static PHP_METHOD(pqres, desc) {
1188 zend_error_handling zeh;
1189 ZEND_RESULT_CODE rv;
1190
1191 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1192 rv = zend_parse_parameters_none();
1193 zend_restore_error_handling(&zeh);
1194
1195 if (SUCCESS == rv) {
1196 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1197
1198 if (!obj->intern) {
1199 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
1200 } else {
1201 int p, params;
1202
1203 array_init(return_value);
1204 for (p = 0, params = PQnparams(obj->intern->res); p < params; ++p) {
1205 add_next_index_long(return_value, PQparamtype(obj->intern->res, p));
1206 }
1207 }
1208 }
1209 }
1210
1211 #if PHP_VERSION_ID >= 80000
1212 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(ai_pqres_getIterator, 0, 0, Traversable, 0)
1213 ZEND_END_ARG_INFO();
1214 static PHP_METHOD(pqres, getIterator)
1215 {
1216 zend_error_handling zeh;
1217 ZEND_RESULT_CODE rv;
1218
1219 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh);
1220 rv = zend_parse_parameters_none();
1221 zend_restore_error_handling(&zeh);
1222
1223 if (SUCCESS == rv) {
1224 php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL);
1225
1226 if (!obj->intern) {
1227 throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
1228 } else {
1229 zend_create_internal_iterator_zval(return_value, getThis());
1230 }
1231 }
1232 }
1233 #endif
1234
1235 static zend_function_entry php_pqres_methods[] = {
1236 PHP_ME(pqres, bind, ai_pqres_bind, ZEND_ACC_PUBLIC)
1237 PHP_ME(pqres, fetchBound, ai_pqres_fetch_bound, ZEND_ACC_PUBLIC)
1238 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
1239 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
1240 PHP_ME(pqres, fetchAll, ai_pqres_fetch_all, ZEND_ACC_PUBLIC)
1241 PHP_ME(pqres, fetchAllCols, ai_pqres_fetch_all_cols, ZEND_ACC_PUBLIC)
1242 PHP_ME(pqres, count, ai_pqres_count, ZEND_ACC_PUBLIC)
1243 PHP_ME(pqres, map, ai_pqres_map, ZEND_ACC_PUBLIC)
1244 PHP_ME(pqres, desc, ai_pqres_desc, ZEND_ACC_PUBLIC)
1245 #if PHP_VERSION_ID >= 80000
1246 PHP_ME(pqres, getIterator, ai_pqres_getIterator, ZEND_ACC_PUBLIC)
1247 #endif
1248 {0}
1249 };
1250
1251 PHP_MSHUTDOWN_FUNCTION(pqres)
1252 {
1253 zend_hash_destroy(&php_pqres_object_prophandlers);
1254 return SUCCESS;
1255 }
1256
1257 PHP_MINIT_FUNCTION(pqres)
1258 {
1259 zend_class_entry ce = {0};
1260 php_pq_object_prophandler_t ph = {0};
1261
1262 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
1263 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL);
1264 php_pqres_class_entry->create_object = php_pqres_create_object;
1265 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
1266 #if PHP_VERSION_ID >= 80000
1267 zend_class_implements(php_pqres_class_entry, 2, zend_ce_aggregate, zend_ce_countable);
1268 #else
1269 zend_class_implements(php_pqres_class_entry, 2, zend_ce_traversable, zend_ce_countable);
1270 #endif
1271
1272 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1273 php_pqres_object_handlers.offset = XtOffsetOf(php_pqres_object_t, zo);
1274 php_pqres_object_handlers.free_obj = php_pqres_object_free;
1275 php_pqres_object_handlers.read_property = php_pq_object_read_prop;
1276 php_pqres_object_handlers.write_property = php_pq_object_write_prop;
1277 php_pqres_object_handlers.clone_obj = NULL;
1278 php_pqres_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null;
1279 php_pqres_object_handlers.get_gc = php_pq_object_get_gc;
1280 php_pqres_object_handlers.get_debug_info = php_pq_object_debug_info;
1281 php_pqres_object_handlers.get_properties = php_pq_object_properties;
1282 php_pqres_object_handlers.count_elements = php_pqres_count_elements;
1283
1284 zend_hash_init(&php_pqres_object_prophandlers, 9, NULL, php_pq_object_prophandler_dtor, 1);
1285
1286 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC);
1287 ph.read = php_pqres_object_read_status;
1288 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "status", sizeof("status")-1, (void *) &ph, sizeof(ph));
1289
1290 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC);
1291 ph.read = php_pqres_object_read_status_message;
1292 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "statusMessage", sizeof("statusMessage")-1, (void *) &ph, sizeof(ph));
1293
1294 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC);
1295 ph.read = php_pqres_object_read_error_message;
1296 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage")-1, (void *) &ph, sizeof(ph));
1297
1298 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("diag"), ZEND_ACC_PUBLIC);
1299 ph.read = php_pqres_object_read_diag;
1300 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "diag", sizeof("diag")-1, (void *) &ph, sizeof(ph));
1301
1302 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC);
1303 ph.read = php_pqres_object_read_num_rows;
1304 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "numRows", sizeof("numRows")-1, (void *) &ph, sizeof(ph));
1305
1306 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC);
1307 ph.read = php_pqres_object_read_num_cols;
1308 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "numCols", sizeof("numCols")-1, (void *) &ph, sizeof(ph));
1309
1310 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC);
1311 ph.read = php_pqres_object_read_affected_rows;
1312 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows")-1, (void *) &ph, sizeof(ph));
1313
1314 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC);
1315 ph.read = php_pqres_object_read_fetch_type;
1316 ph.write = php_pqres_object_write_fetch_type;
1317 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType")-1, (void *) &ph, sizeof(ph));
1318 ph.write = NULL;
1319
1320 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("autoConvert"), PHP_PQRES_CONV_ALL, ZEND_ACC_PUBLIC);
1321 ph.read = php_pqres_object_read_auto_conv;
1322 ph.write = php_pqres_object_write_auto_conv;
1323 zend_hash_str_add_mem(&php_pqres_object_prophandlers, "autoConvert", sizeof("autoConvert")-1, (void *) &ph, sizeof(ph));
1324 ph.write = NULL;
1325
1326 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY);
1327 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK);
1328 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK);
1329 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT);
1330 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN);
1331 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE);
1332 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR);
1333 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR);
1334 #ifdef HAVE_PGRES_COPY_BOTH
1335 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH);
1336 #endif
1337 #ifdef HAVE_PGRES_SINGLE_TUPLE
1338 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE);
1339 #endif
1340
1341 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY);
1342 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC);
1343 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT);
1344
1345 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_BOOL"), PHP_PQRES_CONV_BOOL);
1346 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_INT"), PHP_PQRES_CONV_INT);
1347 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_FLOAT"), PHP_PQRES_CONV_FLOAT);
1348 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR);
1349 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY);
1350 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME);
1351 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_JSON"), PHP_PQRES_CONV_JSON);
1352 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_BYTEA"), PHP_PQRES_CONV_BYTEA);
1353 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL);
1354
1355 return SUCCESS;
1356 }
1357
1358 /*
1359 * Local variables:
1360 * tab-width: 4
1361 * c-basic-offset: 4
1362 * End:
1363 * vim600: noet sw=4 ts=4 fdm=marker
1364 * vim<600: noet sw=4 ts=4
1365 */