build maintenance
[m6w6/ext-pq] / src / php_pq.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 <Zend/zend_interfaces.h>
19 #include <ext/standard/info.h>
20 #include <ext/spl/spl_array.h>
21
22 #include <libpq-events.h>
23 #include <libpq/libpq-fs.h>
24 #include <fnmatch.h>
25
26 #include "php_pq.h"
27
28 typedef int STATUS; /* SUCCESS/FAILURE */
29
30 static char *rtrim(char *e) {
31 size_t l = strlen(e);
32
33 while (l-- > 0 && e[l] == '\n') {
34 e[l] = '\0';
35 }
36 return e;
37 }
38
39 #define PHP_PQerrorMessage(c) rtrim(PQerrorMessage((c)))
40 #define PHP_PQresultErrorMessage(r) rtrim(PQresultErrorMessage((r)))
41
42 static int php_pqconn_event(PGEventId id, void *e, void *data);
43
44 #define PHP_PQclear(_r) \
45 do { \
46 zval *_resinszv = PQresultInstanceData((_r), php_pqconn_event); \
47 if (!_resinszv) PQclear((_r)); \
48 } while (0)
49
50 /*
51 ZEND_DECLARE_MODULE_GLOBALS(pq)
52 */
53
54
55 /* {{{ PHP_INI
56 */
57 /* Remove comments and fill if you need to have entries in php.ini
58 PHP_INI_BEGIN()
59 STD_PHP_INI_ENTRY("pq.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_pq_globals, pq_globals)
60 STD_PHP_INI_ENTRY("pq.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_pq_globals, pq_globals)
61 PHP_INI_END()
62 */
63 /* }}} */
64
65 /* {{{ php_pq_init_globals
66 */
67 /* Uncomment this function if you have INI entries
68 static void php_pq_init_globals(zend_pq_globals *pq_globals)
69 {
70 pq_globals->global_value = 0;
71 pq_globals->global_string = NULL;
72 }
73 */
74 /* }}} */
75
76 static zend_class_entry *php_pqconn_class_entry;
77 static zend_class_entry *php_pqtypes_class_entry;
78 static zend_class_entry *php_pqres_class_entry;
79 static zend_class_entry *php_pqstm_class_entry;
80 static zend_class_entry *php_pqtxn_class_entry;
81 static zend_class_entry *php_pqcancel_class_entry;
82 static zend_class_entry *php_pqevent_class_entry;
83 static zend_class_entry *php_pqlob_class_entry;
84 static zend_class_entry *php_pqcopy_class_entry;
85
86 static zend_object_handlers php_pqconn_object_handlers;
87 static zend_object_handlers php_pqtypes_object_handlers;
88 static zend_object_handlers php_pqres_object_handlers;
89 static zend_object_handlers php_pqstm_object_handlers;
90 static zend_object_handlers php_pqtxn_object_handlers;
91 static zend_object_handlers php_pqcancel_object_handlers;
92 static zend_object_handlers php_pqevent_object_handlers;
93 static zend_object_handlers php_pqlob_object_handlers;
94 static zend_object_handlers php_pqcopy_object_handlers;
95
96 typedef struct php_pq_callback {
97 zend_fcall_info fci;
98 zend_fcall_info_cache fcc;
99 void *data;
100 } php_pq_callback_t;
101
102 typedef struct php_pq_object {
103 zend_object zo;
104 zend_object_value zv;
105 HashTable *prophandler;
106 void *intern;
107 } php_pq_object_t;
108
109 typedef struct php_pqconn {
110 PGconn *conn;
111 int (*poller)(PGconn *);
112 HashTable listeners;
113 HashTable eventhandlers;
114 php_pq_callback_t onevent;
115 unsigned unbuffered:1;
116 } php_pqconn_t;
117
118 typedef struct php_pqconn_object {
119 zend_object zo;
120 zend_object_value zv;
121 HashTable *prophandler;
122 php_pqconn_t *intern;
123 } php_pqconn_object_t;
124
125 typedef struct php_pqtypes {
126 HashTable types;
127 php_pqconn_object_t *conn;
128 } php_pqtypes_t;
129
130 typedef struct php_pqtypes_object {
131 zend_object zo;
132 zend_object_value zv;
133 HashTable *prophandler;
134 php_pqtypes_t *intern;
135 } php_pqtypes_object_t;
136
137 typedef struct php_pqconn_event_data {
138 php_pqconn_object_t *obj;
139 #ifdef ZTS
140 void ***ts;
141 #endif
142 } php_pqconn_event_data_t;
143
144 typedef enum php_pqres_fetch {
145 PHP_PQRES_FETCH_ARRAY,
146 PHP_PQRES_FETCH_ASSOC,
147 PHP_PQRES_FETCH_OBJECT
148 } php_pqres_fetch_t;
149
150 typedef struct php_pqres_iterator {
151 zend_object_iterator zi;
152 zval *current_val;
153 unsigned index;
154 php_pqres_fetch_t fetch_type;
155 } php_pqres_iterator_t;
156
157 typedef struct php_pqres {
158 PGresult *res;
159 php_pqres_iterator_t *iter;
160 } php_pqres_t;
161
162 typedef struct php_pqres_object {
163 zend_object zo;
164 zend_object_value zv;
165 HashTable *prophandler;
166 php_pqres_t *intern;
167 } php_pqres_object_t;
168
169 typedef struct php_pqstm {
170 php_pqconn_object_t *conn;
171 char *name;
172 } php_pqstm_t;
173
174 typedef struct php_pqstm_object {
175 zend_object zo;
176 zend_object_value zv;
177 HashTable *prophandler;
178 php_pqstm_t *intern;
179 } php_pqstm_object_t;
180
181 typedef enum php_pqtxn_isolation {
182 PHP_PQTXN_READ_COMMITTED,
183 PHP_PQTXN_REPEATABLE_READ,
184 PHP_PQTXN_SERIALIZABLE,
185 } php_pqtxn_isolation_t;
186
187 typedef struct php_pqtxn {
188 php_pqconn_object_t *conn;
189 php_pqtxn_isolation_t isolation;
190 unsigned savepoint;
191 unsigned readonly:1;
192 unsigned deferrable:1;
193 } php_pqtxn_t;
194
195 typedef struct php_pqtxn_object {
196 zend_object zo;
197 zend_object_value zv;
198 HashTable *prophandler;
199 php_pqtxn_t *intern;
200 } php_pqtxn_object_t;
201
202 typedef struct php_pqcancel {
203 PGcancel *cancel;
204 php_pqconn_object_t *conn;
205 } php_pqcancel_t;
206
207 typedef struct php_pqcancel_object {
208 zend_object zo;
209 zend_object_value zv;
210 HashTable *prophandler;
211 php_pqcancel_t *intern;
212 } php_pqcancel_object_t;
213
214 typedef struct php_pqevent {
215 php_pq_callback_t cb;
216 php_pqconn_object_t *conn;
217 char *type;
218 } php_pqevent_t;
219
220 typedef struct php_pqevent_object {
221 zend_object zo;
222 zend_object_value zv;
223 HashTable *prophandler;
224 php_pqevent_t *intern;
225 } php_pqevent_object_t;
226
227 typedef struct php_pqlob {
228 int lofd;
229 Oid loid;
230 php_pqtxn_object_t *txn;
231 } php_pqlob_t;
232
233 typedef struct php_pqlob_object {
234 zend_object zo;
235 zend_object_value zv;
236 HashTable *prophandler;
237 php_pqlob_t *intern;
238 } php_pqlob_object_t;
239
240 typedef enum php_pqcopy_direction {
241 PHP_PQCOPY_FROM_STDIN,
242 PHP_PQCOPY_TO_STDOUT
243 } php_pqcopy_direction_t;
244
245 typedef enum php_pqcopy_status {
246 PHP_PQCOPY_FAIL,
247 PHP_PQCOPY_CONT,
248 PHP_PQCOPY_DONE
249 } php_pqcopy_status_t;
250
251 typedef struct php_pqcopy {
252 php_pqcopy_direction_t direction;
253 char *expression;
254 char *options;
255 php_pqconn_object_t *conn;
256 } php_pqcopy_t;
257
258 typedef struct php_pqcopy_object {
259 zend_object zo;
260 zend_object_value zv;
261 HashTable *prophandler;
262 php_pqcopy_t *intern;
263 } php_pqcopy_object_t;
264
265 static HashTable php_pqconn_object_prophandlers;
266 static HashTable php_pqtypes_object_prophandlers;
267 static HashTable php_pqres_object_prophandlers;
268 static HashTable php_pqstm_object_prophandlers;
269 static HashTable php_pqtxn_object_prophandlers;
270 static HashTable php_pqcancel_object_prophandlers;
271 static HashTable php_pqevent_object_prophandlers;
272 static HashTable php_pqlob_object_prophandlers;
273 static HashTable php_pqcopy_object_prophandlers;
274
275 typedef void (*php_pq_object_prophandler_func_t)(zval *object, void *o, zval *return_value TSRMLS_DC);
276
277 typedef struct php_pq_object_prophandler {
278 php_pq_object_prophandler_func_t read;
279 php_pq_object_prophandler_func_t write;
280 } php_pq_object_prophandler_t;
281
282 static zend_object_iterator_funcs php_pqres_iterator_funcs;
283
284 static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
285 {
286 php_pqres_iterator_t *iter;
287 zval *prop, *zfetch_type;
288
289 iter = ecalloc(1, sizeof(*iter));
290 iter->zi.funcs = &php_pqres_iterator_funcs;
291 iter->zi.data = object;
292 Z_ADDREF_P(object);
293
294 zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC);
295 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
296 convert_to_long_ex(&zfetch_type);
297 }
298 iter->fetch_type = Z_LVAL_P(zfetch_type);
299 if (zfetch_type != prop) {
300 zval_ptr_dtor(&zfetch_type);
301 }
302 if (Z_REFCOUNT_P(prop)) {
303 zval_ptr_dtor(&prop);
304 } else {
305 zval_dtor(prop);
306 FREE_ZVAL(prop);
307 }
308
309 return (zend_object_iterator *) iter;
310 }
311
312 static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
313 {
314 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
315
316 if (iter->current_val) {
317 zval_ptr_dtor(&iter->current_val);
318 iter->current_val = NULL;
319 }
320 zval_ptr_dtor((zval **) &iter->zi.data);
321 efree(iter);
322 }
323
324 static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC)
325 {
326 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
327 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
328
329 if (PQresultStatus(obj->intern->res) != PGRES_TUPLES_OK) {
330 return FAILURE;
331 }
332 if (PQntuples(obj->intern->res) <= iter->index) {
333 return FAILURE;
334 }
335
336 return SUCCESS;
337 }
338
339 static zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval **data_ptr TSRMLS_DC)
340 {
341 zval *data = NULL;
342 int c, cols;
343
344 if (data_ptr) {
345 data = *data_ptr;
346 }
347 if (!data) {
348 MAKE_STD_ZVAL(data);
349 if (PHP_PQRES_FETCH_OBJECT == fetch_type) {
350 object_init(data);
351 } else {
352 array_init(data);
353 }
354 if (data_ptr) {
355 *data_ptr = data;
356 }
357 }
358
359 for (c = 0, cols = PQnfields(res); c < cols; ++c) {
360 if (PQgetisnull(res, row, c)) {
361 switch (fetch_type) {
362 case PHP_PQRES_FETCH_OBJECT:
363 add_property_null(data, PQfname(res, c));
364 break;
365
366 case PHP_PQRES_FETCH_ASSOC:
367 add_assoc_null(data, PQfname(res, c));
368 break;
369
370 case PHP_PQRES_FETCH_ARRAY:
371 add_index_null(data, c);
372 break;
373 }
374 } else {
375 char *val = PQgetvalue(res, row, c);
376 int len = PQgetlength(res, row, c);
377
378 switch (fetch_type) {
379 case PHP_PQRES_FETCH_OBJECT:
380 add_property_stringl(data, PQfname(res, c), val, len, 1);
381 break;
382
383 case PHP_PQRES_FETCH_ASSOC:
384 add_assoc_stringl(data, PQfname(res, c), val, len, 1);
385 break;
386
387 case PHP_PQRES_FETCH_ARRAY:
388 add_index_stringl(data, c, val, len ,1);
389 break;
390 }
391 }
392 }
393
394 return data;
395 }
396
397 static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr TSRMLS_DC)
398 {
399 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
400 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
401
402 if (iter->current_val) {
403 zval_ptr_dtor(&iter->current_val);
404 }
405 iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC);
406 *data_ptr = &iter->current_val;
407 }
408
409 static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint *key_len, ulong *key_num TSRMLS_DC)
410 {
411 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
412
413 *key_num = (ulong) iter->index;
414
415 return HASH_KEY_IS_LONG;
416 }
417
418 static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC)
419 {
420 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
421
422 ++iter->index;
423 }
424
425 static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC)
426 {
427 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
428
429 iter->index = 0;
430 }
431
432 static zend_object_iterator_funcs php_pqres_iterator_funcs = {
433 php_pqres_iterator_dtor,
434 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
435 php_pqres_iterator_valid,
436 /* fetch the item data for the current element */
437 php_pqres_iterator_current,
438 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
439 php_pqres_iterator_key,
440 /* step forwards to next element */
441 php_pqres_iterator_next,
442 /* rewind to start of data (optional, may be NULL) */
443 php_pqres_iterator_rewind,
444 /* invalidate current value/key (optional, may be NULL) */
445 NULL
446 };
447
448 static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC)
449 {
450 php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
451
452 if (obj->intern) {
453 *count = (long) PQntuples(obj->intern->res);
454 return SUCCESS;
455 } else {
456 return FAILURE;
457 }
458 }
459
460 static STATUS php_pqres_success(PGresult *res TSRMLS_DC)
461 {
462 switch (PQresultStatus(res)) {
463 case PGRES_BAD_RESPONSE:
464 case PGRES_NONFATAL_ERROR:
465 case PGRES_FATAL_ERROR:
466 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PHP_PQresultErrorMessage(res));
467 return FAILURE;
468 default:
469 return SUCCESS;
470 }
471 }
472
473 static void php_pq_callback_dtor(php_pq_callback_t *cb) {
474 if (cb->fci.size > 0) {
475 zend_fcall_info_args_clear(&cb->fci, 1);
476 zval_ptr_dtor(&cb->fci.function_name);
477 if (cb->fci.object_ptr) {
478 zval_ptr_dtor(&cb->fci.object_ptr);
479 }
480 }
481 cb->fci.size = 0;
482 }
483
484 static void php_pq_callback_addref(php_pq_callback_t *cb)
485 {
486 Z_ADDREF_P(cb->fci.function_name);
487 if (cb->fci.object_ptr) {
488 Z_ADDREF_P(cb->fci.object_ptr);
489 }
490 }
491
492 static void php_pq_object_to_zval(void *o, zval **zv TSRMLS_DC)
493 {
494 php_pq_object_t *obj = o;
495
496 if (!*zv) {
497 MAKE_STD_ZVAL(*zv);
498 }
499
500 zend_objects_store_add_ref_by_handle(obj->zv.handle TSRMLS_CC);
501
502 (*zv)->type = IS_OBJECT;
503 (*zv)->value.obj = obj->zv;
504 }
505
506 static void php_pq_object_addref(void *o TSRMLS_DC)
507 {
508 php_pq_object_t *obj = o;
509 zend_objects_store_add_ref_by_handle(obj->zv.handle TSRMLS_CC);
510 }
511
512 static void php_pq_object_delref(void *o TSRMLS_DC)
513 {
514 php_pq_object_t *obj = o;
515 zend_objects_store_del_ref_by_handle_ex(obj->zv.handle, obj->zv.handlers TSRMLS_CC);
516 }
517
518 static void php_pqconn_object_free(void *o TSRMLS_DC)
519 {
520 php_pqconn_object_t *obj = o;
521
522 if (obj->intern) {
523 PQfinish(obj->intern->conn);
524 php_pq_callback_dtor(&obj->intern->onevent);
525 zend_hash_destroy(&obj->intern->listeners);
526 zend_hash_destroy(&obj->intern->eventhandlers);
527 efree(obj->intern);
528 obj->intern = NULL;
529 }
530 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
531 efree(obj);
532 }
533
534 static void php_pqtypes_object_free(void *o TSRMLS_DC)
535 {
536 php_pqtypes_object_t *obj = o;
537
538 if (obj->intern) {
539 zend_hash_destroy(&obj->intern->types);
540 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
541 efree(obj->intern);
542 obj->intern = NULL;
543 }
544 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
545 efree(obj);
546 }
547
548 static void php_pqres_object_free(void *o TSRMLS_DC)
549 {
550 php_pqres_object_t *obj = o;
551
552 if (obj->intern) {
553 if (obj->intern->res) {
554 zval *res = PQresultInstanceData(obj->intern->res, php_pqconn_event);
555 if (res) {
556 if (1 == Z_REFCOUNT_P(res)) {
557 PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL);
558 }
559 zval_ptr_dtor(&res);
560 } else {
561 PQclear(obj->intern->res);
562 obj->intern->res = NULL;
563 }
564 }
565
566 if (obj->intern->iter) {
567 php_pqres_iterator_dtor((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
568 obj->intern->iter = NULL;
569 }
570
571 efree(obj->intern);
572 obj->intern = NULL;
573 }
574 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
575 efree(obj);
576 }
577
578 static void php_pqstm_object_free(void *o TSRMLS_DC)
579 {
580 php_pqstm_object_t *obj = o;
581
582 if (obj->intern) {
583 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
584 efree(obj->intern->name);
585 efree(obj->intern);
586 obj->intern = NULL;
587 }
588 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
589 efree(obj);
590 }
591
592 static void php_pqtxn_object_free(void *o TSRMLS_DC)
593 {
594 php_pqtxn_object_t *obj = o;
595
596 if (obj->intern) {
597 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
598 efree(obj->intern);
599 obj->intern = NULL;
600 }
601 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
602 efree(obj);
603 }
604
605 static void php_pqcancel_object_free(void *o TSRMLS_DC)
606 {
607 php_pqcancel_object_t *obj = o;
608
609 if (obj->intern) {
610 PQfreeCancel(obj->intern->cancel);
611 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
612 efree(obj->intern);
613 obj->intern = NULL;
614 }
615 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
616 efree(obj);
617 }
618
619 static void php_pqevent_object_free(void *o TSRMLS_DC)
620 {
621 php_pqevent_object_t *obj = o;
622
623 if (obj->intern) {
624 php_pq_callback_dtor(&obj->intern->cb);
625 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
626 efree(obj->intern->type);
627 efree(obj->intern);
628 obj->intern = NULL;
629 }
630 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
631 efree(obj);
632 }
633
634 static void php_pqlob_object_free(void *o TSRMLS_DC)
635 {
636 php_pqlob_object_t *obj = o;
637
638 if (obj->intern) {
639 if (obj->intern->lofd) {
640 lo_close(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd);
641 }
642 php_pq_object_delref(obj->intern->txn TSRMLS_CC);
643 efree(obj->intern);
644 obj->intern = NULL;
645 }
646 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
647 efree(obj);
648 }
649
650 static void php_pqcopy_object_free(void *o TSRMLS_DC)
651 {
652 php_pqcopy_object_t *obj = o;
653
654 if (obj->intern) {
655 efree(obj->intern->expression);
656 efree(obj->intern->options);
657 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
658 efree(obj->intern);
659 obj->intern = NULL;
660 }
661 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
662 efree(obj);
663 }
664
665 static zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern, php_pqconn_object_t **ptr TSRMLS_DC)
666 {
667 php_pqconn_object_t *o;
668
669 o = ecalloc(1, sizeof(*o));
670 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
671 object_properties_init((zend_object *) o, ce);
672 o->prophandler = &php_pqconn_object_prophandlers;
673
674 if (ptr) {
675 *ptr = o;
676 }
677
678 if (intern) {
679 o->intern = intern;
680 }
681
682 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqconn_object_free, NULL TSRMLS_CC);
683 o->zv.handlers = &php_pqconn_object_handlers;
684
685 return o->zv;
686 }
687
688 static zend_object_value php_pqtypes_create_object_ex(zend_class_entry *ce, php_pqtypes_t *intern, php_pqtypes_object_t **ptr TSRMLS_DC)
689 {
690 php_pqtypes_object_t *o;
691
692 o = ecalloc(1, sizeof(*o));
693 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
694 object_properties_init((zend_object *) o, ce);
695 o->prophandler = &php_pqtypes_object_prophandlers;
696
697 if (ptr) {
698 *ptr = o;
699 }
700
701 if (intern) {
702 o->intern = intern;
703 }
704
705 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqtypes_object_free, NULL TSRMLS_CC);
706 o->zv.handlers = &php_pqtypes_object_handlers;
707
708 return o->zv;
709 }
710
711 static zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern, php_pqres_object_t **ptr TSRMLS_DC)
712 {
713 php_pqres_object_t *o;
714
715 o = ecalloc(1, sizeof(*o));
716 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
717 object_properties_init((zend_object *) o, ce);
718 o->prophandler = &php_pqres_object_prophandlers;
719
720 if (ptr) {
721 *ptr = o;
722 }
723
724 if (intern) {
725 o->intern = intern;
726 }
727
728 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqres_object_free, NULL TSRMLS_CC);
729 o->zv.handlers = &php_pqres_object_handlers;
730
731 return o->zv;
732 }
733
734 static zend_object_value php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern, php_pqstm_object_t **ptr TSRMLS_DC)
735 {
736 php_pqstm_object_t *o;
737
738 o = ecalloc(1, sizeof(*o));
739 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
740 object_properties_init((zend_object *) o, ce);
741 o->prophandler = &php_pqstm_object_prophandlers;
742
743 if (ptr) {
744 *ptr = o;
745 }
746
747 if (intern) {
748 o->intern = intern;
749 }
750
751 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqstm_object_free, NULL TSRMLS_CC);
752 o->zv.handlers = &php_pqstm_object_handlers;
753
754 return o->zv;
755 }
756
757 static zend_object_value php_pqtxn_create_object_ex(zend_class_entry *ce, php_pqtxn_t *intern, php_pqtxn_object_t **ptr TSRMLS_DC)
758 {
759 php_pqtxn_object_t *o;
760
761 o = ecalloc(1, sizeof(*o));
762 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
763 object_properties_init((zend_object *) o, ce);
764 o->prophandler = &php_pqtxn_object_prophandlers;
765
766 if (ptr) {
767 *ptr = o;
768 }
769
770 if (intern) {
771 o->intern = intern;
772 }
773
774 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqtxn_object_free, NULL TSRMLS_CC);
775 o->zv.handlers = &php_pqtxn_object_handlers;
776
777 return o->zv;
778 }
779
780 static zend_object_value php_pqcancel_create_object_ex(zend_class_entry *ce, php_pqcancel_t *intern, php_pqcancel_object_t **ptr TSRMLS_DC)
781 {
782 php_pqcancel_object_t *o;
783
784 o = ecalloc(1, sizeof(*o));
785 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
786 object_properties_init((zend_object *) o, ce);
787 o->prophandler = &php_pqcancel_object_prophandlers;
788
789 if (ptr) {
790 *ptr = o;
791 }
792
793 if (intern) {
794 o->intern = intern;
795 }
796
797 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqcancel_object_free, NULL TSRMLS_CC);
798 o->zv.handlers = &php_pqcancel_object_handlers;
799
800 return o->zv;
801 }
802
803 static zend_object_value php_pqevent_create_object_ex(zend_class_entry *ce, php_pqevent_t *intern, php_pqevent_object_t **ptr TSRMLS_DC)
804 {
805 php_pqevent_object_t *o;
806
807 o = ecalloc(1, sizeof(*o));
808 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
809 object_properties_init((zend_object *) o, ce);
810 o->prophandler = &php_pqevent_object_prophandlers;
811
812 if (ptr) {
813 *ptr = o;
814 }
815
816 if (intern) {
817 o->intern = intern;
818 }
819
820 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqevent_object_free, NULL TSRMLS_CC);
821 o->zv.handlers = &php_pqevent_object_handlers;
822
823 return o->zv;
824 }
825
826 static zend_object_value php_pqlob_create_object_ex(zend_class_entry *ce, php_pqlob_t *intern, php_pqlob_object_t **ptr TSRMLS_DC)
827 {
828 php_pqlob_object_t *o;
829
830 o = ecalloc(1, sizeof(*o));
831 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
832 object_properties_init((zend_object *) o, ce);
833 o->prophandler = &php_pqlob_object_prophandlers;
834
835 if (ptr) {
836 *ptr = o;
837 }
838
839 if (intern) {
840 o->intern = intern;
841 }
842
843 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqlob_object_free, NULL TSRMLS_CC);
844 o->zv.handlers = &php_pqlob_object_handlers;
845
846 return o->zv;
847 }
848
849 static zend_object_value php_pqcopy_create_object_ex(zend_class_entry *ce, php_pqcopy_t *intern, php_pqcopy_object_t **ptr TSRMLS_DC)
850 {
851 php_pqcopy_object_t *o;
852
853 o = ecalloc(1, sizeof(*o));
854 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
855 object_properties_init((zend_object *) o, ce);
856 o->prophandler = &php_pqcopy_object_prophandlers;
857
858 if (ptr) {
859 *ptr = o;
860 }
861
862 if (intern) {
863 o->intern = intern;
864 }
865
866 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqcopy_object_free, NULL TSRMLS_CC);
867 o->zv.handlers = &php_pqcopy_object_handlers;
868
869 return o->zv;
870 }
871
872 static zend_object_value php_pqconn_create_object(zend_class_entry *class_type TSRMLS_DC)
873 {
874 return php_pqconn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
875 }
876
877 static zend_object_value php_pqtypes_create_object(zend_class_entry *class_type TSRMLS_DC)
878 {
879 return php_pqtypes_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
880 }
881
882 static zend_object_value php_pqres_create_object(zend_class_entry *class_type TSRMLS_DC)
883 {
884 return php_pqres_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
885 }
886
887 static zend_object_value php_pqstm_create_object(zend_class_entry *class_type TSRMLS_DC)
888 {
889 return php_pqstm_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
890 }
891
892 static zend_object_value php_pqtxn_create_object(zend_class_entry *class_type TSRMLS_DC)
893 {
894 return php_pqtxn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
895 }
896
897 static zend_object_value php_pqcancel_create_object(zend_class_entry *class_type TSRMLS_DC)
898 {
899 return php_pqcancel_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
900 }
901
902 static zend_object_value php_pqevent_create_object(zend_class_entry *class_type TSRMLS_DC)
903 {
904 return php_pqevent_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
905 }
906
907 static zend_object_value php_pqlob_create_object(zend_class_entry *class_type TSRMLS_DC)
908 {
909 return php_pqlob_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
910 }
911
912 static zend_object_value php_pqcopy_create_object(zend_class_entry *class_type TSRMLS_DC)
913 {
914 return php_pqcopy_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
915 }
916
917 static int apply_ph_to_debug(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
918 {
919 php_pq_object_prophandler_t *ph = p;
920 HashTable *ht = va_arg(argv, HashTable *);
921 zval **return_value, *object = va_arg(argv, zval *);
922 php_pq_object_t *obj = va_arg(argv, php_pq_object_t *);
923
924 if (SUCCESS == zend_hash_find(ht, key->arKey, key->nKeyLength, (void *) &return_value)) {
925
926 if (ph->read) {
927 zval_ptr_dtor(return_value);
928 MAKE_STD_ZVAL(*return_value);
929 ZVAL_NULL(*return_value);
930
931 ph->read(object, obj, *return_value TSRMLS_CC);
932 }
933 }
934
935 return ZEND_HASH_APPLY_KEEP;
936 }
937
938 static int apply_pi_to_debug(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
939 {
940 zend_property_info *pi = p;
941 HashTable *ht = va_arg(argv, HashTable *);
942 zval *object = va_arg(argv, zval *);
943 php_pq_object_t *obj = va_arg(argv, php_pq_object_t *);
944 zval *property = zend_read_property(obj->zo.ce, object, pi->name, pi->name_length, 0 TSRMLS_CC);
945
946 if (1||!Z_REFCOUNT_P(property)) {
947 Z_ADDREF_P(property);
948 }
949 zend_hash_add(ht, pi->name, pi->name_length + 1, (void *) &property, sizeof(zval *), NULL);
950
951 return ZEND_HASH_APPLY_KEEP;
952 }
953
954 static HashTable *php_pq_object_debug_info(zval *object, int *temp TSRMLS_DC)
955 {
956 HashTable *ht;
957 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
958
959 *temp = 1;
960 ALLOC_HASHTABLE(ht);
961 ZEND_INIT_SYMTABLE(ht);
962
963 zend_hash_apply_with_arguments(&obj->zo.ce->properties_info TSRMLS_CC, apply_pi_to_debug, 3, ht, object, obj);
964 zend_hash_apply_with_arguments(obj->prophandler TSRMLS_CC, apply_ph_to_debug, 3, ht, object, obj);
965
966 return ht;
967 }
968
969 static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
970 {
971 php_pqconn_object_t *obj = o;
972
973 RETVAL_LONG(PQstatus(obj->intern->conn));
974 }
975
976 static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value TSRMLS_DC)
977 {
978 php_pqconn_object_t *obj = o;
979
980 RETVAL_LONG(PQtransactionStatus(obj->intern->conn));
981 }
982
983 static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
984 {
985 php_pqconn_object_t *obj = o;
986 char *error = PHP_PQerrorMessage(obj->intern->conn);
987
988 if (error) {
989 RETVAL_STRING(error, 1);
990 } else {
991 RETVAL_NULL();
992 }
993 }
994
995 static int apply_notify_listener(void *p, void *arg TSRMLS_DC)
996 {
997 php_pq_callback_t *listener = p;
998 PGnotify *nfy = arg;
999 zval *zpid, *zchannel, *zmessage;
1000
1001 MAKE_STD_ZVAL(zpid);
1002 ZVAL_LONG(zpid, nfy->be_pid);
1003 MAKE_STD_ZVAL(zchannel);
1004 ZVAL_STRING(zchannel, nfy->relname, 1);
1005 MAKE_STD_ZVAL(zmessage);
1006 ZVAL_STRING(zmessage, nfy->extra, 1);
1007
1008 zend_fcall_info_argn(&listener->fci TSRMLS_CC, 3, &zchannel, &zmessage, &zpid);
1009 zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL TSRMLS_CC);
1010
1011 zval_ptr_dtor(&zchannel);
1012 zval_ptr_dtor(&zmessage);
1013 zval_ptr_dtor(&zpid);
1014
1015 return ZEND_HASH_APPLY_KEEP;
1016 }
1017
1018 static int apply_notify_listeners(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1019 {
1020 HashTable *listeners = p;
1021 PGnotify *nfy = va_arg(argv, PGnotify *);
1022
1023 if (0 == fnmatch(key->arKey, nfy->relname, 0)) {
1024 zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy TSRMLS_CC);
1025 }
1026
1027 return ZEND_HASH_APPLY_KEEP;
1028 }
1029
1030 static void php_pqconn_notify_listeners(php_pqconn_object_t *obj TSRMLS_DC)
1031 {
1032 PGnotify *nfy;
1033
1034 while ((nfy = PQnotifies(obj->intern->conn))) {
1035 zend_hash_apply_with_arguments(&obj->intern->listeners TSRMLS_CC, apply_notify_listeners, 1, nfy);
1036 PQfreemem(nfy);
1037 }
1038 }
1039
1040 static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value TSRMLS_DC)
1041 {
1042 php_pqconn_object_t *obj = o;
1043
1044 RETVAL_BOOL(PQisBusy(obj->intern->conn));
1045 }
1046
1047 static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value TSRMLS_DC)
1048 {
1049 php_pqconn_object_t *obj = o;
1050
1051 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn)), 1);
1052 }
1053
1054 static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value TSRMLS_DC)
1055 {
1056 php_pqconn_object_t *obj = o;
1057 zval *zenc = value;
1058
1059 if (Z_TYPE_P(value) != IS_STRING) {
1060 convert_to_string_ex(&zenc);
1061 }
1062
1063 if (0 > PQsetClientEncoding(obj->intern->conn, Z_STRVAL_P(zenc))) {
1064 zend_error(E_NOTICE, "Unrecognized encoding '%s'", Z_STRVAL_P(zenc));
1065 }
1066
1067 if (zenc != value) {
1068 zval_ptr_dtor(&zenc);
1069 }
1070 }
1071
1072 static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value TSRMLS_DC)
1073 {
1074 php_pqconn_object_t *obj = o;
1075
1076 RETVAL_BOOL(obj->intern->unbuffered);
1077 }
1078
1079 static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value TSRMLS_DC)
1080 {
1081 php_pqconn_object_t *obj = o;
1082
1083 obj->intern->unbuffered = zend_is_true(value);
1084 }
1085
1086 static void php_pqconn_object_read_db(zval *objec, void *o, zval *return_value TSRMLS_DC)
1087 {
1088 php_pqconn_object_t *obj = o;
1089 char *db = PQdb(obj->intern->conn);
1090
1091 if (db) {
1092 RETVAL_STRING(db, 1);
1093 } else {
1094 RETVAL_EMPTY_STRING();
1095 }
1096 }
1097
1098 static void php_pqconn_object_read_user(zval *objec, void *o, zval *return_value TSRMLS_DC)
1099 {
1100 php_pqconn_object_t *obj = o;
1101 char *user = PQuser(obj->intern->conn);
1102
1103 if (user) {
1104 RETVAL_STRING(user, 1);
1105 } else {
1106 RETVAL_EMPTY_STRING();
1107 }
1108 }
1109
1110 static void php_pqconn_object_read_pass(zval *objec, void *o, zval *return_value TSRMLS_DC)
1111 {
1112 php_pqconn_object_t *obj = o;
1113 char *pass = PQpass(obj->intern->conn);
1114
1115 if (pass) {
1116 RETVAL_STRING(pass, 1);
1117 } else {
1118 RETVAL_EMPTY_STRING();
1119 }
1120 }
1121
1122 static void php_pqconn_object_read_host(zval *objec, void *o, zval *return_value TSRMLS_DC)
1123 {
1124 php_pqconn_object_t *obj = o;
1125 char *host = PQhost(obj->intern->conn);
1126
1127 if (host) {
1128 RETVAL_STRING(host, 1);
1129 } else {
1130 RETVAL_EMPTY_STRING();
1131 }
1132 }
1133
1134 static void php_pqconn_object_read_port(zval *objec, void *o, zval *return_value TSRMLS_DC)
1135 {
1136 php_pqconn_object_t *obj = o;
1137 char *port = PQport(obj->intern->conn);
1138
1139 if (port) {
1140 RETVAL_STRING(port, 1);
1141 } else {
1142 RETVAL_EMPTY_STRING();
1143 }
1144 }
1145
1146 static void php_pqconn_object_read_options(zval *objec, void *o, zval *return_value TSRMLS_DC)
1147 {
1148 php_pqconn_object_t *obj = o;
1149 char *options = PQoptions(obj->intern->conn);
1150
1151 if (options) {
1152 RETVAL_STRING(options, 1);
1153 } else {
1154 RETVAL_EMPTY_STRING();
1155 }
1156 }
1157
1158 static void php_pqtypes_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1159 {
1160 php_pqtypes_object_t *obj = o;
1161
1162 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1163 }
1164
1165 static int has_dimension(HashTable *ht, zval *member, char **key_str, int *key_len, long *index TSRMLS_DC)
1166 {
1167 long lval = 0;
1168 zval *tmp = member;
1169
1170 switch (Z_TYPE_P(member)) {
1171 default:
1172 convert_to_string_ex(&tmp);
1173 /* no break */
1174 case IS_STRING:
1175 if (!is_numeric_string(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &lval, NULL, 0)) {
1176 if (member != tmp) {
1177 zval_ptr_dtor(&tmp);
1178 }
1179 if (key_str) {
1180 *key_str = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
1181 if (key_len) {
1182 *key_len = Z_STRLEN_P(tmp) + 1;
1183 }
1184 }
1185 return zend_hash_exists(ht, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp) + 1);
1186 }
1187 /* no break */
1188 case IS_LONG:
1189 lval = Z_LVAL_P(member);
1190 break;
1191 }
1192
1193 if (member != tmp) {
1194 zval_ptr_dtor(&tmp);
1195 }
1196 if (index) {
1197 *index = lval;
1198 }
1199 return zend_hash_index_exists(ht, lval);
1200 }
1201
1202 static int php_pqtypes_object_has_dimension(zval *object, zval *member, int check_empty TSRMLS_DC)
1203 {
1204 php_pqtypes_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1205 char *key_str = NULL;
1206 int key_len = 0;
1207 long index = 0;
1208
1209 if (check_empty) {
1210 if (has_dimension(&obj->intern->types, member, &key_str, &key_len, &index TSRMLS_CC)) {
1211 zval **data;
1212
1213 if (key_str && key_len) {
1214 if (SUCCESS == zend_hash_find(&obj->intern->types, key_str, key_len, (void *) &data)) {
1215 efree(key_str);
1216 return Z_TYPE_PP(data) != IS_NULL;
1217 }
1218 efree(key_str);
1219 } else {
1220 if (SUCCESS == zend_hash_index_find(&obj->intern->types, index, (void *) data)) {
1221 return Z_TYPE_PP(data) != IS_NULL;
1222 }
1223 }
1224 }
1225 } else {
1226 return has_dimension(&obj->intern->types, member, NULL, NULL, NULL TSRMLS_CC);
1227 }
1228
1229 return 0;
1230 }
1231
1232 static zval *php_pqtypes_object_read_dimension(zval *object, zval *member, int type TSRMLS_DC)
1233 {
1234 long index = 0;
1235 char *key_str = NULL;
1236 int key_len = 0;
1237 php_pqtypes_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1238
1239 if (has_dimension(&obj->intern->types, member, &key_str, &key_len, &index TSRMLS_CC)) {
1240 zval **data;
1241
1242 if (key_str && key_len) {
1243 if (SUCCESS == zend_hash_find(&obj->intern->types, key_str, key_len, (void *) &data)) {
1244 efree(key_str);
1245 return *data;
1246 }
1247 } else {
1248 if (SUCCESS == zend_hash_index_find(&obj->intern->types, index, (void *) &data)) {
1249 return *data;
1250 }
1251 }
1252 }
1253
1254 return NULL;
1255 }
1256
1257 static void php_pqres_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
1258 {
1259 php_pqres_object_t *obj = o;
1260
1261 RETVAL_LONG(PQresultStatus(obj->intern->res));
1262 }
1263
1264 static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
1265 {
1266 php_pqres_object_t *obj = o;
1267 char *error = PHP_PQresultErrorMessage(obj->intern->res);
1268
1269 if (error) {
1270 RETVAL_STRING(error, 1);
1271 } else {
1272 RETVAL_NULL();
1273 }
1274 }
1275
1276 static void php_pqres_object_read_num_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
1277 {
1278 php_pqres_object_t *obj = o;
1279
1280 RETVAL_LONG(PQntuples(obj->intern->res));
1281 }
1282
1283 static void php_pqres_object_read_num_cols(zval *object, void *o, zval *return_value TSRMLS_DC)
1284 {
1285 php_pqres_object_t *obj = o;
1286
1287 RETVAL_LONG(PQnfields(obj->intern->res));
1288 }
1289
1290 static void php_pqres_object_read_affected_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
1291 {
1292 php_pqres_object_t *obj = o;
1293
1294 RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res)));
1295 }
1296
1297 static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1298 {
1299 php_pqres_object_t *obj = o;
1300
1301 if (obj->intern->iter) {
1302 RETVAL_LONG(obj->intern->iter->fetch_type);
1303 } else {
1304 RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
1305 }
1306 }
1307
1308 static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value TSRMLS_DC)
1309 {
1310 php_pqres_object_t *obj = o;
1311 zval *zfetch_type = value;
1312
1313 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
1314 convert_to_long_ex(&zfetch_type);
1315 }
1316
1317 if (!obj->intern->iter) {
1318 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC);
1319 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
1320 }
1321 obj->intern->iter->fetch_type = Z_LVAL_P(zfetch_type);
1322
1323 if (zfetch_type != value) {
1324 zval_ptr_dtor(&zfetch_type);
1325 }
1326 }
1327
1328 static void php_pqstm_object_read_name(zval *object, void *o, zval *return_value TSRMLS_DC)
1329 {
1330 php_pqstm_object_t *obj = o;
1331
1332 RETVAL_STRING(obj->intern->name, 1);
1333 }
1334
1335 static void php_pqstm_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1336 {
1337 php_pqstm_object_t *obj = o;
1338
1339 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1340 }
1341
1342 static void php_pqtxn_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1343 {
1344 php_pqtxn_object_t *obj = o;
1345
1346 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1347 }
1348
1349 static void php_pqtxn_object_read_isolation(zval *object, void *o, zval *return_value TSRMLS_DC)
1350 {
1351 php_pqtxn_object_t *obj = o;
1352
1353 RETVAL_LONG(obj->intern->isolation);
1354 }
1355
1356 static void php_pqtxn_object_read_readonly(zval *object, void *o, zval *return_value TSRMLS_DC)
1357 {
1358 php_pqtxn_object_t *obj = o;
1359
1360 RETVAL_LONG(obj->intern->readonly);
1361 }
1362
1363 static void php_pqtxn_object_read_deferrable(zval *object, void *o, zval *return_value TSRMLS_DC)
1364 {
1365 php_pqtxn_object_t *obj = o;
1366
1367 RETVAL_LONG(obj->intern->deferrable);
1368 }
1369
1370 static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value TSRMLS_DC)
1371 {
1372 php_pqtxn_object_t *obj = o;
1373 php_pqtxn_isolation_t orig = obj->intern->isolation;
1374 zval *zisolation = value;
1375 PGresult *res;
1376
1377 if (Z_TYPE_P(zisolation) != IS_LONG) {
1378 convert_to_long_ex(&zisolation);
1379 }
1380
1381 switch ((obj->intern->isolation = Z_LVAL_P(zisolation))) {
1382 case PHP_PQTXN_READ_COMMITTED:
1383 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ COMMITED");
1384 break;
1385 case PHP_PQTXN_REPEATABLE_READ:
1386 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION REPEATABLE READ");
1387 break;
1388 case PHP_PQTXN_SERIALIZABLE:
1389 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION SERIALIZABLE");
1390 break;
1391 default:
1392 obj->intern->isolation = orig;
1393 res = NULL;
1394 break;
1395 }
1396
1397 if (zisolation != value) {
1398 zval_ptr_dtor(&zisolation);
1399 }
1400
1401 if (res) {
1402 php_pqres_success(res TSRMLS_CC);
1403 PHP_PQclear(res);
1404 }
1405 }
1406
1407 static void php_pqtxn_object_write_readonly(zval *object, void *o, zval *value TSRMLS_DC)
1408 {
1409 php_pqtxn_object_t *obj = o;
1410 PGresult *res;
1411
1412 if ((obj->intern->readonly = zend_is_true(value))) {
1413 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY");
1414 } else {
1415 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE");
1416 }
1417
1418 if (res) {
1419 php_pqres_success(res TSRMLS_CC);
1420 PHP_PQclear(res);
1421 }
1422 }
1423
1424 static void php_pqtxn_object_write_deferrable(zval *object, void *o, zval *value TSRMLS_DC)
1425 {
1426 php_pqtxn_object_t *obj = o;
1427 PGresult *res;
1428
1429 if ((obj->intern->deferrable = zend_is_true(value))) {
1430 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE");
1431 } else {
1432 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE");
1433 }
1434
1435 if (res) {
1436 php_pqres_success(res TSRMLS_CC);
1437 PHP_PQclear(res);
1438 }
1439 }
1440
1441 static void php_pqcancel_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1442 {
1443 php_pqcancel_object_t *obj = o;
1444
1445 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1446 }
1447
1448 static void php_pqevent_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1449 {
1450 php_pqevent_object_t *obj = o;
1451
1452 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1453 }
1454
1455 static void php_pqevent_object_read_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1456 {
1457 php_pqevent_object_t *obj = o;
1458
1459 RETVAL_STRING(obj->intern->type, 1);
1460 }
1461
1462 static void php_pqlob_object_read_transaction(zval *object, void *o, zval *return_value TSRMLS_DC)
1463 {
1464 php_pqlob_object_t *obj = o;
1465
1466 php_pq_object_to_zval(obj->intern->txn, &return_value TSRMLS_CC);
1467 }
1468
1469 static void php_pqlob_object_read_oid(zval *object, void *o, zval *return_value TSRMLS_DC)
1470 {
1471 php_pqlob_object_t *obj = o;
1472
1473 RETVAL_LONG(obj->intern->loid);
1474 }
1475
1476 static void php_pqcopy_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1477 {
1478 php_pqcopy_object_t *obj = o;
1479
1480 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1481 }
1482
1483 static void php_pqcopy_object_read_direction(zval *object, void *o, zval *return_value TSRMLS_DC)
1484 {
1485 php_pqcopy_object_t *obj = o;
1486
1487 RETVAL_LONG(obj->intern->direction);
1488 }
1489
1490 static void php_pqcopy_object_read_expression(zval *object, void *o, zval *return_value TSRMLS_DC)
1491 {
1492 php_pqcopy_object_t *obj = o;
1493
1494 RETURN_STRING(obj->intern->expression, 1);
1495 }
1496
1497 static void php_pqcopy_object_read_options(zval *object, void *o, zval *return_value TSRMLS_DC)
1498 {
1499 php_pqcopy_object_t *obj = o;
1500
1501 RETURN_STRING(obj->intern->options, 1);
1502 }
1503
1504 static zend_class_entry *ancestor(zend_class_entry *ce) {
1505 while (ce->parent) {
1506 ce = ce->parent;
1507 }
1508 return ce;
1509 }
1510
1511 static zval *php_pq_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
1512 {
1513 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1514 php_pq_object_prophandler_t *handler;
1515 zval *return_value;
1516
1517 if (!obj->intern) {
1518 zend_error(E_WARNING, "%s not initialized", ancestor(obj->zo.ce)->name);
1519 } else if ((SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) && handler->read) {
1520 if (type == BP_VAR_R) {
1521 ALLOC_ZVAL(return_value);
1522 Z_SET_REFCOUNT_P(return_value, 0);
1523 Z_UNSET_ISREF_P(return_value);
1524
1525 handler->read(object, obj, return_value TSRMLS_CC);
1526 } else {
1527 zend_error(E_ERROR, "Cannot access %s properties by reference or array key/index", ancestor(obj->zo.ce)->name);
1528 return_value = NULL;
1529 }
1530 } else {
1531 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
1532 }
1533
1534 return return_value;
1535 }
1536
1537 static void php_pq_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
1538 {
1539 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1540 php_pq_object_prophandler_t *handler;
1541
1542 if (SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
1543 if (handler->write) {
1544 handler->write(object, obj, value TSRMLS_CC);
1545 }
1546 } else {
1547 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
1548 }
1549 }
1550
1551 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
1552 {
1553 zval *zsocket, zmember;
1554 php_stream *stream;
1555 STATUS retval;
1556 int socket;
1557
1558 if (!obj) {
1559 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1560 }
1561
1562 INIT_PZVAL(&zmember);
1563 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
1564 MAKE_STD_ZVAL(zsocket);
1565
1566 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
1567 && (-1 < (socket = PQsocket(obj->intern->conn)))
1568 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
1569 php_stream_to_zval(stream, zsocket);
1570 retval = SUCCESS;
1571 } else {
1572 ZVAL_NULL(zsocket);
1573 retval = FAILURE;
1574 }
1575 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
1576 zval_ptr_dtor(&zsocket);
1577
1578 return retval;
1579 }
1580
1581 #ifdef ZTS
1582 # define TSRMLS_DF(d) TSRMLS_D = (d)->ts
1583 # define TSRMLS_CF(d) (d)->ts = TSRMLS_C
1584 #else
1585 # define TSRMLS_DF(d)
1586 # define TSRMLS_CF(d)
1587 #endif
1588
1589 static void php_pqconn_event_register(PGEventRegister *event, php_pqconn_event_data_t *data)
1590 {
1591 PQsetInstanceData(event->conn, php_pqconn_event, data);
1592 }
1593
1594 static void php_pqconn_event_conndestroy(PGEventConnDestroy *event, php_pqconn_event_data_t *data)
1595 {
1596 PQsetInstanceData(event->conn, php_pqconn_event, NULL);
1597 efree(data);
1598 }
1599
1600 static int apply_event(void *p, void *a TSRMLS_DC)
1601 {
1602 zval **evh = p;
1603 zval *args = a;
1604 zval *retval = NULL;
1605
1606 zend_call_method_with_1_params(evh, Z_OBJCE_PP(evh), NULL, "trigger", &retval, args);
1607 if (retval) {
1608 zval_ptr_dtor(&retval);
1609 }
1610
1611 return ZEND_HASH_APPLY_KEEP;
1612 }
1613
1614 static void php_pqconn_event_connreset(PGEventConnReset *event, php_pqconn_event_data_t *data)
1615 {
1616 zval **evhs;
1617 TSRMLS_DF(data);
1618
1619 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("reset"), (void *) &evhs)) {
1620 zval *args, *connection = NULL;
1621
1622 MAKE_STD_ZVAL(args);
1623 array_init(args);
1624 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1625 add_next_index_zval(args, connection);
1626 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1627 zval_ptr_dtor(&args);
1628 }
1629 }
1630
1631 static zval *result_instance_zval(PGresult *res TSRMLS_DC)
1632 {
1633 zval *rid = PQresultInstanceData(res, php_pqconn_event);
1634
1635 if (!rid) {
1636 php_pqres_t *r = ecalloc(1, sizeof(*r));
1637
1638 MAKE_STD_ZVAL(rid);
1639 r->res = res;
1640 rid->type = IS_OBJECT;
1641 rid->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1642
1643 PQresultSetInstanceData(res, php_pqconn_event, rid);
1644 }
1645
1646 Z_ADDREF_P(rid);
1647 return rid;
1648 }
1649
1650 static void php_pqconn_event_resultcreate(PGEventResultCreate *event, php_pqconn_event_data_t *data)
1651 {
1652 zval **evhs;
1653 TSRMLS_DF(data);
1654
1655 /* event listener */
1656 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) {
1657 zval *args, *connection = NULL, *res = result_instance_zval(event->result TSRMLS_CC);
1658
1659 MAKE_STD_ZVAL(args);
1660 array_init(args);
1661 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1662 add_next_index_zval(args, connection);
1663 add_next_index_zval(args, res);
1664 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1665 zval_ptr_dtor(&args);
1666 }
1667
1668 /* async callback */
1669 if (data->obj->intern->onevent.fci.size > 0) {
1670 zval *res = result_instance_zval(event->result TSRMLS_CC);
1671
1672 zend_fcall_info_argn(&data->obj->intern->onevent.fci TSRMLS_CC, 1, &res);
1673 zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL TSRMLS_CC);
1674 zval_ptr_dtor(&res);
1675 }
1676 }
1677
1678 static int php_pqconn_event(PGEventId id, void *e, void *data)
1679 {
1680 switch (id) {
1681 case PGEVT_REGISTER:
1682 php_pqconn_event_register(e, data);
1683 break;
1684 case PGEVT_CONNDESTROY:
1685 php_pqconn_event_conndestroy(e, data);
1686 break;
1687 case PGEVT_CONNRESET:
1688 php_pqconn_event_connreset(e, data);
1689 break;
1690 case PGEVT_RESULTCREATE:
1691 php_pqconn_event_resultcreate(e, data);
1692 break;
1693 default:
1694 break;
1695 }
1696
1697 return 1;
1698 }
1699
1700 static php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj TSRMLS_DC)
1701 {
1702 php_pqconn_event_data_t *data = emalloc(sizeof(*data));
1703
1704 data->obj = obj;
1705 TSRMLS_CF(data);
1706
1707 return data;
1708 }
1709
1710 static void php_pqconn_notice_recv(void *p, const PGresult *res)
1711 {
1712 php_pqconn_event_data_t *data = p;
1713 zval **evhs;
1714 TSRMLS_DF(data);
1715
1716 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("notice"), (void *) &evhs)) {
1717 zval *args, *connection = NULL;
1718
1719 MAKE_STD_ZVAL(args);
1720 array_init(args);
1721 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1722 add_next_index_zval(args, connection);
1723 add_next_index_string(args, PHP_PQresultErrorMessage(res), 1);
1724 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1725 zval_ptr_dtor(&args);
1726 }
1727 }
1728
1729 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
1730 ZEND_ARG_INFO(0, dsn)
1731 ZEND_ARG_INFO(0, async)
1732 ZEND_END_ARG_INFO();
1733 static PHP_METHOD(pqconn, __construct) {
1734 zend_error_handling zeh;
1735 char *dsn_str = "";
1736 int dsn_len = 0;
1737 zend_bool async = 0;
1738
1739 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1740 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &dsn_str, &dsn_len, &async)) {
1741 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1742 php_pqconn_event_data_t *data = php_pqconn_event_data_init(obj TSRMLS_CC);
1743
1744 obj->intern = ecalloc(1, sizeof(*obj->intern));
1745
1746 zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
1747 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);
1748
1749
1750 if (async) {
1751 obj->intern->conn = PQconnectStart(dsn_str);
1752 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
1753 } else {
1754 obj->intern->conn = PQconnectdb(dsn_str);
1755 }
1756
1757 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, data);
1758 PQregisterEventProc(obj->intern->conn, php_pqconn_event, "ext-pq", data);
1759
1760 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
1761 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn));
1762 }
1763 }
1764 zend_restore_error_handling(&zeh TSRMLS_CC);
1765 }
1766
1767 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
1768 ZEND_END_ARG_INFO();
1769 static PHP_METHOD(pqconn, reset) {
1770 if (SUCCESS == zend_parse_parameters_none()) {
1771 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1772
1773 if (obj->intern) {
1774 PQreset(obj->intern->conn);
1775
1776 if (CONNECTION_OK == PQstatus(obj->intern->conn)) {
1777 RETURN_TRUE;
1778 } else {
1779 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn));
1780 }
1781 } else {
1782 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1783 }
1784 RETURN_FALSE;
1785 }
1786 }
1787
1788 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
1789 ZEND_END_ARG_INFO();
1790 static PHP_METHOD(pqconn, resetAsync) {
1791 if (SUCCESS == zend_parse_parameters_none()) {
1792 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1793
1794 if (obj->intern) {
1795 if (PQresetStart(obj->intern->conn)) {
1796 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
1797 RETURN_TRUE;
1798 }
1799 } else {
1800 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1801 }
1802 RETURN_FALSE;
1803 }
1804 }
1805
1806 static void php_pqconn_add_listener(php_pqconn_object_t *obj, const char *channel_str, size_t channel_len, php_pq_callback_t *listener TSRMLS_DC)
1807 {
1808 HashTable ht, *existing_listeners;
1809
1810 php_pq_callback_addref(listener);
1811
1812 if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
1813 zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
1814 } else {
1815 zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
1816 zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
1817 zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
1818 }
1819 }
1820
1821 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
1822 ZEND_ARG_INFO(0, channel)
1823 ZEND_ARG_INFO(0, callable)
1824 ZEND_END_ARG_INFO();
1825 static PHP_METHOD(pqconn, listen) {
1826 char *channel_str = NULL;
1827 int channel_len = 0;
1828 php_pq_callback_t listener;
1829
1830 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc)) {
1831 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1832
1833 obj->intern->poller = PQconsumeInput;
1834
1835 if (obj->intern) {
1836 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
1837
1838 if (quoted_channel) {
1839 PGresult *res;
1840 char *cmd;
1841
1842 spprintf(&cmd, 0, "LISTEN %s", channel_str);
1843 res = PQexec(obj->intern->conn, cmd);
1844
1845 efree(cmd);
1846 PQfreemem(quoted_channel);
1847
1848 if (res) {
1849 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1850 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
1851 RETVAL_TRUE;
1852 } else {
1853 RETVAL_FALSE;
1854 }
1855 PHP_PQclear(res);
1856 } else {
1857 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
1858 RETVAL_FALSE;
1859 }
1860
1861 php_pqconn_notify_listeners(obj TSRMLS_CC);
1862 } else {
1863 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
1864 }
1865 } else {
1866 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1867 RETVAL_FALSE;
1868 }
1869 }
1870 }
1871
1872 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
1873 ZEND_ARG_INFO(0, channel)
1874 ZEND_ARG_INFO(0, message)
1875 ZEND_END_ARG_INFO();
1876 static PHP_METHOD(pqconn, notify) {
1877 char *channel_str, *message_str;
1878 int channel_len, message_len;
1879
1880 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len)) {
1881 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1882
1883 if (obj->intern) {
1884 PGresult *res;
1885 char *params[2] = {channel_str, message_str};
1886
1887 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
1888
1889 if (res) {
1890 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1891 RETVAL_TRUE;
1892 } else {
1893 RETVAL_FALSE;
1894 }
1895 PHP_PQclear(res);
1896 } else {
1897 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
1898 RETVAL_FALSE;
1899 }
1900
1901 php_pqconn_notify_listeners(obj TSRMLS_CC);
1902
1903 } else {
1904 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1905 RETVAL_FALSE;
1906 }
1907 }
1908 }
1909
1910 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
1911 ZEND_END_ARG_INFO();
1912 static PHP_METHOD(pqconn, poll) {
1913 if (SUCCESS == zend_parse_parameters_none()) {
1914 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1915
1916 if (obj->intern) {
1917 if (obj->intern->poller) {
1918 if (obj->intern->poller == PQconsumeInput) {
1919 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
1920 php_pqconn_notify_listeners(obj TSRMLS_CC);
1921 return;
1922 } else {
1923 RETURN_LONG(obj->intern->poller(obj->intern->conn));
1924 }
1925 } else {
1926 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active");
1927 }
1928 } else {
1929 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1930 }
1931 RETURN_FALSE;
1932 }
1933 }
1934
1935 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
1936 ZEND_ARG_INFO(0, query)
1937 ZEND_END_ARG_INFO();
1938 static PHP_METHOD(pqconn, exec) {
1939 zend_error_handling zeh;
1940 char *query_str;
1941 int query_len;
1942
1943 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1944 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) {
1945 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1946
1947 if (obj->intern) {
1948 PGresult *res = PQexec(obj->intern->conn, query_str);
1949
1950 php_pqconn_notify_listeners(obj TSRMLS_CC);
1951
1952 if (res) {
1953 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1954 php_pqres_t *r = ecalloc(1, sizeof(*r));
1955
1956 r->res = res;
1957 return_value->type = IS_OBJECT;
1958 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1959 }
1960 } else {
1961 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
1962 }
1963 } else {
1964 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1965 }
1966 }
1967 zend_restore_error_handling(&zeh TSRMLS_CC);
1968 }
1969
1970 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
1971 ZEND_END_ARG_INFO();
1972 static PHP_METHOD(pqconn, getResult) {
1973 if (SUCCESS == zend_parse_parameters_none()) {
1974 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1975
1976 if (obj->intern) {
1977 PGresult *res = PQgetResult(obj->intern->conn);
1978
1979 if (res) {
1980 php_pqres_t *r = ecalloc(1, sizeof(*r));
1981
1982 r->res = res;
1983 return_value->type = IS_OBJECT;
1984 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1985 } else {
1986 RETVAL_NULL();
1987 }
1988 } else {
1989 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1990 RETVAL_FALSE;
1991 }
1992 }
1993 }
1994
1995 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
1996 ZEND_ARG_INFO(0, query)
1997 ZEND_ARG_INFO(0, callable)
1998 ZEND_END_ARG_INFO();
1999 static PHP_METHOD(pqconn, execAsync) {
2000 zend_error_handling zeh;
2001 php_pq_callback_t resolver = {{0}};
2002 char *query_str;
2003 int query_len;
2004
2005 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2006 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc)) {
2007 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2008
2009 if (obj->intern) {
2010 php_pq_callback_dtor(&obj->intern->onevent);
2011 if (resolver.fci.size > 0) {
2012 obj->intern->onevent = resolver;
2013 php_pq_callback_addref(&obj->intern->onevent);
2014 }
2015
2016 obj->intern->poller = PQconsumeInput;
2017
2018 if (PQsendQuery(obj->intern->conn, query_str)) {
2019 if (obj->intern->unbuffered) {
2020 if (!PQsetSingleRowMode(obj->intern->conn)) {
2021 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
2022 }
2023 }
2024 RETVAL_TRUE;
2025 } else {
2026 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2027 RETVAL_FALSE;
2028 }
2029 } else {
2030 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2031 RETVAL_FALSE;
2032 }
2033 }
2034 zend_restore_error_handling(&zeh TSRMLS_CC);
2035 }
2036
2037 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
2038 {
2039 Oid **types = arg;
2040 zval **ztype = p;
2041
2042 if (Z_TYPE_PP(ztype) != IS_LONG) {
2043 convert_to_long_ex(ztype);
2044 }
2045
2046 **types = Z_LVAL_PP(ztype);
2047 ++*types;
2048
2049 if (*ztype != *(zval **)p) {
2050 zval_ptr_dtor(ztype);
2051 }
2052 return ZEND_HASH_APPLY_KEEP;
2053 }
2054
2055 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
2056 {
2057 char ***params;
2058 HashTable *zdtor;
2059 zval **zparam = p;
2060
2061 params = (char ***) va_arg(argv, char ***);
2062 zdtor = (HashTable *) va_arg(argv, HashTable *);
2063
2064 if (Z_TYPE_PP(zparam) == IS_NULL) {
2065 **params = NULL;
2066 ++*params;
2067 } else {
2068 if (Z_TYPE_PP(zparam) != IS_STRING) {
2069 convert_to_string_ex(zparam);
2070 }
2071
2072 **params = Z_STRVAL_PP(zparam);
2073 ++*params;
2074
2075 if (*zparam != *(zval **)p) {
2076 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
2077 }
2078 }
2079 return ZEND_HASH_APPLY_KEEP;
2080 }
2081
2082 static int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC)
2083 {
2084 int count = zend_hash_num_elements(ht);
2085
2086 *types = NULL;
2087
2088 if (count) {
2089 Oid *tmp;
2090
2091 /* +1 for when less types than params are specified */
2092 *types = tmp = ecalloc(count + 1, sizeof(Oid));
2093 zend_hash_apply_with_argument(ht, apply_to_oid, &tmp TSRMLS_CC);
2094 }
2095
2096 return count;
2097 }
2098
2099 static int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC)
2100 {
2101 int count = zend_hash_num_elements(ht);
2102
2103 *params = NULL;
2104
2105 if (count) {
2106 char **tmp;
2107
2108 *params = tmp = ecalloc(count, sizeof(char *));
2109 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param, 2, &tmp, zdtor);
2110 }
2111
2112 return count;
2113 }
2114
2115 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
2116 ZEND_ARG_INFO(0, query)
2117 ZEND_ARG_ARRAY_INFO(0, params, 0)
2118 ZEND_ARG_ARRAY_INFO(0, types, 1)
2119 ZEND_END_ARG_INFO();
2120 static PHP_METHOD(pqconn, execParams) {
2121 zend_error_handling zeh;
2122 char *query_str;
2123 int query_len;
2124 zval *zparams;
2125 zval *ztypes = NULL;
2126
2127 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2128 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
2129 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2130
2131 if (obj->intern) {
2132 PGresult *res;
2133 int count;
2134 Oid *types = NULL;
2135 char **params = NULL;
2136 HashTable zdtor;
2137
2138 ZEND_INIT_SYMTABLE(&zdtor);
2139 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2140
2141 if (ztypes) {
2142 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
2143 }
2144
2145 res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
2146
2147 zend_hash_destroy(&zdtor);
2148 if (types) {
2149 efree(types);
2150 }
2151 if (params) {
2152 efree(params);
2153 }
2154
2155 php_pqconn_notify_listeners(obj TSRMLS_CC);
2156
2157 if (res) {
2158 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2159 php_pqres_t *r = ecalloc(1, sizeof(*r));
2160
2161 r->res = res;
2162 return_value->type = IS_OBJECT;
2163 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
2164 }
2165 } else {
2166 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2167 RETVAL_FALSE;
2168 }
2169 } else {
2170 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2171 RETVAL_FALSE;
2172 }
2173 }
2174 zend_restore_error_handling(&zeh TSRMLS_CC);
2175 }
2176
2177 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
2178 ZEND_ARG_INFO(0, query)
2179 ZEND_ARG_ARRAY_INFO(0, params, 0)
2180 ZEND_ARG_ARRAY_INFO(0, types, 1)
2181 ZEND_ARG_INFO(0, callable)
2182 ZEND_END_ARG_INFO();
2183 static PHP_METHOD(pqconn, execParamsAsync) {
2184 zend_error_handling zeh;
2185 php_pq_callback_t resolver = {{0}};
2186 char *query_str;
2187 int query_len;
2188 zval *zparams;
2189 zval *ztypes = NULL;
2190
2191 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2192 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc)) {
2193 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2194
2195 if (obj->intern) {
2196 int count;
2197 Oid *types = NULL;
2198 char **params = NULL;
2199 HashTable zdtor;
2200
2201 ZEND_INIT_SYMTABLE(&zdtor);
2202 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2203
2204 if (ztypes) {
2205 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
2206 }
2207
2208 php_pq_callback_dtor(&obj->intern->onevent);
2209 if (resolver.fci.size > 0) {
2210 obj->intern->onevent = resolver;
2211 php_pq_callback_addref(&obj->intern->onevent);
2212 }
2213
2214 obj->intern->poller = PQconsumeInput;
2215
2216 if (PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) {
2217 if (obj->intern->unbuffered) {
2218 if (!PQsetSingleRowMode(obj->intern->conn)) {
2219 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
2220 }
2221 }
2222 RETVAL_TRUE;
2223 } else {
2224 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2225 RETVAL_FALSE;
2226 }
2227
2228 zend_hash_destroy(&zdtor);
2229 if (types) {
2230 efree(types);
2231 }
2232 if (params) {
2233 efree(params);
2234 }
2235
2236 php_pqconn_notify_listeners(obj TSRMLS_CC);
2237
2238 } else {
2239 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2240 RETVAL_FALSE;
2241 }
2242 }
2243 zend_restore_error_handling(&zeh TSRMLS_CC);
2244 }
2245
2246 static STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
2247 {
2248 Oid *types = NULL;
2249 int count = 0;
2250 PGresult *res;
2251 STATUS rv;
2252
2253 if (!obj) {
2254 obj = zend_object_store_get_object(object TSRMLS_CC);
2255 }
2256
2257 if (typest) {
2258 count = zend_hash_num_elements(typest);
2259 php_pq_types_to_array(typest, &types TSRMLS_CC);
2260 }
2261
2262 res = PQprepare(obj->intern->conn, name, query, count, types);
2263
2264 if (types) {
2265 efree(types);
2266 }
2267
2268 if (res) {
2269 rv = php_pqres_success(res TSRMLS_CC);
2270 PHP_PQclear(res);
2271 } else {
2272 rv = FAILURE;
2273 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
2274 }
2275
2276 return rv;
2277 }
2278
2279 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
2280 ZEND_ARG_INFO(0, type)
2281 ZEND_ARG_INFO(0, query)
2282 ZEND_ARG_ARRAY_INFO(0, types, 1)
2283 ZEND_END_ARG_INFO();
2284 static PHP_METHOD(pqconn, prepare) {
2285 zend_error_handling zeh;
2286 zval *ztypes = NULL;
2287 char *name_str, *query_str;
2288 int name_len, *query_len;
2289
2290 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2291 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
2292 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2293
2294 if (obj->intern) {
2295 if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
2296 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2297
2298 php_pq_object_addref(obj TSRMLS_CC);
2299 stm->conn = obj;
2300 stm->name = estrdup(name_str);
2301
2302 return_value->type = IS_OBJECT;
2303 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
2304 }
2305 php_pqconn_notify_listeners(obj TSRMLS_CC);
2306 } else {
2307 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2308 }
2309 }
2310 zend_restore_error_handling(&zeh TSRMLS_CC);
2311 }
2312
2313 static STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
2314 {
2315 STATUS rv;
2316 int count;
2317 Oid *types = NULL;
2318
2319 if (!obj) {
2320 obj = zend_object_store_get_object(object TSRMLS_CC);
2321 }
2322
2323 if (typest) {
2324 count = php_pq_types_to_array(typest, &types TSRMLS_CC);
2325 }
2326
2327 if (PQsendPrepare(obj->intern->conn, name, query, count, types)) {
2328 if (obj->intern->unbuffered) {
2329 if (!PQsetSingleRowMode(obj->intern->conn)) {
2330 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
2331 }
2332 }
2333 rv = SUCCESS;
2334 } else {
2335 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
2336 rv = FAILURE;
2337 }
2338
2339 if (types) {
2340 efree(types);
2341 }
2342
2343 return rv;
2344 }
2345
2346 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
2347 ZEND_ARG_INFO(0, type)
2348 ZEND_ARG_INFO(0, query)
2349 ZEND_ARG_ARRAY_INFO(0, types, 1)
2350 ZEND_END_ARG_INFO();
2351 static PHP_METHOD(pqconn, prepareAsync) {
2352 zend_error_handling zeh;
2353 zval *ztypes = NULL;
2354 char *name_str, *query_str;
2355 int name_len, *query_len;
2356
2357 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2358 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
2359 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2360
2361 if (obj->intern) {
2362 obj->intern->poller = PQconsumeInput;
2363 if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
2364 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2365
2366 php_pq_object_addref(obj TSRMLS_CC);
2367 stm->conn = obj;
2368 stm->name = estrdup(name_str);
2369
2370 return_value->type = IS_OBJECT;
2371 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
2372 }
2373 php_pqconn_notify_listeners(obj TSRMLS_CC);
2374 } else {
2375 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2376 }
2377 }
2378 zend_restore_error_handling(&zeh TSRMLS_CC);
2379 }
2380
2381 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
2382 ZEND_ARG_INFO(0, string)
2383 ZEND_END_ARG_INFO();
2384 static PHP_METHOD(pqconn, quote) {
2385 char *str;
2386 int len;
2387
2388 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2389 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2390
2391 if (obj->intern) {
2392 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
2393
2394 if (quoted) {
2395 RETVAL_STRING(quoted, 1);
2396 PQfreemem(quoted);
2397 } else {
2398 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote string (%s)", PHP_PQerrorMessage(obj->intern->conn));
2399 RETVAL_FALSE;
2400 }
2401 } else {
2402 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2403 RETVAL_FALSE;
2404 }
2405 }
2406 }
2407
2408 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
2409 ZEND_ARG_INFO(0, type)
2410 ZEND_END_ARG_INFO();
2411 static PHP_METHOD(pqconn, quoteName) {
2412 char *str;
2413 int len;
2414
2415 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2416 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2417
2418 if (obj->intern) {
2419 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
2420
2421 if (quoted) {
2422 RETVAL_STRING(quoted, 1);
2423 PQfreemem(quoted);
2424 } else {
2425 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote name (%s)", PHP_PQerrorMessage(obj->intern->conn));
2426 RETVAL_FALSE;
2427 }
2428 } else {
2429 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2430 RETVAL_FALSE;
2431 }
2432 }
2433 }
2434
2435 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
2436 ZEND_ARG_INFO(0, bytea)
2437 ZEND_END_ARG_INFO();
2438 static PHP_METHOD(pqconn, escapeBytea) {
2439 char *str;
2440 int len;
2441
2442 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2443 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2444
2445 if (obj->intern) {
2446 size_t escaped_len;
2447 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
2448
2449 if (escaped_str) {
2450 RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
2451 PQfreemem(escaped_str);
2452 } else {
2453 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
2454 RETVAL_FALSE;
2455 }
2456 } else {
2457 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2458 RETVAL_FALSE;
2459 }
2460 }
2461 }
2462
2463 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
2464 ZEND_ARG_INFO(0, bytea)
2465 ZEND_END_ARG_INFO();
2466 static PHP_METHOD(pqconn, unescapeBytea) {
2467 char *str;
2468 int len;
2469
2470 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2471 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2472
2473 if (obj->intern) {
2474 size_t unescaped_len;
2475 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
2476
2477 if (unescaped_str) {
2478 RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
2479 PQfreemem(unescaped_str);
2480 } else {
2481 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
2482 RETVAL_FALSE;
2483 }
2484 } else {
2485 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2486 RETVAL_FALSE;
2487 }
2488 }
2489 }
2490
2491 static const char *isolation_level(long *isolation) {
2492 switch (*isolation) {
2493 case PHP_PQTXN_SERIALIZABLE:
2494 return "SERIALIZABLE";
2495 case PHP_PQTXN_REPEATABLE_READ:
2496 return "REPEATABLE READ";
2497 default:
2498 *isolation = PHP_PQTXN_READ_COMMITTED;
2499 /* no break */
2500 case PHP_PQTXN_READ_COMMITTED:
2501 return "READ COMMITTED";
2502 }
2503 }
2504
2505 static STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
2506 {
2507 if (!conn_obj) {
2508 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2509 }
2510
2511 if (conn_obj->intern) {
2512 PGresult *res;
2513 char *cmd;
2514
2515 spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
2516 isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
2517
2518 res = PQexec(conn_obj->intern->conn, cmd);
2519
2520 efree(cmd);
2521
2522 if (res) {
2523 STATUS rv = php_pqres_success(res TSRMLS_CC);
2524
2525 PHP_PQclear(res);
2526 return rv;
2527 } else {
2528 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
2529 return FAILURE;
2530 }
2531 } else {
2532 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2533 return FAILURE;
2534 }
2535 }
2536
2537 static STATUS php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
2538 {
2539 if (!conn_obj) {
2540 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2541 }
2542
2543 if (conn_obj->intern->conn) {
2544 char *cmd;
2545
2546 spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
2547 isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
2548
2549 if (PQsendQuery(conn_obj->intern->conn, cmd)) {
2550 conn_obj->intern->poller = PQconsumeInput;
2551 efree(cmd);
2552 return SUCCESS;
2553 } else {
2554 efree(cmd);
2555 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
2556 return FAILURE;
2557 }
2558 } else {
2559 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2560 return FAILURE;
2561 }
2562 }
2563
2564 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
2565 ZEND_ARG_INFO(0, isolation)
2566 ZEND_ARG_INFO(0, readonly)
2567 ZEND_ARG_INFO(0, deferrable)
2568 ZEND_END_ARG_INFO();
2569 static PHP_METHOD(pqconn, startTransaction) {
2570 zend_error_handling zeh;
2571 long isolation = PHP_PQTXN_READ_COMMITTED;
2572 zend_bool readonly = 0, deferrable = 0;
2573
2574 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2575 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
2576 STATUS rv;
2577 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2578
2579 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
2580
2581 if (SUCCESS == rv) {
2582 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
2583
2584 php_pq_object_addref(obj TSRMLS_CC);
2585 txn->conn = obj;
2586 txn->isolation = isolation;
2587 txn->readonly = readonly;
2588 txn->deferrable = deferrable;
2589
2590 return_value->type = IS_OBJECT;
2591 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
2592 }
2593 }
2594 zend_restore_error_handling(&zeh TSRMLS_CC);
2595 }
2596
2597
2598 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
2599 ZEND_ARG_INFO(0, isolation)
2600 ZEND_ARG_INFO(0, readonly)
2601 ZEND_ARG_INFO(0, deferrable)
2602 ZEND_END_ARG_INFO();
2603 static PHP_METHOD(pqconn, startTransactionAsync) {
2604 zend_error_handling zeh;
2605 long isolation = PHP_PQTXN_READ_COMMITTED;
2606 zend_bool readonly = 0, deferrable = 0;
2607
2608 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2609 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
2610 STATUS rv;
2611 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2612
2613 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
2614
2615 if (SUCCESS == rv) {
2616 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
2617
2618 php_pq_object_addref(obj TSRMLS_CC);
2619 txn->conn = obj;
2620 txn->isolation = isolation;
2621 txn->readonly = readonly;
2622 txn->deferrable = deferrable;
2623
2624 return_value->type = IS_OBJECT;
2625 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
2626 }
2627 }
2628 zend_restore_error_handling(&zeh TSRMLS_CC);
2629 }
2630
2631 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
2632 ZEND_ARG_INFO(0, stdio_stream)
2633 ZEND_END_ARG_INFO();
2634 static PHP_METHOD(pqconn, trace) {
2635 zval *zstream = NULL;
2636
2637 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) {
2638 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2639 if (obj->intern) {
2640 if (zstream) {
2641 FILE *fp;
2642 php_stream *stream = NULL;
2643
2644 php_stream_from_zval(stream, &zstream);
2645
2646 if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
2647 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
2648 PQtrace(obj->intern->conn, fp);
2649 RETVAL_TRUE;
2650 } else {
2651 RETVAL_FALSE;
2652 }
2653 } else {
2654 PQuntrace(obj->intern->conn);
2655 RETVAL_TRUE;
2656 }
2657 } else {
2658 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2659 RETVAL_FALSE;
2660 }
2661 }
2662 }
2663
2664 static zend_function_entry php_pqconn_methods[] = {
2665 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2666 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
2667 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
2668 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
2669 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
2670 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
2671 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
2672 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
2673 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
2674 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
2675 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
2676 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
2677 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
2678 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
2679 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
2680 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
2681 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
2682 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
2683 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
2684 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
2685 {0}
2686 };
2687
2688 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct, 0, 0, 1)
2689 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2690 ZEND_END_ARG_INFO();
2691 static PHP_METHOD(pqtypes, __construct) {
2692 zend_error_handling zeh;
2693 zval *zconn;
2694
2695 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2696 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zconn, php_pqconn_class_entry)) {
2697 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2698
2699 if (conn_obj->intern) {
2700 zval *retval = NULL;
2701 php_pqtypes_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2702
2703 obj->intern = ecalloc(1, sizeof(*obj->intern));
2704 obj->intern->conn = conn_obj;
2705 php_pq_object_addref(conn_obj TSRMLS_CC);
2706 zend_hash_init(&obj->intern->types, 300, NULL, ZVAL_PTR_DTOR, 0);
2707
2708 zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "refresh", &retval);
2709 if (retval) {
2710 zval_ptr_dtor(&retval);
2711 }
2712 } else {
2713 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2714 }
2715 }
2716 zend_restore_error_handling(&zeh TSRMLS_CC);
2717 }
2718
2719 #define PHP_PQ_TYPES_QUERY \
2720 "select t.oid, t.* " \
2721 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
2722 "where typisdefined " \
2723 "and typrelid=0 " \
2724 "and nspname in ('public', 'pg_catalog')"
2725
2726 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh, 0, 0, 0)
2727 ZEND_END_ARG_INFO();
2728 static PHP_METHOD(pqtypes, refresh) {
2729 if (SUCCESS == zend_parse_parameters_none()) {
2730 php_pqtypes_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2731
2732 if (obj->intern) {
2733 PGresult *res = PQexec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY);
2734
2735 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2736
2737 if (res) {
2738 if (PGRES_TUPLES_OK == PQresultStatus(res)) {
2739 int r, rows;
2740
2741 for (r = 0, rows = PQntuples(res); r < rows; ++r) {
2742 zval *row = php_pqres_row_to_zval(res, r, PHP_PQRES_FETCH_OBJECT, NULL TSRMLS_CC);
2743 long oid = atol(PQgetvalue(res, r, 0 ));
2744 char *name = PQgetvalue(res, r, 1);
2745
2746 Z_ADDREF_P(row);
2747
2748 zend_hash_index_update(&obj->intern->types, oid, (void *) &row, sizeof(zval *), NULL);
2749 zend_hash_add(&obj->intern->types, name, strlen(name) + 1, (void *) &row, sizeof(zval *), NULL);
2750 }
2751 } else {
2752 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types (%s)", PHP_PQresultErrorMessage(res));
2753 }
2754 PHP_PQclear(res);
2755 } else {
2756 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
2757 }
2758
2759 } else {
2760 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Types not initialized");
2761 }
2762 }
2763 }
2764
2765 static zend_function_entry php_pqtypes_methods[] = {
2766 PHP_ME(pqtypes, __construct, ai_pqtypes_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2767 PHP_ME(pqtypes, refresh, ai_pqtypes_refresh, ZEND_ACC_PUBLIC)
2768 {0}
2769 };
2770
2771 static zval *php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval ***row TSRMLS_DC)
2772 {
2773 php_pqres_fetch_t orig_fetch;
2774
2775 if (!obj) {
2776 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2777 }
2778
2779 if (!obj->intern->iter) {
2780 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
2781 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
2782 }
2783 orig_fetch = obj->intern->iter->fetch_type;
2784 obj->intern->iter->fetch_type = fetch_type;
2785 if (SUCCESS == obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC)) {
2786 obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, row TSRMLS_CC);
2787 obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
2788 }
2789 obj->intern->iter->fetch_type = orig_fetch;
2790
2791 return *row ? **row : NULL;
2792 }
2793
2794 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
2795 ZEND_ARG_INFO(0, fetch_type)
2796 ZEND_END_ARG_INFO();
2797 static PHP_METHOD(pqres, fetchRow) {
2798 zend_error_handling zeh;
2799 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2800 long fetch_type = -1;
2801
2802 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2803 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) {
2804 if (obj->intern) {
2805 zval **row = NULL;
2806
2807 if (fetch_type == -1) {
2808 fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
2809 }
2810 php_pqres_iteration(getThis(), obj, fetch_type, &row TSRMLS_CC);
2811
2812 if (row) {
2813 RETVAL_ZVAL(*row, 1, 0);
2814 }
2815 } else {
2816 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized");
2817 }
2818 }
2819 zend_restore_error_handling(&zeh TSRMLS_CC);
2820 }
2821
2822 static zval **column_at(zval *row, int col TSRMLS_DC)
2823 {
2824 zval **data = NULL;
2825 HashTable *ht = HASH_OF(row);
2826 int count = zend_hash_num_elements(ht);
2827
2828 if (col < count) {
2829 zend_hash_internal_pointer_reset(ht);
2830 while (col-- > 0) {
2831 zend_hash_move_forward(ht);
2832 }
2833 zend_hash_get_current_data(ht, (void *) &data);
2834 } else {
2835 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count);
2836 }
2837 return data;
2838 }
2839
2840 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
2841 ZEND_ARG_INFO(0, col_num)
2842 ZEND_END_ARG_INFO();
2843 static PHP_METHOD(pqres, fetchCol) {
2844 zend_error_handling zeh;
2845 long fetch_col = 0;
2846
2847 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2848 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
2849 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2850
2851 if (obj->intern) {
2852 zval **row = NULL;
2853
2854 php_pqres_iteration(getThis(), obj, obj->intern->iter ? obj->intern->iter->fetch_type : 0, &row TSRMLS_CC);
2855
2856 if (row) {
2857 zval **col = column_at(*row, fetch_col TSRMLS_CC);
2858
2859 if (col) {
2860 RETVAL_ZVAL(*col, 1, 0);
2861 }
2862 }
2863 } else {
2864 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized");
2865 }
2866 }
2867 zend_restore_error_handling(&zeh TSRMLS_CC);
2868 }
2869
2870 typedef struct php_pqres_col {
2871 char *name;
2872 int num;
2873 } php_pqres_col_t;
2874
2875 static int apply_to_col(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
2876 {
2877 zval **c = p;
2878 php_pqres_object_t *obj = va_arg(argv, php_pqres_object_t *);
2879 php_pqres_col_t *col, **cols = va_arg(argv, php_pqres_col_t **);
2880 STATUS *rv = va_arg(argv, STATUS *);
2881 long index = -1;
2882 char *name = NULL;
2883
2884 switch (Z_TYPE_PP(c)) {
2885 default:
2886 convert_to_string(*c);
2887 /* no break */
2888 case IS_STRING:
2889 if (!is_numeric_string(Z_STRVAL_PP(c), Z_STRLEN_PP(c), &index, NULL, 0)) {
2890 name = Z_STRVAL_PP(c);
2891 }
2892 break;
2893 case IS_LONG:
2894 index = Z_LVAL_PP(c);
2895 break;
2896 }
2897
2898 col = *cols;
2899 if (name) {
2900 col->name = name;
2901 col->num = PQfnumber(obj->intern->res, name);
2902 } else {
2903 col->name = PQfname(obj->intern->res, index);
2904 col->num = index;
2905 }
2906
2907 if (!col->name) {
2908 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column at index %ld", index);
2909 *rv = FAILURE;
2910 return ZEND_HASH_APPLY_STOP;
2911 }
2912 if (col->num == -1) {
2913 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column with name '%s'", name);
2914 *rv = FAILURE;
2915 return ZEND_HASH_APPLY_STOP;
2916 }
2917
2918 ++*cols;
2919 return ZEND_HASH_APPLY_KEEP;
2920 }
2921
2922 static php_pqres_col_t *php_pqres_convert_to_cols(php_pqres_object_t *obj, HashTable *ht TSRMLS_DC)
2923 {
2924 php_pqres_col_t *tmp, *cols = ecalloc(zend_hash_num_elements(ht), sizeof(*cols));
2925 STATUS rv = SUCCESS;
2926
2927 tmp = cols;
2928 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_col, 2, obj, &tmp, &rv);
2929
2930 if (SUCCESS == rv) {
2931 return cols;
2932 } else {
2933 efree(cols);
2934 return NULL;
2935 }
2936 }
2937
2938 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_map, 0, 0, 0)
2939 ZEND_ARG_INFO(0, keys)
2940 ZEND_ARG_INFO(0, vals)
2941 ZEND_ARG_INFO(0, fetch_type)
2942 ZEND_END_ARG_INFO();
2943 static PHP_METHOD(pqres, map) {
2944 zend_error_handling zeh;
2945 zval *zkeys = 0, *zvals = 0;
2946 long fetch_type = -1;
2947
2948
2949 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2950 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/!z/!l", &zkeys, &zvals, &fetch_type)) {
2951 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2952
2953 if (obj->intern) {
2954 int ks = 0, vs = 0;
2955 php_pqres_col_t def = {PQfname(obj->intern->res, 0), 0}, *keys = NULL, *vals = NULL;
2956
2957 if (zkeys) {
2958 convert_to_array(zkeys);
2959
2960 if ((ks = zend_hash_num_elements(Z_ARRVAL_P(zkeys)))) {
2961 keys = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zkeys) TSRMLS_CC);
2962 } else {
2963 ks = 1;
2964 keys = &def;
2965 }
2966 } else {
2967 ks = 1;
2968 keys = &def;
2969 }
2970 if (zvals) {
2971 convert_to_array(zvals);
2972
2973 if ((vs = zend_hash_num_elements(Z_ARRVAL_P(zvals)))) {
2974 vals = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zvals) TSRMLS_CC);
2975 }
2976 }
2977
2978 if (fetch_type == -1) {
2979 fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
2980 }
2981
2982 if (keys) {
2983 int rows, r;
2984 zval **cur;
2985
2986 switch (fetch_type) {
2987 case PHP_PQRES_FETCH_ARRAY:
2988 case PHP_PQRES_FETCH_ASSOC:
2989 array_init(return_value);
2990 break;
2991 case PHP_PQRES_FETCH_OBJECT:
2992 object_init(return_value);
2993 break;
2994 }
2995 for (r = 0, rows = PQntuples(obj->intern->res); r < rows; ++r) {
2996 int k, v;
2997
2998 cur = &return_value;
2999 for (k = 0; k < ks; ++k) {
3000 char *key = PQgetvalue(obj->intern->res, r, keys[k].num);
3001 int len = PQgetlength(obj->intern->res, r, keys[k].num);
3002
3003 if (SUCCESS != zend_symtable_find(HASH_OF(*cur), key, len + 1, (void *) &cur)) {
3004 zval *tmp;
3005
3006 MAKE_STD_ZVAL(tmp);
3007 switch (fetch_type) {
3008 case PHP_PQRES_FETCH_ARRAY:
3009 case PHP_PQRES_FETCH_ASSOC:
3010 array_init(tmp);
3011 break;
3012 case PHP_PQRES_FETCH_OBJECT:
3013 object_init(tmp);
3014 break;
3015 }
3016 if (SUCCESS != zend_symtable_update(HASH_OF(*cur), key, len + 1, (void *) &tmp, sizeof(zval *), (void *) &cur)) {
3017 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create map");
3018 goto err;
3019 }
3020 }
3021 }
3022 if (vals && vs) {
3023 for (v = 0; v < vs; ++v) {
3024 char *val = PQgetvalue(obj->intern->res, r, vals[v].num);
3025 int len = PQgetlength(obj->intern->res, r, vals[v].num);
3026
3027 switch (fetch_type) {
3028 case PHP_PQRES_FETCH_ARRAY:
3029 add_index_stringl(*cur, vals[v].num, val, len, 1);
3030 break;
3031 case PHP_PQRES_FETCH_ASSOC:
3032 add_assoc_stringl(*cur, vals[v].name, val, len, 1);
3033 break;
3034 case PHP_PQRES_FETCH_OBJECT:
3035 add_property_stringl(*cur, vals[v].name, val, len, 1);
3036 break;
3037 }
3038 }
3039 } else {
3040 php_pqres_row_to_zval(obj->intern->res, r, fetch_type, cur TSRMLS_CC);
3041 }
3042 }
3043 }
3044
3045 err:
3046 if (keys && keys != &def) {
3047 efree(keys);
3048 }
3049 if (vals) {
3050 efree(vals);
3051 }
3052 } else {
3053 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized");
3054 }
3055 }
3056 zend_restore_error_handling(&zeh TSRMLS_CC);
3057 }
3058
3059 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count, 0, 0, 0)
3060 ZEND_END_ARG_INFO();
3061 static PHP_METHOD(pqres, count) {
3062 if (SUCCESS == zend_parse_parameters_none()) {
3063 long count;
3064
3065 if (SUCCESS == php_pqres_count_elements(getThis(), &count TSRMLS_CC)) {
3066 RETVAL_LONG(count);
3067 } else {
3068 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized");
3069 }
3070 }
3071 }
3072
3073 static zend_function_entry php_pqres_methods[] = {
3074 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
3075 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
3076 PHP_ME(pqres, count, ai_pqres_count, ZEND_ACC_PUBLIC)
3077 PHP_ME(pqres, map, ai_pqres_map, ZEND_ACC_PUBLIC)
3078 {0}
3079 };
3080
3081 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
3082 ZEND_ARG_OBJ_INFO(0, Connection, pq\\Connection, 0)
3083 ZEND_ARG_INFO(0, type)
3084 ZEND_ARG_INFO(0, query)
3085 ZEND_ARG_ARRAY_INFO(0, types, 1)
3086 ZEND_ARG_INFO(0, async)
3087 ZEND_END_ARG_INFO();
3088 static PHP_METHOD(pqstm, __construct) {
3089 zend_error_handling zeh;
3090 zval *zconn, *ztypes = NULL;
3091 char *name_str, *query_str;
3092 int name_len, *query_len;
3093 zend_bool async = 0;
3094
3095 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
3096 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|a/!b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes, &async)) {
3097 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3098 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
3099
3100 if (conn_obj->intern) {
3101 STATUS rv;
3102 if (async) {
3103 conn_obj->intern->poller = PQconsumeInput;
3104 rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
3105 } else {
3106 rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
3107 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
3108 }
3109
3110 if (SUCCESS == rv) {
3111 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
3112
3113 php_pq_object_addref(conn_obj TSRMLS_CC);
3114 stm->conn = conn_obj;
3115 stm->name = estrdup(name_str);
3116 obj->intern = stm;
3117 }
3118 } else {
3119 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
3120 }
3121 }
3122 zend_restore_error_handling(&zeh TSRMLS_CC);
3123 }
3124
3125 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
3126 ZEND_ARG_ARRAY_INFO(0, params, 1)
3127 ZEND_END_ARG_INFO();
3128 static PHP_METHOD(pqstm, exec) {
3129 zend_error_handling zeh;
3130 zval *zparams = NULL;
3131
3132 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
3133 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
3134 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3135
3136 if (obj->intern) {
3137 if (obj->intern->conn->intern) {
3138 int count = 0;
3139 char **params = NULL;
3140 HashTable zdtor;
3141 PGresult *res;
3142
3143 if (zparams) {
3144 ZEND_INIT_SYMTABLE(&zdtor);
3145 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
3146 }
3147
3148 res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0);
3149
3150 if (params) {
3151 efree(params);
3152 }
3153 if (zparams) {
3154 zend_hash_destroy(&zdtor);
3155 }
3156
3157 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
3158
3159 if (res) {
3160 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
3161 php_pqres_t *r = ecalloc(1, sizeof(*r));
3162
3163 r->res = res;
3164 return_value->type = IS_OBJECT;
3165 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
3166 }
3167 } else {
3168 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3169 }
3170 } else {
3171 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
3172 }
3173 } else {
3174 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
3175 }
3176 }
3177 zend_restore_error_handling(&zeh TSRMLS_CC);
3178 }
3179
3180 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0)
3181 ZEND_ARG_ARRAY_INFO(0, params, 1)
3182 ZEND_ARG_INFO(0, callable)
3183 ZEND_END_ARG_INFO();
3184 static PHP_METHOD(pqstm, execAsync) {
3185 zend_error_handling zeh;
3186 zval *zparams = NULL;
3187 php_pq_callback_t resolver = {{0}};
3188
3189 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
3190 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc)) {
3191<