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