79fa9a0422d58ca8bd74779b5b32a401d7bfada8
[m6w6/ext-pq] / src / php_pqconn.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
19 #define SMART_STR_PREALLOC 256
20 #include <ext/standard/php_smart_str.h>
21
22 #include <libpq-events.h>
23 #include <fnmatch.h>
24
25 #include "php_pq.h"
26 #include "php_pq_misc.h"
27 #include "php_pq_object.h"
28 #include "php_pqexc.h"
29 #include "php_pqconn.h"
30 #include "php_pqconn_event.h"
31 #include "php_pqres.h"
32 #include "php_pqstm.h"
33 #include "php_pqtxn.h"
34 #include "php_pqcur.h"
35
36 zend_class_entry *php_pqconn_class_entry;
37 static zend_object_handlers php_pqconn_object_handlers;
38 static HashTable php_pqconn_object_prophandlers;
39
40 /*
41 static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC)
42 {
43 zval **evhs;
44
45 if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
46 zend_hash_index_del(Z_ARRVAL_PP(evhs), id);
47 }
48 }
49 */
50
51 static ulong php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, php_pq_callback_t *cb TSRMLS_DC)
52 {
53 ulong h;
54 HashTable *evhs;
55
56 if (SUCCESS != zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
57 HashTable evh;
58
59 zend_hash_init(&evh, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
60 zend_hash_add(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(evh), (void *) &evhs);
61 }
62
63 php_pq_callback_addref(cb);
64 h = zend_hash_next_free_element(evhs);
65 zend_hash_index_update(evhs, h, (void *) cb, sizeof(*cb), NULL);
66
67 return h;
68 }
69
70 static void php_pqconn_object_free(void *o TSRMLS_DC)
71 {
72 php_pqconn_object_t *obj = o;
73 #if DBG_GC
74 fprintf(stderr, "FREE conn(#%d) %p\n", obj->zv.handle, obj);
75 #endif
76 if (obj->intern) {
77 php_pq_callback_dtor(&obj->intern->onevent);
78 php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn TSRMLS_CC);
79 php_resource_factory_dtor(&obj->intern->factory);
80 zend_hash_destroy(&obj->intern->listeners);
81 zend_hash_destroy(&obj->intern->converters);
82 zend_hash_destroy(&obj->intern->eventhandlers);
83 efree(obj->intern);
84 obj->intern = NULL;
85 }
86 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
87 efree(obj);
88 }
89
90
91 zend_object_value php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern, php_pqconn_object_t **ptr TSRMLS_DC)
92 {
93 php_pqconn_object_t *o;
94
95 o = ecalloc(1, sizeof(*o));
96 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
97 object_properties_init((zend_object *) o, ce);
98 o->prophandler = &php_pqconn_object_prophandlers;
99
100 if (ptr) {
101 *ptr = o;
102 }
103
104 if (intern) {
105 o->intern = intern;
106 }
107
108 o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqconn_object_free, NULL TSRMLS_CC);
109 o->zv.handlers = &php_pqconn_object_handlers;
110
111 return o->zv;
112 }
113
114 static zend_object_value php_pqconn_create_object(zend_class_entry *class_type TSRMLS_DC)
115 {
116 return php_pqconn_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
117 }
118
119 static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC)
120 {
121 php_pqconn_object_t *obj = o;
122
123 RETVAL_LONG(PQstatus(obj->intern->conn));
124 }
125
126 static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value TSRMLS_DC)
127 {
128 php_pqconn_object_t *obj = o;
129
130 RETVAL_LONG(PQtransactionStatus(obj->intern->conn));
131 }
132
133 static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC)
134 {
135 php_pqconn_object_t *obj = o;
136 char *error = PHP_PQerrorMessage(obj->intern->conn);
137
138 if (error) {
139 RETVAL_STRING(error, 1);
140 } else {
141 RETVAL_NULL();
142 }
143 }
144
145 static int apply_notify_listener(void *p, void *arg TSRMLS_DC)
146 {
147 php_pq_callback_t *listener = p;
148 PGnotify *nfy = arg;
149 zval *zpid, *zchannel, *zmessage;
150
151 MAKE_STD_ZVAL(zpid);
152 ZVAL_LONG(zpid, nfy->be_pid);
153 MAKE_STD_ZVAL(zchannel);
154 ZVAL_STRING(zchannel, nfy->relname, 1);
155 MAKE_STD_ZVAL(zmessage);
156 ZVAL_STRING(zmessage, nfy->extra, 1);
157
158 zend_fcall_info_argn(&listener->fci TSRMLS_CC, 3, &zchannel, &zmessage, &zpid);
159 zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL TSRMLS_CC);
160
161 zval_ptr_dtor(&zchannel);
162 zval_ptr_dtor(&zmessage);
163 zval_ptr_dtor(&zpid);
164
165 return ZEND_HASH_APPLY_KEEP;
166 }
167
168 static int apply_notify_listeners(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
169 {
170 HashTable *listeners = p;
171 PGnotify *nfy = va_arg(argv, PGnotify *);
172
173 if (0 == fnmatch(key->arKey, nfy->relname, 0)) {
174 zend_hash_apply_with_argument(listeners, apply_notify_listener, nfy TSRMLS_CC);
175 }
176
177 return ZEND_HASH_APPLY_KEEP;
178 }
179
180 void php_pqconn_notify_listeners(php_pqconn_object_t *obj TSRMLS_DC)
181 {
182 PGnotify *nfy;
183
184 while ((nfy = PQnotifies(obj->intern->conn))) {
185 zend_hash_apply_with_arguments(&obj->intern->listeners TSRMLS_CC, apply_notify_listeners, 1, nfy);
186 PQfreemem(nfy);
187 }
188 }
189
190 static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value TSRMLS_DC)
191 {
192 php_pqconn_object_t *obj = o;
193
194 RETVAL_BOOL(PQisBusy(obj->intern->conn));
195 }
196
197 static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value TSRMLS_DC)
198 {
199 php_pqconn_object_t *obj = o;
200
201 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn)), 1);
202 }
203
204 static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value TSRMLS_DC)
205 {
206 php_pqconn_object_t *obj = o;
207 zval *zenc = value;
208
209 if (Z_TYPE_P(value) != IS_STRING) {
210 if (Z_REFCOUNT_P(value) > 1) {
211 zval *tmp;
212 MAKE_STD_ZVAL(tmp);
213 ZVAL_ZVAL(tmp, zenc, 1, 0);
214 convert_to_string(tmp);
215 zenc = tmp;
216 } else {
217 convert_to_string_ex(&zenc);
218 }
219 }
220
221 if (0 > PQsetClientEncoding(obj->intern->conn, Z_STRVAL_P(zenc))) {
222 zend_error(E_NOTICE, "Unrecognized encoding '%s'", Z_STRVAL_P(zenc));
223 }
224
225 if (zenc != value) {
226 zval_ptr_dtor(&zenc);
227 }
228 }
229
230 static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value TSRMLS_DC)
231 {
232 php_pqconn_object_t *obj = o;
233
234 RETVAL_BOOL(obj->intern->unbuffered);
235 }
236
237 static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value TSRMLS_DC)
238 {
239 php_pqconn_object_t *obj = o;
240
241 obj->intern->unbuffered = zend_is_true(value);
242 }
243
244 static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value TSRMLS_DC)
245 {
246 php_pqconn_object_t *obj = o;
247 char *db = PQdb(obj->intern->conn);
248
249 if (db) {
250 RETVAL_STRING(db, 1);
251 } else {
252 RETVAL_EMPTY_STRING();
253 }
254 }
255
256 static void php_pqconn_object_read_user(zval *object, void *o, zval *return_value TSRMLS_DC)
257 {
258 php_pqconn_object_t *obj = o;
259 char *user = PQuser(obj->intern->conn);
260
261 if (user) {
262 RETVAL_STRING(user, 1);
263 } else {
264 RETVAL_EMPTY_STRING();
265 }
266 }
267
268 static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_value TSRMLS_DC)
269 {
270 php_pqconn_object_t *obj = o;
271 char *pass = PQpass(obj->intern->conn);
272
273 if (pass) {
274 RETVAL_STRING(pass, 1);
275 } else {
276 RETVAL_EMPTY_STRING();
277 }
278 }
279
280 static void php_pqconn_object_read_host(zval *object, void *o, zval *return_value TSRMLS_DC)
281 {
282 php_pqconn_object_t *obj = o;
283 char *host = PQhost(obj->intern->conn);
284
285 if (host) {
286 RETVAL_STRING(host, 1);
287 } else {
288 RETVAL_EMPTY_STRING();
289 }
290 }
291
292 static void php_pqconn_object_read_port(zval *object, void *o, zval *return_value TSRMLS_DC)
293 {
294 php_pqconn_object_t *obj = o;
295 char *port = PQport(obj->intern->conn);
296
297 if (port) {
298 RETVAL_STRING(port, 1);
299 } else {
300 RETVAL_EMPTY_STRING();
301 }
302 }
303
304 static void php_pqconn_object_read_options(zval *object, void *o, zval *return_value TSRMLS_DC)
305 {
306 php_pqconn_object_t *obj = o;
307 char *options = PQoptions(obj->intern->conn);
308
309 if (options) {
310 RETVAL_STRING(options, 1);
311 } else {
312 RETVAL_EMPTY_STRING();
313 }
314 }
315
316 static int apply_read_event_handler_ex(void *p, void *arg TSRMLS_DC)
317 {
318 HashTable *rv = arg;
319 zval *zcb = php_pq_callback_to_zval(p);
320
321 zend_hash_next_index_insert(rv, &zcb, sizeof(zval *), NULL);
322
323 return ZEND_HASH_APPLY_KEEP;
324 }
325
326 static int apply_read_event_handlers(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
327 {
328 HashTable *evhs = p, *rv = va_arg(argv, HashTable *);
329 zval *entry, **entry_ptr;
330
331 MAKE_STD_ZVAL(entry);
332 array_init_size(entry, zend_hash_num_elements(evhs));
333
334 if (key->nKeyLength) {
335 zend_hash_add(rv, key->arKey, key->nKeyLength, &entry, sizeof(zval *), (void *) &entry_ptr);
336 } else {
337 zend_hash_index_update(rv, key->h, &entry, sizeof(zval *), (void *) &entry_ptr);
338 }
339
340 zend_hash_apply_with_argument(evhs, apply_read_event_handler_ex, Z_ARRVAL_PP(entry_ptr) TSRMLS_CC);
341
342 return ZEND_HASH_APPLY_KEEP;
343 }
344 static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value TSRMLS_DC)
345 {
346 php_pqconn_object_t *obj = o;
347
348 array_init(return_value);
349 zend_hash_apply_with_arguments(&obj->intern->eventhandlers TSRMLS_CC, apply_read_event_handlers, 1, Z_ARRVAL_P(return_value) TSRMLS_CC);
350 }
351
352 static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC)
353 {
354 zval *zsocket, zmember;
355 php_stream *stream;
356 STATUS retval;
357 int socket;
358
359 if (!obj) {
360 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
361 }
362
363 INIT_PZVAL(&zmember);
364 ZVAL_STRINGL(&zmember, "socket", sizeof("socket")-1, 0);
365 MAKE_STD_ZVAL(zsocket);
366
367 if ((CONNECTION_BAD != PQstatus(obj->intern->conn))
368 && (-1 < (socket = PQsocket(obj->intern->conn)))
369 && (stream = php_stream_fopen_from_fd(socket, "r+b", NULL))) {
370 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
371 php_stream_to_zval(stream, zsocket);
372 retval = SUCCESS;
373 } else {
374 ZVAL_NULL(zsocket);
375 retval = FAILURE;
376 }
377 zend_get_std_object_handlers()->write_property(getThis(), &zmember, zsocket, NULL TSRMLS_CC);
378 zval_ptr_dtor(&zsocket);
379
380 return retval;
381 }
382
383 static void *php_pqconn_resource_factory_ctor(void *data, void *init_arg TSRMLS_DC)
384 {
385 php_pqconn_resource_factory_data_t *o = init_arg;
386 PGconn *conn = NULL;;
387
388 if (o->flags & PHP_PQCONN_ASYNC) {
389 conn = PQconnectStart(o->dsn);
390 } else {
391 conn = PQconnectdb(o->dsn);
392 }
393
394 if (conn) {
395 PQregisterEventProc(conn, php_pqconn_event, "ext-pq", NULL);
396 }
397
398 return conn;
399 }
400
401 static void php_pqconn_resource_factory_dtor(void *opaque, void *handle TSRMLS_DC)
402 {
403 php_pqconn_event_data_t *evdata = PQinstanceData(handle, php_pqconn_event);
404
405 /* we don't care for anything, except free'ing evdata */
406 if (evdata) {
407 PQsetInstanceData(handle, php_pqconn_event, NULL);
408 memset(evdata, 0, sizeof(*evdata));
409 efree(evdata);
410 }
411
412 PQfinish(handle);
413 }
414
415 static php_resource_factory_ops_t php_pqconn_resource_factory_ops = {
416 php_pqconn_resource_factory_ctor,
417 NULL,
418 php_pqconn_resource_factory_dtor
419 };
420
421 php_resource_factory_ops_t *php_pqconn_get_resource_factory_ops(void)
422 {
423 return &php_pqconn_resource_factory_ops;
424 }
425
426 static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC)
427 {
428 // FIXME: ping server
429 }
430
431 static int apply_unlisten(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
432 {
433 php_pqconn_object_t *obj = va_arg(argv, php_pqconn_object_t *);
434 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, key->arKey, key->nKeyLength - 1);
435
436 if (quoted_channel) {
437 PGresult *res;
438 char *cmd;
439
440 spprintf(&cmd, 0, "UNLISTEN %s", quoted_channel);
441 if ((res = PQexec(obj->intern->conn, cmd))) {
442 PHP_PQclear(res);
443 }
444
445 efree(cmd);
446 PQfreemem(quoted_channel);
447 }
448
449 return ZEND_HASH_APPLY_REMOVE;
450 }
451
452 static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC)
453 {
454 php_pqconn_event_data_t *evdata = PQinstanceData(*handle, php_pqconn_event);
455 PGcancel *cancel;
456 PGresult *res;
457
458 /* go away */
459 PQsetInstanceData(*handle, php_pqconn_event, NULL);
460
461 /* ignore notices */
462 PQsetNoticeReceiver(*handle, php_pqconn_notice_ignore, NULL);
463
464 /* cancel async queries */
465 if (PQisBusy(*handle) && (cancel = PQgetCancel(*handle))) {
466 char err[256] = {0};
467
468 PQcancel(cancel, err, sizeof(err));
469 PQfreeCancel(cancel);
470 }
471 /* clean up async results */
472 while ((res = PQgetResult(*handle))) {
473 PHP_PQclear(res);
474 }
475
476 /* clean up transaction & session */
477 switch (PQtransactionStatus(*handle)) {
478 case PQTRANS_IDLE:
479 res = PQexec(*handle, "RESET ALL");
480 break;
481 default:
482 res = PQexec(*handle, "ROLLBACK; RESET ALL");
483 break;
484 }
485
486 if (res) {
487 PHP_PQclear(res);
488 }
489
490 if (evdata) {
491 /* clean up notify listeners */
492 zend_hash_apply_with_arguments(&evdata->obj->intern->listeners TSRMLS_CC, apply_unlisten, 1, evdata->obj);
493
494 /* release instance data */
495 //memset(evdata, 0, sizeof(*evdata));
496 efree(evdata);
497 }
498 }
499
500 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct, 0, 0, 1)
501 ZEND_ARG_INFO(0, dsn)
502 ZEND_ARG_INFO(0, async)
503 ZEND_END_ARG_INFO();
504 static PHP_METHOD(pqconn, __construct) {
505 zend_error_handling zeh;
506 char *dsn_str = "";
507 int dsn_len = 0;
508 long flags = 0;
509 STATUS rv;
510
511 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
512 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &dsn_str, &dsn_len, &flags);
513 zend_restore_error_handling(&zeh TSRMLS_CC);
514
515 if (SUCCESS == rv) {
516 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
517
518 if (obj->intern) {
519 throw_exce(EX_BAD_METHODCALL TSRMLS_CC, "pq\\Connection already initialized");
520 } else {
521 php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj TSRMLS_CC);
522 php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags};
523
524 obj->intern = ecalloc(1, sizeof(*obj->intern));
525
526 zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
527 zend_hash_init(&obj->intern->converters, 0, NULL, ZVAL_PTR_DTOR, 0);
528 zend_hash_init(&obj->intern->eventhandlers, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
529
530 if (flags & PHP_PQCONN_PERSISTENT) {
531 php_persistent_handle_factory_t *phf = php_persistent_handle_concede(NULL, ZEND_STRL("pq\\Connection"), dsn_str, dsn_len, php_pqconn_wakeup, php_pqconn_retire TSRMLS_CC);
532 php_resource_factory_init(&obj->intern->factory, php_persistent_handle_get_resource_factory_ops(), phf, (void (*)(void*)) php_persistent_handle_abandon);
533 } else {
534 php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL);
535 }
536
537 if (flags & PHP_PQCONN_ASYNC) {
538 obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
539 }
540
541 obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata TSRMLS_CC);
542
543 PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata);
544 PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata);
545
546 if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
547 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn));
548 }
549 }
550 }
551 }
552
553 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
554 ZEND_END_ARG_INFO();
555 static PHP_METHOD(pqconn, reset) {
556 zend_error_handling zeh;
557 STATUS rv;
558
559 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
560 rv = zend_parse_parameters_none();
561 zend_restore_error_handling(&zeh TSRMLS_CC);
562
563 if (SUCCESS == rv) {
564 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
565
566 if (!obj->intern) {
567 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
568 } else {
569 PQreset(obj->intern->conn);
570
571 if (CONNECTION_OK != PQstatus(obj->intern->conn)) {
572 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn));
573 }
574
575 php_pqconn_notify_listeners(obj TSRMLS_CC);
576 }
577 }
578 }
579
580 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
581 ZEND_END_ARG_INFO();
582 static PHP_METHOD(pqconn, resetAsync) {
583 zend_error_handling zeh;
584 STATUS rv;
585
586 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
587 rv = zend_parse_parameters_none();
588 zend_restore_error_handling(&zeh TSRMLS_CC);
589
590 if (SUCCESS == rv) {
591 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
592
593 if (!obj->intern) {
594 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
595 } else {
596 if (!PQresetStart(obj->intern->conn)) {
597 throw_exce(EX_IO TSRMLS_CC, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn));
598 } else {
599 obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
600 }
601
602 php_pqconn_notify_listeners(obj TSRMLS_CC);
603 }
604 }
605 }
606
607 static void php_pqconn_add_listener(php_pqconn_object_t *obj, const char *channel_str, size_t channel_len, php_pq_callback_t *listener TSRMLS_DC)
608 {
609 HashTable ht, *existing_listeners;
610
611 php_pq_callback_addref(listener);
612
613 if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
614 zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
615 } else {
616 zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
617 zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
618 zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
619 }
620 }
621
622 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
623 ZEND_ARG_INFO(0, channel)
624 ZEND_ARG_INFO(0, callable)
625 ZEND_END_ARG_INFO();
626 static PHP_METHOD(pqconn, listen) {
627 zend_error_handling zeh;
628 char *channel_str = NULL;
629 int channel_len = 0;
630 php_pq_callback_t listener = {{0}};
631 STATUS rv;
632
633 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
634 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
635 zend_restore_error_handling(&zeh TSRMLS_CC);
636
637 if (SUCCESS == rv) {
638 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
639
640 if (!obj->intern) {
641 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
642 } else {
643 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
644
645 if (!quoted_channel) {
646 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
647 } else {
648 PGresult *res;
649 smart_str cmd = {0};
650
651 smart_str_appends(&cmd, "LISTEN ");
652 smart_str_appends(&cmd, quoted_channel);
653 smart_str_0(&cmd);
654
655 res = PQexec(obj->intern->conn, cmd.c);
656
657 smart_str_free(&cmd);
658 PQfreemem(quoted_channel);
659
660 if (!res) {
661 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
662 } else {
663 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
664 obj->intern->poller = PQconsumeInput;
665 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
666 }
667 PHP_PQclear(res);
668 }
669
670 php_pqconn_notify_listeners(obj TSRMLS_CC);
671 }
672 }
673 }
674 }
675
676 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async, 0, 0, 0)
677 ZEND_ARG_INFO(0, channel)
678 ZEND_ARG_INFO(0, callable)
679 ZEND_END_ARG_INFO();
680 static PHP_METHOD(pqconn, listenAsync) {
681 zend_error_handling zeh;
682 char *channel_str = NULL;
683 int channel_len = 0;
684 php_pq_callback_t listener = {{0}};
685 STATUS rv;
686
687 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
688 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
689 zend_restore_error_handling(&zeh TSRMLS_CC);
690
691 if (SUCCESS == rv) {
692 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
693
694 if (!obj->intern) {
695 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
696 } else {
697 char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len);
698
699 if (!quoted_channel) {
700 throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn));
701 } else {
702 smart_str cmd = {0};
703
704 smart_str_appends(&cmd, "LISTEN ");
705 smart_str_appends(&cmd, quoted_channel);
706 smart_str_0(&cmd);
707
708 if (!PQsendQuery(obj->intern->conn, cmd.c)) {
709 throw_exce(EX_IO TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn));
710 } else {
711 obj->intern->poller = PQconsumeInput;
712 php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC);
713 }
714
715 smart_str_free(&cmd);
716 PQfreemem(quoted_channel);
717 php_pqconn_notify_listeners(obj TSRMLS_CC);
718 }
719 }
720 }
721 }
722
723 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2)
724 ZEND_ARG_INFO(0, channel)
725 ZEND_ARG_INFO(0, message)
726 ZEND_END_ARG_INFO();
727 static PHP_METHOD(pqconn, notify) {
728 zend_error_handling zeh;
729 char *channel_str, *message_str;
730 int channel_len, message_len;
731 STATUS rv;
732
733 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
734 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len);
735 zend_restore_error_handling(&zeh TSRMLS_CC);
736
737 if (SUCCESS == rv) {
738 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
739
740 if (!obj->intern) {
741 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
742 } else {
743 PGresult *res;
744 char *params[2] = {channel_str, message_str};
745
746 res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
747
748 if (!res) {
749 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
750 } else {
751 php_pqres_success(res TSRMLS_CC);
752 PHP_PQclear(res);
753 }
754
755 php_pqconn_notify_listeners(obj TSRMLS_CC);
756 }
757 }
758 }
759
760 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async, 0, 0, 2)
761 ZEND_ARG_INFO(0, channel)
762 ZEND_ARG_INFO(0, message)
763 ZEND_END_ARG_INFO();
764 static PHP_METHOD(pqconn, notifyAsync) {
765 zend_error_handling zeh;
766 char *channel_str, *message_str;
767 int channel_len, message_len;
768 STATUS rv;
769
770 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
771 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len);
772 zend_restore_error_handling(&zeh TSRMLS_CC);
773
774 if (SUCCESS == rv) {
775 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
776
777 if (!obj->intern) {
778 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
779 } else {
780 char *params[2] = {channel_str, message_str};
781
782 if (!PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) {
783 throw_exce(EX_IO TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
784 } else {
785 obj->intern->poller = PQconsumeInput;
786 }
787
788 php_pqconn_notify_listeners(obj TSRMLS_CC);
789 }
790 }
791 }
792
793 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0)
794 ZEND_END_ARG_INFO();
795 static PHP_METHOD(pqconn, poll) {
796 zend_error_handling zeh;
797 STATUS rv;
798
799 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
800 rv = zend_parse_parameters_none();
801 zend_restore_error_handling(&zeh TSRMLS_CC);
802
803 if (SUCCESS == rv) {
804 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
805
806 if (!obj->intern) {
807 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
808 } else if (!obj->intern->poller) {
809 throw_exce(EX_RUNTIME TSRMLS_CC, "No asynchronous operation active");
810 } else {
811 if (obj->intern->poller == PQconsumeInput) {
812 RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK);
813 } else {
814 RETVAL_LONG(obj->intern->poller(obj->intern->conn));
815 }
816 php_pqconn_notify_listeners(obj TSRMLS_CC);
817 }
818 }
819 }
820
821 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1)
822 ZEND_ARG_INFO(0, query)
823 ZEND_END_ARG_INFO();
824 static PHP_METHOD(pqconn, exec) {
825 zend_error_handling zeh;
826 char *query_str;
827 int query_len;
828 STATUS rv;
829
830 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
831 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len);
832 zend_restore_error_handling(&zeh TSRMLS_CC);
833
834 if (SUCCESS == rv) {
835 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
836
837 if (!obj->intern) {
838 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
839 } else {
840 PGresult *res = PQexec(obj->intern->conn, query_str);
841
842 if (!res) {
843 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
844 } else if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
845 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
846 } else {
847 PHP_PQclear(res);
848 }
849
850 php_pqconn_notify_listeners(obj TSRMLS_CC);
851 }
852 }
853 }
854
855 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0)
856 ZEND_END_ARG_INFO();
857 static PHP_METHOD(pqconn, getResult) {
858 zend_error_handling zeh;
859 STATUS rv;
860
861 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
862 rv = zend_parse_parameters_none();
863 zend_restore_error_handling(&zeh TSRMLS_CC);
864
865 if (SUCCESS == rv) {
866 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
867
868 if (!obj->intern) {
869 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
870 } else {
871 PGresult *res = PQgetResult(obj->intern->conn);
872
873 if (!res) {
874 RETVAL_NULL();
875 } else {
876 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
877 }
878
879 php_pqconn_notify_listeners(obj TSRMLS_CC);
880 }
881 }
882 }
883
884 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1)
885 ZEND_ARG_INFO(0, query)
886 ZEND_ARG_INFO(0, callable)
887 ZEND_END_ARG_INFO();
888 static PHP_METHOD(pqconn, execAsync) {
889 zend_error_handling zeh;
890 php_pq_callback_t resolver = {{0}};
891 char *query_str;
892 int query_len;
893 STATUS rv;
894
895 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
896 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc);
897 zend_restore_error_handling(&zeh TSRMLS_CC);
898
899 if (SUCCESS == rv) {
900 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
901
902 if (!obj->intern) {
903 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
904 } else if (!PQsendQuery(obj->intern->conn, query_str)) {
905 throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
906 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
907 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
908 } else {
909 obj->intern->poller = PQconsumeInput;
910 php_pq_callback_dtor(&obj->intern->onevent);
911 if (resolver.fci.size > 0) {
912 obj->intern->onevent = resolver;
913 php_pq_callback_addref(&obj->intern->onevent);
914 }
915 php_pqconn_notify_listeners(obj TSRMLS_CC);
916 }
917 }
918 }
919
920 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params, 0, 0, 2)
921 ZEND_ARG_INFO(0, query)
922 ZEND_ARG_ARRAY_INFO(0, params, 0)
923 ZEND_ARG_ARRAY_INFO(0, types, 1)
924 ZEND_END_ARG_INFO();
925 static PHP_METHOD(pqconn, execParams) {
926 zend_error_handling zeh;
927 char *query_str;
928 int query_len;
929 zval *zparams;
930 zval *ztypes = NULL;
931 STATUS rv;
932
933 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
934 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes);
935 zend_restore_error_handling(&zeh TSRMLS_CC);
936
937 if (SUCCESS == rv) {
938 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
939
940 if (!obj->intern) {
941 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
942 } else {
943 PGresult *res;
944 php_pq_params_t *params;
945
946 params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams) TSRMLS_CC);
947 res = PQexecParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
948 php_pq_params_free(&params);
949
950 if (!res) {
951 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
952 } else {
953 if (SUCCESS == php_pqres_success(res TSRMLS_CC)) {
954 php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC);
955 } else {
956 PHP_PQclear(res);
957 }
958
959 php_pqconn_notify_listeners(obj TSRMLS_CC);
960 }
961 }
962 }
963 }
964
965 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2)
966 ZEND_ARG_INFO(0, query)
967 ZEND_ARG_ARRAY_INFO(0, params, 0)
968 ZEND_ARG_ARRAY_INFO(0, types, 1)
969 ZEND_ARG_INFO(0, callable)
970 ZEND_END_ARG_INFO();
971 static PHP_METHOD(pqconn, execParamsAsync) {
972 zend_error_handling zeh;
973 php_pq_callback_t resolver = {{0}};
974 char *query_str;
975 int query_len;
976 zval *zparams;
977 zval *ztypes = NULL;
978 STATUS rv;
979
980 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
981 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc);
982 zend_restore_error_handling(&zeh TSRMLS_CC);
983
984 if (SUCCESS == rv) {
985 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
986
987 if (!obj->intern) {
988 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
989 } else {
990 int rc;
991 php_pq_params_t *params;
992
993 params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams) TSRMLS_CC);
994 rc = PQsendQueryParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
995 php_pq_params_free(&params);
996
997 if (!rc) {
998 throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn));
999 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1000 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1001 } else {
1002 obj->intern->poller = PQconsumeInput;
1003 php_pq_callback_dtor(&obj->intern->onevent);
1004 if (resolver.fci.size > 0) {
1005 obj->intern->onevent = resolver;
1006 php_pq_callback_addref(&obj->intern->onevent);
1007 }
1008 php_pqconn_notify_listeners(obj TSRMLS_CC);
1009 }
1010 }
1011 }
1012 zend_restore_error_handling(&zeh TSRMLS_CC);
1013 }
1014
1015 STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC)
1016 {
1017 PGresult *res;
1018 STATUS rv;
1019
1020 if (!obj) {
1021 obj = zend_object_store_get_object(object TSRMLS_CC);
1022 }
1023
1024 res = PQprepare(obj->intern->conn, name, query, params->type.count, params->type.oids);
1025
1026 if (!res) {
1027 rv = FAILURE;
1028 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
1029 } else {
1030 rv = php_pqres_success(res TSRMLS_CC);
1031 PHP_PQclear(res);
1032 php_pqconn_notify_listeners(obj TSRMLS_CC);
1033 }
1034
1035 return rv;
1036 }
1037
1038 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
1039 ZEND_ARG_INFO(0, name)
1040 ZEND_ARG_INFO(0, query)
1041 ZEND_ARG_ARRAY_INFO(0, types, 1)
1042 ZEND_END_ARG_INFO();
1043 static PHP_METHOD(pqconn, prepare) {
1044 zend_error_handling zeh;
1045 zval *ztypes = NULL;
1046 char *name_str, *query_str;
1047 int name_len, *query_len;
1048 STATUS rv;
1049
1050 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1051 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
1052 zend_restore_error_handling(&zeh TSRMLS_CC);
1053
1054 if (SUCCESS == rv) {
1055 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1056
1057 if (!obj->intern) {
1058 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1059 } else {
1060 php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC);
1061
1062 if (SUCCESS != php_pqconn_prepare(getThis(), obj, name_str, query_str, params TSRMLS_CC)) {
1063 php_pq_params_free(&params);
1064 } else {
1065 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1066
1067 php_pq_object_addref(obj TSRMLS_CC);
1068 stm->conn = obj;
1069 stm->name = estrdup(name_str);
1070 stm->params = params;
1071 ZEND_INIT_SYMTABLE(&stm->bound);
1072
1073 return_value->type = IS_OBJECT;
1074 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1075 }
1076 }
1077 }
1078 }
1079
1080 STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC)
1081 {
1082 STATUS rv;
1083
1084 if (!obj) {
1085 obj = zend_object_store_get_object(object TSRMLS_CC);
1086 }
1087
1088 if (!PQsendPrepare(obj->intern->conn, name, query, params->type.count, params->type.oids)) {
1089 rv = FAILURE;
1090 throw_exce(EX_IO TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn));
1091 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1092 rv = FAILURE;
1093 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1094 } else {
1095 rv = SUCCESS;
1096 obj->intern->poller = PQconsumeInput;
1097 php_pqconn_notify_listeners(obj TSRMLS_CC);
1098 }
1099
1100 return rv;
1101 }
1102
1103 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
1104 ZEND_ARG_INFO(0, name)
1105 ZEND_ARG_INFO(0, query)
1106 ZEND_ARG_ARRAY_INFO(0, types, 1)
1107 ZEND_END_ARG_INFO();
1108 static PHP_METHOD(pqconn, prepareAsync) {
1109 zend_error_handling zeh;
1110 zval *ztypes = NULL;
1111 char *name_str, *query_str;
1112 int name_len, *query_len;
1113 STATUS rv;
1114
1115 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1116 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes);
1117 zend_restore_error_handling(&zeh TSRMLS_CC);
1118
1119 if (SUCCESS == rv) {
1120 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1121
1122 if (!obj->intern) {
1123 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1124 } else {
1125 php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC);
1126
1127 if (SUCCESS != php_pqconn_prepare_async(getThis(), obj, name_str, query_str, params TSRMLS_CC)) {
1128 php_pq_params_free(&params);
1129 } else {
1130 php_pqstm_t *stm = ecalloc(1, sizeof(*stm));
1131
1132 php_pq_object_addref(obj TSRMLS_CC);
1133 stm->conn = obj;
1134 stm->name = estrdup(name_str);
1135 stm->params = params;
1136 ZEND_INIT_SYMTABLE(&stm->bound);
1137
1138 return_value->type = IS_OBJECT;
1139 return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC);
1140 }
1141 }
1142 }
1143 }
1144
1145 static inline char *declare_str(const char *name_str, size_t name_len, unsigned flags, const char *query_str, size_t query_len)
1146 {
1147 size_t decl_len = name_len + query_len + sizeof("DECLARE BINARY INSENSITIVE NO SCROLL CURSOR WITHOUT HOLD FOR ");
1148 char *decl_str;
1149
1150 decl_str = emalloc(decl_len);
1151 decl_len = slprintf(decl_str, decl_len, "DECLARE %s %s %s %s CURSOR %s FOR %s",
1152 name_str,
1153 (flags & PHP_PQ_DECLARE_BINARY) ? "BINARY" : "",
1154 (flags & PHP_PQ_DECLARE_INSENSITIVE) ? "INSENSITIVE" : "",
1155 (flags & PHP_PQ_DECLARE_NO_SCROLL) ? "NO SCROLL" :
1156 (flags & PHP_PQ_DECLARE_SCROLL) ? "SCROLL" : "",
1157 (flags & PHP_PQ_DECLARE_WITH_HOLD) ? "WITH HOLD" : "",
1158 query_str
1159 );
1160 return decl_str;
1161 }
1162
1163 STATUS php_pqconn_declare(zval *object, php_pqconn_object_t *obj, const char *decl TSRMLS_DC)
1164 {
1165 PGresult *res;
1166 STATUS rv;
1167
1168 if (!obj) {
1169 obj = zend_object_store_get_object(object TSRMLS_CC);
1170 }
1171
1172 res = PQexec(obj->intern->conn, decl);
1173
1174 if (!res) {
1175 rv = FAILURE;
1176 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn));
1177 } else {
1178 rv = php_pqres_success(res TSRMLS_CC);
1179 PHP_PQclear(res);
1180 php_pqconn_notify_listeners(obj TSRMLS_CC);
1181 }
1182
1183 return rv;
1184 }
1185
1186 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare, 0, 0, 3)
1187 ZEND_ARG_INFO(0, name)
1188 ZEND_ARG_INFO(0, flags)
1189 ZEND_ARG_INFO(0, query)
1190 ZEND_END_ARG_INFO();
1191 static PHP_METHOD(pqconn, declare) {
1192 zend_error_handling zeh;
1193 char *name_str, *query_str;
1194 int name_len, query_len;
1195 long flags;
1196 STATUS rv;
1197
1198 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1199 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls", &name_str, &name_len, &flags, &query_str, &query_len);
1200 zend_restore_error_handling(&zeh TSRMLS_CC);
1201
1202 if (SUCCESS == rv) {
1203 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1204
1205 if (!obj->intern) {
1206 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1207 } else {
1208 char *decl = declare_str(name_str, name_len, flags, query_str, query_len);
1209
1210 if (SUCCESS != php_pqconn_declare(getThis(), obj, decl TSRMLS_CC)) {
1211 efree(decl);
1212 } else {
1213 php_pqcur_t *cur = ecalloc(1, sizeof(*cur));
1214
1215 php_pq_object_addref(obj TSRMLS_CC);
1216 cur->conn = obj;
1217 cur->open = 1;
1218 cur->name = estrdup(name_str);
1219 cur->decl = decl;
1220
1221 return_value->type = IS_OBJECT;
1222 return_value->value.obj = php_pqcur_create_object_ex(php_pqcur_class_entry, cur, NULL TSRMLS_CC);
1223 }
1224 }
1225 }
1226 }
1227
1228 STATUS php_pqconn_declare_async(zval *object, php_pqconn_object_t *obj, const char *decl TSRMLS_DC)
1229 {
1230 STATUS rv;
1231
1232 if (!obj) {
1233 obj = zend_object_store_get_object(object TSRMLS_CC);
1234 }
1235
1236 if (!PQsendQuery(obj->intern->conn, decl)) {
1237 rv = FAILURE;
1238 throw_exce(EX_IO TSRMLS_CC, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn));
1239 } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
1240 rv = FAILURE;
1241 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
1242 } else {
1243 rv = SUCCESS;
1244 obj->intern->poller = PQconsumeInput;
1245 php_pqconn_notify_listeners(obj TSRMLS_CC);
1246 }
1247
1248 return rv;
1249 }
1250
1251 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare_async, 0, 0, 2)
1252 ZEND_ARG_INFO(0, name)
1253 ZEND_ARG_INFO(0, flags)
1254 ZEND_ARG_INFO(0, query)
1255 ZEND_END_ARG_INFO();
1256 static PHP_METHOD(pqconn, declareAsync) {
1257 zend_error_handling zeh;
1258 char *name_str, *query_str;
1259 int name_len, query_len;
1260 long flags;
1261 STATUS rv;
1262
1263 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1264 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls", &name_str, &name_len, &flags, &query_str, &query_len);
1265 zend_restore_error_handling(&zeh TSRMLS_CC);
1266
1267 if (SUCCESS == rv) {
1268 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1269
1270 if (!obj->intern) {
1271 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1272 } else {
1273 char *decl = declare_str(name_str, name_len, flags, query_str, query_len);
1274
1275 if (SUCCESS != php_pqconn_declare_async(getThis(), obj, decl TSRMLS_CC)) {
1276 efree(decl);
1277 } else {
1278 php_pqcur_t *cur = ecalloc(1, sizeof(*cur));
1279
1280 php_pq_object_addref(obj TSRMLS_CC);
1281 cur->conn = obj;
1282 cur->open = 1;
1283 cur->name = estrdup(name_str);
1284 cur->decl = decl;
1285
1286 return_value->type = IS_OBJECT;
1287 return_value->value.obj = php_pqcur_create_object_ex(php_pqcur_class_entry, cur, NULL TSRMLS_CC);
1288 }
1289 }
1290 }
1291 }
1292
1293 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
1294 ZEND_ARG_INFO(0, string)
1295 ZEND_END_ARG_INFO();
1296 static PHP_METHOD(pqconn, quote) {
1297 char *str;
1298 int len;
1299
1300 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1301 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1302
1303 if (!obj->intern) {
1304 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1305 } else {
1306 char *quoted = PQescapeLiteral(obj->intern->conn, str, len);
1307
1308 if (!quoted) {
1309 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote string (%s)", PHP_PQerrorMessage(obj->intern->conn));
1310 RETVAL_FALSE;
1311 } else {
1312 RETVAL_STRING(quoted, 1);
1313 PQfreemem(quoted);
1314 }
1315 }
1316 }
1317 }
1318
1319 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name, 0, 0, 1)
1320 ZEND_ARG_INFO(0, type)
1321 ZEND_END_ARG_INFO();
1322 static PHP_METHOD(pqconn, quoteName) {
1323 char *str;
1324 int len;
1325
1326 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1327 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1328
1329 if (!obj->intern) {
1330 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1331 } else {
1332 char *quoted = PQescapeIdentifier(obj->intern->conn, str, len);
1333
1334 if (!quoted) {
1335 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote name (%s)", PHP_PQerrorMessage(obj->intern->conn));
1336 RETVAL_FALSE;
1337 } else {
1338 RETVAL_STRING(quoted, 1);
1339 PQfreemem(quoted);
1340 }
1341 }
1342 }
1343 }
1344
1345 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1)
1346 ZEND_ARG_INFO(0, bytea)
1347 ZEND_END_ARG_INFO();
1348 static PHP_METHOD(pqconn, escapeBytea) {
1349 char *str;
1350 int len;
1351
1352 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1353 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1354
1355 if (!obj->intern) {
1356 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1357 } else {
1358 size_t escaped_len;
1359 char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len);
1360
1361 if (!escaped_str) {
1362 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
1363 RETVAL_FALSE;
1364 } else {
1365 RETVAL_STRINGL(escaped_str, escaped_len - 1, 1);
1366 PQfreemem(escaped_str);
1367 }
1368 }
1369 }
1370 }
1371
1372 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea, 0, 0, 1)
1373 ZEND_ARG_INFO(0, bytea)
1374 ZEND_END_ARG_INFO();
1375 static PHP_METHOD(pqconn, unescapeBytea) {
1376 char *str;
1377 int len;
1378
1379 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) {
1380 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1381
1382 if (!obj->intern) {
1383 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1384 } else {
1385 size_t unescaped_len;
1386 char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len);
1387
1388 if (!unescaped_str) {
1389 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn));
1390 RETVAL_FALSE;
1391 } else {
1392 RETVAL_STRINGL(unescaped_str, unescaped_len, 1);
1393 PQfreemem(unescaped_str);
1394 }
1395 }
1396 }
1397 }
1398
1399 STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
1400 {
1401 STATUS rv = FAILURE;
1402
1403 if (!conn_obj) {
1404 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
1405 }
1406
1407 if (!conn_obj->intern) {
1408 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1409 } else {
1410 PGresult *res;
1411 smart_str cmd = {0};
1412 const char *il = isolation_level(&isolation);
1413
1414 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
1415 smart_str_appends(&cmd, il);
1416 smart_str_appends(&cmd, ", READ ");
1417 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
1418 smart_str_appends(&cmd, ",");
1419 smart_str_appends(&cmd, deferrable ? "" : " NOT");
1420 smart_str_appends(&cmd, " DEFERRABLE");
1421 smart_str_0(&cmd);
1422
1423 res = PQexec(conn_obj->intern->conn, cmd.c);
1424
1425 if (!res) {
1426 throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
1427 } else {
1428 rv = php_pqres_success(res TSRMLS_CC);
1429 PHP_PQclear(res);
1430 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
1431 }
1432
1433 smart_str_free(&cmd);
1434 }
1435
1436 return rv;
1437 }
1438
1439 STATUS php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC)
1440 {
1441 STATUS rv = FAILURE;
1442
1443 if (!conn_obj) {
1444 conn_obj = zend_object_store_get_object(zconn TSRMLS_CC);
1445 }
1446
1447 if (!conn_obj->intern) {
1448 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1449 } else {
1450 smart_str cmd = {0};
1451 const char *il = isolation_level(&isolation);
1452
1453 smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL ");
1454 smart_str_appends(&cmd, il);
1455 smart_str_appends(&cmd, ", READ ");
1456 smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE");
1457 smart_str_appends(&cmd, ",");
1458 smart_str_appends(&cmd, deferrable ? "" : "NOT ");
1459 smart_str_appends(&cmd, " DEFERRABLE");
1460 smart_str_0(&cmd);
1461
1462 if (!PQsendQuery(conn_obj->intern->conn, cmd.c)) {
1463 throw_exce(EX_IO TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn));
1464 } else {
1465 rv = SUCCESS;
1466 conn_obj->intern->poller = PQconsumeInput;
1467 php_pqconn_notify_listeners(conn_obj TSRMLS_CC);
1468 }
1469
1470 smart_str_free(&cmd);
1471 }
1472
1473 return rv;
1474 }
1475
1476 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0)
1477 ZEND_ARG_INFO(0, isolation)
1478 ZEND_ARG_INFO(0, readonly)
1479 ZEND_ARG_INFO(0, deferrable)
1480 ZEND_END_ARG_INFO();
1481 static PHP_METHOD(pqconn, startTransaction) {
1482 zend_error_handling zeh;
1483 long isolation = PHP_PQTXN_READ_COMMITTED;
1484 zend_bool readonly = 0, deferrable = 0;
1485 STATUS rv;
1486
1487 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1488 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable);
1489 zend_restore_error_handling(&zeh TSRMLS_CC);
1490
1491 if (SUCCESS == rv) {
1492 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1493
1494 rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
1495
1496 if (SUCCESS == rv) {
1497 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
1498
1499 php_pq_object_addref(obj TSRMLS_CC);
1500 txn->conn = obj;
1501 txn->open = 1;
1502 txn->isolation = isolation;
1503 txn->readonly = readonly;
1504 txn->deferrable = deferrable;
1505
1506 return_value->type = IS_OBJECT;
1507 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
1508 }
1509 }
1510 }
1511
1512 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0)
1513 ZEND_ARG_INFO(0, isolation)
1514 ZEND_ARG_INFO(0, readonly)
1515 ZEND_ARG_INFO(0, deferrable)
1516 ZEND_END_ARG_INFO();
1517 static PHP_METHOD(pqconn, startTransactionAsync) {
1518 zend_error_handling zeh;
1519 long isolation = PHP_PQTXN_READ_COMMITTED;
1520 zend_bool readonly = 0, deferrable = 0;
1521 STATUS rv;
1522
1523 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1524 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable);
1525 zend_restore_error_handling(&zeh TSRMLS_CC);
1526 if (SUCCESS == rv) {
1527 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1528
1529 rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC);
1530
1531 if (SUCCESS == rv) {
1532 php_pqtxn_t *txn = ecalloc(1, sizeof(*txn));
1533
1534 php_pq_object_addref(obj TSRMLS_CC);
1535 txn->conn = obj;
1536 txn->isolation = isolation;
1537 txn->readonly = readonly;
1538 txn->deferrable = deferrable;
1539
1540 return_value->type = IS_OBJECT;
1541 return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC);
1542 }
1543 }
1544 }
1545
1546 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0)
1547 ZEND_ARG_INFO(0, stdio_stream)
1548 ZEND_END_ARG_INFO();
1549 static PHP_METHOD(pqconn, trace) {
1550 zval *zstream = NULL;
1551
1552 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) {
1553 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1554
1555 if (!obj->intern) {
1556 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1557 } else {
1558 if (!zstream) {
1559 PQuntrace(obj->intern->conn);
1560 RETVAL_TRUE;
1561 } else {
1562 FILE *fp;
1563 php_stream *stream = NULL;
1564
1565 php_stream_from_zval(stream, &zstream);
1566
1567 if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) {
1568 RETVAL_FALSE;
1569 } else {
1570 stream->flags |= PHP_STREAM_FLAG_NO_CLOSE;
1571 PQtrace(obj->intern->conn, fp);
1572 RETVAL_TRUE;
1573 }
1574 }
1575 }
1576 }
1577 }
1578
1579 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_on, 0, 0, 2)
1580 ZEND_ARG_INFO(0, type)
1581 ZEND_ARG_INFO(0, callable)
1582 ZEND_END_ARG_INFO();
1583 static PHP_METHOD(pqconn, on) {
1584 zend_error_handling zeh;
1585 char *type_str;
1586 int type_len;
1587 php_pq_callback_t cb = {{0}};
1588 STATUS rv;
1589
1590 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1591 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &type_str, &type_len, &cb.fci, &cb.fcc);
1592 zend_restore_error_handling(&zeh TSRMLS_CC);
1593
1594 if (SUCCESS == rv) {
1595 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1596
1597 if (!obj->intern) {
1598 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1599 } else {
1600 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1601
1602 RETVAL_LONG(php_pqconn_add_eventhandler(obj, type_str, type_len, &cb TSRMLS_CC));
1603 }
1604 }
1605 }
1606
1607 static int apply_set_converter(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key)
1608 {
1609 zval *tmp, **zoid = p, **zcnv = va_arg(argv, zval **);
1610 HashTable *converters = va_arg(argv, HashTable *);
1611
1612 tmp = *zoid;
1613 convert_to_long_ex(&tmp);
1614 Z_ADDREF_PP(zcnv);
1615 zend_hash_index_update(converters, Z_LVAL_P(tmp), zcnv, sizeof(zval *), NULL);
1616 if (tmp != *zoid) {
1617 zval_ptr_dtor(&tmp);
1618 }
1619
1620 return ZEND_HASH_APPLY_KEEP;
1621 }
1622
1623 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_set_converter, 0, 0, 1)
1624 ZEND_ARG_OBJ_INFO(0, converter, pq\\ConverterInterface, 0)
1625 ZEND_END_ARG_INFO();
1626 static PHP_METHOD(pqconn, setConverter) {
1627 STATUS rv;
1628 zend_error_handling zeh;
1629 zval *zcnv;
1630
1631 zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
1632 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zcnv, php_pqconv_class_entry);
1633 zend_restore_error_handling(&zeh TSRMLS_CC);
1634
1635 if (SUCCESS == rv) {
1636 php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
1637
1638 if (!obj->intern) {
1639 throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
1640 } else {
1641 zval *tmp, *zoids = NULL;
1642
1643 zend_call_method_with_0_params(&zcnv, NULL, NULL, "converttypes", &zoids);
1644 tmp = zoids;
1645 convert_to_array_ex(&zoids);
1646 zend_hash_apply_with_arguments(Z_ARRVAL_P(zoids) TSRMLS_CC, apply_set_converter, 2, &zcnv, &obj->intern->converters);
1647 if (tmp != zoids) {
1648 zval_ptr_dtor(&tmp);
1649 }
1650 zval_ptr_dtor(&zoids);
1651 }
1652 }
1653 }
1654
1655 static zend_function_entry php_pqconn_methods[] = {
1656 PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1657 PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC)
1658 PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC)
1659 PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC)
1660 PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC)
1661 PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC)
1662 PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC)
1663 PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
1664 PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
1665 PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
1666 PHP_ME(pqconn, declare, ai_pqconn_declare, ZEND_ACC_PUBLIC)
1667 PHP_ME(pqconn, declareAsync, ai_pqconn_declare_async, ZEND_ACC_PUBLIC)
1668 PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
1669 PHP_ME(pqconn, listenAsync, ai_pqconn_listen_async, ZEND_ACC_PUBLIC)
1670 PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
1671 PHP_ME(pqconn, notifyAsync, ai_pqconn_notify_async, ZEND_ACC_PUBLIC)
1672 PHP_ME(pqconn, getResult, ai_pqconn_get_result, ZEND_ACC_PUBLIC)
1673 PHP_ME(pqconn, quote, ai_pqconn_quote, ZEND_ACC_PUBLIC)
1674 PHP_ME(pqconn, quoteName, ai_pqconn_quote_name, ZEND_ACC_PUBLIC)
1675 PHP_ME(pqconn, escapeBytea, ai_pqconn_escape_bytea, ZEND_ACC_PUBLIC)
1676 PHP_ME(pqconn, unescapeBytea, ai_pqconn_unescape_bytea, ZEND_ACC_PUBLIC)
1677 PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC)
1678 PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC)
1679 PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC)
1680 PHP_ME(pqconn, on, ai_pqconn_on, ZEND_ACC_PUBLIC)
1681 PHP_ME(pqconn, setConverter, ai_pqconn_set_converter, ZEND_ACC_PUBLIC)
1682 {0}
1683 };
1684
1685 PHP_MSHUTDOWN_FUNCTION(pqconn)
1686 {
1687 zend_hash_destroy(&php_pqconn_object_prophandlers);
1688 return SUCCESS;
1689 }
1690
1691 PHP_MINIT_FUNCTION(pqconn)
1692 {
1693 zend_class_entry ce = {0};
1694 php_pq_object_prophandler_t ph = {0};
1695
1696 INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods);
1697 php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
1698 php_pqconn_class_entry->create_object = php_pqconn_create_object;
1699
1700 memcpy(&php_pqconn_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1701 php_pqconn_object_handlers.read_property = php_pq_object_read_prop;
1702 php_pqconn_object_handlers.write_property = php_pq_object_write_prop;
1703 php_pqconn_object_handlers.clone_obj = NULL;
1704 php_pqconn_object_handlers.get_property_ptr_ptr = NULL;
1705 php_pqconn_object_handlers.get_gc = NULL;
1706 php_pqconn_object_handlers.get_properties = php_pq_object_properties;
1707 php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info;
1708
1709 zend_hash_init(&php_pqconn_object_prophandlers, 14, NULL, NULL, 1);
1710
1711 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC);
1712 ph.read = php_pqconn_object_read_status;
1713 zend_hash_add(&php_pqconn_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL);
1714
1715 zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN, ZEND_ACC_PUBLIC TSRMLS_CC);
1716 ph.read = php_pqconn_object_read_transaction_status;
1717 zend_hash_add(&php_pqconn_object_prophandlers, "transactionStatus", sizeof("transactionStatus"), (void *) &ph, sizeof(ph), NULL);
1718
1719 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC);
1720 ph.read = NULL; /* forward to std prophandler */
1721 zend_hash_add(&php_pqconn_object_prophandlers, "socket", sizeof("socket"), (void *) &ph, sizeof(ph), NULL);
1722
1723 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC);
1724 ph.read = php_pqconn_object_read_error_message;
1725 zend_hash_add(&php_pqconn_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL);
1726
1727 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1728 ph.read = php_pqconn_object_read_busy;
1729 zend_hash_add(&php_pqconn_object_prophandlers, "busy", sizeof("busy"), (void *) &ph, sizeof(ph), NULL);
1730
1731 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC TSRMLS_CC);
1732 ph.read = php_pqconn_object_read_encoding;
1733 ph.write = php_pqconn_object_write_encoding;
1734 zend_hash_add(&php_pqconn_object_prophandlers, "encoding", sizeof("encoding"), (void *) &ph, sizeof(ph), NULL);
1735 ph.write = NULL;
1736
1737 zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1738 ph.read = php_pqconn_object_read_unbuffered;
1739 ph.write = php_pqconn_object_write_unbuffered;
1740 zend_hash_add(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered"), (void *) &ph, sizeof(ph), NULL);
1741 ph.write = NULL;
1742
1743 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC TSRMLS_CC);
1744 ph.read = php_pqconn_object_read_db;
1745 zend_hash_add(&php_pqconn_object_prophandlers, "db", sizeof("db"), (void *) &ph, sizeof(ph), NULL);
1746
1747 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC);
1748 ph.read = php_pqconn_object_read_user;
1749 zend_hash_add(&php_pqconn_object_prophandlers, "user", sizeof("user"), (void *) &ph, sizeof(ph), NULL);
1750
1751 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC);
1752 ph.read = php_pqconn_object_read_pass;
1753 zend_hash_add(&php_pqconn_object_prophandlers, "pass", sizeof("pass"), (void *) &ph, sizeof(ph), NULL);
1754
1755 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
1756 ph.read = php_pqconn_object_read_host;
1757 zend_hash_add(&php_pqconn_object_prophandlers, "host", sizeof("host"), (void *) &ph, sizeof(ph), NULL);
1758
1759 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC);
1760 ph.read = php_pqconn_object_read_port;
1761 zend_hash_add(&php_pqconn_object_prophandlers, "port", sizeof("port"), (void *) &ph, sizeof(ph), NULL);
1762
1763 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("options"), ZEND_ACC_PUBLIC TSRMLS_CC);
1764 ph.read = php_pqconn_object_read_options;
1765 zend_hash_add(&php_pqconn_object_prophandlers, "options", sizeof("options"), (void *) &ph, sizeof(ph), NULL);
1766
1767 zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC TSRMLS_CC);
1768 ph.read = php_pqconn_object_read_event_handlers;
1769 zend_hash_add(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers"), (void *) &ph, sizeof(ph), NULL);
1770
1771 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC);
1772 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC);
1773 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC);
1774 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC);
1775 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC);
1776 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC);
1777 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC);
1778 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC);
1779
1780 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC);
1781 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC);
1782 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC);
1783 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC);
1784 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC);
1785
1786 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC);
1787 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC);
1788 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC);
1789 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC);
1790
1791 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_NOTICE"), ZEND_STRL("notice") TSRMLS_CC);
1792 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESULT"), ZEND_STRL("result") TSRMLS_CC);
1793 zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESET"), ZEND_STRL("reset") TSRMLS_CC);
1794
1795 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("ASYNC"), 0x1 TSRMLS_CC);
1796 zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("PERSISTENT"), 0x2 TSRMLS_CC);
1797
1798 return SUCCESS;
1799 }
1800
1801 /*
1802 * Local variables:
1803 * tab-width: 4
1804 * c-basic-offset: 4
1805 * End:
1806 * vim600: noet sw=4 ts=4 fdm=marker
1807 * vim<600: noet sw=4 ts=4
1808 */