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