only create a stream once out of the PQsocket
[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 blocking: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->blocking = !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, block)
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 block = 1;
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, &block)) {
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->blocking = block)) {
753 obj->conn = PQconnectdb(dsn_str);
754 } else {
755 obj->conn = PQconnectStart(dsn_str);
756 obj->poller = (int (*)(PGconn*)) PQconnectPoll;
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->blocking) {
774 PQreset(obj->conn);
775 if (CONNECTION_OK == PQstatus(obj->conn)) {
776 RETURN_TRUE;
777 } else {
778 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection reset failed: %s", PQerrorMessage(obj->conn));
779 }
780 } else if (PQresetStart(obj->conn)) {
781 obj->poller = (int (*)(PGconn*)) PQresetPoll;
782 RETURN_TRUE;
783 }
784 } else {
785 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
786 }
787 RETURN_FALSE;
788 }
789 }
790
791 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
792 ZEND_END_ARG_INFO();
793 static PHP_METHOD(pqconn, poll) {
794 if (SUCCESS == zend_parse_parameters_none()) {
795 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
796
797 if (obj->conn) {
798 if (obj->poller) {
799 RETURN_LONG(obj->poller(obj->conn));
800 } else {
801 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active");
802 }
803 } else {
804 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
805 }
806 RETURN_FALSE;
807 }
808 }
809
810 static STATUS php_pqres_success(PGresult *res TSRMLS_DC)
811 {
812 switch (PQresultStatus(res)) {
813 case PGRES_BAD_RESPONSE:
814 case PGRES_NONFATAL_ERROR:
815 case PGRES_FATAL_ERROR:
816 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res));
817 return FAILURE;
818 default:
819 return SUCCESS;
820 }
821 }
822
823 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
824 ZEND_ARG_INFO(0, query)
825 ZEND_END_ARG_INFO();
826 static PHP_METHOD(pqconn, exec) {
827 zend_error_handling zeh;
828 char *query_str;
829 int query_len;
830
831 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
832 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) {
833 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
834
835 if (obj->conn) {
836 PGresult *res = PQexec(obj->conn, query_str);
837
838 if (res) {
839 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
840 return_value->type = IS_OBJECT;
841 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
842 }
843 } else {
844 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
845 }
846 } else {
847 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
848 }
849 }
850 zend_restore_error_handling(&zeh TSRMLS_CC);
851 }
852
853 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
854 {
855 Oid **types = arg;
856 zval **ztype = p;
857
858 if (Z_TYPE_PP(ztype) != IS_LONG) {
859 convert_to_long_ex(ztype);
860 }
861
862 **types = Z_LVAL_PP(ztype);
863 ++*types;
864
865 if (*ztype != *(zval **)p) {
866 zval_ptr_dtor(ztype);
867 }
868 return ZEND_HASH_APPLY_KEEP;
869 }
870
871 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
872 {
873 char ***params;
874 HashTable *zdtor;
875 zval **zparam = p;
876
877 params = (char ***) va_arg(argv, char ***);
878 zdtor = (HashTable *) va_arg(argv, HashTable *);
879
880 if (Z_TYPE_PP(zparam) == IS_NULL) {
881 **params = NULL;
882 ++*params;
883 } else {
884 if (Z_TYPE_PP(zparam) != IS_STRING) {
885 convert_to_string_ex(zparam);
886 }
887
888 **params = Z_STRVAL_PP(zparam);
889 ++*params;
890
891 if (*zparam != *(zval **)p) {
892 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
893 }
894 }
895 return ZEND_HASH_APPLY_KEEP;
896 }
897
898 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
899 ZEND_ARG_INFO(0, query)
900 ZEND_ARG_ARRAY_INFO(0, params, 0)
901 ZEND_ARG_ARRAY_INFO(0, types, 1)
902 ZEND_END_ARG_INFO();
903 static PHP_METHOD(pqconn, execParams) {
904 zend_error_handling zeh;
905 char *query_str;
906 int query_len;
907 zval *zparams;
908 zval *ztypes = NULL;
909
910 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
911 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
912 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
913
914 if (obj->conn) {
915 PGresult *res;
916 int count = 0;
917 Oid *types = NULL;
918 char **params = NULL;
919 HashTable zdtor;
920
921 ZEND_INIT_SYMTABLE(&zdtor);
922
923 if (ztypes && zend_hash_num_elements(Z_ARRVAL_P(ztypes))) {
924 Oid *tmp;
925
926 tmp = types = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(ztypes)), sizeof(Oid));
927 zend_hash_apply_with_argument(Z_ARRVAL_P(ztypes), apply_to_oid, &tmp TSRMLS_CC);
928 }
929 if ((count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
930 char **tmp;
931
932 tmp = params = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zparams)), sizeof(char *));
933 zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
934 }
935
936 res = PQexecParams(obj->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
937
938 zend_hash_destroy(&zdtor);
939 if (types) {
940 efree(types);
941 }
942 if (params) {
943 efree(params);
944 }
945
946 if (res) {
947 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
948 return_value->type = IS_OBJECT;
949 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
950 }
951 } else {
952 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
953 }
954 } else {
955 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
956 }
957 }
958 zend_restore_error_handling(&zeh TSRMLS_CC);
959 }
960
961 static STATUS php_pqconn_prepare(PGconn *conn, const char *name, const char *query, HashTable *typest TSRMLS_DC)
962 {
963 Oid *types = NULL;
964 int count = 0;
965 PGresult *res;
966
967 if (typest && (count = zend_hash_num_elements(typest))) {
968 Oid *tmp;
969
970 tmp = types = ecalloc(count, sizeof(Oid));
971 zend_hash_apply_with_argument(typest, apply_to_oid, &tmp TSRMLS_CC);
972 }
973
974 res = PQprepare(conn, name, query, count, types);
975
976 if (types) {
977 efree(types);
978 }
979
980 if (res) {
981 if (PGRES_COMMAND_OK == PQresultStatus(res)) {
982 return SUCCESS;
983 } else {
984 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQresultErrorMessage(res));
985 }
986 PQclear(res);
987 } else {
988 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(conn));
989 }
990 return FAILURE;
991 }
992
993 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
994 ZEND_ARG_INFO(0, "name")
995 ZEND_ARG_INFO(0, "query")
996 ZEND_ARG_ARRAY_INFO(0, "types", 1)
997 ZEND_END_ARG_INFO();
998 static PHP_METHOD(pqconn, prepare) {
999 zend_error_handling zeh;
1000 zval *ztypes = NULL;
1001 char *name_str, *query_str;
1002 int name_len, *query_len;
1003
1004 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1005 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
1006 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1007
1008 if (obj->conn) {
1009 if (SUCCESS == php_pqconn_prepare(obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1010 return_value->type = IS_OBJECT;
1011 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, getThis(), name_str, NULL TSRMLS_CC);
1012 }
1013 } else {
1014 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1015 }
1016 }
1017 }
1018
1019 static zend_function_entry php_pqconn_methods[] = {
1020 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1021 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
1022 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
1023 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
1024 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
1025 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
1026 {0}
1027 };
1028
1029 static zval **php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type TSRMLS_DC)
1030 {
1031 zval **row = NULL;
1032 php_pqres_fetch_t orig_fetch;
1033
1034 if (!obj) {
1035 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1036 }
1037
1038 if (!obj->iter) {
1039 obj->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
1040 obj->iter->zi.funcs->rewind((zend_object_iterator *) obj->iter TSRMLS_CC);
1041 }
1042 orig_fetch = obj->iter->fetch_type;
1043 obj->iter->fetch_type = fetch_type;
1044 if (SUCCESS == obj->iter->zi.funcs->valid((zend_object_iterator *) obj->iter TSRMLS_CC)) {
1045 obj->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->iter, &row TSRMLS_CC);
1046 obj->iter->zi.funcs->move_forward((zend_object_iterator *) obj->iter TSRMLS_CC);
1047 }
1048 obj->iter->fetch_type = orig_fetch;
1049
1050 return row ? row : NULL;
1051 }
1052
1053 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
1054 ZEND_ARG_INFO(0, fetch_type)
1055 ZEND_END_ARG_INFO();
1056 static PHP_METHOD(pqres, fetchRow) {
1057 zend_error_handling zeh;
1058 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1059 long fetch_type = obj->iter ? obj->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
1060
1061 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1062 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) {
1063 zval **row = php_pqres_iteration(getThis(), obj, fetch_type TSRMLS_CC);
1064
1065 if (row) {
1066 RETVAL_ZVAL(*row, 1, 0);
1067 } else {
1068 RETVAL_FALSE;
1069 }
1070 }
1071 zend_restore_error_handling(&zeh TSRMLS_CC);
1072 }
1073
1074 static zval **column_at(zval *row, int col TSRMLS_DC)
1075 {
1076 zval **data = NULL;
1077 HashTable *ht = HASH_OF(row);
1078 int count = zend_hash_num_elements(ht);
1079
1080 if (col < count) {
1081 zend_hash_internal_pointer_reset(ht);
1082 while (col-- > 0) {
1083 zend_hash_move_forward(ht);
1084 }
1085 zend_hash_get_current_data(ht, (void *) &data);
1086 } else {
1087 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d does excess column count %d", col, count);
1088 }
1089 return data;
1090 }
1091
1092 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
1093 ZEND_ARG_INFO(0, col_num)
1094 ZEND_END_ARG_INFO();
1095 static PHP_METHOD(pqres, fetchCol) {
1096 zend_error_handling zeh;
1097 long fetch_col = 0;
1098
1099 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1100 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
1101 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1102 zval **row = php_pqres_iteration(getThis(), obj, obj->iter ? obj->iter->fetch_type : 0 TSRMLS_CC);
1103
1104 if (row) {
1105 zval **col = column_at(*row, fetch_col TSRMLS_CC);
1106
1107 if (col) {
1108 RETVAL_ZVAL(*col, 1, 0);
1109 } else {
1110 RETVAL_FALSE;
1111 }
1112 } else {
1113 RETVAL_FALSE;
1114 }
1115 }
1116 zend_restore_error_handling(&zeh TSRMLS_CC);
1117
1118 }
1119
1120 static zend_function_entry php_pqres_methods[] = {
1121 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
1122 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
1123 {0}
1124 };
1125
1126 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
1127 ZEND_ARG_OBJ_INFO(0, "Connection", "pq\\Connection", 0)
1128 ZEND_ARG_INFO(0, "name")
1129 ZEND_ARG_INFO(0, "query")
1130 ZEND_ARG_ARRAY_INFO(0, "types", 1)
1131 ZEND_END_ARG_INFO();
1132 static PHP_METHOD(pqstm, __construct) {
1133 zend_error_handling zeh;
1134 zval *zconn, *ztypes = NULL;
1135 char *name_str, *query_str;
1136 int name_len, *query_len;
1137
1138 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1139 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)) {
1140 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1141 php_pqconn_object_t *conn_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1142
1143 if (conn_obj->conn) {
1144 if (SUCCESS == php_pqconn_prepare(conn_obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1145 Z_ADDREF_P(zconn);
1146 obj->conn = zconn;
1147 obj->name = estrdup(name_str);
1148 }
1149 } else {
1150 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1151 }
1152 }
1153 }
1154
1155 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
1156 ZEND_ARG_ARRAY_INFO(0, "params", 1)
1157 ZEND_END_ARG_INFO();
1158 static PHP_METHOD(pqstm, exec) {
1159 zend_error_handling zeh;
1160 zval *zparams = NULL;
1161
1162 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1163 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
1164 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1165
1166 if (obj->conn && obj->name) {
1167 php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
1168
1169 if (conn_obj->conn) {
1170 int count = 0;
1171 char **params = NULL;
1172 HashTable zdtor;
1173 PGresult *res;
1174
1175 ZEND_INIT_SYMTABLE(&zdtor);
1176
1177 if (zparams && (count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
1178 char **tmp;
1179
1180 tmp = params = ecalloc(count, sizeof(char *));
1181 zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
1182 }
1183
1184 res = PQexecPrepared(conn_obj->conn, obj->name, count, (const char *const*) params, NULL, NULL, 0);
1185
1186 if (params) {
1187 efree(params);
1188 }
1189 zend_hash_destroy(&zdtor);
1190
1191 if (res) {
1192 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1193 return_value->type = IS_OBJECT;
1194 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
1195 }
1196 } else {
1197 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(conn_obj->conn));
1198 }
1199 } else {
1200 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1201 }
1202 } else {
1203 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
1204 }
1205 }
1206 zend_restore_error_handling(&zeh TSRMLS_CC);
1207 }
1208
1209 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
1210 ZEND_END_ARG_INFO();
1211 static PHP_METHOD(pqstm, desc) {
1212 zend_error_handling zeh;
1213
1214 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1215 if (SUCCESS == zend_parse_parameters_none()) {
1216 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1217
1218 if (obj->conn && obj->name) {
1219 php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
1220
1221 if (conn_obj->conn) {
1222 PGresult *res = PQdescribePrepared(conn_obj->conn, obj->name);
1223
1224 if (res) {
1225 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1226 int p, params;
1227
1228 array_init(return_value);
1229 for (p = 0, params = PQnparams(res); p < params; ++p) {
1230 add_next_index_long(return_value, PQparamtype(res, p));
1231 }
1232 }
1233 } else {
1234 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PQerrorMessage(conn_obj->conn));
1235 }
1236 } else {
1237 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1238 }
1239 } else {
1240 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
1241 }
1242 }
1243 zend_restore_error_handling(&zeh TSRMLS_CC);
1244 }
1245
1246 static zend_function_entry php_pqstm_methods[] = {
1247 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1248 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
1249 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
1250 {0}
1251 };
1252
1253 /* {{{ PHP_MINIT_FUNCTION
1254 */
1255 PHP_MINIT_FUNCTION(pq)
1256 {
1257 zend_class_entry ce = {0};
1258 php_pq_object_prophandler_t ph = {0};
1259
1260 zend_hash_init(&php_pqconn_object_prophandlers, 1, NULL, NULL, 1);
1261 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
1262 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1263 php_pqconn_class_entry->create_object = php_pqconn_create_object;
1264 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1265 php_pqconn_object_handlers.read_property = php_pqconn_object_read_prop;
1266 php_pqconn_object_handlers.write_property = php_pqconn_object_write_prop;
1267
1268 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
1269 ph.read = php_pqconn_object_read_status;
1270 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1271
1272 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
1273 ph.read = php_pqconn_object_read_transaction_status;
1274 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
1275
1276 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
1277 ph.read = NULL; /* forward to std prophandler */
1278 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
1279
1280 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1281 ph.read = php_pqconn_object_read_error_message;
1282 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1283
1284 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("types"), ZEND_ACC_PUBLIC TSRMLS_CC);
1285 ph.read = php_pqconn_object_read_types;
1286 zend_hash_add(&php_pqconn_object_prophandlers, "types", sizeof("types"), (void *) &ph, sizeof(ph), NULL);
1287
1288 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
1289 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
1290 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
1291 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
1292 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
1293 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
1294 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
1295 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
1296
1297 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
1298 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
1299 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
1300 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
1301 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
1302
1303 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
1304 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
1305 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
1306 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
1307
1308 zend_hash_init(&php_pqres_object_prophandlers, 1, NULL, NULL, 1);
1309 memset(&ce, 0, sizeof(ce));
1310 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
1311 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1312 php_pqres_class_entry->create_object = php_pqres_create_object;
1313 php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs;
1314 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
1315
1316 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1317 php_pqres_object_handlers.read_property = php_pqres_object_read_prop;
1318 php_pqres_object_handlers.write_property = php_pqres_object_write_prop;
1319
1320 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
1321 ph.read = php_pqres_object_read_status;
1322 zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1323
1324 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1325 ph.read = php_pqres_object_read_error_message;
1326 zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1327
1328 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1329 ph.read = php_pqres_object_read_num_rows;
1330 zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL);
1331
1332 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1333 ph.read = php_pqres_object_read_num_cols;
1334 zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL);
1335
1336 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1337 ph.read = php_pqres_object_read_affected_rows;
1338 zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL);
1339
1340 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);
1341 ph.read = php_pqres_object_read_fetch_type;
1342 ph.write = php_pqres_object_write_fetch_type;
1343 zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL);
1344 ph.write = NULL;
1345
1346 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC);
1347 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC);
1348 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC);
1349 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC);
1350 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC);
1351 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC);
1352 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC);
1353 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC);
1354 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC);
1355 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC);
1356
1357 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC);
1358 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC);
1359 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
1360
1361 zend_hash_init(&php_pqstm_object_prophandlers, 1, NULL, NULL, 1);
1362 memset(&ce, 0, sizeof(ce));
1363 INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods);
1364 php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1365 php_pqstm_class_entry->create_object = php_pqstm_create_object;
1366
1367 memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1368 php_pqstm_object_handlers.read_property = php_pqstm_object_read_prop;
1369 php_pqstm_object_handlers.write_property = php_pqstm_object_write_prop;
1370
1371 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
1372 ph.read = php_pqstm_object_read_name;
1373 zend_hash_add(&php_pqstm_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
1374
1375 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
1376 ph.read = php_pqstm_object_read_connection;
1377 zend_hash_add(&php_pqstm_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
1378
1379 /*
1380 REGISTER_INI_ENTRIES();
1381 */
1382 return SUCCESS;
1383 }
1384 /* }}} */
1385
1386 /* {{{ PHP_MSHUTDOWN_FUNCTION
1387 */
1388 PHP_MSHUTDOWN_FUNCTION(pq)
1389 {
1390 /* uncomment this line if you have INI entries
1391 UNREGISTER_INI_ENTRIES();
1392 */
1393 return SUCCESS;
1394 }
1395 /* }}} */
1396
1397 /* {{{ PHP_MINFO_FUNCTION
1398 */
1399 PHP_MINFO_FUNCTION(pq)
1400 {
1401 php_info_print_table_start();
1402 php_info_print_table_header(2, "pq support", "enabled");
1403 php_info_print_table_end();
1404
1405 /* Remove comments if you have entries in php.ini
1406 DISPLAY_INI_ENTRIES();
1407 */
1408 }
1409 /* }}} */
1410
1411
1412
1413 /*
1414 * Local variables:
1415 * tab-width: 4
1416 * c-basic-offset: 4
1417 * End:
1418 * vim600: noet sw=4 ts=4 fdm=marker
1419 * vim<600: noet sw=4 ts=4
1420 */