inverted blocking option to async
[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_pqconn_object {
86 zend_object zo;
87 PGconn *conn;
88 int (*poller)(PGconn *);
89 unsigned async:1;
90 } php_pqconn_object_t;
91
92 typedef enum php_pqres_fetch {
93 PHP_PQRES_FETCH_ARRAY,
94 PHP_PQRES_FETCH_ASSOC,
95 PHP_PQRES_FETCH_OBJECT
96 } php_pqres_fetch_t;
97
98 typedef struct php_pqres_iterator {
99 zend_object_iterator zi;
100 zval *current_val;
101 unsigned index;
102 php_pqres_fetch_t fetch_type;
103 } php_pqres_iterator_t;
104
105 typedef struct php_pqres_object {
106 zend_object zo;
107 PGresult *res;
108 php_pqres_iterator_t *iter;
109 } php_pqres_object_t;
110
111 typedef struct php_pqstm_intern {
112 char *name;
113 zval *conn;
114 } php_pqstm_intern_t;
115
116 typedef struct php_pqstm_object {
117 zend_object zo;
118 char *name;
119 zval *conn;
120 } php_pqstm_object_t;
121
122 static zend_object_iterator_funcs php_pqres_iterator_funcs;
123
124 static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
125 {
126 php_pqres_iterator_t *iter;
127 zval *prop, *zfetch_type;
128
129 iter = ecalloc(1, sizeof(*iter));
130 iter->zi.funcs = &php_pqres_iterator_funcs;
131 iter->zi.data = object;
132 Z_ADDREF_P(object);
133
134 zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC);
135 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
136 convert_to_long_ex(&zfetch_type);
137 }
138 iter->fetch_type = Z_LVAL_P(zfetch_type);
139 if (zfetch_type != prop) {
140 zval_ptr_dtor(&zfetch_type);
141 }
142 if (Z_REFCOUNT_P(prop)) {
143 zval_ptr_dtor(&prop);
144 } else {
145 zval_dtor(prop);
146 FREE_ZVAL(prop);
147 }
148
149 return (zend_object_iterator *) iter;
150 }
151
152 static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
153 {
154 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
155
156 if (iter->current_val) {
157 zval_ptr_dtor(&iter->current_val);
158 iter->current_val = NULL;
159 }
160 zval_ptr_dtor((zval **) &iter->zi.data);
161 efree(iter);
162 }
163
164 static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC)
165 {
166 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
167 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
168
169 if (PQresultStatus(obj->res) != PGRES_TUPLES_OK) {
170 return FAILURE;
171 }
172 if (PQntuples(obj->res) <= iter->index) {
173 return FAILURE;
174 }
175
176 return SUCCESS;
177 }
178
179 static zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type TSRMLS_DC)
180 {
181 zval *data;
182 int c, cols;
183
184 MAKE_STD_ZVAL(data);
185 if (PHP_PQRES_FETCH_OBJECT == fetch_type) {
186 object_init(data);
187 } else {
188 array_init(data);
189 }
190
191 for (c = 0, cols = PQnfields(res); c < cols; ++c) {
192 if (PQgetisnull(res, row, c)) {
193 switch (fetch_type) {
194 case PHP_PQRES_FETCH_OBJECT:
195 add_property_null(data, PQfname(res, c));
196 break;
197
198 case PHP_PQRES_FETCH_ASSOC:
199 add_assoc_null(data, PQfname(res, c));
200 break;
201
202 case PHP_PQRES_FETCH_ARRAY:
203 add_index_null(data, c);
204 break;
205 }
206 } else {
207 char *val = PQgetvalue(res, row, c);
208 int len = PQgetlength(res, row, c);
209
210 switch (fetch_type) {
211 case PHP_PQRES_FETCH_OBJECT:
212 add_property_stringl(data, PQfname(res, c), val, len, 1);
213 break;
214
215 case PHP_PQRES_FETCH_ASSOC:
216 add_assoc_stringl(data, PQfname(res, c), val, len, 1);
217 break;
218
219 case PHP_PQRES_FETCH_ARRAY:
220 add_index_stringl(data, c, val, len ,1);
221 break;
222 }
223 }
224 }
225
226 return data;
227 }
228
229 static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr TSRMLS_DC)
230 {
231 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
232 php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC);
233
234 if (iter->current_val) {
235 zval_ptr_dtor(&iter->current_val);
236 }
237 iter->current_val = php_pqres_row_to_zval(obj->res, iter->index, iter->fetch_type TSRMLS_CC);
238 *data_ptr = &iter->current_val;
239 }
240
241 static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint *key_len, ulong *key_num TSRMLS_DC)
242 {
243 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
244
245 *key_num = (ulong) iter->index;
246
247 return HASH_KEY_IS_LONG;
248 }
249
250 static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC)
251 {
252 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
253
254 ++iter->index;
255 }
256
257 static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC)
258 {
259 php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
260
261 iter->index = 0;
262 }
263
264 static zend_object_iterator_funcs php_pqres_iterator_funcs = {
265 php_pqres_iterator_dtor,
266 /* check for end of iteration (FAILURE or SUCCESS if data is valid) */
267 php_pqres_iterator_valid,
268 /* fetch the item data for the current element */
269 php_pqres_iterator_current,
270 /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */
271 php_pqres_iterator_key,
272 /* step forwards to next element */
273 php_pqres_iterator_next,
274 /* rewind to start of data (optional, may be NULL) */
275 php_pqres_iterator_rewind,
276 /* invalidate current value/key (optional, may be NULL) */
277 NULL
278 };
279
280 static void php_pqconn_object_free(void *o TSRMLS_DC)
281 {
282 php_pqconn_object_t *obj = o;
283
284 if (obj->conn) {
285 PQfinish(obj->conn);
286 obj->conn = NULL;
287 }
288 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
289 efree(obj);
290 }
291
292 static void php_pqres_object_free(void *o TSRMLS_DC)
293 {
294 php_pqres_object_t *obj = o;
295
296 if (obj->res) {
297 PQclear(obj->res);
298 obj->res = NULL;
299 }
300 if (obj->iter) {
301 php_pqres_iterator_dtor((zend_object_iterator *) obj->iter TSRMLS_CC);
302 obj->iter = NULL;
303 }
304 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
305 efree(obj);
306 }
307
308 static void php_pqstm_object_free(void *o TSRMLS_DC)
309 {
310 php_pqstm_object_t *obj = o;
311
312 if (obj->name) {
313 efree(obj->name);
314 obj->name = NULL;
315 }
316 if (obj->conn) {
317 zval_ptr_dtor(&obj->conn);
318 obj->conn = NULL;
319 }
320 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
321 efree(obj);
322 }
323
324 static zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, PGconn *conn, php_pqconn_object_t **ptr TSRMLS_DC)
325 {
326 zend_object_value ov;
327 php_pqconn_object_t *o;
328
329 o = ecalloc(1, sizeof(*o));
330 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
331 object_properties_init((zend_object *) o, ce);
332
333 if (ptr) {
334 *ptr = o;
335 }
336
337 if (conn) {
338 o->conn = conn;
339 o->async = !PQisnonblocking(o->conn);
340 }
341
342 ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqconn_object_free, NULL TSRMLS_CC);
343 ov.handlers = &php_pqconn_object_handlers;
344
345 return ov;
346 }
347
348 static zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, PGresult *res, php_pqres_object_t **ptr TSRMLS_DC)
349 {
350 zend_object_value ov;
351 php_pqres_object_t *o;
352
353 o = ecalloc(1, sizeof(*o));
354 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
355 object_properties_init((zend_object *) o, ce);
356
357 if (ptr) {
358 *ptr = o;
359 }
360
361 if (res) {
362 o->res = res;
363 }
364
365 ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqres_object_free, NULL TSRMLS_CC);
366 ov.handlers = &php_pqres_object_handlers;
367
368 return ov;
369 }
370
371 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)
372 {
373 zend_object_value ov;
374 php_pqstm_object_t *o;
375
376 o = ecalloc(1, sizeof(*o));
377 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
378 object_properties_init((zend_object *) o, ce);
379
380 if (ptr) {
381 *ptr = o;
382 }
383
384 if (conn) {
385 Z_ADDREF_P(conn);
386 o->conn = conn;
387 }
388
389 if (name) {
390 o->name = estrdup(name);
391 }
392
393 ov.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqstm_object_free, NULL TSRMLS_CC);
394 ov.handlers = &php_pqstm_object_handlers;
395
396 return ov;
397 }
398
399 static zend_object_value php_pqconn_create_object(zend_class_entry *class_type TSRMLS_DC)
400 {
401 return php_pqconn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
402 }
403
404 static zend_object_value php_pqres_create_object(zend_class_entry *class_type TSRMLS_DC)
405 {
406 return php_pqres_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
407 }
408
409 static zend_object_value php_pqstm_create_object(zend_class_entry *class_type TSRMLS_DC)
410 {
411 return php_pqstm_create_object_ex(class_type, NULL, NULL, NULL TSRMLS_CC);
412 }
413
414 static HashTable php_pqconn_object_prophandlers;
415 static HashTable php_pqres_object_prophandlers;
416 static HashTable php_pqstm_object_prophandlers;
417
418 typedef void (*php_pq_object_prophandler_func_t)(void *o, zval *return_value TSRMLS_DC);
419
420 typedef struct php_pq_object_prophandler {
421 php_pq_object_prophandler_func_t read;
422 php_pq_object_prophandler_func_t write;
423 } php_pq_object_prophandler_t;
424
425 static void php_pqconn_object_read_status(void *o, zval *return_value TSRMLS_DC)
426 {
427 php_pqconn_object_t *obj = o;
428
429 RETVAL_LONG(PQstatus(obj->conn));
430 }
431
432 static void php_pqconn_object_read_transaction_status(void *o, zval *return_value TSRMLS_DC)
433 {
434 php_pqconn_object_t *obj = o;
435
436 RETVAL_LONG(PQtransactionStatus(obj->conn));
437 }
438
439 static void php_pqconn_object_read_error_message(void *o, zval *return_value TSRMLS_DC)
440 {
441 php_pqconn_object_t *obj = o;
442 char *error = PQerrorMessage(obj->conn);
443
444 if (error) {
445 RETVAL_STRING(error, 1);
446 } else {
447 RETVAL_NULL();
448 }
449 }
450
451 /* FIXME: extend to types->nspname->typname */
452 #define PHP_PQ_TYPES_QUERY \
453 "select t.oid, t.* " \
454 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
455 "where typisdefined " \
456 "and typrelid=0 " \
457 "and nspname in ('public', 'pg_catalog')"
458 static void php_pqconn_object_read_types(void *o, zval *return_value TSRMLS_DC)
459 {
460 php_pqconn_object_t *obj = o;
461 PGresult *res = PQexec(obj->conn, PHP_PQ_TYPES_QUERY);
462
463 /* FIXME: cache that */
464 if (res) {
465 if (PGRES_TUPLES_OK == PQresultStatus(res)) {
466 int r, rows;
467 zval *byoid, *byname;
468
469 MAKE_STD_ZVAL(byoid);
470 MAKE_STD_ZVAL(byname);
471 object_init(byoid);
472 object_init(byname);
473 object_init(return_value);
474 for (r = 0, rows = PQntuples(res); r < rows; ++r) {
475 zval *row = php_pqres_row_to_zval(res, r, PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
476
477 add_property_zval(byoid, PQgetvalue(res, r, 0), row);
478 add_property_zval(byname, PQgetvalue(res, r, 1), row);
479 zval_ptr_dtor(&row);
480 }
481
482 add_property_zval(return_value, "byOid", byoid);
483 add_property_zval(return_value, "byName", byname);
484 zval_ptr_dtor(&byoid);
485 zval_ptr_dtor(&byname);
486 } else {
487 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types: %s", PQresultErrorMessage(res));
488 }
489 PQclear(res);
490 } else {
491 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types: %s", PQerrorMessage(obj->conn));
492 }
493 }
494
495 static void php_pqres_object_read_status(void *o, zval *return_value TSRMLS_DC)
496 {
497 php_pqres_object_t *obj = o;
498
499 RETVAL_LONG(PQresultStatus(obj->res));
500 }
501
502 static void php_pqres_object_read_error_message(void *o, zval *return_value TSRMLS_DC)
503 {
504 php_pqres_object_t *obj = o;
505 char *error = PQresultErrorMessage(obj->res);
506
507 if (error) {
508 RETVAL_STRING(error, 1);
509 } else {
510 RETVAL_NULL();
511 }
512 }
513
514 static void php_pqres_object_read_num_rows(void *o, zval *return_value TSRMLS_DC)
515 {
516 php_pqres_object_t *obj = o;
517
518 RETVAL_LONG(PQntuples(obj->res));
519 }
520
521 static void php_pqres_object_read_num_cols(void *o, zval *return_value TSRMLS_DC)
522 {
523 php_pqres_object_t *obj = o;
524
525 RETVAL_LONG(PQnfields(obj->res));
526 }
527
528 static void php_pqres_object_read_affected_rows(void *o, zval *return_value TSRMLS_DC)
529 {
530 php_pqres_object_t *obj = o;
531
532 RETVAL_LONG(atoi(PQcmdTuples(obj->res)));
533 }
534
535 static void php_pqres_object_read_fetch_type(void *o, zval *return_value TSRMLS_DC)
536 {
537 php_pqres_object_t *obj = o;
538
539 if (obj->iter) {
540 RETVAL_LONG(obj->iter->fetch_type);
541 } else {
542 RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
543 }
544 }
545
546 static void php_pqres_object_write_fetch_type(void *o, zval *value TSRMLS_DC)
547 {
548 php_pqres_object_t *obj = o;
549 zval *zfetch_type = value;
550
551 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
552 convert_to_long_ex(&zfetch_type);
553 }
554
555 obj->iter->fetch_type = Z_LVAL_P(zfetch_type);
556
557 if (zfetch_type != value) {
558 zval_ptr_dtor(&zfetch_type);
559 }
560 }
561
562 static void php_pqstm_object_read_name(void *o, zval *return_value TSRMLS_DC)
563 {
564 php_pqstm_object_t *obj = o;
565
566 RETVAL_STRING(obj->name, 1);
567 }
568
569 static void php_pqstm_object_read_connection(void *o, zval *return_value TSRMLS_DC)
570 {
571 php_pqstm_object_t *obj = o;
572
573 RETVAL_ZVAL(obj->conn, 1, 0);
574 }
575
576 static zval *php_pqconn_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
577 {
578 php_pqconn_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
579 php_pq_object_prophandler_t *handler;
580 zval *return_value;
581
582 if (!obj->conn) {
583 zend_error(E_WARNING, "Connection not initialized");
584 } else if ((SUCCESS == zend_hash_find(&php_pqconn_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) && handler->read) {
585 if (type == BP_VAR_R) {
586 ALLOC_ZVAL(return_value);
587 Z_SET_REFCOUNT_P(return_value, 0);
588 Z_UNSET_ISREF_P(return_value);
589
590 handler->read(obj, return_value TSRMLS_CC);
591 } else {
592 zend_error(E_ERROR, "Cannot access pq\\Connection properties by reference or array key/index");
593 return_value = NULL;
594 }
595 } else {
596 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
597 }
598
599 return return_value;
600 }
601
602 static void php_pqconn_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
603 {
604 php_pqconn_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
605 php_pq_object_prophandler_t *handler;
606
607 if (SUCCESS == zend_hash_find(&php_pqconn_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
608 if (handler->write) {
609 handler->write(obj, value TSRMLS_CC);
610 }
611 } else {
612 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
613 }
614 }
615
616 static zval *php_pqres_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
617 {
618 php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
619 php_pq_object_prophandler_t *handler;
620 zval *return_value;
621
622 if (!obj->res) {
623 zend_error(E_WARNING, "Result not initialized");
624 } else if (SUCCESS == zend_hash_find(&php_pqres_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
625 if (type == BP_VAR_R) {
626 ALLOC_ZVAL(return_value);
627 Z_SET_REFCOUNT_P(return_value, 0);
628 Z_UNSET_ISREF_P(return_value);
629
630 handler->read(obj, return_value TSRMLS_CC);
631 } else {
632 zend_error(E_ERROR, "Cannot access pq\\Result properties by reference or array key/index");
633 return_value = NULL;
634 }
635 } else {
636 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
637 }
638
639 return return_value;
640 }
641
642 static void php_pqres_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
643 {
644 php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
645 php_pq_object_prophandler_t *handler;
646
647 if (!obj->res) {
648 zend_error(E_WARNING, "Result not initialized");
649 } else if (SUCCESS == zend_hash_find(&php_pqres_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
650 if (handler->write) {
651 /* ensure obj->iter is initialized, for e.g. write_fetch_type */
652 if (!obj->iter) {
653 obj->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC);
654 obj->iter->zi.funcs->rewind((zend_object_iterator *) obj->iter TSRMLS_CC);
655 }
656 handler->write(obj, value TSRMLS_CC);
657 }
658 } else {
659 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
660 }
661 }
662
663 static zval *php_pqstm_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
664 {
665 php_pqstm_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
666 php_pq_object_prophandler_t *handler;
667 zval *return_value;
668
669 if (!obj->conn) {
670 zend_error(E_WARNING, "Statement not initialized");
671 } else if (SUCCESS == zend_hash_find(&php_pqstm_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
672 if (type == BP_VAR_R) {
673 ALLOC_ZVAL(return_value);
674 Z_SET_REFCOUNT_P(return_value, 0);
675 Z_UNSET_ISREF_P(return_value);
676
677 handler->read(obj, return_value TSRMLS_CC);
678 } else {
679 zend_error(E_ERROR, "Cannot access pq\\Statement properties by reference or array key/index");
680 return_value = NULL;
681 }
682 } else {
683 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
684 }
685
686 return return_value;
687 }
688
689 static void php_pqstm_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
690 {
691 php_pqstm_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
692 php_pq_object_prophandler_t *handler;
693
694 if (!obj->conn) {
695 zend_error(E_WARNING, "Result not initialized");
696 } else if (SUCCESS == zend_hash_find(&php_pqstm_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
697 if (handler->write) {
698 handler->write(obj, value TSRMLS_CC);
699 }
700 } else {
701 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
702 }
703 }
704
705 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
706 {
707 zval *zsocket, zmember;
708 php_stream *stream;
709 STATUS retval;
710 int socket;
711
712 if (!obj) {
713 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
714 }
715
716 INIT_PZVAL(&zmember);
717 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
718 MAKE_STD_ZVAL(zsocket);
719
720 if ((CONNECTION_BAD != PQstatus(obj->conn))
721 && (-1 < (socket = PQsocket(obj->conn)))
722 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
723 php_stream_to_zval(stream, zsocket);
724 retval = SUCCESS;
725 } else {
726 ZVAL_NULL(zsocket);
727 retval = FAILURE;
728 }
729 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
730 zval_ptr_dtor(&zsocket);
731
732 return retval;
733 }
734
735 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
736 ZEND_ARG_INFO(0, dsn)
737 ZEND_ARG_INFO(0, async)
738 ZEND_END_ARG_INFO();
739 static PHP_METHOD(pqconn, __construct) {
740 zend_error_handling zeh;
741 char *dsn_str;
742 int dsn_len;
743 zend_bool async = 0;
744
745 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
746 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &dsn_str, &dsn_len, &async)) {
747 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
748
749 if (obj->conn) {
750 PQfinish(obj->conn);
751 }
752 if ((obj->async = async)) {
753 obj->conn = PQconnectStart(dsn_str);
754 obj->poller = (int (*)(PGconn*)) PQconnectPoll;
755 } else {
756 obj->conn = PQconnectdb(dsn_str);
757 }
758
759 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
760 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection failed: %s", PQerrorMessage(obj->conn));
761 }
762 }
763 zend_restore_error_handling(&zeh TSRMLS_CC);
764 }
765
766 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
767 ZEND_END_ARG_INFO();
768 static PHP_METHOD(pqconn, reset) {
769 if (SUCCESS == zend_parse_parameters_none()) {
770 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
771
772 if (obj->conn) {
773 if (obj->async) {
774 if (PQresetStart(obj->conn)) {
775 obj->poller = (int (*)(PGconn*)) PQresetPoll;
776 RETURN_TRUE;
777 }
778 } else {
779 PQreset(obj->conn);
780
781 if (CONNECTION_OK == PQstatus(obj->conn)) {
782 RETURN_TRUE;
783 } else {
784 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection reset failed: %s", PQerrorMessage(obj->conn));
785 }
786 }
787 } else {
788 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
789 }
790 RETURN_FALSE;
791 }
792 }
793
794 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
795 ZEND_END_ARG_INFO();
796 static PHP_METHOD(pqconn, poll) {
797 if (SUCCESS == zend_parse_parameters_none()) {
798 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
799
800 if (obj->conn) {
801 if (obj->poller) {
802 RETURN_LONG(obj->poller(obj->conn));
803 } else {
804 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active");
805 }
806 } else {
807 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
808 }
809 RETURN_FALSE;
810 }
811 }
812
813 static STATUS php_pqres_success(PGresult *res TSRMLS_DC)
814 {
815 switch (PQresultStatus(res)) {
816 case PGRES_BAD_RESPONSE:
817 case PGRES_NONFATAL_ERROR:
818 case PGRES_FATAL_ERROR:
819 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res));
820 return FAILURE;
821 default:
822 return SUCCESS;
823 }
824 }
825
826 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
827 ZEND_ARG_INFO(0, query)
828 ZEND_END_ARG_INFO();
829 static PHP_METHOD(pqconn, exec) {
830 zend_error_handling zeh;
831 char *query_str;
832 int query_len;
833
834 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
835 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) {
836 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
837
838 if (obj->conn) {
839 PGresult *res = PQexec(obj->conn, query_str);
840
841 if (res) {
842 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
843 return_value->type = IS_OBJECT;
844 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
845 }
846 } else {
847 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
848 }
849 } else {
850 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
851 }
852 }
853 zend_restore_error_handling(&zeh TSRMLS_CC);
854 }
855
856 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
857 {
858 Oid **types = arg;
859 zval **ztype = p;
860
861 if (Z_TYPE_PP(ztype) != IS_LONG) {
862 convert_to_long_ex(ztype);
863 }
864
865 **types = Z_LVAL_PP(ztype);
866 ++*types;
867
868 if (*ztype != *(zval **)p) {
869 zval_ptr_dtor(ztype);
870 }
871 return ZEND_HASH_APPLY_KEEP;
872 }
873
874 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
875 {
876 char ***params;
877 HashTable *zdtor;
878 zval **zparam = p;
879
880 params = (char ***) va_arg(argv, char ***);
881 zdtor = (HashTable *) va_arg(argv, HashTable *);
882
883 if (Z_TYPE_PP(zparam) == IS_NULL) {
884 **params = NULL;
885 ++*params;
886 } else {
887 if (Z_TYPE_PP(zparam) != IS_STRING) {
888 convert_to_string_ex(zparam);
889 }
890
891 **params = Z_STRVAL_PP(zparam);
892 ++*params;
893
894 if (*zparam != *(zval **)p) {
895 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
896 }
897 }
898 return ZEND_HASH_APPLY_KEEP;
899 }
900
901 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
902 ZEND_ARG_INFO(0, query)
903 ZEND_ARG_ARRAY_INFO(0, params, 0)
904 ZEND_ARG_ARRAY_INFO(0, types, 1)
905 ZEND_END_ARG_INFO();
906 static PHP_METHOD(pqconn, execParams) {
907 zend_error_handling zeh;
908 char *query_str;
909 int query_len;
910 zval *zparams;
911 zval *ztypes = NULL;
912
913 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
914 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
915 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
916
917 if (obj->conn) {
918 PGresult *res;
919 int count = 0;
920 Oid *types = NULL;
921 char **params = NULL;
922 HashTable zdtor;
923
924 ZEND_INIT_SYMTABLE(&zdtor);
925
926 if (ztypes && zend_hash_num_elements(Z_ARRVAL_P(ztypes))) {
927 Oid *tmp;
928
929 tmp = types = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(ztypes)), sizeof(Oid));
930 zend_hash_apply_with_argument(Z_ARRVAL_P(ztypes), apply_to_oid, &tmp TSRMLS_CC);
931 }
932 if ((count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
933 char **tmp;
934
935 tmp = params = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zparams)), sizeof(char *));
936 zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
937 }
938
939 res = PQexecParams(obj->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
940
941 zend_hash_destroy(&zdtor);
942 if (types) {
943 efree(types);
944 }
945 if (params) {
946 efree(params);
947 }
948
949 if (res) {
950 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
951 return_value->type = IS_OBJECT;
952 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
953 }
954 } else {
955 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
956 }
957 } else {
958 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
959 }
960 }
961 zend_restore_error_handling(&zeh TSRMLS_CC);
962 }
963
964 static STATUS php_pqconn_prepare(PGconn *conn, const char *name, const char *query, HashTable *typest TSRMLS_DC)
965 {
966 Oid *types = NULL;
967 int count = 0;
968 PGresult *res;
969
970 if (typest && (count = zend_hash_num_elements(typest))) {
971 Oid *tmp;
972
973 tmp = types = ecalloc(count, sizeof(Oid));
974 zend_hash_apply_with_argument(typest, apply_to_oid, &tmp TSRMLS_CC);
975 }
976
977 res = PQprepare(conn, name, query, count, types);
978
979 if (types) {
980 efree(types);
981 }
982
983 if (res) {
984 if (PGRES_COMMAND_OK == PQresultStatus(res)) {
985 return SUCCESS;
986 } else {
987 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQresultErrorMessage(res));
988 }
989 PQclear(res);
990 } else {
991 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(conn));
992 }
993 return FAILURE;
994 }
995
996 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
997 ZEND_ARG_INFO(0, "name")
998 ZEND_ARG_INFO(0, "query")
999 ZEND_ARG_ARRAY_INFO(0, "types", 1)
1000 ZEND_END_ARG_INFO();
1001 static PHP_METHOD(pqconn, prepare) {
1002 zend_error_handling zeh;
1003 zval *ztypes = NULL;
1004 char *name_str, *query_str;
1005 int name_len, *query_len;
1006
1007 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1008 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
1009 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1010
1011 if (obj->conn) {
1012 if (SUCCESS == php_pqconn_prepare(obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1013 return_value->type = IS_OBJECT;
1014 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, getThis(), name_str, NULL TSRMLS_CC);
1015 }
1016 } else {
1017 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1018 }
1019 }
1020 }
1021
1022 static zend_function_entry php_pqconn_methods[] = {
1023 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1024 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
1025 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
1026 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
1027 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
1028 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
1029 {0}
1030 };
1031
1032 static zval **php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type TSRMLS_DC)
1033 {
1034 zval **row = NULL;
1035 php_pqres_fetch_t orig_fetch;
1036
1037 if (!obj) {
1038 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1039 }
1040
1041 if (!obj->iter) {
1042 obj->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
1043 obj->iter->zi.funcs->rewind((zend_object_iterator *) obj->iter TSRMLS_CC);
1044 }
1045 orig_fetch = obj->iter->fetch_type;
1046 obj->iter->fetch_type = fetch_type;
1047 if (SUCCESS == obj->iter->zi.funcs->valid((zend_object_iterator *) obj->iter TSRMLS_CC)) {
1048 obj->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->iter, &row TSRMLS_CC);
1049 obj->iter->zi.funcs->move_forward((zend_object_iterator *) obj->iter TSRMLS_CC);
1050 }
1051 obj->iter->fetch_type = orig_fetch;
1052
1053 return row ? row : NULL;
1054 }
1055
1056 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
1057 ZEND_ARG_INFO(0, fetch_type)
1058 ZEND_END_ARG_INFO();
1059 static PHP_METHOD(pqres, fetchRow) {
1060 zend_error_handling zeh;
1061 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1062 long fetch_type = obj->iter ? obj->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
1063
1064 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1065 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) {
1066 zval **row = php_pqres_iteration(getThis(), obj, fetch_type TSRMLS_CC);
1067
1068 if (row) {
1069 RETVAL_ZVAL(*row, 1, 0);
1070 } else {
1071 RETVAL_FALSE;
1072 }
1073 }
1074 zend_restore_error_handling(&zeh TSRMLS_CC);
1075 }
1076
1077 static zval **column_at(zval *row, int col TSRMLS_DC)
1078 {
1079 zval **data = NULL;
1080 HashTable *ht = HASH_OF(row);
1081 int count = zend_hash_num_elements(ht);
1082
1083 if (col < count) {
1084 zend_hash_internal_pointer_reset(ht);
1085 while (col-- > 0) {
1086 zend_hash_move_forward(ht);
1087 }
1088 zend_hash_get_current_data(ht, (void *) &data);
1089 } else {
1090 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d does excess column count %d", col, count);
1091 }
1092 return data;
1093 }
1094
1095 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
1096 ZEND_ARG_INFO(0, col_num)
1097 ZEND_END_ARG_INFO();
1098 static PHP_METHOD(pqres, fetchCol) {
1099 zend_error_handling zeh;
1100 long fetch_col = 0;
1101
1102 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1103 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
1104 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1105 zval **row = php_pqres_iteration(getThis(), obj, obj->iter ? obj->iter->fetch_type : 0 TSRMLS_CC);
1106
1107 if (row) {
1108 zval **col = column_at(*row, fetch_col TSRMLS_CC);
1109
1110 if (col) {
1111 RETVAL_ZVAL(*col, 1, 0);
1112 } else {
1113 RETVAL_FALSE;
1114 }
1115 } else {
1116 RETVAL_FALSE;
1117 }
1118 }
1119 zend_restore_error_handling(&zeh TSRMLS_CC);
1120
1121 }
1122
1123 static zend_function_entry php_pqres_methods[] = {
1124 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
1125 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
1126 {0}
1127 };
1128
1129 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
1130 ZEND_ARG_OBJ_INFO(0, "Connection", "pq\\Connection", 0)
1131 ZEND_ARG_INFO(0, "name")
1132 ZEND_ARG_INFO(0, "query")
1133 ZEND_ARG_ARRAY_INFO(0, "types", 1)
1134 ZEND_END_ARG_INFO();
1135 static PHP_METHOD(pqstm, __construct) {
1136 zend_error_handling zeh;
1137 zval *zconn, *ztypes = NULL;
1138 char *name_str, *query_str;
1139 int name_len, *query_len;
1140
1141 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1142 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|a/!", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes)) {
1143 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1144 php_pqconn_object_t *conn_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1145
1146 if (conn_obj->conn) {
1147 if (SUCCESS == php_pqconn_prepare(conn_obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1148 Z_ADDREF_P(zconn);
1149 obj->conn = zconn;
1150 obj->name = estrdup(name_str);
1151 }
1152 } else {
1153 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1154 }
1155 }
1156 }
1157
1158 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
1159 ZEND_ARG_ARRAY_INFO(0, "params", 1)
1160 ZEND_END_ARG_INFO();
1161 static PHP_METHOD(pqstm, exec) {
1162 zend_error_handling zeh;
1163 zval *zparams = NULL;
1164
1165 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1166 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
1167 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1168
1169 if (obj->conn && obj->name) {
1170 php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
1171
1172 if (conn_obj->conn) {
1173 int count = 0;
1174 char **params = NULL;
1175 HashTable zdtor;
1176 PGresult *res;
1177
1178 ZEND_INIT_SYMTABLE(&zdtor);
1179
1180 if (zparams && (count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
1181 char **tmp;
1182
1183 tmp = params = ecalloc(count, sizeof(char *));
1184 zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
1185 }
1186
1187 res = PQexecPrepared(conn_obj->conn, obj->name, count, (const char *const*) params, NULL, NULL, 0);
1188
1189 if (params) {
1190 efree(params);
1191 }
1192 zend_hash_destroy(&zdtor);
1193
1194 if (res) {
1195 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1196 return_value->type = IS_OBJECT;
1197 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
1198 }
1199 } else {
1200 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(conn_obj->conn));
1201 }
1202 } else {
1203 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1204 }
1205 } else {
1206 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
1207 }
1208 }
1209 zend_restore_error_handling(&zeh TSRMLS_CC);
1210 }
1211
1212 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
1213 ZEND_END_ARG_INFO();
1214 static PHP_METHOD(pqstm, desc) {
1215 zend_error_handling zeh;
1216
1217 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1218 if (SUCCESS == zend_parse_parameters_none()) {
1219 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1220
1221 if (obj->conn && obj->name) {
1222 php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
1223
1224 if (conn_obj->conn) {
1225 PGresult *res = PQdescribePrepared(conn_obj->conn, obj->name);
1226
1227 if (res) {
1228 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1229 int p, params;
1230
1231 array_init(return_value);
1232 for (p = 0, params = PQnparams(res); p < params; ++p) {
1233 add_next_index_long(return_value, PQparamtype(res, p));
1234 }
1235 }
1236 } else {
1237 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PQerrorMessage(conn_obj->conn));
1238 }
1239 } else {
1240 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1241 }
1242 } else {
1243 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
1244 }
1245 }
1246 zend_restore_error_handling(&zeh TSRMLS_CC);
1247 }
1248
1249 static zend_function_entry php_pqstm_methods[] = {
1250 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1251 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
1252 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
1253 {0}
1254 };
1255
1256 /* {{{ PHP_MINIT_FUNCTION
1257 */
1258 PHP_MINIT_FUNCTION(pq)
1259 {
1260 zend_class_entry ce = {0};
1261 php_pq_object_prophandler_t ph = {0};
1262
1263 zend_hash_init(&php_pqconn_object_prophandlers, 1, NULL, NULL, 1);
1264 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
1265 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1266 php_pqconn_class_entry->create_object = php_pqconn_create_object;
1267 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1268 php_pqconn_object_handlers.read_property = php_pqconn_object_read_prop;
1269 php_pqconn_object_handlers.write_property = php_pqconn_object_write_prop;
1270
1271 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
1272 ph.read = php_pqconn_object_read_status;
1273 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1274
1275 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
1276 ph.read = php_pqconn_object_read_transaction_status;
1277 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
1278
1279 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
1280 ph.read = NULL; /* forward to std prophandler */
1281 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
1282
1283 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1284 ph.read = php_pqconn_object_read_error_message;
1285 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1286
1287 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("types"), ZEND_ACC_PUBLIC TSRMLS_CC);
1288 ph.read = php_pqconn_object_read_types;
1289 zend_hash_add(&php_pqconn_object_prophandlers, "types", sizeof("types"), (void *) &ph, sizeof(ph), NULL);
1290
1291 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
1292 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
1293 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
1294 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
1295 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
1296 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
1297 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
1298 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
1299
1300 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
1301 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
1302 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
1303 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
1304 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
1305
1306 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
1307 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
1308 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
1309 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
1310
1311 zend_hash_init(&php_pqres_object_prophandlers, 1, NULL, NULL, 1);
1312 memset(&ce, 0, sizeof(ce));
1313 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
1314 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1315 php_pqres_class_entry->create_object = php_pqres_create_object;
1316 php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs;
1317 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
1318
1319 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1320 php_pqres_object_handlers.read_property = php_pqres_object_read_prop;
1321 php_pqres_object_handlers.write_property = php_pqres_object_write_prop;
1322
1323 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
1324 ph.read = php_pqres_object_read_status;
1325 zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1326
1327 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1328 ph.read = php_pqres_object_read_error_message;
1329 zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1330
1331 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1332 ph.read = php_pqres_object_read_num_rows;
1333 zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL);
1334
1335 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1336 ph.read = php_pqres_object_read_num_cols;
1337 zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL);
1338
1339 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1340 ph.read = php_pqres_object_read_affected_rows;
1341 zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL);
1342
1343 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);
1344 ph.read = php_pqres_object_read_fetch_type;
1345 ph.write = php_pqres_object_write_fetch_type;
1346 zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL);
1347 ph.write = NULL;
1348
1349 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC);
1350 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC);
1351 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC);
1352 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC);
1353 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC);
1354 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC);
1355 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC);
1356 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC);
1357 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC);
1358 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC);
1359
1360 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC);
1361 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC);
1362 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
1363
1364 zend_hash_init(&php_pqstm_object_prophandlers, 1, NULL, NULL, 1);
1365 memset(&ce, 0, sizeof(ce));
1366 INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods);
1367 php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1368 php_pqstm_class_entry->create_object = php_pqstm_create_object;
1369
1370 memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1371 php_pqstm_object_handlers.read_property = php_pqstm_object_read_prop;
1372 php_pqstm_object_handlers.write_property = php_pqstm_object_write_prop;
1373
1374 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
1375 ph.read = php_pqstm_object_read_name;
1376 zend_hash_add(&php_pqstm_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
1377
1378 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
1379 ph.read = php_pqstm_object_read_connection;
1380 zend_hash_add(&php_pqstm_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
1381
1382 /*
1383 REGISTER_INI_ENTRIES();
1384 */
1385 return SUCCESS;
1386 }
1387 /* }}} */
1388
1389 /* {{{ PHP_MSHUTDOWN_FUNCTION
1390 */
1391 PHP_MSHUTDOWN_FUNCTION(pq)
1392 {
1393 /* uncomment this line if you have INI entries
1394 UNREGISTER_INI_ENTRIES();
1395 */
1396 return SUCCESS;
1397 }
1398 /* }}} */
1399
1400 /* {{{ PHP_MINFO_FUNCTION
1401 */
1402 PHP_MINFO_FUNCTION(pq)
1403 {
1404 php_info_print_table_start();
1405 php_info_print_table_header(2, "pq support", "enabled");
1406 php_info_print_table_end();
1407
1408 /* Remove comments if you have entries in php.ini
1409 DISPLAY_INI_ENTRIES();
1410 */
1411 }
1412 /* }}} */
1413
1414
1415
1416 /*
1417 * Local variables:
1418 * tab-width: 4
1419 * c-basic-offset: 4
1420 * End:
1421 * vim600: noet sw=4 ts=4 fdm=marker
1422 * vim<600: noet sw=4 ts=4
1423 */