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