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