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