1fe45971a95d0fe66703b8a0928c0571d3247d7a
[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_pqres_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
904 {
905 php_pqres_object_t *obj = o;
906
907 RETVAL_LONG(PQresultStatus(obj->intern->res));
908 }
909
910 static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
911 {
912 php_pqres_object_t *obj = o;
913 char *error = PQresultErrorMessage(obj->intern->res);
914
915 if (error) {
916 RETVAL_STRING(error, 1);
917 } else {
918 RETVAL_NULL();
919 }
920 }
921
922 static void php_pqres_object_read_num_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
923 {
924 php_pqres_object_t *obj = o;
925
926 RETVAL_LONG(PQntuples(obj->intern->res));
927 }
928
929 static void php_pqres_object_read_num_cols(zval *object, void *o, zval *return_value TSRMLS_DC)
930 {
931 php_pqres_object_t *obj = o;
932
933 RETVAL_LONG(PQnfields(obj->intern->res));
934 }
935
936 static void php_pqres_object_read_affected_rows(zval *object, void *o, zval *return_value TSRMLS_DC)
937 {
938 php_pqres_object_t *obj = o;
939
940 RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res)));
941 }
942
943 static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return_value TSRMLS_DC)
944 {
945 php_pqres_object_t *obj = o;
946
947 if (obj->intern->iter) {
948 RETVAL_LONG(obj->intern->iter->fetch_type);
949 } else {
950 RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
951 }
952 }
953
954 static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value TSRMLS_DC)
955 {
956 php_pqres_object_t *obj = o;
957 zval *zfetch_type = value;
958
959 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
960 convert_to_long_ex(&zfetch_type);
961 }
962
963 if (!obj->intern->iter) {
964 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC);
965 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
966 }
967 obj->intern->iter->fetch_type = Z_LVAL_P(zfetch_type);
968
969 if (zfetch_type != value) {
970 zval_ptr_dtor(&zfetch_type);
971 }
972 }
973
974 static void php_pqstm_object_read_name(zval *object, void *o, zval *return_value TSRMLS_DC)
975 {
976 php_pqstm_object_t *obj = o;
977
978 RETVAL_STRING(obj->intern->name, 1);
979 }
980
981 static void php_pqstm_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
982 {
983 php_pqstm_object_t *obj = o;
984
985 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
986 }
987
988 static void php_pqtxn_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
989 {
990 php_pqtxn_object_t *obj = o;
991
992 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
993 }
994
995 static void php_pqtxn_object_read_isolation(zval *object, void *o, zval *return_value TSRMLS_DC)
996 {
997 php_pqtxn_object_t *obj = o;
998
999 RETVAL_LONG(obj->intern->isolation);
1000 }
1001
1002 static void php_pqtxn_object_read_readonly(zval *object, void *o, zval *return_value TSRMLS_DC)
1003 {
1004 php_pqtxn_object_t *obj = o;
1005
1006 RETVAL_LONG(obj->intern->readonly);
1007 }
1008
1009 static void php_pqtxn_object_read_deferrable(zval *object, void *o, zval *return_value TSRMLS_DC)
1010 {
1011 php_pqtxn_object_t *obj = o;
1012
1013 RETVAL_LONG(obj->intern->deferrable);
1014 }
1015
1016 static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value TSRMLS_DC)
1017 {
1018 php_pqtxn_object_t *obj = o;
1019 php_pqtxn_isolation_t orig = obj->intern->isolation;
1020 zval *zisolation = value;
1021 PGresult *res;
1022
1023 if (Z_TYPE_P(zisolation) != IS_LONG) {
1024 convert_to_long_ex(&zisolation);
1025 }
1026
1027 switch ((obj->intern->isolation = Z_LVAL_P(zisolation))) {
1028 case PHP_PQTXN_READ_COMMITTED:
1029 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ COMMITED");
1030 break;
1031 case PHP_PQTXN_REPEATABLE_READ:
1032 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION REPEATABLE READ");
1033 break;
1034 case PHP_PQTXN_SERIALIZABLE:
1035 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION SERIALIZABLE");
1036 break;
1037 default:
1038 obj->intern->isolation = orig;
1039 res = NULL;
1040 break;
1041 }
1042
1043 if (zisolation != value) {
1044 zval_ptr_dtor(&zisolation);
1045 }
1046
1047 if (res) {
1048 php_pqres_success(res TSRMLS_CC);
1049 PQclear(res);
1050 }
1051 }
1052
1053 static void php_pqtxn_object_write_readonly(zval *object, void *o, zval *value TSRMLS_DC)
1054 {
1055 php_pqtxn_object_t *obj = o;
1056 PGresult *res;
1057
1058 if ((obj->intern->readonly = zend_is_true(value))) {
1059 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY");
1060 } else {
1061 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE");
1062 }
1063
1064 if (res) {
1065 php_pqres_success(res TSRMLS_CC);
1066 PQclear(res);
1067 }
1068 }
1069
1070 static void php_pqtxn_object_write_deferrable(zval *object, void *o, zval *value TSRMLS_DC)
1071 {
1072 php_pqtxn_object_t *obj = o;
1073 PGresult *res;
1074
1075 if ((obj->intern->deferrable = zend_is_true(value))) {
1076 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE");
1077 } else {
1078 res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE");
1079 }
1080
1081 if (res) {
1082 php_pqres_success(res TSRMLS_CC);
1083 PQclear(res);
1084 }
1085 }
1086
1087 static void php_pqcancel_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1088 {
1089 php_pqcancel_object_t *obj = o;
1090
1091 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1092 }
1093
1094 static void php_pqevent_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
1095 {
1096 php_pqevent_object_t *obj = o;
1097
1098 php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
1099 }
1100
1101 static void php_pqevent_object_read_type(zval *object, void *o, zval *return_value TSRMLS_DC)
1102 {
1103 php_pqevent_object_t *obj = o;
1104
1105 RETVAL_STRING(obj->intern->type, 1);
1106 }
1107
1108 static zend_class_entry *ancestor(zend_class_entry *ce) {
1109 while (ce->parent) {
1110 ce = ce->parent;
1111 }
1112 return ce;
1113 }
1114
1115 static zval *php_pq_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
1116 {
1117 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1118 php_pq_object_prophandler_t *handler;
1119 zval *return_value;
1120
1121 if (!obj->intern) {
1122 zend_error(E_WARNING, "%s not initialized", ancestor(obj->zo.ce)->name);
1123 } else if ((SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) && handler->read) {
1124 if (type == BP_VAR_R) {
1125 ALLOC_ZVAL(return_value);
1126 Z_SET_REFCOUNT_P(return_value, 0);
1127 Z_UNSET_ISREF_P(return_value);
1128
1129 handler->read(object, obj, return_value TSRMLS_CC);
1130 } else {
1131 zend_error(E_ERROR, "Cannot access %s properties by reference or array key/index", ancestor(obj->zo.ce)->name);
1132 return_value = NULL;
1133 }
1134 } else {
1135 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
1136 }
1137
1138 return return_value;
1139 }
1140
1141 static void php_pq_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
1142 {
1143 php_pq_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
1144 php_pq_object_prophandler_t *handler;
1145
1146 if (SUCCESS == zend_hash_find(obj->prophandler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
1147 if (handler->write) {
1148 handler->write(object, obj, value TSRMLS_CC);
1149 }
1150 } else {
1151 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
1152 }
1153 }
1154
1155 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
1156 {
1157 zval *zsocket, zmember;
1158 php_stream *stream;
1159 STATUS retval;
1160 int socket;
1161
1162 if (!obj) {
1163 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1164 }
1165
1166 INIT_PZVAL(&zmember);
1167 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
1168 MAKE_STD_ZVAL(zsocket);
1169
1170 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
1171 && (-1 < (socket = PQsocket(obj->intern->conn)))
1172 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
1173 php_stream_to_zval(stream, zsocket);
1174 retval = SUCCESS;
1175 } else {
1176 ZVAL_NULL(zsocket);
1177 retval = FAILURE;
1178 }
1179 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
1180 zval_ptr_dtor(&zsocket);
1181
1182 return retval;
1183 }
1184
1185 #ifdef ZTS
1186 # define TSRMLS_DF(d) TSRMLS_D = (d)->ts
1187 # define TSRMLS_CF(d) (d)->ts = TSRMLS_C
1188 #else
1189 # define TSRMLS_DF(d)
1190 # define TSRMLS_CF(d)
1191 #endif
1192
1193 static void php_pqconn_event_register(PGEventRegister *event, php_pqconn_event_data_t *data)
1194 {
1195 PQsetInstanceData(event->conn, php_pqconn_event, data);
1196 }
1197
1198 static void php_pqconn_event_conndestroy(PGEventConnDestroy *event, php_pqconn_event_data_t *data)
1199 {
1200 PQsetInstanceData(event->conn, php_pqconn_event, NULL);
1201 efree(data);
1202 }
1203
1204 static zval *result_instance_zval(PGresult *res TSRMLS_DC)
1205 {
1206 zval *rid = PQresultInstanceData(res, php_pqconn_event);
1207
1208 if (!rid) {
1209 php_pqres_t *r = ecalloc(1, sizeof(*r));
1210
1211 MAKE_STD_ZVAL(rid);
1212 r->res = res;
1213 rid->type = IS_OBJECT;
1214 rid->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1215
1216 PQresultSetInstanceData(res, php_pqconn_event, rid);
1217 }
1218
1219 Z_ADDREF_P(rid);
1220 return rid;
1221 }
1222
1223 static int apply_event(void *p, void *a TSRMLS_DC)
1224 {
1225 zval **evh = p;
1226 zval *args = a;
1227 zval *retval = NULL;
1228
1229 zend_call_method_with_1_params(evh, Z_OBJCE_PP(evh), NULL, "trigger", &retval, args);
1230 if (retval) {
1231 zval_ptr_dtor(&retval);
1232 }
1233
1234 return ZEND_HASH_APPLY_KEEP;
1235 }
1236
1237 static void php_pqconn_event_resultcreate(PGEventResultCreate *event, php_pqconn_event_data_t *data)
1238 {
1239 zval **evhs;
1240 TSRMLS_DF(data);
1241
1242 /* event listener */
1243 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) {
1244 zval *args, *connection = NULL, *res = result_instance_zval(event->result TSRMLS_CC);
1245
1246 MAKE_STD_ZVAL(args);
1247 array_init(args);
1248 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1249 add_next_index_zval(args, connection);
1250 add_next_index_zval(args, res);
1251 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1252 zval_ptr_dtor(&args);
1253 }
1254
1255 /* async callback */
1256 if (data->obj->intern->onevent.fci.size > 0) {
1257 zval *res = result_instance_zval(event->result TSRMLS_CC);
1258
1259 zend_fcall_info_argn(&data->obj->intern->onevent.fci TSRMLS_CC, 1, &res);
1260 zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL TSRMLS_CC);
1261 zval_ptr_dtor(&res);
1262 }
1263 }
1264
1265 static int php_pqconn_event(PGEventId id, void *e, void *data)
1266 {
1267 switch (id) {
1268 case PGEVT_REGISTER:
1269 php_pqconn_event_register(e, data);
1270 break;
1271 case PGEVT_CONNDESTROY:
1272 php_pqconn_event_conndestroy(e, data);
1273 break;
1274 case PGEVT_RESULTCREATE:
1275 php_pqconn_event_resultcreate(e, data);
1276 break;
1277 default:
1278 break;
1279 }
1280
1281 return 1;
1282 }
1283
1284 static php_pqconn_event_data_t *php_pqconn_event_data_init(php_pqconn_object_t *obj TSRMLS_DC)
1285 {
1286 php_pqconn_event_data_t *data = emalloc(sizeof(*data));
1287
1288 data->obj = obj;
1289 TSRMLS_CF(data);
1290
1291 return data;
1292 }
1293
1294 static void php_pqconn_notice_recv(void *p, const PGresult *res)
1295 {
1296 php_pqconn_event_data_t *data = p;
1297 zval **evhs;
1298 TSRMLS_DF(data);
1299
1300 if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("notice"), (void *) &evhs)) {
1301 zval *args, *connection = NULL;
1302
1303 MAKE_STD_ZVAL(args);
1304 array_init(args);
1305 php_pq_object_to_zval(data->obj, &connection TSRMLS_CC);
1306 add_next_index_zval(args, connection);
1307 add_next_index_string(args, PQresultErrorMessage(res), 1);
1308 zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC);
1309 zval_ptr_dtor(&args);
1310 }
1311 }
1312
1313 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
1314 ZEND_ARG_INFO(0, dsn)
1315 ZEND_ARG_INFO(0, async)
1316 ZEND_END_ARG_INFO();
1317 static PHP_METHOD(pqconn, __construct) {
1318 zend_error_handling zeh;
1319 char *dsn_str;
1320 int dsn_len;
1321 zend_bool async = 0;
1322
1323 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1324 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &dsn_str, &dsn_len, &async)) {
1325 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1326 php_pqconn_event_data_t *data = php_pqconn_event_data_init(obj TSRMLS_CC);
1327
1328 obj->intern = ecalloc(1, sizeof(*obj->intern));
1329
1330 zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
1331 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);
1332
1333
1334 if (async) {
1335 obj->intern->conn = PQconnectStart(dsn_str);
1336 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
1337 } else {
1338 obj->intern->conn = PQconnectdb(dsn_str);
1339 }
1340
1341 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, data);
1342 PQregisterEventProc(obj->intern->conn, php_pqconn_event, "ext-pq", data);
1343
1344 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
1345 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection failed: %s", PQerrorMessage(obj->intern->conn));
1346 }
1347 }
1348 zend_restore_error_handling(&zeh TSRMLS_CC);
1349 }
1350
1351 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
1352 ZEND_END_ARG_INFO();
1353 static PHP_METHOD(pqconn, reset) {
1354 if (SUCCESS == zend_parse_parameters_none()) {
1355 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1356
1357 if (obj->intern) {
1358 PQreset(obj->intern->conn);
1359
1360 if (CONNECTION_OK == PQstatus(obj->intern->conn)) {
1361 RETURN_TRUE;
1362 } else {
1363 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection reset failed: %s", PQerrorMessage(obj->intern->conn));
1364 }
1365 } else {
1366 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1367 }
1368 RETURN_FALSE;
1369 }
1370 }
1371
1372 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
1373 ZEND_END_ARG_INFO();
1374 static PHP_METHOD(pqconn, resetAsync) {
1375 if (SUCCESS == zend_parse_parameters_none()) {
1376 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1377
1378 if (obj->intern) {
1379 if (PQresetStart(obj->intern->conn)) {
1380 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
1381 RETURN_TRUE;
1382 }
1383 } else {
1384 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1385 }
1386 RETURN_FALSE;
1387 }
1388 }
1389
1390 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)
1391 {
1392 HashTable ht, *existing_listeners;
1393
1394 php_pq_callback_addref(listener);
1395
1396 if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
1397 zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
1398 } else {
1399 zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
1400 zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
1401 zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
1402 }
1403 }
1404
1405 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
1406 ZEND_ARG_INFO(0, channel)
1407 ZEND_ARG_INFO(0, callable)
1408 ZEND_END_ARG_INFO();
1409 static PHP_METHOD(pqconn, listen) {
1410 char *channel_str = NULL;
1411 int channel_len = 0;
1412 php_pq_callback_t listener;
1413
1414 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc)) {
1415 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1416
1417 obj->intern->poller = PQconsumeInput;
1418
1419 if (obj->intern) {
1420 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
1421
1422 if (quoted_channel) {
1423 PGresult *res;
1424 char *cmd;
1425
1426 spprintf(&cmd, 0, "LISTEN %s", channel_str);
1427 res = PQexec(obj->intern->conn, cmd);
1428
1429 efree(cmd);
1430 PQfreemem(quoted_channel);
1431
1432 if (res) {
1433 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1434 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
1435 RETVAL_TRUE;
1436 } else {
1437 RETVAL_FALSE;
1438 }
1439 PQclear(res);
1440 } else {
1441 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not install listener: %s", PQerrorMessage(obj->intern->conn));
1442 RETVAL_FALSE;
1443 }
1444
1445 php_pqconn_notify_listeners(obj TSRMLS_CC);
1446 } else {
1447 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape channel identifier: %s", PQerrorMessage(obj->intern->conn));
1448 }
1449 } else {
1450 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1451 RETVAL_FALSE;
1452 }
1453 }
1454 }
1455
1456 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
1457 ZEND_ARG_INFO(0, channel)
1458 ZEND_ARG_INFO(0, message)
1459 ZEND_END_ARG_INFO();
1460 static PHP_METHOD(pqconn, notify) {
1461 char *channel_str, *message_str;
1462 int channel_len, message_len;
1463
1464 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len)) {
1465 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1466
1467 if (obj->intern) {
1468 PGresult *res;
1469 char *params[2] = {channel_str, message_str};
1470
1471 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
1472
1473 if (res) {
1474 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1475 RETVAL_TRUE;
1476 } else {
1477 RETVAL_FALSE;
1478 }
1479 PQclear(res);
1480 } else {
1481 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not notify listeners: %s", PQerrorMessage(obj->intern->conn));
1482 RETVAL_FALSE;
1483 }
1484
1485 php_pqconn_notify_listeners(obj TSRMLS_CC);
1486
1487 } else {
1488 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1489 RETVAL_FALSE;
1490 }
1491 }
1492 }
1493
1494 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
1495 ZEND_END_ARG_INFO();
1496 static PHP_METHOD(pqconn, poll) {
1497 if (SUCCESS == zend_parse_parameters_none()) {
1498 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1499
1500 if (obj->intern) {
1501 if (obj->intern->poller) {
1502 if (obj->intern->poller == PQconsumeInput) {
1503 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
1504 php_pqconn_notify_listeners(obj TSRMLS_CC);
1505 return;
1506 } else {
1507 RETURN_LONG(obj->intern->poller(obj->intern->conn));
1508 }
1509 } else {
1510 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active");
1511 }
1512 } else {
1513 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1514 }
1515 RETURN_FALSE;
1516 }
1517 }
1518
1519 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
1520 ZEND_ARG_INFO(0, query)
1521 ZEND_END_ARG_INFO();
1522 static PHP_METHOD(pqconn, exec) {
1523 zend_error_handling zeh;
1524 char *query_str;
1525 int query_len;
1526
1527 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1528 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) {
1529 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1530
1531 if (obj->intern) {
1532 PGresult *res = PQexec(obj->intern->conn, query_str);
1533
1534 php_pqconn_notify_listeners(obj TSRMLS_CC);
1535
1536 if (res) {
1537 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1538 php_pqres_t *r = ecalloc(1, sizeof(*r));
1539
1540 r->res = res;
1541 return_value->type = IS_OBJECT;
1542 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1543 }
1544 } else {
1545 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1546 }
1547 } else {
1548 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1549 }
1550 }
1551 zend_restore_error_handling(&zeh TSRMLS_CC);
1552 }
1553
1554 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
1555 ZEND_END_ARG_INFO();
1556 static PHP_METHOD(pqconn, getResult) {
1557 if (SUCCESS == zend_parse_parameters_none()) {
1558 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1559
1560 if (obj->intern) {
1561 PGresult *res = PQgetResult(obj->intern->conn);
1562
1563 if (res) {
1564 php_pqres_t *r = ecalloc(1, sizeof(*r));
1565
1566 r->res = res;
1567 return_value->type = IS_OBJECT;
1568 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1569 } else {
1570 RETVAL_NULL();
1571 }
1572 } else {
1573 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1574 RETVAL_FALSE;
1575 }
1576 }
1577 }
1578
1579 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
1580 ZEND_ARG_INFO(0, query)
1581 ZEND_ARG_INFO(0, callable)
1582 ZEND_END_ARG_INFO();
1583 static PHP_METHOD(pqconn, execAsync) {
1584 zend_error_handling zeh;
1585 php_pq_callback_t resolver = {{0}};
1586 char *query_str;
1587 int query_len;
1588
1589 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1590 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc)) {
1591 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1592
1593 if (obj->intern) {
1594 php_pq_callback_dtor(&obj->intern->onevent);
1595 if (resolver.fci.size > 0) {
1596 obj->intern->onevent = resolver;
1597 php_pq_callback_addref(&obj->intern->onevent);
1598 }
1599
1600 obj->intern->poller = PQconsumeInput;
1601
1602 if (PQsendQuery(obj->intern->conn, query_str)) {
1603 if (obj->intern->unbuffered) {
1604 if (!PQsetSingleRowMode(obj->intern->conn)) {
1605 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn));
1606 }
1607 }
1608 RETVAL_TRUE;
1609 } else {
1610 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1611 RETVAL_FALSE;
1612 }
1613 } else {
1614 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1615 RETVAL_FALSE;
1616 }
1617 }
1618 zend_restore_error_handling(&zeh TSRMLS_CC);
1619 }
1620
1621 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
1622 {
1623 Oid **types = arg;
1624 zval **ztype = p;
1625
1626 if (Z_TYPE_PP(ztype) != IS_LONG) {
1627 convert_to_long_ex(ztype);
1628 }
1629
1630 **types = Z_LVAL_PP(ztype);
1631 ++*types;
1632
1633 if (*ztype != *(zval **)p) {
1634 zval_ptr_dtor(ztype);
1635 }
1636 return ZEND_HASH_APPLY_KEEP;
1637 }
1638
1639 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1640 {
1641 char ***params;
1642 HashTable *zdtor;
1643 zval **zparam = p;
1644
1645 params = (char ***) va_arg(argv, char ***);
1646 zdtor = (HashTable *) va_arg(argv, HashTable *);
1647
1648 if (Z_TYPE_PP(zparam) == IS_NULL) {
1649 **params = NULL;
1650 ++*params;
1651 } else {
1652 if (Z_TYPE_PP(zparam) != IS_STRING) {
1653 convert_to_string_ex(zparam);
1654 }
1655
1656 **params = Z_STRVAL_PP(zparam);
1657 ++*params;
1658
1659 if (*zparam != *(zval **)p) {
1660 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
1661 }
1662 }
1663 return ZEND_HASH_APPLY_KEEP;
1664 }
1665
1666 static int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC)
1667 {
1668 int count = zend_hash_num_elements(ht);
1669
1670 *types = NULL;
1671
1672 if (count) {
1673 Oid *tmp;
1674
1675 /* +1 for when less types than params are specified */
1676 *types = tmp = ecalloc(count + 1, sizeof(Oid));
1677 zend_hash_apply_with_argument(ht, apply_to_oid, &tmp TSRMLS_CC);
1678 }
1679
1680 return count;
1681 }
1682
1683 static int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC)
1684 {
1685 int count = zend_hash_num_elements(ht);
1686
1687 *params = NULL;
1688
1689 if (count) {
1690 char **tmp;
1691
1692 *params = tmp = ecalloc(count, sizeof(char *));
1693 zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_param, 2, &tmp, zdtor);
1694 }
1695
1696 return count;
1697 }
1698
1699 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
1700 ZEND_ARG_INFO(0, query)
1701 ZEND_ARG_ARRAY_INFO(0, params, 0)
1702 ZEND_ARG_ARRAY_INFO(0, types, 1)
1703 ZEND_END_ARG_INFO();
1704 static PHP_METHOD(pqconn, execParams) {
1705 zend_error_handling zeh;
1706 char *query_str;
1707 int query_len;
1708 zval *zparams;
1709 zval *ztypes = NULL;
1710
1711 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1712 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
1713 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1714
1715 if (obj->intern) {
1716 PGresult *res;
1717 int count;
1718 Oid *types = NULL;
1719 char **params = NULL;
1720 HashTable zdtor;
1721
1722 ZEND_INIT_SYMTABLE(&zdtor);
1723 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
1724
1725 if (ztypes) {
1726 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
1727 }
1728
1729 res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
1730
1731 zend_hash_destroy(&zdtor);
1732 if (types) {
1733 efree(types);
1734 }
1735 if (params) {
1736 efree(params);
1737 }
1738
1739 php_pqconn_notify_listeners(obj TSRMLS_CC);
1740
1741 if (res) {
1742 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1743 php_pqres_t *r = ecalloc(1, sizeof(*r));
1744
1745 r->res = res;
1746 return_value->type = IS_OBJECT;
1747 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
1748 }
1749 } else {
1750 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1751 RETVAL_FALSE;
1752 }
1753 } else {
1754 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1755 RETVAL_FALSE;
1756 }
1757 }
1758 zend_restore_error_handling(&zeh TSRMLS_CC);
1759 }
1760
1761 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
1762 ZEND_ARG_INFO(0, query)
1763 ZEND_ARG_ARRAY_INFO(0, params, 0)
1764 ZEND_ARG_ARRAY_INFO(0, types, 1)
1765 ZEND_ARG_INFO(0, callable)
1766 ZEND_END_ARG_INFO();
1767 static PHP_METHOD(pqconn, execParamsAsync) {
1768 zend_error_handling zeh;
1769 php_pq_callback_t resolver = {{0}};
1770 char *query_str;
1771 int query_len;
1772 zval *zparams;
1773 zval *ztypes = NULL;
1774
1775 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1776 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc)) {
1777 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1778
1779 if (obj->intern) {
1780 int count;
1781 Oid *types = NULL;
1782 char **params = NULL;
1783 HashTable zdtor;
1784
1785 ZEND_INIT_SYMTABLE(&zdtor);
1786 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
1787
1788 if (ztypes) {
1789 php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC);
1790 }
1791
1792 php_pq_callback_dtor(&obj->intern->onevent);
1793 if (resolver.fci.size > 0) {
1794 obj->intern->onevent = resolver;
1795 php_pq_callback_addref(&obj->intern->onevent);
1796 }
1797
1798 obj->intern->poller = PQconsumeInput;
1799
1800 if (PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) {
1801 if (obj->intern->unbuffered) {
1802 if (!PQsetSingleRowMode(obj->intern->conn)) {
1803 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn));
1804 }
1805 }
1806 RETVAL_TRUE;
1807 } else {
1808 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->intern->conn));
1809 RETVAL_FALSE;
1810 }
1811
1812 zend_hash_destroy(&zdtor);
1813 if (types) {
1814 efree(types);
1815 }
1816 if (params) {
1817 efree(params);
1818 }
1819
1820 php_pqconn_notify_listeners(obj TSRMLS_CC);
1821
1822 } else {
1823 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1824 RETVAL_FALSE;
1825 }
1826 }
1827 zend_restore_error_handling(&zeh TSRMLS_CC);
1828 }
1829
1830 static STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
1831 {
1832 Oid *types = NULL;
1833 int count = 0;
1834 PGresult *res;
1835 STATUS rv;
1836
1837 if (!obj) {
1838 obj = zend_object_store_get_object(object TSRMLS_CC);
1839 }
1840
1841 if (typest) {
1842 count = zend_hash_num_elements(typest);
1843 php_pq_types_to_array(typest, &types TSRMLS_CC);
1844 }
1845
1846 res = PQprepare(obj->intern->conn, name, query, count, types);
1847
1848 if (types) {
1849 efree(types);
1850 }
1851
1852 if (res) {
1853 rv = php_pqres_success(res TSRMLS_CC);
1854 PQclear(res);
1855 } else {
1856 rv = FAILURE;
1857 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(obj->intern->conn));
1858 }
1859
1860 return rv;
1861 }
1862
1863 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
1864 ZEND_ARG_INFO(0, type)
1865 ZEND_ARG_INFO(0, query)
1866 ZEND_ARG_ARRAY_INFO(0, types, 1)
1867 ZEND_END_ARG_INFO();
1868 static PHP_METHOD(pqconn, prepare) {
1869 zend_error_handling zeh;
1870 zval *ztypes = NULL;
1871 char *name_str, *query_str;
1872 int name_len, *query_len;
1873
1874 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1875 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
1876 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1877
1878 if (obj->intern) {
1879 if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1880 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1881
1882 php_pq_object_addref(obj TSRMLS_CC);
1883 stm->conn = obj;
1884 stm->name = estrdup(name_str);
1885
1886 return_value->type = IS_OBJECT;
1887 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1888 }
1889 php_pqconn_notify_listeners(obj TSRMLS_CC);
1890 } else {
1891 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1892 }
1893 }
1894 zend_restore_error_handling(&zeh TSRMLS_CC);
1895 }
1896
1897 static STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC)
1898 {
1899 STATUS rv;
1900 int count;
1901 Oid *types = NULL;
1902
1903 if (!obj) {
1904 obj = zend_object_store_get_object(object TSRMLS_CC);
1905 }
1906
1907 if (typest) {
1908 count = php_pq_types_to_array(typest, &types TSRMLS_CC);
1909 }
1910
1911 if (PQsendPrepare(obj->intern->conn, name, query, count, types)) {
1912 if (obj->intern->unbuffered) {
1913 if (!PQsetSingleRowMode(obj->intern->conn)) {
1914 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn));
1915 }
1916 }
1917 rv = SUCCESS;
1918 } else {
1919 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(obj->intern->conn));
1920 rv = FAILURE;
1921 }
1922
1923 if (types) {
1924 efree(types);
1925 }
1926
1927 return rv;
1928 }
1929
1930 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
1931 ZEND_ARG_INFO(0, type)
1932 ZEND_ARG_INFO(0, query)
1933 ZEND_ARG_ARRAY_INFO(0, types, 1)
1934 ZEND_END_ARG_INFO();
1935 static PHP_METHOD(pqconn, prepareAsync) {
1936 zend_error_handling zeh;
1937 zval *ztypes = NULL;
1938 char *name_str, *query_str;
1939 int name_len, *query_len;
1940
1941 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1942 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
1943 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1944
1945 if (obj->intern) {
1946 obj->intern->poller = PQconsumeInput;
1947 if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1948 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1949
1950 php_pq_object_addref(obj TSRMLS_CC);
1951 stm->conn = obj;
1952 stm->name = estrdup(name_str);
1953
1954 return_value->type = IS_OBJECT;
1955 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1956 }
1957 php_pqconn_notify_listeners(obj TSRMLS_CC);
1958 } else {
1959 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1960 }
1961 }
1962 zend_restore_error_handling(&zeh TSRMLS_CC);
1963 }
1964
1965 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
1966 ZEND_ARG_INFO(0, string)
1967 ZEND_END_ARG_INFO();
1968 static PHP_METHOD(pqconn, quote) {
1969 char *str;
1970 int len;
1971
1972 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1973 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1974
1975 if (obj->intern) {
1976 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
1977
1978 if (quoted) {
1979 RETVAL_STRING(quoted, 1);
1980 PQfreemem(quoted);
1981 } else {
1982 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote string: %s", PQerrorMessage(obj->intern->conn));
1983 RETVAL_FALSE;
1984 }
1985 } else {
1986 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
1987 RETVAL_FALSE;
1988 }
1989 }
1990 }
1991
1992 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
1993 ZEND_ARG_INFO(0, type)
1994 ZEND_END_ARG_INFO();
1995 static PHP_METHOD(pqconn, quoteName) {
1996 char *str;
1997 int len;
1998
1999 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2000 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2001
2002 if (obj->intern) {
2003 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
2004
2005 if (quoted) {
2006 RETVAL_STRING(quoted, 1);
2007 PQfreemem(quoted);
2008 } else {
2009 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote name: %s", PQerrorMessage(obj->intern->conn));
2010 RETVAL_FALSE;
2011 }
2012 } else {
2013 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2014 RETVAL_FALSE;
2015 }
2016 }
2017 }
2018
2019 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
2020 ZEND_ARG_INFO(0, bytea)
2021 ZEND_END_ARG_INFO();
2022 static PHP_METHOD(pqconn, escapeBytea) {
2023 char *str;
2024 int len;
2025
2026 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2027 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2028
2029 if (obj->intern) {
2030 size_t escaped_len;
2031 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
2032
2033 if (escaped_str) {
2034 RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
2035 PQfreemem(escaped_str);
2036 } else {
2037 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape bytea: %s", PQerrorMessage(obj->intern->conn));
2038 RETVAL_FALSE;
2039 }
2040 } else {
2041 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2042 RETVAL_FALSE;
2043 }
2044 }
2045 }
2046
2047 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
2048 ZEND_ARG_INFO(0, bytea)
2049 ZEND_END_ARG_INFO();
2050 static PHP_METHOD(pqconn, unescapeBytea) {
2051 char *str;
2052 int len;
2053
2054 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
2055 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2056
2057 if (obj->intern) {
2058 size_t unescaped_len;
2059 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
2060
2061 if (unescaped_str) {
2062 RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
2063 PQfreemem(unescaped_str);
2064 } else {
2065 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not unescape bytea: %s", PQerrorMessage(obj->intern->conn));
2066 RETVAL_FALSE;
2067 }
2068 } else {
2069 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2070 RETVAL_FALSE;
2071 }
2072 }
2073 }
2074
2075 static const char *isolation_level(long *isolation) {
2076 switch (*isolation) {
2077 case PHP_PQTXN_SERIALIZABLE:
2078 return "SERIALIZABLE";
2079 case PHP_PQTXN_REPEATABLE_READ:
2080 return "REPEATABLE READ";
2081 default:
2082 *isolation = PHP_PQTXN_READ_COMMITTED;
2083 /* no break */
2084 case PHP_PQTXN_READ_COMMITTED:
2085 return "READ COMMITTED";
2086 }
2087 }
2088
2089 static STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
2090 {
2091 if (!conn_obj) {
2092 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2093 }
2094
2095 if (conn_obj->intern) {
2096 PGresult *res;
2097 char *cmd;
2098
2099 spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
2100 isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
2101
2102 res = PQexec(conn_obj->intern->conn, cmd);
2103
2104 efree(cmd);
2105
2106 if (res) {
2107 STATUS rv = php_pqres_success(res TSRMLS_CC);
2108
2109 PQclear(res);
2110 return rv;
2111 } else {
2112 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction: %s", PQerrorMessage(conn_obj->intern->conn));
2113 return FAILURE;
2114 }
2115 } else {
2116 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2117 return FAILURE;
2118 }
2119 }
2120
2121 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)
2122 {
2123 if (!conn_obj) {
2124 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2125 }
2126
2127 if (conn_obj->intern->conn) {
2128 char *cmd;
2129
2130 spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE",
2131 isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT");
2132
2133 if (PQsendQuery(conn_obj->intern->conn, cmd)) {
2134 conn_obj->intern->poller = PQconsumeInput;
2135 efree(cmd);
2136 return SUCCESS;
2137 } else {
2138 efree(cmd);
2139 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction: %s", PQerrorMessage(conn_obj->intern->conn));
2140 return FAILURE;
2141 }
2142 } else {
2143 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2144 return FAILURE;
2145 }
2146 }
2147
2148 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
2149 ZEND_ARG_INFO(0, isolation)
2150 ZEND_ARG_INFO(0, readonly)
2151 ZEND_ARG_INFO(0, deferrable)
2152 ZEND_END_ARG_INFO();
2153 static PHP_METHOD(pqconn, startTransaction) {
2154 zend_error_handling zeh;
2155 long isolation = PHP_PQTXN_READ_COMMITTED;
2156 zend_bool readonly = 0, deferrable = 0;
2157
2158 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2159 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
2160 STATUS rv;
2161 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2162
2163 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
2164
2165 if (SUCCESS == rv) {
2166 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
2167
2168 php_pq_object_addref(obj TSRMLS_CC);
2169 txn->conn = obj;
2170 txn->isolation = isolation;
2171 txn->readonly = readonly;
2172 txn->deferrable = deferrable;
2173
2174 return_value->type = IS_OBJECT;
2175 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
2176 }
2177 }
2178 zend_restore_error_handling(&zeh TSRMLS_CC);
2179 }
2180
2181
2182 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
2183 ZEND_ARG_INFO(0, isolation)
2184 ZEND_ARG_INFO(0, readonly)
2185 ZEND_ARG_INFO(0, deferrable)
2186 ZEND_END_ARG_INFO();
2187 static PHP_METHOD(pqconn, startTransactionAsync) {
2188 zend_error_handling zeh;
2189 long isolation = PHP_PQTXN_READ_COMMITTED;
2190 zend_bool readonly = 0, deferrable = 0;
2191
2192 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2193 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) {
2194 STATUS rv;
2195 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2196
2197 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
2198
2199 if (SUCCESS == rv) {
2200 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
2201
2202 php_pq_object_addref(obj TSRMLS_CC);
2203 txn->conn = obj;
2204 txn->isolation = isolation;
2205 txn->readonly = readonly;
2206 txn->deferrable = deferrable;
2207
2208 return_value->type = IS_OBJECT;
2209 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
2210 }
2211 }
2212 zend_restore_error_handling(&zeh TSRMLS_CC);
2213 }
2214
2215 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
2216 ZEND_ARG_INFO(0, stdio_stream)
2217 ZEND_END_ARG_INFO();
2218 static PHP_METHOD(pqconn, trace) {
2219 zval *zstream = NULL;
2220
2221 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) {
2222 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2223 if (obj->intern) {
2224 if (zstream) {
2225 FILE *fp;
2226 php_stream *stream = NULL;
2227
2228 php_stream_from_zval(stream, &zstream);
2229
2230 if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
2231 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
2232 PQtrace(obj->intern->conn, fp);
2233 RETVAL_TRUE;
2234 } else {
2235 RETVAL_FALSE;
2236 }
2237 } else {
2238 PQuntrace(obj->intern->conn);
2239 RETVAL_TRUE;
2240 }
2241 } else {
2242 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2243 RETVAL_FALSE;
2244 }
2245 }
2246 }
2247
2248 static zend_function_entry php_pqconn_methods[] = {
2249 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2250 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
2251 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
2252 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
2253 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
2254 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
2255 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
2256 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
2257 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
2258 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
2259 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
2260 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
2261 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
2262 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
2263 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
2264 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
2265 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
2266 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
2267 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
2268 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
2269 {0}
2270 };
2271
2272 static zval **php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type TSRMLS_DC)
2273 {
2274 zval **row = NULL;
2275 php_pqres_fetch_t orig_fetch;
2276
2277 if (!obj) {
2278 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2279 }
2280
2281 if (!obj->intern->iter) {
2282 obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
2283 obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
2284 }
2285 orig_fetch = obj->intern->iter->fetch_type;
2286 obj->intern->iter->fetch_type = fetch_type;
2287 if (SUCCESS == obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC)) {
2288 obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, &row TSRMLS_CC);
2289 obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC);
2290 }
2291 obj->intern->iter->fetch_type = orig_fetch;
2292
2293 return row ? row : NULL;
2294 }
2295
2296 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
2297 ZEND_ARG_INFO(0, fetch_type)
2298 ZEND_END_ARG_INFO();
2299 static PHP_METHOD(pqres, fetchRow) {
2300 zend_error_handling zeh;
2301 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2302 long fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
2303
2304 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2305 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) {
2306 zval **row = php_pqres_iteration(getThis(), obj, fetch_type TSRMLS_CC);
2307
2308 if (row) {
2309 RETVAL_ZVAL(*row, 1, 0);
2310 } else {
2311 RETVAL_FALSE;
2312 }
2313 }
2314 zend_restore_error_handling(&zeh TSRMLS_CC);
2315 }
2316
2317 static zval **column_at(zval *row, int col TSRMLS_DC)
2318 {
2319 zval **data = NULL;
2320 HashTable *ht = HASH_OF(row);
2321 int count = zend_hash_num_elements(ht);
2322
2323 if (col < count) {
2324 zend_hash_internal_pointer_reset(ht);
2325 while (col-- > 0) {
2326 zend_hash_move_forward(ht);
2327 }
2328 zend_hash_get_current_data(ht, (void *) &data);
2329 } else {
2330 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count);
2331 }
2332 return data;
2333 }
2334
2335 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
2336 ZEND_ARG_INFO(0, col_num)
2337 ZEND_END_ARG_INFO();
2338 static PHP_METHOD(pqres, fetchCol) {
2339 zend_error_handling zeh;
2340 long fetch_col = 0;
2341
2342 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2343 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
2344 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2345 zval **row = php_pqres_iteration(getThis(), obj, obj->intern->iter ? obj->intern->iter->fetch_type : 0 TSRMLS_CC);
2346
2347 if (row) {
2348 zval **col = column_at(*row, fetch_col TSRMLS_CC);
2349
2350 if (col) {
2351 RETVAL_ZVAL(*col, 1, 0);
2352 } else {
2353 RETVAL_FALSE;
2354 }
2355 } else {
2356 RETVAL_FALSE;
2357 }
2358 }
2359 zend_restore_error_handling(&zeh TSRMLS_CC);
2360
2361 }
2362
2363 static zend_function_entry php_pqres_methods[] = {
2364 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
2365 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
2366 {0}
2367 };
2368
2369 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
2370 ZEND_ARG_OBJ_INFO(0, Connection, pq\\Connection, 0)
2371 ZEND_ARG_INFO(0, type)
2372 ZEND_ARG_INFO(0, query)
2373 ZEND_ARG_ARRAY_INFO(0, types, 1)
2374 ZEND_ARG_INFO(0, async)
2375 ZEND_END_ARG_INFO();
2376 static PHP_METHOD(pqstm, __construct) {
2377 zend_error_handling zeh;
2378 zval *zconn, *ztypes = NULL;
2379 char *name_str, *query_str;
2380 int name_len, *query_len;
2381 zend_bool async = 0;
2382
2383 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2384 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)) {
2385 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2386 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2387
2388 if (conn_obj->intern) {
2389 STATUS rv;
2390 if (async) {
2391 conn_obj->intern->poller = PQconsumeInput;
2392 rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
2393 } else {
2394 rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC);
2395 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
2396 }
2397
2398 if (SUCCESS == rv) {
2399 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
2400
2401 php_pq_object_addref(conn_obj TSRMLS_CC);
2402 stm->conn = conn_obj;
2403 stm->name = estrdup(name_str);
2404 obj->intern = stm;
2405 }
2406 } else {
2407 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2408 }
2409 }
2410 zend_restore_error_handling(&zeh TSRMLS_CC);
2411 }
2412
2413 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
2414 ZEND_ARG_ARRAY_INFO(0, params, 1)
2415 ZEND_END_ARG_INFO();
2416 static PHP_METHOD(pqstm, exec) {
2417 zend_error_handling zeh;
2418 zval *zparams = NULL;
2419
2420 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2421 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
2422 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2423
2424 if (obj->intern) {
2425 if (obj->intern->conn->intern) {
2426 int count = 0;
2427 char **params = NULL;
2428 HashTable zdtor;
2429 PGresult *res;
2430
2431 if (zparams) {
2432 ZEND_INIT_SYMTABLE(&zdtor);
2433 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2434 }
2435
2436 res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0);
2437
2438 if (params) {
2439 efree(params);
2440 }
2441 if (zparams) {
2442 zend_hash_destroy(&zdtor);
2443 }
2444
2445 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2446
2447 if (res) {
2448 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2449 php_pqres_t *r = ecalloc(1, sizeof(*r));
2450
2451 r->res = res;
2452 return_value->type = IS_OBJECT;
2453 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC);
2454 }
2455 } else {
2456 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2457 }
2458 } else {
2459 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2460 }
2461 } else {
2462 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
2463 }
2464 }
2465 zend_restore_error_handling(&zeh TSRMLS_CC);
2466 }
2467
2468 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0)
2469 ZEND_ARG_ARRAY_INFO(0, params, 1)
2470 ZEND_ARG_INFO(0, callable)
2471 ZEND_END_ARG_INFO();
2472 static PHP_METHOD(pqstm, execAsync) {
2473 zend_error_handling zeh;
2474 zval *zparams = NULL;
2475 php_pq_callback_t resolver = {{0}};
2476
2477 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2478 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc)) {
2479 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2480
2481 if (obj->intern) {
2482 if (obj->intern->conn->intern) {
2483 int count;
2484 char **params = NULL;
2485 HashTable zdtor;
2486
2487 if (zparams) {
2488 ZEND_INIT_SYMTABLE(&zdtor);
2489 count = php_pq_params_to_array(Z_ARRVAL_P(zparams), &params, &zdtor TSRMLS_CC);
2490 }
2491
2492 php_pq_callback_dtor(&obj->intern->conn->intern->onevent);
2493 if (resolver.fci.size > 0) {
2494 obj->intern->conn->intern->onevent = resolver;
2495 php_pq_callback_addref(&obj->intern->conn->intern->onevent);
2496 }
2497
2498 obj->intern->conn->intern->poller = PQconsumeInput;
2499
2500 if (PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0)) {
2501 if (obj->intern->conn->intern->unbuffered) {
2502 if (!PQsetSingleRowMode(obj->intern->conn->intern->conn)) {
2503 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2504 }
2505 }
2506 RETVAL_TRUE;
2507 } else {
2508 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2509 RETVAL_FALSE;
2510 }
2511
2512 if (params) {
2513 efree(params);
2514 }
2515 if (zparams) {
2516 zend_hash_destroy(&zdtor);
2517 }
2518
2519 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2520
2521 } else {
2522 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2523 RETVAL_FALSE;
2524 }
2525 } else {
2526 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
2527 RETVAL_FALSE;
2528 }
2529 }
2530 zend_restore_error_handling(&zeh TSRMLS_CC);
2531 }
2532
2533 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
2534 ZEND_END_ARG_INFO();
2535 static PHP_METHOD(pqstm, desc) {
2536 zend_error_handling zeh;
2537
2538 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2539 if (SUCCESS == zend_parse_parameters_none()) {
2540 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2541
2542 if (obj->intern) {
2543 if (obj->intern->conn->intern) {
2544 PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name);
2545
2546 php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
2547
2548 if (res) {
2549 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
2550 int p, params;
2551
2552 array_init(return_value);
2553 for (p = 0, params = PQnparams(res); p < params; ++p) {
2554 add_next_index_long(return_value, PQparamtype(res, p));
2555 }
2556 }
2557 } else {
2558 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2559 }
2560 } else {
2561 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2562 }
2563 } else {
2564 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized");
2565 }
2566 }
2567 zend_restore_error_handling(&zeh TSRMLS_CC);
2568 }
2569
2570 static zend_function_entry php_pqstm_methods[] = {
2571 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2572 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
2573 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
2574 PHP_ME(pqstm, execAsync, ai_pqstm_exec_async, ZEND_ACC_PUBLIC)
2575 {0}
2576 };
2577
2578 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_construct, 0, 0, 1)
2579 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2580 ZEND_ARG_INFO(0, async)
2581 ZEND_ARG_INFO(0, isolation)
2582 ZEND_ARG_INFO(0, readonly)
2583 ZEND_ARG_INFO(0, deferrable)
2584 ZEND_END_ARG_INFO();
2585 static PHP_METHOD(pqtxn, __construct) {
2586 zend_error_handling zeh;
2587 zval *zconn;
2588 long isolation = PHP_PQTXN_READ_COMMITTED;
2589 zend_bool async = 0, readonly = 0, deferrable = 0;
2590
2591 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2592 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|blbb", &zconn, php_pqconn_class_entry, &async, &isolation, &readonly, &deferrable)) {
2593 STATUS rv;
2594 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2595 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2596
2597 if (conn_obj->intern) {
2598 if (async) {
2599 rv = php_pqconn_start_transaction_async(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC);
2600 } else {
2601 rv = php_pqconn_start_transaction(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC);
2602 }
2603
2604 if (SUCCESS == rv) {
2605 obj->intern = ecalloc(1, sizeof(*obj->intern));
2606
2607 php_pq_object_addref(conn_obj TSRMLS_CC);
2608 obj->intern->conn = conn_obj;
2609 obj->intern->isolation = isolation;
2610 obj->intern->readonly = readonly;
2611 obj->intern->deferrable = deferrable;
2612 }
2613 } else {
2614 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2615 }
2616 }
2617 zend_restore_error_handling(&zeh TSRMLS_CC);
2618 }
2619
2620 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit, 0, 0, 0)
2621 ZEND_END_ARG_INFO();
2622 static PHP_METHOD(pqtxn, commit) {
2623 zend_error_handling zeh;
2624
2625 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2626 if (SUCCESS == zend_parse_parameters_none()) {
2627 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2628
2629 if (obj->intern) {
2630
2631 if (obj->intern->conn->intern) {
2632 PGresult *res = PQexec(obj->intern->conn->intern->conn, "COMMIT");
2633
2634 if (res) {
2635 php_pqres_success(res TSRMLS_CC);
2636 PQclear(res);
2637 } else {
2638 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not commit transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2639 }
2640 } else {
2641 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2642 }
2643 } else {
2644 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2645 }
2646 }
2647 zend_restore_error_handling(&zeh TSRMLS_CC);
2648 }
2649
2650 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async, 0, 0, 0)
2651 ZEND_END_ARG_INFO();
2652 static PHP_METHOD(pqtxn, commitAsync) {
2653 zend_error_handling zeh;
2654
2655 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2656 if (SUCCESS == zend_parse_parameters_none()) {
2657 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2658
2659 if (obj->intern) {
2660 if (obj->intern->conn->intern) {
2661 obj->intern->conn->intern->poller = PQconsumeInput;
2662
2663 if (!PQsendQuery(obj->intern->conn->intern->conn, "COMMIT")) {
2664 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not commit transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2665 }
2666 } else {
2667 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2668 }
2669 } else {
2670 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2671 }
2672 }
2673 zend_restore_error_handling(&zeh TSRMLS_CC);
2674 }
2675
2676 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback, 0, 0, 0)
2677 ZEND_END_ARG_INFO();
2678 static PHP_METHOD(pqtxn, rollback) {
2679 zend_error_handling zeh;
2680
2681 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2682 if (SUCCESS == zend_parse_parameters_none()) {
2683 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2684
2685 if (obj->intern) {
2686 if (obj->intern->conn->intern) {
2687 PGresult *res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK");
2688
2689 if (res) {
2690 php_pqres_success(res TSRMLS_CC);
2691 PQclear(res);
2692 } else {
2693 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not rollback transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2694 }
2695 } else {
2696 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2697 }
2698 } else {
2699 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2700 }
2701 }
2702 zend_restore_error_handling(&zeh TSRMLS_CC);
2703 }
2704
2705 ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async, 0, 0, 0)
2706 ZEND_END_ARG_INFO();
2707 static PHP_METHOD(pqtxn, rollbackAsync) {
2708 zend_error_handling zeh;
2709
2710 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2711 if (SUCCESS == zend_parse_parameters_none()) {
2712 php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2713
2714 if (obj->intern) {
2715 if (obj->intern->conn->intern) {
2716 obj->intern->conn->intern->poller = PQconsumeInput;
2717 if (!PQsendQuery(obj->intern->conn->intern->conn, "REOLLBACK")) {
2718 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not rollback transaction: %s", PQerrorMessage(obj->intern->conn->intern->conn));
2719 }
2720 } else {
2721 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not intialized");
2722 }
2723 } else {
2724 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized");
2725 }
2726 }
2727 zend_restore_error_handling(&zeh TSRMLS_CC);
2728 }
2729
2730 static zend_function_entry php_pqtxn_methods[] = {
2731 PHP_ME(pqtxn, __construct, ai_pqtxn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2732 PHP_ME(pqtxn, commit, ai_pqtxn_commit, ZEND_ACC_PUBLIC)
2733 PHP_ME(pqtxn, rollback, ai_pqtxn_rollback, ZEND_ACC_PUBLIC)
2734 PHP_ME(pqtxn, commitAsync, ai_pqtxn_commit_async, ZEND_ACC_PUBLIC)
2735 PHP_ME(pqtxn, rollbackAsync, ai_pqtxn_rollback_async, ZEND_ACC_PUBLIC)
2736 {0}
2737 };
2738
2739 ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_construct, 0, 0, 1)
2740 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2741 ZEND_END_ARG_INFO();
2742 static PHP_METHOD(pqcancel, __construct) {
2743 zend_error_handling zeh;
2744 zval *zconn;
2745
2746 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2747 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zconn, php_pqconn_class_entry)) {
2748 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2749
2750 if (conn_obj->intern) {
2751 PGcancel *cancel = PQgetCancel(conn_obj->intern->conn);
2752
2753 if (cancel) {
2754 php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2755
2756 obj->intern = ecalloc(1, sizeof(*obj->intern));
2757 obj->intern->cancel = cancel;
2758 php_pq_object_addref(conn_obj TSRMLS_CC);
2759 obj->intern->conn = conn_obj;
2760 } else {
2761 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not acquire cancel: %s", PQerrorMessage(conn_obj->intern->conn));
2762 }
2763 } else {
2764 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2765 }
2766 }
2767 zend_restore_error_handling(&zeh TSRMLS_CC);
2768 }
2769
2770 ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_cancel, 0, 0, 0)
2771 ZEND_END_ARG_INFO();
2772 static PHP_METHOD(pqcancel, cancel) {
2773 zend_error_handling zeh;
2774
2775 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2776 if (SUCCESS == zend_parse_parameters_none()) {
2777 php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2778
2779 if (obj->intern) {
2780 char err[256];
2781
2782 if (!PQcancel(obj->intern->cancel, err, sizeof(err))) {
2783 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not request cancellation: %s", err);
2784 }
2785 } else {
2786 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Cancel not initialized");
2787 }
2788 }
2789 zend_restore_error_handling(&zeh TSRMLS_CC);
2790 }
2791
2792 static zend_function_entry php_pqcancel_methods[] = {
2793 PHP_ME(pqcancel, __construct, ai_pqcancel_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2794 PHP_ME(pqcancel, cancel, ai_pqcancel_cancel, ZEND_ACC_PUBLIC)
2795 {0}
2796 };
2797
2798 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)
2799 {
2800 zval **evhs;
2801
2802 if (SUCCESS == zend_hash_find(&conn_obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
2803 Z_ADDREF_P(zevent);
2804 add_next_index_zval(*evhs, zevent);
2805 } else {
2806 zval *evh;
2807
2808 MAKE_STD_ZVAL(evh);
2809 array_init(evh);
2810 Z_ADDREF_P(zevent);
2811 add_next_index_zval(evh, zevent);
2812 zend_hash_add(&conn_obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(zval *), NULL);
2813 }
2814 }
2815
2816 ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_construct, 0, 0, 3)
2817 ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0)
2818 ZEND_ARG_INFO(0, type)
2819 ZEND_ARG_INFO(0, callable)
2820 ZEND_END_ARG_INFO();
2821 static PHP_METHOD(pqevent, __construct) {
2822 zend_error_handling zeh;
2823 zval *zconn;
2824 char *type_str;
2825 int type_len;
2826 php_pq_callback_t cb;
2827
2828 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
2829 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osf", &zconn, php_pqconn_class_entry, &type_str, &type_len, &cb.fci, &cb.fcc)) {
2830 php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
2831
2832 if (conn_obj->intern) {
2833 php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2834
2835 obj->intern = ecalloc(1, sizeof(*obj->intern));
2836 php_pq_callback_addref(&cb);
2837 obj->intern->cb = cb;
2838 php_pq_object_addref(conn_obj TSRMLS_CC);
2839 obj->intern->conn = conn_obj;
2840 obj->intern->type = estrdup(type_str);
2841
2842 php_pqconn_add_eventhandler(zconn, conn_obj, type_str, type_len, getThis() TSRMLS_CC);
2843
2844 } else {
2845 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized");
2846 }
2847 }
2848 zend_restore_error_handling(&zeh TSRMLS_CC);
2849 }
2850
2851 ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_trigger, 0, 0, 1)
2852 ZEND_ARG_ARRAY_INFO(0, args, 1)
2853 ZEND_END_ARG_INFO();
2854 static PHP_METHOD(pqevent, trigger) {
2855 zval *args;
2856
2857 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &args)) {
2858 php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
2859
2860 if (obj->intern) {
2861 zval *rv = NULL;
2862
2863 if (SUCCESS == zend_fcall_info_call(&obj->intern->cb.fci, &obj->intern->cb.fcc, &rv, args TSRMLS_CC)) {
2864 if (rv) {
2865 RETVAL_ZVAL(rv, 0, 1);
2866 } else {
2867 RETVAL_TRUE;
2868 }
2869 }
2870 } else {
2871 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Event not initialized");
2872 RETVAL_FALSE;
2873 }
2874 }
2875 }
2876
2877 static zend_function_entry php_pqevent_methods[] = {
2878 PHP_ME(pqevent, __construct, ai_pqevent_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
2879 PHP_ME(pqevent, trigger, ai_pqevent_trigger, ZEND_ACC_PUBLIC)
2880 {0}
2881 };
2882
2883 /* {{{ PHP_MINIT_FUNCTION
2884 */
2885 static PHP_MINIT_FUNCTION(pq)
2886 {
2887 zend_class_entry ce = {0};
2888 php_pq_object_prophandler_t ph = {0};
2889
2890 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
2891 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
2892 php_pqconn_class_entry->create_object = php_pqconn_create_object;
2893
2894 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2895 php_pqconn_object_handlers.read_property = php_pq_object_read_prop;
2896 php_pqconn_object_handlers.write_property = php_pq_object_write_prop;
2897 php_pqconn_object_handlers.clone_obj = NULL;
2898 php_pqconn_object_handlers.get_property_ptr_ptr = NULL;
2899 php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info;
2900
2901 zend_hash_init(&php_pqconn_object_prophandlers, 8, NULL, NULL, 1);
2902
2903 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
2904 ph.read = php_pqconn_object_read_status;
2905 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
2906
2907 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
2908 ph.read = php_pqconn_object_read_transaction_status;
2909 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
2910
2911 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
2912 ph.read = NULL; /* forward to std prophandler */
2913 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
2914
2915 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
2916 ph.read = php_pqconn_object_read_error_message;
2917 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
2918
2919 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("types"), ZEND_ACC_PUBLIC TSRMLS_CC);
2920 ph.read = php_pqconn_object_read_types;
2921 zend_hash_add(&php_pqconn_object_prophandlers, "types", sizeof("types"), (void *) &ph, sizeof(ph), NULL);
2922
2923 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
2924 ph.read = php_pqconn_object_read_busy;
2925 zend_hash_add(&php_pqconn_object_prophandlers, "busy", sizeof("busy"), (void *) &ph, sizeof(ph), NULL);
2926
2927 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC TSRMLS_CC);
2928 ph.read = php_pqconn_object_read_encoding;
2929 ph.write = php_pqconn_object_write_encoding;
2930 zend_hash_add(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding"), (void *) &ph, sizeof(ph), NULL);
2931 ph.write = NULL;
2932
2933 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
2934 ph.read = php_pqconn_object_read_unbuffered;
2935 ph.write = php_pqconn_object_write_unbuffered;
2936 zend_hash_add(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered"), (void *) &ph, sizeof(ph), NULL);
2937 ph.write = NULL;
2938
2939 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
2940 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
2941 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
2942 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
2943 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
2944 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
2945 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
2946 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
2947
2948 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
2949 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
2950 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
2951 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
2952 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
2953
2954 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
2955 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
2956 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
2957 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
2958
2959 memset(&ce, 0, sizeof(ce));
2960 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
2961 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
2962 php_pqres_class_entry->create_object = php_pqres_create_object;
2963 php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs;
2964 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
2965 zend_class_implements(php_pqres_class_entry TSRMLS_CC, 1, zend_ce_traversable);
2966
2967 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
2968 php_pqres_object_handlers.read_property = php_pq_object_read_prop;
2969 php_pqres_object_handlers.write_property = php_pq_object_write_prop;
2970 php_pqres_object_handlers.clone_obj = NULL;
2971 php_pqres_object_handlers.get_property_ptr_ptr = NULL;
2972 php_pqres_object_handlers.get_debug_info = php_pq_object_debug_info;
2973
2974 zend_hash_init(&php_pqres_object_prophandlers, 6, NULL, NULL, 1);
2975
2976 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
2977 ph.read = php_pqres_object_read_status;
2978 zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
2979
2980 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
2981 ph.read = php_pqres_object_read_error_message;
2982 zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
2983
2984 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
2985 ph.read = php_pqres_object_read_num_rows;
2986 zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL);
2987
2988 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
2989 ph.read = php_pqres_object_read_num_cols;
2990 zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL);
2991
2992 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
2993 ph.read = php_pqres_object_read_affected_rows;
2994 zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL);
2995
2996 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);
2997 ph.read = php_pqres_object_read_fetch_type;
2998 ph.write = php_pqres_object_write_fetch_type;
2999 zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL);
3000 ph.write = NULL;
3001
3002 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC);
3003 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC);
3004 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC);
3005 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC);
3006 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC);
3007 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC);
3008 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC);
3009 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC);
3010 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC);
3011 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC);
3012
3013 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC);
3014 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC);
3015 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
3016
3017 memset(&ce, 0, sizeof(ce));
3018 INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods);
3019 php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
3020 php_pqstm_class_entry->create_object = php_pqstm_create_object;
3021
3022 memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3023 php_pqstm_object_handlers.read_property = php_pq_object_read_prop;
3024 php_pqstm_object_handlers.write_property = php_pq_object_write_prop;
3025 php_pqstm_object_handlers.clone_obj = NULL;
3026 php_pqstm_object_handlers.get_property_ptr_ptr = NULL;
3027 php_pqstm_object_handlers.get_debug_info = php_pq_object_debug_info;
3028
3029 zend_hash_init(&php_pqstm_object_prophandlers, 2, NULL, NULL, 1);
3030
3031 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
3032 ph.read = php_pqstm_object_read_name;
3033 zend_hash_add(&php_pqstm_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
3034
3035 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
3036 ph.read = php_pqstm_object_read_connection;
3037 zend_hash_add(&php_pqstm_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
3038
3039 memset(&ce, 0, sizeof(ce));
3040 INIT_NS_CLASS_ENTRY(ce, "pq", "Transaction", php_pqtxn_methods);
3041 php_pqtxn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
3042 php_pqtxn_class_entry->create_object = php_pqtxn_create_object;
3043
3044 memcpy(&php_pqtxn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3045 php_pqtxn_object_handlers.read_property = php_pq_object_read_prop;
3046 php_pqtxn_object_handlers.write_property = php_pq_object_write_prop;
3047 php_pqtxn_object_handlers.clone_obj = NULL;
3048 php_pqtxn_object_handlers.get_property_ptr_ptr = NULL;
3049 php_pqtxn_object_handlers.get_debug_info = php_pq_object_debug_info;
3050
3051 zend_hash_init(&php_pqtxn_object_prophandlers, 4, NULL, NULL, 1);
3052
3053 zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
3054 ph.read = php_pqtxn_object_read_connection;
3055 zend_hash_add(&php_pqtxn_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
3056
3057 zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("isolation"), ZEND_ACC_PUBLIC TSRMLS_CC);
3058 ph.read = php_pqtxn_object_read_isolation;
3059 ph.write = php_pqtxn_object_write_isolation;
3060 zend_hash_add(&php_pqtxn_object_prophandlers, "isolation", sizeof("isolation"), (void *) &ph, sizeof(ph), NULL);
3061
3062 zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("readonly"), ZEND_ACC_PUBLIC TSRMLS_CC);
3063 ph.read = php_pqtxn_object_read_readonly;
3064 ph.write = php_pqtxn_object_write_readonly;
3065 zend_hash_add(&php_pqtxn_object_prophandlers, "readonly", sizeof("readonly"), (void *) &ph, sizeof(ph), NULL);
3066
3067 zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("deferrable"), ZEND_ACC_PUBLIC TSRMLS_CC);
3068 ph.read = php_pqtxn_object_read_deferrable;
3069 ph.write = php_pqtxn_object_write_deferrable;
3070 zend_hash_add(&php_pqtxn_object_prophandlers, "deferrable", sizeof("deferrable"), (void *) &ph, sizeof(ph), NULL);
3071 ph.write = NULL;
3072
3073 zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED TSRMLS_CC);
3074 zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("REPEATABLE READ"), PHP_PQTXN_REPEATABLE_READ TSRMLS_CC);
3075 zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE TSRMLS_CC);
3076
3077 memset(&ce, 0, sizeof(ce));
3078 INIT_NS_CLASS_ENTRY(ce, "pq", "Cancel", php_pqcancel_methods);
3079 php_pqcancel_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
3080 php_pqcancel_class_entry->create_object = php_pqcancel_create_object;
3081
3082 memcpy(&php_pqcancel_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3083 php_pqcancel_object_handlers.read_property = php_pq_object_read_prop;
3084 php_pqcancel_object_handlers.write_property = php_pq_object_write_prop;
3085 php_pqcancel_object_handlers.clone_obj = NULL;
3086 php_pqcancel_object_handlers.get_property_ptr_ptr = NULL;
3087 php_pqcancel_object_handlers.get_debug_info = php_pq_object_debug_info;
3088
3089 zend_hash_init(&php_pqcancel_object_prophandlers, 1, NULL, NULL, 1);
3090
3091 zend_declare_property_null(php_pqcancel_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
3092 ph.read