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