2 +--------------------------------------------------------------------+
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 +--------------------------------------------------------------------+
19 #define SMART_STR_PREALLOC 256
20 #include <ext/standard/php_smart_str.h>
22 #include <libpq-events.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"
35 zend_class_entry
*php_pqconn_class_entry
;
36 static zend_object_handlers php_pqconn_object_handlers
;
37 static HashTable php_pqconn_object_prophandlers
;
40 static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC)
44 if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) {
45 zend_hash_index_del(Z_ARRVAL_PP(evhs), id);
50 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
)
55 if (SUCCESS
!= zend_hash_find(&obj
->intern
->eventhandlers
, type_str
, type_len
+ 1, (void *) &evhs
)) {
58 zend_hash_init(&evh
, 1, NULL
, (dtor_func_t
) php_pq_callback_dtor
, 0);
59 zend_hash_add(&obj
->intern
->eventhandlers
, type_str
, type_len
+ 1, (void *) &evh
, sizeof(evh
), (void *) &evhs
);
62 php_pq_callback_addref(cb
);
63 h
= zend_hash_next_free_element(evhs
);
64 zend_hash_index_update(evhs
, h
, (void *) cb
, sizeof(*cb
), NULL
);
69 static void php_pqconn_object_free(void *o TSRMLS_DC
)
71 php_pqconn_object_t
*obj
= o
;
73 fprintf(stderr
, "FREE conn(#%d) %p\n", obj
->zv
.handle
, obj
);
76 php_resource_factory_handle_dtor(&obj
->intern
->factory
, obj
->intern
->conn TSRMLS_CC
);
77 php_resource_factory_dtor(&obj
->intern
->factory
);
78 php_pq_callback_dtor(&obj
->intern
->onevent
);
79 zend_hash_destroy(&obj
->intern
->listeners
);
80 zend_hash_destroy(&obj
->intern
->eventhandlers
);
84 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
89 zend_object_value
php_pqconn_create_object_ex(zend_class_entry
*ce
, php_pqconn_t
*intern
, php_pqconn_object_t
**ptr TSRMLS_DC
)
91 php_pqconn_object_t
*o
;
93 o
= ecalloc(1, sizeof(*o
));
94 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
95 object_properties_init((zend_object
*) o
, ce
);
96 o
->prophandler
= &php_pqconn_object_prophandlers
;
106 o
->zv
.handle
= zend_objects_store_put((zend_object
*) o
, NULL
, php_pqconn_object_free
, NULL TSRMLS_CC
);
107 o
->zv
.handlers
= &php_pqconn_object_handlers
;
112 static zend_object_value
php_pqconn_create_object(zend_class_entry
*class_type TSRMLS_DC
)
114 return php_pqconn_create_object_ex(class_type
, NULL
, NULL TSRMLS_CC
);
117 static void php_pqconn_object_read_status(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
119 php_pqconn_object_t
*obj
= o
;
121 RETVAL_LONG(PQstatus(obj
->intern
->conn
));
124 static void php_pqconn_object_read_transaction_status(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
126 php_pqconn_object_t
*obj
= o
;
128 RETVAL_LONG(PQtransactionStatus(obj
->intern
->conn
));
131 static void php_pqconn_object_read_error_message(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
133 php_pqconn_object_t
*obj
= o
;
134 char *error
= PHP_PQerrorMessage(obj
->intern
->conn
);
137 RETVAL_STRING(error
, 1);
143 static int apply_notify_listener(void *p
, void *arg TSRMLS_DC
)
145 php_pq_callback_t
*listener
= p
;
147 zval
*zpid
, *zchannel
, *zmessage
;
150 ZVAL_LONG(zpid
, nfy
->be_pid
);
151 MAKE_STD_ZVAL(zchannel
);
152 ZVAL_STRING(zchannel
, nfy
->relname
, 1);
153 MAKE_STD_ZVAL(zmessage
);
154 ZVAL_STRING(zmessage
, nfy
->extra
, 1);
156 zend_fcall_info_argn(&listener
->fci TSRMLS_CC
, 3, &zchannel
, &zmessage
, &zpid
);
157 zend_fcall_info_call(&listener
->fci
, &listener
->fcc
, NULL
, NULL TSRMLS_CC
);
159 zval_ptr_dtor(&zchannel
);
160 zval_ptr_dtor(&zmessage
);
161 zval_ptr_dtor(&zpid
);
163 return ZEND_HASH_APPLY_KEEP
;
166 static int apply_notify_listeners(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
168 HashTable
*listeners
= p
;
169 PGnotify
*nfy
= va_arg(argv
, PGnotify
*);
171 if (0 == fnmatch(key
->arKey
, nfy
->relname
, 0)) {
172 zend_hash_apply_with_argument(listeners
, apply_notify_listener
, nfy TSRMLS_CC
);
175 return ZEND_HASH_APPLY_KEEP
;
178 void php_pqconn_notify_listeners(php_pqconn_object_t
*obj TSRMLS_DC
)
182 while ((nfy
= PQnotifies(obj
->intern
->conn
))) {
183 zend_hash_apply_with_arguments(&obj
->intern
->listeners TSRMLS_CC
, apply_notify_listeners
, 1, nfy
);
188 static void php_pqconn_object_read_busy(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
190 php_pqconn_object_t
*obj
= o
;
192 RETVAL_BOOL(PQisBusy(obj
->intern
->conn
));
195 static void php_pqconn_object_read_encoding(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
197 php_pqconn_object_t
*obj
= o
;
199 RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj
->intern
->conn
)), 1);
202 static void php_pqconn_object_write_encoding(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
204 php_pqconn_object_t
*obj
= o
;
207 if (Z_TYPE_P(value
) != IS_STRING
) {
208 if (Z_REFCOUNT_P(value
) > 1) {
211 ZVAL_ZVAL(tmp
, zenc
, 1, 0);
212 convert_to_string(tmp
);
215 convert_to_string_ex(&zenc
);
219 if (0 > PQsetClientEncoding(obj
->intern
->conn
, Z_STRVAL_P(zenc
))) {
220 zend_error(E_NOTICE
, "Unrecognized encoding '%s'", Z_STRVAL_P(zenc
));
224 zval_ptr_dtor(&zenc
);
228 static void php_pqconn_object_read_unbuffered(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
230 php_pqconn_object_t
*obj
= o
;
232 RETVAL_BOOL(obj
->intern
->unbuffered
);
235 static void php_pqconn_object_write_unbuffered(zval
*object
, void *o
, zval
*value TSRMLS_DC
)
237 php_pqconn_object_t
*obj
= o
;
239 obj
->intern
->unbuffered
= zend_is_true(value
);
242 static void php_pqconn_object_read_db(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
244 php_pqconn_object_t
*obj
= o
;
245 char *db
= PQdb(obj
->intern
->conn
);
248 RETVAL_STRING(db
, 1);
250 RETVAL_EMPTY_STRING();
254 static void php_pqconn_object_read_user(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
256 php_pqconn_object_t
*obj
= o
;
257 char *user
= PQuser(obj
->intern
->conn
);
260 RETVAL_STRING(user
, 1);
262 RETVAL_EMPTY_STRING();
266 static void php_pqconn_object_read_pass(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
268 php_pqconn_object_t
*obj
= o
;
269 char *pass
= PQpass(obj
->intern
->conn
);
272 RETVAL_STRING(pass
, 1);
274 RETVAL_EMPTY_STRING();
278 static void php_pqconn_object_read_host(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
280 php_pqconn_object_t
*obj
= o
;
281 char *host
= PQhost(obj
->intern
->conn
);
284 RETVAL_STRING(host
, 1);
286 RETVAL_EMPTY_STRING();
290 static void php_pqconn_object_read_port(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
292 php_pqconn_object_t
*obj
= o
;
293 char *port
= PQport(obj
->intern
->conn
);
296 RETVAL_STRING(port
, 1);
298 RETVAL_EMPTY_STRING();
302 static void php_pqconn_object_read_options(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
304 php_pqconn_object_t
*obj
= o
;
305 char *options
= PQoptions(obj
->intern
->conn
);
308 RETVAL_STRING(options
, 1);
310 RETVAL_EMPTY_STRING();
314 static void php_pqconn_object_read_event_handlers(zval
*object
, void *o
, zval
*return_value TSRMLS_DC
)
316 php_pqconn_object_t
*obj
= o
;
318 array_init(return_value
);
319 zend_hash_copy(Z_ARRVAL_P(return_value
), &obj
->intern
->eventhandlers
, (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
322 static STATUS
php_pqconn_update_socket(zval
*this_ptr
, php_pqconn_object_t
*obj TSRMLS_DC
)
324 zval
*zsocket
, zmember
;
330 obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
333 INIT_PZVAL(&zmember
);
334 ZVAL_STRINGL(&zmember
, "socket", sizeof("socket")-1, 0);
335 MAKE_STD_ZVAL(zsocket
);
337 if ((CONNECTION_BAD
!= PQstatus(obj
->intern
->conn
))
338 && (-1 < (socket
= PQsocket(obj
->intern
->conn
)))
339 && (stream
= php_stream_fopen_from_fd(socket
, "r+b", NULL
))) {
340 stream
->flags
|= PHP_STREAM_FLAG_NO_CLOSE
;
341 php_stream_to_zval(stream
, zsocket
);
347 zend_get_std_object_handlers()->write_property(getThis(), &zmember
, zsocket
, NULL TSRMLS_CC
);
348 zval_ptr_dtor(&zsocket
);
353 static void *php_pqconn_resource_factory_ctor(void *data
, void *init_arg TSRMLS_DC
)
355 php_pqconn_resource_factory_data_t
*o
= init_arg
;
356 PGconn
*conn
= NULL
;;
358 if (o
->flags
& PHP_PQCONN_ASYNC
) {
359 conn
= PQconnectStart(o
->dsn
);
361 conn
= PQconnectdb(o
->dsn
);
365 PQregisterEventProc(conn
, php_pqconn_event
, "ext-pq", NULL
);
371 static void php_pqconn_resource_factory_dtor(void *opaque
, void *handle TSRMLS_DC
)
373 php_pqconn_event_data_t
*evdata
= PQinstanceData(handle
, php_pqconn_event
);
375 /* we don't care for anything, except free'ing evdata */
377 PQsetInstanceData(handle
, php_pqconn_event
, NULL
);
378 memset(evdata
, 0, sizeof(*evdata
));
385 static php_resource_factory_ops_t php_pqconn_resource_factory_ops
= {
386 php_pqconn_resource_factory_ctor
,
388 php_pqconn_resource_factory_dtor
391 php_resource_factory_ops_t
*php_pqconn_get_resource_factory_ops(void)
393 return &php_pqconn_resource_factory_ops
;
396 static void php_pqconn_wakeup(php_persistent_handle_factory_t
*f
, void **handle TSRMLS_DC
)
398 // FIXME: ping server
401 static int apply_unlisten(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
403 php_pqconn_object_t
*obj
= va_arg(argv
, php_pqconn_object_t
*);
404 char *quoted_channel
= PQescapeIdentifier(obj
->intern
->conn
, key
->arKey
, key
->nKeyLength
- 1);
406 if (quoted_channel
) {
410 spprintf(&cmd
, 0, "UNLISTEN %s", quoted_channel
);
411 if ((res
= PQexec(obj
->intern
->conn
, cmd
))) {
416 PQfreemem(quoted_channel
);
419 return ZEND_HASH_APPLY_REMOVE
;
422 static void php_pqconn_retire(php_persistent_handle_factory_t
*f
, void **handle TSRMLS_DC
)
424 php_pqconn_event_data_t
*evdata
= PQinstanceData(*handle
, php_pqconn_event
);
429 PQsetInstanceData(*handle
, php_pqconn_event
, NULL
);
432 PQsetNoticeReceiver(*handle
, php_pqconn_notice_ignore
, NULL
);
434 /* cancel async queries */
435 if (PQisBusy(*handle
) && (cancel
= PQgetCancel(*handle
))) {
438 PQcancel(cancel
, err
, sizeof(err
));
439 PQfreeCancel(cancel
);
441 /* clean up async results */
442 while ((res
= PQgetResult(*handle
))) {
446 /* clean up transaction & session */
447 switch (PQtransactionStatus(*handle
)) {
449 res
= PQexec(*handle
, "RESET ALL");
452 res
= PQexec(*handle
, "ROLLBACK; RESET ALL");
461 /* clean up notify listeners */
462 zend_hash_apply_with_arguments(&evdata
->obj
->intern
->listeners TSRMLS_CC
, apply_unlisten
, 1, evdata
->obj
);
464 /* release instance data */
465 memset(evdata
, 0, sizeof(*evdata
));
470 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_construct
, 0, 0, 1)
471 ZEND_ARG_INFO(0, dsn
)
472 ZEND_ARG_INFO(0, async
)
474 static PHP_METHOD(pqconn
, __construct
) {
475 zend_error_handling zeh
;
481 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
482 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|sl", &dsn_str
, &dsn_len
, &flags
);
483 zend_restore_error_handling(&zeh TSRMLS_CC
);
486 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
489 throw_exce(EX_BAD_METHODCALL TSRMLS_CC
, "pq\\Connection already initialized");
491 php_pqconn_event_data_t
*evdata
= php_pqconn_event_data_init(obj TSRMLS_CC
);
492 php_pqconn_resource_factory_data_t rfdata
= {dsn_str
, flags
};
494 obj
->intern
= ecalloc(1, sizeof(*obj
->intern
));
496 zend_hash_init(&obj
->intern
->listeners
, 0, NULL
, (dtor_func_t
) zend_hash_destroy
, 0);
497 zend_hash_init(&obj
->intern
->eventhandlers
, 0, NULL
, (dtor_func_t
) zend_hash_destroy
, 0);
499 if (flags
& PHP_PQCONN_PERSISTENT
) {
500 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
);
501 php_resource_factory_init(&obj
->intern
->factory
, php_persistent_handle_get_resource_factory_ops(), phf
, (void (*)(void*)) php_persistent_handle_abandon
);
503 php_resource_factory_init(&obj
->intern
->factory
, &php_pqconn_resource_factory_ops
, NULL
, NULL
);
506 if (flags
& PHP_PQCONN_ASYNC
) {
507 obj
->intern
->poller
= (int (*)(PGconn
*)) PQconnectPoll
;
510 obj
->intern
->conn
= php_resource_factory_handle_ctor(&obj
->intern
->factory
, &rfdata TSRMLS_CC
);
512 PQsetInstanceData(obj
->intern
->conn
, php_pqconn_event
, evdata
);
513 PQsetNoticeReceiver(obj
->intern
->conn
, php_pqconn_notice_recv
, evdata
);
515 if (SUCCESS
!= php_pqconn_update_socket(getThis(), obj TSRMLS_CC
)) {
516 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC
, "Connection failed (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
522 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset
, 0, 0, 0)
524 static PHP_METHOD(pqconn
, reset
) {
525 zend_error_handling zeh
;
528 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
529 rv
= zend_parse_parameters_none();
530 zend_restore_error_handling(&zeh TSRMLS_CC
);
533 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
536 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
538 PQreset(obj
->intern
->conn
);
540 if (CONNECTION_OK
!= PQstatus(obj
->intern
->conn
)) {
541 throw_exce(EX_CONNECTION_FAILED TSRMLS_CC
, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
544 php_pqconn_notify_listeners(obj TSRMLS_CC
);
549 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async
, 0, 0, 0)
551 static PHP_METHOD(pqconn
, resetAsync
) {
552 zend_error_handling zeh
;
555 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
556 rv
= zend_parse_parameters_none();
557 zend_restore_error_handling(&zeh TSRMLS_CC
);
560 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
563 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
565 if (!PQresetStart(obj
->intern
->conn
)) {
566 throw_exce(EX_IO TSRMLS_CC
, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
568 obj
->intern
->poller
= (int (*)(PGconn
*)) PQresetPoll
;
571 php_pqconn_notify_listeners(obj TSRMLS_CC
);
576 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
)
578 HashTable ht
, *existing_listeners
;
580 php_pq_callback_addref(listener
);
582 if (SUCCESS
== zend_hash_find(&obj
->intern
->listeners
, channel_str
, channel_len
+ 1, (void *) &existing_listeners
)) {
583 zend_hash_next_index_insert(existing_listeners
, (void *) listener
, sizeof(*listener
), NULL
);
585 zend_hash_init(&ht
, 1, NULL
, (dtor_func_t
) php_pq_callback_dtor
, 0);
586 zend_hash_next_index_insert(&ht
, (void *) listener
, sizeof(*listener
), NULL
);
587 zend_hash_add(&obj
->intern
->listeners
, channel_str
, channel_len
+ 1, (void *) &ht
, sizeof(HashTable
), NULL
);
591 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen
, 0, 0, 0)
592 ZEND_ARG_INFO(0, channel
)
593 ZEND_ARG_INFO(0, callable
)
595 static PHP_METHOD(pqconn
, listen
) {
596 zend_error_handling zeh
;
597 char *channel_str
= NULL
;
599 php_pq_callback_t listener
;
602 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
603 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sf", &channel_str
, &channel_len
, &listener
.fci
, &listener
.fcc
);
604 zend_restore_error_handling(&zeh TSRMLS_CC
);
607 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
610 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
612 char *quoted_channel
= PQescapeIdentifier(obj
->intern
->conn
, channel_str
, channel_len
);
614 if (!quoted_channel
) {
615 throw_exce(EX_ESCAPE TSRMLS_CC
, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
620 smart_str_appends(&cmd
, "LISTEN ");
621 smart_str_appends(&cmd
, quoted_channel
);
624 res
= PQexec(obj
->intern
->conn
, cmd
.c
);
626 smart_str_free(&cmd
);
627 PQfreemem(quoted_channel
);
630 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to install listener (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
632 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
633 obj
->intern
->poller
= PQconsumeInput
;
634 php_pqconn_add_listener(obj
, channel_str
, channel_len
, &listener TSRMLS_CC
);
639 php_pqconn_notify_listeners(obj TSRMLS_CC
);
645 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async
, 0, 0, 0)
646 ZEND_ARG_INFO(0, channel
)
647 ZEND_ARG_INFO(0, callable
)
649 static PHP_METHOD(pqconn
, listenAsync
) {
650 zend_error_handling zeh
;
651 char *channel_str
= NULL
;
653 php_pq_callback_t listener
;
656 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
657 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sf", &channel_str
, &channel_len
, &listener
.fci
, &listener
.fcc
);
658 zend_restore_error_handling(&zeh TSRMLS_CC
);
661 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
664 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
666 char *quoted_channel
= PQescapeIdentifier(obj
->intern
->conn
, channel_str
, channel_len
);
668 if (!quoted_channel
) {
669 throw_exce(EX_ESCAPE TSRMLS_CC
, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
673 smart_str_appends(&cmd
, "LISTEN ");
674 smart_str_appends(&cmd
, quoted_channel
);
677 if (!PQsendQuery(obj
->intern
->conn
, cmd
.c
)) {
678 throw_exce(EX_IO TSRMLS_CC
, "Failed to install listener (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
680 obj
->intern
->poller
= PQconsumeInput
;
681 php_pqconn_add_listener(obj
, channel_str
, channel_len
, &listener TSRMLS_CC
);
684 smart_str_free(&cmd
);
685 PQfreemem(quoted_channel
);
686 php_pqconn_notify_listeners(obj TSRMLS_CC
);
692 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify
, 0, 0, 2)
693 ZEND_ARG_INFO(0, channel
)
694 ZEND_ARG_INFO(0, message
)
696 static PHP_METHOD(pqconn
, notify
) {
697 zend_error_handling zeh
;
698 char *channel_str
, *message_str
;
699 int channel_len
, message_len
;
702 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
703 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss", &channel_str
, &channel_len
, &message_str
, &message_len
);
704 zend_restore_error_handling(&zeh TSRMLS_CC
);
707 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
710 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
713 char *params
[2] = {channel_str
, message_str
};
715 res
= PQexecParams(obj
->intern
->conn
, "select pg_notify($1, $2)", 2, NULL
, (const char *const*) params
, NULL
, NULL
, 0);
718 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
720 php_pqres_success(res TSRMLS_CC
);
724 php_pqconn_notify_listeners(obj TSRMLS_CC
);
729 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async
, 0, 0, 2)
730 ZEND_ARG_INFO(0, channel
)
731 ZEND_ARG_INFO(0, message
)
733 static PHP_METHOD(pqconn
, notifyAsync
) {
734 zend_error_handling zeh
;
735 char *channel_str
, *message_str
;
736 int channel_len
, message_len
;
739 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
740 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss", &channel_str
, &channel_len
, &message_str
, &message_len
);
741 zend_restore_error_handling(&zeh TSRMLS_CC
);
744 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
747 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
749 char *params
[2] = {channel_str
, message_str
};
751 if (!PQsendQueryParams(obj
->intern
->conn
, "select pg_notify($1, $2)", 2, NULL
, (const char *const*) params
, NULL
, NULL
, 0)) {
752 throw_exce(EX_IO TSRMLS_CC
, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
754 obj
->intern
->poller
= PQconsumeInput
;
757 php_pqconn_notify_listeners(obj TSRMLS_CC
);
762 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll
, 0, 0, 0)
764 static PHP_METHOD(pqconn
, poll
) {
765 zend_error_handling zeh
;
768 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
769 rv
= zend_parse_parameters_none();
770 zend_restore_error_handling(&zeh TSRMLS_CC
);
773 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
776 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
777 } else if (!obj
->intern
->poller
) {
778 throw_exce(EX_RUNTIME TSRMLS_CC
, "No asynchronous operation active");
780 if (obj
->intern
->poller
== PQconsumeInput
) {
781 RETVAL_LONG(obj
->intern
->poller(obj
->intern
->conn
) * PGRES_POLLING_OK
);
783 RETVAL_LONG(obj
->intern
->poller(obj
->intern
->conn
));
785 php_pqconn_notify_listeners(obj TSRMLS_CC
);
790 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec
, 0, 0, 1)
791 ZEND_ARG_INFO(0, query
)
793 static PHP_METHOD(pqconn
, exec
) {
794 zend_error_handling zeh
;
799 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
800 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &query_str
, &query_len
);
801 zend_restore_error_handling(&zeh TSRMLS_CC
);
804 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
807 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
809 PGresult
*res
= PQexec(obj
->intern
->conn
, query_str
);
812 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to execute query (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
813 } else if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
814 php_pq_object_to_zval_no_addref(PQresultInstanceData(res
, php_pqconn_event
), &return_value TSRMLS_CC
);
819 php_pqconn_notify_listeners(obj TSRMLS_CC
);
824 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result
, 0, 0, 0)
826 static PHP_METHOD(pqconn
, getResult
) {
827 zend_error_handling zeh
;
830 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
831 rv
= zend_parse_parameters_none();
832 zend_restore_error_handling(&zeh TSRMLS_CC
);
835 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
838 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
840 PGresult
*res
= PQgetResult(obj
->intern
->conn
);
845 php_pq_object_to_zval_no_addref(PQresultInstanceData(res
, php_pqconn_event
), &return_value TSRMLS_CC
);
848 php_pqconn_notify_listeners(obj TSRMLS_CC
);
853 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async
, 0, 0, 1)
854 ZEND_ARG_INFO(0, query
)
855 ZEND_ARG_INFO(0, callable
)
857 static PHP_METHOD(pqconn
, execAsync
) {
858 zend_error_handling zeh
;
859 php_pq_callback_t resolver
= {{0}};
864 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
865 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s|f", &query_str
, &query_len
, &resolver
.fci
, &resolver
.fcc
);
866 zend_restore_error_handling(&zeh TSRMLS_CC
);
869 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
872 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
873 } else if (!PQsendQuery(obj
->intern
->conn
, query_str
)) {
874 throw_exce(EX_IO TSRMLS_CC
, "Failed to execute query (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
875 } else if (obj
->intern
->unbuffered
&& !PQsetSingleRowMode(obj
->intern
->conn
)) {
876 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
878 obj
->intern
->poller
= PQconsumeInput
;
879 php_pq_callback_dtor(&obj
->intern
->onevent
);
880 if (resolver
.fci
.size
> 0) {
881 obj
->intern
->onevent
= resolver
;
882 php_pq_callback_addref(&obj
->intern
->onevent
);
884 php_pqconn_notify_listeners(obj TSRMLS_CC
);
889 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params
, 0, 0, 2)
890 ZEND_ARG_INFO(0, query
)
891 ZEND_ARG_ARRAY_INFO(0, params
, 0)
892 ZEND_ARG_ARRAY_INFO(0, types
, 1)
894 static PHP_METHOD(pqconn
, execParams
) {
895 zend_error_handling zeh
;
902 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
903 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sa/|a/!", &query_str
, &query_len
, &zparams
, &ztypes
);
904 zend_restore_error_handling(&zeh TSRMLS_CC
);
907 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
910 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
915 char **params
= NULL
;
918 ZEND_INIT_SYMTABLE(&zdtor
);
919 count
= php_pq_params_to_array(Z_ARRVAL_P(zparams
), ¶ms
, &zdtor TSRMLS_CC
);
922 php_pq_types_to_array(Z_ARRVAL_P(ztypes
), &types TSRMLS_CC
);
925 res
= PQexecParams(obj
->intern
->conn
, query_str
, count
, types
, (const char *const*) params
, NULL
, NULL
, 0);
927 zend_hash_destroy(&zdtor
);
936 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to execute query (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
938 if (SUCCESS
== php_pqres_success(res TSRMLS_CC
)) {
939 php_pq_object_to_zval_no_addref(PQresultInstanceData(res
, php_pqconn_event
), &return_value TSRMLS_CC
);
944 php_pqconn_notify_listeners(obj TSRMLS_CC
);
950 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async
, 0, 0, 2)
951 ZEND_ARG_INFO(0, query
)
952 ZEND_ARG_ARRAY_INFO(0, params
, 0)
953 ZEND_ARG_ARRAY_INFO(0, types
, 1)
954 ZEND_ARG_INFO(0, callable
)
956 static PHP_METHOD(pqconn
, execParamsAsync
) {
957 zend_error_handling zeh
;
958 php_pq_callback_t resolver
= {{0}};
965 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
966 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sa/|a/!f", &query_str
, &query_len
, &zparams
, &ztypes
, &resolver
.fci
, &resolver
.fcc
);
967 zend_restore_error_handling(&zeh TSRMLS_CC
);
970 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
973 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
977 char **params
= NULL
;
980 ZEND_INIT_SYMTABLE(&zdtor
);
981 count
= php_pq_params_to_array(Z_ARRVAL_P(zparams
), ¶ms
, &zdtor TSRMLS_CC
);
984 php_pq_types_to_array(Z_ARRVAL_P(ztypes
), &types TSRMLS_CC
);
987 if (!PQsendQueryParams(obj
->intern
->conn
, query_str
, count
, types
, (const char *const*) params
, NULL
, NULL
, 0)) {
988 throw_exce(EX_IO TSRMLS_CC
, "Failed to execute query (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
989 } else if (obj
->intern
->unbuffered
&& !PQsetSingleRowMode(obj
->intern
->conn
)) {
990 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
992 obj
->intern
->poller
= PQconsumeInput
;
993 php_pq_callback_dtor(&obj
->intern
->onevent
);
994 if (resolver
.fci
.size
> 0) {
995 obj
->intern
->onevent
= resolver
;
996 php_pq_callback_addref(&obj
->intern
->onevent
);
998 php_pqconn_notify_listeners(obj TSRMLS_CC
);
1001 zend_hash_destroy(&zdtor
);
1010 zend_restore_error_handling(&zeh TSRMLS_CC
);
1013 STATUS
php_pqconn_prepare(zval
*object
, php_pqconn_object_t
*obj
, const char *name
, const char *query
, HashTable
*typest TSRMLS_DC
)
1021 obj
= zend_object_store_get_object(object TSRMLS_CC
);
1025 count
= zend_hash_num_elements(typest
);
1026 php_pq_types_to_array(typest
, &types TSRMLS_CC
);
1029 res
= PQprepare(obj
->intern
->conn
, name
, query
, count
, types
);
1037 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1039 rv
= php_pqres_success(res TSRMLS_CC
);
1041 php_pqconn_notify_listeners(obj TSRMLS_CC
);
1047 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare
, 0, 0, 2)
1048 ZEND_ARG_INFO(0, type
)
1049 ZEND_ARG_INFO(0, query
)
1050 ZEND_ARG_ARRAY_INFO(0, types
, 1)
1051 ZEND_END_ARG_INFO();
1052 static PHP_METHOD(pqconn
, prepare
) {
1053 zend_error_handling zeh
;
1054 zval
*ztypes
= NULL
;
1055 char *name_str
, *query_str
;
1056 int name_len
, *query_len
;
1059 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
1060 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|a/!", &name_str
, &name_len
, &query_str
, &query_len
, &ztypes
);
1061 zend_restore_error_handling(&zeh TSRMLS_CC
);
1063 if (SUCCESS
== rv
) {
1064 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1067 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1068 } else if (SUCCESS
== php_pqconn_prepare(getThis(), obj
, name_str
, query_str
, ztypes
? Z_ARRVAL_P(ztypes
) : NULL TSRMLS_CC
)) {
1069 php_pqstm_t
*stm
= ecalloc(1, sizeof(*stm
));
1071 php_pq_object_addref(obj TSRMLS_CC
);
1073 stm
->name
= estrdup(name_str
);
1074 ZEND_INIT_SYMTABLE(&stm
->bound
);
1076 return_value
->type
= IS_OBJECT
;
1077 return_value
->value
.obj
= php_pqstm_create_object_ex(php_pqstm_class_entry
, stm
, NULL TSRMLS_CC
);
1082 STATUS
php_pqconn_prepare_async(zval
*object
, php_pqconn_object_t
*obj
, const char *name
, const char *query
, HashTable
*typest TSRMLS_DC
)
1089 obj
= zend_object_store_get_object(object TSRMLS_CC
);
1093 count
= php_pq_types_to_array(typest
, &types TSRMLS_CC
);
1096 if (!PQsendPrepare(obj
->intern
->conn
, name
, query
, count
, types
)) {
1098 throw_exce(EX_IO TSRMLS_CC
, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1099 } else if (obj
->intern
->unbuffered
&& !PQsetSingleRowMode(obj
->intern
->conn
)) {
1101 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1104 obj
->intern
->poller
= PQconsumeInput
;
1105 php_pqconn_notify_listeners(obj TSRMLS_CC
);
1115 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async
, 0, 0, 2)
1116 ZEND_ARG_INFO(0, type
)
1117 ZEND_ARG_INFO(0, query
)
1118 ZEND_ARG_ARRAY_INFO(0, types
, 1)
1119 ZEND_END_ARG_INFO();
1120 static PHP_METHOD(pqconn
, prepareAsync
) {
1121 zend_error_handling zeh
;
1122 zval
*ztypes
= NULL
;
1123 char *name_str
, *query_str
;
1124 int name_len
, *query_len
;
1127 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
1128 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "ss|a/!", &name_str
, &name_len
, &query_str
, &query_len
, &ztypes
);
1129 zend_restore_error_handling(&zeh TSRMLS_CC
);
1131 if (SUCCESS
== rv
) {
1132 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1135 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1136 } else if (SUCCESS
== php_pqconn_prepare_async(getThis(), obj
, name_str
, query_str
, ztypes
? Z_ARRVAL_P(ztypes
) : NULL TSRMLS_CC
)) {
1137 php_pqstm_t
*stm
= ecalloc(1, sizeof(*stm
));
1139 php_pq_object_addref(obj TSRMLS_CC
);
1141 stm
->name
= estrdup(name_str
);
1142 ZEND_INIT_SYMTABLE(&stm
->bound
);
1144 return_value
->type
= IS_OBJECT
;
1145 return_value
->value
.obj
= php_pqstm_create_object_ex(php_pqstm_class_entry
, stm
, NULL TSRMLS_CC
);
1150 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote
, 0, 0, 1)
1151 ZEND_ARG_INFO(0, string
)
1152 ZEND_END_ARG_INFO();
1153 static PHP_METHOD(pqconn
, quote
) {
1157 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &str
, &len
)) {
1158 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1161 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1163 char *quoted
= PQescapeLiteral(obj
->intern
->conn
, str
, len
);
1166 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to quote string (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1169 RETVAL_STRING(quoted
, 1);
1176 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote_name
, 0, 0, 1)
1177 ZEND_ARG_INFO(0, type
)
1178 ZEND_END_ARG_INFO();
1179 static PHP_METHOD(pqconn
, quoteName
) {
1183 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &str
, &len
)) {
1184 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1187 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1189 char *quoted
= PQescapeIdentifier(obj
->intern
->conn
, str
, len
);
1192 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to quote name (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1195 RETVAL_STRING(quoted
, 1);
1202 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea
, 0, 0, 1)
1203 ZEND_ARG_INFO(0, bytea
)
1204 ZEND_END_ARG_INFO();
1205 static PHP_METHOD(pqconn
, escapeBytea
) {
1209 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &str
, &len
)) {
1210 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1213 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1216 char *escaped_str
= (char *) PQescapeByteaConn(obj
->intern
->conn
, (unsigned char *) str
, len
, &escaped_len
);
1219 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1222 RETVAL_STRINGL(escaped_str
, escaped_len
- 1, 1);
1223 PQfreemem(escaped_str
);
1229 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_unescape_bytea
, 0, 0, 1)
1230 ZEND_ARG_INFO(0, bytea
)
1231 ZEND_END_ARG_INFO();
1232 static PHP_METHOD(pqconn
, unescapeBytea
) {
1236 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &str
, &len
)) {
1237 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1240 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1242 size_t unescaped_len
;
1243 char *unescaped_str
= (char *) PQunescapeBytea((unsigned char *)str
, &unescaped_len
);
1245 if (!unescaped_str
) {
1246 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj
->intern
->conn
));
1249 RETVAL_STRINGL(unescaped_str
, unescaped_len
, 1);
1250 PQfreemem(unescaped_str
);
1256 STATUS
php_pqconn_start_transaction(zval
*zconn
, php_pqconn_object_t
*conn_obj
, long isolation
, zend_bool readonly
, zend_bool deferrable TSRMLS_DC
)
1258 STATUS rv
= FAILURE
;
1261 conn_obj
= zend_object_store_get_object(zconn TSRMLS_CC
);
1264 if (!conn_obj
->intern
) {
1265 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1268 smart_str cmd
= {0};
1269 const char *il
= isolation_level(&isolation
);
1271 smart_str_appends(&cmd
, "START TRANSACTION ISOLATION LEVEL ");
1272 smart_str_appends(&cmd
, il
);
1273 smart_str_appends(&cmd
, ", READ ");
1274 smart_str_appends(&cmd
, readonly
? "ONLY" : "WRITE");
1275 smart_str_appends(&cmd
, ",");
1276 smart_str_appends(&cmd
, deferrable
? "" : " NOT");
1277 smart_str_appends(&cmd
, " DEFERRABLE");
1280 res
= PQexec(conn_obj
->intern
->conn
, cmd
.c
);
1283 throw_exce(EX_RUNTIME TSRMLS_CC
, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj
->intern
->conn
));
1285 rv
= php_pqres_success(res TSRMLS_CC
);
1287 php_pqconn_notify_listeners(conn_obj TSRMLS_CC
);
1290 smart_str_free(&cmd
);
1296 STATUS
php_pqconn_start_transaction_async(zval
*zconn
, php_pqconn_object_t
*conn_obj
, long isolation
, zend_bool readonly
, zend_bool deferrable TSRMLS_DC
)
1298 STATUS rv
= FAILURE
;
1301 conn_obj
= zend_object_store_get_object(zconn TSRMLS_CC
);
1304 if (!conn_obj
->intern
) {
1305 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1307 smart_str cmd
= {0};
1308 const char *il
= isolation_level(&isolation
);
1310 smart_str_appends(&cmd
, "START TRANSACTION ISOLATION LEVEL ");
1311 smart_str_appends(&cmd
, il
);
1312 smart_str_appends(&cmd
, ", READ ");
1313 smart_str_appends(&cmd
, readonly
? "ONLY" : "WRITE");
1314 smart_str_appends(&cmd
, ",");
1315 smart_str_appends(&cmd
, deferrable
? "" : "NOT ");
1316 smart_str_appends(&cmd
, " DEFERRABLE");
1319 if (!PQsendQuery(conn_obj
->intern
->conn
, cmd
.c
)) {
1320 throw_exce(EX_IO TSRMLS_CC
, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj
->intern
->conn
));
1323 conn_obj
->intern
->poller
= PQconsumeInput
;
1324 php_pqconn_notify_listeners(conn_obj TSRMLS_CC
);
1327 smart_str_free(&cmd
);
1333 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction
, 0, 0, 0)
1334 ZEND_ARG_INFO(0, isolation
)
1335 ZEND_ARG_INFO(0, readonly
)
1336 ZEND_ARG_INFO(0, deferrable
)
1337 ZEND_END_ARG_INFO();
1338 static PHP_METHOD(pqconn
, startTransaction
) {
1339 zend_error_handling zeh
;
1340 long isolation
= PHP_PQTXN_READ_COMMITTED
;
1341 zend_bool readonly
= 0, deferrable
= 0;
1344 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
1345 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|lbb", &isolation
, &readonly
, &deferrable
);
1346 zend_restore_error_handling(&zeh TSRMLS_CC
);
1348 if (SUCCESS
== rv
) {
1349 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1351 rv
= php_pqconn_start_transaction(getThis(), obj
, isolation
, readonly
, deferrable TSRMLS_CC
);
1353 if (SUCCESS
== rv
) {
1354 php_pqtxn_t
*txn
= ecalloc(1, sizeof(*txn
));
1356 php_pq_object_addref(obj TSRMLS_CC
);
1359 txn
->isolation
= isolation
;
1360 txn
->readonly
= readonly
;
1361 txn
->deferrable
= deferrable
;
1363 return_value
->type
= IS_OBJECT
;
1364 return_value
->value
.obj
= php_pqtxn_create_object_ex(php_pqtxn_class_entry
, txn
, NULL TSRMLS_CC
);
1369 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async
, 0, 0, 0)
1370 ZEND_ARG_INFO(0, isolation
)
1371 ZEND_ARG_INFO(0, readonly
)
1372 ZEND_ARG_INFO(0, deferrable
)
1373 ZEND_END_ARG_INFO();
1374 static PHP_METHOD(pqconn
, startTransactionAsync
) {
1375 zend_error_handling zeh
;
1376 long isolation
= PHP_PQTXN_READ_COMMITTED
;
1377 zend_bool readonly
= 0, deferrable
= 0;
1380 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
1381 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|lbb", &isolation
, &readonly
, &deferrable
);
1382 zend_restore_error_handling(&zeh TSRMLS_CC
);
1383 if (SUCCESS
== rv
) {
1384 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1386 rv
= php_pqconn_start_transaction_async(getThis(), obj
, isolation
, readonly
, deferrable TSRMLS_CC
);
1388 if (SUCCESS
== rv
) {
1389 php_pqtxn_t
*txn
= ecalloc(1, sizeof(*txn
));
1391 php_pq_object_addref(obj TSRMLS_CC
);
1393 txn
->isolation
= isolation
;
1394 txn
->readonly
= readonly
;
1395 txn
->deferrable
= deferrable
;
1397 return_value
->type
= IS_OBJECT
;
1398 return_value
->value
.obj
= php_pqtxn_create_object_ex(php_pqtxn_class_entry
, txn
, NULL TSRMLS_CC
);
1403 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace
, 0, 0, 0)
1404 ZEND_ARG_INFO(0, stdio_stream
)
1405 ZEND_END_ARG_INFO();
1406 static PHP_METHOD(pqconn
, trace
) {
1407 zval
*zstream
= NULL
;
1409 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|r!", &zstream
)) {
1410 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1413 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1416 PQuntrace(obj
->intern
->conn
);
1420 php_stream
*stream
= NULL
;
1422 php_stream_from_zval(stream
, &zstream
);
1424 if (SUCCESS
!= php_stream_cast(stream
, PHP_STREAM_AS_STDIO
, (void *) &fp
, REPORT_ERRORS
)) {
1427 stream
->flags
|= PHP_STREAM_FLAG_NO_CLOSE
;
1428 PQtrace(obj
->intern
->conn
, fp
);
1436 ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_on
, 0, 0, 2)
1437 ZEND_ARG_INFO(0, type
)
1438 ZEND_ARG_INFO(0, callable
)
1439 ZEND_END_ARG_INFO();
1440 static PHP_METHOD(pqconn
, on
) {
1441 zend_error_handling zeh
;
1444 php_pq_callback_t cb
;
1447 zend_replace_error_handling(EH_THROW
, exce(EX_INVALID_ARGUMENT
), &zeh TSRMLS_CC
);
1448 rv
= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sf", &type_str
, &type_len
, &cb
.fci
, &cb
.fcc
);
1449 zend_restore_error_handling(&zeh TSRMLS_CC
);
1451 if (SUCCESS
== rv
) {
1452 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1455 throw_exce(EX_UNINITIALIZED TSRMLS_CC
, "pq\\Connection not initialized");
1457 php_pqconn_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1459 RETVAL_LONG(php_pqconn_add_eventhandler(obj
, type_str
, type_len
, &cb TSRMLS_CC
));
1464 static zend_function_entry php_pqconn_methods
[] = {
1465 PHP_ME(pqconn
, __construct
, ai_pqconn_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
1466 PHP_ME(pqconn
, reset
, ai_pqconn_reset
, ZEND_ACC_PUBLIC
)
1467 PHP_ME(pqconn
, resetAsync
, ai_pqconn_reset_async
, ZEND_ACC_PUBLIC
)
1468 PHP_ME(pqconn
, poll
, ai_pqconn_poll
, ZEND_ACC_PUBLIC
)
1469 PHP_ME(pqconn
, exec
, ai_pqconn_exec
, ZEND_ACC_PUBLIC
)
1470 PHP_ME(pqconn
, execAsync
, ai_pqconn_exec_async
, ZEND_ACC_PUBLIC
)
1471 PHP_ME(pqconn
, execParams
, ai_pqconn_exec_params
, ZEND_ACC_PUBLIC
)
1472 PHP_ME(pqconn
, execParamsAsync
, ai_pqconn_exec_params_async
, ZEND_ACC_PUBLIC
)
1473 PHP_ME(pqconn
, prepare
, ai_pqconn_prepare
, ZEND_ACC_PUBLIC
)
1474 PHP_ME(pqconn
, prepareAsync
, ai_pqconn_prepare_async
, ZEND_ACC_PUBLIC
)
1475 PHP_ME(pqconn
, listen
, ai_pqconn_listen
, ZEND_ACC_PUBLIC
)
1476 PHP_ME(pqconn
, listenAsync
, ai_pqconn_listen_async
, ZEND_ACC_PUBLIC
)
1477 PHP_ME(pqconn
, notify
, ai_pqconn_notify
, ZEND_ACC_PUBLIC
)
1478 PHP_ME(pqconn
, notifyAsync
, ai_pqconn_notify_async
, ZEND_ACC_PUBLIC
)
1479 PHP_ME(pqconn
, getResult
, ai_pqconn_get_result
, ZEND_ACC_PUBLIC
)
1480 PHP_ME(pqconn
, quote
, ai_pqconn_quote
, ZEND_ACC_PUBLIC
)
1481 PHP_ME(pqconn
, quoteName
, ai_pqconn_quote_name
, ZEND_ACC_PUBLIC
)
1482 PHP_ME(pqconn
, escapeBytea
, ai_pqconn_escape_bytea
, ZEND_ACC_PUBLIC
)
1483 PHP_ME(pqconn
, unescapeBytea
, ai_pqconn_unescape_bytea
, ZEND_ACC_PUBLIC
)
1484 PHP_ME(pqconn
, startTransaction
, ai_pqconn_start_transaction
, ZEND_ACC_PUBLIC
)
1485 PHP_ME(pqconn
, startTransactionAsync
, ai_pqconn_start_transaction_async
, ZEND_ACC_PUBLIC
)
1486 PHP_ME(pqconn
, trace
, ai_pqconn_trace
, ZEND_ACC_PUBLIC
)
1487 PHP_ME(pqconn
, on
, ai_pqconn_on
, ZEND_ACC_PUBLIC
)
1491 PHP_MINIT_FUNCTION(pqconn
)
1493 zend_class_entry ce
= {0};
1494 php_pq_object_prophandler_t ph
= {0};
1496 INIT_NS_CLASS_ENTRY(ce
, "pq", "Connection", php_pqconn_methods
);
1497 php_pqconn_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
1498 php_pqconn_class_entry
->create_object
= php_pqconn_create_object
;
1500 memcpy(&php_pqconn_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1501 php_pqconn_object_handlers
.read_property
= php_pq_object_read_prop
;
1502 php_pqconn_object_handlers
.write_property
= php_pq_object_write_prop
;
1503 php_pqconn_object_handlers
.clone_obj
= NULL
;
1504 php_pqconn_object_handlers
.get_property_ptr_ptr
= NULL
;
1505 php_pqconn_object_handlers
.get_properties
= php_pq_object_properties
;
1506 php_pqconn_object_handlers
.get_debug_info
= php_pq_object_debug_info
;
1508 zend_hash_init(&php_pqconn_object_prophandlers
, 14, NULL
, NULL
, 1);
1510 zend_declare_property_long(php_pqconn_class_entry
, ZEND_STRL("status"), CONNECTION_BAD
, ZEND_ACC_PUBLIC TSRMLS_CC
);
1511 ph
.read
= php_pqconn_object_read_status
;
1512 zend_hash_add(&php_pqconn_object_prophandlers
, "status", sizeof("status"), (void *) &ph
, sizeof(ph
), NULL
);
1514 zend_declare_property_long(php_pqconn_class_entry
, ZEND_STRL("transactionStatus"), PQTRANS_UNKNOWN
, ZEND_ACC_PUBLIC TSRMLS_CC
);
1515 ph
.read
= php_pqconn_object_read_transaction_status
;
1516 zend_hash_add(&php_pqconn_object_prophandlers
, "transactionStatus", sizeof("transactionStatus"), (void *) &ph
, sizeof(ph
), NULL
);
1518 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("socket"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1519 ph
.read
= NULL
; /* forward to std prophandler */
1520 zend_hash_add(&php_pqconn_object_prophandlers
, "socket", sizeof("socket"), (void *) &ph
, sizeof(ph
), NULL
);
1522 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1523 ph
.read
= php_pqconn_object_read_error_message
;
1524 zend_hash_add(&php_pqconn_object_prophandlers
, "errorMessage", sizeof("errorMessage"), (void *) &ph
, sizeof(ph
), NULL
);
1526 zend_declare_property_bool(php_pqconn_class_entry
, ZEND_STRL("busy"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1527 ph
.read
= php_pqconn_object_read_busy
;
1528 zend_hash_add(&php_pqconn_object_prophandlers
, "busy", sizeof("busy"), (void *) &ph
, sizeof(ph
), NULL
);
1530 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("encoding"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1531 ph
.read
= php_pqconn_object_read_encoding
;
1532 ph
.write
= php_pqconn_object_write_encoding
;
1533 zend_hash_add(&php_pqconn_object_prophandlers
, "encoding", sizeof("encoding"), (void *) &ph
, sizeof(ph
), NULL
);
1536 zend_declare_property_bool(php_pqconn_class_entry
, ZEND_STRL("unbuffered"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1537 ph
.read
= php_pqconn_object_read_unbuffered
;
1538 ph
.write
= php_pqconn_object_write_unbuffered
;
1539 zend_hash_add(&php_pqconn_object_prophandlers
, "unbuffered", sizeof("unbuffered"), (void *) &ph
, sizeof(ph
), NULL
);
1542 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("db"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1543 ph
.read
= php_pqconn_object_read_db
;
1544 zend_hash_add(&php_pqconn_object_prophandlers
, "db", sizeof("db"), (void *) &ph
, sizeof(ph
), NULL
);
1546 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1547 ph
.read
= php_pqconn_object_read_user
;
1548 zend_hash_add(&php_pqconn_object_prophandlers
, "user", sizeof("user"), (void *) &ph
, sizeof(ph
), NULL
);
1550 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1551 ph
.read
= php_pqconn_object_read_pass
;
1552 zend_hash_add(&php_pqconn_object_prophandlers
, "pass", sizeof("pass"), (void *) &ph
, sizeof(ph
), NULL
);
1554 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1555 ph
.read
= php_pqconn_object_read_host
;
1556 zend_hash_add(&php_pqconn_object_prophandlers
, "host", sizeof("host"), (void *) &ph
, sizeof(ph
), NULL
);
1558 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1559 ph
.read
= php_pqconn_object_read_port
;
1560 zend_hash_add(&php_pqconn_object_prophandlers
, "port", sizeof("port"), (void *) &ph
, sizeof(ph
), NULL
);
1562 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("options"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1563 ph
.read
= php_pqconn_object_read_options
;
1564 zend_hash_add(&php_pqconn_object_prophandlers
, "options", sizeof("options"), (void *) &ph
, sizeof(ph
), NULL
);
1566 zend_declare_property_null(php_pqconn_class_entry
, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC TSRMLS_CC
);
1567 ph
.read
= php_pqconn_object_read_event_handlers
;
1568 zend_hash_add(&php_pqconn_object_prophandlers
, "eventHandlers", sizeof("eventHandlers"), (void *) &ph
, sizeof(ph
), NULL
);
1570 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC
);
1571 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC
);
1572 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC
);
1573 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("MADE"), CONNECTION_MADE TSRMLS_CC
);
1574 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("AWAITING_RESPONSE"), CONNECTION_AWAITING_RESPONSE TSRMLS_CC
);
1575 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK TSRMLS_CC
);
1576 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP TSRMLS_CC
);
1577 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("SETENV"), CONNECTION_SETENV TSRMLS_CC
);
1579 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE TSRMLS_CC
);
1580 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE TSRMLS_CC
);
1581 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("TRANS_INTRANS"), PQTRANS_INTRANS TSRMLS_CC
);
1582 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("TRANS_INERROR"), PQTRANS_INERROR TSRMLS_CC
);
1583 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("TRANS_UNKNOWN"), PQTRANS_UNKNOWN TSRMLS_CC
);
1585 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("POLLING_FAILED"), PGRES_POLLING_FAILED TSRMLS_CC
);
1586 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("POLLING_READING"), PGRES_POLLING_READING TSRMLS_CC
);
1587 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC
);
1588 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC
);
1590 zend_declare_class_constant_stringl(php_pqconn_class_entry
, ZEND_STRL("EVENT_NOTICE"), ZEND_STRL("notice") TSRMLS_CC
);
1591 zend_declare_class_constant_stringl(php_pqconn_class_entry
, ZEND_STRL("EVENT_RESULT"), ZEND_STRL("result") TSRMLS_CC
);
1592 zend_declare_class_constant_stringl(php_pqconn_class_entry
, ZEND_STRL("EVENT_RESET"), ZEND_STRL("reset") TSRMLS_CC
);
1594 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("ASYNC"), 0x1 TSRMLS_CC
);
1595 zend_declare_class_constant_long(php_pqconn_class_entry
, ZEND_STRL("PERSISTENT"), 0x2 TSRMLS_CC
);
1605 * vim600: noet sw=4 ts=4 fdm=marker
1606 * vim<600: noet sw=4 ts=4