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