X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-pq;a=blobdiff_plain;f=src%2Fphp_pqconn.c;h=19ea6f05ebcaebd0abb059d475c7bad802f29128;hp=3e4aed88bf2354208ad76991d2a6cf3b295940dd;hb=HEAD;hpb=6e28a8741be3fccdaca960e492c31bc26837a4ed diff --git a/src/php_pqconn.c b/src/php_pqconn.c index 3e4aed8..19ea6f0 100644 --- a/src/php_pqconn.c +++ b/src/php_pqconn.c @@ -35,8 +35,14 @@ zend_class_entry *php_pqconn_class_entry; static zend_object_handlers php_pqconn_object_handlers; static HashTable php_pqconn_object_prophandlers; +static void php_pq_callback_hash_dtor(zval *p) +{ + php_pq_callback_dtor(Z_PTR_P(p)); + efree(Z_PTR_P(p)); +} + /* -static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC) +static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, unsigned long id) { zval **evhs; @@ -46,21 +52,25 @@ static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *ty } */ -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) +static zend_long php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, php_pq_callback_t *cb) { - ulong h; - HashTable *evhs; + zend_long h; + zval *zevhs; + + if (!(zevhs = zend_hash_str_find(&obj->intern->eventhandlers, type_str, type_len))) { + HashTable *evhs; + zval tmp; - if (!(evhs = zend_hash_str_find_ptr(&obj->intern->eventhandlers, type_str, type_len))) { - HashTable evh; + ALLOC_HASHTABLE(evhs); + zend_hash_init(evhs, 1, NULL, php_pq_callback_hash_dtor, 0); - zend_hash_init(&evh, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0); - evhs = zend_hash_str_add_mem(&obj->intern->eventhandlers, type_str, type_len, (void *) &evh, sizeof(evh)); + ZVAL_ARR(&tmp, evhs); + zevhs = zend_hash_str_add(&obj->intern->eventhandlers, type_str, type_len, &tmp); } php_pq_callback_addref(cb); - h = zend_hash_next_free_element(evhs); - zend_hash_index_update_ptr(evhs, h, (void *) cb); + h = zend_hash_next_free_element(Z_ARRVAL_P(zevhs)); + zend_hash_index_update_mem(Z_ARRVAL_P(zevhs), h, (void *) cb, sizeof(*cb)); return h; } @@ -69,39 +79,27 @@ static void php_pqconn_object_free(zend_object *o) { php_pqconn_object_t *obj = PHP_PQ_OBJ(NULL, o); #if DBG_GC - fprintf(stderr, "FREE conn(#%d) %p\n", obj->zv.handle, obj); + fprintf(stderr, "FREE conn(#%d) %p\n", obj->zo.handle, obj); #endif if (obj->intern) { php_pq_callback_dtor(&obj->intern->onevent); php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn); php_resource_factory_dtor(&obj->intern->factory); zend_hash_destroy(&obj->intern->listeners); + zend_hash_destroy(&obj->intern->statements); zend_hash_destroy(&obj->intern->converters); zend_hash_destroy(&obj->intern->eventhandlers); efree(obj->intern); obj->intern = NULL; } - zend_object_std_dtor(o); - efree(obj); + php_pq_object_dtor(o); } php_pqconn_object_t *php_pqconn_create_object_ex(zend_class_entry *ce, php_pqconn_t *intern) { - php_pqconn_object_t *o; - - o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); - zend_object_std_init(&o->zo, ce); - object_properties_init(&o->zo, ce); - o->prophandler = &php_pqconn_object_prophandlers; - - if (intern) { - o->intern = intern; - } - - o->zo.handlers = &php_pqconn_object_handlers; - - return o; + return php_pq_object_create(ce, intern, sizeof(php_pqconn_object_t), + &php_pqconn_object_handlers, &php_pqconn_object_prophandlers); } static zend_object *php_pqconn_create_object(zend_class_entry *class_type) @@ -109,21 +107,21 @@ static zend_object *php_pqconn_create_object(zend_class_entry *class_type) return &php_pqconn_create_object_ex(class_type, NULL)->zo; } -static void php_pqconn_object_read_status(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_status(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(PQstatus(obj->intern->conn)); } -static void php_pqconn_object_read_transaction_status(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_transaction_status(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(PQtransactionStatus(obj->intern->conn)); } -static void php_pqconn_object_read_error_message(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_error_message(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *error = PHP_PQerrorMessage(obj->intern->conn); @@ -147,6 +145,7 @@ static int apply_notify_listener(zval *p, void *arg) zend_fcall_info_argn(&listener->fci, 3, &zchannel, &zmessage, &zpid); zend_fcall_info_call(&listener->fci, &listener->fcc, NULL, NULL); + zend_fcall_info_args_clear(&listener->fci, 0); zval_ptr_dtor(&zchannel); zval_ptr_dtor(&zmessage); @@ -177,21 +176,21 @@ void php_pqconn_notify_listeners(php_pqconn_object_t *obj) } } -static void php_pqconn_object_read_busy(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_busy(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(PQisBusy(obj->intern->conn)); } -static void php_pqconn_object_read_encoding(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_encoding(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_STRING(pg_encoding_to_char(PQclientEncoding(obj->intern->conn))); } -static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value) +static void php_pqconn_object_write_encoding(void *o, zval *value) { php_pqconn_object_t *obj = o; zend_string *zenc = zval_get_string(value); @@ -203,21 +202,35 @@ static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value) zend_string_release(zenc); } -static void php_pqconn_object_read_unbuffered(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_unbuffered(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(obj->intern->unbuffered); } -static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *value) +static void php_pqconn_object_write_unbuffered(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->unbuffered = z_is_true(value); } -static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_nonblocking(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + + RETVAL_BOOL(PQisnonblocking(obj->intern->conn)); +} + +static void php_pqconn_object_write_nonblocking(void *o, zval *value) +{ + php_pqconn_object_t *obj = o; + + PQsetnonblocking(obj->intern->conn, z_is_true(value)); +} + +static void php_pqconn_object_read_db(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *db = PQdb(obj->intern->conn); @@ -229,7 +242,7 @@ static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value) } } -static void php_pqconn_object_read_user(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_user(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *user = PQuser(obj->intern->conn); @@ -241,7 +254,7 @@ static void php_pqconn_object_read_user(zval *object, void *o, zval *return_valu } } -static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_pass(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *pass = PQpass(obj->intern->conn); @@ -253,7 +266,7 @@ static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_valu } } -static void php_pqconn_object_read_host(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_host(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *host = PQhost(obj->intern->conn); @@ -265,7 +278,7 @@ static void php_pqconn_object_read_host(zval *object, void *o, zval *return_valu } } -static void php_pqconn_object_read_port(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_port(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *port = PQport(obj->intern->conn); @@ -278,7 +291,7 @@ static void php_pqconn_object_read_port(zval *object, void *o, zval *return_valu } #if HAVE_PQCONNINFO -static void php_pqconn_object_read_params(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_params(void *o, zval *return_value) { php_pqconn_object_t *obj = o; PQconninfoOption *ptr, *params = PQconninfo(obj->intern->conn); @@ -298,7 +311,7 @@ static void php_pqconn_object_read_params(zval *object, void *o, zval *return_va } #endif -static void php_pqconn_object_read_options(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_options(void *o, zval *return_value) { php_pqconn_object_t *obj = o; char *options = PQoptions(obj->intern->conn); @@ -310,7 +323,7 @@ static void php_pqconn_object_read_options(zval *object, void *o, zval *return_v } } -static int apply_read_event_handler_ex(zval *p, void *arg) +static int apply_read_callback_ex(zval *p, void *arg) { HashTable *rv = arg; zval zcb; @@ -320,9 +333,9 @@ static int apply_read_event_handler_ex(zval *p, void *arg) return ZEND_HASH_APPLY_KEEP; } -static int apply_read_event_handlers(zval *p, int argc, va_list argv, zend_hash_key *key) +static int apply_read_callbacks(zval *p, int argc, va_list argv, zend_hash_key *key) { - HashTable *evhs = Z_PTR_P(p), *rv = va_arg(argv, HashTable *); + HashTable *evhs = Z_ARRVAL_P(p), *rv = va_arg(argv, HashTable *); zval entry, *entry_ptr; array_init_size(&entry, zend_hash_num_elements(evhs)); @@ -333,83 +346,179 @@ static int apply_read_event_handlers(zval *p, int argc, va_list argv, zend_hash_ entry_ptr = zend_hash_index_update(rv, key->h, &entry); } - zend_hash_apply_with_argument(evhs, apply_read_event_handler_ex, Z_ARRVAL_P(entry_ptr)); + zend_hash_apply_with_argument(evhs, apply_read_callback_ex, Z_ARRVAL_P(entry_ptr)); return ZEND_HASH_APPLY_KEEP; } -static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_event_handlers(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + + array_init(return_value); + zend_hash_apply_with_arguments(&obj->intern->eventhandlers, apply_read_callbacks, 1, Z_ARRVAL_P(return_value)); +} + +static void php_pqconn_object_gc_event_handlers(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + zval *evhs; + + ZEND_HASH_FOREACH_VAL(&obj->intern->eventhandlers, evhs) + { + zval *evh; + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(evhs), evh) + { + zval zcb; + + add_next_index_zval(return_value, php_pq_callback_to_zval_no_addref(Z_PTR_P(evh), &zcb)); + } + ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); +} + +static void php_pqconn_object_read_listeners(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + + array_init(return_value); + zend_hash_apply_with_arguments(&obj->intern->listeners, apply_read_callbacks, 1, Z_ARRVAL_P(return_value)); +} + +static void php_pqconn_object_gc_listeners(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + zval *listeners; + + ZEND_HASH_FOREACH_VAL(&obj->intern->listeners, listeners) + { + zval *listener; + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(listeners), listener) + { + zval zcb; + + add_next_index_zval(return_value, php_pq_callback_to_zval_no_addref(Z_PTR_P(listener), &zcb)); + } + ZEND_HASH_FOREACH_END(); + } + ZEND_HASH_FOREACH_END(); +} + +static void php_pqconn_object_read_converters(void *o, zval *return_value) { php_pqconn_object_t *obj = o; array_init(return_value); - zend_hash_apply_with_arguments(&obj->intern->eventhandlers, apply_read_event_handlers, 1, Z_ARRVAL_P(return_value) TSRMLS_CC); + zend_hash_copy(Z_ARRVAL_P(return_value), &obj->intern->converters, zval_add_ref); } -static void php_pqconn_object_read_def_fetch_type(zval *object, void *o, zval *return_value) +static void php_pqconn_object_gc_converters(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + zval *converter; + + ZEND_HASH_FOREACH_VAL(&obj->intern->converters, converter) + { + add_next_index_zval(return_value, converter); + } + ZEND_HASH_FOREACH_END(); +} + +static void php_pqconn_object_read_def_fetch_type(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(obj->intern->default_fetch_type); } -static void php_pqconn_object_write_def_fetch_type(zval *object, void *o, zval *value) +static void php_pqconn_object_write_def_fetch_type(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_fetch_type = zval_get_long(value) & 0x3; /* two bits only */ } -static void php_pqconn_object_read_def_txn_isolation(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_def_txn_isolation(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(obj->intern->default_txn_isolation); } -static void php_pqconn_object_write_def_txn_isolation(zval *object, void *o, zval *value) +static void php_pqconn_object_write_def_txn_isolation(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_txn_isolation = zval_get_long(value) & 0x3; /* two bits only */ } -static void php_pqconn_object_read_def_txn_readonly(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_def_txn_readonly(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(obj->intern->default_txn_readonly); } -static void php_pqconn_object_write_def_txn_readonly(zval *object, void *o, zval *value) +static void php_pqconn_object_write_def_txn_readonly(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_txn_readonly = z_is_true(value); } -static void php_pqconn_object_read_def_txn_deferrable(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_def_txn_deferrable(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_BOOL(obj->intern->default_txn_deferrable); } -static void php_pqconn_object_write_def_txn_deferrable(zval *object, void *o, zval *value) +static void php_pqconn_object_write_def_txn_deferrable(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_txn_deferrable = zend_is_true(value); } -static void php_pqconn_object_read_def_auto_conv(zval *object, void *o, zval *return_value) +static void php_pqconn_object_read_def_auto_conv(void *o, zval *return_value) { php_pqconn_object_t *obj = o; RETVAL_LONG(obj->intern->default_auto_convert); } -static void php_pqconn_object_write_def_auto_conv(zval*object, void *o, zval *value) +static void php_pqconn_object_write_def_auto_conv(void *o, zval *value) { php_pqconn_object_t *obj = o; obj->intern->default_auto_convert = zval_get_long(value) & PHP_PQRES_CONV_ALL; } +#ifdef HAVE_PQLIBVERSION +static void php_pqconn_object_read_lib_version(void *o, zval *return_value) +{ + char ver[16]; + + php_pq_version_to_string(PQlibVersion(), ver, sizeof(ver)); + RETVAL_STRING(ver); +} +#endif +#ifdef HAVE_PQPROTOCOLVERSION +static void php_pqconn_object_read_protocol_version(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + + RETVAL_LONG(PQprotocolVersion(obj->intern->conn)); +} +#endif +#ifdef HAVE_PQSERVERVERSION +static void php_pqconn_object_read_server_version(void *o, zval *return_value) +{ + php_pqconn_object_t *obj = o; + char ver[16]; + + php_pq_version_to_string(PQserverVersion(obj->intern->conn), ver, sizeof(ver)); + RETVAL_STRING(ver); +} +#endif + static ZEND_RESULT_CODE php_pqconn_update_socket(zval *zobj, php_pqconn_object_t *obj) { zval zsocket, zmember; @@ -433,8 +542,13 @@ static ZEND_RESULT_CODE php_pqconn_update_socket(zval *zobj, php_pqconn_object_t ZVAL_NULL(&zsocket); retval = FAILURE; } - zend_get_std_object_handlers()->write_property(zobj, &zmember, &zsocket, NULL); +#if PHP_VERSION_ID >= 80000 + zend_std_write_property(Z_OBJ_P(zobj), Z_STR(zmember), &zsocket, NULL); +#else + zend_std_write_property(zobj, &zmember, &zsocket, NULL); +#endif zval_ptr_dtor(&zsocket); + zval_ptr_dtor(&zmember); return retval; } @@ -485,7 +599,7 @@ php_resource_factory_ops_t *php_pqconn_get_resource_factory_ops(void) static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle) { PGresult *res = PQexec(*handle, ""); - PHP_PQclear(res); + php_pqres_clear(res); if (CONNECTION_OK != PQstatus(*handle)) { PQreset(*handle); @@ -504,7 +618,7 @@ static inline PGresult *unlisten(PGconn *conn, const char *channel_str, size_t c smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); - res = PQexec(conn, smart_str_v(&cmd)); + res = php_pq_exec(conn, smart_str_v(&cmd)); smart_str_free(&cmd); PQfreemem(quoted_channel); @@ -519,7 +633,7 @@ static int apply_unlisten(zval *p, int argc, va_list argv, zend_hash_key *key) PGresult *res = unlisten(obj->intern->conn, key->key->val, key->key->len); if (res) { - PHP_PQclear(res); + php_pqres_clear(res); } return ZEND_HASH_APPLY_REMOVE; @@ -546,7 +660,7 @@ static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle) } /* clean up async results */ while ((res = PQgetResult(*handle))) { - PHP_PQclear(res); + php_pqres_clear(res); } /* clean up transaction & session */ @@ -560,7 +674,7 @@ static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle) } if (res) { - PHP_PQclear(res); + php_pqres_clear(res); } if (evdata) { @@ -585,7 +699,7 @@ static PHP_METHOD(pqconn, __construct) { zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &dsn_str, &dsn_len, &flags); - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_restore_error_handling(&zeh); if (SUCCESS == rv) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); @@ -601,8 +715,9 @@ static PHP_METHOD(pqconn, __construct) { obj->intern->default_auto_convert = PHP_PQRES_CONV_ALL; zend_hash_init(&obj->intern->listeners, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(&obj->intern->statements, 0, NULL, NULL, 0); zend_hash_init(&obj->intern->converters, 0, NULL, ZVAL_PTR_DTOR, 0); - zend_hash_init(&obj->intern->eventhandlers, 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) { zend_string *dsn = zend_string_init(dsn_str, dsn_len, 0); @@ -670,10 +785,10 @@ static PHP_METHOD(pqconn, resetAsync) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + throw_exce(EX_UNINITIALIZED, "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)); + throw_exce(EX_IO, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { obj->intern->poller = (int (*)(PGconn*)) PQresetPoll; } @@ -707,7 +822,7 @@ static PHP_METHOD(pqconn, unlisten) if (res) { php_pqres_success(res); - PHP_PQclear(res); + php_pqres_clear(res); } } } @@ -760,15 +875,21 @@ static PHP_METHOD(pqconn, unlistenAsync) { static void php_pqconn_add_listener(php_pqconn_object_t *obj, const char *channel_str, size_t channel_len, php_pq_callback_t *listener) { - zval *existing, tmp; + zval *existing; php_pq_callback_addref(listener); if ((existing = zend_hash_str_find(&obj->intern->listeners, channel_str, channel_len))) { zend_hash_next_index_insert_mem(Z_ARRVAL_P(existing), (void *) listener, sizeof(*listener)); } else { - ZVAL_NEW_ARR(&tmp); - zend_hash_next_index_insert_mem(Z_ARRVAL(tmp), (void *) listener, sizeof(*listener)); + zval tmp; + HashTable *ht; + + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 0, NULL, php_pq_callback_hash_dtor, 0); + zend_hash_next_index_insert_mem(ht, (void *) listener, sizeof(*listener)); + + ZVAL_ARR(&tmp, ht); zend_hash_str_add(&obj->intern->listeners, channel_str, channel_len, &tmp); } } @@ -781,7 +902,7 @@ static PHP_METHOD(pqconn, listen) { zend_error_handling zeh; char *channel_str = NULL; size_t channel_len = 0; - php_pq_callback_t listener = {{0}}; + php_pq_callback_t listener = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); @@ -806,7 +927,7 @@ static PHP_METHOD(pqconn, listen) { smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); - res = PQexec(obj->intern->conn, smart_str_v(&cmd)); + res = php_pq_exec(obj->intern->conn, smart_str_v(&cmd)); smart_str_free(&cmd); PQfreemem(quoted_channel); @@ -818,7 +939,7 @@ static PHP_METHOD(pqconn, listen) { obj->intern->poller = PQconsumeInput; php_pqconn_add_listener(obj, channel_str, channel_len, &listener); } - PHP_PQclear(res); + php_pqres_clear(res); } php_pqconn_notify_listeners(obj); @@ -835,7 +956,7 @@ static PHP_METHOD(pqconn, listenAsync) { zend_error_handling zeh; char *channel_str = NULL; size_t channel_len = 0; - php_pq_callback_t listener = {{0}}; + php_pq_callback_t listener = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); @@ -846,12 +967,12 @@ static PHP_METHOD(pqconn, listenAsync) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len); if (!quoted_channel) { - throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); + throw_exce(EX_ESCAPE, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { smart_str cmd = {0}; @@ -897,13 +1018,13 @@ static PHP_METHOD(pqconn, notify) { PGresult *res; char *params[2] = {channel_str, message_str}; - res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0); + res = php_pq_exec_params(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0); if (!res) { throw_exce(EX_RUNTIME, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { php_pqres_success(res); - PHP_PQclear(res); + php_pqres_clear(res); } php_pqconn_notify_listeners(obj); @@ -972,6 +1093,40 @@ static PHP_METHOD(pqconn, poll) { } } +ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_flush, 0, 0, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(pqconn, flush) { + zend_error_handling zeh; + ZEND_RESULT_CODE rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters_none(); + zend_restore_error_handling(&zeh); + + if (SUCCESS == rv) { + php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); + + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); + } else if (!obj->intern->poller) { + throw_exce(EX_RUNTIME, "No asynchronous operation active"); + } else { + switch (PQflush(obj->intern->conn)) { + case -1: + default: + throw_exce(EX_RUNTIME, "Failed to flush connection: %s", PHP_PQerrorMessage(obj->intern->conn)); + break; + case 0: + RETVAL_TRUE; + break; + case 1: + RETVAL_FALSE; + break; + } + } + } +} + ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec, 0, 0, 1) ZEND_ARG_INFO(0, query) ZEND_END_ARG_INFO(); @@ -991,14 +1146,14 @@ static PHP_METHOD(pqconn, exec) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { - PGresult *res = PQexec(obj->intern->conn, query_str); + PGresult *res = php_pq_exec(obj->intern->conn, query_str); if (!res) { throw_exce(EX_RUNTIME, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else if (SUCCESS == php_pqres_success(res)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); } else { - PHP_PQclear(res); + php_pqres_clear(res); } php_pqconn_notify_listeners(obj); @@ -1023,11 +1178,12 @@ static PHP_METHOD(pqconn, getResult) { throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res = PQgetResult(obj->intern->conn); + php_pq_object_t *res_obj; - if (!res) { - RETVAL_NULL(); + if (res && (res_obj = PQresultInstanceData(res, php_pqconn_event))) { + php_pq_object_to_zval_no_addref(res_obj, return_value); } else { - php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); + RETVAL_NULL(); } php_pqconn_notify_listeners(obj); @@ -1041,7 +1197,7 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_async, 0, 0, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, execAsync) { zend_error_handling zeh; - php_pq_callback_t resolver = {{0}}; + php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; char *query_str; size_t query_len; ZEND_RESULT_CODE rv; @@ -1096,7 +1252,7 @@ static PHP_METHOD(pqconn, execParams) { php_pq_params_t *params; params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams)); - res = PQexecParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); + res = php_pq_exec_params(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); php_pq_params_free(¶ms); if (!res) { @@ -1105,7 +1261,7 @@ static PHP_METHOD(pqconn, execParams) { if (SUCCESS == php_pqres_success(res)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), return_value); } else { - PHP_PQclear(res); + php_pqres_clear(res); } php_pqconn_notify_listeners(obj); @@ -1122,7 +1278,7 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, execParamsAsync) { zend_error_handling zeh; - php_pq_callback_t resolver = {{0}}; + php_pq_callback_t resolver = PHP_PQ_CALLBACK_INIT; char *query_str; size_t query_len; zval *zparams; @@ -1171,14 +1327,14 @@ ZEND_RESULT_CODE php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, cons obj = PHP_PQ_OBJ(object, NULL); } - res = PQprepare(obj->intern->conn, name, query, params->type.count, params->type.oids); + res = php_pq_prepare(obj->intern->conn, name, query, params->type.count, params->type.oids); if (!res) { rv = FAILURE; throw_exce(EX_RUNTIME, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = php_pqres_success(res); - PHP_PQclear(res); + php_pqres_clear(res); php_pqconn_notify_listeners(obj); } @@ -1220,7 +1376,7 @@ static PHP_METHOD(pqconn, prepare) { } } -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) +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) { ZEND_RESULT_CODE rv; @@ -1284,14 +1440,14 @@ ZEND_RESULT_CODE php_pqconn_declare(zval *object, php_pqconn_object_t *obj, cons obj = PHP_PQ_OBJ(object, NULL); } - res = PQexec(obj->intern->conn, decl); + res = php_pq_exec(obj->intern->conn, decl); if (!res) { rv = FAILURE; throw_exce(EX_RUNTIME, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = php_pqres_success(res); - PHP_PQclear(res); + php_pqres_clear(res); php_pqconn_notify_listeners(obj); } @@ -1447,7 +1603,7 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_escape_bytea, 0, 0, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, escapeBytea) { char *str; - int len; + size_t len; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); @@ -1505,7 +1661,7 @@ ZEND_RESULT_CODE php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t * } if (!conn_obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { PGresult *res; smart_str cmd = {0}; @@ -1520,13 +1676,13 @@ ZEND_RESULT_CODE php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t * smart_str_appends(&cmd, " DEFERRABLE"); smart_str_0(&cmd); - res = PQexec(conn_obj->intern->conn, smart_str_v(&cmd)); + res = php_pq_exec(conn_obj->intern->conn, smart_str_v(&cmd)); if (!res) { throw_exce(EX_RUNTIME, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } else { rv = php_pqres_success(res); - PHP_PQclear(res); + php_pqres_clear(res); php_pqconn_notify_listeners(conn_obj); } @@ -1707,7 +1863,7 @@ static PHP_METHOD(pqconn, on) { zend_error_handling zeh; char *type_str; size_t type_len; - php_pq_callback_t cb = {{0}}; + php_pq_callback_t cb = PHP_PQ_CALLBACK_INIT; ZEND_RESULT_CODE rv; zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); @@ -1718,7 +1874,7 @@ static PHP_METHOD(pqconn, on) { php_pqconn_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Connection not initialized"); } else { RETVAL_LONG(php_pqconn_add_eventhandler(obj, type_str, type_len, &cb)); } @@ -1768,7 +1924,7 @@ static PHP_METHOD(pqconn, setConverter) { struct apply_set_converter_arg arg = {NULL}; ZVAL_NULL(&zoids); - zend_call_method_with_0_params(zcnv, NULL, NULL, "converttypes", &zoids); + php_pq_call_method(zcnv, "converttypes", 0, &zoids); ZVAL_DUP(&tmp, &zoids); convert_to_array(&tmp); @@ -1806,7 +1962,7 @@ static PHP_METHOD(pqconn, unsetConverter) { struct apply_set_converter_arg arg = {NULL}; ZVAL_NULL(&zoids); - zend_call_method_with_0_params(zcnv, NULL, NULL, "converttypes", &zoids); + php_pq_call_method(zcnv, "converttypes", 0, &zoids); ZVAL_DUP(&tmp, &zoids); convert_to_array(&tmp); @@ -1823,10 +1979,11 @@ static PHP_METHOD(pqconn, unsetConverter) { } static zend_function_entry php_pqconn_methods[] = { - PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) + PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC) PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC) PHP_ME(pqconn, resetAsync, ai_pqconn_reset_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, poll, ai_pqconn_poll, ZEND_ACC_PUBLIC) + PHP_ME(pqconn, flush, ai_pqconn_flush, ZEND_ACC_PUBLIC) PHP_ME(pqconn, exec, ai_pqconn_exec, ZEND_ACC_PUBLIC) PHP_ME(pqconn, execAsync, ai_pqconn_exec_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, execParams, ai_pqconn_exec_params, ZEND_ACC_PUBLIC) @@ -1879,12 +2036,12 @@ PHP_MINIT_FUNCTION(pqconn) php_pqconn_object_handlers.read_property = php_pq_object_read_prop; php_pqconn_object_handlers.write_property = php_pq_object_write_prop; php_pqconn_object_handlers.clone_obj = NULL; - php_pqconn_object_handlers.get_property_ptr_ptr = NULL; - php_pqconn_object_handlers.get_gc = NULL; + php_pqconn_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; + php_pqconn_object_handlers.get_gc = php_pq_object_get_gc; php_pqconn_object_handlers.get_properties = php_pq_object_properties; php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info; - zend_hash_init(&php_pqconn_object_prophandlers, 20, NULL, NULL, 1); + zend_hash_init(&php_pqconn_object_prophandlers, 23, NULL, php_pq_object_prophandler_dtor, 1); zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_status; @@ -1918,6 +2075,12 @@ PHP_MINIT_FUNCTION(pqconn) zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "unbuffered", sizeof("unbuffered")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; + zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("nonblocking"), 0, ZEND_ACC_PUBLIC); + ph.read = php_pqconn_object_read_nonblocking; + ph.write = php_pqconn_object_write_nonblocking; + zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "nonblocking", sizeof("nonblocking")-1, (void *) &ph, sizeof(ph)); + ph.write = NULL; + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("db"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_db; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "db", sizeof("db")-1, (void *) &ph, sizeof(ph)); @@ -1950,7 +2113,21 @@ PHP_MINIT_FUNCTION(pqconn) zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_event_handlers; + ph.gc = php_pqconn_object_gc_event_handlers; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers")-1, (void *) &ph, sizeof(ph)); + ph.gc = NULL; + + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("listeners"), ZEND_ACC_PUBLIC); + ph.read = php_pqconn_object_read_listeners; + ph.gc = php_pqconn_object_gc_listeners; + zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "listeners", sizeof("listeners")-1, (void *) &ph, sizeof(ph)); + ph.gc = NULL; + + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("converters"), ZEND_ACC_PUBLIC); + ph.read = php_pqconn_object_read_converters; + ph.gc = php_pqconn_object_gc_converters; + zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "converters", sizeof("converters")-1, (void *) &ph, sizeof(ph)); + ph.gc = NULL; zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("defaultFetchType"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_fetch_type; @@ -1970,7 +2147,7 @@ PHP_MINIT_FUNCTION(pqconn) zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionReadonly", sizeof("defaultTransactionReadonly")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; - zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("defaultTransactionDeferrable"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_bool(php_pqconn_class_entry, ZEND_STRL("defaultTransactionDeferrable"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqconn_object_read_def_txn_deferrable; ph.write = php_pqconn_object_write_def_txn_deferrable; zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultTransactionDeferrable", sizeof("defaultTransactionDeferrable")-1, (void *) &ph, sizeof(ph)); @@ -1982,6 +2159,24 @@ PHP_MINIT_FUNCTION(pqconn) zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultAutoConvert", sizeof("defaultAutoConvert")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; +#ifdef HAVE_PQLIBVERSION + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("libraryVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY); + ph.read = php_pqconn_object_read_lib_version; + zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("libraryVersion"), (void *) &ph, sizeof(ph)); +#endif + +#ifdef HAVE_PQPROTOCOLVERSION + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("protocolVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY); + ph.read = php_pqconn_object_read_protocol_version; + zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("protocolVersion"), (void *) &ph, sizeof(ph)); +#endif + +#ifdef HAVE_PQSERVERVERSION + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("serverVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY); + ph.read = php_pqconn_object_read_server_version; + zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("serverVersion"), (void *) &ph, sizeof(ph)); +#endif + zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED); @@ -1990,6 +2185,15 @@ PHP_MINIT_FUNCTION(pqconn) zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("AUTH_OK"), CONNECTION_AUTH_OK); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SSL_STARTUP"), CONNECTION_SSL_STARTUP); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("SETENV"), CONNECTION_SETENV); +#ifdef HAVE_CONNECTION_CHECK_WRITABLE + zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("CHECK_WRITABLE"), CONNECTION_CHECK_WRITABLE); +#endif +#ifdef HAVE_CONNECTION_CONSUME + zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("CONSUME"), CONNECTION_CONSUME); +#endif +#ifdef HAVE_CONNECTION_GSS_STARTUP + zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("GSS_STARTUP"), CONNECTION_GSS_STARTUP); +#endif zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_IDLE"), PQTRANS_IDLE); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("TRANS_ACTIVE"), PQTRANS_ACTIVE);