license
[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_socket(void *o, zval *return_value TSRMLS_DC)
440 {
441 php_pqconn_object_t *obj = o;
442 php_stream *stream;
443 int socket = PQsocket(obj->conn);
444
445 if ((stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
446 php_stream_to_zval(stream, return_value);
447 } else {
448 RETVAL_NULL();
449 }
450 }
451
452 static void php_pqconn_object_read_error_message(void *o, zval *return_value TSRMLS_DC)
453 {
454 php_pqconn_object_t *obj = o;
455 char *error = PQerrorMessage(obj->conn);
456
457 if (error) {
458 RETVAL_STRING(error, 1);
459 } else {
460 RETVAL_NULL();
461 }
462 }
463
464 /* FIXME: extend to types->nspname->typname */
465 #define PHP_PQ_TYPES_QUERY \
466 "select t.oid, t.* " \
467 "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \
468 "where typisdefined " \
469 "and typrelid=0 " \
470 "and nspname in ('public', 'pg_catalog')"
471 static void php_pqconn_object_read_types(void *o, zval *return_value TSRMLS_DC)
472 {
473 php_pqconn_object_t *obj = o;
474 PGresult *res = PQexec(obj->conn, PHP_PQ_TYPES_QUERY);
475
476 /* FIXME: cache that */
477 if (res) {
478 if (PGRES_TUPLES_OK == PQresultStatus(res)) {
479 int r, rows;
480 zval *byoid, *byname;
481
482 MAKE_STD_ZVAL(byoid);
483 MAKE_STD_ZVAL(byname);
484 object_init(byoid);
485 object_init(byname);
486 object_init(return_value);
487 for (r = 0, rows = PQntuples(res); r < rows; ++r) {
488 zval *row = php_pqres_row_to_zval(res, r, PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
489
490 add_property_zval(byoid, PQgetvalue(res, r, 0), row);
491 add_property_zval(byname, PQgetvalue(res, r, 1), row);
492 zval_ptr_dtor(&row);
493 }
494
495 add_property_zval(return_value, "byOid", byoid);
496 add_property_zval(return_value, "byName", byname);
497 zval_ptr_dtor(&byoid);
498 zval_ptr_dtor(&byname);
499 } else {
500 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types: %s", PQresultErrorMessage(res));
501 }
502 PQclear(res);
503 } else {
504 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types: %s", PQerrorMessage(obj->conn));
505 }
506 }
507
508 static void php_pqres_object_read_status(void *o, zval *return_value TSRMLS_DC)
509 {
510 php_pqres_object_t *obj = o;
511
512 RETVAL_LONG(PQresultStatus(obj->res));
513 }
514
515 static void php_pqres_object_read_error_message(void *o, zval *return_value TSRMLS_DC)
516 {
517 php_pqres_object_t *obj = o;
518 char *error = PQresultErrorMessage(obj->res);
519
520 if (error) {
521 RETVAL_STRING(error, 1);
522 } else {
523 RETVAL_NULL();
524 }
525 }
526
527 static void php_pqres_object_read_num_rows(void *o, zval *return_value TSRMLS_DC)
528 {
529 php_pqres_object_t *obj = o;
530
531 RETVAL_LONG(PQntuples(obj->res));
532 }
533
534 static void php_pqres_object_read_num_cols(void *o, zval *return_value TSRMLS_DC)
535 {
536 php_pqres_object_t *obj = o;
537
538 RETVAL_LONG(PQnfields(obj->res));
539 }
540
541 static void php_pqres_object_read_affected_rows(void *o, zval *return_value TSRMLS_DC)
542 {
543 php_pqres_object_t *obj = o;
544
545 RETVAL_LONG(atoi(PQcmdTuples(obj->res)));
546 }
547
548 static void php_pqres_object_read_fetch_type(void *o, zval *return_value TSRMLS_DC)
549 {
550 php_pqres_object_t *obj = o;
551
552 if (obj->iter) {
553 RETVAL_LONG(obj->iter->fetch_type);
554 } else {
555 RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
556 }
557 }
558
559 static void php_pqres_object_write_fetch_type(void *o, zval *value TSRMLS_DC)
560 {
561 php_pqres_object_t *obj = o;
562 zval *zfetch_type = value;
563
564 if (Z_TYPE_P(zfetch_type) != IS_LONG) {
565 convert_to_long_ex(&zfetch_type);
566 }
567
568 obj->iter->fetch_type = Z_LVAL_P(zfetch_type);
569
570 if (zfetch_type != value) {
571 zval_ptr_dtor(&zfetch_type);
572 }
573 }
574
575 static void php_pqstm_object_read_name(void *o, zval *return_value TSRMLS_DC)
576 {
577 php_pqstm_object_t *obj = o;
578
579 RETVAL_STRING(obj->name, 1);
580 }
581
582 static void php_pqstm_object_read_connection(void *o, zval *return_value TSRMLS_DC)
583 {
584 php_pqstm_object_t *obj = o;
585
586 RETVAL_ZVAL(obj->conn, 1, 0);
587 }
588
589 static zval *php_pqconn_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
590 {
591 php_pqconn_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
592 php_pq_object_prophandler_t *handler;
593 zval *return_value;
594
595 if (!obj->conn) {
596 zend_error(E_WARNING, "Connection not initialized");
597 } else if (SUCCESS == zend_hash_find(&php_pqconn_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
598 if (type == BP_VAR_R) {
599 ALLOC_ZVAL(return_value);
600 Z_SET_REFCOUNT_P(return_value, 0);
601 Z_UNSET_ISREF_P(return_value);
602
603 handler->read(obj, return_value TSRMLS_CC);
604 } else {
605 zend_error(E_ERROR, "Cannot access pq\\Connection properties by reference or array key/index");
606 return_value = NULL;
607 }
608 } else {
609 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
610 }
611
612 return return_value;
613 }
614
615 static void php_pqconn_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
616 {
617 php_pqconn_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
618 php_pq_object_prophandler_t *handler;
619
620 if (SUCCESS == zend_hash_find(&php_pqconn_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
621 if (handler->write) {
622 handler->write(obj, value TSRMLS_CC);
623 }
624 } else {
625 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
626 }
627 }
628
629 static zval *php_pqres_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
630 {
631 php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
632 php_pq_object_prophandler_t *handler;
633 zval *return_value;
634
635 if (!obj->res) {
636 zend_error(E_WARNING, "Result not initialized");
637 } else if (SUCCESS == zend_hash_find(&php_pqres_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
638 if (type == BP_VAR_R) {
639 ALLOC_ZVAL(return_value);
640 Z_SET_REFCOUNT_P(return_value, 0);
641 Z_UNSET_ISREF_P(return_value);
642
643 handler->read(obj, return_value TSRMLS_CC);
644 } else {
645 zend_error(E_ERROR, "Cannot access pq\\Result properties by reference or array key/index");
646 return_value = NULL;
647 }
648 } else {
649 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
650 }
651
652 return return_value;
653 }
654
655 static void php_pqres_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
656 {
657 php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
658 php_pq_object_prophandler_t *handler;
659
660 if (!obj->res) {
661 zend_error(E_WARNING, "Result not initialized");
662 } else if (SUCCESS == zend_hash_find(&php_pqres_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
663 if (handler->write) {
664 /* ensure obj->iter is initialized, for e.g. write_fetch_type */
665 if (!obj->iter) {
666 obj->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC);
667 obj->iter->zi.funcs->rewind((zend_object_iterator *) obj->iter TSRMLS_CC);
668 }
669 handler->write(obj, value TSRMLS_CC);
670 }
671 } else {
672 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
673 }
674 }
675
676 static zval *php_pqstm_object_read_prop(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
677 {
678 php_pqstm_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
679 php_pq_object_prophandler_t *handler;
680 zval *return_value;
681
682 if (!obj->conn) {
683 zend_error(E_WARNING, "Statement not initialized");
684 } else if (SUCCESS == zend_hash_find(&php_pqstm_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
685 if (type == BP_VAR_R) {
686 ALLOC_ZVAL(return_value);
687 Z_SET_REFCOUNT_P(return_value, 0);
688 Z_UNSET_ISREF_P(return_value);
689
690 handler->read(obj, return_value TSRMLS_CC);
691 } else {
692 zend_error(E_ERROR, "Cannot access pq\\Statement properties by reference or array key/index");
693 return_value = NULL;
694 }
695 } else {
696 return_value = zend_get_std_object_handlers()->read_property(object, member, type, key TSRMLS_CC);
697 }
698
699 return return_value;
700 }
701
702 static void php_pqstm_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
703 {
704 php_pqstm_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
705 php_pq_object_prophandler_t *handler;
706
707 if (!obj->conn) {
708 zend_error(E_WARNING, "Result not initialized");
709 } else if (SUCCESS == zend_hash_find(&php_pqstm_object_prophandlers, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void *) &handler)) {
710 if (handler->write) {
711 handler->write(obj, value TSRMLS_CC);
712 }
713 } else {
714 zend_get_std_object_handlers()->write_property(object, member, value, key TSRMLS_CC);
715 }
716 }
717
718 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
719 ZEND_ARG_INFO(0, dsn)
720 ZEND_ARG_INFO(0, block)
721 ZEND_END_ARG_INFO();
722 static PHP_METHOD(pqconn, __construct) {
723 zend_error_handling zeh;
724 char *dsn_str;
725 int dsn_len;
726 zend_bool block = 1;
727
728 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
729 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &dsn_str, &dsn_len, &block)) {
730 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
731
732 if (obj->conn) {
733 PQfinish(obj->conn);
734 }
735 if ((obj->blocking = block)) {
736 obj->conn = PQconnectdb(dsn_str);
737 } else {
738 obj->conn = PQconnectStart(dsn_str);
739 obj->poller = (int (*)(PGconn*)) PQconnectPoll;
740 }
741
742 if (CONNECTION_BAD == PQstatus(obj->conn)) {
743 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection failed: %s", PQerrorMessage(obj->conn));
744 }
745 }
746 zend_restore_error_handling(&zeh TSRMLS_CC);
747 }
748
749 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
750 ZEND_END_ARG_INFO();
751 static PHP_METHOD(pqconn, reset) {
752 if (SUCCESS == zend_parse_parameters_none()) {
753 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
754
755 if (obj->conn) {
756 if (obj->blocking) {
757 PQreset(obj->conn);
758 RETURN_TRUE; /* probably ;) */
759 } if (PQresetStart(obj->conn)) {
760 obj->poller = (int (*)(PGconn*)) PQresetPoll;
761 RETURN_TRUE;
762 }
763 } else {
764 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
765 }
766 RETURN_FALSE;
767 }
768 }
769
770 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
771 ZEND_END_ARG_INFO();
772 static PHP_METHOD(pqconn, poll) {
773 if (SUCCESS == zend_parse_parameters_none()) {
774 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
775
776 if (obj->conn) {
777 if (obj->poller) {
778 RETURN_LONG(obj->poller(obj->conn));
779 } else {
780 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active");
781 }
782 } else {
783 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
784 }
785 RETURN_FALSE;
786 }
787 }
788
789 static STATUS php_pqres_success(PGresult *res TSRMLS_DC)
790 {
791 switch (PQresultStatus(res)) {
792 case PGRES_BAD_RESPONSE:
793 case PGRES_NONFATAL_ERROR:
794 case PGRES_FATAL_ERROR:
795 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res));
796 return FAILURE;
797 default:
798 return SUCCESS;
799 }
800 }
801
802 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
803 ZEND_ARG_INFO(0, query)
804 ZEND_END_ARG_INFO();
805 static PHP_METHOD(pqconn, exec) {
806 zend_error_handling zeh;
807 char *query_str;
808 int query_len;
809
810 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
811 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) {
812 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
813
814 if (obj->conn) {
815 PGresult *res = PQexec(obj->conn, query_str);
816
817 if (res) {
818 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
819 return_value->type = IS_OBJECT;
820 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
821 }
822 } else {
823 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
824 }
825 } else {
826 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
827 }
828 }
829 zend_restore_error_handling(&zeh TSRMLS_CC);
830 }
831
832 static int apply_to_oid(void *p, void *arg TSRMLS_DC)
833 {
834 Oid **types = arg;
835 zval **ztype = p;
836
837 if (Z_TYPE_PP(ztype) != IS_LONG) {
838 convert_to_long_ex(ztype);
839 }
840
841 **types = Z_LVAL_PP(ztype);
842 ++*types;
843
844 if (*ztype != *(zval **)p) {
845 zval_ptr_dtor(ztype);
846 }
847 return ZEND_HASH_APPLY_KEEP;
848 }
849
850 static int apply_to_param(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
851 {
852 char ***params;
853 HashTable *zdtor;
854 zval **zparam = p;
855
856 params = (char ***) va_arg(argv, char ***);
857 zdtor = (HashTable *) va_arg(argv, HashTable *);
858
859 if (Z_TYPE_PP(zparam) == IS_NULL) {
860 **params = NULL;
861 ++*params;
862 } else {
863 if (Z_TYPE_PP(zparam) != IS_STRING) {
864 convert_to_string_ex(zparam);
865 }
866
867 **params = Z_STRVAL_PP(zparam);
868 ++*params;
869
870 if (*zparam != *(zval **)p) {
871 zend_hash_next_index_insert(zdtor, zparam, sizeof(zval *), NULL);
872 }
873 }
874 return ZEND_HASH_APPLY_KEEP;
875 }
876
877 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
878 ZEND_ARG_INFO(0, query)
879 ZEND_ARG_ARRAY_INFO(0, params, 0)
880 ZEND_ARG_ARRAY_INFO(0, types, 1)
881 ZEND_END_ARG_INFO();
882 static PHP_METHOD(pqconn, execParams) {
883 zend_error_handling zeh;
884 char *query_str;
885 int query_len;
886 zval *zparams;
887 zval *ztypes = NULL;
888
889 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
890 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) {
891 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
892
893 if (obj->conn) {
894 PGresult *res;
895 int count = 0;
896 Oid *types = NULL;
897 char **params = NULL;
898 HashTable zdtor;
899
900 ZEND_INIT_SYMTABLE(&zdtor);
901
902 if (ztypes && zend_hash_num_elements(Z_ARRVAL_P(ztypes))) {
903 Oid *tmp;
904
905 tmp = types = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(ztypes)), sizeof(Oid));
906 zend_hash_apply_with_argument(Z_ARRVAL_P(ztypes), apply_to_oid, &tmp TSRMLS_CC);
907 }
908 if ((count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
909 char **tmp;
910
911 tmp = params = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zparams)), sizeof(char *));
912 zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
913 }
914
915 res = PQexecParams(obj->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0);
916
917 zend_hash_destroy(&zdtor);
918 if (types) {
919 efree(types);
920 }
921 if (params) {
922 efree(params);
923 }
924
925 if (res) {
926 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
927 return_value->type = IS_OBJECT;
928 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
929 }
930 } else {
931 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query: %s", PQerrorMessage(obj->conn));
932 }
933 } else {
934 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
935 }
936 }
937 zend_restore_error_handling(&zeh TSRMLS_CC);
938 }
939
940 static STATUS php_pqconn_prepare(PGconn *conn, const char *name, const char *query, HashTable *typest TSRMLS_DC)
941 {
942 Oid *types = NULL;
943 int count = 0;
944 PGresult *res;
945
946 if (typest && (count = zend_hash_num_elements(typest))) {
947 Oid *tmp;
948
949 tmp = types = ecalloc(count, sizeof(Oid));
950 zend_hash_apply_with_argument(typest, apply_to_oid, &tmp TSRMLS_CC);
951 }
952
953 res = PQprepare(conn, name, query, count, types);
954
955 if (types) {
956 efree(types);
957 }
958
959 if (res) {
960 if (PGRES_COMMAND_OK == PQresultStatus(res)) {
961 return SUCCESS;
962 } else {
963 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQresultErrorMessage(res));
964 }
965 PQclear(res);
966 } else {
967 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement: %s", PQerrorMessage(conn));
968 }
969 return FAILURE;
970 }
971
972 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
973 ZEND_ARG_INFO(0, "name")
974 ZEND_ARG_INFO(0, "query")
975 ZEND_ARG_ARRAY_INFO(0, "types", 1)
976 ZEND_END_ARG_INFO();
977 static PHP_METHOD(pqconn, prepare) {
978 zend_error_handling zeh;
979 zval *ztypes = NULL;
980 char *name_str, *query_str;
981 int name_len, *query_len;
982
983 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
984 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) {
985 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
986
987 if (obj->conn) {
988 if (SUCCESS == php_pqconn_prepare(obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
989 return_value->type = IS_OBJECT;
990 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, getThis(), name_str, NULL TSRMLS_CC);
991 }
992 } else {
993 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
994 }
995 }
996 }
997
998 static zend_function_entry php_pqconn_methods[] = {
999 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1000 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
1001 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
1002 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
1003 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
1004 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
1005 {0}
1006 };
1007
1008 static zval **php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type TSRMLS_DC)
1009 {
1010 zval **row = NULL;
1011 php_pqres_fetch_t orig_fetch;
1012
1013 if (!obj) {
1014 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1015 }
1016
1017 if (!obj->iter) {
1018 obj->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC);
1019 obj->iter->zi.funcs->rewind((zend_object_iterator *) obj->iter TSRMLS_CC);
1020 }
1021 orig_fetch = obj->iter->fetch_type;
1022 obj->iter->fetch_type = fetch_type;
1023 if (SUCCESS == obj->iter->zi.funcs->valid((zend_object_iterator *) obj->iter TSRMLS_CC)) {
1024 obj->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->iter, &row TSRMLS_CC);
1025 obj->iter->zi.funcs->move_forward((zend_object_iterator *) obj->iter TSRMLS_CC);
1026 }
1027 obj->iter->fetch_type = orig_fetch;
1028
1029 return row ? row : NULL;
1030 }
1031
1032 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0)
1033 ZEND_ARG_INFO(0, fetch_type)
1034 ZEND_END_ARG_INFO();
1035 static PHP_METHOD(pqres, fetchRow) {
1036 zend_error_handling zeh;
1037 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1038 long fetch_type = obj->iter ? obj->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
1039
1040 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1041 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) {
1042 zval **row = php_pqres_iteration(getThis(), obj, fetch_type TSRMLS_CC);
1043
1044 if (row) {
1045 RETVAL_ZVAL(*row, 1, 0);
1046 } else {
1047 RETVAL_FALSE;
1048 }
1049 }
1050 zend_restore_error_handling(&zeh TSRMLS_CC);
1051 }
1052
1053 static zval **column_at(zval *row, int col TSRMLS_DC)
1054 {
1055 zval **data = NULL;
1056 HashTable *ht = HASH_OF(row);
1057 int count = zend_hash_num_elements(ht);
1058
1059 if (col < count) {
1060 zend_hash_internal_pointer_reset(ht);
1061 while (col-- > 0) {
1062 zend_hash_move_forward(ht);
1063 }
1064 zend_hash_get_current_data(ht, (void *) &data);
1065 } else {
1066 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d does excess column count %d", col, count);
1067 }
1068 return data;
1069 }
1070
1071 ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
1072 ZEND_ARG_INFO(0, col_num)
1073 ZEND_END_ARG_INFO();
1074 static PHP_METHOD(pqres, fetchCol) {
1075 zend_error_handling zeh;
1076 long fetch_col = 0;
1077
1078 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1079 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) {
1080 php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1081 zval **row = php_pqres_iteration(getThis(), obj, obj->iter ? obj->iter->fetch_type : 0 TSRMLS_CC);
1082
1083 if (row) {
1084 zval **col = column_at(*row, fetch_col TSRMLS_CC);
1085
1086 if (col) {
1087 RETVAL_ZVAL(*col, 1, 0);
1088 } else {
1089 RETVAL_FALSE;
1090 }
1091 } else {
1092 RETVAL_FALSE;
1093 }
1094 }
1095 zend_restore_error_handling(&zeh TSRMLS_CC);
1096
1097 }
1098
1099 static zend_function_entry php_pqres_methods[] = {
1100 PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC)
1101 PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC)
1102 {0}
1103 };
1104
1105 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_construct, 0, 0, 3)
1106 ZEND_ARG_OBJ_INFO(0, "Connection", "pq\\Connection", 0)
1107 ZEND_ARG_INFO(0, "name")
1108 ZEND_ARG_INFO(0, "query")
1109 ZEND_ARG_ARRAY_INFO(0, "types", 1)
1110 ZEND_END_ARG_INFO();
1111 static PHP_METHOD(pqstm, __construct) {
1112 zend_error_handling zeh;
1113 zval *zconn, *ztypes = NULL;
1114 char *name_str, *query_str;
1115 int name_len, *query_len;
1116
1117 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1118 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)) {
1119 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1120 php_pqconn_object_t *conn_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1121
1122 if (conn_obj->conn) {
1123 if (SUCCESS == php_pqconn_prepare(conn_obj->conn, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) {
1124 Z_ADDREF_P(zconn);
1125 obj->conn = zconn;
1126 obj->name = estrdup(name_str);
1127 }
1128 } else {
1129 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1130 }
1131 }
1132 }
1133
1134 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec, 0, 0, 0)
1135 ZEND_ARG_ARRAY_INFO(0, "params", 1)
1136 ZEND_END_ARG_INFO();
1137 static PHP_METHOD(pqstm, exec) {
1138 zend_error_handling zeh;
1139 zval *zparams = NULL;
1140
1141 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1142 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) {
1143 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1144
1145 if (obj->conn && obj->name) {
1146 php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
1147
1148 if (conn_obj->conn) {
1149 int count = 0;
1150 char **params = NULL;
1151 HashTable zdtor;
1152 PGresult *res;
1153
1154 ZEND_INIT_SYMTABLE(&zdtor);
1155
1156 if (zparams && (count = zend_hash_num_elements(Z_ARRVAL_P(zparams)))) {
1157 char **tmp;
1158
1159 tmp = params = ecalloc(count, sizeof(char *));
1160 zend_hash_apply_with_arguments(Z_ARRVAL_P(zparams) TSRMLS_CC, apply_to_param, 2, &tmp, &zdtor);
1161 }
1162
1163 res = PQexecPrepared(conn_obj->conn, obj->name, count, (const char *const*) params, NULL, NULL, 0);
1164
1165 if (params) {
1166 efree(params);
1167 }
1168 zend_hash_destroy(&zdtor);
1169
1170 if (res) {
1171 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1172 return_value->type = IS_OBJECT;
1173 return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, res, NULL TSRMLS_CC);
1174 }
1175 } else {
1176 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement: %s", PQerrorMessage(conn_obj->conn));
1177 }
1178 } else {
1179 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1180 }
1181 } else {
1182 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
1183 }
1184 }
1185 zend_restore_error_handling(&zeh TSRMLS_CC);
1186 }
1187
1188 ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0)
1189 ZEND_END_ARG_INFO();
1190 static PHP_METHOD(pqstm, desc) {
1191 zend_error_handling zeh;
1192
1193 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
1194 if (SUCCESS == zend_parse_parameters_none()) {
1195 php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1196
1197 if (obj->conn && obj->name) {
1198 php_pqconn_object_t *conn_obj = zend_object_store_get_object(obj->conn TSRMLS_CC);
1199
1200 if (conn_obj->conn) {
1201 PGresult *res = PQdescribePrepared(conn_obj->conn, obj->name);
1202
1203 if (res) {
1204 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
1205 int p, params;
1206
1207 array_init(return_value);
1208 for (p = 0, params = PQnparams(res); p < params; ++p) {
1209 add_next_index_long(return_value, PQparamtype(res, p));
1210 }
1211 }
1212 } else {
1213 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PQerrorMessage(conn_obj->conn));
1214 }
1215 } else {
1216 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not initialized");
1217 }
1218 } else {
1219 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized");
1220 }
1221 }
1222 zend_restore_error_handling(&zeh TSRMLS_CC);
1223 }
1224
1225 static zend_function_entry php_pqstm_methods[] = {
1226 PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1227 PHP_ME(pqstm, exec, ai_pqstm_exec, ZEND_ACC_PUBLIC)
1228 PHP_ME(pqstm, desc, ai_pqstm_desc, ZEND_ACC_PUBLIC)
1229 {0}
1230 };
1231
1232 /* {{{ PHP_MINIT_FUNCTION
1233 */
1234 PHP_MINIT_FUNCTION(pq)
1235 {
1236 zend_class_entry ce = {0};
1237 php_pq_object_prophandler_t ph = {0};
1238
1239 zend_hash_init(&php_pqconn_object_prophandlers, 1, NULL, NULL, 1);
1240 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
1241 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1242 php_pqconn_class_entry->create_object = php_pqconn_create_object;
1243 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1244 php_pqconn_object_handlers.read_property = php_pqconn_object_read_prop;
1245 php_pqconn_object_handlers.write_property = php_pqconn_object_write_prop;
1246
1247 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
1248 ph.read = php_pqconn_object_read_status;
1249 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1250
1251 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
1252 ph.read = php_pqconn_object_read_transaction_status;
1253 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
1254
1255 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
1256 ph.read = php_pqconn_object_read_socket;
1257 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
1258
1259 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1260 ph.read = php_pqconn_object_read_error_message;
1261 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1262
1263 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("types"), ZEND_ACC_PUBLIC TSRMLS_CC);
1264 ph.read = php_pqconn_object_read_types;
1265 zend_hash_add(&php_pqconn_object_prophandlers, "types", sizeof("types"), (void *) &ph, sizeof(ph), NULL);
1266
1267 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
1268 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
1269 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
1270 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
1271 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
1272 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
1273 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
1274 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
1275
1276 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
1277 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
1278 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
1279 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
1280 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
1281
1282 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
1283 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
1284 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
1285 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
1286
1287 zend_hash_init(&php_pqres_object_prophandlers, 1, NULL, NULL, 1);
1288 memset(&ce, 0, sizeof(ce));
1289 INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods);
1290 php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1291 php_pqres_class_entry->create_object = php_pqres_create_object;
1292 php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs;
1293 php_pqres_class_entry->get_iterator = php_pqres_iterator_init;
1294
1295 memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1296 php_pqres_object_handlers.read_property = php_pqres_object_read_prop;
1297 php_pqres_object_handlers.write_property = php_pqres_object_write_prop;
1298
1299 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
1300 ph.read = php_pqres_object_read_status;
1301 zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1302
1303 zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1304 ph.read = php_pqres_object_read_error_message;
1305 zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1306
1307 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1308 ph.read = php_pqres_object_read_num_rows;
1309 zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL);
1310
1311 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1312 ph.read = php_pqres_object_read_num_cols;
1313 zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL);
1314
1315 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1316 ph.read = php_pqres_object_read_affected_rows;
1317 zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL);
1318
1319 zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);
1320 ph.read = php_pqres_object_read_fetch_type;
1321 ph.write = php_pqres_object_write_fetch_type;
1322 zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL);
1323 ph.write = NULL;
1324
1325 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC);
1326 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC);
1327 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC);
1328 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC);
1329 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC);
1330 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC);
1331 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC);
1332 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC);
1333 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC);
1334 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC);
1335
1336 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC);
1337 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC);
1338 zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC);
1339
1340 zend_hash_init(&php_pqstm_object_prophandlers, 1, NULL, NULL, 1);
1341 memset(&ce, 0, sizeof(ce));
1342 INIT_NS_CLASS_ENTRY(ce, "pq", "Statement", php_pqstm_methods);
1343 php_pqstm_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1344 php_pqstm_class_entry->create_object = php_pqstm_create_object;
1345
1346 memcpy(&php_pqstm_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1347 php_pqstm_object_handlers.read_property = php_pqstm_object_read_prop;
1348 php_pqstm_object_handlers.write_property = php_pqstm_object_write_prop;
1349
1350 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
1351 ph.read = php_pqstm_object_read_name;
1352 zend_hash_add(&php_pqstm_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
1353
1354 zend_declare_property_null(php_pqstm_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
1355 ph.read = php_pqstm_object_read_connection;
1356 zend_hash_add(&php_pqstm_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
1357
1358 /*
1359 REGISTER_INI_ENTRIES();
1360 */
1361 return SUCCESS;
1362 }
1363 /* }}} */
1364
1365 /* {{{ PHP_MSHUTDOWN_FUNCTION
1366 */
1367 PHP_MSHUTDOWN_FUNCTION(pq)
1368 {
1369 /* uncomment this line if you have INI entries
1370 UNREGISTER_INI_ENTRIES();
1371 */
1372 return SUCCESS;
1373 }
1374 /* }}} */
1375
1376 /* {{{ PHP_MINFO_FUNCTION
1377 */
1378 PHP_MINFO_FUNCTION(pq)
1379 {
1380 php_info_print_table_start();
1381 php_info_print_table_header(2, "pq support", "enabled");
1382 php_info_print_table_end();
1383
1384 /* Remove comments if you have entries in php.ini
1385 DISPLAY_INI_ENTRIES();
1386 */
1387 }
1388 /* }}} */
1389
1390
1391
1392 /*
1393 * Local variables:
1394 * tab-width: 4
1395 * c-basic-offset: 4
1396 * End:
1397 * vim600: noet sw=4 ts=4 fdm=marker
1398 * vim<600: noet sw=4 ts=4
1399 */