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