+ throw_exce(EX_BAD_METHODCALL TSRMLS_CC, "pq\\Connection already initialized");
+ } else {
+ php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj TSRMLS_CC);
+ php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags};
+
+ obj->intern = ecalloc(1, sizeof(*obj->intern));
+
+ zend_hash_init(&obj->intern->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0);
+ zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ if (flags & PHP_PQCONN_PERSISTENT) {
+ 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);
+ php_resource_factory_init(&obj->intern->factory, php_persistent_handle_get_resource_factory_ops(), phf, (void (*)(void*)) php_persistent_handle_abandon);
+ } else {
+ php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL);
+ }
+
+ if (flags & PHP_PQCONN_ASYNC) {
+ obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll;
+ }
+
+ obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata TSRMLS_CC);
+
+ PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata);
+ PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata);
+
+ if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) {
+ throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn));
+ }
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, reset) {
+ zend_error_handling zeh;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters_none();
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
+ } else {
+ PQreset(obj->intern->conn);
+
+ if (CONNECTION_OK != PQstatus(obj->intern->conn)) {
+ throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn));
+ }
+
+ php_pqconn_notify_listeners(obj TSRMLS_CC);
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, resetAsync) {
+ zend_error_handling zeh;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters_none();
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
+ } else {
+ if (!PQresetStart(obj->intern->conn)) {
+ throw_exce(EX_IO TSRMLS_CC, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn));
+ } else {
+ obj->intern->poller = (int (*)(PGconn*)) PQresetPoll;
+ }
+
+ php_pqconn_notify_listeners(obj TSRMLS_CC);
+ }
+ }
+}
+
+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)
+{
+ HashTable ht, *existing_listeners;
+
+ php_pq_callback_addref(listener);
+
+ if (SUCCESS == zend_hash_find(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &existing_listeners)) {
+ zend_hash_next_index_insert(existing_listeners, (void *) listener, sizeof(*listener), NULL);
+ } else {
+ zend_hash_init(&ht, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0);
+ zend_hash_next_index_insert(&ht, (void *) listener, sizeof(*listener), NULL);
+ zend_hash_add(&obj->intern->listeners, channel_str, channel_len + 1, (void *) &ht, sizeof(HashTable), NULL);
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0)
+ ZEND_ARG_INFO(0, channel)
+ ZEND_ARG_INFO(0, callable)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, listen) {
+ zend_error_handling zeh;
+ char *channel_str = NULL;
+ int channel_len = 0;
+ php_pq_callback_t listener;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized");
+ } else {