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