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