6743cf60dda2744e0341d7d5375eb40d25e470ee
[m6w6/ext-pq] / 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 #define SMART_STR_PREALLOC 256
18
19 #include <php.h>
20 #include <Zend/zend_interfaces.h>
21 #include <Zend/zend_exceptions.h>
22 #include <ext/standard/info.h>
23 #include <ext/standard/php_smart_str.h>
24 #include <ext/spl/spl_array.h>
25 #include <ext/spl/spl_exceptions.h>
26 #include <ext/raphf/php_raphf.h>
27
28 #include <libpq-events.h>
29 #include <libpq/libpq-fs.h>
30 #include <fnmatch.h>
31
32 #include "php_pq.h"
33
34 typedef int STATUS; /* SUCCESS/FAILURE */
35
36 static char *rtrim(char *e) {
37 size_t l = strlen(e);
38
39 while (l-- > 0 && e[l] == '\n') {
40 e[l] = '\0';
41 }
42 return e;
43 }
44
45 #define PHP_PQerrorMessage(c) rtrim(PQerrorMessage((c)))
46 #define PHP_PQresultErrorMessage(r) rtrim(PQresultErrorMessage((r)))
47
48 static int php_pqconn_event(PGEventId id, void *e, void *data);
49
50 #define PHP_PQclear(_r) \
51 do { \
52 php_pqres_object_t *_o = PQresultInstanceData((_r), php_pqconn_event); \
53 if (_o) { \
54 php_pq_object_delref(_o TSRMLS_CC); \
55 } else { \
56 PQclear(_r); \
57 } \
58 } while (0)
59
60 /*
61 ZEND_DECLARE_MODULE_GLOBALS(pq)
62 */
63
64 /* {{{ PHP_INI
65 */
66 /* Remove comments and fill if you need to have entries in php.ini
67 PHP_INI_BEGIN()
68 STD_PHP_INI_ENTRY("pq.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_pq_globals, pq_globals)
69 STD_PHP_INI_ENTRY("pq.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_pq_globals, pq_globals)
70 PHP_INI_END()
71 */
72 /* }}} */
73
74 /* {{{ php_pq_init_globals
75 */
76 /* Uncomment this function if you have INI entries
77 static void php_pq_init_globals(zend_pq_globals *pq_globals)
78 {
79 pq_globals->global_value = 0;
80 pq_globals->global_string = NULL;
81 }
82 */
83 /* }}} */
84
85 static zend_class_entry *php_pqconn_class_entry;
86 static zend_class_entry *php_pqtypes_class_entry;
87 static zend_class_entry *php_pqres_class_entry;
88 static zend_class_entry *php_pqstm_class_entry;
89 static zend_class_entry *php_pqtxn_class_entry;
90 static zend_class_entry *php_pqcancel_class_entry;
91 static zend_class_entry *php_pqevent_class_entry;
92 static zend_class_entry *php_pqlob_class_entry;
93 static zend_class_entry *php_pqcopy_class_entry;
94
95 typedef enum php_pqexc_type {
96 EX_INVALID_ARGUMENT,
97 EX_RUNTIME,
98 EX_CONNECTION_FAILED,
99 EX_IO,
100 EX_ESCAPE,
101 EX_BAD_METHODCALL,
102 EX_UNINITIALIZED,
103 EX_DOMAIN,
104 EX_SQL
105 } php_pqexc_type_t;
106
107 static zend_class_entry *php_pqexc_interface_class_entry;
108 static zend_class_entry *php_pqexc_invalid_argument_class_entry;
109 static zend_class_entry *php_pqexc_runtime_class_entry;
110 static zend_class_entry *php_pqexc_bad_methodcall_class_entry;
111 static zend_class_entry *php_pqexc_domain_class_entry;
112
113 static zend_class_entry *exce(php_pqexc_type_t type)
114 {
115 switch (type) {
116 default:
117 case EX_INVALID_ARGUMENT:
118 return php_pqexc_invalid_argument_class_entry;
119 case EX_RUNTIME:
120 case EX_CONNECTION_FAILED:
121 case EX_IO:
122 case EX_ESCAPE:
123 return php_pqexc_runtime_class_entry;
124 case EX_UNINITIALIZED:
125 case EX_BAD_METHODCALL:
126 return php_pqexc_bad_methodcall_class_entry;
127 case EX_DOMAIN:
128 case EX_SQL:
129 return php_pqexc_domain_class_entry;
130 }
131 }
132
133 static zval *throw_exce(php_pqexc_type_t type TSRMLS_DC, const char *fmt, ...)
134 {
135 char *msg;
136 zval *zexc;
137 va_list argv;
138
139 va_start(argv, fmt);
140 vspprintf(&msg, 0, fmt, argv);
141 va_end(argv);
142
143 zexc = zend_throw_exception(exce(type), msg, type TSRMLS_CC);
144 efree(msg);
145
146 return zexc;
147 }
148
149 static zend_object_handlers php_pqconn_object_handlers;
150 static zend_object_handlers php_pqtypes_object_handlers;
151 static zend_object_handlers php_pqres_object_handlers;
152 static zend_object_handlers php_pqstm_object_handlers;
153 static zend_object_handlers php_pqtxn_object_handlers;
154 static zend_object_handlers php_pqcancel_object_handlers;
155 static zend_object_handlers php_pqevent_object_handlers;
156 static zend_object_handlers php_pqlob_object_handlers;
157 static zend_object_handlers php_pqcopy_object_handlers;
158
159 typedef struct php_pq_callback {
160 zend_fcall_info fci;
161 zend_fcall_info_cache fcc;
162 void *data;
163 } php_pq_callback_t;
164
165 typedef struct php_pq_object {
166 zend_object zo;
167 zend_object_value zv;
168 HashTable *prophandler;
169 void *intern;
170 } php_pq_object_t;
171
172 #define PHP_PQCONN_ASYNC 0x01
173 #define PHP_PQCONN_PERSISTENT 0x02
174
175 typedef struct php_pqconn {
176 PGconn *conn;
177 int (*poller)(PGconn *);
178 php_resource_factory_t factory;
179 HashTable listeners;
180 HashTable eventhandlers;
181 php_pq_callback_t onevent;
182 unsigned unbuffered:1;
183 } php_pqconn_t;
184
185 typedef struct php_pqconn_object {
186 zend_object zo;
187 zend_object_value zv;
188 HashTable *prophandler;
189 php_pqconn_t *intern;
190 } php_pqconn_object_t;
191
192 typedef struct php_pqtypes {
193 HashTable types;
194 php_pqconn_object_t *conn;
195 } php_pqtypes_t;
196
197 typedef struct php_pqtypes_object {
198 zend_object zo;
199 zend_object_value zv;
200 HashTable *prophandler;
201 php_pqtypes_t *intern;
202 } php_pqtypes_object_t;
203
204 typedef struct php_pqconn_event_data {
205 php_pqconn_object_t *obj;
206 #ifdef ZTS
207 void ***ts;
208 #endif
209 } php_pqconn_event_data_t;
210
211 typedef enum php_pqres_fetch {
212 PHP_PQRES_FETCH_ARRAY,
213 PHP_PQRES_FETCH_ASSOC,
214 PHP_PQRES_FETCH_OBJECT
215 } php_pqres_fetch_t;
216
217 typedef struct php_pqres_iterator {
218 zend_object_iterator zi;
219 zval *current_val;
220 unsigned index;
221 php_pqres_fetch_t fetch_type;
222 } php_pqres_iterator_t;
223
224 typedef struct php_pqres {
225 PGresult *res;
226 php_pqres_iterator_t *iter;
227 HashTable bound;
228 } php_pqres_t;
229
230 typedef struct php_pqres_object {
231 zend_object zo;
232 zend_object_value zv;
233 HashTable *prophandler;
234 php_pqres_t *intern;
235 } php_pqres_object_t;
236
237 typedef struct php_pqstm {
238 php_pqconn_object_t *conn;
239 char *name;
240 HashTable bound;
241 } php_pqstm_t;
242
243 typedef struct php_pqstm_object {
244 zend_object zo;
245 zend_object_value zv;
246 HashTable *prophandler;
247 php_pqstm_t *intern;
248 } php_pqstm_object_t;
249
250 typedef enum php_pqtxn_isolation {
251 PHP_PQTXN_READ_COMMITTED,
252 PHP_PQTXN_REPEATABLE_READ,
253 PHP_PQTXN_SERIALIZABLE,
254 } php_pqtxn_isolation_t;
255
256 typedef struct php_pqtxn {
257 php_pqconn_object_t *conn;
258 php_pqtxn_isolation_t isolation;
259 unsigned savepoint;
260 unsigned open:1;
261 unsigned readonly:1;
262 unsigned deferrable:1;
263 } php_pqtxn_t;
264
265 typedef struct php_pqtxn_object {
266 zend_object zo;
267 zend_object_value zv;
268 HashTable *prophandler;
269 php_pqtxn_t *intern;
270 } php_pqtxn_object_t;
271
272 typedef struct php_pqcancel {
273 PGcancel *cancel;
274 php_pqconn_object_t *conn;
275 } php_pqcancel_t;
276
277 typedef struct php_pqcancel_object {
278 zend_object zo;
279 zend_object_value zv;
280 HashTable *prophandler;
281 php_pqcancel_t *intern;
282 } php_pqcancel_object_t;
283
284 typedef struct php_pqevent {
285 php_pq_callback_t cb;
286 char *type;
287 ulong h;
288 } php_pqevent_t;
289
290 typedef struct php_pqevent_object {
291 zend_object zo;
292 zend_object_value zv;
293 HashTable *prophandler;
294 php_pqevent_t *intern;
295 } php_pqevent_object_t;
296
297 typedef struct php_pqlob {
298 int lofd;
299 Oid loid;
300 php_pqtxn_object_t *txn;
301 } php_pqlob_t;
302
303 typedef struct php_pqlob_object {
304 zend_object zo;
305 zend_object_value zv;
306 HashTable *prophandler;
307 php_pqlob_t *intern;
308 } php_pqlob_object_t;
309
310 typedef enum php_pqcopy_direction {
311 PHP_PQCOPY_FROM_STDIN,
312 PHP_PQCOPY_TO_STDOUT
313 } php_pqcopy_direction_t;
314
315 typedef enum php_pqcopy_status {
316 PHP_PQCOPY_FAIL,
317 PHP_PQCOPY_CONT,
318 PHP_PQCOPY_DONE
319 } php_pqcopy_status_t;
320
321 typedef struct php_pqcopy {
322 php_pqcopy_direction_t direction;
323 char *expression;
324 char *options;
325 php_pqconn_object_t *conn;
326 } php_pqcopy_t;
327
328 typedef struct php_pqcopy_object {
329 zend_object zo;
330 zend_object_value zv;
331 HashTable *prophandler;
332 php_pqcopy_t *intern;
333 } php_pqcopy_object_t;
334
335 static HashTable php_pqconn_object_prophandlers;
336 static HashTable php_pqtypes_object_prophandlers;
337 static HashTable php_pqres_object_prophandlers;
338 static HashTable php_pqstm_object_prophandlers;
339 static HashTable php_pqtxn_object_prophandlers;
340 static HashTable php_pqcancel_object_prophandlers;
341 static HashTable php_pqevent_object_prophandlers;
342 static HashTable php_pqlob_object_prophandlers;
343 static HashTable php_pqcopy_object_prophandlers;
344
345 typedef void (*php_pq_object_prophandler_func_t)(zval *object, void *o, zval *return_value TSRMLS_DC);
346
347 typedef struct php_pq_object_prophandler {
348 php_pq_object_prophandler_func_t read;
349 php_pq_object_prophandler_func_t write;
350 } php_pq_object_prophandler_t;
351
352 static zend_object_iterator_funcs php_pqres_iterator_funcs;
353
354 static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
355 {
356 php_pqres_iterator_t *iter;
357 zval *prop, *zfetch_type;
358
359 iter = ecalloc(1, sizeof(*iter));
360 iter->zi.funcs = &php_pqres_iterator_funcs;
361 iter->zi.data = object;
362 Z_ADDREF_P(object);
363
364 zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC);
365 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
366 convert_to_long_ex(&zfetch_type);
367 }
368 iter->fetch_type = Z_LVAL_P(zfetch_type);
369 if (zfetch_type != prop) {
370 zval_ptr_dtor(&zfetch_type);
371 }
372 if (Z_REFCOUNT_P(prop)) {
373 zval_ptr_dtor(&prop);
374 } else {
375 zval_dtor(prop);
376 FREE_ZVAL(prop);
377 }
378
379 return (zend_object_iterator *) iter;
380 }
381
382 static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
383 {
384 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
385
386 if (iter->current_val) {
387 zval_ptr_dtor(&iter->current_val);
388 iter->current_val = NULL;
389 }
390 zval_ptr_dtor((zval **) &iter->zi.data);
391 efree(iter);
392 }
393
394 static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC)
395 {
396 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
397 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
398
399 switch (PQresultStatus(obj->intern->res)) {
400 case PGRES_TUPLES_OK:
401 case PGRES_SINGLE_TUPLE:
402 if (PQntuples(obj->intern->res) <= iter->index) {
403 return FAILURE;
404 }
405 break;
406 default:
407 return FAILURE;
408 }
409
410 return SUCCESS;
411 }
412
413 static zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval **data_ptr TSRMLS_DC)
414 {
415 zval *data = NULL;
416 int c, cols;
417
418 if (data_ptr) {
419 data = *data_ptr;
420 }
421 if (!data) {
422 MAKE_STD_ZVAL(data);
423 if (PHP_PQRES_FETCH_OBJECT == fetch_type) {
424 object_init(data);
425 } else {
426 array_init(data);
427 }
428 if (data_ptr) {
429 *data_ptr = data;
430 }
431 }
432
433 for (c = 0, cols = PQnfields(res); c < cols; ++c) {
434 if (PQgetisnull(res, row, c)) {
435 switch (fetch_type) {
436 case PHP_PQRES_FETCH_OBJECT:
437 add_property_null(data, PQfname(res, c));
438 break;
439
440 case PHP_PQRES_FETCH_ASSOC:
441 add_assoc_null(data, PQfname(res, c));
442 break;
443
444 case PHP_PQRES_FETCH_ARRAY:
445 add_index_null(data, c);
446 break;
447 }
448 } else {
449 char *val = PQgetvalue(res, row, c);
450 int len = PQgetlength(res, row, c);
451
452 switch (fetch_type) {
453 case PHP_PQRES_FETCH_OBJECT:
454 add_property_stringl(data, PQfname(res, c), val, len, 1);
455 break;
456
457 case PHP_PQRES_FETCH_ASSOC:
458 add_assoc_stringl(data, PQfname(res, c), val, len, 1);
459 break;
460
461 case PHP_PQRES_FETCH_ARRAY:
462 add_index_stringl(data, c, val, len ,1);
463 break;
464 }
465 }
466 }
467
468 return data;
469 }
470
471 static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr TSRMLS_DC)
472 {
473 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
474 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
475
476 if (iter->current_val) {
477 zval_ptr_dtor(&iter->current_val);
478 }
479 iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC);
480 *data_ptr = &iter->current_val;
481 }
482
483 static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint *key_len, ulong *key_num TSRMLS_DC)
484 {
485 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
486
487 *key_num = (ulong) iter->index;
488
489 return HASH_KEY_IS_LONG;
490 }
491
492 static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC)
493 {
494 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
495
496 ++iter->index;
497 }
498
499 static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC)
500 {
501 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
502
503 iter->index = 0;
504 }
505
506 static zend_object_iterator_funcs php_pqres_iterator_funcs = {
507 php_pqres_iterator_dtor,
508 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
509 php_pqres_iterator_valid,
510 /* fetch the item data for the current element */
511 php_pqres_iterator_current,
512 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
513 php_pqres_iterator_key,
514 /* step forwards to next element */
515 php_pqres_iterator_next,
516 /* rewind to start of data (optional, may be NULL) */
517 php_pqres_iterator_rewind,
518 /* invalidate current value/key (optional, may be NULL) */
519 NULL
520 };
521
522 static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC)
523 {
524 php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
525
526 if (!obj->intern) {
527 return FAILURE;
528 } else {
529 *count = (long) PQntuples(obj->intern->res);
530 return SUCCESS;
531 }
532 }
533
534 static STATUS php_pqres_success(PGresult *res TSRMLS_DC)
535 {
536 zval *zexc;
537
538 switch (PQresultStatus(res)) {
539 case PGRES_BAD_RESPONSE:
540 case PGRES_NONFATAL_ERROR:
541 case PGRES_FATAL_ERROR:
542 zexc = throw_exce(EX_SQL TSRMLS_CC, "%s", PHP_PQresultErrorMessage(res));
543 zend_update_property_string(php_pqexc_domain_class_entry, zexc, ZEND_STRL("sqlstate"), PQresultErrorField(res, PG_DIAG_SQLSTATE) TSRMLS_CC);
544 return FAILURE;
545 default:
546 return SUCCESS;
547 }
548 }
549
550 /*
551 static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC)
552 {
553 zval **evhs;
554
555 if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
556 zend_hash_index_del(Z_ARRVAL_PP(evhs), id);
557 }
558 }
559 */
560
561 static ulong php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, zval *zevent TSRMLS_DC)
562 {
563 zval **evhs;
564 ulong h;
565
566 if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
567 Z_ADDREF_P(zevent);
568 h = zend_hash_next_free_element(Z_ARRVAL_PP(evhs));
569 add_next_index_zval(*evhs, zevent);
570 } else {
571 zval *evh;
572
573 MAKE_STD_ZVAL(evh);
574 array_init(evh);
575 Z_ADDREF_P(zevent);
576 h = zend_hash_next_free_element(Z_ARRVAL_P(evh));
577 add_next_index_zval(evh, zevent);
578 zend_hash_add(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(zval *), NULL);
579 }
580
581 return h;
582 }
583
584 static void php_pq_callback_dtor(php_pq_callback_t *cb) {
585 if (cb->fci.size > 0) {
586 zend_fcall_info_args_clear(&cb->fci, 1);
587 zval_ptr_dtor(&cb->fci.function_name);
588 if (cb->fci.object_ptr) {
589 zval_ptr_dtor(&cb->fci.object_ptr);
590 }
591 }
592 cb->fci.size = 0;
593 }
594
595 static void php_pq_callback_addref(php_pq_callback_t *cb)
596 {
597 Z_ADDREF_P(cb->fci.function_name);
598 if (cb->fci.object_ptr) {
599 Z_ADDREF_P(cb->fci.object_ptr);
600 }
601 }
602
603 static void php_pq_object_to_zval(void *o, zval **zv TSRMLS_DC)
604 {
605 php_pq_object_t *obj = o;
606
607 if (!*zv) {
608 MAKE_STD_ZVAL(*zv);
609 }
610
611 zend_objects_store_add_ref_by_handle(obj->zv.handle TSRMLS_CC);
612
613 (*zv)->type = IS_OBJECT;
614 (*zv)->value.obj = obj->zv;
615 }
616
617 static void php_pq_object_to_zval_no_addref(void *o, zval **zv TSRMLS_DC)
618 {
619 php_pq_object_t *obj = o;
620
621 if (!*zv) {
622 MAKE_STD_ZVAL(*zv);
623 }
624
625 /* no add ref */
626
627 (*zv)->type = IS_OBJECT;
628 (*zv)->value.obj = obj->zv;
629 }
630
631 static void php_pq_object_addref(void *o TSRMLS_DC)
632 {
633 php_pq_object_t *obj = o;
634 zend_objects_store_add_ref_by_handle(obj->zv.handle TSRMLS_CC);
635 }
636
637 static void php_pq_object_delref(void *o TSRMLS_DC)
638 {
639 php_pq_object_t *obj = o;
640 zend_objects_store_del_ref_by_handle_ex(obj->zv.handle, obj->zv.handlers TSRMLS_CC);
641 }
642
643 static void php_pqconn_object_free(void *o TSRMLS_DC)
644 {
645 php_pqconn_object_t *obj = o;
646 #if DBG_GC
647 fprintf(stderr, "FREE conn(#%d) %p\n", obj->zv.handle, obj);
648 #endif
649 if (obj->intern) {
650 php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn TSRMLS_CC);
651 php_resource_factory_dtor(&obj->intern->factory);
652 php_pq_callback_dtor(&obj->intern->onevent);
653 zend_hash_destroy(&obj->intern->listeners);
654 zend_hash_destroy(&obj->intern->eventhandlers);
655 efree(obj->intern);
656 obj->intern = NULL;
657 }
658 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
659 efree(obj);
660 }
661
662 static void php_pqtypes_object_free(void *o TSRMLS_DC)
663 {
664 php_pqtypes_object_t *obj = o;
665 #if DBG_GC
666 fprintf(stderr, "FREE types(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn);
667 #endif
668 if (obj->intern) {
669 zend_hash_destroy(&obj->intern->types);
670 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
671 efree(obj->intern);
672 obj->intern = NULL;
673 }
674 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
675 efree(obj);
676 }
677
678 static void php_pqres_object_free(void *o TSRMLS_DC)
679 {
680 php_pqres_object_t *obj = o;
681 #if DBG_GC
682 fprintf(stderr, "FREE res(#%d) %p\n", obj->zv.handle, obj);
683 #endif
684 if (obj->intern) {
685 if (obj->intern->res) {
686 PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL);
687 PQclear(obj->intern->res);
688 obj->intern->res = NULL;
689 }
690
691 if (obj->intern->iter) {
692 php_pqres_iterator_dtor((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
693 obj->intern->iter = NULL;
694 }
695
696 zend_hash_destroy(&obj->intern->bound);
697
698 efree(obj->intern);
699 obj->intern = NULL;
700 }
701 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
702 efree(obj);
703 }
704
705 static void php_pqstm_object_free(void *o TSRMLS_DC)
706 {
707 php_pqstm_object_t *obj = o;
708 #if DBG_GC
709 fprintf(stderr, "FREE stm(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn);
710 #endif
711 if (obj->intern) {
712 char *quoted_name = PQescapeIdentifier(obj->intern->conn->intern->conn, obj->intern->name, strlen(obj->intern->name));
713
714 php_pq_callback_dtor(&obj->intern->conn->intern->onevent);
715
716 if (quoted_name) {
717 PGresult *res;
718 smart_str cmd = {0};
719
720 smart_str_appends(&cmd, "DEALLOCATE ");
721 smart_str_appends(&cmd, quoted_name);
722 smart_str_0(&cmd);
723 PQfreemem(quoted_name);
724
725 if ((res = PQexec(obj->intern->conn->intern->conn, cmd.c))) {
726 PHP_PQclear(res);
727 }
728 smart_str_free(&cmd);
729 }
730
731 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
732 efree(obj->intern->name);
733 zend_hash_destroy(&obj->intern->bound);
734 efree(obj->intern);
735 obj->intern = NULL;
736 }
737 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
738 efree(obj);
739 }
740
741 static void php_pqtxn_object_free(void *o TSRMLS_DC)
742 {
743 php_pqtxn_object_t *obj = o;
744 #if DBG_GC
745 fprintf(stderr, "FREE txn(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn);
746 #endif
747 if (obj->intern) {
748 if (obj->intern->open) {
749 PGresult *res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK");
750
751 if (res) {
752 PHP_PQclear(res);
753 }
754 }
755 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
756 efree(obj->intern);
757 obj->intern = NULL;
758 }
759 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
760 efree(obj);
761 }
762
763 static void php_pqcancel_object_free(void *o TSRMLS_DC)
764 {
765 php_pqcancel_object_t *obj = o;
766 #if DBG_GC
767 fprintf(stderr, "FREE cancel(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn);
768 #endif
769 if (obj->intern) {
770 PQfreeCancel(obj->intern->cancel);
771 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
772 efree(obj->intern);
773 obj->intern = NULL;
774 }
775 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
776 efree(obj);
777 }
778
779 static void php_pqevent_object_free(void *o TSRMLS_DC)
780 {
781 php_pqevent_object_t *obj = o;
782 #if DBG_GC
783 fprintf(stderr, "FREE event(#%d) %p\n", obj->zv.handle, obj);
784 #endif
785 if (obj->intern) {
786 php_pq_callback_dtor(&obj->intern->cb);
787 efree(obj->intern->type);
788 efree(obj->intern);
789 obj->intern = NULL;
790 }
791 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
792 efree(obj);
793 }
794
795 static void php_pqlob_object_free(void *o TSRMLS_DC)
796 {
797 php_pqlob_object_t *obj = o;
798 #if DBG_GC
799 fprintf(stderr, "FREE lob(#%d) %p (txn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->txn->zv.handle, obj->intern->txn);
800 #endif
801 if (obj->intern) {
802 if (obj->intern->lofd) {
803 lo_close(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd);
804 }
805 php_pq_object_delref(obj->intern->txn TSRMLS_CC);
806 efree(obj->intern);
807 obj->intern = NULL;
808 }
809 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
810 efree(obj);
811 }
812
813 static void php_pqcopy_object_free(void *o TSRMLS_DC)
814 {
815 php_pqcopy_object_t *obj = o;
816 #if DBG_GC
817 fprintf(stderr, "FREE copy(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn);
818 #endif
819 if (obj->intern) {
820 efree(obj->intern->expression);
821 efree(obj->intern->options);
822 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
823 efree(obj->intern);
824 obj->intern = NULL;
825 }
826 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
827 efree(obj);
828 }
829
830 static zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern, php_pqconn_object_t **ptr TSRMLS_DC)
831 {
832 php_pqconn_object_t *o;
833
834 o = ecalloc(1, sizeof(*o));
835 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
836 object_properties_init((zend_object *) o, ce);
837 o->prophandler = &php_pqconn_object_prophandlers;
838
839 if (ptr) {
840 *ptr = o;
841 }
842
843 if (intern) {
844 o->intern = intern;
845 }
846
847 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqconn_object_free, NULL TSRMLS_CC);
848 o->zv.handlers = &php_pqconn_object_handlers;
849
850 return o->zv;
851 }
852
853 static zend_object_value php_pqtypes_create_object_ex(zend_class_entry *ce, php_pqtypes_t *intern, php_pqtypes_object_t **ptr TSRMLS_DC)
854 {
855 php_pqtypes_object_t *o;
856
857 o = ecalloc(1, sizeof(*o));
858 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
859 object_properties_init((zend_object *) o, ce);
860 o->prophandler = &php_pqtypes_object_prophandlers;
861
862 if (ptr) {
863 *ptr = o;
864 }
865
866 if (intern) {
867 o->intern = intern;
868 }
869
870 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqtypes_object_free, NULL TSRMLS_CC);
871 o->zv.handlers = &php_pqtypes_object_handlers;
872
873 return o->zv;
874 }
875
876 static zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern, php_pqres_object_t **ptr TSRMLS_DC)
877 {
878 php_pqres_object_t *o;
879
880 o = ecalloc(1, sizeof(*o));
881 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
882 object_properties_init((zend_object *) o, ce);
883 o->prophandler = &php_pqres_object_prophandlers;
884
885 if (ptr) {
886 *ptr = o;
887 }
888
889 if (intern) {
890 o->intern = intern;
891 }
892
893 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqres_object_free, NULL TSRMLS_CC);
894 o->zv.handlers = &php_pqres_object_handlers;
895
896 return o->zv;
897 }
898
899 static zend_object_value php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern, php_pqstm_object_t **ptr TSRMLS_DC)
900 {
901 php_pqstm_object_t *o;
902
903 o = ecalloc(1, sizeof(*o));
904 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
905 object_properties_init((zend_object *) o, ce);
906 o->prophandler = &php_pqstm_object_prophandlers;
907
908 if (ptr) {
909 *ptr = o;
910 }
911
912 if (intern) {
913 o->intern = intern;
914 }
915
916 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqstm_object_free, NULL TSRMLS_CC);
917 o->zv.handlers = &php_pqstm_object_handlers;
918
919 return o->zv;
920 }
921
922 static zend_object_value php_pqtxn_create_object_ex(zend_class_entry *ce, php_pqtxn_t *intern, php_pqtxn_object_t **ptr TSRMLS_DC)
923 {
924 php_pqtxn_object_t *o;
925
926 o = ecalloc(1, sizeof(*o));
927 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
928 object_properties_init((zend_object *) o, ce);
929 o->prophandler = &php_pqtxn_object_prophandlers;
930
931 if (ptr) {
932 *ptr = o;
933 }
934
935 if (intern) {
936 o->intern = intern;
937 }
938
939 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqtxn_object_free, NULL TSRMLS_CC);
940 o->zv.handlers = &php_pqtxn_object_handlers;
941
942 return o->zv;
943 }
944
945 static zend_object_value php_pqcancel_create_object_ex(zend_class_entry *ce, php_pqcancel_t *intern, php_pqcancel_object_t **ptr TSRMLS_DC)
946 {
947 php_pqcancel_object_t *o;
948
949 o = ecalloc(1, sizeof(*o));
950 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
951 object_properties_init((zend_object *) o, ce);
952 o->prophandler = &php_pqcancel_object_prophandlers;
953
954 if (ptr) {
955 *ptr = o;
956 }
957
958 if (intern) {
959 o->intern = intern;
960 }
961
962 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqcancel_object_free, NULL TSRMLS_CC);
963 o->zv.handlers = &php_pqcancel_object_handlers;
964
965 return o->zv;
966 }
967
968 static zend_object_value php_pqevent_create_object_ex(zend_class_entry *ce, php_pqevent_t *intern, php_pqevent_object_t **ptr TSRMLS_DC)
969 {
970 php_pqevent_object_t *o;
971
972 o = ecalloc(1, sizeof(*o));
973 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
974 object_properties_init((zend_object *) o, ce);
975 o->prophandler = &php_pqevent_object_prophandlers;
976
977 if (ptr) {
978 *ptr = o;
979 }
980
981 if (intern) {
982 o->intern = intern;
983 }
984
985 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqevent_object_free, NULL TSRMLS_CC);
986 o->zv.handlers = &php_pqevent_object_handlers;
987
988 return o->zv;
989 }
990
991 static zend_object_value php_pqlob_create_object_ex(zend_class_entry *ce, php_pqlob_t *intern, php_pqlob_object_t **ptr TSRMLS_DC)
992 {
993 php_pqlob_object_t *o;
994
995 o = ecalloc(1, sizeof(*o));
996 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
997 object_properties_init((zend_object *) o, ce);
998 o->prophandler = &php_pqlob_object_prophandlers;
999
1000 if (ptr) {
1001 *ptr = o;
1002 }
1003
1004 if (intern) {
1005 o->intern = intern;
1006 }
1007
1008 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqlob_object_free, NULL TSRMLS_CC);
1009 o->zv.handlers = &php_pqlob_object_handlers;
1010
1011 return o->zv;
1012 }
1013
1014 static zend_object_value php_pqcopy_create_object_ex(zend_class_entry *ce, php_pqcopy_t *intern, php_pqcopy_object_t **ptr TSRMLS_DC)
1015 {
1016 php_pqcopy_object_t *o;
1017
1018 o = ecalloc(1, sizeof(*o));
1019 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
1020 object_properties_init((zend_object *) o, ce);
1021 o->prophandler = &php_pqcopy_object_prophandlers;
1022
1023 if (ptr) {
1024 *ptr = o;
1025 }
1026
1027 if (intern) {
1028 o->intern = intern;
1029 }
1030
1031 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqcopy_object_free, NULL TSRMLS_CC);
1032 o->zv.handlers = &php_pqcopy_object_handlers;
1033
1034 return o->zv;
1035 }
1036
1037 static zend_object_value php_pqconn_create_object(zend_class_entry *class_type TSRMLS_DC)
1038 {
1039 return php_pqconn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1040 }
1041
1042 static zend_object_value php_pqtypes_create_object(zend_class_entry *class_type TSRMLS_DC)
1043 {
1044 return php_pqtypes_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1045 }
1046
1047 static zend_object_value php_pqres_create_object(zend_class_entry *class_type TSRMLS_DC)
1048 {
1049 return php_pqres_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1050 }
1051
1052 static zend_object_value php_pqstm_create_object(zend_class_entry *class_type TSRMLS_DC)
1053 {
1054 return php_pqstm_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1055 }
1056
1057 static zend_object_value php_pqtxn_create_object(zend_class_entry *class_type TSRMLS_DC)
1058 {
1059 return php_pqtxn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1060 }
1061
1062 static zend_object_value php_pqcancel_create_object(zend_class_entry *class_type TSRMLS_DC)
1063 {
1064 return php_pqcancel_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1065 }
1066
1067 static zend_object_value php_pqevent_create_object(zend_class_entry *class_type TSRMLS_DC)
1068 {
1069 return php_pqevent_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1070 }
1071
1072 static zend_object_value php_pqlob_create_object(zend_class_entry *class_type TSRMLS_DC)
1073 {
1074 return php_pqlob_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1075 }
1076
1077 static zend_object_value php_pqcopy_create_object(zend_class_entry *class_type TSRMLS_DC)
1078 {
1079 return php_pqcopy_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
1080 }
1081
1082 static int apply_pi_to_ht(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1083 {
1084 zend_property_info *pi = p;
1085 HashTable *ht = va_arg(argv, HashTable *);
1086 zval *object = va_arg(argv, zval *);
1087 php_pq_object_t *obj = va_arg(argv, php_pq_object_t *);
1088 int addref = va_arg(argv, int);
1089 zval *property = zend_read_property(obj->zo.ce, object, pi->name, pi->name_length, 0 TSRMLS_CC);
1090
1091 if (addref) {
1092 Z_ADDREF_P(property);
1093 }
1094 zend_hash_add(ht, pi->name, pi->name_length + 1, (void *) &property, sizeof(zval *), NULL);
1095
1096 return ZEND_HASH_APPLY_KEEP;
1097 }
1098
1099 static HashTable *php_pq_object_debug_info(zval *object, int *temp TSRMLS_DC)
1100 {
1101 HashTable *ht;
1102 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1103
1104 *temp = 1;
1105 ALLOC_HASHTABLE(ht);
1106 ZEND_INIT_SYMTABLE(ht);
1107
1108 zend_hash_apply_with_arguments(&obj->zo.ce->properties_info TSRMLS_CC, apply_pi_to_ht, 4, ht, object, obj, 1);
1109
1110 return ht;
1111 }
1112
1113 static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
1114 {
1115 php_pqconn_object_t *obj = o;
1116
1117 RETVAL_LONG(PQstatus(obj->intern->conn));
1118 }
1119
1120 static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value TSRMLS_DC)
1121 {
1122 php_pqconn_object_t *obj = o;
1123
1124 RETVAL_LONG(PQtransactionStatus(obj->intern->conn));
1125 }
1126
1127 static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
1128 {
1129 php_pqconn_object_t *obj = o;
1130 char *error = PHP_PQerrorMessage(obj->intern->conn);
1131
1132 if (error) {
1133 RETVAL_STRING(error, 1);
1134 } else {
1135 RETVAL_NULL();
1136 }
1137 }
1138
1139 static int apply_notify_listener(void *p, void *arg TSRMLS_DC)
1140 {
1141 php_pq_callback_t *listener = p;
1142 PGnotify *nfy = arg;
1143 zval *zpid, *zchannel, *zmessage;
1144
1145 MAKE_STD_ZVAL(zpid);
1146 ZVAL_LONG(zpid, nfy->be_pid);
1147 MAKE_STD_ZVAL(zchannel);
1148 ZVAL_STRING(zchannel, nfy->relname, 1);
1149 MAKE_STD_ZVAL(zmessage);
1150 ZVAL_STRING(zmessage, nfy->extra, 1);
1151
1152 zend_fcall_info_argn(&listener->fci TSRMLS_CC, 3, &zchannel, &zmessage, &zpid);
1153 zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL TSRMLS_CC);
1154
1155 zval_ptr_dtor(&zchannel);
1156 zval_ptr_dtor(&zmessage);
1157 zval_ptr_dtor(&zpid);
1158
1159 return ZEND_HASH_APPLY_KEEP;
1160 }
1161
1162 static int apply_notify_listeners(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1163 {
1164 HashTable *listeners = p;
1165 PGnotify *nfy = va_arg(argv, PGnotify *);
1166
1167 if (0 == fnmatch(key->arKey, nfy->relname, 0)) {
1168 zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy TSRMLS_CC);
1169 }
1170
1171 return ZEND_HASH_APPLY_KEEP;
1172 }
1173
1174 static void php_pqconn_notify_listeners(php_pqconn_object_t *obj TSRMLS_DC)
1175 {
1176 PGnotify *nfy;
1177
1178 while ((nfy = PQnotifies(obj->intern->conn))) {
1179 zend_hash_apply_with_arguments(&obj->intern->listeners TSRMLS_CC, apply_notify_listeners, 1, nfy);
1180 PQfreemem(nfy);
1181 }
1182 }
1183
1184 static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value TSRMLS_DC)
1185 {
1186 php_pqconn_object_t *obj = o;
1187
1188 RETVAL_BOOL(PQisBusy(obj->intern->conn));
1189 }
1190
1191 static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value TSRMLS_DC)
1192 {
1193 php_pqconn_object_t *obj = o;
1194
1195 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn)), 1);
1196 }
1197
1198 static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value TSRMLS_DC)
1199 {
1200 php_pqconn_object_t *obj = o;
1201 zval *zenc = value;
1202
1203 if (Z_TYPE_P(value) != IS_STRING) {
1204 if (Z_REFCOUNT_P(value) > 1) {
1205 zval *tmp;
1206 MAKE_STD_ZVAL(tmp);
1207 ZVAL_ZVAL(tmp, zenc, 1, 0);
1208 convert_to_string(tmp);
1209 zenc = tmp;
1210 } else {
1211 convert_to_string_ex(&zenc);
1212 }
1213 }
1214
1215 if (0 > PQsetClientEncoding(obj->intern->conn, Z_STRVAL_P(zenc))) {
1216 zend_error(E_NOTICE, "Unrecognized encoding '%s'", Z_STRVAL_P(zenc));
1217 }
1218
1219 if (zenc != value) {
1220 zval_ptr_dtor(&zenc);
1221 }
1222 }
1223
1224 static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value TSRMLS_DC)
1225 {
1226 php_pqconn_object_t *obj = o;
1227
1228 RETVAL_BOOL(obj->intern->unbuffered);
1229 }
1230
1231 static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value TSRMLS_DC)
1232 {
1233 php_pqconn_object_t *obj = o;
1234
1235 obj->intern->unbuffered = zend_is_true(value);
1236 }
1237
1238 static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value TSRMLS_DC)
1239 {
1240 php_pqconn_object_t *obj = o;
1241 char *db = PQdb(obj->intern->conn);
1242
1243 if (db) {
1244 RETVAL_STRING(db, 1);
1245 } else {
1246 RETVAL_EMPTY_STRING();
1247 }
1248 }
1249
1250 static void php_pqconn_object_read_user(zval *object, void *o, zval *return_value TSRMLS_DC)
1251 {
1252 php_pqconn_object_t *obj = o;
1253 char *user = PQuser(obj->intern->conn);
1254
1255 if (user) {
1256 RETVAL_STRING(user, 1);
1257 } else {
1258 RETVAL_EMPTY_STRING();
1259 }
1260 }
1261
1262 static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_value TSRMLS_DC)
1263 {
1264 php_pqconn_object_t *obj = o;
1265 char *pass = PQpass(obj->intern->conn);
1266
1267 if (pass) {
1268 RETVAL_STRING(pass, 1);
1269 } else {
1270 RETVAL_EMPTY_STRING();
1271 }
1272 }
1273
1274 static void php_pqconn_object_read_host(zval *object, void *o, zval *return_value TSRMLS_DC)
1275 {
1276 php_pqconn_object_t *obj = o;
1277 char *host = PQhost(obj->intern->conn);
1278
1279 if (host) {
1280 RETVAL_STRING(host, 1);
1281 } else {
1282 RETVAL_EMPTY_STRING();
1283 }
1284 }
1285
1286 static void php_pqconn_object_read_port(zval *object, void *o, zval *return_value TSRMLS_DC)
1287 {
1288 php_pqconn_object_t *obj = o;
1289 char *port = PQport(obj->intern->conn);
1290
1291 if (port) {
1292 RETVAL_STRING(port, 1);
1293 } else {
1294 RETVAL_EMPTY_STRING();
1295 }
1296 }
1297
1298 static void php_pqconn_object_read_options(zval *object, void *o, zval *return_value TSRMLS_DC)
1299 {
1300 php_pqconn_object_t *obj = o;
1301 char *options = PQoptions(obj->intern->conn);
1302
1303 if (options) {
1304 RETVAL_STRING(options, 1);
1305 } else {
1306 RETVAL_EMPTY_STRING();
1307 }
1308 }
1309
1310 static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value TSRMLS_DC)
1311 {
1312 php_pqconn_object_t *obj = o;
1313
1314 array_init(return_value);
1315 zend_hash_copy(Z_ARRVAL_P(return_value), &obj->intern->eventhandlers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
1316 }
1317
1318 static void php_pqtypes_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1319 {
1320 php_pqtypes_object_t *obj = o;
1321
1322 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1323 }
1324
1325 static int has_dimension(HashTable *ht, zval *member, char **key_str, int *key_len, ulong *index TSRMLS_DC)
1326 {
1327 long lval = 0;
1328 zval *tmp = member;
1329
1330 switch (Z_TYPE_P(member)) {
1331 default:
1332 convert_to_string_ex(&tmp);
1333 /* no break */
1334 case IS_STRING:
1335 if (!is_numeric_string(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &lval, NULL, 0)) {
1336 int exists = zend_hash_exists(ht, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp) + 1);
1337
1338 if (key_str) {
1339 *key_str = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
1340 if (key_len) {
1341 *key_len = Z_STRLEN_P(tmp) + 1;
1342 }
1343 }
1344 if (member != tmp) {
1345 zval_ptr_dtor(&tmp);
1346 }
1347
1348 return exists;
1349 }
1350 break;
1351 case IS_LONG:
1352 lval = Z_LVAL_P(member);
1353 break;
1354 }
1355
1356 if (member != tmp) {
1357 zval_ptr_dtor(&tmp);
1358 }
1359 if (index) {
1360 *index = lval;
1361 }
1362 return zend_hash_index_exists(ht, lval);
1363 }
1364
1365 static int php_pqtypes_object_has_dimension(zval *object, zval *member, int check_empty TSRMLS_DC)
1366 {
1367 php_pqtypes_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1368 char *key_str = NULL;
1369 int key_len = 0;
1370 ulong index = 0;
1371
1372 if (check_empty) {
1373 if (has_dimension(&obj->intern->types, member, &key_str, &key_len, &index TSRMLS_CC)) {
1374 zval **data;
1375
1376 if (key_str && key_len) {
1377 if (SUCCESS == zend_hash_find(&obj->intern->types, key_str, key_len, (void *) &data)) {
1378 efree(key_str);
1379 return Z_TYPE_PP(data) != IS_NULL;
1380 }
1381 efree(key_str);
1382 } else {
1383 if (SUCCESS == zend_hash_index_find(&obj->intern->types, index, (void *) &data)) {
1384 return Z_TYPE_PP(data) != IS_NULL;
1385 }
1386 }
1387 }
1388 if (key_str) {
1389 efree(key_str);
1390 }
1391 } else {
1392 return has_dimension(&obj->intern->types, member, NULL, NULL, NULL TSRMLS_CC);
1393 }
1394
1395 return 0;
1396 }
1397
1398 static zval *php_pqtypes_object_read_dimension(zval *object, zval *member, int type TSRMLS_DC)
1399 {
1400 ulong index = 0;
1401 char *key_str = NULL;
1402 int key_len = 0;
1403 php_pqtypes_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1404
1405 if (has_dimension(&obj->intern->types, member, &key_str, &key_len, &index TSRMLS_CC)) {
1406 zval **data;
1407
1408 if (key_str && key_len) {
1409 if (SUCCESS == zend_hash_find(&obj->intern->types, key_str, key_len, (void *) &data)) {
1410 efree(key_str);
1411 return *data;
1412 }
1413 } else {
1414 if (SUCCESS == zend_hash_index_find(&obj->intern->types, index, (void *) &data)) {
1415 return *data;
1416 }
1417 }
1418 if (key_str) {
1419 efree(key_str);
1420 }
1421 }
1422
1423 return NULL;
1424 }
1425
1426 static void php_pqres_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
1427 {
1428 php_pqres_object_t *obj = o;
1429
1430 RETVAL_LONG(PQresultStatus(obj->intern->res));
1431 }
1432
1433 static void php_pqres_object_read_status_message(zval *object, void *o, zval *return_value TSRMLS_DC)
1434 {
1435 php_pqres_object_t *obj = o;
1436
1437 RETVAL_STRING(PQresStatus(PQresultStatus(obj->intern->res))+sizeof("PGRES"), 1);
1438 }
1439
1440 static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
1441 {
1442 php_pqres_object_t *obj = o;
1443 char *error = PHP_PQresultErrorMessage(obj->intern->res);
1444
1445 if (error) {
1446 RETVAL_STRING(error, 1);
1447 } else {
1448 RETVAL_NULL();
1449 }
1450 }
1451
1452 static void php_pqres_object_read_num_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
1453 {
1454 php_pqres_object_t *obj = o;
1455
1456 RETVAL_LONG(PQntuples(obj->intern->res));
1457 }
1458
1459 static void php_pqres_object_read_num_cols(zval *object, void *o, zval *return_value TSRMLS_DC)
1460 {
1461 php_pqres_object_t *obj = o;
1462
1463 RETVAL_LONG(PQnfields(obj->intern->res));
1464 }
1465
1466 static void php_pqres_object_read_affected_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
1467 {
1468 php_pqres_object_t *obj = o;
1469
1470 RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res)));
1471 }
1472
1473 static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1474 {
1475 php_pqres_object_t *obj = o;
1476
1477 if (obj->intern->iter) {
1478 RETVAL_LONG(obj->intern->iter->fetch_type);
1479 } else {
1480 RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
1481 }
1482 }
1483
1484 static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value TSRMLS_DC)
1485 {
1486 php_pqres_object_t *obj = o;
1487 zval *zfetch_type = value;
1488
1489 if (Z_TYPE_P(value) != IS_LONG) {
1490 if (Z_REFCOUNT_P(value) > 1) {
1491 zval *tmp;
1492 MAKE_STD_ZVAL(tmp);
1493 ZVAL_ZVAL(tmp, zfetch_type, 1, 0);
1494 convert_to_long(tmp);
1495 zfetch_type = tmp;
1496 } else {
1497 convert_to_long_ex(&zfetch_type);
1498 }
1499 }
1500
1501 if (!obj->intern->iter) {
1502 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC);
1503 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
1504 }
1505 obj->intern->iter->fetch_type = Z_LVAL_P(zfetch_type);
1506
1507 if (zfetch_type != value) {
1508 zval_ptr_dtor(&zfetch_type);
1509 }
1510 }
1511
1512 static void php_pqstm_object_read_name(zval *object, void *o, zval *return_value TSRMLS_DC)
1513 {
1514 php_pqstm_object_t *obj = o;
1515
1516 RETVAL_STRING(obj->intern->name, 1);
1517 }
1518
1519 static void php_pqstm_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1520 {
1521 php_pqstm_object_t *obj = o;
1522
1523 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1524 }
1525
1526 static void php_pqtxn_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1527 {
1528 php_pqtxn_object_t *obj = o;
1529
1530 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1531 }
1532
1533 static void php_pqtxn_object_read_isolation(zval *object, void *o, zval *return_value TSRMLS_DC)
1534 {
1535 php_pqtxn_object_t *obj = o;
1536
1537 RETVAL_LONG(obj->intern->isolation);
1538 }
1539
1540 static void php_pqtxn_object_read_readonly(zval *object, void *o, zval *return_value TSRMLS_DC)
1541 {
1542 php_pqtxn_object_t *obj = o;
1543
1544 RETVAL_BOOL(obj->intern->readonly);
1545 }
1546
1547 static void php_pqtxn_object_read_deferrable(zval *object, void *o, zval *return_value TSRMLS_DC)
1548 {
1549 php_pqtxn_object_t *obj = o;
1550
1551 RETVAL_BOOL(obj->intern->deferrable);
1552 }
1553
1554 static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value TSRMLS_DC)
1555 {
1556 php_pqtxn_object_t *obj = o;
1557 php_pqtxn_isolation_t orig = obj->intern->isolation;
1558 zval *zisolation = value;
1559 PGresult *res;
1560
1561 if (Z_TYPE_P(zisolation) != IS_LONG) {
1562 if (Z_REFCOUNT_P(value) > 1) {
1563 zval *tmp;
1564 MAKE_STD_ZVAL(tmp);
1565 ZVAL_ZVAL(tmp, zisolation, 1, 0);
1566 convert_to_long(tmp);
1567 zisolation = tmp;
1568 } else {
1569 convert_to_long_ex(&zisolation);
1570 }
1571 }
1572
1573 switch ((obj->intern->isolation = Z_LVAL_P(zisolation))) {
1574 case PHP_PQTXN_READ_COMMITTED:
1575 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL READ COMMITED");
1576 break;
1577 case PHP_PQTXN_REPEATABLE_READ:
1578 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
1579 break;
1580 case PHP_PQTXN_SERIALIZABLE:
1581 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1582 break;
1583 default:
1584 obj->intern->isolation = orig;
1585 res = NULL;
1586 break;
1587 }
1588
1589 if (zisolation != value) {
1590 zval_ptr_dtor(&zisolation);
1591 }
1592
1593 if (res) {
1594 php_pqres_success(res TSRMLS_CC);
1595 PHP_PQclear(res);
1596 }
1597 }
1598
1599 static void php_pqtxn_object_write_readonly(zval *object, void *o, zval *value TSRMLS_DC)
1600 {
1601 php_pqtxn_object_t *obj = o;
1602 PGresult *res;
1603
1604 if ((obj->intern->readonly = zend_is_true(value))) {
1605 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY");
1606 } else {
1607 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE");
1608 }
1609
1610 if (res) {
1611 php_pqres_success(res TSRMLS_CC);
1612 PHP_PQclear(res);
1613 }
1614 }
1615
1616 static void php_pqtxn_object_write_deferrable(zval *object, void *o, zval *value TSRMLS_DC)
1617 {
1618 php_pqtxn_object_t *obj = o;
1619 PGresult *res;
1620
1621 if ((obj->intern->deferrable = zend_is_true(value))) {
1622 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE");
1623 } else {
1624 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE");
1625 }
1626
1627 if (res) {
1628 php_pqres_success(res TSRMLS_CC);
1629 PHP_PQclear(res);
1630 }
1631 }
1632
1633 static void php_pqcancel_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1634 {
1635 php_pqcancel_object_t *obj = o;
1636
1637 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1638 }
1639
1640 static void php_pqevent_object_read_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1641 {
1642 php_pqevent_object_t *obj = o;
1643
1644 RETVAL_STRING(obj->intern->type, 1);
1645 }
1646
1647 static void php_pqlob_object_read_transaction(zval *object, void *o, zval *return_value TSRMLS_DC)
1648 {
1649 php_pqlob_object_t *obj = o;
1650
1651 php_pq_object_to_zval(obj->intern->txn, &return_value TSRMLS_CC);
1652 }
1653
1654 static void php_pqlob_object_read_oid(zval *object, void *o, zval *return_value TSRMLS_DC)
1655 {
1656 php_pqlob_object_t *obj = o;
1657
1658 RETVAL_LONG(obj->intern->loid);
1659 }
1660
1661 static void php_pqcopy_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1662 {
1663 php_pqcopy_object_t *obj = o;
1664
1665 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1666 }
1667
1668 static void php_pqcopy_object_read_direction(zval *object, void *o, zval *return_value TSRMLS_DC)
1669 {
1670 php_pqcopy_object_t *obj = o;
1671
1672 RETVAL_LONG(obj->intern->direction);
1673 }
1674
1675 static void php_pqcopy_object_read_expression(zval *object, void *o, zval *return_value TSRMLS_DC)
1676 {
1677 php_pqcopy_object_t *obj = o;
1678
1679 RETURN_STRING(obj->intern->expression, 1);
1680 }
1681
1682 static void php_pqcopy_object_read_options(zval *object, void *o, zval *return_value TSRMLS_DC)
1683 {
1684 php_pqcopy_object_t *obj = o;
1685
1686 RETURN_STRING(obj->intern->options, 1);
1687 }
1688
1689 static zend_class_entry *ancestor(zend_class_entry *ce) {
1690 while (ce->parent) {
1691 ce = ce->parent;
1692 }
1693 return ce;
1694 }
1695
1696 static zval *php_pq_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
1697 {
1698 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1699 php_pq_object_prophandler_t *handler;
1700 zval *return_value;
1701
1702 if (!obj->intern) {
1703 zend_error(E_WARNING, "%s not initialized", ancestor(obj->zo.ce)->name);
1704 } else if ((SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) && handler->read) {
1705 if (type == BP_VAR_R) {
1706 ALLOC_ZVAL(return_value);
1707 Z_SET_REFCOUNT_P(return_value, 0);
1708 Z_UNSET_ISREF_P(return_value);
1709
1710 handler->read(object, obj, return_value TSRMLS_CC);
1711 } else {
1712 zend_error(E_ERROR, "Cannot access %s properties by reference or array key/index", ancestor(obj->zo.ce)->name);
1713 return_value = NULL;
1714 }
1715 } else {
1716 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
1717 }
1718
1719 return return_value;
1720 }
1721
1722 static void php_pq_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
1723 {
1724 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1725 php_pq_object_prophandler_t *handler;
1726
1727 if (SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
1728 if (handler->write) {
1729 handler->write(object, obj, value TSRMLS_CC);
1730 }
1731 } else {
1732 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
1733 }
1734 }
1735
1736 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
1737 {
1738 zval *zsocket, zmember;
1739 php_stream *stream;
1740 STATUS retval;
1741 int socket;
1742
1743 if (!obj) {
1744 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1745 }
1746
1747 INIT_PZVAL(&zmember);
1748 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
1749 MAKE_STD_ZVAL(zsocket);
1750
1751 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
1752 && (-1 < (socket = PQsocket(obj->intern->conn)))
1753 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
1754 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
1755 php_stream_to_zval(stream, zsocket);
1756 retval = SUCCESS;
1757 } else {
1758 ZVAL_NULL(zsocket);
1759 retval = FAILURE;
1760 }
1761 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
1762 zval_ptr_dtor(&zsocket);
1763
1764 return retval;
1765 }
1766
1767 #ifdef ZTS
1768 # define TSRMLS_DF(d) TSRMLS_D = (d)->ts
1769 # define TSRMLS_CF(d) (d)->ts = TSRMLS_C
1770 #else
1771 # define TSRMLS_DF(d)
1772 # define TSRMLS_CF(d)
1773 #endif
1774
1775 static int apply_event(void *p, void *a TSRMLS_DC)
1776 {
1777 zval **evh = p;
1778 zval *args = a;
1779 zval *retval = NULL;
1780
1781 zend_call_method_with_1_params(evh, Z_OBJCE_PP(evh), NULL, "trigger", &retval, args);
1782 if (retval) {
1783 zval_ptr_dtor(&retval);
1784 }
1785
1786 return ZEND_HASH_APPLY_KEEP;
1787 }
1788
1789 static void php_pqconn_event_connreset(PGEventConnReset *event)
1790 {
1791 php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event);
1792
1793 if (data) {
1794 zval **evhs;
1795 TSRMLS_DF(data);
1796
1797 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("reset"), (void *) &evhs)) {
1798 zval *args, *connection = NULL;
1799
1800 MAKE_STD_ZVAL(args);
1801 array_init(args);
1802 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1803 add_next_index_zval(args, connection);
1804 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1805 zval_ptr_dtor(&args);
1806 }
1807 }
1808 }
1809
1810 static void php_pqres_init_instance_data(PGresult *res, php_pqres_object_t **ptr TSRMLS_DC)
1811 {
1812 php_pqres_object_t *obj;
1813 php_pqres_t *r = ecalloc(1, sizeof(*r));
1814
1815 r->res = res;
1816 ZEND_INIT_SYMTABLE(&r->bound);
1817 php_pqres_create_object_ex(php_pqres_class_entry, r, &obj TSRMLS_CC);
1818
1819 PQresultSetInstanceData(res, php_pqconn_event, obj);
1820
1821 if (ptr) {
1822 *ptr = obj;
1823 }
1824 }
1825
1826 static void php_pqconn_event_resultcreate(PGEventResultCreate *event)
1827 {
1828 php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event);
1829
1830 if (data) {
1831 php_pqres_object_t *obj;
1832 zval **evhs;
1833 TSRMLS_DF(data);
1834
1835 php_pqres_init_instance_data(event->result, &obj TSRMLS_CC);
1836
1837 /* event listener */
1838 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) {
1839 zval *args, *connection = NULL, *res = NULL;
1840
1841 MAKE_STD_ZVAL(args);
1842 array_init(args);
1843 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1844 add_next_index_zval(args, connection);
1845 php_pq_object_to_zval(obj, &res TSRMLS_CC);
1846 add_next_index_zval(args, res);
1847 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1848 zval_ptr_dtor(&args);
1849 }
1850
1851 /* async callback */
1852 if (data->obj->intern->onevent.fci.size > 0) {
1853 zval *res = NULL;
1854
1855 php_pq_object_to_zval(obj, &res TSRMLS_CC);
1856 zend_fcall_info_argn(&data->obj->intern->onevent.fci TSRMLS_CC, 1, &res);
1857 zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL TSRMLS_CC);
1858 zval_ptr_dtor(&res);
1859 }
1860
1861 }
1862 }
1863
1864 static void php_pqconn_event_resultdestroy(PGEventResultDestroy *event)
1865 {
1866 php_pqres_object_t *obj = PQresultInstanceData(event->result, php_pqconn_event);
1867
1868 if (obj) {
1869 obj->intern->res = NULL;
1870 }
1871 }
1872
1873 static int php_pqconn_event(PGEventId id, void *e, void *data)
1874 {
1875 switch (id) {
1876 case PGEVT_CONNRESET:
1877 php_pqconn_event_connreset(e);
1878 break;
1879 case PGEVT_RESULTCREATE:
1880 php_pqconn_event_resultcreate(e);
1881 break;
1882 case PGEVT_RESULTDESTROY:
1883 php_pqconn_event_resultdestroy(e);
1884 break;
1885 default:
1886 break;
1887 }
1888
1889 return 1;
1890 }
1891
1892 static php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj TSRMLS_DC)
1893 {
1894 php_pqconn_event_data_t *data = emalloc(sizeof(*data));
1895
1896 data->obj = obj;
1897 TSRMLS_CF(data);
1898
1899 return data;
1900 }
1901
1902 static void php_pqconn_notice_recv(void *p, const PGresult *res)
1903 {
1904 php_pqconn_event_data_t *data = p;
1905
1906 if (data) {
1907 zval **evhs;
1908 TSRMLS_DF(data);
1909
1910 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("notice"), (void *) &evhs)) {
1911 zval *args, *connection = NULL;
1912
1913 MAKE_STD_ZVAL(args);
1914 array_init(args);
1915 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1916 add_next_index_zval(args, connection);
1917 add_next_index_string(args, PHP_PQresultErrorMessage(res), 1);
1918 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1919 zval_ptr_dtor(&args);
1920 }
1921 }
1922 }
1923
1924 typedef struct php_pqconn_resource_factory_data {
1925 char *dsn;
1926 long flags;
1927 } php_pqconn_resource_factory_data_t;
1928
1929 static void *php_pqconn_resource_factory_ctor(void *data, void *init_arg TSRMLS_DC)
1930 {
1931 php_pqconn_resource_factory_data_t *o = init_arg;
1932 PGconn *conn = NULL;;
1933
1934 if (o->flags & PHP_PQCONN_ASYNC) {
1935 conn = PQconnectStart(o->dsn);
1936 } else {
1937 conn = PQconnectdb(o->dsn);
1938 }
1939
1940 if (conn) {
1941 PQregisterEventProc(conn, php_pqconn_event, "ext-pq", NULL);
1942 }
1943
1944 return conn;
1945 }
1946
1947 static void php_pqconn_resource_factory_dtor(void *opaque, void *handle TSRMLS_DC)
1948 {
1949 php_pqconn_event_data_t *evdata = PQinstanceData(handle, php_pqconn_event);
1950
1951 /* we don't care for anything, except free'ing evdata */
1952 if (evdata) {
1953 PQsetInstanceData(handle, php_pqconn_event, NULL);
1954 memset(evdata, 0, sizeof(*evdata));
1955 efree(evdata);
1956 }
1957
1958 PQfinish(handle);
1959 }
1960
1961 static php_resource_factory_ops_t php_pqconn_resource_factory_ops = {
1962 php_pqconn_resource_factory_ctor,
1963 NULL,
1964 php_pqconn_resource_factory_dtor
1965 };
1966
1967 static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC)
1968 {
1969 // FIXME: ping server
1970 }
1971
1972 static int apply_unlisten(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1973 {
1974 php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
1975 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, key->arKey, key->nKeyLength - 1);
1976
1977 if (quoted_channel) {
1978 PGresult *res;
1979 char *cmd;
1980
1981 spprintf(&cmd, 0, "UNLISTEN %s", quoted_channel);
1982 if ((res = PQexec(obj->intern->conn, cmd))) {
1983 PHP_PQclear(res);
1984 }
1985
1986 efree(cmd);
1987 PQfreemem(quoted_channel);
1988 }
1989
1990 return ZEND_HASH_APPLY_REMOVE;
1991 }
1992
1993 static void php_pqconn_notice_ignore(void *p, const PGresult *res)
1994 {
1995 }
1996
1997 static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC)
1998 {
1999 php_pqconn_event_data_t *evdata = PQinstanceData(*handle, php_pqconn_event);
2000 PGcancel *cancel;
2001 PGresult *res;
2002
2003 /* go away */
2004 PQsetInstanceData(*handle, php_pqconn_event, NULL);
2005
2006 /* ignore notices */
2007 PQsetNoticeReceiver(*handle, php_pqconn_notice_ignore, NULL);
2008
2009 /* cancel async queries */
2010 if (PQisBusy(*handle) && (cancel = PQgetCancel(*handle))) {
2011 char err[256] = {0};
2012
2013 PQcancel(cancel, err, sizeof(err));
2014 PQfreeCancel(cancel);
2015 }
2016 /* clean up async results */
2017 while ((res = PQgetResult(*handle))) {
2018 PHP_PQclear(res);
2019 }
2020
2021 /* clean up transaction & session */
2022 switch (PQtransactionStatus(*handle)) {
2023 case PQTRANS_IDLE:
2024 res = PQexec(*handle, "RESET ALL");
2025 break;
2026 default:
2027 res = PQexec(*handle, "ROLLBACK; RESET ALL");
2028 break;
2029 }
2030
2031 if (res) {
2032 PHP_PQclear(res);
2033 }
2034
2035 if (evdata) {
2036 /* clean up notify listeners */
2037 zend_hash_apply_with_arguments(&evdata->obj->intern->listeners TSRMLS_CC, apply_unlisten, 1, evdata->obj);
2038
2039 /* release instance data */
2040 memset(evdata, 0, sizeof(*evdata));
2041 efree(evdata);
2042 }
2043 }
2044
2045 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
2046 ZEND_ARG_INFO(0, dsn)
2047 ZEND_ARG_INFO(0, async)
2048 ZEND_END_ARG_INFO();
2049 static PHP_METHOD(pqconn, __construct) {
2050 zend_error_handling zeh;
2051 char *dsn_str = "";
2052 int dsn_len = 0;
2053 long flags = 0;
2054 STATUS rv;
2055
2056 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2057 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &dsn_str, &dsn_len, &flags);
2058 zend_restore_error_handling(&zeh TSRMLS_CC);
2059
2060 if (SUCCESS == rv) {
2061 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2062
2063 if (obj->intern) {
2064 throw_exce(EX_BAD_METHODCALL TSRMLS_CC, "pq\\Connection already initialized");
2065 } else {
2066 php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj TSRMLS_CC);
2067 php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags};
2068
2069 obj->intern = ecalloc(1, sizeof(*obj->intern));
2070
2071 zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
2072 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);
2073
2074 if (flags & PHP_PQCONN_PERSISTENT) {
2075 php_persistent_handle_factory_t *phf = php_persistent_handle_concede(NULL, ZEND_STRL("pq\\Connection"), dsn_str, dsn_len, php_pqconn_wakeup, php_pqconn_retire TSRMLS_CC);
2076 php_resource_factory_init(&obj->intern->factory, php_persistent_handle_get_resource_factory_ops(), phf, (void (*)(void*)) php_persistent_handle_abandon);
2077 } else {
2078 php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL);
2079 }
2080
2081 if (flags & PHP_PQCONN_ASYNC) {
2082 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
2083 }
2084
2085 obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata TSRMLS_CC);
2086
2087 PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata);
2088 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata);
2089
2090 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
2091 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn));
2092 }
2093 }
2094 }
2095 }
2096
2097 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
2098 ZEND_END_ARG_INFO();
2099 static PHP_METHOD(pqconn, reset) {
2100 zend_error_handling zeh;
2101 STATUS rv;
2102
2103 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2104 rv = zend_parse_parameters_none();
2105 zend_restore_error_handling(&zeh TSRMLS_CC);
2106
2107 if (SUCCESS == rv) {
2108 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2109
2110 if (!obj->intern) {
2111 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2112 } else {
2113 PQreset(obj->intern->conn);
2114
2115 if (CONNECTION_OK != PQstatus(obj->intern->conn)) {
2116 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn));
2117 }
2118
2119 php_pqconn_notify_listeners(obj TSRMLS_CC);
2120 }
2121 }
2122 }
2123
2124 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
2125 ZEND_END_ARG_INFO();
2126 static PHP_METHOD(pqconn, resetAsync) {
2127 zend_error_handling zeh;
2128 STATUS rv;
2129
2130 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2131 rv = zend_parse_parameters_none();
2132 zend_restore_error_handling(&zeh TSRMLS_CC);
2133
2134 if (SUCCESS == rv) {
2135 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2136
2137 if (!obj->intern) {
2138 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2139 } else {
2140 if (!PQresetStart(obj->intern->conn)) {
2141 throw_exce(EX_IO TSRMLS_CC, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn));
2142 } else {
2143 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
2144 }
2145
2146 php_pqconn_notify_listeners(obj TSRMLS_CC);
2147 }
2148 }
2149 }
2150
2151 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)
2152 {
2153 HashTable ht, *existing_listeners;
2154
2155 php_pq_callback_addref(listener);
2156
2157 if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
2158 zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
2159 } else {
2160 zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
2161 zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
2162 zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
2163 }
2164 }
2165
2166 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
2167 ZEND_ARG_INFO(0, channel)
2168 ZEND_ARG_INFO(0, callable)
2169 ZEND_END_ARG_INFO();
2170 static PHP_METHOD(pqconn, listen) {
2171 zend_error_handling zeh;
2172 char *channel_str = NULL;
2173 int channel_len = 0;
2174 php_pq_callback_t listener;
2175 STATUS rv;
2176
2177 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2178 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
2179 zend_restore_error_handling(&zeh TSRMLS_CC);
2180
2181 if (SUCCESS == rv) {
2182 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2183
2184 if (!obj->intern) {
2185 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2186 } else {
2187 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
2188
2189 if (!quoted_channel) {
2190 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
2191 } else {
2192 PGresult *res;
2193 smart_str cmd = {0};
2194
2195 smart_str_appends(&cmd, "LISTEN ");
2196 smart_str_appends(&cmd, quoted_channel);
2197 smart_str_0(&cmd);
2198
2199 res = PQexec(obj->intern->conn, cmd.c);
2200
2201 smart_str_free(&cmd);
2202 PQfreemem(quoted_channel);
2203
2204 if (!res) {
2205 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
2206 } else {
2207 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2208 obj->intern->poller = PQconsumeInput;
2209 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
2210 }
2211 PHP_PQclear(res);
2212 }
2213
2214 php_pqconn_notify_listeners(obj TSRMLS_CC);
2215 }
2216 }
2217 }
2218 }
2219
2220 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async, 0, 0, 0)
2221 ZEND_ARG_INFO(0, channel)
2222 ZEND_ARG_INFO(0, callable)
2223 ZEND_END_ARG_INFO();
2224 static PHP_METHOD(pqconn, listenAsync) {
2225 zend_error_handling zeh;
2226 char *channel_str = NULL;
2227 int channel_len = 0;
2228 php_pq_callback_t listener;
2229 STATUS rv;
2230
2231 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2232 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
2233 zend_restore_error_handling(&zeh TSRMLS_CC);
2234
2235 if (SUCCESS == rv) {
2236 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2237
2238 if (!obj->intern) {
2239 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2240 } else {
2241 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
2242
2243 if (!quoted_channel) {
2244 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
2245 } else {
2246 smart_str cmd = {0};
2247
2248 smart_str_appends(&cmd, "LISTEN ");
2249 smart_str_appends(&cmd, quoted_channel);
2250 smart_str_0(&cmd);
2251
2252 if (!PQsendQuery(obj->intern->conn, cmd.c)) {
2253 throw_exce(EX_IO TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
2254 } else {
2255 obj->intern->poller = PQconsumeInput;
2256 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
2257 }
2258
2259 smart_str_free(&cmd);
2260 PQfreemem(quoted_channel);
2261 php_pqconn_notify_listeners(obj TSRMLS_CC);
2262 }
2263 }
2264 }
2265 }
2266
2267 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
2268 ZEND_ARG_INFO(0, channel)
2269 ZEND_ARG_INFO(0, message)
2270 ZEND_END_ARG_INFO();
2271 static PHP_METHOD(pqconn, notify) {
2272 zend_error_handling zeh;
2273 char *channel_str, *message_str;
2274 int channel_len, message_len;
2275 STATUS rv;
2276
2277 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2278 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len);
2279 zend_restore_error_handling(&zeh TSRMLS_CC);
2280
2281 if (SUCCESS == rv) {
2282 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2283
2284 if (!obj->intern) {
2285 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2286 } else {
2287 PGresult *res;
2288 char *params[2] = {channel_str, message_str};
2289
2290 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
2291
2292 if (!res) {
2293 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
2294 } else {
2295 php_pqres_success(res TSRMLS_CC);
2296 PHP_PQclear(res);
2297 }
2298
2299 php_pqconn_notify_listeners(obj TSRMLS_CC);
2300 }
2301 }
2302 }
2303
2304 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async, 0, 0, 2)
2305 ZEND_ARG_INFO(0, channel)
2306 ZEND_ARG_INFO(0, message)
2307 ZEND_END_ARG_INFO();
2308 static PHP_METHOD(pqconn, notifyAsync) {
2309 zend_error_handling zeh;
2310 char *channel_str, *message_str;
2311 int channel_len, message_len;
2312 STATUS rv;
2313
2314 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2315 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len);
2316 zend_restore_error_handling(&zeh TSRMLS_CC);
2317
2318 if (SUCCESS == rv) {
2319 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2320
2321 if (!obj->intern) {
2322 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2323 } else {
2324 char *params[2] = {channel_str, message_str};
2325
2326 if (!PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) {
2327 throw_exce(EX_IO TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
2328 } else {
2329 obj->intern->poller = PQconsumeInput;
2330 }
2331
2332 php_pqconn_notify_listeners(obj TSRMLS_CC);
2333 }
2334 }
2335 }
2336
2337 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
2338 ZEND_END_ARG_INFO();
2339 static PHP_METHOD(pqconn, poll) {
2340 zend_error_handling zeh;
2341 STATUS rv;
2342
2343 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2344 rv = zend_parse_parameters_none();
2345 zend_restore_error_handling(&zeh TSRMLS_CC);
2346
2347 if (SUCCESS == rv) {
2348 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2349
2350 if (!obj->intern) {
2351 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2352 } else if (!obj->intern->poller) {
2353 throw_exce(EX_RUNTIME TSRMLS_CC, "No asynchronous operation active");
2354 } else {
2355 if (obj->intern->poller == PQconsumeInput) {
2356 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
2357 } else {
2358 RETVAL_LONG(obj->intern->poller(obj->intern->conn));
2359 }
2360 php_pqconn_notify_listeners(obj TSRMLS_CC);
2361 }
2362 }
2363 }
2364
2365 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
2366 ZEND_ARG_INFO(0, query)
2367 ZEND_END_ARG_INFO();
2368 static PHP_METHOD(pqconn, exec) {
2369 zend_error_handling zeh;
2370 char *query_str;
2371 int query_len;
2372 STATUS rv;
2373
2374 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2375 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len);
2376 zend_restore_error_handling(&zeh TSRMLS_CC);
2377
2378 if (SUCCESS == rv) {
2379 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2380
2381 if (!obj->intern) {
2382 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2383 } else {
2384 PGresult *res = PQexec(obj->intern->conn, query_str);
2385
2386 if (!res) {
2387 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2388 } else if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2389 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
2390 } else {
2391 PHP_PQclear(res);
2392 }
2393
2394 php_pqconn_notify_listeners(obj TSRMLS_CC);
2395 }
2396 }
2397 }
2398
2399 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
2400 ZEND_END_ARG_INFO();
2401 static PHP_METHOD(pqconn, getResult) {
2402 zend_error_handling zeh;
2403 STATUS rv;
2404
2405 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2406 rv = zend_parse_parameters_none();
2407 zend_restore_error_handling(&zeh TSRMLS_CC);
2408
2409 if (SUCCESS == rv) {
2410 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2411
2412 if (!obj->intern) {
2413 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connectio not initialized");
2414 } else {
2415 PGresult *res = PQgetResult(obj->intern->conn);
2416
2417 if (!res) {
2418 RETVAL_NULL();
2419 } else {
2420 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
2421 }
2422
2423 php_pqconn_notify_listeners(obj TSRMLS_CC);
2424 }
2425 }
2426 }
2427
2428 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
2429 ZEND_ARG_INFO(0, query)
2430 ZEND_ARG_INFO(0, callable)
2431 ZEND_END_ARG_INFO();
2432 static PHP_METHOD(pqconn, execAsync) {
2433 zend_error_handling zeh;
2434 php_pq_callback_t resolver = {{0}};
2435 char *query_str;
2436 int query_len;
2437 STATUS rv;
2438
2439 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2440 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc);
2441 zend_restore_error_handling(&zeh TSRMLS_CC);
2442
2443 if (SUCCESS == rv) {
2444 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2445
2446 if (!obj->intern) {
2447 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2448 } else if (!PQsendQuery(obj->intern->conn, query_str)) {
2449 throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2450 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
2451 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
2452 } else {
2453 obj->intern->poller = PQconsumeInput;
2454 php_pq_callback_dtor(&obj->intern->onevent);
2455 if (resolver.fci.size > 0) {
2456 obj->intern->onevent = resolver;
2457 php_pq_callback_addref(&obj->intern->onevent);
2458 }
2459 php_pqconn_notify_listeners(obj TSRMLS_CC);
2460 }
2461 }
2462 }
2463
2464 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
2465 {
2466 Oid **types = arg;
2467 zval **ztype = p;
2468
2469 if (Z_TYPE_PP(ztype) != IS_LONG) {
2470 convert_to_long_ex(ztype);
2471 }
2472
2473 **types = Z_LVAL_PP(ztype);
2474 ++*types;
2475
2476 if (*ztype != *(zval **)p) {
2477 zval_ptr_dtor(ztype);
2478 }
2479 return ZEND_HASH_APPLY_KEEP;
2480 }
2481
2482 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
2483 {
2484 char ***params;
2485 HashTable *zdtor;
2486 zval **zparam = p;
2487
2488 params = (char ***) va_arg(argv, char ***);
2489 zdtor = (HashTable *) va_arg(argv, HashTable *);
2490
2491 if (Z_TYPE_PP(zparam) == IS_NULL) {
2492 **params = NULL;
2493 ++*params;
2494 } else {
2495 if (Z_TYPE_PP(zparam) != IS_STRING) {
2496 convert_to_string_ex(zparam);
2497 }
2498
2499 **params = Z_STRVAL_PP(zparam);
2500 ++*params;
2501
2502 if (*zparam != *(zval **)p) {
2503 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
2504 }
2505 }
2506 return ZEND_HASH_APPLY_KEEP;
2507 }
2508
2509 static int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC)
2510 {
2511 int count = zend_hash_num_elements(ht);
2512
2513 *types = NULL;
2514
2515 if (count) {
2516 Oid *tmp;
2517
2518 /* +1 for when less types than params are specified */
2519 *types = tmp = ecalloc(count + 1, sizeof(**types));
2520 zend_hash_apply_with_argument(ht, apply_to_oid, &tmp TSRMLS_CC);
2521 }
2522
2523 return count;
2524 }
2525
2526 static int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC)
2527 {
2528 int count = zend_hash_num_elements(ht);
2529
2530 *params = NULL;
2531
2532 if (count) {
2533 char **tmp;
2534
2535 *params = tmp = ecalloc(count, sizeof(char *));
2536 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param, 2, &tmp, zdtor);
2537 }
2538
2539 return count;
2540 }
2541 /*
2542 static Oid *php_pq_ntypes_to_array(zend_bool fill, int argc, ...)
2543 {
2544 int i;
2545 Oid *oids = ecalloc(argc + 1, sizeof(*oids));
2546 va_list argv;
2547
2548 va_start(argv, argc);
2549 for (i = 0; i < argc; ++i) {
2550 if (!fill || !i) {
2551 oids[i] = va_arg(argv, Oid);
2552 } else {
2553 oids[i] = oids[0];
2554 }
2555 }
2556 va_end(argv);
2557
2558 return oids;
2559 }
2560 */
2561 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
2562 ZEND_ARG_INFO(0, query)
2563 ZEND_ARG_ARRAY_INFO(0, params, 0)
2564 ZEND_ARG_ARRAY_INFO(0, types, 1)
2565 ZEND_END_ARG_INFO();
2566 static PHP_METHOD(pqconn, execParams) {
2567 zend_error_handling zeh;
2568 char *query_str;
2569 int query_len;
2570 zval *zparams;
2571 zval *ztypes = NULL;
2572 STATUS rv;
2573
2574 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2575 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes);
2576 zend_restore_error_handling(&zeh TSRMLS_CC);
2577
2578 if (SUCCESS == rv) {
2579 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2580
2581 if (!obj->intern) {
2582 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2583 } else {
2584 PGresult *res;
2585 int count;
2586 Oid *types = NULL;
2587 char **params = NULL;
2588 HashTable zdtor;
2589
2590 ZEND_INIT_SYMTABLE(&zdtor);
2591 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2592
2593 if (ztypes) {
2594 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
2595 }
2596
2597 res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
2598
2599 zend_hash_destroy(&zdtor);
2600 if (types) {
2601 efree(types);
2602 }
2603 if (params) {
2604 efree(params);
2605 }
2606
2607 if (!res) {
2608 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2609 } else {
2610 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2611 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
2612 } else {
2613 PHP_PQclear(res);
2614 }
2615
2616 php_pqconn_notify_listeners(obj TSRMLS_CC);
2617 }
2618 }
2619 }
2620 }
2621
2622 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
2623 ZEND_ARG_INFO(0, query)
2624 ZEND_ARG_ARRAY_INFO(0, params, 0)
2625 ZEND_ARG_ARRAY_INFO(0, types, 1)
2626 ZEND_ARG_INFO(0, callable)
2627 ZEND_END_ARG_INFO();
2628 static PHP_METHOD(pqconn, execParamsAsync) {
2629 zend_error_handling zeh;
2630 php_pq_callback_t resolver = {{0}};
2631 char *query_str;
2632 int query_len;
2633 zval *zparams;
2634 zval *ztypes = NULL;
2635 STATUS rv;
2636
2637 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2638 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc);
2639 zend_restore_error_handling(&zeh TSRMLS_CC);
2640
2641 if (SUCCESS == rv) {
2642 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2643
2644 if (!obj->intern) {
2645 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2646 } else {
2647 int count;
2648 Oid *types = NULL;
2649 char **params = NULL;
2650 HashTable zdtor;
2651
2652 ZEND_INIT_SYMTABLE(&zdtor);
2653 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2654
2655 if (ztypes) {
2656 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
2657 }
2658
2659 if (!PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) {
2660 throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
2661 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
2662 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
2663 } else {
2664 obj->intern->poller = PQconsumeInput;
2665 php_pq_callback_dtor(&obj->intern->onevent);
2666 if (resolver.fci.size > 0) {
2667 obj->intern->onevent = resolver;
2668 php_pq_callback_addref(&obj->intern->onevent);
2669 }
2670 php_pqconn_notify_listeners(obj TSRMLS_CC);
2671 }
2672
2673 zend_hash_destroy(&zdtor);
2674 if (types) {
2675 efree(types);
2676 }
2677 if (params) {
2678 efree(params);
2679 }
2680 }
2681 }
2682 zend_restore_error_handling(&zeh TSRMLS_CC);
2683 }
2684
2685 static STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
2686 {
2687 Oid *types = NULL;
2688 int count = 0;
2689 PGresult *res;
2690 STATUS rv;
2691
2692 if (!obj) {
2693 obj = zend_object_store_get_object(object TSRMLS_CC);
2694 }
2695
2696 if (typest) {
2697 count = zend_hash_num_elements(typest);
2698 php_pq_types_to_array(typest, &types TSRMLS_CC);
2699 }
2700
2701 res = PQprepare(obj->intern->conn, name, query, count, types);
2702
2703 if (types) {
2704 efree(types);
2705 }
2706
2707 if (!res) {
2708 rv = FAILURE;
2709 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
2710 } else {
2711 rv = php_pqres_success(res TSRMLS_CC);
2712 PHP_PQclear(res);
2713 php_pqconn_notify_listeners(obj TSRMLS_CC);
2714 }
2715
2716 return rv;
2717 }
2718
2719 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
2720 ZEND_ARG_INFO(0, type)
2721 ZEND_ARG_INFO(0, query)
2722 ZEND_ARG_ARRAY_INFO(0, types, 1)
2723 ZEND_END_ARG_INFO();
2724 static PHP_METHOD(pqconn, prepare) {
2725 zend_error_handling zeh;
2726 zval *ztypes = NULL;
2727 char *name_str, *query_str;
2728 int name_len, *query_len;
2729 STATUS rv;
2730
2731 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2732 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
2733 zend_restore_error_handling(&zeh TSRMLS_CC);
2734
2735 if (SUCCESS == rv) {
2736 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2737
2738 if (!obj->intern) {
2739 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2740 } else if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
2741 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2742
2743 php_pq_object_addref(obj TSRMLS_CC);
2744 stm->conn = obj;
2745 stm->name = estrdup(name_str);
2746 ZEND_INIT_SYMTABLE(&stm->bound);
2747
2748 return_value->type = IS_OBJECT;
2749 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
2750 }
2751 }
2752 }
2753
2754 static STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
2755 {
2756 STATUS rv;
2757 int count;
2758 Oid *types = NULL;
2759
2760 if (!obj) {
2761 obj = zend_object_store_get_object(object TSRMLS_CC);
2762 }
2763
2764 if (typest) {
2765 count = php_pq_types_to_array(typest, &types TSRMLS_CC);
2766 }
2767
2768 if (!PQsendPrepare(obj->intern->conn, name, query, count, types)) {
2769 rv = FAILURE;
2770 throw_exce(EX_IO TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
2771 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
2772 rv = FAILURE;
2773 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
2774 } else {
2775 rv = SUCCESS;
2776 obj->intern->poller = PQconsumeInput;
2777 php_pqconn_notify_listeners(obj TSRMLS_CC);
2778 }
2779
2780 if (types) {
2781 efree(types);
2782 }
2783
2784 return rv;
2785 }
2786
2787 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
2788 ZEND_ARG_INFO(0, type)
2789 ZEND_ARG_INFO(0, query)
2790 ZEND_ARG_ARRAY_INFO(0, types, 1)
2791 ZEND_END_ARG_INFO();
2792 static PHP_METHOD(pqconn, prepareAsync) {
2793 zend_error_handling zeh;
2794 zval *ztypes = NULL;
2795 char *name_str, *query_str;
2796 int name_len, *query_len;
2797 STATUS rv;
2798
2799 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
2800 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
2801 zend_restore_error_handling(&zeh TSRMLS_CC);
2802
2803 if (SUCCESS == rv) {
2804 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2805
2806 if (!obj->intern) {
2807 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2808 } else if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
2809 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2810
2811 php_pq_object_addref(obj TSRMLS_CC);
2812 stm->conn = obj;
2813 stm->name = estrdup(name_str);
2814 ZEND_INIT_SYMTABLE(&stm->bound);
2815
2816 return_value->type = IS_OBJECT;
2817 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
2818 }
2819 }
2820 }
2821
2822 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
2823 ZEND_ARG_INFO(0, string)
2824 ZEND_END_ARG_INFO();
2825 static PHP_METHOD(pqconn, quote) {
2826 char *str;
2827 int len;
2828
2829 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2830 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2831
2832 if (!obj->intern) {
2833 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2834 } else {
2835 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
2836
2837 if (!quoted) {
2838 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote string (%s)", PHP_PQerrorMessage(obj->intern->conn));
2839 RETVAL_FALSE;
2840 } else {
2841 RETVAL_STRING(quoted, 1);
2842 PQfreemem(quoted);
2843 }
2844 }
2845 }
2846 }
2847
2848 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
2849 ZEND_ARG_INFO(0, type)
2850 ZEND_END_ARG_INFO();
2851 static PHP_METHOD(pqconn, quoteName) {
2852 char *str;
2853 int len;
2854
2855 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2856 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2857
2858 if (!obj->intern) {
2859 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2860 } else {
2861 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
2862
2863 if (!quoted) {
2864 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote name (%s)", PHP_PQerrorMessage(obj->intern->conn));
2865 RETVAL_FALSE;
2866 } else {
2867 RETVAL_STRING(quoted, 1);
2868 PQfreemem(quoted);
2869 }
2870 }
2871 }
2872 }
2873
2874 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
2875 ZEND_ARG_INFO(0, bytea)
2876 ZEND_END_ARG_INFO();
2877 static PHP_METHOD(pqconn, escapeBytea) {
2878 char *str;
2879 int len;
2880
2881 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2882 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2883
2884 if (!obj->intern) {
2885 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2886 } else {
2887 size_t escaped_len;
2888 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
2889
2890 if (!escaped_str) {
2891 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
2892 RETVAL_FALSE;
2893 } else {
2894 RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
2895 PQfreemem(escaped_str);
2896 }
2897 }
2898 }
2899 }
2900
2901 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
2902 ZEND_ARG_INFO(0, bytea)
2903 ZEND_END_ARG_INFO();
2904 static PHP_METHOD(pqconn, unescapeBytea) {
2905 char *str;
2906 int len;
2907
2908 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2909 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2910
2911 if (!obj->intern) {
2912 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2913 } else {
2914 size_t unescaped_len;
2915 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
2916
2917 if (!unescaped_str) {
2918 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
2919 RETVAL_FALSE;
2920 } else {
2921 RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
2922 PQfreemem(unescaped_str);
2923 }
2924 }
2925 }
2926 }
2927
2928 static const char *isolation_level(long *isolation) {
2929 switch (*isolation) {
2930 case PHP_PQTXN_SERIALIZABLE:
2931 return "SERIALIZABLE";
2932 case PHP_PQTXN_REPEATABLE_READ:
2933 return "REPEATABLE READ";
2934 default:
2935 *isolation = PHP_PQTXN_READ_COMMITTED;
2936 /* no break */
2937 case PHP_PQTXN_READ_COMMITTED:
2938 return "READ COMMITTED";
2939 }
2940 }
2941
2942 static STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
2943 {
2944 STATUS rv = FAILURE;
2945
2946 if (!conn_obj) {
2947 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2948 }
2949
2950 if (!conn_obj->intern) {
2951 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2952 } else {
2953 PGresult *res;
2954 smart_str cmd = {0};
2955 const char *il = isolation_level(&isolation);
2956
2957 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
2958 smart_str_appends(&cmd, il);
2959 smart_str_appends(&cmd, ", READ ");
2960 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
2961 smart_str_appends(&cmd, ",");
2962 smart_str_appends(&cmd, deferrable ? "" : " NOT");
2963 smart_str_appends(&cmd, " DEFERRABLE");
2964 smart_str_0(&cmd);
2965
2966 res = PQexec(conn_obj->intern->conn, cmd.c);
2967
2968 if (!res) {
2969 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
2970 } else {
2971 rv = php_pqres_success(res TSRMLS_CC);
2972 PHP_PQclear(res);
2973 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
2974 }
2975
2976 smart_str_free(&cmd);
2977 }
2978
2979 return rv;
2980 }
2981
2982 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)
2983 {
2984 STATUS rv = FAILURE;
2985
2986 if (!conn_obj) {
2987 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2988 }
2989
2990 if (!conn_obj->intern) {
2991 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
2992 } else {
2993 smart_str cmd = {0};
2994 const char *il = isolation_level(&isolation);
2995
2996 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
2997 smart_str_appends(&cmd, il);
2998 smart_str_appends(&cmd, ", READ ");
2999 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
3000 smart_str_appends(&cmd, ",");
3001 smart_str_appends(&cmd, deferrable ? "" : "NOT ");
3002 smart_str_appends(&cmd, " DEFERRABLE");
3003 smart_str_0(&cmd);
3004
3005 if (!PQsendQuery(conn_obj->intern->conn, cmd.c)) {
3006 throw_exce(EX_IO TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
3007 } else {
3008 rv = SUCCESS;
3009 conn_obj->intern->poller = PQconsumeInput;
3010 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
3011 }
3012
3013 smart_str_free(&cmd);
3014 }
3015
3016 return rv;
3017 }
3018
3019 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
3020 ZEND_ARG_INFO(0, isolation)
3021 ZEND_ARG_INFO(0, readonly)
3022 ZEND_ARG_INFO(0, deferrable)
3023 ZEND_END_ARG_INFO();
3024 static PHP_METHOD(pqconn, startTransaction) {
3025 zend_error_handling zeh;
3026 long isolation = PHP_PQTXN_READ_COMMITTED;
3027 zend_bool readonly = 0, deferrable = 0;
3028 STATUS rv;
3029
3030 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3031 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable);
3032 zend_restore_error_handling(&zeh TSRMLS_CC);
3033
3034 if (SUCCESS == rv) {
3035 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3036
3037 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
3038
3039 if (SUCCESS == rv) {
3040 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
3041
3042 php_pq_object_addref(obj TSRMLS_CC);
3043 txn->conn = obj;
3044 txn->open = 1;
3045 txn->isolation = isolation;
3046 txn->readonly = readonly;
3047 txn->deferrable = deferrable;
3048
3049 return_value->type = IS_OBJECT;
3050 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
3051 }
3052 }
3053 }
3054
3055 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
3056 ZEND_ARG_INFO(0, isolation)
3057 ZEND_ARG_INFO(0, readonly)
3058 ZEND_ARG_INFO(0, deferrable)
3059 ZEND_END_ARG_INFO();
3060 static PHP_METHOD(pqconn, startTransactionAsync) {
3061 zend_error_handling zeh;
3062 long isolation = PHP_PQTXN_READ_COMMITTED;
3063 zend_bool readonly = 0, deferrable = 0;
3064 STATUS rv;
3065
3066 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3067 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable);
3068 zend_restore_error_handling(&zeh TSRMLS_CC);
3069 if (SUCCESS == rv) {
3070 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3071
3072 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
3073
3074 if (SUCCESS == rv) {
3075 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
3076
3077 php_pq_object_addref(obj TSRMLS_CC);
3078 txn->conn = obj;
3079 txn->isolation = isolation;
3080 txn->readonly = readonly;
3081 txn->deferrable = deferrable;
3082
3083 return_value->type = IS_OBJECT;
3084 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
3085 }
3086 }
3087 }
3088
3089 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
3090 ZEND_ARG_INFO(0, stdio_stream)
3091 ZEND_END_ARG_INFO();
3092 static PHP_METHOD(pqconn, trace) {
3093 zval *zstream = NULL;
3094
3095 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) {
3096 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3097
3098 if (!obj->intern) {
3099 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
3100 } else {
3101 if (!zstream) {
3102 PQuntrace(obj->intern->conn);
3103 RETVAL_TRUE;
3104 } else {
3105 FILE *fp;
3106 php_stream *stream = NULL;
3107
3108 php_stream_from_zval(stream, &zstream);
3109
3110 if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
3111 RETVAL_FALSE;
3112 } else {
3113 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
3114 PQtrace(obj->intern->conn, fp);
3115 RETVAL_TRUE;
3116 }
3117 }
3118 }
3119 }
3120 }
3121
3122 static zend_function_entry php_pqconn_methods[] = {
3123 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
3124 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
3125 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
3126 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
3127 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
3128 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
3129 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
3130 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
3131 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
3132 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
3133 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
3134 PHP_ME(pqconn, listenAsync, ai_pqconn_listen_async, ZEND_ACC_PUBLIC)
3135 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
3136 PHP_ME(pqconn, notifyAsync, ai_pqconn_notify_async, ZEND_ACC_PUBLIC)
3137 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
3138 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
3139 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
3140 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
3141 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
3142 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
3143 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
3144 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
3145 {0}
3146 };
3147
3148 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_construct, 0, 0, 1)
3149 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
3150 ZEND_ARG_ARRAY_INFO(0, namespaces, 1)
3151 ZEND_END_ARG_INFO();
3152 static PHP_METHOD(pqtypes, __construct) {
3153 zend_error_handling zeh;
3154 zval *zconn, *znsp = NULL;
3155 STATUS rv;
3156
3157 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3158 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a!", &zconn, php_pqconn_class_entry, &znsp);
3159 zend_restore_error_handling(&zeh TSRMLS_CC);
3160
3161 if (SUCCESS == rv) {
3162 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
3163
3164 if (!conn_obj->intern) {
3165 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
3166 } else {
3167 php_pqtypes_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3168 zval *retval = NULL;
3169
3170 obj->intern = ecalloc(1, sizeof(*obj->intern));
3171 obj->intern->conn = conn_obj;
3172 php_pq_object_addref(conn_obj TSRMLS_CC);
3173 zend_hash_init(&obj->intern->types, 300, NULL, ZVAL_PTR_DTOR, 0);
3174
3175 if (znsp) {
3176 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "refresh", &retval, znsp);
3177 } else {
3178 zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "refresh", &retval);
3179 }
3180
3181 if (retval) {
3182 zval_ptr_dtor(&retval);
3183 }
3184 }
3185 }
3186 }
3187
3188 #define PHP_PQ_TYPES_QUERY \
3189 "select t.oid, t.* " \
3190 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
3191 "where typisdefined " \
3192 "and typrelid=0"
3193 #define PHP_PQ_OID_TEXT 25
3194
3195 ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh, 0, 0, 0)
3196 ZEND_ARG_ARRAY_INFO(0, namespaces, 1)
3197 ZEND_END_ARG_INFO();
3198 static PHP_METHOD(pqtypes, refresh) {
3199 HashTable *nsp = NULL;
3200 zend_error_handling zeh;
3201 STATUS rv;
3202
3203 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3204 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H/!", &nsp);
3205 zend_restore_error_handling(&zeh TSRMLS_CC);
3206
3207 if (SUCCESS == rv) {
3208 php_pqtypes_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3209
3210 if (!obj->intern) {
3211 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Types not initialized");
3212 } else {
3213 PGresult *res;
3214
3215 if (!nsp || !zend_hash_num_elements(nsp)) {
3216 res = PQexec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')");
3217 } else {
3218 int i, count;
3219 Oid *oids;
3220 char **params = NULL;
3221 HashTable zdtor;
3222 smart_str str = {0};
3223
3224 smart_str_appends(&str, PHP_PQ_TYPES_QUERY " and nspname in(");
3225 zend_hash_init(&zdtor, 0, NULL, ZVAL_PTR_DTOR, 0);
3226 count = php_pq_params_to_array(nsp, &params, &zdtor TSRMLS_CC);
3227 oids = ecalloc(count + 1, sizeof(*oids));
3228 for (i = 0; i < count; ++i) {
3229 oids[i] = PHP_PQ_OID_TEXT;
3230 if (i) {
3231 smart_str_appendc(&str, ',');
3232 }
3233 smart_str_appendc(&str, '$');
3234 smart_str_append_unsigned(&str, i+1);
3235 }
3236 smart_str_appendc(&str, ')');
3237 smart_str_0(&str);
3238
3239 res = PQexecParams(obj->intern->conn->intern->conn, str.c, count, oids, (const char *const*) params, NULL, NULL, 0);
3240
3241 smart_str_free(&str);
3242 efree(oids);
3243 efree(params);
3244 zend_hash_destroy(&zdtor);
3245 }
3246
3247 if (!res) {
3248 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3249 } else {
3250 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
3251 int r, rows;
3252
3253 for (r = 0, rows = PQntuples(res); r < rows; ++r) {
3254 zval *row = php_pqres_row_to_zval(res, r, PHP_PQRES_FETCH_OBJECT, NULL TSRMLS_CC);
3255 long oid = atol(PQgetvalue(res, r, 0 ));
3256 char *name = PQgetvalue(res, r, 1);
3257
3258 Z_ADDREF_P(row);
3259
3260 zend_hash_index_update(&obj->intern->types, oid, (void *) &row, sizeof(zval *), NULL);
3261 zend_hash_add(&obj->intern->types, name, strlen(name) + 1, (void *) &row, sizeof(zval *), NULL);
3262 }
3263 }
3264
3265 PHP_PQclear(res);
3266 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
3267 }
3268 }
3269 }
3270 }
3271
3272 static zend_function_entry php_pqtypes_methods[] = {
3273 PHP_ME(pqtypes, __construct, ai_pqtypes_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
3274 PHP_ME(pqtypes, refresh, ai_pqtypes_refresh, ZEND_ACC_PUBLIC)
3275 {0}
3276 };
3277
3278 static STATUS php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval ***row TSRMLS_DC)
3279 {
3280 STATUS rv;
3281 php_pqres_fetch_t orig_fetch;
3282
3283 if (!obj) {
3284 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3285 }
3286
3287 if (!obj->intern->iter) {
3288 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
3289 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
3290 }
3291 orig_fetch = obj->intern->iter->fetch_type;
3292 obj->intern->iter->fetch_type = fetch_type;
3293 if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC))) {
3294 obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, row TSRMLS_CC);
3295 obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
3296 }
3297 obj->intern->iter->fetch_type = orig_fetch;
3298
3299 return rv;
3300 }
3301
3302 typedef struct php_pqres_col {
3303 char *name;
3304 int num;
3305 } php_pqres_col_t;
3306
3307 static STATUS column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *col TSRMLS_DC)
3308 {
3309 long index = -1;
3310 char *name = NULL;
3311
3312 switch (Z_TYPE_P(zcol)) {
3313 default:
3314 convert_to_string(zcol);
3315 /* no break */
3316
3317 case IS_STRING:
3318 if (!is_numeric_string(Z_STRVAL_P(zcol), Z_STRLEN_P(zcol), &index, NULL, 0)) {
3319 name = Z_STRVAL_P(zcol);
3320 }
3321 break;
3322
3323 case IS_LONG:
3324 index = Z_LVAL_P(zcol);
3325 break;
3326 }
3327
3328 if (name) {
3329 col->name = name;
3330 col->num = PQfnumber(obj->intern->res, name);
3331 } else {
3332 col->name = PQfname(obj->intern->res, index);
3333 col->num = index;
3334 }
3335
3336 if (!col->name) {
3337 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column at index %ld", index);
3338 return FAILURE;
3339 }
3340 if (col->num == -1) {
3341 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column with name '%s'", name);
3342 return FAILURE;
3343 }
3344 return SUCCESS;
3345 }
3346
3347 static int compare_index(const void *lptr, const void *rptr TSRMLS_DC)
3348 {
3349 const Bucket *l = *(const Bucket **) lptr;
3350 const Bucket *r = *(const Bucket **) rptr;
3351
3352 if (l->h < r->h) {
3353 return -1;
3354 }
3355 if (l->h > r->h) {
3356 return 1;
3357 }
3358 return 0;
3359 }
3360
3361 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind, 0, 0, 2)
3362 ZEND_ARG_INFO(0, col)
3363 ZEND_ARG_INFO(1, ref)
3364 ZEND_END_ARG_INFO();
3365 static PHP_METHOD(pqres, bind) {
3366 zval *zcol, *zref;
3367
3368 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z", &zcol, &zref)) {
3369 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3370
3371 if (!obj->intern) {
3372 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3373 } else {
3374 php_pqres_col_t col;
3375
3376 if (SUCCESS != column_nn(obj, zcol, &col TSRMLS_CC)) {
3377 RETVAL_FALSE;
3378 } else {
3379 Z_ADDREF_P(zref);
3380
3381 if (SUCCESS != zend_hash_index_update(&obj->intern->bound, col.num, (void *) &zref, sizeof(zval *), NULL)) {
3382 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to bind column %s@%d", col.name, col.num);
3383 RETVAL_FALSE;
3384 } else {
3385 zend_hash_sort(&obj->intern->bound, zend_qsort, compare_index, 0 TSRMLS_CC);
3386 RETVAL_TRUE;
3387 }
3388 }
3389 }
3390 }
3391 }
3392
3393 static int apply_bound(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
3394 {
3395 zval **zvalue, **zbound = p;
3396 zval **zrow = va_arg(argv, zval **);
3397 STATUS *rv = va_arg(argv, STATUS *);
3398
3399 if (SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrow), key->h, (void *) &zvalue)) {
3400 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column ad index %lu", key->h);
3401 *rv = FAILURE;
3402 return ZEND_HASH_APPLY_STOP;
3403 } else {
3404 zval_dtor(*zbound);
3405 ZVAL_COPY_VALUE(*zbound, *zvalue);
3406 ZVAL_NULL(*zvalue);
3407 zval_ptr_dtor(zvalue);
3408 Z_ADDREF_P(*zbound);
3409 *zvalue = *zbound;
3410 *rv = SUCCESS;
3411 return ZEND_HASH_APPLY_KEEP;
3412 }
3413 }
3414
3415 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound, 0, 0, 0)
3416 ZEND_END_ARG_INFO();
3417 static PHP_METHOD(pqres, fetchBound) {
3418 zend_error_handling zeh;
3419 STATUS rv;
3420
3421 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3422 rv = zend_parse_parameters_none();
3423 zend_restore_error_handling(&zeh TSRMLS_CC);
3424
3425 if (SUCCESS == rv) {
3426 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3427
3428 if (!obj->intern) {
3429 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3430 } else {
3431 zval **row = NULL;
3432
3433 if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row TSRMLS_CC) && row) {
3434 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC);
3435 zend_hash_apply_with_arguments(&obj->intern->bound TSRMLS_CC, apply_bound, 2, row, &rv);
3436 zend_restore_error_handling(&zeh TSRMLS_CC);
3437
3438 if (SUCCESS != rv) {
3439 zval_ptr_dtor(row);
3440 } else {
3441 RETVAL_ZVAL(*row, 1, 0);
3442 }
3443 }
3444 }
3445 }
3446 }
3447
3448 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
3449 ZEND_ARG_INFO(0, fetch_type)
3450 ZEND_END_ARG_INFO();
3451 static PHP_METHOD(pqres, fetchRow) {
3452 zend_error_handling zeh;
3453 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3454 long fetch_type = -1;
3455 STATUS rv;
3456
3457 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3458 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type);
3459 zend_restore_error_handling(&zeh TSRMLS_CC);
3460
3461 if (SUCCESS == rv) {
3462 if (!obj->intern) {
3463 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3464 } else {
3465 zval **row = NULL;
3466
3467 if (fetch_type == -1) {
3468 fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
3469 }
3470
3471 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC);
3472 php_pqres_iteration(getThis(), obj, fetch_type, &row TSRMLS_CC);
3473 zend_restore_error_handling(&zeh TSRMLS_CC);
3474
3475 if (row) {
3476 RETVAL_ZVAL(*row, 1, 0);
3477 }
3478 }
3479 }
3480 }
3481
3482 static zval **column_at(zval *row, int col TSRMLS_DC)
3483 {
3484 zval **data = NULL;
3485 HashTable *ht = HASH_OF(row);
3486 int count = zend_hash_num_elements(ht);
3487
3488 if (col >= count) {
3489 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count);
3490 } else {
3491 zend_hash_internal_pointer_reset(ht);
3492 while (col-- > 0) {
3493 zend_hash_move_forward(ht);
3494 }
3495 zend_hash_get_current_data(ht, (void *) &data);
3496 }
3497 return data;
3498 }
3499
3500 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
3501 ZEND_ARG_INFO(0, col_num)
3502 ZEND_END_ARG_INFO();
3503 static PHP_METHOD(pqres, fetchCol) {
3504 zend_error_handling zeh;
3505 long fetch_col = 0;
3506 STATUS rv;
3507
3508 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3509 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col);
3510 zend_restore_error_handling(&zeh TSRMLS_CC);
3511
3512 if (SUCCESS == rv) {
3513 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3514
3515 if (!obj->intern) {
3516 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3517 } else {
3518 zval **row = NULL;
3519
3520 zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC);
3521 php_pqres_iteration(getThis(), obj, obj->intern->iter ? obj->intern->iter->fetch_type : 0, &row TSRMLS_CC);
3522 if (row) {
3523 zval **col = column_at(*row, fetch_col TSRMLS_CC);
3524
3525 if (col) {
3526 RETVAL_ZVAL(*col, 1, 0);
3527 }
3528 }
3529 zend_restore_error_handling(&zeh TSRMLS_CC);
3530 }
3531 }
3532 }
3533
3534 static int apply_to_col(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
3535 {
3536 zval **c = p;
3537 php_pqres_object_t *obj = va_arg(argv, php_pqres_object_t *);
3538 php_pqres_col_t *col, **cols = va_arg(argv, php_pqres_col_t **);
3539 STATUS *rv = va_arg(argv, STATUS *);
3540
3541 col = *cols;
3542
3543 if (SUCCESS != column_nn(obj, *c, col TSRMLS_CC)) {
3544 *rv = FAILURE;
3545 return ZEND_HASH_APPLY_STOP;
3546 } else {
3547 *rv = SUCCESS;
3548 ++*cols;
3549 return ZEND_HASH_APPLY_KEEP;
3550 }
3551 }
3552
3553 static php_pqres_col_t *php_pqres_convert_to_cols(php_pqres_object_t *obj, HashTable *ht TSRMLS_DC)
3554 {
3555 php_pqres_col_t *tmp, *cols = ecalloc(zend_hash_num_elements(ht), sizeof(*cols));
3556 STATUS rv = SUCCESS;
3557
3558 tmp = cols;
3559 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_col, 2, obj, &tmp, &rv);
3560
3561 if (SUCCESS == rv) {
3562 return cols;
3563 } else {
3564 efree(cols);
3565 return NULL;
3566 }
3567 }
3568
3569 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_map, 0, 0, 0)
3570 ZEND_ARG_INFO(0, keys)
3571 ZEND_ARG_INFO(0, vals)
3572 ZEND_ARG_INFO(0, fetch_type)
3573 ZEND_END_ARG_INFO();
3574 static PHP_METHOD(pqres, map) {
3575 zend_error_handling zeh;
3576 zval *zkeys = 0, *zvals = 0;
3577 long fetch_type = -1;
3578 STATUS rv;
3579
3580 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3581 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/!z/!l", &zkeys, &zvals, &fetch_type);
3582 zend_restore_error_handling(&zeh TSRMLS_CC);
3583
3584 if (SUCCESS == rv) {
3585 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3586
3587 if (!obj->intern) {
3588 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3589 } else {
3590 int ks = 0, vs = 0;
3591 php_pqres_col_t def = {PQfname(obj->intern->res, 0), 0}, *keys = NULL, *vals = NULL;
3592
3593 if (zkeys) {
3594 convert_to_array(zkeys);
3595
3596 if ((ks = zend_hash_num_elements(Z_ARRVAL_P(zkeys)))) {
3597 keys = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zkeys) TSRMLS_CC);
3598 } else {
3599 ks = 1;
3600 keys = &def;
3601 }
3602 } else {
3603 ks = 1;
3604 keys = &def;
3605 }
3606 if (zvals) {
3607 convert_to_array(zvals);
3608
3609 if ((vs = zend_hash_num_elements(Z_ARRVAL_P(zvals)))) {
3610 vals = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zvals) TSRMLS_CC);
3611 }
3612 }
3613
3614 if (fetch_type == -1) {
3615 fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
3616 }
3617
3618 if (keys) {
3619 int rows, r;
3620 zval **cur;
3621
3622 switch (fetch_type) {
3623 case PHP_PQRES_FETCH_ARRAY:
3624 case PHP_PQRES_FETCH_ASSOC:
3625 array_init(return_value);
3626 break;
3627 case PHP_PQRES_FETCH_OBJECT:
3628 object_init(return_value);
3629 break;
3630 }
3631 for (r = 0, rows = PQntuples(obj->intern->res); r < rows; ++r) {
3632 int k, v;
3633
3634 cur = &return_value;
3635 for (k = 0; k < ks; ++k) {
3636 char *key = PQgetvalue(obj->intern->res, r, keys[k].num);
3637 int len = PQgetlength(obj->intern->res, r, keys[k].num);
3638
3639 if (SUCCESS != zend_symtable_find(HASH_OF(*cur), key, len + 1, (void *) &cur)) {
3640 zval *tmp;
3641
3642 MAKE_STD_ZVAL(tmp);
3643 switch (fetch_type) {
3644 case PHP_PQRES_FETCH_ARRAY:
3645 case PHP_PQRES_FETCH_ASSOC:
3646 array_init(tmp);
3647 break;
3648 case PHP_PQRES_FETCH_OBJECT:
3649 object_init(tmp);
3650 break;
3651 }
3652 if (SUCCESS != zend_symtable_update(HASH_OF(*cur), key, len + 1, (void *) &tmp, sizeof(zval *), (void *) &cur)) {
3653 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create map");
3654 goto err;
3655 }
3656 }
3657 }
3658 if (vals && vs) {
3659 for (v = 0; v < vs; ++v) {
3660 char *val = PQgetvalue(obj->intern->res, r, vals[v].num);
3661 int len = PQgetlength(obj->intern->res, r, vals[v].num);
3662
3663 switch (fetch_type) {
3664 case PHP_PQRES_FETCH_ARRAY:
3665 add_index_stringl(*cur, vals[v].num, val, len, 1);
3666 break;
3667 case PHP_PQRES_FETCH_ASSOC:
3668 add_assoc_stringl(*cur, vals[v].name, val, len, 1);
3669 break;
3670 case PHP_PQRES_FETCH_OBJECT:
3671 add_property_stringl(*cur, vals[v].name, val, len, 1);
3672 break;
3673 }
3674 }
3675 } else {
3676 php_pqres_row_to_zval(obj->intern->res, r, fetch_type, cur TSRMLS_CC);
3677 }
3678 }
3679 }
3680
3681 err:
3682 if (keys && keys != &def) {
3683 efree(keys);
3684 }
3685 if (vals) {
3686 efree(vals);
3687 }
3688 }
3689 }
3690 }
3691
3692 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all, 0, 0, 0)
3693 ZEND_ARG_INFO(0, fetch_type)
3694 ZEND_END_ARG_INFO();
3695 static PHP_METHOD(pqres, fetchAll) {
3696 zend_error_handling zeh;
3697 long fetch_type = -1;
3698 STATUS rv;
3699
3700 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3701 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type);
3702 zend_restore_error_handling(&zeh TSRMLS_CC);
3703
3704 if (SUCCESS == rv) {
3705 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3706 if (!obj->intern) {
3707 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3708 } else {
3709 int r, rows = PQntuples(obj->intern->res);
3710
3711 if (fetch_type == -1) {
3712 fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
3713 }
3714
3715 array_init(return_value);
3716 for (r = 0; r < rows; ++r) {
3717 add_next_index_zval(return_value, php_pqres_row_to_zval(obj->intern->res, r, fetch_type, NULL TSRMLS_CC));
3718 }
3719 }
3720 }
3721 }
3722
3723 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count, 0, 0, 0)
3724 ZEND_END_ARG_INFO();
3725 static PHP_METHOD(pqres, count) {
3726 if (SUCCESS == zend_parse_parameters_none()) {
3727 long count;
3728
3729 if (SUCCESS != php_pqres_count_elements(getThis(), &count TSRMLS_CC)) {
3730 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
3731 } else {
3732 RETVAL_LONG(count);
3733 }
3734 }
3735 }
3736
3737 static zend_function_entry php_pqres_methods[] = {
3738 PHP_ME(pqres, bind, ai_pqres_bind, ZEND_ACC_PUBLIC)
3739 PHP_ME(pqres, fetchBound, ai_pqres_fetch_bound, ZEND_ACC_PUBLIC)
3740 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
3741 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
3742 PHP_ME(pqres, fetchAll, ai_pqres_fetch_all, ZEND_ACC_PUBLIC)
3743 PHP_ME(pqres, count, ai_pqres_count, ZEND_ACC_PUBLIC)
3744 PHP_ME(pqres, map, ai_pqres_map, ZEND_ACC_PUBLIC)
3745 {0}
3746 };
3747
3748 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
3749 ZEND_ARG_OBJ_INFO(0, Connection, pq\\Connection, 0)
3750 ZEND_ARG_INFO(0, type)
3751 ZEND_ARG_INFO(0, query)
3752 ZEND_ARG_ARRAY_INFO(0, types, 1)
3753 ZEND_ARG_INFO(0, async)
3754 ZEND_END_ARG_INFO();
3755 static PHP_METHOD(pqstm, __construct) {
3756 zend_error_handling zeh;
3757 zval *zconn, *ztypes = NULL;
3758 char *name_str, *query_str;
3759 int name_len, *query_len;
3760 zend_bool async = 0;
3761 STATUS rv;
3762
3763 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3764 rv = 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);
3765 zend_restore_error_handling(&zeh TSRMLS_CC);
3766
3767 if (SUCCESS == rv) {
3768 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3769 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
3770
3771 if (!conn_obj->intern) {
3772 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
3773 } else {
3774 if (async) {
3775 rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
3776 } else {
3777 rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
3778 }
3779
3780 if (SUCCESS == rv) {
3781 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
3782
3783 php_pq_object_addref(conn_obj TSRMLS_CC);
3784 stm->conn = conn_obj;
3785 stm->name = estrdup(name_str);
3786 ZEND_INIT_SYMTABLE(&stm->bound);
3787 obj->intern = stm;
3788 }
3789 }
3790 }
3791 }
3792 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_bind, 0, 0, 2)
3793 ZEND_ARG_INFO(0, param_no)
3794 ZEND_ARG_INFO(1, param_ref)
3795 ZEND_END_ARG_INFO();
3796 static PHP_METHOD(pqstm, bind) {
3797 long param_no;
3798 zval *param_ref;
3799
3800 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &param_no, &param_ref)) {
3801 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3802
3803 if (!obj->intern) {
3804 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
3805 } else {
3806 Z_ADDREF_P(param_ref);
3807 zend_hash_index_update(&obj->intern->bound, param_no, (void *) &param_ref, sizeof(zval *), NULL);
3808 zend_hash_sort(&obj->intern->bound, zend_qsort, compare_index, 0 TSRMLS_CC);
3809 }
3810 }
3811 }
3812
3813 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
3814 ZEND_ARG_ARRAY_INFO(0, params, 1)
3815 ZEND_END_ARG_INFO();
3816 static PHP_METHOD(pqstm, exec) {
3817 zend_error_handling zeh;
3818 zval *zparams = NULL;
3819 STATUS rv;
3820
3821 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3822 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams);
3823 zend_restore_error_handling(&zeh TSRMLS_CC);
3824
3825 if (SUCCESS == rv) {
3826 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3827
3828 if (!obj->intern) {
3829 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
3830 } else {
3831 int count = 0;
3832 char **params = NULL;
3833 HashTable zdtor;
3834 PGresult *res;
3835
3836 ZEND_INIT_SYMTABLE(&zdtor);
3837
3838 if (zparams) {
3839 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
3840 } else {
3841 count = php_pq_params_to_array(&obj->intern->bound, &params, &zdtor TSRMLS_CC);
3842 }
3843
3844 res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0);
3845
3846 if (params) {
3847 efree(params);
3848 }
3849 zend_hash_destroy(&zdtor);
3850
3851 if (!res) {
3852 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3853 } else if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
3854 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
3855 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
3856 }
3857 }
3858 }
3859 }
3860
3861 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0)
3862 ZEND_ARG_ARRAY_INFO(0, params, 1)
3863 ZEND_ARG_INFO(0, callable)
3864 ZEND_END_ARG_INFO();
3865 static PHP_METHOD(pqstm, execAsync) {
3866 zend_error_handling zeh;
3867 zval *zparams = NULL;
3868 php_pq_callback_t resolver = {{0}};
3869 STATUS rv;
3870
3871 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3872 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc);
3873 zend_restore_error_handling(&zeh TSRMLS_CC);
3874
3875 if (SUCCESS == rv) {
3876 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3877
3878 if (!obj->intern) {
3879 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
3880 } else {
3881 int count;
3882 char **params = NULL;
3883 HashTable zdtor;
3884
3885 if (zparams) {
3886 ZEND_INIT_SYMTABLE(&zdtor);
3887 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
3888 }
3889
3890 if (!PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0)) {
3891 throw_exce(EX_IO TSRMLS_CC, "Failed to execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3892 } else if (obj->intern->conn->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn->intern->conn)) {
3893 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3894 } else {
3895 php_pq_callback_dtor(&obj->intern->conn->intern->onevent);
3896 if (resolver.fci.size > 0) {
3897 obj->intern->conn->intern->onevent = resolver;
3898 php_pq_callback_addref(&obj->intern->conn->intern->onevent);
3899 }
3900 obj->intern->conn->intern->poller = PQconsumeInput;
3901 }
3902
3903 if (params) {
3904 efree(params);
3905 }
3906 if (zparams) {
3907 zend_hash_destroy(&zdtor);
3908 }
3909
3910 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
3911 }
3912 }
3913 }
3914
3915 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
3916 ZEND_END_ARG_INFO();
3917 static PHP_METHOD(pqstm, desc) {
3918 zend_error_handling zeh;
3919 STATUS rv;
3920
3921 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3922 rv = zend_parse_parameters_none();
3923 zend_restore_error_handling(&zeh TSRMLS_CC);
3924
3925 if (SUCCESS == rv) {
3926 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3927
3928 if (!obj->intern) {
3929 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
3930 } else {
3931 PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name);
3932
3933 if (!res) {
3934 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to describe statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3935 } else {
3936 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
3937 int p, params;
3938
3939 array_init(return_value);
3940 for (p = 0, params = PQnparams(res); p < params; ++p) {
3941 add_next_index_long(return_value, PQparamtype(res, p));
3942 }
3943 }
3944 PHP_PQclear(res);
3945 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
3946 }
3947 }
3948 }
3949 }
3950
3951 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc_async, 0, 0, 0)
3952 ZEND_END_ARG_INFO();
3953 static PHP_METHOD(pqstm, descAsync) {
3954 zend_error_handling zeh;
3955 STATUS rv;
3956
3957 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
3958 rv = zend_parse_parameters_none();
3959 zend_restore_error_handling(&zeh TSRMLS_CC);
3960
3961 if (SUCCESS == rv) {
3962 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
3963
3964 if (!obj->intern) {
3965 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized");
3966 } else if (!PQsendDescribePrepared(obj->intern->conn->intern->conn, obj->intern->name)) {
3967 throw_exce(EX_IO TSRMLS_CC, "Failed to describe statement: %s", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
3968 } else {
3969 obj->intern->conn->intern->poller = PQconsumeInput;
3970 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
3971 }
3972 }
3973 }
3974
3975 static zend_function_entry php_pqstm_methods[] = {
3976 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
3977 PHP_ME(pqstm, bind, ai_pqstm_bind, ZEND_ACC_PUBLIC)
3978 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
3979 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
3980 PHP_ME(pqstm, execAsync, ai_pqstm_exec_async, ZEND_ACC_PUBLIC)
3981 PHP_ME(pqstm, descAsync, ai_pqstm_desc_async, ZEND_ACC_PUBLIC)
3982 {0}
3983 };
3984
3985 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_construct, 0, 0, 1)
3986 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
3987 ZEND_ARG_INFO(0, async)
3988 ZEND_ARG_INFO(0, isolation)
3989 ZEND_ARG_INFO(0, readonly)
3990 ZEND_ARG_INFO(0, deferrable)
3991 ZEND_END_ARG_INFO();
3992 static PHP_METHOD(pqtxn, __construct) {
3993 zend_error_handling zeh;
3994 zval *zconn;
3995 long isolation = PHP_PQTXN_READ_COMMITTED;
3996 zend_bool async = 0, readonly = 0, deferrable = 0;
3997 STATUS rv;
3998
3999 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4000 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|blbb", &zconn, php_pqconn_class_entry, &async, &isolation, &readonly, &deferrable);
4001 zend_restore_error_handling(&zeh TSRMLS_CC);
4002
4003 if (SUCCESS == rv) {
4004 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
4005
4006 if (!conn_obj->intern) {
4007 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
4008 } else {
4009 if (async) {
4010 rv = php_pqconn_start_transaction_async(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC);
4011 } else {
4012 rv = php_pqconn_start_transaction(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC);
4013 }
4014
4015 if (SUCCESS == rv) {
4016 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4017
4018 obj->intern = ecalloc(1, sizeof(*obj->intern));
4019
4020 php_pq_object_addref(conn_obj TSRMLS_CC);
4021 obj->intern->conn = conn_obj;
4022 obj->intern->open = 1;
4023 obj->intern->isolation = isolation;
4024 obj->intern->readonly = readonly;
4025 obj->intern->deferrable = deferrable;
4026 }
4027 }
4028 }
4029 }
4030
4031 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint, 0, 0, 0)
4032 ZEND_END_ARG_INFO();
4033 static PHP_METHOD(pqtxn, savepoint) {
4034 zend_error_handling zeh;
4035 STATUS rv;
4036
4037 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4038 rv = zend_parse_parameters_none();
4039 zend_restore_error_handling(&zeh TSRMLS_CC);
4040
4041 if (SUCCESS == rv) {
4042 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4043
4044 if (!obj->intern) {
4045 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4046 } else if (!obj->intern->open) {
4047 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed");
4048 } else {
4049 PGresult *res;
4050 smart_str cmd = {0};
4051
4052 smart_str_appends(&cmd, "SAVEPOINT \"");
4053 smart_str_append_unsigned(&cmd, ++obj->intern->savepoint);
4054 smart_str_appends(&cmd, "\"");
4055 smart_str_0(&cmd);
4056
4057 res = PQexec(obj->intern->conn->intern->conn, cmd.c);
4058
4059 if (!res) {
4060 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4061 } else {
4062 php_pqres_success(res TSRMLS_CC);
4063 PHP_PQclear(res);
4064 }
4065
4066 smart_str_free(&cmd);
4067 }
4068 }
4069 }
4070
4071 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint_async, 0, 0, 0)
4072 ZEND_END_ARG_INFO();
4073 static PHP_METHOD(pqtxn, savepointAsync) {
4074 zend_error_handling zeh;
4075 STATUS rv;
4076
4077 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4078 rv = zend_parse_parameters_none();
4079 zend_restore_error_handling(&zeh TSRMLS_CC);
4080
4081 if (SUCCESS == rv) {
4082 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4083
4084 if (!obj->intern) {
4085 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4086 } else if (!obj->intern->open) {
4087 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed");
4088 } else {
4089 smart_str cmd = {0};
4090
4091 smart_str_appends(&cmd, "SAVEPOINT \"");
4092 smart_str_append_unsigned(&cmd, ++obj->intern->savepoint);
4093 smart_str_appends(&cmd, "\"");
4094 smart_str_0(&cmd);
4095
4096 if (!PQsendQuery(obj->intern->conn->intern->conn, cmd.c)) {
4097 throw_exce(EX_IO TSRMLS_CC, "Failed to create %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4098 }
4099
4100 smart_str_free(&cmd);
4101 }
4102 }
4103 }
4104
4105 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit, 0, 0, 0)
4106 ZEND_END_ARG_INFO();
4107 static PHP_METHOD(pqtxn, commit) {
4108 zend_error_handling zeh;
4109 STATUS rv;
4110
4111 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4112 rv = zend_parse_parameters_none();
4113 zend_restore_error_handling(&zeh TSRMLS_CC);
4114
4115 if (SUCCESS == rv) {
4116 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4117
4118 if (!obj->intern) {
4119 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transacation not initialized");
4120 } else if (!obj->intern->open) {
4121 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transacation already closed");
4122 } else {
4123 PGresult *res;
4124 smart_str cmd = {0};
4125
4126 if (!obj->intern->savepoint) {
4127 res = PQexec(obj->intern->conn->intern->conn, "COMMIT");
4128 } else {
4129 smart_str_appends(&cmd, "RELEASE SAVEPOINT \"");
4130 smart_str_append_unsigned(&cmd, obj->intern->savepoint--);
4131 smart_str_appends(&cmd, "\"");
4132 smart_str_0(&cmd);
4133
4134 res = PQexec(obj->intern->conn->intern->conn, cmd.c);
4135 }
4136
4137 if (!res) {
4138 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "commit transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4139 } else {
4140 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
4141 if (!cmd.c) {
4142 obj->intern->open = 0;
4143 }
4144 }
4145 PHP_PQclear(res);
4146 }
4147
4148 smart_str_free(&cmd);
4149 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4150 }
4151 }
4152 }
4153
4154 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async, 0, 0, 0)
4155 ZEND_END_ARG_INFO();
4156 static PHP_METHOD(pqtxn, commitAsync) {
4157 zend_error_handling zeh;
4158 STATUS rv;
4159
4160 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4161 rv = zend_parse_parameters_none();
4162 zend_restore_error_handling(&zeh TSRMLS_CC);
4163
4164 if (SUCCESS == rv) {
4165 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4166
4167 if (!obj->intern) {
4168 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4169 } else if (!obj->intern->open) {
4170 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed");
4171 } else {
4172 int rc;
4173 smart_str cmd = {0};
4174
4175 if (!obj->intern->savepoint) {
4176 rc = PQsendQuery(obj->intern->conn->intern->conn, "COMMIT");
4177 } else {
4178 smart_str_appends(&cmd, "RELEASE SAVEPOINT \"");
4179 smart_str_append_unsigned(&cmd, obj->intern->savepoint--);
4180 smart_str_appends(&cmd, "\"");
4181 smart_str_0(&cmd);
4182
4183 rc = PQsendQuery(obj->intern->conn->intern->conn, cmd.c);
4184 }
4185
4186 if (!rc) {
4187 throw_exce(EX_IO TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "commmit transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4188 } else {
4189 if (!cmd.c) {
4190 obj->intern->open = 0;
4191 }
4192 obj->intern->conn->intern->poller = PQconsumeInput;
4193 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4194 }
4195
4196 smart_str_free(&cmd);
4197 }
4198 }
4199 }
4200
4201 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback, 0, 0, 0)
4202 ZEND_END_ARG_INFO();
4203 static PHP_METHOD(pqtxn, rollback) {
4204 zend_error_handling zeh;
4205 STATUS rv;
4206
4207 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4208 rv = zend_parse_parameters_none();
4209 zend_restore_error_handling(&zeh TSRMLS_CC);
4210
4211 if (SUCCESS == rv) {
4212 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4213
4214 if (!obj->intern) {
4215 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4216 } else if (!obj->intern->open) {
4217 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed");
4218 } else {
4219 PGresult *res;
4220 smart_str cmd = {0};
4221
4222 if (!obj->intern->savepoint) {
4223 res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK");
4224 } else {
4225 smart_str_appends(&cmd, "ROLLBACK TO SAVEPOINT \"");
4226 smart_str_append_unsigned(&cmd, obj->intern->savepoint--);
4227 smart_str_appends(&cmd, "\"");
4228 smart_str_0(&cmd);
4229
4230 res = PQexec(obj->intern->conn->intern->conn, cmd.c);
4231 }
4232
4233 if (!res) {
4234 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "rollback transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4235 } else {
4236 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
4237 if (!cmd.c) {
4238 obj->intern->open = 0;
4239 }
4240 }
4241 PHP_PQclear(res);
4242 }
4243
4244 smart_str_free(&cmd);
4245 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4246 }
4247 }
4248 }
4249
4250 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async, 0, 0, 0)
4251 ZEND_END_ARG_INFO();
4252 static PHP_METHOD(pqtxn, rollbackAsync) {
4253 zend_error_handling zeh;
4254 STATUS rv;
4255
4256 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4257 rv = zend_parse_parameters_none();
4258 zend_restore_error_handling(&zeh TSRMLS_CC);
4259
4260 if (SUCCESS == rv) {
4261 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4262
4263 if (!obj->intern) {
4264 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4265 } else if (!obj->intern->open) {
4266 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed");
4267 } else {
4268 int rc;
4269 smart_str cmd = {0};
4270
4271 if (!obj->intern->savepoint) {
4272 rc = PQsendQuery(obj->intern->conn->intern->conn, "ROLLBACK");
4273 } else {
4274 smart_str_appends(&cmd, "ROLLBACK TO SAVEPOINT \"");
4275 smart_str_append_unsigned(&cmd, obj->intern->savepoint--);
4276 smart_str_appends(&cmd, "\"");
4277 smart_str_0(&cmd);
4278
4279 rc = PQsendQuery(obj->intern->conn->intern->conn, cmd.c);
4280 }
4281
4282 if (!rc) {
4283 throw_exce(EX_IO TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "rollback transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4284 } else {
4285 if (!cmd.c) {
4286 obj->intern->open = 0;
4287 }
4288 obj->intern->conn->intern->poller = PQconsumeInput;
4289 }
4290
4291 smart_str_free(&cmd);
4292 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4293 }
4294 }
4295 }
4296
4297 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot, 0, 0, 0)
4298 ZEND_END_ARG_INFO();
4299 static PHP_METHOD(pqtxn, exportSnapshot) {
4300 zend_error_handling zeh;
4301 STATUS rv;
4302
4303 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4304 rv = zend_parse_parameters_none();
4305 zend_restore_error_handling(&zeh TSRMLS_CC);
4306
4307 if (SUCCESS == rv) {
4308 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4309
4310 if (!obj->intern) {
4311 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4312 } else {
4313 PGresult *res = PQexec(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()");
4314
4315 if (!res) {
4316 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4317 } else {
4318 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
4319 RETVAL_STRING(PQgetvalue(res, 0, 0), 1);
4320 }
4321
4322 PHP_PQclear(res);
4323 }
4324
4325 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4326 }
4327 }
4328 }
4329
4330 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot_async, 0, 0, 0)
4331 ZEND_END_ARG_INFO();
4332 static PHP_METHOD(pqtxn, exportSnapshotAsync) {
4333 zend_error_handling zeh;
4334 STATUS rv;
4335
4336 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4337 rv = zend_parse_parameters_none();
4338 zend_restore_error_handling(&zeh TSRMLS_CC);
4339
4340 if (SUCCESS == rv) {
4341 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4342
4343 if (!obj->intern) {
4344 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4345 } else if (!PQsendQuery(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()")) {
4346 throw_exce(EX_IO TSRMLS_CC, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4347 } else {
4348 obj->intern->conn->intern->poller = PQconsumeInput;
4349 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4350 }
4351 }
4352 }
4353
4354 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot, 0, 0, 1)
4355 ZEND_ARG_INFO(0, snapshot_id)
4356 ZEND_END_ARG_INFO();
4357 static PHP_METHOD(pqtxn, importSnapshot) {
4358 zend_error_handling zeh;
4359 char *snapshot_str;
4360 int snapshot_len;
4361 STATUS rv;
4362
4363 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4364 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &snapshot_str, &snapshot_len);
4365 zend_restore_error_handling(&zeh TSRMLS_CC);
4366
4367 if (SUCCESS == rv) {
4368 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4369
4370 if (!obj->intern) {
4371 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4372 } else if (obj->intern->isolation < PHP_PQTXN_REPEATABLE_READ) {
4373 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
4374 } else {
4375 char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len);
4376
4377 if (!sid) {
4378 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4379 } else {
4380 PGresult *res;
4381 smart_str cmd = {0};
4382
4383 smart_str_appends(&cmd, "SET TRANSACTION SNAPSHOT ");
4384 smart_str_appends(&cmd, sid);
4385 smart_str_0(&cmd);
4386
4387 res = PQexec(obj->intern->conn->intern->conn, cmd.c);
4388
4389 if (!res) {
4390 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to import transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4391 } else {
4392 php_pqres_success(res TSRMLS_CC);
4393 PHP_PQclear(res);
4394 }
4395
4396 smart_str_free(&cmd);
4397 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4398 }
4399 }
4400 }
4401 }
4402
4403 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot_async, 0, 0, 1)
4404 ZEND_ARG_INFO(0, snapshot_id)
4405 ZEND_END_ARG_INFO();
4406 static PHP_METHOD(pqtxn, importSnapshotAsync) {
4407 zend_error_handling zeh;
4408 char *snapshot_str;
4409 int snapshot_len;
4410 STATUS rv;
4411
4412 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4413 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &snapshot_str, &snapshot_len);
4414 zend_restore_error_handling(&zeh TSRMLS_CC);
4415
4416 if (SUCCESS == rv) {
4417 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4418
4419 if (!obj->intern) {
4420 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4421 } else if (obj->intern->isolation < PHP_PQTXN_REPEATABLE_READ) {
4422 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot");
4423 } else {
4424 char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len);
4425
4426 if (!sid) {
4427 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4428 } else {
4429 smart_str cmd = {0};
4430
4431 smart_str_appends(&cmd, "SET TRANSACTION SNAPSHOT ");
4432 smart_str_appends(&cmd, sid);
4433 smart_str_0(&cmd);
4434
4435 if (!PQsendQuery(obj->intern->conn->intern->conn, cmd.c)) {
4436 throw_exce(EX_IO TSRMLS_CC, "Failed to %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4437 } else {
4438 obj->intern->conn->intern->poller = PQconsumeInput;
4439 }
4440
4441 smart_str_free(&cmd);
4442 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4443 }
4444 }
4445 }
4446 }
4447
4448 static const char *strmode(long mode)
4449 {
4450 switch (mode & (INV_READ|INV_WRITE)) {
4451 case INV_READ|INV_WRITE:
4452 return "rw";
4453 case INV_READ:
4454 return "r";
4455 case INV_WRITE:
4456 return "w";
4457 default:
4458 return "-";
4459 }
4460 }
4461
4462 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_open_lob, 0, 0, 1)
4463 ZEND_ARG_INFO(0, oid)
4464 ZEND_ARG_INFO(0, mode)
4465 ZEND_END_ARG_INFO();
4466 static PHP_METHOD(pqtxn, openLOB) {
4467 zend_error_handling zeh;
4468 long mode = INV_WRITE|INV_READ, loid;
4469 STATUS rv;
4470
4471 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4472 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &loid, &mode);
4473 zend_restore_error_handling(&zeh TSRMLS_CC);
4474
4475 if (SUCCESS == rv) {
4476 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4477
4478 if (!obj->intern) {
4479 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4480 } else {
4481 int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode);
4482
4483 if (lofd < 0) {
4484 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4485 } else {
4486 php_pqlob_t *lob = ecalloc(1, sizeof(*lob));
4487
4488 lob->lofd = lofd;
4489 lob->loid = loid;
4490 php_pq_object_addref(obj TSRMLS_CC);
4491 lob->txn = obj;
4492
4493 return_value->type = IS_OBJECT;
4494 return_value->value.obj = php_pqlob_create_object_ex(php_pqlob_class_entry, lob, NULL TSRMLS_CC);
4495 }
4496
4497 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4498 }
4499 }
4500 }
4501
4502 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_create_lob, 0, 0, 0)
4503 ZEND_ARG_INFO(0, mode)
4504 ZEND_END_ARG_INFO();
4505 static PHP_METHOD(pqtxn, createLOB) {
4506 zend_error_handling zeh;
4507 long mode = INV_WRITE|INV_READ;
4508 STATUS rv;
4509
4510 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4511 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &mode);
4512 zend_restore_error_handling(&zeh TSRMLS_CC);
4513
4514 if (SUCCESS == rv) {
4515 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4516
4517 if (!obj->intern) {
4518 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4519 } else {
4520 Oid loid = lo_creat(obj->intern->conn->intern->conn, mode);
4521
4522 if (loid == InvalidOid) {
4523 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create large object with mode '%s' (%s)", strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4524 } else {
4525 int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode);
4526
4527 if (lofd < 0) {
4528 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s': %s", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4529 } else {
4530 php_pqlob_t *lob = ecalloc(1, sizeof(*lob));
4531
4532 lob->lofd = lofd;
4533 lob->loid = loid;
4534 php_pq_object_addref(obj TSRMLS_CC);
4535 lob->txn = obj;
4536
4537 return_value->type = IS_OBJECT;
4538 return_value->value.obj = php_pqlob_create_object_ex(php_pqlob_class_entry, lob, NULL TSRMLS_CC);
4539 }
4540 }
4541
4542 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4543 }
4544 }
4545 }
4546
4547 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_unlink_lob, 0, 0, 1)
4548 ZEND_ARG_INFO(0, oid)
4549 ZEND_END_ARG_INFO();
4550 static PHP_METHOD(pqtxn, unlinkLOB) {
4551 zend_error_handling zeh;
4552 long loid;
4553 STATUS rv;
4554
4555 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4556 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &loid);
4557 zend_restore_error_handling(&zeh TSRMLS_CC);
4558
4559 if (SUCCESS == rv) {
4560 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4561
4562 if (!obj->intern) {
4563 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4564 } else {
4565 int rc = lo_unlink(obj->intern->conn->intern->conn, loid);
4566
4567 if (rc != 1) {
4568 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to unlink LOB (oid=%ld): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
4569 }
4570
4571 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
4572 }
4573 }
4574 }
4575
4576 static zend_function_entry php_pqtxn_methods[] = {
4577 PHP_ME(pqtxn, __construct, ai_pqtxn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
4578 PHP_ME(pqtxn, commit, ai_pqtxn_commit, ZEND_ACC_PUBLIC)
4579 PHP_ME(pqtxn, rollback, ai_pqtxn_rollback, ZEND_ACC_PUBLIC)
4580 PHP_ME(pqtxn, commitAsync, ai_pqtxn_commit_async, ZEND_ACC_PUBLIC)
4581 PHP_ME(pqtxn, rollbackAsync, ai_pqtxn_rollback_async, ZEND_ACC_PUBLIC)
4582 PHP_ME(pqtxn, savepoint, ai_pqtxn_savepoint, ZEND_ACC_PUBLIC)
4583 PHP_ME(pqtxn, savepointAsync, ai_pqtxn_savepoint_async, ZEND_ACC_PUBLIC)
4584 PHP_ME(pqtxn, exportSnapshot, ai_pqtxn_export_snapshot, ZEND_ACC_PUBLIC)
4585 PHP_ME(pqtxn, exportSnapshotAsync, ai_pqtxn_export_snapshot_async, ZEND_ACC_PUBLIC)
4586 PHP_ME(pqtxn, importSnapshot, ai_pqtxn_import_snapshot, ZEND_ACC_PUBLIC)
4587 PHP_ME(pqtxn, importSnapshotAsync, ai_pqtxn_import_snapshot_async, ZEND_ACC_PUBLIC)
4588 PHP_ME(pqtxn, openLOB, ai_pqtxn_open_lob, ZEND_ACC_PUBLIC)
4589 PHP_ME(pqtxn, createLOB, ai_pqtxn_create_lob, ZEND_ACC_PUBLIC)
4590 PHP_ME(pqtxn, unlinkLOB, ai_pqtxn_unlink_lob, ZEND_ACC_PUBLIC)
4591 {0}
4592 };
4593
4594 ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_construct, 0, 0, 1)
4595 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
4596 ZEND_END_ARG_INFO();
4597 static PHP_METHOD(pqcancel, __construct) {
4598 zend_error_handling zeh;
4599 zval *zconn;
4600 STATUS rv;
4601
4602 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4603 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zconn, php_pqconn_class_entry);
4604 zend_restore_error_handling(&zeh TSRMLS_CC);
4605
4606 if (SUCCESS == rv) {
4607 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
4608
4609 if (!conn_obj->intern) {
4610 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
4611 } else {
4612 PGcancel *cancel = PQgetCancel(conn_obj->intern->conn);
4613
4614 if (!cancel) {
4615 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to acquire cancel (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
4616 } else {
4617 php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4618
4619 obj->intern = ecalloc(1, sizeof(*obj->intern));
4620 obj->intern->cancel = cancel;
4621 php_pq_object_addref(conn_obj TSRMLS_CC);
4622 obj->intern->conn = conn_obj;
4623 }
4624 }
4625 }
4626 }
4627
4628 ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_cancel, 0, 0, 0)
4629 ZEND_END_ARG_INFO();
4630 static PHP_METHOD(pqcancel, cancel) {
4631 zend_error_handling zeh;
4632 STATUS rv;
4633
4634 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4635 rv = zend_parse_parameters_none();
4636 zend_restore_error_handling(&zeh TSRMLS_CC);
4637
4638 if (SUCCESS == rv) {
4639 php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4640
4641 if (!obj->intern) {
4642 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Cancel not initialized");
4643 } else {
4644 char err[256] = {0};
4645
4646 if (!PQcancel(obj->intern->cancel, err, sizeof(err))) {
4647 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to request cancellation (%s)", err);
4648 }
4649 }
4650 }
4651 }
4652
4653 static zend_function_entry php_pqcancel_methods[] = {
4654 PHP_ME(pqcancel, __construct, ai_pqcancel_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
4655 PHP_ME(pqcancel, cancel, ai_pqcancel_cancel, ZEND_ACC_PUBLIC)
4656 {0}
4657 };
4658
4659 ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_construct, 0, 0, 3)
4660 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
4661 ZEND_ARG_INFO(0, type)
4662 ZEND_ARG_INFO(0, callable)
4663 ZEND_END_ARG_INFO();
4664 static PHP_METHOD(pqevent, __construct) {
4665 zend_error_handling zeh;
4666 zval *zconn;
4667 char *type_str;
4668 int type_len;
4669 php_pq_callback_t cb;
4670 STATUS rv;
4671
4672 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4673 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osf", &zconn, php_pqconn_class_entry, &type_str, &type_len, &cb.fci, &cb.fcc);
4674 zend_restore_error_handling(&zeh TSRMLS_CC);
4675
4676 if (SUCCESS == rv) {
4677 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
4678
4679 if (!conn_obj->intern) {
4680 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
4681 } else {
4682 php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4683
4684 obj->intern = ecalloc(1, sizeof(*obj->intern));
4685 php_pq_callback_addref(&cb);
4686 obj->intern->cb = cb;
4687 obj->intern->type = estrdup(type_str);
4688 obj->intern->h = php_pqconn_add_eventhandler(conn_obj, type_str, type_len, getThis() TSRMLS_CC);
4689 }
4690 }
4691 }
4692
4693 ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_trigger, 0, 0, 1)
4694 ZEND_ARG_ARRAY_INFO(0, args, 1)
4695 ZEND_END_ARG_INFO();
4696 static PHP_METHOD(pqevent, trigger) {
4697 zend_error_handling zeh;
4698 zval *args;
4699 STATUS rv;
4700
4701 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4702 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &args);
4703 zend_restore_error_handling(&zeh TSRMLS_CC);
4704
4705 if (SUCCESS == rv) {
4706 php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4707
4708 if (!obj->intern) {
4709 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Event not initialized");
4710 } else {
4711 zval *rv = NULL;
4712
4713 if (SUCCESS != zend_fcall_info_call(&obj->intern->cb.fci, &obj->intern->cb.fcc, &rv, args TSRMLS_CC)) {
4714 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to trigger event");
4715 } else {
4716 if (rv) {
4717 RETVAL_ZVAL(rv, 0, 1);
4718 } else {
4719 RETVAL_TRUE;
4720 }
4721 }
4722 }
4723 }
4724 }
4725
4726 static zend_function_entry php_pqevent_methods[] = {
4727 PHP_ME(pqevent, __construct, ai_pqevent_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
4728 PHP_ME(pqevent, trigger, ai_pqevent_trigger, ZEND_ACC_PUBLIC)
4729 {0}
4730 };
4731
4732 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct, 0, 0, 1)
4733 ZEND_ARG_OBJ_INFO(0, transaction, pq\\Transaction, 0)
4734 ZEND_ARG_INFO(0, oid)
4735 ZEND_ARG_INFO(0, mode)
4736 ZEND_END_ARG_INFO();
4737 static PHP_METHOD(pqlob, __construct) {
4738 zend_error_handling zeh;
4739 zval *ztxn;
4740 long mode = INV_WRITE|INV_READ, loid = InvalidOid;
4741 STATUS rv;
4742
4743 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4744 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &ztxn, php_pqtxn_class_entry, &loid, &mode);
4745 zend_restore_error_handling(&zeh TSRMLS_CC);
4746
4747 if (SUCCESS == rv) {
4748 php_pqtxn_object_t *txn_obj = zend_object_store_get_object(ztxn TSRMLS_CC);
4749
4750 if (!txn_obj->intern) {
4751 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized");
4752 } else if (!txn_obj->intern->open) {
4753 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transation already closed");
4754 } else {
4755 if (loid == InvalidOid) {
4756 loid = lo_creat(txn_obj->intern->conn->intern->conn, mode);
4757 }
4758
4759 if (loid == InvalidOid) {
4760 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create large object with mode '%s' (%s)", strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn));
4761 } else {
4762 int lofd = lo_open(txn_obj->intern->conn->intern->conn, loid, mode);
4763
4764 if (lofd < 0) {
4765 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn));
4766 } else {
4767 php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4768
4769 obj->intern = ecalloc(1, sizeof(*obj->intern));
4770 obj->intern->lofd = lofd;
4771 obj->intern->loid = loid;
4772 php_pq_object_addref(txn_obj TSRMLS_CC);
4773 obj->intern->txn = txn_obj;
4774 }
4775 }
4776
4777 php_pqconn_notify_listeners(txn_obj->intern->conn TSRMLS_CC);
4778 }
4779 }
4780 }
4781
4782 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write, 0, 0, 1)
4783 ZEND_ARG_INFO(0, data)
4784 ZEND_END_ARG_INFO();
4785 static PHP_METHOD(pqlob, write) {
4786 zend_error_handling zeh;
4787 char *data_str;
4788 int data_len;
4789 STATUS rv;
4790
4791 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4792 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len);
4793 zend_restore_error_handling(&zeh TSRMLS_CC);
4794
4795 if (SUCCESS == rv) {
4796 php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4797
4798 if (!obj->intern) {
4799 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized");
4800 } else {
4801 int written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, data_str, data_len);
4802
4803 if (written < 0) {
4804 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to write to LOB with oid=%ld (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
4805 } else {
4806 RETVAL_LONG(written);
4807 }
4808
4809 php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
4810 }
4811 }
4812 }
4813
4814 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read, 0, 0, 0)
4815 ZEND_ARG_INFO(0, length)
4816 ZEND_ARG_INFO(1, read)
4817 ZEND_END_ARG_INFO();
4818 static PHP_METHOD(pqlob, read) {
4819 zend_error_handling zeh;
4820 long length = 0x1000;
4821 zval *zread = NULL;
4822 STATUS rv;
4823
4824 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4825 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lz!", &length, &zread);
4826 zend_restore_error_handling(&zeh TSRMLS_CC);
4827
4828 if (SUCCESS == rv) {
4829 php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4830
4831 if (!obj->intern) {
4832 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized");
4833 } else {
4834 char *buffer = emalloc(length + 1);
4835 int read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length);
4836
4837 if (read < 0) {
4838 efree(buffer);
4839 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to read from LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
4840 } else {
4841 if (zread) {
4842 zval_dtor(zread);
4843 ZVAL_LONG(zread, read);
4844 }
4845 buffer[read] = '\0';
4846 RETVAL_STRINGL(buffer, read, 0);
4847 }
4848
4849 php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
4850 }
4851 }
4852 }
4853
4854 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek, 0, 0, 1)
4855 ZEND_ARG_INFO(0, offset)
4856 ZEND_ARG_INFO(0, whence)
4857 ZEND_END_ARG_INFO();
4858 static PHP_METHOD(pqlob, seek) {
4859 zend_error_handling zeh;
4860 long offset, whence = SEEK_SET;
4861 STATUS rv;
4862
4863 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4864 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &offset, &whence);
4865 zend_restore_error_handling(&zeh TSRMLS_CC);
4866
4867 if (SUCCESS == rv) {
4868 php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4869
4870 if (!obj->intern) {
4871 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized");
4872 } else {
4873 int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence);
4874
4875 if (position < 0) {
4876 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to seek offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
4877 } else {
4878 RETVAL_LONG(position);
4879 }
4880
4881 php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
4882 }
4883 }
4884 }
4885
4886 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell, 0, 0, 0)
4887 ZEND_END_ARG_INFO();
4888 static PHP_METHOD(pqlob, tell) {
4889 zend_error_handling zeh;
4890 STATUS rv;
4891
4892 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4893 rv = zend_parse_parameters_none();
4894 zend_restore_error_handling(&zeh TSRMLS_CC);
4895
4896 if (SUCCESS == rv) {
4897 php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4898
4899 if (!obj->intern) {
4900 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized");
4901 } else {
4902 int position = lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd);
4903
4904 if (position < 0) {
4905 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to tell offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
4906 } else {
4907 RETVAL_LONG(position);
4908 }
4909
4910 php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
4911 }
4912 }
4913 }
4914
4915 ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate, 0, 0, 0)
4916 ZEND_ARG_INFO(0, length)
4917 ZEND_END_ARG_INFO();
4918 static PHP_METHOD(pqlob, truncate) {
4919 zend_error_handling zeh;
4920 long length = 0;
4921 STATUS rv;
4922
4923 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4924 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &length);
4925 zend_restore_error_handling(&zeh TSRMLS_CC);
4926
4927 if (SUCCESS == rv) {
4928 php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4929
4930 if (!obj->intern) {
4931 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized");
4932 } else {
4933 int rc = lo_truncate(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, length);
4934
4935 if (rc != 0) {
4936 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to truncate LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn));
4937 }
4938
4939 php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC);
4940 }
4941 }
4942 }
4943
4944 static zend_function_entry php_pqlob_methods[] = {
4945 PHP_ME(pqlob, __construct, ai_pqlob_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
4946 PHP_ME(pqlob, write, ai_pqlob_write, ZEND_ACC_PUBLIC)
4947 PHP_ME(pqlob, read, ai_pqlob_read, ZEND_ACC_PUBLIC)
4948 PHP_ME(pqlob, seek, ai_pqlob_seek, ZEND_ACC_PUBLIC)
4949 PHP_ME(pqlob, tell, ai_pqlob_tell, ZEND_ACC_PUBLIC)
4950 PHP_ME(pqlob, truncate, ai_pqlob_truncate, ZEND_ACC_PUBLIC)
4951 {0}
4952 };
4953
4954 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_construct, 0, 0, 3)
4955 ZEND_ARG_OBJ_INFO(0, "connection", pq\\Connection, 0)
4956 ZEND_ARG_INFO(0, expression)
4957 ZEND_ARG_INFO(0, direction)
4958 ZEND_ARG_INFO(0, options)
4959 ZEND_END_ARG_INFO();
4960 static PHP_METHOD(pqcopy, __construct) {
4961 zend_error_handling zeh;
4962 zval *zconn;
4963 char *expr_str, *opt_str = "";
4964 int expr_len, opt_len = 0;
4965 long direction;
4966 STATUS rv;
4967
4968 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
4969 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osl|s", &zconn, php_pqconn_class_entry, &expr_str, &expr_len, &direction, &opt_str, &opt_len);
4970 zend_restore_error_handling(&zeh TSRMLS_CC);
4971
4972 if (SUCCESS == rv) {
4973 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
4974
4975 if (!conn_obj->intern) {
4976 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
4977 } else {
4978 php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
4979 smart_str cmd = {0};
4980 PGresult *res;
4981
4982 smart_str_appends(&cmd, "COPY ");
4983 smart_str_appendl(&cmd, expr_str, expr_len);
4984
4985 switch (direction) {
4986 case PHP_PQCOPY_FROM_STDIN:
4987 smart_str_appends(&cmd, " FROM STDIN ");
4988 break;
4989 case PHP_PQCOPY_TO_STDOUT:
4990 smart_str_appends(&cmd, " TO STDOUT ");
4991 break;
4992 default:
4993 throw_exce(EX_RUNTIME TSRMLS_CC, "Invalid COPY direction, expected one of FROM_STDIN (%d) TO_STDOUT (%d), got %ld", PHP_PQCOPY_FROM_STDIN, PHP_PQCOPY_TO_STDOUT, direction);
4994 smart_str_free(&cmd);
4995 return;
4996 }
4997 smart_str_appendl(&cmd, opt_str, opt_len);
4998 smart_str_0(&cmd);
4999
5000 res = PQexec(conn_obj->intern->conn, cmd.c);
5001
5002 if (!res) {
5003 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to start %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn));
5004 } else {
5005 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
5006 obj->intern = ecalloc(1, sizeof(*obj->intern));
5007 obj->intern->direction = direction;
5008 obj->intern->expression = estrdup(expr_str);
5009 obj->intern->options = estrdup(opt_str);
5010 obj->intern->conn = conn_obj;
5011 php_pq_object_addref(conn_obj TSRMLS_CC);
5012 }
5013
5014 PHP_PQclear(res);
5015 }
5016
5017 smart_str_free(&cmd);
5018 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
5019 }
5020 }
5021 }
5022
5023 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_put, 0, 0, 1)
5024 ZEND_ARG_INFO(0, data)
5025 ZEND_END_ARG_INFO();
5026 static PHP_METHOD(pqcopy, put) {
5027 zend_error_handling zeh;
5028 char *data_str;
5029 int data_len;
5030 STATUS rv;
5031
5032 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
5033 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len);
5034 zend_restore_error_handling(&zeh TSRMLS_CC);
5035
5036 if (SUCCESS == rv) {
5037 php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
5038
5039 if (!obj->intern) {
5040 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\COPY not initialized");
5041 } else if (obj->intern->direction != PHP_PQCOPY_FROM_STDIN) {
5042 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY was not initialized with FROM_STDIN");
5043 } else {
5044 if (1 != PQputCopyData(obj->intern->conn->intern->conn, data_str, data_len)) {
5045 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to put COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
5046 }
5047 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
5048 }
5049 }
5050 }
5051
5052 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_end, 0, 0, 0)
5053 ZEND_ARG_INFO(0, error)
5054 ZEND_END_ARG_INFO();
5055 static PHP_METHOD(pqcopy, end) {
5056 zend_error_handling zeh;
5057 char *error_str = NULL;
5058 int error_len = 0;
5059 STATUS rv;
5060
5061 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
5062 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &error_str, &error_len);
5063 zend_restore_error_handling(&zeh TSRMLS_CC);
5064
5065 if (SUCCESS == rv) {
5066 php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
5067
5068 if (!obj->intern) {
5069 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY not intitialized");
5070 } else if (obj->intern->direction != PHP_PQCOPY_FROM_STDIN) {
5071 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY was not intitialized with FROM_STDIN");
5072 } else {
5073 if (1 != PQputCopyEnd(obj->intern->conn->intern->conn, error_str)) {
5074 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to end COPY (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
5075 } else {
5076 PGresult *res = PQgetResult(obj->intern->conn->intern->conn);
5077
5078 if (!res) {
5079 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
5080 } else {
5081 php_pqres_success(res TSRMLS_CC);
5082 PHP_PQclear(res);
5083 }
5084 }
5085
5086 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
5087 }
5088 }
5089 }
5090
5091 ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_get, 0, 0, 1)
5092 ZEND_ARG_INFO(1, data)
5093 ZEND_END_ARG_INFO();
5094 static PHP_METHOD(pqcopy, get) {
5095 zend_error_handling zeh;
5096 zval *zdata;
5097 STATUS rv;
5098
5099 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
5100 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata);
5101 zend_restore_error_handling(&zeh TSRMLS_CC);
5102
5103 if (SUCCESS == rv) {
5104 php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
5105
5106 if (!obj->intern) {
5107 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\COPY not initialized");
5108 } else if (obj->intern->direction != PHP_PQCOPY_TO_STDOUT) {
5109 throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY was not intialized with TO_STDOUT");
5110 } else {
5111 PGresult *res;
5112 char *buffer = NULL;
5113 int bytes = PQgetCopyData(obj->intern->conn->intern->conn, &buffer, 0);
5114
5115 switch (bytes) {
5116 case -2:
5117 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
5118 break;
5119
5120 case -1:
5121 res = PQgetResult(obj->intern->conn->intern->conn);
5122
5123 if (!res) {
5124 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
5125 } else {
5126 php_pqres_success(res TSRMLS_CC);
5127 PHP_PQclear(res);
5128 RETVAL_FALSE;
5129 }
5130 break;
5131
5132 default:
5133 zval_dtor(zdata);
5134 if (buffer) {
5135 ZVAL_STRINGL(zdata, buffer, bytes, 1);
5136 } else {
5137 ZVAL_EMPTY_STRING(zdata);
5138 }
5139 RETVAL_TRUE;
5140 break;
5141 }
5142
5143 if (buffer) {
5144 PQfreemem(buffer);
5145 }
5146 }
5147 }
5148 }
5149
5150 static zend_function_entry php_pqcopy_methods[] = {
5151 PHP_ME(pqcopy, __construct, ai_pqcopy_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
5152 PHP_ME(pqcopy, put, ai_pqcopy_put, ZEND_ACC_PUBLIC)
5153 PHP_ME(pqcopy, end, ai_pqcopy_end, ZEND_ACC_PUBLIC)
5154 PHP_ME(pqcopy, get, ai_pqcopy_get, ZEND_ACC_PUBLIC)
5155 {0}
5156 };
5157
5158 static zend_function_entry php_pqexc_methods[] = {
5159 {0}
5160 };
5161
5162 /* {{{ PHP_MINIT_FUNCTION
5163 */
5164 static PHP_MINIT_FUNCTION(pq)
5165 {
5166 zend_class_entry ce = {0};
5167 php_pq_object_prophandler_t ph = {0};
5168
5169 INIT_NS_CLASS_ENTRY(ce, "pq", "Exception", php_pqexc_methods);
5170 php_pqexc_interface_class_entry = zend_register_internal_interface(&ce TSRMLS_CC);
5171
5172 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("INVALID_ARGUMENT"), EX_INVALID_ARGUMENT TSRMLS_CC);
5173 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("RUNTIME"), EX_RUNTIME TSRMLS_CC);
5174 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("CONNECTION_FAILED"), EX_CONNECTION_FAILED TSRMLS_CC);
5175 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("IO"), EX_IO TSRMLS_CC);
5176 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("ESCAPE"), EX_ESCAPE TSRMLS_CC);
5177 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("BAD_METHODCALL"), EX_BAD_METHODCALL TSRMLS_CC);
5178 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("UNINITIALIZED"), EX_UNINITIALIZED TSRMLS_CC);
5179 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("DOMAIN"), EX_DOMAIN TSRMLS_CC);
5180 zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("SQL"), EX_SQL TSRMLS_CC);
5181
5182 memset(&ce, 0, sizeof(ce));
5183 INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "InvalidArgumentException", php_pqexc_methods);
5184 php_pqexc_invalid_argument_class_entry = zend_register_internal_class_ex(&ce, spl_ce_InvalidArgumentException, "InvalidArgumentException" TSRMLS_CC);
5185 zend_class_implements(php_pqexc_invalid_argument_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry);
5186
5187 memset(&ce, 0, sizeof(ce));
5188 INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "RuntimeException", php_pqexc_methods);
5189 php_pqexc_runtime_class_entry = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException, "RuntimeException" TSRMLS_CC);
5190 zend_class_implements(php_pqexc_runtime_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry);
5191
5192 memset(&ce, 0, sizeof(ce));
5193 INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "BadMethodCallException", php_pqexc_methods);
5194 php_pqexc_bad_methodcall_class_entry = zend_register_internal_class_ex(&ce, spl_ce_BadMethodCallException, "BadMethodCallException" TSRMLS_CC);
5195 zend_class_implements(php_pqexc_bad_methodcall_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry);
5196
5197 memset(&ce, 0, sizeof(ce));
5198 INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "DomainException", php_pqexc_methods);
5199 php_pqexc_domain_class_entry = zend_register_internal_class_ex(&ce, spl_ce_DomainException, "DomainException" TSRMLS_CC);
5200 zend_class_implements(php_pqexc_domain_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry);
5201 zend_declare_property_null(php_pqexc_domain_class_entry, ZEND_STRL("sqlstate"), ZEND_ACC_PUBLIC TSRMLS_CC);
5202
5203 memset(&ce, 0, sizeof(ce));
5204 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
5205 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5206 php_pqconn_class_entry->create_object = php_pqconn_create_object;
5207
5208 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5209 php_pqconn_object_handlers.read_property = php_pq_object_read_prop;
5210 php_pqconn_object_handlers.write_property = php_pq_object_write_prop;
5211 php_pqconn_object_handlers.clone_obj = NULL;
5212 php_pqconn_object_handlers.get_property_ptr_ptr = NULL;
5213 php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info;
5214
5215 zend_hash_init(&php_pqconn_object_prophandlers, 14, NULL, NULL, 1);
5216
5217 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
5218 ph.read = php_pqconn_object_read_status;
5219 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
5220
5221 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
5222 ph.read = php_pqconn_object_read_transaction_status;
5223 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
5224
5225 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
5226 ph.read = NULL; /* forward to std prophandler */
5227 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
5228
5229 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
5230 ph.read = php_pqconn_object_read_error_message;
5231 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
5232
5233 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5234 ph.read = php_pqconn_object_read_busy;
5235 zend_hash_add(&php_pqconn_object_prophandlers, "busy", sizeof("busy"), (void *) &ph, sizeof(ph), NULL);
5236
5237 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC TSRMLS_CC);
5238 ph.read = php_pqconn_object_read_encoding;
5239 ph.write = php_pqconn_object_write_encoding;
5240 zend_hash_add(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding"), (void *) &ph, sizeof(ph), NULL);
5241 ph.write = NULL;
5242
5243 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5244 ph.read = php_pqconn_object_read_unbuffered;
5245 ph.write = php_pqconn_object_write_unbuffered;
5246 zend_hash_add(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered"), (void *) &ph, sizeof(ph), NULL);
5247 ph.write = NULL;
5248
5249 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC TSRMLS_CC);
5250 ph.read = php_pqconn_object_read_db;
5251 zend_hash_add(&php_pqconn_object_prophandlers, "db", sizeof("db"), (void *) &ph, sizeof(ph), NULL);
5252
5253 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC);
5254 ph.read = php_pqconn_object_read_user;
5255 zend_hash_add(&php_pqconn_object_prophandlers, "user", sizeof("user"), (void *) &ph, sizeof(ph), NULL);
5256
5257 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC);
5258 ph.read = php_pqconn_object_read_pass;
5259 zend_hash_add(&php_pqconn_object_prophandlers, "pass", sizeof("pass"), (void *) &ph, sizeof(ph), NULL);
5260
5261 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
5262 ph.read = php_pqconn_object_read_host;
5263 zend_hash_add(&php_pqconn_object_prophandlers, "host", sizeof("host"), (void *) &ph, sizeof(ph), NULL);
5264
5265 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC);
5266 ph.read = php_pqconn_object_read_port;
5267 zend_hash_add(&php_pqconn_object_prophandlers, "port", sizeof("port"), (void *) &ph, sizeof(ph), NULL);
5268
5269 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC TSRMLS_CC);
5270 ph.read = php_pqconn_object_read_options;
5271 zend_hash_add(&php_pqconn_object_prophandlers, "options", sizeof("options"), (void *) &ph, sizeof(ph), NULL);
5272
5273 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC TSRMLS_CC);
5274 ph.read = php_pqconn_object_read_event_handlers;
5275 zend_hash_add(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers"), (void *) &ph, sizeof(ph), NULL);
5276
5277 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
5278 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
5279 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
5280 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
5281 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
5282 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
5283 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
5284 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
5285
5286 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
5287 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
5288 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
5289 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
5290 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
5291
5292 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
5293 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
5294 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
5295 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
5296
5297 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("ASYNC"), 0x1 TSRMLS_CC);
5298 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("PERSISTENT"), 0x2 TSRMLS_CC);
5299 memset(&ce, 0, sizeof(ce));
5300 INIT_NS_CLASS_ENTRY(ce, "pq", "Types", php_pqtypes_methods);
5301 php_pqtypes_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5302 php_pqtypes_class_entry->create_object = php_pqtypes_create_object;
5303
5304 memcpy(&php_pqtypes_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5305 php_pqtypes_object_handlers.read_property = php_pq_object_read_prop;
5306 php_pqtypes_object_handlers.write_property = php_pq_object_write_prop;
5307 php_pqtypes_object_handlers.clone_obj = NULL;
5308 php_pqtypes_object_handlers.get_property_ptr_ptr = NULL;
5309 php_pqtypes_object_handlers.get_debug_info = php_pq_object_debug_info;
5310 php_pqtypes_object_handlers.has_dimension = php_pqtypes_object_has_dimension;
5311 php_pqtypes_object_handlers.read_dimension = php_pqtypes_object_read_dimension;
5312 php_pqtypes_object_handlers.unset_dimension = NULL;
5313 php_pqtypes_object_handlers.write_dimension = NULL;
5314
5315 zend_hash_init(&php_pqtypes_object_prophandlers, 1, NULL, NULL, 1);
5316
5317 zend_declare_property_null(php_pqtypes_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
5318 ph.read = php_pqtypes_object_read_connection;
5319 zend_hash_add(&php_pqtypes_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
5320
5321 memset(&ce, 0, sizeof(ce));
5322 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
5323 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5324 php_pqres_class_entry->create_object = php_pqres_create_object;
5325 php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs;
5326 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
5327 zend_class_implements(php_pqres_class_entry TSRMLS_CC, 2, zend_ce_traversable, spl_ce_Countable);
5328
5329 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5330 php_pqres_object_handlers.read_property = php_pq_object_read_prop;
5331 php_pqres_object_handlers.write_property = php_pq_object_write_prop;
5332 php_pqres_object_handlers.clone_obj = NULL;
5333 php_pqres_object_handlers.get_property_ptr_ptr = NULL;
5334 php_pqres_object_handlers.get_debug_info = php_pq_object_debug_info;
5335 php_pqres_object_handlers.count_elements = php_pqres_count_elements;
5336
5337 zend_hash_init(&php_pqres_object_prophandlers, 6, NULL, NULL, 1);
5338
5339 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
5340 ph.read = php_pqres_object_read_status;
5341 zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
5342
5343 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
5344 ph.read = php_pqres_object_read_status_message;
5345 zend_hash_add(&php_pqres_object_prophandlers, "statusMessage", sizeof("statusMessage"), (void *) &ph, sizeof(ph), NULL);
5346
5347 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
5348 ph.read = php_pqres_object_read_error_message;
5349 zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
5350
5351 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5352 ph.read = php_pqres_object_read_num_rows;
5353 zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL);
5354
5355 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5356 ph.read = php_pqres_object_read_num_cols;
5357 zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL);
5358
5359 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5360 ph.read = php_pqres_object_read_affected_rows;
5361 zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL);
5362
5363 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);
5364 ph.read = php_pqres_object_read_fetch_type;
5365 ph.write = php_pqres_object_write_fetch_type;
5366 zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL);
5367 ph.write = NULL;
5368
5369 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC);
5370 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC);
5371 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC);
5372 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC);
5373 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC);
5374 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC);
5375 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC);
5376 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC);
5377 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC);
5378 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC);
5379
5380 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC);
5381 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC);
5382 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
5383
5384 memset(&ce, 0, sizeof(ce));
5385 INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods);
5386 php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5387 php_pqstm_class_entry->create_object = php_pqstm_create_object;
5388
5389 memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5390 php_pqstm_object_handlers.read_property = php_pq_object_read_prop;
5391 php_pqstm_object_handlers.write_property = php_pq_object_write_prop;
5392 php_pqstm_object_handlers.clone_obj = NULL;
5393 php_pqstm_object_handlers.get_property_ptr_ptr = NULL;
5394 php_pqstm_object_handlers.get_debug_info = php_pq_object_debug_info;
5395
5396 zend_hash_init(&php_pqstm_object_prophandlers, 2, NULL, NULL, 1);
5397
5398 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
5399 ph.read = php_pqstm_object_read_name;
5400 zend_hash_add(&php_pqstm_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
5401
5402 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
5403 ph.read = php_pqstm_object_read_connection;
5404 zend_hash_add(&php_pqstm_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
5405
5406 memset(&ce, 0, sizeof(ce));
5407 INIT_NS_CLASS_ENTRY(ce, "pq", "Transaction", php_pqtxn_methods);
5408 php_pqtxn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5409 php_pqtxn_class_entry->create_object = php_pqtxn_create_object;
5410
5411 memcpy(&php_pqtxn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5412 php_pqtxn_object_handlers.read_property = php_pq_object_read_prop;
5413 php_pqtxn_object_handlers.write_property = php_pq_object_write_prop;
5414 php_pqtxn_object_handlers.clone_obj = NULL;
5415 php_pqtxn_object_handlers.get_property_ptr_ptr = NULL;
5416 php_pqtxn_object_handlers.get_debug_info = php_pq_object_debug_info;
5417
5418 zend_hash_init(&php_pqtxn_object_prophandlers, 4, NULL, NULL, 1);
5419
5420 zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
5421 ph.read = php_pqtxn_object_read_connection;
5422 zend_hash_add(&php_pqtxn_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
5423
5424 zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("isolation"), ZEND_ACC_PUBLIC TSRMLS_CC);
5425 ph.read = php_pqtxn_object_read_isolation;
5426 ph.write = php_pqtxn_object_write_isolation;
5427 zend_hash_add(&php_pqtxn_object_prophandlers, "isolation", sizeof("isolation"), (void *) &ph, sizeof(ph), NULL);
5428
5429 zend_declare_property_bool(php_pqtxn_class_entry, ZEND_STRL("readonly"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5430 ph.read = php_pqtxn_object_read_readonly;
5431 ph.write = php_pqtxn_object_write_readonly;
5432 zend_hash_add(&php_pqtxn_object_prophandlers, "readonly", sizeof("readonly"), (void *) &ph, sizeof(ph), NULL);
5433
5434 zend_declare_property_bool(php_pqtxn_class_entry, ZEND_STRL("deferrable"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
5435 ph.read = php_pqtxn_object_read_deferrable;
5436 ph.write = php_pqtxn_object_write_deferrable;
5437 zend_hash_add(&php_pqtxn_object_prophandlers, "deferrable", sizeof("deferrable"), (void *) &ph, sizeof(ph), NULL);
5438 ph.write = NULL;
5439
5440 zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED TSRMLS_CC);
5441 zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("REPEATABLE_READ"), PHP_PQTXN_REPEATABLE_READ TSRMLS_CC);
5442 zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE TSRMLS_CC);
5443
5444 memset(&ce, 0, sizeof(ce));
5445 INIT_NS_CLASS_ENTRY(ce, "pq", "Cancel", php_pqcancel_methods);
5446 php_pqcancel_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5447 php_pqcancel_class_entry->create_object = php_pqcancel_create_object;
5448
5449 memcpy(&php_pqcancel_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5450 php_pqcancel_object_handlers.read_property = php_pq_object_read_prop;
5451 php_pqcancel_object_handlers.write_property = php_pq_object_write_prop;
5452 php_pqcancel_object_handlers.clone_obj = NULL;
5453 php_pqcancel_object_handlers.get_property_ptr_ptr = NULL;
5454 php_pqcancel_object_handlers.get_debug_info = php_pq_object_debug_info;
5455
5456 zend_hash_init(&php_pqcancel_object_prophandlers, 1, NULL, NULL, 1);
5457
5458 zend_declare_property_null(php_pqcancel_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
5459 ph.read = php_pqcancel_object_read_connection;
5460 zend_hash_add(&php_pqcancel_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
5461
5462 memset(&ce, 0, sizeof(ce));
5463 INIT_NS_CLASS_ENTRY(ce, "pq", "Event", php_pqevent_methods);
5464 php_pqevent_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5465 php_pqevent_class_entry->create_object = php_pqevent_create_object;
5466
5467 memcpy(&php_pqevent_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5468 php_pqevent_object_handlers.read_property = php_pq_object_read_prop;
5469 php_pqevent_object_handlers.write_property = php_pq_object_write_prop;
5470 php_pqevent_object_handlers.clone_obj = NULL;
5471 php_pqevent_object_handlers.get_property_ptr_ptr = NULL;
5472 php_pqevent_object_handlers.get_debug_info = php_pq_object_debug_info;
5473
5474 zend_hash_init(&php_pqevent_object_prophandlers, 1, NULL, NULL, 1);
5475
5476 zend_declare_property_null(php_pqevent_class_entry, ZEND_STRL("type"), ZEND_ACC_PUBLIC TSRMLS_CC);
5477 ph.read = php_pqevent_object_read_type;
5478 zend_hash_add(&php_pqevent_object_prophandlers, "type", sizeof("type"), (void *) &ph, sizeof(ph), NULL);
5479
5480 zend_declare_class_constant_stringl(php_pqevent_class_entry, ZEND_STRL("NOTICE"), ZEND_STRL("notice") TSRMLS_CC);
5481 zend_declare_class_constant_stringl(php_pqevent_class_entry, ZEND_STRL("RESULT"), ZEND_STRL("result") TSRMLS_CC);
5482 zend_declare_class_constant_stringl(php_pqevent_class_entry, ZEND_STRL("RESET"), ZEND_STRL("reset") TSRMLS_CC);
5483
5484 memset(&ce, 0, sizeof(ce));
5485 INIT_NS_CLASS_ENTRY(ce, "pq", "LOB", php_pqlob_methods);
5486 php_pqlob_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5487 php_pqlob_class_entry->create_object = php_pqlob_create_object;
5488
5489 memcpy(&php_pqlob_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5490 php_pqlob_object_handlers.read_property = php_pq_object_read_prop;
5491 php_pqlob_object_handlers.write_property = php_pq_object_write_prop;
5492 php_pqlob_object_handlers.clone_obj = NULL;
5493 php_pqlob_object_handlers.get_property_ptr_ptr = NULL;
5494 php_pqlob_object_handlers.get_debug_info = php_pq_object_debug_info;
5495
5496 zend_hash_init(&php_pqlob_object_prophandlers, 2, NULL, NULL, 1);
5497
5498 zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC TSRMLS_CC);
5499 ph.read = php_pqlob_object_read_transaction;
5500 zend_hash_add(&php_pqlob_object_prophandlers, "transaction", sizeof("transaction"), (void *) &ph, sizeof(ph), NULL);
5501
5502 zend_declare_property_long(php_pqlob_class_entry, ZEND_STRL("oid"), InvalidOid, ZEND_ACC_PUBLIC TSRMLS_CC);
5503 ph.read = php_pqlob_object_read_oid;
5504 zend_hash_add(&php_pqlob_object_prophandlers, "oid", sizeof("oid"), (void *) &ph, sizeof(ph), NULL);
5505
5506 zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("INVALID_OID"), InvalidOid TSRMLS_CC);
5507 zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("R"), INV_READ TSRMLS_CC);
5508 zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("W"), INV_WRITE TSRMLS_CC);
5509 zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("RW"), INV_READ|INV_WRITE TSRMLS_CC);
5510
5511 memset(&ce, 0, sizeof(ce));
5512 INIT_NS_CLASS_ENTRY(ce, "pq", "COPY", php_pqcopy_methods);
5513 php_pqcopy_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
5514 php_pqcopy_class_entry->create_object = php_pqcopy_create_object;
5515
5516 memcpy(&php_pqcopy_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5517 php_pqcopy_object_handlers.read_property = php_pq_object_read_prop;
5518 php_pqcopy_object_handlers.write_property = php_pq_object_write_prop;
5519 php_pqcopy_object_handlers.clone_obj = NULL;
5520 php_pqcopy_object_handlers.get_property_ptr_ptr = NULL;
5521 php_pqcopy_object_handlers.get_debug_info = php_pq_object_debug_info;
5522
5523 zend_hash_init(&php_pqcopy_object_prophandlers, 4, NULL, NULL, 1);
5524
5525 zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
5526 ph.read = php_pqcopy_object_read_connection;
5527 zend_hash_add(&php_pqcopy_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
5528
5529 zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("expression"), ZEND_ACC_PUBLIC TSRMLS_CC);
5530 ph.read = php_pqcopy_object_read_expression;
5531 zend_hash_add(&php_pqcopy_object_prophandlers, "expression", sizeof("expression"), (void *) &ph, sizeof(ph), NULL);
5532
5533 zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("direction"), ZEND_ACC_PUBLIC TSRMLS_CC);
5534 ph.read = php_pqcopy_object_read_direction;
5535 zend_hash_add(&php_pqcopy_object_prophandlers, "direction", sizeof("direction"), (void *) &ph, sizeof(ph), NULL);
5536
5537 zend_declare_property_null(php_pqcopy_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC TSRMLS_CC);
5538 ph.read = php_pqcopy_object_read_options;
5539 zend_hash_add(&php_pqcopy_object_prophandlers, "options", sizeof("options"), (void *) &ph, sizeof(ph), NULL);
5540
5541 zend_declare_class_constant_long(php_pqcopy_class_entry, ZEND_STRL("FROM_STDIN"), PHP_PQCOPY_FROM_STDIN TSRMLS_CC);
5542 zend_declare_class_constant_long(php_pqcopy_class_entry, ZEND_STRL("TO_STDOUT"), PHP_PQCOPY_TO_STDOUT TSRMLS_CC);
5543
5544 php_persistent_handle_provide(ZEND_STRL("pq\\Connection"), &php_pqconn_resource_factory_ops, NULL, NULL TSRMLS_CC);
5545
5546 /*
5547 REGISTER_INI_ENTRIES();
5548 */
5549 return SUCCESS;
5550 }
5551 /* }}} */
5552
5553 /* {{{ PHP_MSHUTDOWN_FUNCTION
5554 */
5555 static PHP_MSHUTDOWN_FUNCTION(pq)
5556 {
5557 /* uncomment this line if you have INI entries
5558 UNREGISTER_INI_ENTRIES();
5559 */
5560 php_persistent_handle_cleanup(ZEND_STRL("pq\\Connection"), NULL, 0 TSRMLS_CC);
5561 return SUCCESS;
5562 }
5563 /* }}} */
5564
5565 /* {{{ PHP_MINFO_FUNCTION
5566 */
5567 static PHP_MINFO_FUNCTION(pq)
5568 {
5569 #ifdef HAVE_PQLIBVERSION
5570 int libpq_v;
5571 #endif
5572 char libpq_version[10] = "pre-9.1";
5573
5574 php_info_print_table_start();
5575 php_info_print_table_header(2, "PQ Support", "enabled");
5576 php_info_print_table_row(2, "Extension Version", PHP_PQ_EXT_VERSION);
5577 php_info_print_table_end();
5578
5579 php_info_print_table_start();
5580 php_info_print_table_header(2, "Used Library", "Version");
5581 #ifdef HAVE_PQLIBVERSION
5582 libpq_v = PQlibVersion();
5583 slprintf(libpq_version, sizeof(libpq_version), "%d.%d.%d", libpq_v/10000%100, libpq_v/100%100, libpq_v%100);
5584 #endif
5585 php_info_print_table_row(2, "libpq", libpq_version);
5586 php_info_print_table_end();
5587
5588 /* Remove comments if you have entries in php.ini
5589 DISPLAY_INI_ENTRIES();
5590 */
5591 }
5592 /* }}} */
5593
5594 const zend_function_entry pq_functions[] = {
5595 {0}
5596 };
5597
5598 static zend_module_dep pq_module_deps[] = {
5599 ZEND_MOD_REQUIRED("raphf")
5600 ZEND_MOD_REQUIRED("spl")
5601 ZEND_MOD_END
5602 };
5603
5604 /* {{{ pq_module_entry
5605 */
5606 zend_module_entry pq_module_entry = {
5607 STANDARD_MODULE_HEADER_EX,
5608 NULL,
5609 pq_module_deps,
5610 "pq",
5611 pq_functions,
5612 PHP_MINIT(pq),
5613 PHP_MSHUTDOWN(pq),
5614 NULL,/*PHP_RINIT(pq),*/
5615 NULL,/*PHP_RSHUTDOWN(pq),*/
5616 PHP_MINFO(pq),
5617 PHP_PQ_EXT_VERSION,
5618 STANDARD_MODULE_PROPERTIES
5619 };
5620 /* }}} */
5621
5622 #ifdef COMPILE_DL_PQ
5623 ZEND_GET_MODULE(pq)
5624 #endif
5625
5626
5627 /*
5628 * Local variables:
5629 * tab-width: 4
5630 * c-basic-offset: 4
5631 * End:
5632 * vim600: noet sw=4 ts=4 fdm=marker
5633 * vim<600: noet sw=4 ts=4
5634 */