X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;ds=sidebyside;f=src%2Fphp_pqconn.c;h=79bb57047ae0173431fa7782b04aeea7c21dddb5;hb=de42b70bed81a6f47bbb8f614413ae9a04ec9940;hp=e71199d59e3fb133e22e61a313e8b1032fe04a31;hpb=9f5cecf26bd70a92ed013f31afec59e272623ac1;p=m6w6%2Fext-pq diff --git a/src/php_pqconn.c b/src/php_pqconn.c index e71199d..79bb570 100644 --- a/src/php_pqconn.c +++ b/src/php_pqconn.c @@ -77,6 +77,7 @@ static void php_pqconn_object_free(void *o TSRMLS_DC) php_resource_factory_dtor(&obj->intern->factory); php_pq_callback_dtor(&obj->intern->onevent); zend_hash_destroy(&obj->intern->listeners); + zend_hash_destroy(&obj->intern->converters); zend_hash_destroy(&obj->intern->eventhandlers); efree(obj->intern); obj->intern = NULL; @@ -311,12 +312,40 @@ static void php_pqconn_object_read_options(zval *object, void *o, zval *return_v } } +static int apply_read_event_handler_ex(void *p, void *arg TSRMLS_DC) +{ + HashTable *rv = arg; + zval *zcb = php_pq_callback_to_zval(p); + + zend_hash_next_index_insert(rv, &zcb, sizeof(zval *), NULL); + + return ZEND_HASH_APPLY_KEEP; +} + +static int apply_read_event_handlers(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +{ + HashTable *evhs = p, *rv = va_arg(argv, HashTable *); + zval *entry, **entry_ptr; + + MAKE_STD_ZVAL(entry); + array_init_size(entry, zend_hash_num_elements(evhs)); + + if (key->nKeyLength) { + zend_hash_add(rv, key->arKey, key->nKeyLength, &entry, sizeof(zval *), (void *) &entry_ptr); + } else { + zend_hash_index_update(rv, key->h, &entry, sizeof(zval *), (void *) &entry_ptr); + } + + zend_hash_apply_with_argument(evhs, apply_read_event_handler_ex, Z_ARRVAL_PP(entry_ptr) TSRMLS_CC); + + return ZEND_HASH_APPLY_KEEP; +} static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; array_init(return_value); - zend_hash_copy(Z_ARRVAL_P(return_value), &obj->intern->eventhandlers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + zend_hash_apply_with_arguments(&obj->intern->eventhandlers TSRMLS_CC, apply_read_event_handlers, 1, Z_ARRVAL_P(return_value) TSRMLS_CC); } static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj TSRMLS_DC) @@ -494,6 +523,7 @@ static PHP_METHOD(pqconn, __construct) { 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->converters, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&obj->intern->eventhandlers, 0, NULL, (dtor_func_t) zend_hash_destroy, 0); if (flags & PHP_PQCONN_PERSISTENT) { @@ -910,27 +940,11 @@ static PHP_METHOD(pqconn, execParams) { throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); } else { PGresult *res; - int count; - Oid *types = NULL; - char **params = NULL; - HashTable zdtor; - - ZEND_INIT_SYMTABLE(&zdtor); - count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC); - - if (ztypes) { - php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC); - } - - res = PQexecParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0); + php_pq_params_t *params; - zend_hash_destroy(&zdtor); - if (types) { - efree(types); - } - if (params) { - efree(params); - } + params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams) TSRMLS_CC); + res = PQexecParams(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) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); @@ -972,19 +986,14 @@ static PHP_METHOD(pqconn, execParamsAsync) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); } else { - int count; - Oid *types = NULL; - char **params = NULL; - HashTable zdtor; + int rc; + php_pq_params_t *params; - ZEND_INIT_SYMTABLE(&zdtor); - count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC); + params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams) TSRMLS_CC); + rc = PQsendQueryParams(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 (ztypes) { - php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC); - } - - if (!PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) { + if (!rc) { throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); @@ -997,23 +1006,13 @@ static PHP_METHOD(pqconn, execParamsAsync) { } php_pqconn_notify_listeners(obj TSRMLS_CC); } - - zend_hash_destroy(&zdtor); - if (types) { - efree(types); - } - if (params) { - efree(params); - } } } zend_restore_error_handling(&zeh TSRMLS_CC); } -STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC) +STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC) { - Oid *types = NULL; - int count = 0; PGresult *res; STATUS rv; @@ -1021,16 +1020,7 @@ STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const char *na obj = zend_object_store_get_object(object TSRMLS_CC); } - if (typest) { - count = zend_hash_num_elements(typest); - php_pq_types_to_array(typest, &types TSRMLS_CC); - } - - res = PQprepare(obj->intern->conn, name, query, count, types); - - if (types) { - efree(types); - } + res = PQprepare(obj->intern->conn, name, query, params->type.count, params->type.oids); if (!res) { rv = FAILURE; @@ -1065,35 +1055,36 @@ static PHP_METHOD(pqconn, prepare) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); - } else if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) { - php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); + } else { + php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC); - php_pq_object_addref(obj TSRMLS_CC); - stm->conn = obj; - stm->name = estrdup(name_str); - ZEND_INIT_SYMTABLE(&stm->bound); + if (SUCCESS != php_pqconn_prepare(getThis(), obj, name_str, query_str, params TSRMLS_CC)) { + php_pq_params_free(¶ms); + } else { + php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); + php_pq_object_addref(obj TSRMLS_CC); + stm->conn = obj; + stm->name = estrdup(name_str); + stm->params = params; + ZEND_INIT_SYMTABLE(&stm->bound); + + return_value->type = IS_OBJECT; + return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); + } } } } -STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC) +STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, php_pq_params_t *params TSRMLS_DC) { STATUS rv; - int count; - Oid *types = NULL; if (!obj) { obj = zend_object_store_get_object(object TSRMLS_CC); } - if (typest) { - count = php_pq_types_to_array(typest, &types TSRMLS_CC); - } - - if (!PQsendPrepare(obj->intern->conn, name, query, count, types)) { + if (!PQsendPrepare(obj->intern->conn, name, query, params->type.count, params->type.oids)) { rv = FAILURE; throw_exce(EX_IO TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { @@ -1105,10 +1096,6 @@ STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const ch php_pqconn_notify_listeners(obj TSRMLS_CC); } - if (types) { - efree(types); - } - return rv; } @@ -1133,16 +1120,23 @@ static PHP_METHOD(pqconn, prepareAsync) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); - } else if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) { - php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); + } else { + php_pq_params_t *params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, NULL TSRMLS_CC); - php_pq_object_addref(obj TSRMLS_CC); - stm->conn = obj; - stm->name = estrdup(name_str); - ZEND_INIT_SYMTABLE(&stm->bound); + if (SUCCESS != php_pqconn_prepare_async(getThis(), obj, name_str, query_str, params TSRMLS_CC)) { + php_pq_params_free(¶ms); + } else { + php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); + php_pq_object_addref(obj TSRMLS_CC); + stm->conn = obj; + stm->name = estrdup(name_str); + stm->params = params; + ZEND_INIT_SYMTABLE(&stm->bound); + + return_value->type = IS_OBJECT; + return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); + } } } } @@ -1461,6 +1455,54 @@ static PHP_METHOD(pqconn, on) { } } +static int apply_set_converter(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +{ + zval *tmp, **zoid = p, **zcnv = va_arg(argv, zval **); + HashTable *converters = va_arg(argv, HashTable *); + + tmp = *zoid; + convert_to_long_ex(&tmp); + Z_ADDREF_PP(zcnv); + zend_hash_index_update(converters, Z_LVAL_P(tmp), zcnv, sizeof(zval *), NULL); + if (tmp != *zoid) { + zval_ptr_dtor(&tmp); + } + + return ZEND_HASH_APPLY_KEEP; +} + +ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_set_converter, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, converter, pq\\ConverterInterface, 0) +ZEND_END_ARG_INFO(); +static PHP_METHOD(pqconn, setConverter) { + STATUS rv; + zend_error_handling zeh; + zval *zcnv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zcnv, php_pqconv_class_entry); + 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 { + zval *tmp, *zoids = NULL; + + zend_call_method_with_0_params(&zcnv, NULL, NULL, "converttypes", &zoids); + tmp = zoids; + convert_to_array_ex(&zoids); + zend_hash_apply_with_arguments(Z_ARRVAL_P(zoids) TSRMLS_CC, apply_set_converter, 2, &zcnv, &obj->intern->converters); + if (tmp != zoids) { + zval_ptr_dtor(&tmp); + } + zval_ptr_dtor(&zoids); + } + } +} + static zend_function_entry php_pqconn_methods[] = { PHP_ME(pqconn, __construct, ai_pqconn_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(pqconn, reset, ai_pqconn_reset, ZEND_ACC_PUBLIC) @@ -1485,9 +1527,16 @@ static zend_function_entry php_pqconn_methods[] = { PHP_ME(pqconn, startTransactionAsync, ai_pqconn_start_transaction_async, ZEND_ACC_PUBLIC) PHP_ME(pqconn, trace, ai_pqconn_trace, ZEND_ACC_PUBLIC) PHP_ME(pqconn, on, ai_pqconn_on, ZEND_ACC_PUBLIC) + PHP_ME(pqconn, setConverter, ai_pqconn_set_converter, ZEND_ACC_PUBLIC) {0} }; +PHP_MSHUTDOWN_FUNCTION(pqconn) +{ + zend_hash_destroy(&php_pqconn_object_prophandlers); + return SUCCESS; +} + PHP_MINIT_FUNCTION(pqconn) { zend_class_entry ce = {0}; @@ -1502,6 +1551,8 @@ PHP_MINIT_FUNCTION(pqconn) 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_properties = php_pq_object_properties; php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info; zend_hash_init(&php_pqconn_object_prophandlers, 14, NULL, NULL, 1);