44a253d758a1bcbc2701527c769fabcf6af31c69
[m6w6/ext-pq] / src / php_pq.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: pq |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <php.h>
18 #include <Zend/zend_interfaces.h>
19 #include <ext/standard/info.h>
20 #include <ext/spl/spl_array.h>
21
22 #include <libpq-events.h>
23 #include <fnmatch.h>
24
25 #include "php_pq.h"
26
27 typedef int STATUS; /* SUCCESS/FAILURE */
28
29 /*
30 ZEND_DECLARE_MODULE_GLOBALS(pq)
31 */
32
33
34 /* {{{ PHP_INI
35 */
36 /* Remove comments and fill if you need to have entries in php.ini
37 PHP_INI_BEGIN()
38 STD_PHP_INI_ENTRY("pq.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_pq_globals, pq_globals)
39 STD_PHP_INI_ENTRY("pq.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_pq_globals, pq_globals)
40 PHP_INI_END()
41 */
42 /* }}} */
43
44 /* {{{ php_pq_init_globals
45 */
46 /* Uncomment this function if you have INI entries
47 static void php_pq_init_globals(zend_pq_globals *pq_globals)
48 {
49 pq_globals->global_value = 0;
50 pq_globals->global_string = NULL;
51 }
52 */
53 /* }}} */
54
55 static zend_class_entry *php_pqconn_class_entry;
56 static zend_class_entry *php_pqres_class_entry;
57 static zend_class_entry *php_pqstm_class_entry;
58 static zend_class_entry *php_pqtxn_class_entry;
59 static zend_class_entry *php_pqcancel_class_entry;
60 static zend_class_entry *php_pqevent_class_entry;
61
62 static zend_object_handlers php_pqconn_object_handlers;
63 static zend_object_handlers php_pqres_object_handlers;
64 static zend_object_handlers php_pqstm_object_handlers;
65 static zend_object_handlers php_pqtxn_object_handlers;
66 static zend_object_handlers php_pqcancel_object_handlers;
67 static zend_object_handlers php_pqevent_object_handlers;
68
69 typedef struct php_pq_callback {
70 zend_fcall_info fci;
71 zend_fcall_info_cache fcc;
72 void *data;
73 } php_pq_callback_t;
74
75 typedef struct php_pq_object {
76 zend_object zo;
77 zend_object_value zv;
78 HashTable *prophandler;
79 void *intern;
80 } php_pq_object_t;
81
82 typedef struct php_pqconn {
83 PGconn *conn;
84 int (*poller)(PGconn *);
85 HashTable listeners;
86 HashTable eventhandlers;
87 php_pq_callback_t onevent;
88 unsigned unbuffered:1;
89 } php_pqconn_t;
90
91 typedef struct php_pqconn_object {
92 zend_object zo;
93 zend_object_value zv;
94 HashTable *prophandler;
95 php_pqconn_t *intern;
96 } php_pqconn_object_t;
97
98 typedef struct php_pqconn_event_data {
99 php_pqconn_object_t *obj;
100 #ifdef ZTS
101 void ***ts;
102 #endif
103 } php_pqconn_event_data_t;
104
105 typedef enum php_pqres_fetch {
106 PHP_PQRES_FETCH_ARRAY,
107 PHP_PQRES_FETCH_ASSOC,
108 PHP_PQRES_FETCH_OBJECT
109 } php_pqres_fetch_t;
110
111 typedef struct php_pqres_iterator {
112 zend_object_iterator zi;
113 zval *current_val;
114 unsigned index;
115 php_pqres_fetch_t fetch_type;
116 } php_pqres_iterator_t;
117
118 typedef struct php_pqres {
119 PGresult *res;
120 php_pqres_iterator_t *iter;
121 } php_pqres_t;
122
123 typedef struct php_pqres_object {
124 zend_object zo;
125 zend_object_value zv;
126 HashTable *prophandler;
127 php_pqres_t *intern;
128 } php_pqres_object_t;
129
130 typedef struct php_pqstm {
131 php_pqconn_object_t *conn;
132 char *name;
133 } php_pqstm_t;
134
135 typedef struct php_pqstm_object {
136 zend_object zo;
137 zend_object_value zv;
138 HashTable *prophandler;
139 php_pqstm_t *intern;
140 } php_pqstm_object_t;
141
142 typedef enum php_pqtxn_isolation {
143 PHP_PQTXN_READ_COMMITTED,
144 PHP_PQTXN_REPEATABLE_READ,
145 PHP_PQTXN_SERIALIZABLE,
146 } php_pqtxn_isolation_t;
147
148 typedef struct php_pqtxn {
149 php_pqconn_object_t *conn;
150 php_pqtxn_isolation_t isolation;
151 unsigned readonly:1;
152 unsigned deferrable:1;
153 } php_pqtxn_t;
154
155 typedef struct php_pqtxn_object {
156 zend_object zo;
157 zend_object_value zv;
158 HashTable *prophandler;
159 php_pqtxn_t *intern;
160 } php_pqtxn_object_t;
161
162 typedef struct php_pqcancel {
163 PGcancel *cancel;
164 php_pqconn_object_t *conn;
165 } php_pqcancel_t;
166
167 typedef struct php_pqcancel_object {
168 zend_object zo;
169 zend_object_value zv;
170 HashTable *prophandler;
171 php_pqcancel_t *intern;
172 } php_pqcancel_object_t;
173
174 typedef struct php_pqevent {
175 php_pq_callback_t cb;
176 php_pqconn_object_t *conn;
177 char *type;
178 } php_pqevent_t;
179
180 typedef struct php_pqevent_object {
181 zend_object zo;
182 zend_object_value zv;
183 HashTable *prophandler;
184 php_pqevent_t *intern;
185 } php_pqevent_object_t;
186
187 static HashTable php_pqconn_object_prophandlers;
188 static HashTable php_pqres_object_prophandlers;
189 static HashTable php_pqstm_object_prophandlers;
190 static HashTable php_pqtxn_object_prophandlers;
191 static HashTable php_pqcancel_object_prophandlers;
192 static HashTable php_pqevent_object_prophandlers;
193
194 typedef void (*php_pq_object_prophandler_func_t)(zval *object, void *o, zval *return_value TSRMLS_DC);
195
196 typedef struct php_pq_object_prophandler {
197 php_pq_object_prophandler_func_t read;
198 php_pq_object_prophandler_func_t write;
199 } php_pq_object_prophandler_t;
200
201 static zend_object_iterator_funcs php_pqres_iterator_funcs;
202
203 static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
204 {
205 php_pqres_iterator_t *iter;
206 zval *prop, *zfetch_type;
207
208 iter = ecalloc(1, sizeof(*iter));
209 iter->zi.funcs = &php_pqres_iterator_funcs;
210 iter->zi.data = object;
211 Z_ADDREF_P(object);
212
213 zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC);
214 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
215 convert_to_long_ex(&zfetch_type);
216 }
217 iter->fetch_type = Z_LVAL_P(zfetch_type);
218 if (zfetch_type != prop) {
219 zval_ptr_dtor(&zfetch_type);
220 }
221 if (Z_REFCOUNT_P(prop)) {
222 zval_ptr_dtor(&prop);
223 } else {
224 zval_dtor(prop);
225 FREE_ZVAL(prop);
226 }
227
228 return (zend_object_iterator *) iter;
229 }
230
231 static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
232 {
233 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
234
235 if (iter->current_val) {
236 zval_ptr_dtor(&iter->current_val);
237 iter->current_val = NULL;
238 }
239 zval_ptr_dtor((zval **) &iter->zi.data);
240 efree(iter);
241 }
242
243 static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC)
244 {
245 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
246 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
247
248 if (PQresultStatus(obj->intern->res) != PGRES_TUPLES_OK) {
249 return FAILURE;
250 }
251 if (PQntuples(obj->intern->res) <= iter->index) {
252 return FAILURE;
253 }
254
255 return SUCCESS;
256 }
257
258 static zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type TSRMLS_DC)
259 {
260 zval *data;
261 int c, cols;
262
263 MAKE_STD_ZVAL(data);
264 if (PHP_PQRES_FETCH_OBJECT == fetch_type) {
265 object_init(data);
266 } else {
267 array_init(data);
268 }
269
270 for (c = 0, cols = PQnfields(res); c < cols; ++c) {
271 if (PQgetisnull(res, row, c)) {
272 switch (fetch_type) {
273 case PHP_PQRES_FETCH_OBJECT:
274 add_property_null(data, PQfname(res, c));
275 break;
276
277 case PHP_PQRES_FETCH_ASSOC:
278 add_assoc_null(data, PQfname(res, c));
279 break;
280
281 case PHP_PQRES_FETCH_ARRAY:
282 add_index_null(data, c);
283 break;
284 }
285 } else {
286 char *val = PQgetvalue(res, row, c);
287 int len = PQgetlength(res, row, c);
288
289 switch (fetch_type) {
290 case PHP_PQRES_FETCH_OBJECT:
291 add_property_stringl(data, PQfname(res, c), val, len, 1);
292 break;
293
294 case PHP_PQRES_FETCH_ASSOC:
295 add_assoc_stringl(data, PQfname(res, c), val, len, 1);
296 break;
297
298 case PHP_PQRES_FETCH_ARRAY:
299 add_index_stringl(data, c, val, len ,1);
300 break;
301 }
302 }
303 }
304
305 return data;
306 }
307
308 static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr TSRMLS_DC)
309 {
310 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
311 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
312
313 if (iter->current_val) {
314 zval_ptr_dtor(&iter->current_val);
315 }
316 iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type TSRMLS_CC);
317 *data_ptr = &iter->current_val;
318 }
319
320 static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint *key_len, ulong *key_num TSRMLS_DC)
321 {
322 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
323
324 *key_num = (ulong) iter->index;
325
326 return HASH_KEY_IS_LONG;
327 }
328
329 static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC)
330 {
331 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
332
333 ++iter->index;
334 }
335
336 static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC)
337 {
338 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
339
340 iter->index = 0;
341 }
342
343 static zend_object_iterator_funcs php_pqres_iterator_funcs = {
344 php_pqres_iterator_dtor,
345 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
346 php_pqres_iterator_valid,
347 /* fetch the item data for the current element */
348 php_pqres_iterator_current,
349 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
350 php_pqres_iterator_key,
351 /* step forwards to next element */
352 php_pqres_iterator_next,
353 /* rewind to start of data (optional, may be NULL) */
354 php_pqres_iterator_rewind,
355 /* invalidate current value/key (optional, may be NULL) */
356 NULL
357 };
358
359 static STATUS php_pqres_success(PGresult *res TSRMLS_DC)
360 {
361 switch (PQresultStatus(res)) {
362 case PGRES_BAD_RESPONSE:
363 case PGRES_NONFATAL_ERROR:
364 case PGRES_FATAL_ERROR:
365 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(res));
366 return FAILURE;
367 default:
368 return SUCCESS;
369 }
370 }
371
372 static void php_pq_callback_dtor(php_pq_callback_t *cb) {
373 if (cb->fci.size > 0) {
374 zend_fcall_info_args_clear(&cb->fci, 1);
375 zval_ptr_dtor(&cb->fci.function_name);
376 if (cb->fci.object_ptr) {
377 zval_ptr_dtor(&cb->fci.object_ptr);
378 }
379 }
380 cb->fci.size = 0;
381 }
382
383 static void php_pq_callback_addref(php_pq_callback_t *cb)
384 {
385 Z_ADDREF_P(cb->fci.function_name);
386 if (cb->fci.object_ptr) {
387 Z_ADDREF_P(cb->fci.object_ptr);
388 }
389 }
390
391 static void php_pq_object_to_zval(void *o, zval **zv TSRMLS_DC)
392 {
393 php_pq_object_t *obj = o;
394
395 if (!*zv) {
396 MAKE_STD_ZVAL(*zv);
397 }
398
399 zend_objects_store_add_ref_by_handle(obj->zv.handle TSRMLS_CC);
400
401 (*zv)->type = IS_OBJECT;
402 (*zv)->value.obj = obj->zv;
403 }
404
405 static void php_pq_object_addref(void *o TSRMLS_DC)
406 {
407 php_pq_object_t *obj = o;
408 zend_objects_store_add_ref_by_handle(obj->zv.handle TSRMLS_CC);
409 }
410
411 static void php_pq_object_delref(void *o TSRMLS_DC)
412 {
413 php_pq_object_t *obj = o;
414 zend_objects_store_del_ref_by_handle_ex(obj->zv.handle, obj->zv.handlers TSRMLS_CC);
415 }
416
417 static void php_pqconn_object_free(void *o TSRMLS_DC)
418 {
419 php_pqconn_object_t *obj = o;
420
421 if (obj->intern) {
422 PQfinish(obj->intern->conn);
423 php_pq_callback_dtor(&obj->intern->onevent);
424 zend_hash_destroy(&obj->intern->listeners);
425 zend_hash_destroy(&obj->intern->eventhandlers);
426 efree(obj->intern);
427 obj->intern = NULL;
428 }
429 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
430 efree(obj);
431 }
432
433 static int php_pqconn_event(PGEventId id, void *e, void *data);
434
435 static void php_pqres_object_free(void *o TSRMLS_DC)
436 {
437 php_pqres_object_t *obj = o;
438
439 if (obj->intern) {
440 if (obj->intern->res) {
441 zval *res = PQresultInstanceData(obj->intern->res, php_pqconn_event);
442 if (res) {
443 PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL);
444 zval_ptr_dtor(&res);
445 } else {
446 PQclear(obj->intern->res);
447 obj->intern->res = NULL;
448 }
449 }
450
451 if (obj->intern->iter) {
452 php_pqres_iterator_dtor((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
453 obj->intern->iter = NULL;
454 }
455
456 efree(obj->intern);
457 obj->intern = NULL;
458 }
459 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
460 efree(obj);
461 }
462
463 static void php_pqstm_object_free(void *o TSRMLS_DC)
464 {
465 php_pqstm_object_t *obj = o;
466
467 if (obj->intern) {
468 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
469 efree(obj->intern->name);
470 efree(obj->intern);
471 obj->intern = NULL;
472 }
473 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
474 efree(obj);
475 }
476
477 static void php_pqtxn_object_free(void *o TSRMLS_DC)
478 {
479 php_pqtxn_object_t *obj = o;
480
481 if (obj->intern) {
482 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
483 efree(obj->intern);
484 obj->intern = NULL;
485 }
486 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
487 efree(obj);
488 }
489
490 static void php_pqcancel_object_free(void *o TSRMLS_DC)
491 {
492 php_pqcancel_object_t *obj = o;
493
494 if (obj->intern) {
495 PQfreeCancel(obj->intern->cancel);
496 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
497 efree(obj->intern);
498 obj->intern = NULL;
499 }
500 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
501 efree(obj);
502 }
503
504 static void php_pqevent_object_free(void *o TSRMLS_DC)
505 {
506 php_pqevent_object_t *obj = o;
507
508 if (obj->intern) {
509 php_pq_callback_dtor(&obj->intern->cb);
510 php_pq_object_delref(obj->intern->conn TSRMLS_CC);
511 efree(obj->intern->type);
512 efree(obj->intern);
513 obj->intern = NULL;
514 }
515 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
516 efree(obj);
517 }
518
519
520 static zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern, php_pqconn_object_t **ptr TSRMLS_DC)
521 {
522 php_pqconn_object_t *o;
523
524 o = ecalloc(1, sizeof(*o));
525 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
526 object_properties_init((zend_object *) o, ce);
527 o->prophandler = &php_pqconn_object_prophandlers;
528
529 if (ptr) {
530 *ptr = o;
531 }
532
533 if (intern) {
534 o->intern = intern;
535 }
536
537 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqconn_object_free, NULL TSRMLS_CC);
538 o->zv.handlers = &php_pqconn_object_handlers;
539
540 return o->zv;
541 }
542
543 static zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern, php_pqres_object_t **ptr TSRMLS_DC)
544 {
545 php_pqres_object_t *o;
546
547 o = ecalloc(1, sizeof(*o));
548 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
549 object_properties_init((zend_object *) o, ce);
550 o->prophandler = &php_pqres_object_prophandlers;
551
552 if (ptr) {
553 *ptr = o;
554 }
555
556 if (intern) {
557 o->intern = intern;
558 }
559
560 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqres_object_free, NULL TSRMLS_CC);
561 o->zv.handlers = &php_pqres_object_handlers;
562
563 return o->zv;
564 }
565
566 static zend_object_value php_pqstm_create_object_ex(zend_class_entry *ce, php_pqstm_t *intern, php_pqstm_object_t **ptr TSRMLS_DC)
567 {
568 php_pqstm_object_t *o;
569
570 o = ecalloc(1, sizeof(*o));
571 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
572 object_properties_init((zend_object *) o, ce);
573 o->prophandler = &php_pqstm_object_prophandlers;
574
575 if (ptr) {
576 *ptr = o;
577 }
578
579 if (intern) {
580 o->intern = intern;
581 }
582
583 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqstm_object_free, NULL TSRMLS_CC);
584 o->zv.handlers = &php_pqstm_object_handlers;
585
586 return o->zv;
587 }
588
589 static zend_object_value php_pqtxn_create_object_ex(zend_class_entry *ce, php_pqtxn_t *intern, php_pqtxn_object_t **ptr TSRMLS_DC)
590 {
591 php_pqtxn_object_t *o;
592
593 o = ecalloc(1, sizeof(*o));
594 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
595 object_properties_init((zend_object *) o, ce);
596 o->prophandler = &php_pqtxn_object_prophandlers;
597
598 if (ptr) {
599 *ptr = o;
600 }
601
602 if (intern) {
603 o->intern = intern;
604 }
605
606 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqtxn_object_free, NULL TSRMLS_CC);
607 o->zv.handlers = &php_pqtxn_object_handlers;
608
609 return o->zv;
610 }
611
612 static zend_object_value php_pqcancel_create_object_ex(zend_class_entry *ce, php_pqcancel_t *intern, php_pqcancel_object_t **ptr TSRMLS_DC)
613 {
614 php_pqcancel_object_t *o;
615
616 o = ecalloc(1, sizeof(*o));
617 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
618 object_properties_init((zend_object *) o, ce);
619 o->prophandler = &php_pqcancel_object_prophandlers;
620
621 if (ptr) {
622 *ptr = o;
623 }
624
625 if (intern) {
626 o->intern = intern;
627 }
628
629 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqcancel_object_free, NULL TSRMLS_CC);
630 o->zv.handlers = &php_pqcancel_object_handlers;
631
632 return o->zv;
633 }
634
635 static zend_object_value php_pqevent_create_object_ex(zend_class_entry *ce, php_pqevent_t *intern, php_pqevent_object_t **ptr TSRMLS_DC)
636 {
637 php_pqevent_object_t *o;
638
639 o = ecalloc(1, sizeof(*o));
640 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
641 object_properties_init((zend_object *) o, ce);
642 o->prophandler = &php_pqevent_object_prophandlers;
643
644 if (ptr) {
645 *ptr = o;
646 }
647
648 if (intern) {
649 o->intern = intern;
650 }
651
652 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqevent_object_free, NULL TSRMLS_CC);
653 o->zv.handlers = &php_pqevent_object_handlers;
654
655 return o->zv;
656 }
657
658 static zend_object_value php_pqconn_create_object(zend_class_entry *class_type TSRMLS_DC)
659 {
660 return php_pqconn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
661 }
662
663 static zend_object_value php_pqres_create_object(zend_class_entry *class_type TSRMLS_DC)
664 {
665 return php_pqres_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
666 }
667
668 static zend_object_value php_pqstm_create_object(zend_class_entry *class_type TSRMLS_DC)
669 {
670 return php_pqstm_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
671 }
672
673 static zend_object_value php_pqtxn_create_object(zend_class_entry *class_type TSRMLS_DC)
674 {
675 return php_pqtxn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
676 }
677
678 static zend_object_value php_pqcancel_create_object(zend_class_entry *class_type TSRMLS_DC)
679 {
680 return php_pqcancel_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
681 }
682
683 static zend_object_value php_pqevent_create_object(zend_class_entry *class_type TSRMLS_DC)
684 {
685 return php_pqevent_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
686 }
687
688 static int apply_ph_to_debug(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
689 {
690 php_pq_object_prophandler_t *ph = p;
691 HashTable *ht = va_arg(argv, HashTable *);
692 zval **return_value, *object = va_arg(argv, zval *);
693 php_pq_object_t *obj = va_arg(argv, php_pq_object_t *);
694
695 if (SUCCESS == zend_hash_find(ht, key->arKey, key->nKeyLength, (void *) &return_value)) {
696
697 if (ph->read) {
698 zval_ptr_dtor(return_value);
699 MAKE_STD_ZVAL(*return_value);
700 ZVAL_NULL(*return_value);
701
702 ph->read(object, obj, *return_value TSRMLS_CC);
703 }
704 }
705
706 return ZEND_HASH_APPLY_KEEP;
707 }
708
709 static int apply_pi_to_debug(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
710 {
711 zend_property_info *pi = p;
712 HashTable *ht = va_arg(argv, HashTable *);
713 zval *object = va_arg(argv, zval *);
714 php_pq_object_t *obj = va_arg(argv, php_pq_object_t *);
715 zval *property = zend_read_property(obj->zo.ce, object, pi->name, pi->name_length, 0 TSRMLS_CC);
716
717 if (!Z_REFCOUNT_P(property)) {
718 Z_ADDREF_P(property);
719 }
720 zend_hash_add(ht, pi->name, pi->name_length + 1, (void *) &property, sizeof(zval *), NULL);
721
722 return ZEND_HASH_APPLY_KEEP;
723 }
724
725 static HashTable *php_pq_object_debug_info(zval *object, int *temp TSRMLS_DC)
726 {
727 HashTable *ht;
728 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
729
730 *temp = 1;
731 ALLOC_HASHTABLE(ht);
732 ZEND_INIT_SYMTABLE(ht);
733
734 zend_hash_apply_with_arguments(&obj->zo.ce->properties_info TSRMLS_CC, apply_pi_to_debug, 3, ht, object, obj);
735 zend_hash_apply_with_arguments(obj->prophandler TSRMLS_CC, apply_ph_to_debug, 3, ht, object, obj);
736
737 return ht;
738 }
739
740 static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
741 {
742 php_pqconn_object_t *obj = o;
743
744 RETVAL_LONG(PQstatus(obj->intern->conn));
745 }
746
747 static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value TSRMLS_DC)
748 {
749 php_pqconn_object_t *obj = o;
750
751 RETVAL_LONG(PQtransactionStatus(obj->intern->conn));
752 }
753
754 static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
755 {
756 php_pqconn_object_t *obj = o;
757 char *error = PQerrorMessage(obj->intern->conn);
758
759 if (error) {
760 RETVAL_STRING(error, 1);
761 } else {
762 RETVAL_NULL();
763 }
764 }
765
766 static int apply_notify_listener(void *p, void *arg TSRMLS_DC)
767 {
768 php_pq_callback_t *listener = p;
769 PGnotify *nfy = arg;
770 zval *zpid, *zchannel, *zmessage;
771
772 MAKE_STD_ZVAL(zpid);
773 ZVAL_LONG(zpid, nfy->be_pid);
774 MAKE_STD_ZVAL(zchannel);
775 ZVAL_STRING(zchannel, nfy->relname, 1);
776 MAKE_STD_ZVAL(zmessage);
777 ZVAL_STRING(zmessage, nfy->extra, 1);
778
779 zend_fcall_info_argn(&listener->fci TSRMLS_CC, 3, &zchannel, &zmessage, &zpid);
780 zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL TSRMLS_CC);
781
782 zval_ptr_dtor(&zchannel);
783 zval_ptr_dtor(&zmessage);
784 zval_ptr_dtor(&zpid);
785
786 return ZEND_HASH_APPLY_KEEP;
787 }
788
789 static int apply_notify_listeners(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
790 {
791 HashTable *listeners = p;
792 PGnotify *nfy = va_arg(argv, PGnotify *);
793
794 if (0 == fnmatch(key->arKey, nfy->relname, 0)) {
795 zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy TSRMLS_CC);
796 }
797
798 return ZEND_HASH_APPLY_KEEP;
799 }
800
801 static void php_pqconn_notify_listeners(php_pqconn_object_t *obj TSRMLS_DC)
802 {
803 PGnotify *nfy;
804
805 while ((nfy = PQnotifies(obj->intern->conn))) {
806 zend_hash_apply_with_arguments(&obj->intern->listeners TSRMLS_CC, apply_notify_listeners, 1, nfy);
807 PQfreemem(nfy);
808 }
809 }
810
811 /* FIXME: extend to types->nspname->typname */
812 #define PHP_PQ_TYPES_QUERY \
813 "select t.oid, t.* " \
814 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
815 "where typisdefined " \
816 "and typrelid=0 " \
817 "and nspname in ('public', 'pg_catalog')"
818 static void php_pqconn_object_read_types(zval *object, void *o, zval *return_value TSRMLS_DC)
819 {
820 php_pqconn_object_t *obj = o;
821 PGresult *res = PQexec(obj->intern->conn, PHP_PQ_TYPES_QUERY);
822
823 php_pqconn_notify_listeners(obj TSRMLS_CC);
824
825 /* FIXME: cache that */
826 if (res) {
827 if (PGRES_TUPLES_OK == PQresultStatus(res)) {
828 int r, rows;
829 zval *byoid, *byname;
830
831 MAKE_STD_ZVAL(byoid);
832 MAKE_STD_ZVAL(byname);
833 object_init(byoid);
834 object_init(byname);
835 object_init(return_value);
836 for (r = 0, rows = PQntuples(res); r < rows; ++r) {
837 zval *row = php_pqres_row_to_zval(res, r, PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
838
839 add_property_zval(byoid, PQgetvalue(res, r, 0), row);
840 add_property_zval(byname, PQgetvalue(res, r, 1), row);
841 zval_ptr_dtor(&row);
842 }
843
844 add_property_zval(return_value, "byOid", byoid);
845 add_property_zval(return_value, "byName", byname);
846 zval_ptr_dtor(&byoid);
847 zval_ptr_dtor(&byname);
848 } else {
849 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types: %s", PQresultErrorMessage(res));
850 }
851 PQclear(res);
852 } else {
853 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types: %s", PQerrorMessage(obj->intern->conn));
854 }
855 }
856
857 static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value TSRMLS_DC)
858 {
859 php_pqconn_object_t *obj = o;
860
861 RETVAL_BOOL(PQisBusy(obj->intern->conn));
862 }
863
864 static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value TSRMLS_DC)
865 {
866 php_pqconn_object_t *obj = o;
867
868 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn)), 1);
869 }
870
871 static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value TSRMLS_DC)
872 {
873 php_pqconn_object_t *obj = o;
874 zval *zenc = value;
875
876 if (Z_TYPE_P(value) != IS_STRING) {
877 convert_to_string_ex(&zenc);
878 }
879
880 if (0 > PQsetClientEncoding(obj->intern->conn, Z_STRVAL_P(zenc))) {
881 zend_error(E_NOTICE, "Unrecognized encoding '%s'", Z_STRVAL_P(zenc));
882 }
883
884 if (zenc != value) {
885 zval_ptr_dtor(&zenc);
886 }
887 }
888
889 static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value TSRMLS_DC)
890 {
891 php_pqconn_object_t *obj = o;
892
893 RETVAL_BOOL(obj->intern->unbuffered);
894 }
895
896 static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value TSRMLS_DC)
897 {
898 php_pqconn_object_t *obj = o;
899
900 obj->intern->unbuffered = zend_is_true(value);
901 }
902
903 static void php_pqconn_object_read_db(zval *objec, void *o, zval *return_value TSRMLS_DC)
904 {
905 php_pqconn_object_t *obj = o;
906 char *db = PQdb(obj->intern->conn);
907
908 if (db) {
909 RETVAL_STRING(db, 1);
910 } else {
911 RETVAL_EMPTY_STRING();
912 }
913 }
914
915 static void php_pqconn_object_read_user(zval *objec, void *o, zval *return_value TSRMLS_DC)
916 {
917 php_pqconn_object_t *obj = o;
918 char *user = PQuser(obj->intern->conn);
919
920 if (user) {
921 RETVAL_STRING(user, 1);
922 } else {
923 RETVAL_EMPTY_STRING();
924 }
925 }
926
927 static void php_pqconn_object_read_pass(zval *objec, void *o, zval *return_value TSRMLS_DC)
928 {
929 php_pqconn_object_t *obj = o;
930 char *pass = PQpass(obj->intern->conn);
931
932 if (pass) {
933 RETVAL_STRING(pass, 1);
934 } else {
935 RETVAL_EMPTY_STRING();
936 }
937 }
938
939 static void php_pqconn_object_read_host(zval *objec, void *o, zval *return_value TSRMLS_DC)
940 {
941 php_pqconn_object_t *obj = o;
942 char *host = PQhost(obj->intern->conn);
943
944 if (host) {
945 RETVAL_STRING(host, 1);
946 } else {
947 RETVAL_EMPTY_STRING();
948 }
949 }
950
951 static void php_pqconn_object_read_port(zval *objec, void *o, zval *return_value TSRMLS_DC)
952 {
953 php_pqconn_object_t *obj = o;
954 char *port = PQport(obj->intern->conn);
955
956 if (port) {
957 RETVAL_STRING(port, 1);
958 } else {
959 RETVAL_EMPTY_STRING();
960 }
961 }
962
963 static void php_pqconn_object_read_options(zval *objec, void *o, zval *return_value TSRMLS_DC)
964 {
965 php_pqconn_object_t *obj = o;
966 char *options = PQoptions(obj->intern->conn);
967
968 if (options) {
969 RETVAL_STRING(options, 1);
970 } else {
971 RETVAL_EMPTY_STRING();
972 }
973 }
974
975 static void php_pqres_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
976 {
977 php_pqres_object_t *obj = o;
978
979 RETVAL_LONG(PQresultStatus(obj->intern->res));
980 }
981
982 static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
983 {
984 php_pqres_object_t *obj = o;
985 char *error = PQresultErrorMessage(obj->intern->res);
986
987 if (error) {
988 RETVAL_STRING(error, 1);
989 } else {
990 RETVAL_NULL();
991 }
992 }
993
994 static void php_pqres_object_read_num_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
995 {
996 php_pqres_object_t *obj = o;
997
998 RETVAL_LONG(PQntuples(obj->intern->res));
999 }
1000
1001 static void php_pqres_object_read_num_cols(zval *object, void *o, zval *return_value TSRMLS_DC)
1002 {
1003 php_pqres_object_t *obj = o;
1004
1005 RETVAL_LONG(PQnfields(obj->intern->res));
1006 }
1007
1008 static void php_pqres_object_read_affected_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
1009 {
1010 php_pqres_object_t *obj = o;
1011
1012 RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res)));
1013 }
1014
1015 static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1016 {
1017 php_pqres_object_t *obj = o;
1018
1019 if (obj->intern->iter) {
1020 RETVAL_LONG(obj->intern->iter->fetch_type);
1021 } else {
1022 RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
1023 }
1024 }
1025
1026 static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value TSRMLS_DC)
1027 {
1028 php_pqres_object_t *obj = o;
1029 zval *zfetch_type = value;
1030
1031 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
1032 convert_to_long_ex(&zfetch_type);
1033 }
1034
1035 if (!obj->intern->iter) {
1036 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC);
1037 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
1038 }
1039 obj->intern->iter->fetch_type = Z_LVAL_P(zfetch_type);
1040
1041 if (zfetch_type != value) {
1042 zval_ptr_dtor(&zfetch_type);
1043 }
1044 }
1045
1046 static void php_pqstm_object_read_name(zval *object, void *o, zval *return_value TSRMLS_DC)
1047 {
1048 php_pqstm_object_t *obj = o;
1049
1050 RETVAL_STRING(obj->intern->name, 1);
1051 }
1052
1053 static void php_pqstm_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1054 {
1055 php_pqstm_object_t *obj = o;
1056
1057 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1058 }
1059
1060 static void php_pqtxn_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1061 {
1062 php_pqtxn_object_t *obj = o;
1063
1064 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1065 }
1066
1067 static void php_pqtxn_object_read_isolation(zval *object, void *o, zval *return_value TSRMLS_DC)
1068 {
1069 php_pqtxn_object_t *obj = o;
1070
1071 RETVAL_LONG(obj->intern->isolation);
1072 }
1073
1074 static void php_pqtxn_object_read_readonly(zval *object, void *o, zval *return_value TSRMLS_DC)
1075 {
1076 php_pqtxn_object_t *obj = o;
1077
1078 RETVAL_LONG(obj->intern->readonly);
1079 }
1080
1081 static void php_pqtxn_object_read_deferrable(zval *object, void *o, zval *return_value TSRMLS_DC)
1082 {
1083 php_pqtxn_object_t *obj = o;
1084
1085 RETVAL_LONG(obj->intern->deferrable);
1086 }
1087
1088 static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value TSRMLS_DC)
1089 {
1090 php_pqtxn_object_t *obj = o;
1091 php_pqtxn_isolation_t orig = obj->intern->isolation;
1092 zval *zisolation = value;
1093 PGresult *res;
1094
1095 if (Z_TYPE_P(zisolation) != IS_LONG) {
1096 convert_to_long_ex(&zisolation);
1097 }
1098
1099 switch ((obj->intern->isolation = Z_LVAL_P(zisolation))) {
1100 case PHP_PQTXN_READ_COMMITTED:
1101 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ COMMITED");
1102 break;
1103 case PHP_PQTXN_REPEATABLE_READ:
1104 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION REPEATABLE READ");
1105 break;
1106 case PHP_PQTXN_SERIALIZABLE:
1107 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION SERIALIZABLE");
1108 break;
1109 default:
1110 obj->intern->isolation = orig;
1111 res = NULL;
1112 break;
1113 }
1114
1115 if (zisolation != value) {
1116 zval_ptr_dtor(&zisolation);
1117 }
1118
1119 if (res) {
1120 php_pqres_success(res TSRMLS_CC);
1121 PQclear(res);
1122 }
1123 }
1124
1125 static void php_pqtxn_object_write_readonly(zval *object, void *o, zval *value TSRMLS_DC)
1126 {
1127 php_pqtxn_object_t *obj = o;
1128 PGresult *res;
1129
1130 if ((obj->intern->readonly = zend_is_true(value))) {
1131 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY");
1132 } else {
1133 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE");
1134 }
1135
1136 if (res) {
1137 php_pqres_success(res TSRMLS_CC);
1138 PQclear(res);
1139 }
1140 }
1141
1142 static void php_pqtxn_object_write_deferrable(zval *object, void *o, zval *value TSRMLS_DC)
1143 {
1144 php_pqtxn_object_t *obj = o;
1145 PGresult *res;
1146
1147 if ((obj->intern->deferrable = zend_is_true(value))) {
1148 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE");
1149 } else {
1150 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE");
1151 }
1152
1153 if (res) {
1154 php_pqres_success(res TSRMLS_CC);
1155 PQclear(res);
1156 }
1157 }
1158
1159 static void php_pqcancel_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1160 {
1161 php_pqcancel_object_t *obj = o;
1162
1163 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1164 }
1165
1166 static void php_pqevent_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1167 {
1168 php_pqevent_object_t *obj = o;
1169
1170 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1171 }
1172
1173 static void php_pqevent_object_read_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1174 {
1175 php_pqevent_object_t *obj = o;
1176
1177 RETVAL_STRING(obj->intern->type, 1);
1178 }
1179
1180 static zend_class_entry *ancestor(zend_class_entry *ce) {
1181 while (ce->parent) {
1182 ce = ce->parent;
1183 }
1184 return ce;
1185 }
1186
1187 static zval *php_pq_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
1188 {
1189 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1190 php_pq_object_prophandler_t *handler;
1191 zval *return_value;
1192
1193 if (!obj->intern) {
1194 zend_error(E_WARNING, "%s not initialized", ancestor(obj->zo.ce)->name);
1195 } else if ((SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) && handler->read) {
1196 if (type == BP_VAR_R) {
1197 ALLOC_ZVAL(return_value);
1198 Z_SET_REFCOUNT_P(return_value, 0);
1199 Z_UNSET_ISREF_P(return_value);
1200
1201 handler->read(object, obj, return_value TSRMLS_CC);
1202 } else {
1203 zend_error(E_ERROR, "Cannot access %s properties by reference or array key/index", ancestor(obj->zo.ce)->name);
1204 return_value = NULL;
1205 }
1206 } else {
1207 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
1208 }
1209
1210 return return_value;
1211 }
1212
1213 static void php_pq_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
1214 {
1215 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1216 php_pq_object_prophandler_t *handler;
1217
1218 if (SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
1219 if (handler->write) {
1220 handler->write(object, obj, value TSRMLS_CC);
1221 }
1222 } else {
1223 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
1224 }
1225 }
1226
1227 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
1228 {
1229 zval *zsocket, zmember;
1230 php_stream *stream;
1231 STATUS retval;
1232 int socket;
1233
1234 if (!obj) {
1235 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1236 }
1237
1238 INIT_PZVAL(&zmember);
1239 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
1240 MAKE_STD_ZVAL(zsocket);
1241
1242 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
1243 && (-1 < (socket = PQsocket(obj->intern->conn)))
1244 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
1245 php_stream_to_zval(stream, zsocket);
1246 retval = SUCCESS;
1247 } else {
1248 ZVAL_NULL(zsocket);
1249 retval = FAILURE;
1250 }
1251 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
1252 zval_ptr_dtor(&zsocket);
1253
1254 return retval;
1255 }
1256
1257 #ifdef ZTS
1258 # define TSRMLS_DF(d) TSRMLS_D = (d)->ts
1259 # define TSRMLS_CF(d) (d)->ts = TSRMLS_C
1260 #else
1261 # define TSRMLS_DF(d)
1262 # define TSRMLS_CF(d)
1263 #endif
1264
1265 static void php_pqconn_event_register(PGEventRegister *event, php_pqconn_event_data_t *data)
1266 {
1267 PQsetInstanceData(event->conn, php_pqconn_event, data);
1268 }
1269
1270 static void php_pqconn_event_conndestroy(PGEventConnDestroy *event, php_pqconn_event_data_t *data)
1271 {
1272 PQsetInstanceData(event->conn, php_pqconn_event, NULL);
1273 efree(data);
1274 }
1275
1276 static int apply_event(void *p, void *a TSRMLS_DC)
1277 {
1278 zval **evh = p;
1279 zval *args = a;
1280 zval *retval = NULL;
1281
1282 zend_call_method_with_1_params(evh, Z_OBJCE_PP(evh), NULL, "trigger", &retval, args);
1283 if (retval) {
1284 zval_ptr_dtor(&retval);
1285 }
1286
1287 return ZEND_HASH_APPLY_KEEP;
1288 }
1289
1290 static void php_pqconn_event_connreset(PGEventConnReset *event, php_pqconn_event_data_t *data)
1291 {
1292 zval **evhs;
1293 TSRMLS_DF(data);
1294
1295 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("reset"), (void *) &evhs)) {
1296 zval *args, *connection = NULL;
1297
1298 MAKE_STD_ZVAL(args);
1299 array_init(args);
1300 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1301 add_next_index_zval(args, connection);
1302 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1303 zval_ptr_dtor(&args);
1304 }
1305 }
1306
1307 static zval *result_instance_zval(PGresult *res TSRMLS_DC)
1308 {
1309 zval *rid = PQresultInstanceData(res, php_pqconn_event);
1310
1311 if (!rid) {
1312 php_pqres_t *r = ecalloc(1, sizeof(*r));
1313
1314 MAKE_STD_ZVAL(rid);
1315 r->res = res;
1316 rid->type = IS_OBJECT;
1317 rid->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1318
1319 PQresultSetInstanceData(res, php_pqconn_event, rid);
1320 }
1321
1322 Z_ADDREF_P(rid);
1323 return rid;
1324 }
1325
1326 static void php_pqconn_event_resultcreate(PGEventResultCreate *event, php_pqconn_event_data_t *data)
1327 {
1328 zval **evhs;
1329 TSRMLS_DF(data);
1330
1331 /* event listener */
1332 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) {
1333 zval *args, *connection = NULL, *res = result_instance_zval(event->result TSRMLS_CC);
1334
1335 MAKE_STD_ZVAL(args);
1336 array_init(args);
1337 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1338 add_next_index_zval(args, connection);
1339 add_next_index_zval(args, res);
1340 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1341 zval_ptr_dtor(&args);
1342 }
1343
1344 /* async callback */
1345 if (data->obj->intern->onevent.fci.size > 0) {
1346 zval *res = result_instance_zval(event->result TSRMLS_CC);
1347
1348 zend_fcall_info_argn(&data->obj->intern->onevent.fci TSRMLS_CC, 1, &res);
1349 zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL TSRMLS_CC);
1350 zval_ptr_dtor(&res);
1351 }
1352 }
1353
1354 static int php_pqconn_event(PGEventId id, void *e, void *data)
1355 {
1356 switch (id) {
1357 case PGEVT_REGISTER:
1358 php_pqconn_event_register(e, data);
1359 break;
1360 case PGEVT_CONNDESTROY:
1361 php_pqconn_event_conndestroy(e, data);
1362 break;
1363 case PGEVT_CONNRESET:
1364 php_pqconn_event_connreset(e, data);
1365 break;
1366 case PGEVT_RESULTCREATE:
1367 php_pqconn_event_resultcreate(e, data);
1368 break;
1369 default:
1370 break;
1371 }
1372
1373 return 1;
1374 }
1375
1376 static php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj TSRMLS_DC)
1377 {
1378 php_pqconn_event_data_t *data = emalloc(sizeof(*data));
1379
1380 data->obj = obj;
1381 TSRMLS_CF(data);
1382
1383 return data;
1384 }
1385
1386 static void php_pqconn_notice_recv(void *p, const PGresult *res)
1387 {
1388 php_pqconn_event_data_t *data = p;
1389 zval **evhs;
1390 TSRMLS_DF(data);
1391
1392 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("notice"), (void *) &evhs)) {
1393 zval *args, *connection = NULL;
1394
1395 MAKE_STD_ZVAL(args);
1396 array_init(args);
1397 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1398 add_next_index_zval(args, connection);
1399 add_next_index_string(args, PQresultErrorMessage(res), 1);
1400 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1401 zval_ptr_dtor(&args);
1402 }
1403 }
1404
1405 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
1406 ZEND_ARG_INFO(0, dsn)
1407 ZEND_ARG_INFO(0, async)
1408 ZEND_END_ARG_INFO();
1409 static PHP_METHOD(pqconn, __construct) {
1410 zend_error_handling zeh;
1411 char *dsn_str = "";
1412 int dsn_len = 0;
1413 zend_bool async = 0;
1414
1415 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1416 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &dsn_str, &dsn_len, &async)) {
1417 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1418 php_pqconn_event_data_t *data = php_pqconn_event_data_init(obj TSRMLS_CC);
1419
1420 obj->intern = ecalloc(1, sizeof(*obj->intern));
1421
1422 zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
1423 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);
1424
1425
1426 if (async) {
1427 obj->intern->conn = PQconnectStart(dsn_str);
1428 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
1429 } else {
1430 obj->intern->conn = PQconnectdb(dsn_str);
1431 }
1432
1433 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, data);
1434 PQregisterEventProc(obj->intern->conn, php_pqconn_event, "ext-pq", data);
1435
1436 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
1437 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection failed: %s", PQerrorMessage(obj->intern->conn));
1438 }
1439 }
1440 zend_restore_error_handling(&zeh TSRMLS_CC);
1441 }
1442
1443 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
1444 ZEND_END_ARG_INFO();
1445 static PHP_METHOD(pqconn, reset) {
1446 if (SUCCESS == zend_parse_parameters_none()) {
1447 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1448
1449 if (obj->intern) {
1450 PQreset(obj->intern->conn);
1451
1452 if (CONNECTION_OK == PQstatus(obj->intern->conn)) {
1453 RETURN_TRUE;
1454 } else {
1455 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection reset failed: %s", PQerrorMessage(obj->intern->conn));
1456 }
1457 } else {
1458 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1459 }
1460 RETURN_FALSE;
1461 }
1462 }
1463
1464 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
1465 ZEND_END_ARG_INFO();
1466 static PHP_METHOD(pqconn, resetAsync) {
1467 if (SUCCESS == zend_parse_parameters_none()) {
1468 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1469
1470 if (obj->intern) {
1471 if (PQresetStart(obj->intern->conn)) {
1472 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
1473 RETURN_TRUE;
1474 }
1475 } else {
1476 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1477 }
1478 RETURN_FALSE;
1479 }
1480 }
1481
1482 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)
1483 {
1484 HashTable ht, *existing_listeners;
1485
1486 php_pq_callback_addref(listener);
1487
1488 if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
1489 zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
1490 } else {
1491 zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
1492 zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
1493 zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
1494 }
1495 }
1496
1497 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
1498 ZEND_ARG_INFO(0, channel)
1499 ZEND_ARG_INFO(0, callable)
1500 ZEND_END_ARG_INFO();
1501 static PHP_METHOD(pqconn, listen) {
1502 char *channel_str = NULL;
1503 int channel_len = 0;
1504 php_pq_callback_t listener;
1505
1506 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc)) {
1507 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1508
1509 obj->intern->poller = PQconsumeInput;
1510
1511 if (obj->intern) {
1512 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
1513
1514 if (quoted_channel) {
1515 PGresult *res;
1516 char *cmd;
1517
1518 spprintf(&cmd, 0, "LISTEN %s", channel_str);
1519 res = PQexec(obj->intern->conn, cmd);
1520
1521 efree(cmd);
1522 PQfreemem(quoted_channel);
1523
1524 if (res) {
1525 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1526 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
1527 RETVAL_TRUE;
1528 } else {
1529 RETVAL_FALSE;
1530 }
1531 PQclear(res);
1532 } else {
1533 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not install listener: %s", PQerrorMessage(obj->intern->conn));
1534 RETVAL_FALSE;
1535 }
1536
1537 php_pqconn_notify_listeners(obj TSRMLS_CC);
1538 } else {
1539 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape channel identifier: %s", PQerrorMessage(obj->intern->conn));
1540 }
1541 } else {
1542 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1543 RETVAL_FALSE;
1544 }
1545 }
1546 }
1547
1548 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
1549 ZEND_ARG_INFO(0, channel)
1550 ZEND_ARG_INFO(0, message)
1551 ZEND_END_ARG_INFO();
1552 static PHP_METHOD(pqconn, notify) {
1553 char *channel_str, *message_str;
1554 int channel_len, message_len;
1555
1556 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len)) {
1557 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1558
1559 if (obj->intern) {
1560 PGresult *res;
1561 char *params[2] = {channel_str, message_str};
1562
1563 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
1564
1565 if (res) {
1566 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1567 RETVAL_TRUE;
1568 } else {
1569 RETVAL_FALSE;
1570 }
1571 PQclear(res);
1572 } else {
1573 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not notify listeners: %s", PQerrorMessage(obj->intern->conn));
1574 RETVAL_FALSE;
1575 }
1576
1577 php_pqconn_notify_listeners(obj TSRMLS_CC);
1578
1579 } else {
1580 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1581 RETVAL_FALSE;
1582 }
1583 }
1584 }
1585
1586 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
1587 ZEND_END_ARG_INFO();
1588 static PHP_METHOD(pqconn, poll) {
1589 if (SUCCESS == zend_parse_parameters_none()) {
1590 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1591
1592 if (obj->intern) {
1593 if (obj->intern->poller) {
1594 if (obj->intern->poller == PQconsumeInput) {
1595 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
1596 php_pqconn_notify_listeners(obj TSRMLS_CC);
1597 return;
1598 } else {
1599 RETURN_LONG(obj->intern->poller(obj->intern->conn));
1600 }
1601 } else {
1602 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active");
1603 }
1604 } else {
1605 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1606 }
1607 RETURN_FALSE;
1608 }
1609 }
1610
1611 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
1612 ZEND_ARG_INFO(0, query)
1613 ZEND_END_ARG_INFO();
1614 static PHP_METHOD(pqconn, exec) {
1615 zend_error_handling zeh;
1616 char *query_str;
1617 int query_len;
1618
1619 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1620 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) {
1621 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1622
1623 if (obj->intern) {
1624 PGresult *res = PQexec(obj->intern->conn, query_str);
1625
1626 php_pqconn_notify_listeners(obj TSRMLS_CC);
1627
1628 if (res) {
1629 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1630 php_pqres_t *r = ecalloc(1, sizeof(*r));
1631
1632 r->res = res;
1633 return_value->type = IS_OBJECT;
1634 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1635 }
1636 } else {
1637 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1638 }
1639 } else {
1640 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1641 }
1642 }
1643 zend_restore_error_handling(&zeh TSRMLS_CC);
1644 }
1645
1646 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
1647 ZEND_END_ARG_INFO();
1648 static PHP_METHOD(pqconn, getResult) {
1649 if (SUCCESS == zend_parse_parameters_none()) {
1650 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1651
1652 if (obj->intern) {
1653 PGresult *res = PQgetResult(obj->intern->conn);
1654
1655 if (res) {
1656 php_pqres_t *r = ecalloc(1, sizeof(*r));
1657
1658 r->res = res;
1659 return_value->type = IS_OBJECT;
1660 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1661 } else {
1662 RETVAL_NULL();
1663 }
1664 } else {
1665 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1666 RETVAL_FALSE;
1667 }
1668 }
1669 }
1670
1671 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
1672 ZEND_ARG_INFO(0, query)
1673 ZEND_ARG_INFO(0, callable)
1674 ZEND_END_ARG_INFO();
1675 static PHP_METHOD(pqconn, execAsync) {
1676 zend_error_handling zeh;
1677 php_pq_callback_t resolver = {{0}};
1678 char *query_str;
1679 int query_len;
1680
1681 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1682 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc)) {
1683 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1684
1685 if (obj->intern) {
1686 php_pq_callback_dtor(&obj->intern->onevent);
1687 if (resolver.fci.size > 0) {
1688 obj->intern->onevent = resolver;
1689 php_pq_callback_addref(&obj->intern->onevent);
1690 }
1691
1692 obj->intern->poller = PQconsumeInput;
1693
1694 if (PQsendQuery(obj->intern->conn, query_str)) {
1695 if (obj->intern->unbuffered) {
1696 if (!PQsetSingleRowMode(obj->intern->conn)) {
1697 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn));
1698 }
1699 }
1700 RETVAL_TRUE;
1701 } else {
1702 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1703 RETVAL_FALSE;
1704 }
1705 } else {
1706 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1707 RETVAL_FALSE;
1708 }
1709 }
1710 zend_restore_error_handling(&zeh TSRMLS_CC);
1711 }
1712
1713 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
1714 {
1715 Oid **types = arg;
1716 zval **ztype = p;
1717
1718 if (Z_TYPE_PP(ztype) != IS_LONG) {
1719 convert_to_long_ex(ztype);
1720 }
1721
1722 **types = Z_LVAL_PP(ztype);
1723 ++*types;
1724
1725 if (*ztype != *(zval **)p) {
1726 zval_ptr_dtor(ztype);
1727 }
1728 return ZEND_HASH_APPLY_KEEP;
1729 }
1730
1731 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1732 {
1733 char ***params;
1734 HashTable *zdtor;
1735 zval **zparam = p;
1736
1737 params = (char ***) va_arg(argv, char ***);
1738 zdtor = (HashTable *) va_arg(argv, HashTable *);
1739
1740 if (Z_TYPE_PP(zparam) == IS_NULL) {
1741 **params = NULL;
1742 ++*params;
1743 } else {
1744 if (Z_TYPE_PP(zparam) != IS_STRING) {
1745 convert_to_string_ex(zparam);
1746 }
1747
1748 **params = Z_STRVAL_PP(zparam);
1749 ++*params;
1750
1751 if (*zparam != *(zval **)p) {
1752 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
1753 }
1754 }
1755 return ZEND_HASH_APPLY_KEEP;
1756 }
1757
1758 static int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC)
1759 {
1760 int count = zend_hash_num_elements(ht);
1761
1762 *types = NULL;
1763
1764 if (count) {
1765 Oid *tmp;
1766
1767 /* +1 for when less types than params are specified */
1768 *types = tmp = ecalloc(count + 1, sizeof(Oid));
1769 zend_hash_apply_with_argument(ht, apply_to_oid, &tmp TSRMLS_CC);
1770 }
1771
1772 return count;
1773 }
1774
1775 static int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC)
1776 {
1777 int count = zend_hash_num_elements(ht);
1778
1779 *params = NULL;
1780
1781 if (count) {
1782 char **tmp;
1783
1784 *params = tmp = ecalloc(count, sizeof(char *));
1785 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param, 2, &tmp, zdtor);
1786 }
1787
1788 return count;
1789 }
1790
1791 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
1792 ZEND_ARG_INFO(0, query)
1793 ZEND_ARG_ARRAY_INFO(0, params, 0)
1794 ZEND_ARG_ARRAY_INFO(0, types, 1)
1795 ZEND_END_ARG_INFO();
1796 static PHP_METHOD(pqconn, execParams) {
1797 zend_error_handling zeh;
1798 char *query_str;
1799 int query_len;
1800 zval *zparams;
1801 zval *ztypes = NULL;
1802
1803 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1804 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
1805 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1806
1807 if (obj->intern) {
1808 PGresult *res;
1809 int count;
1810 Oid *types = NULL;
1811 char **params = NULL;
1812 HashTable zdtor;
1813
1814 ZEND_INIT_SYMTABLE(&zdtor);
1815 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
1816
1817 if (ztypes) {
1818 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
1819 }
1820
1821 res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
1822
1823 zend_hash_destroy(&zdtor);
1824 if (types) {
1825 efree(types);
1826 }
1827 if (params) {
1828 efree(params);
1829 }
1830
1831 php_pqconn_notify_listeners(obj TSRMLS_CC);
1832
1833 if (res) {
1834 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1835 php_pqres_t *r = ecalloc(1, sizeof(*r));
1836
1837 r->res = res;
1838 return_value->type = IS_OBJECT;
1839 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1840 }
1841 } else {
1842 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1843 RETVAL_FALSE;
1844 }
1845 } else {
1846 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1847 RETVAL_FALSE;
1848 }
1849 }
1850 zend_restore_error_handling(&zeh TSRMLS_CC);
1851 }
1852
1853 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
1854 ZEND_ARG_INFO(0, query)
1855 ZEND_ARG_ARRAY_INFO(0, params, 0)
1856 ZEND_ARG_ARRAY_INFO(0, types, 1)
1857 ZEND_ARG_INFO(0, callable)
1858 ZEND_END_ARG_INFO();
1859 static PHP_METHOD(pqconn, execParamsAsync) {
1860 zend_error_handling zeh;
1861 php_pq_callback_t resolver = {{0}};
1862 char *query_str;
1863 int query_len;
1864 zval *zparams;
1865 zval *ztypes = NULL;
1866
1867 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1868 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc)) {
1869 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1870
1871 if (obj->intern) {
1872 int count;
1873 Oid *types = NULL;
1874 char **params = NULL;
1875 HashTable zdtor;
1876
1877 ZEND_INIT_SYMTABLE(&zdtor);
1878 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
1879
1880 if (ztypes) {
1881 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
1882 }
1883
1884 php_pq_callback_dtor(&obj->intern->onevent);
1885 if (resolver.fci.size > 0) {
1886 obj->intern->onevent = resolver;
1887 php_pq_callback_addref(&obj->intern->onevent);
1888 }
1889
1890 obj->intern->poller = PQconsumeInput;
1891
1892 if (PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) {
1893 if (obj->intern->unbuffered) {
1894 if (!PQsetSingleRowMode(obj->intern->conn)) {
1895 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn));
1896 }
1897 }
1898 RETVAL_TRUE;
1899 } else {
1900 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1901 RETVAL_FALSE;
1902 }
1903
1904 zend_hash_destroy(&zdtor);
1905 if (types) {
1906 efree(types);
1907 }
1908 if (params) {
1909 efree(params);
1910 }
1911
1912 php_pqconn_notify_listeners(obj TSRMLS_CC);
1913
1914 } else {
1915 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1916 RETVAL_FALSE;
1917 }
1918 }
1919 zend_restore_error_handling(&zeh TSRMLS_CC);
1920 }
1921
1922 static STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
1923 {
1924 Oid *types = NULL;
1925 int count = 0;
1926 PGresult *res;
1927 STATUS rv;
1928
1929 if (!obj) {
1930 obj = zend_object_store_get_object(object TSRMLS_CC);
1931 }
1932
1933 if (typest) {
1934 count = zend_hash_num_elements(typest);
1935 php_pq_types_to_array(typest, &types TSRMLS_CC);
1936 }
1937
1938 res = PQprepare(obj->intern->conn, name, query, count, types);
1939
1940 if (types) {
1941 efree(types);
1942 }
1943
1944 if (res) {
1945 rv = php_pqres_success(res TSRMLS_CC);
1946 PQclear(res);
1947 } else {
1948 rv = FAILURE;
1949 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(obj->intern->conn));
1950 }
1951
1952 return rv;
1953 }
1954
1955 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
1956 ZEND_ARG_INFO(0, type)
1957 ZEND_ARG_INFO(0, query)
1958 ZEND_ARG_ARRAY_INFO(0, types, 1)
1959 ZEND_END_ARG_INFO();
1960 static PHP_METHOD(pqconn, prepare) {
1961 zend_error_handling zeh;
1962 zval *ztypes = NULL;
1963 char *name_str, *query_str;
1964 int name_len, *query_len;
1965
1966 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1967 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
1968 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1969
1970 if (obj->intern) {
1971 if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1972 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1973
1974 php_pq_object_addref(obj TSRMLS_CC);
1975 stm->conn = obj;
1976 stm->name = estrdup(name_str);
1977
1978 return_value->type = IS_OBJECT;
1979 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1980 }
1981 php_pqconn_notify_listeners(obj TSRMLS_CC);
1982 } else {
1983 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1984 }
1985 }
1986 zend_restore_error_handling(&zeh TSRMLS_CC);
1987 }
1988
1989 static STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
1990 {
1991 STATUS rv;
1992 int count;
1993 Oid *types = NULL;
1994
1995 if (!obj) {
1996 obj = zend_object_store_get_object(object TSRMLS_CC);
1997 }
1998
1999 if (typest) {
2000 count = php_pq_types_to_array(typest, &types TSRMLS_CC);
2001 }
2002
2003 if (PQsendPrepare(obj->intern->conn, name, query, count, types)) {
2004 if (obj->intern->unbuffered) {
2005 if (!PQsetSingleRowMode(obj->intern->conn)) {
2006 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn));
2007 }
2008 }
2009 rv = SUCCESS;
2010 } else {
2011 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(obj->intern->conn));
2012 rv = FAILURE;
2013 }
2014
2015 if (types) {
2016 efree(types);
2017 }
2018
2019 return rv;
2020 }
2021
2022 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
2023 ZEND_ARG_INFO(0, type)
2024 ZEND_ARG_INFO(0, query)
2025 ZEND_ARG_ARRAY_INFO(0, types, 1)
2026 ZEND_END_ARG_INFO();
2027 static PHP_METHOD(pqconn, prepareAsync) {
2028 zend_error_handling zeh;
2029 zval *ztypes = NULL;
2030 char *name_str, *query_str;
2031 int name_len, *query_len;
2032
2033 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2034 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
2035 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2036
2037 if (obj->intern) {
2038 obj->intern->poller = PQconsumeInput;
2039 if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
2040 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2041
2042 php_pq_object_addref(obj TSRMLS_CC);
2043 stm->conn = obj;
2044 stm->name = estrdup(name_str);
2045
2046 return_value->type = IS_OBJECT;
2047 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
2048 }
2049 php_pqconn_notify_listeners(obj TSRMLS_CC);
2050 } else {
2051 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2052 }
2053 }
2054 zend_restore_error_handling(&zeh TSRMLS_CC);
2055 }
2056
2057 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
2058 ZEND_ARG_INFO(0, string)
2059 ZEND_END_ARG_INFO();
2060 static PHP_METHOD(pqconn, quote) {
2061 char *str;
2062 int len;
2063
2064 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2065 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2066
2067 if (obj->intern) {
2068 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
2069
2070 if (quoted) {
2071 RETVAL_STRING(quoted, 1);
2072 PQfreemem(quoted);
2073 } else {
2074 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote string: %s", PQerrorMessage(obj->intern->conn));
2075 RETVAL_FALSE;
2076 }
2077 } else {
2078 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2079 RETVAL_FALSE;
2080 }
2081 }
2082 }
2083
2084 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
2085 ZEND_ARG_INFO(0, type)
2086 ZEND_END_ARG_INFO();
2087 static PHP_METHOD(pqconn, quoteName) {
2088 char *str;
2089 int len;
2090
2091 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2092 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2093
2094 if (obj->intern) {
2095 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
2096
2097 if (quoted) {
2098 RETVAL_STRING(quoted, 1);
2099 PQfreemem(quoted);
2100 } else {
2101 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote name: %s", PQerrorMessage(obj->intern->conn));
2102 RETVAL_FALSE;
2103 }
2104 } else {
2105 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2106 RETVAL_FALSE;
2107 }
2108 }
2109 }
2110
2111 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
2112 ZEND_ARG_INFO(0, bytea)
2113 ZEND_END_ARG_INFO();
2114 static PHP_METHOD(pqconn, escapeBytea) {
2115 char *str;
2116 int len;
2117
2118 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2119 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2120
2121 if (obj->intern) {
2122 size_t escaped_len;
2123 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
2124
2125 if (escaped_str) {
2126 RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
2127 PQfreemem(escaped_str);
2128 } else {
2129 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape bytea: %s", PQerrorMessage(obj->intern->conn));
2130 RETVAL_FALSE;
2131 }
2132 } else {
2133 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2134 RETVAL_FALSE;
2135 }
2136 }
2137 }
2138
2139 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
2140 ZEND_ARG_INFO(0, bytea)
2141 ZEND_END_ARG_INFO();
2142 static PHP_METHOD(pqconn, unescapeBytea) {
2143 char *str;
2144 int len;
2145
2146 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2147 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2148
2149 if (obj->intern) {
2150 size_t unescaped_len;
2151 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
2152
2153 if (unescaped_str) {
2154 RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
2155 PQfreemem(unescaped_str);
2156 } else {
2157 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not unescape bytea: %s", PQerrorMessage(obj->intern->conn));
2158 RETVAL_FALSE;
2159 }
2160 } else {
2161 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2162 RETVAL_FALSE;
2163 }
2164 }
2165 }
2166
2167 static const char *isolation_level(long *isolation) {
2168 switch (*isolation) {
2169 case PHP_PQTXN_SERIALIZABLE:
2170 return "SERIALIZABLE";
2171 case PHP_PQTXN_REPEATABLE_READ:
2172 return "REPEATABLE READ";
2173 default:
2174 *isolation = PHP_PQTXN_READ_COMMITTED;
2175 /* no break */
2176 case PHP_PQTXN_READ_COMMITTED:
2177 return "READ COMMITTED";
2178 }
2179 }
2180
2181 static STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
2182 {
2183 if (!conn_obj) {
2184 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2185 }
2186
2187 if (conn_obj->intern) {
2188 PGresult *res;
2189 char *cmd;
2190
2191 spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
2192 isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
2193
2194 res = PQexec(conn_obj->intern->conn, cmd);
2195
2196 efree(cmd);
2197
2198 if (res) {
2199 STATUS rv = php_pqres_success(res TSRMLS_CC);
2200
2201 PQclear(res);
2202 return rv;
2203 } else {
2204 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction: %s", PQerrorMessage(conn_obj->intern->conn));
2205 return FAILURE;
2206 }
2207 } else {
2208 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2209 return FAILURE;
2210 }
2211 }
2212
2213 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)
2214 {
2215 if (!conn_obj) {
2216 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2217 }
2218
2219 if (conn_obj->intern->conn) {
2220 char *cmd;
2221
2222 spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
2223 isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
2224
2225 if (PQsendQuery(conn_obj->intern->conn, cmd)) {
2226 conn_obj->intern->poller = PQconsumeInput;
2227 efree(cmd);
2228 return SUCCESS;
2229 } else {
2230 efree(cmd);
2231 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction: %s", PQerrorMessage(conn_obj->intern->conn));
2232 return FAILURE;
2233 }
2234 } else {
2235 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2236 return FAILURE;
2237 }
2238 }
2239
2240 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
2241 ZEND_ARG_INFO(0, isolation)
2242 ZEND_ARG_INFO(0, readonly)
2243 ZEND_ARG_INFO(0, deferrable)
2244 ZEND_END_ARG_INFO();
2245 static PHP_METHOD(pqconn, startTransaction) {
2246 zend_error_handling zeh;
2247 long isolation = PHP_PQTXN_READ_COMMITTED;
2248 zend_bool readonly = 0, deferrable = 0;
2249
2250 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2251 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
2252 STATUS rv;
2253 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2254
2255 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
2256
2257 if (SUCCESS == rv) {
2258 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
2259
2260 php_pq_object_addref(obj TSRMLS_CC);
2261 txn->conn = obj;
2262 txn->isolation = isolation;
2263 txn->readonly = readonly;
2264 txn->deferrable = deferrable;
2265
2266 return_value->type = IS_OBJECT;
2267 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
2268 }
2269 }
2270 zend_restore_error_handling(&zeh TSRMLS_CC);
2271 }
2272
2273
2274 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
2275 ZEND_ARG_INFO(0, isolation)
2276 ZEND_ARG_INFO(0, readonly)
2277 ZEND_ARG_INFO(0, deferrable)
2278 ZEND_END_ARG_INFO();
2279 static PHP_METHOD(pqconn, startTransactionAsync) {
2280 zend_error_handling zeh;
2281 long isolation = PHP_PQTXN_READ_COMMITTED;
2282 zend_bool readonly = 0, deferrable = 0;
2283
2284 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2285 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
2286 STATUS rv;
2287 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2288
2289 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
2290
2291 if (SUCCESS == rv) {
2292 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
2293
2294 php_pq_object_addref(obj TSRMLS_CC);
2295 txn->conn = obj;
2296 txn->isolation = isolation;
2297 txn->readonly = readonly;
2298 txn->deferrable = deferrable;
2299
2300 return_value->type = IS_OBJECT;
2301 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
2302 }
2303 }
2304 zend_restore_error_handling(&zeh TSRMLS_CC);
2305 }
2306
2307 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
2308 ZEND_ARG_INFO(0, stdio_stream)
2309 ZEND_END_ARG_INFO();
2310 static PHP_METHOD(pqconn, trace) {
2311 zval *zstream = NULL;
2312
2313 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) {
2314 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2315 if (obj->intern) {
2316 if (zstream) {
2317 FILE *fp;
2318 php_stream *stream = NULL;
2319
2320 php_stream_from_zval(stream, &zstream);
2321
2322 if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
2323 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
2324 PQtrace(obj->intern->conn, fp);
2325 RETVAL_TRUE;
2326 } else {
2327 RETVAL_FALSE;
2328 }
2329 } else {
2330 PQuntrace(obj->intern->conn);
2331 RETVAL_TRUE;
2332 }
2333 } else {
2334 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2335 RETVAL_FALSE;
2336 }
2337 }
2338 }
2339
2340 static zend_function_entry php_pqconn_methods[] = {
2341 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2342 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
2343 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
2344 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
2345 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
2346 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
2347 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
2348 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
2349 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
2350 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
2351 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
2352 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
2353 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
2354 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
2355 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
2356 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
2357 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
2358 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
2359 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
2360 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
2361 {0}
2362 };
2363
2364 static zval **php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type TSRMLS_DC)
2365 {
2366 zval **row = NULL;
2367 php_pqres_fetch_t orig_fetch;
2368
2369 if (!obj) {
2370 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2371 }
2372
2373 if (!obj->intern->iter) {
2374 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
2375 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
2376 }
2377 orig_fetch = obj->intern->iter->fetch_type;
2378 obj->intern->iter->fetch_type = fetch_type;
2379 if (SUCCESS == obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC)) {
2380 obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, &row TSRMLS_CC);
2381 obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
2382 }
2383 obj->intern->iter->fetch_type = orig_fetch;
2384
2385 return row ? row : NULL;
2386 }
2387
2388 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
2389 ZEND_ARG_INFO(0, fetch_type)
2390 ZEND_END_ARG_INFO();
2391 static PHP_METHOD(pqres, fetchRow) {
2392 zend_error_handling zeh;
2393 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2394 long fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
2395
2396 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2397 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) {
2398 zval **row = php_pqres_iteration(getThis(), obj, fetch_type TSRMLS_CC);
2399
2400 if (row) {
2401 RETVAL_ZVAL(*row, 1, 0);
2402 } else {
2403 RETVAL_FALSE;
2404 }
2405 }
2406 zend_restore_error_handling(&zeh TSRMLS_CC);
2407 }
2408
2409 static zval **column_at(zval *row, int col TSRMLS_DC)
2410 {
2411 zval **data = NULL;
2412 HashTable *ht = HASH_OF(row);
2413 int count = zend_hash_num_elements(ht);
2414
2415 if (col < count) {
2416 zend_hash_internal_pointer_reset(ht);
2417 while (col-- > 0) {
2418 zend_hash_move_forward(ht);
2419 }
2420 zend_hash_get_current_data(ht, (void *) &data);
2421 } else {
2422 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count);
2423 }
2424 return data;
2425 }
2426
2427 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
2428 ZEND_ARG_INFO(0, col_num)
2429 ZEND_END_ARG_INFO();
2430 static PHP_METHOD(pqres, fetchCol) {
2431 zend_error_handling zeh;
2432 long fetch_col = 0;
2433
2434 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2435 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
2436 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2437 zval **row = php_pqres_iteration(getThis(), obj, obj->intern->iter ? obj->intern->iter->fetch_type : 0 TSRMLS_CC);
2438
2439 if (row) {
2440 zval **col = column_at(*row, fetch_col TSRMLS_CC);
2441
2442 if (col) {
2443 RETVAL_ZVAL(*col, 1, 0);
2444 } else {
2445 RETVAL_FALSE;
2446 }
2447 } else {
2448 RETVAL_FALSE;
2449 }
2450 }
2451 zend_restore_error_handling(&zeh TSRMLS_CC);
2452
2453 }
2454
2455 static zend_function_entry php_pqres_methods[] = {
2456 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
2457 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
2458 {0}
2459 };
2460
2461 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
2462 ZEND_ARG_OBJ_INFO(0, Connection, pq\\Connection, 0)
2463 ZEND_ARG_INFO(0, type)
2464 ZEND_ARG_INFO(0, query)
2465 ZEND_ARG_ARRAY_INFO(0, types, 1)
2466 ZEND_ARG_INFO(0, async)
2467 ZEND_END_ARG_INFO();
2468 static PHP_METHOD(pqstm, __construct) {
2469 zend_error_handling zeh;
2470 zval *zconn, *ztypes = NULL;
2471 char *name_str, *query_str;
2472 int name_len, *query_len;
2473 zend_bool async = 0;
2474
2475 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2476 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|a/!b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes, &async)) {
2477 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2478 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2479
2480 if (conn_obj->intern) {
2481 STATUS rv;
2482 if (async) {
2483 conn_obj->intern->poller = PQconsumeInput;
2484 rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
2485 } else {
2486 rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
2487 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
2488 }
2489
2490 if (SUCCESS == rv) {
2491 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2492
2493 php_pq_object_addref(conn_obj TSRMLS_CC);
2494 stm->conn = conn_obj;
2495 stm->name = estrdup(name_str);
2496 obj->intern = stm;
2497 }
2498 } else {
2499 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2500 }
2501 }
2502 zend_restore_error_handling(&zeh TSRMLS_CC);
2503 }
2504
2505 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
2506 ZEND_ARG_ARRAY_INFO(0, params, 1)
2507 ZEND_END_ARG_INFO();
2508 static PHP_METHOD(pqstm, exec) {
2509 zend_error_handling zeh;
2510 zval *zparams = NULL;
2511
2512 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2513 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
2514 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2515
2516 if (obj->intern) {
2517 if (obj->intern->conn->intern) {
2518 int count = 0;
2519 char **params = NULL;
2520 HashTable zdtor;
2521 PGresult *res;
2522
2523 if (zparams) {
2524 ZEND_INIT_SYMTABLE(&zdtor);
2525 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2526 }
2527
2528 res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0);
2529
2530 if (params) {
2531 efree(params);
2532 }
2533 if (zparams) {
2534 zend_hash_destroy(&zdtor);
2535 }
2536
2537 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2538
2539 if (res) {
2540 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2541 php_pqres_t *r = ecalloc(1, sizeof(*r));
2542
2543 r->res = res;
2544 return_value->type = IS_OBJECT;
2545 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
2546 }
2547 } else {
2548 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2549 }
2550 } else {
2551 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2552 }
2553 } else {
2554 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
2555 }
2556 }
2557 zend_restore_error_handling(&zeh TSRMLS_CC);
2558 }
2559
2560 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0)
2561 ZEND_ARG_ARRAY_INFO(0, params, 1)
2562 ZEND_ARG_INFO(0, callable)
2563 ZEND_END_ARG_INFO();
2564 static PHP_METHOD(pqstm, execAsync) {
2565 zend_error_handling zeh;
2566 zval *zparams = NULL;
2567 php_pq_callback_t resolver = {{0}};
2568
2569 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2570 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc)) {
2571 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2572
2573 if (obj->intern) {
2574 if (obj->intern->conn->intern) {
2575 int count;
2576 char **params = NULL;
2577 HashTable zdtor;
2578
2579 if (zparams) {
2580 ZEND_INIT_SYMTABLE(&zdtor);
2581 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2582 }
2583
2584 php_pq_callback_dtor(&obj->intern->conn->intern->onevent);
2585 if (resolver.fci.size > 0) {
2586 obj->intern->conn->intern->onevent = resolver;
2587 php_pq_callback_addref(&obj->intern->conn->intern->onevent);
2588 }
2589
2590 obj->intern->conn->intern->poller = PQconsumeInput;
2591
2592 if (PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0)) {
2593 if (obj->intern->conn->intern->unbuffered) {
2594 if (!PQsetSingleRowMode(obj->intern->conn->intern->conn)) {
2595 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2596 }
2597 }
2598 RETVAL_TRUE;
2599 } else {
2600 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2601 RETVAL_FALSE;
2602 }
2603
2604 if (params) {
2605 efree(params);
2606 }
2607 if (zparams) {
2608 zend_hash_destroy(&zdtor);
2609 }
2610
2611 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2612
2613 } else {
2614 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2615 RETVAL_FALSE;
2616 }
2617 } else {
2618 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
2619 RETVAL_FALSE;
2620 }
2621 }
2622 zend_restore_error_handling(&zeh TSRMLS_CC);
2623 }
2624
2625 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
2626 ZEND_END_ARG_INFO();
2627 static PHP_METHOD(pqstm, desc) {
2628 zend_error_handling zeh;
2629
2630 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2631 if (SUCCESS == zend_parse_parameters_none()) {
2632 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2633
2634 if (obj->intern) {
2635 if (obj->intern->conn->intern) {
2636 PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name);
2637
2638 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2639
2640 if (res) {
2641 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2642 int p, params;
2643
2644 array_init(return_value);
2645 for (p = 0, params = PQnparams(res); p < params; ++p) {
2646 add_next_index_long(return_value, PQparamtype(res, p));
2647 }
2648 }
2649 } else {
2650 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2651 }
2652 } else {
2653 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2654 }
2655 } else {
2656 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
2657 }
2658 }
2659 zend_restore_error_handling(&zeh TSRMLS_CC);
2660 }
2661
2662 static zend_function_entry php_pqstm_methods[] = {
2663 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2664 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
2665 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
2666 PHP_ME(pqstm, execAsync, ai_pqstm_exec_async, ZEND_ACC_PUBLIC)
2667 {0}
2668 };
2669
2670 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_construct, 0, 0, 1)
2671 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2672 ZEND_ARG_INFO(0, async)
2673 ZEND_ARG_INFO(0, isolation)
2674 ZEND_ARG_INFO(0, readonly)
2675 ZEND_ARG_INFO(0, deferrable)
2676 ZEND_END_ARG_INFO();
2677 static PHP_METHOD(pqtxn, __construct) {
2678 zend_error_handling zeh;
2679 zval *zconn;
2680 long isolation = PHP_PQTXN_READ_COMMITTED;
2681 zend_bool async = 0, readonly = 0, deferrable = 0;
2682
2683 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2684 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|blbb", &zconn, php_pqconn_class_entry, &async, &isolation, &readonly, &deferrable)) {
2685 STATUS rv;
2686 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2687 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2688
2689 if (conn_obj->intern) {
2690 if (async) {
2691 rv = php_pqconn_start_transaction_async(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC);
2692 } else {
2693 rv = php_pqconn_start_transaction(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC);
2694 }
2695
2696 if (SUCCESS == rv) {
2697 obj->intern = ecalloc(1, sizeof(*obj->intern));
2698
2699 php_pq_object_addref(conn_obj TSRMLS_CC);
2700 obj->intern->conn = conn_obj;
2701 obj->intern->isolation = isolation;
2702 obj->intern->readonly = readonly;
2703 obj->intern->deferrable = deferrable;
2704 }
2705 } else {
2706 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2707 }
2708 }
2709 zend_restore_error_handling(&zeh TSRMLS_CC);
2710 }
2711
2712 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit, 0, 0, 0)
2713 ZEND_END_ARG_INFO();
2714 static PHP_METHOD(pqtxn, commit) {
2715 zend_error_handling zeh;
2716
2717 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2718 if (SUCCESS == zend_parse_parameters_none()) {
2719 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2720
2721 if (obj->intern) {
2722
2723 if (obj->intern->conn->intern) {
2724 PGresult *res = PQexec(obj->intern->conn->intern->conn, "COMMIT");
2725
2726 if (res) {
2727 php_pqres_success(res TSRMLS_CC);
2728 PQclear(res);
2729 } else {
2730 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not commit transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2731 }
2732 } else {
2733 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2734 }
2735 } else {
2736 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2737 }
2738 }
2739 zend_restore_error_handling(&zeh TSRMLS_CC);
2740 }
2741
2742 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async, 0, 0, 0)
2743 ZEND_END_ARG_INFO();
2744 static PHP_METHOD(pqtxn, commitAsync) {
2745 zend_error_handling zeh;
2746
2747 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2748 if (SUCCESS == zend_parse_parameters_none()) {
2749 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2750
2751 if (obj->intern) {
2752 if (obj->intern->conn->intern) {
2753 obj->intern->conn->intern->poller = PQconsumeInput;
2754
2755 if (!PQsendQuery(obj->intern->conn->intern->conn, "COMMIT")) {
2756 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not commit transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2757 }
2758 } else {
2759 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2760 }
2761 } else {
2762 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2763 }
2764 }
2765 zend_restore_error_handling(&zeh TSRMLS_CC);
2766 }
2767
2768 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback, 0, 0, 0)
2769 ZEND_END_ARG_INFO();
2770 static PHP_METHOD(pqtxn, rollback) {
2771 zend_error_handling zeh;
2772
2773 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2774 if (SUCCESS == zend_parse_parameters_none()) {
2775 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2776
2777 if (obj->intern) {
2778 if (obj->intern->conn->intern) {
2779 PGresult *res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK");
2780
2781 if (res) {
2782 php_pqres_success(res TSRMLS_CC);
2783 PQclear(res);
2784 } else {
2785 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not rollback transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2786 }
2787 } else {
2788 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2789 }
2790 } else {
2791 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2792 }
2793 }
2794 zend_restore_error_handling(&zeh TSRMLS_CC);
2795 }
2796
2797 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async, 0, 0, 0)
2798 ZEND_END_ARG_INFO();
2799 static PHP_METHOD(pqtxn, rollbackAsync) {
2800 zend_error_handling zeh;
2801
2802 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2803 if (SUCCESS == zend_parse_parameters_none()) {
2804 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2805
2806 if (obj->intern) {
2807 if (obj->intern->conn->intern) {
2808 obj->intern->conn->intern->poller = PQconsumeInput;
2809 if (!PQsendQuery(obj->intern->conn->intern->conn, "REOLLBACK")) {
2810 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not rollback transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2811 }
2812 } else {
2813 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2814 }
2815 } else {
2816 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2817 }
2818 }
2819 zend_restore_error_handling(&zeh TSRMLS_CC);
2820 }
2821
2822 static zend_function_entry php_pqtxn_methods[] = {
2823 PHP_ME(pqtxn, __construct, ai_pqtxn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2824 PHP_ME(pqtxn, commit, ai_pqtxn_commit, ZEND_ACC_PUBLIC)
2825 PHP_ME(pqtxn, rollback, ai_pqtxn_rollback, ZEND_ACC_PUBLIC)
2826 PHP_ME(pqtxn, commitAsync, ai_pqtxn_commit_async, ZEND_ACC_PUBLIC)
2827 PHP_ME(pqtxn, rollbackAsync, ai_pqtxn_rollback_async, ZEND_ACC_PUBLIC)
2828 {0}
2829 };
2830
2831 ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_construct, 0, 0, 1)
2832 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2833 ZEND_END_ARG_INFO();
2834 static PHP_METHOD(pqcancel, __construct) {
2835 zend_error_handling zeh;
2836 zval *zconn;
2837
2838 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2839 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zconn, php_pqconn_class_entry)) {
2840 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2841
2842 if (conn_obj->intern) {
2843 PGcancel *cancel = PQgetCancel(conn_obj->intern->conn);
2844
2845 if (cancel) {
2846 php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2847
2848 obj->intern = ecalloc(1, sizeof(*obj->intern));
2849 obj->intern->cancel = cancel;
2850 php_pq_object_addref(conn_obj TSRMLS_CC);
2851 obj->intern->conn = conn_obj;
2852 } else {
2853 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not acquire cancel: %s", PQerrorMessage(conn_obj->intern->conn));
2854 }
2855 } else {
2856 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2857 }
2858 }
2859 zend_restore_error_handling(&zeh TSRMLS_CC);
2860 }
2861
2862 ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_cancel, 0, 0, 0)
2863 ZEND_END_ARG_INFO();
2864 static PHP_METHOD(pqcancel, cancel) {
2865 zend_error_handling zeh;
2866
2867 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2868 if (SUCCESS == zend_parse_parameters_none()) {
2869 php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2870
2871 if (obj->intern) {
2872 char err[256];
2873
2874 if (!PQcancel(obj->intern->cancel, err, sizeof(err))) {
2875 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not request cancellation: %s", err);
2876 }
2877 } else {
2878 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Cancel not initialized");
2879 }
2880 }
2881 zend_restore_error_handling(&zeh TSRMLS_CC);
2882 }
2883
2884 static zend_function_entry php_pqcancel_methods[] = {
2885 PHP_ME(pqcancel, __construct, ai_pqcancel_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2886 PHP_ME(pqcancel, cancel, ai_pqcancel_cancel, ZEND_ACC_PUBLIC)
2887 {0}
2888 };
2889
2890 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)
2891 {
2892 zval **evhs;
2893
2894 if (SUCCESS == zend_hash_find(&conn_obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
2895 Z_ADDREF_P(zevent);
2896 add_next_index_zval(*evhs, zevent);
2897 } else {
2898 zval *evh;
2899
2900 MAKE_STD_ZVAL(evh);
2901 array_init(evh);
2902 Z_ADDREF_P(zevent);
2903 add_next_index_zval(evh, zevent);
2904 zend_hash_add(&conn_obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(zval *), NULL);
2905 }
2906 }
2907
2908 ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_construct, 0, 0, 3)
2909 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2910 ZEND_ARG_INFO(0, type)
2911 ZEND_ARG_INFO(0, callable)
2912 ZEND_END_ARG_INFO();
2913 static PHP_METHOD(pqevent, __construct) {
2914 zend_error_handling zeh;
2915 zval *zconn;
2916 char *type_str;
2917 int type_len;
2918 php_pq_callback_t cb;
2919
2920 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2921 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osf", &zconn, php_pqconn_class_entry, &type_str, &type_len, &cb.fci, &cb.fcc)) {
2922 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2923
2924 if (conn_obj->intern) {
2925 php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2926
2927 obj->intern = ecalloc(1, sizeof(*obj->intern));
2928 php_pq_callback_addref(&cb);
2929 obj->intern->cb = cb;
2930 php_pq_object_addref(conn_obj TSRMLS_CC);
2931 obj->intern->conn = conn_obj;
2932 obj->intern->type = estrdup(type_str);
2933
2934 php_pqconn_add_eventhandler(zconn, conn_obj, type_str, type_len, getThis() TSRMLS_CC);
2935
2936 } else {
2937 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2938 }
2939 }
2940 zend_restore_error_handling(&zeh TSRMLS_CC);
2941 }
2942
2943 ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_trigger, 0, 0, 1)
2944 ZEND_ARG_ARRAY_INFO(0, args, 1)
2945 ZEND_END_ARG_INFO();
2946 static PHP_METHOD(pqevent, trigger) {
2947 zval *args;
2948
2949 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &args)) {
2950 php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2951
2952 if (obj->intern) {
2953 zval *rv = NULL;
2954
2955 if (SUCCESS == zend_fcall_info_call(&obj->intern->cb.fci, &obj->intern->cb.fcc, &rv, args TSRMLS_CC)) {
2956 if (rv) {
2957 RETVAL_ZVAL(rv, 0, 1);
2958 } else {
2959 RETVAL_TRUE;
2960 }
2961 }
2962 } else {
2963 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Event not initialized");
2964 RETVAL_FALSE;
2965 }
2966 }
2967 }
2968
2969 static zend_function_entry php_pqevent_methods[] = {
2970 PHP_ME(pqevent, __construct, ai_pqevent_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2971 PHP_ME(pqevent, trigger, ai_pqevent_trigger, ZEND_ACC_PUBLIC)
2972 {0}
2973 };
2974
2975 /* {{{ PHP_MINIT_FUNCTION
2976 */
2977 static PHP_MINIT_FUNCTION(pq)
2978 {
2979 zend_class_entry ce = {0};
2980 php_pq_object_prophandler_t ph = {0};
2981
2982 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
2983 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
2984 php_pqconn_class_entry->create_object = php_pqconn_create_object;
2985
2986 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2987 php_pqconn_object_handlers.read_property = php_pq_object_read_prop;
2988 php_pqconn_object_handlers.write_property = php_pq_object_write_prop;
2989 php_pqconn_object_handlers.clone_obj = NULL;
2990 php_pqconn_object_handlers.get_property_ptr_ptr = NULL;
2991 php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info;
2992
2993 zend_hash_init(&php_pqconn_object_prophandlers, 14, NULL, NULL, 1);
2994
2995 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
2996 ph.read = php_pqconn_object_read_status;
2997 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
2998
2999 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
3000 ph.read = php_pqconn_object_read_transaction_status;
3001 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
3002
3003 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
3004 ph.read = NULL; /* forward to std prophandler */
3005 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
3006
3007 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
3008 ph.read = php_pqconn_object_read_error_message;
3009 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
3010
3011 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("types"), ZEND_ACC_PUBLIC TSRMLS_CC);
3012 ph.read = php_pqconn_object_read_types;
3013 zend_hash_add(&php_pqconn_object_prophandlers, "types", sizeof("types"), (void *) &ph, sizeof(ph), NULL);
3014
3015 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
3016 ph.read = php_pqconn_object_read_busy;
3017 zend_hash_add(&php_pqconn_object_prophandlers, "busy", sizeof("busy"), (void *) &ph, sizeof(ph), NULL);
3018
3019 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC TSRMLS_CC);
3020 ph.read = php_pqconn_object_read_encoding;
3021 ph.write = php_pqconn_object_write_encoding;
3022 zend_hash_add(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding"), (void *) &ph, sizeof(ph), NULL);
3023 ph.write = NULL;
3024
3025 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
3026 ph.read = php_pqconn_object_read_unbuffered;
3027 ph.write = php_pqconn_object_write_unbuffered;
3028 zend_hash_add(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered"), (void *) &ph, sizeof(ph), NULL);
3029 ph.write = NULL;
3030
3031 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC TSRMLS_CC);
3032 ph.read = php_pqconn_object_read_db;
3033 zend_hash_add(&php_pqconn_object_prophandlers, "db", sizeof("db"), (void *) &ph, sizeof(ph), NULL);
3034
3035 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC);
3036 ph.read = php_pqconn_object_read_user;
3037 zend_hash_add(&php_pqconn_object_prophandlers, "user", sizeof("user"), (void *) &ph, sizeof(ph), NULL);
3038
3039 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC);
3040 ph.read = php_pqconn_object_read_pass;
3041 zend_hash_add(&php_pqconn_object_prophandlers, "pass", sizeof("pass"), (void *) &ph, sizeof(ph), NULL);
3042
3043 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
3044 ph.read = php_pqconn_object_read_host;
3045 zend_hash_add(&php_pqconn_object_prophandlers, "host", sizeof("host"), (void *) &ph, sizeof(ph), NULL);
3046
3047 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC);
3048 ph.read = php_pqconn_object_read_port;
3049 zend_hash_add(&php_pqconn_object_prophandlers, "port", sizeof("port"), (void *) &ph, sizeof(ph), NULL);
3050
3051 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC TSRMLS_CC);
3052 ph.read = php_pqconn_object_read_options;
3053 zend_hash_add(&php_pqconn_object_prophandlers, "options", sizeof("options"), (void *) &ph, sizeof(ph), NULL);
3054
3055 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
3056 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
3057 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
3058 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
3059 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
3060 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
3061 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
3062 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
3063
3064 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
3065 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
3066 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
3067 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
3068 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
3069
3070 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
3071 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
3072 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
3073 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
3074
3075 memset(&ce, 0, sizeof(ce));
3076 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
3077 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
3078 php_pqres_class_entry->create_object = php_pqres_create_object;
3079 php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs;
3080 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
3081 zend_class_implements(php_pqres_class_entry TSRMLS_CC, 1, zend_ce_traversable);
3082
3083 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3084 php_pqres_object_handlers.read_property = php_pq_object_read_prop;
3085 php_pqres_object_handlers.write_property = php_pq_object_write_prop;
3086 php_pqres_object_handlers.clone_obj = NULL;
3087 php_pqres_object_handlers.get_property_ptr_ptr = NULL;
3088 php_pqres_object_handlers.get_debug_info = php_pq_object_debug_info;
3089
3090 zend_hash_init(&php_pqres_object_prophandlers, 6, NULL, NULL, 1);
3091
3092 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
3093 ph.read = php_pqres_object_read_status;
3094 zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
3095
3096 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
3097 ph.read = php_pqres_object_read_error_message;
3098 zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
3099
3100 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
3101 ph.read = php_pqres_object_read_num_rows;
3102 zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL);
3103
3104 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
3105 ph.read = php_pqres_object_read_num_cols;
3106 zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL);
3107
3108 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
3109 ph.read = php_pqres_object_read_affected_rows;
3110 zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL);
3111
3112 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);