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