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