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