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