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