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