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