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