From a06db6d217fc8ba0fd9b8273a9e595477d59afcc Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 3 May 2016 14:19:26 +0200 Subject: [PATCH] fix issue #9 @github: execAsync - gets another result --- package.xml | 5 ++- php_pq.h | 2 +- src/php_pq_callback.c | 79 ++++++++++++++++++++++++++++++--------- src/php_pq_callback.h | 4 ++ src/php_pq_misc.c | 54 +++++++++++++++++++++++++++ src/php_pq_misc.h | 10 +++++ src/php_pq_module.c | 2 +- src/php_pqconn.c | 34 ++++++++--------- src/php_pqconn.h | 1 + src/php_pqconn_event.c | 2 +- src/php_pqcopy.c | 8 ++-- src/php_pqcur.c | 6 +-- src/php_pqres.h | 8 ---- src/php_pqstm.c | 8 ++-- src/php_pqtxn.c | 48 ++++++++++++------------ src/php_pqtypes.c | 6 +-- tests/callback001.phpt | 37 +++++++++++++++++++ tests/callback002.phpt | 44 ++++++++++++++++++++++ tests/callback003.phpt | 84 ++++++++++++++++++++++++++++++++++++++++++ travis/pecl | 2 +- 20 files changed, 358 insertions(+), 86 deletions(-) create mode 100644 tests/callback001.phpt create mode 100644 tests/callback002.phpt create mode 100644 tests/callback003.phpt diff --git a/package.xml b/package.xml index 0b5fb18..ab2f642 100644 --- a/package.xml +++ b/package.xml @@ -46,7 +46,7 @@ BSD-2-Clause @@ -110,6 +110,9 @@ + + + diff --git a/php_pq.h b/php_pq.h index 8fd0a11..1462be0 100644 --- a/php_pq.h +++ b/php_pq.h @@ -14,7 +14,7 @@ #ifndef PHP_PQ_H #define PHP_PQ_H -#define PHP_PQ_VERSION "1.0.0dev" +#define PHP_PQ_VERSION "1.0.1dev" #ifdef PHP_WIN32 # define PHP_PQ_API __declspec(dllexport) diff --git a/src/php_pq_callback.c b/src/php_pq_callback.c index 63f2edc..de01c37 100644 --- a/src/php_pq_callback.c +++ b/src/php_pq_callback.c @@ -64,35 +64,78 @@ zval *php_pq_callback_to_zval(php_pq_callback_t *cb) zend_bool php_pq_callback_is_locked(php_pq_callback_t *cb TSRMLS_DC) { - if (cb->fci.size > 0 && Z_TYPE_P(cb->fci.function_name) == IS_OBJECT) { - const zend_function *closure = zend_get_closure_method_def(cb->fci.function_name TSRMLS_CC); + if (php_pq_callback_is_enabled(cb)) { + const zend_function *closure; + const zend_execute_data *ex; - if (closure->type == ZEND_USER_FUNCTION) { - zend_execute_data *ex = EG(current_execute_data); + if (Z_TYPE_P(cb->fci.function_name) != IS_OBJECT) { + return 0; + } - while (ex) { - if (ex->op_array == &closure->op_array) { - return 1; - } - ex = ex->prev_execute_data; + closure = zend_get_closure_method_def(cb->fci.function_name TSRMLS_CC); + if (closure->type != ZEND_USER_FUNCTION) { + return 0; + } + + for (ex = EG(current_execute_data); ex; ex = ex->prev_execute_data) { + if (ex->op_array == &closure->op_array) { + return 1; } } } - return 0; + + if (!php_pq_callback_is_recurrent(cb)) { + return 0; + } + return php_pq_callback_is_locked(cb->recursion TSRMLS_CC); } void php_pq_callback_recurse(php_pq_callback_t *old, php_pq_callback_t *new TSRMLS_DC) { - if (new && new->fci.size > 0 && php_pq_callback_is_locked(old TSRMLS_CC)) { - new->recursion = emalloc(sizeof(*old)); - memcpy(new->recursion, old, sizeof(*old)); - } else if (new && new->fci.size > 0) { - php_pq_callback_dtor(old); - php_pq_callback_addref(new); - memcpy(old, new, sizeof(*old)); - new->fci.size = 0; + if (php_pq_callback_is_locked(old TSRMLS_CC)) { + php_pq_callback_recurse_ex(old, new TSRMLS_CC); } else { php_pq_callback_dtor(old); + if (php_pq_callback_is_enabled(new)) { + php_pq_callback_addref(new); + memcpy(old, new, sizeof(*old)); + new->fci.size = 0; + } + } +} + +extern zend_bool php_pq_callback_is_enabled(php_pq_callback_t *cb) +{ + return cb && cb->fci.size > 0; +} + +extern zend_bool php_pq_callback_is_recurrent(php_pq_callback_t *cb) +{ + return cb && cb->recursion != NULL; +} + +extern void php_pq_callback_disable(php_pq_callback_t *cb TSRMLS_DC) +{ + if (php_pq_callback_is_enabled(cb)) { + php_pq_callback_recurse_ex(cb, NULL TSRMLS_CC); + } +} + +extern void php_pq_callback_recurse_ex(php_pq_callback_t *old, php_pq_callback_t *new TSRMLS_DC) +{ + php_pq_callback_t *tmp = emalloc(sizeof(*tmp)); + + if (new) { + memcpy(tmp, old, sizeof(*tmp)); + memcpy(old, new, sizeof(*old)); + old->recursion = tmp; + + php_pq_callback_addref(old); + php_pq_callback_disable(tmp TSRMLS_CC); + } else { + memcpy(tmp, old, sizeof(*tmp)); + memset(old, 0, sizeof(*old)); + old->recursion = tmp; } } diff --git a/src/php_pq_callback.h b/src/php_pq_callback.h index 2edf6d5..412d5ed 100644 --- a/src/php_pq_callback.h +++ b/src/php_pq_callback.h @@ -26,6 +26,10 @@ extern void php_pq_callback_addref(php_pq_callback_t *cb); extern zval *php_pq_callback_to_zval(php_pq_callback_t *cb); extern zend_bool php_pq_callback_is_locked(php_pq_callback_t *cb TSRMLS_DC); extern void php_pq_callback_recurse(php_pq_callback_t *old, php_pq_callback_t *new TSRMLS_DC); +extern zend_bool php_pq_callback_is_enabled(php_pq_callback_t *cb); +extern void php_pq_callback_disable(php_pq_callback_t *cb TSRMLS_DC); +extern void php_pq_callback_recurse_ex(php_pq_callback_t *old, php_pq_callback_t *new TSRMLS_DC); +extern zend_bool php_pq_callback_is_recurrent(php_pq_callback_t *cb); #endif diff --git a/src/php_pq_misc.c b/src/php_pq_misc.c index a3db8bb..296c6b5 100644 --- a/src/php_pq_misc.c +++ b/src/php_pq_misc.c @@ -24,10 +24,64 @@ #include "php_pq.h" #include "php_pqexc.h" +#include "php_pqconn_event.h" #include "php_pq_misc.h" #undef PHP_PQ_TYPE #include "php_pq_type.h" + +/* clear result object associated with a result handle */ +void php_pq_clear_res(PGresult *r) { + php_pq_object_t *o = PQresultInstanceData(r, php_pqconn_event); + + if (o) { + TSRMLS_FETCH(); + php_pq_object_delref(o TSRMLS_CC); + } else { + PQclear(r); + } +} + +/* clear any asynchronous results */ +void php_pq_clear_conn(PGconn *conn) { + PGresult *r; + php_pqconn_event_data_t *evdata = PQinstanceData(conn, php_pqconn_event); + + while ((r = PQgetResult(conn))) { + php_pq_clear_res(r); + } + + if (evdata && evdata->obj) { + if (php_pq_callback_is_enabled(&evdata->obj->intern->onevent)) { + TSRMLS_FETCH_FROM_CTX(evdata->ts); + + if (php_pq_callback_is_locked(&evdata->obj->intern->onevent TSRMLS_CC)) { + php_pq_callback_disable(&evdata->obj->intern->onevent TSRMLS_CC); + } else { + php_pq_callback_dtor(&evdata->obj->intern->onevent); + } + } + } +} + +/* safe wrappers to clear any asynchronous wrappers before querying synchronously */ +PGresult *php_pq_exec(PGconn *conn, const char *query) { + php_pq_clear_conn(conn); + return PQexec(conn, query); +} +PGresult *php_pq_exec_params(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { + php_pq_clear_conn(conn); + return PQexecParams(conn, command, nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat); +} +PGresult *php_pq_prepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes) { + php_pq_clear_conn(conn); + return PQprepare(conn, stmtName, query, nParams, paramTypes); +} +PGresult *php_pq_exec_prepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) { + php_pq_clear_conn(conn); + return PQexecPrepared(conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat); +} + char *php_pq_rtrim(char *e) { size_t l = strlen(e); diff --git a/src/php_pq_misc.h b/src/php_pq_misc.h index 9fc086a..c4fed18 100644 --- a/src/php_pq_misc.h +++ b/src/php_pq_misc.h @@ -27,6 +27,16 @@ typedef enum { #include "php_pqres.h" +/* clear result object associated with a result handle */ +extern void php_pq_clear_res(PGresult *r); +/* clear any asynchronous results */ +extern void php_pq_clear_conn(PGconn *conn); +/* safe wrappers to clear any asynchronous wrappers before querying synchronously */ +extern PGresult *php_pq_exec(PGconn *conn, const char *query); +extern PGresult *php_pq_exec_params(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); +extern PGresult *php_pq_prepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes); +extern PGresult *php_pq_exec_prepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); + /* TSRM morony */ #if PHP_VERSION_ID >= 50700 # define z_is_true(z) zend_is_true(z TSRMLS_CC) diff --git a/src/php_pq_module.c b/src/php_pq_module.c index 989b7c8..b567b4b 100644 --- a/src/php_pq_module.c +++ b/src/php_pq_module.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include "php_pq.h" #include "php_pq_misc.h" diff --git a/src/php_pqconn.c b/src/php_pqconn.c index e753c7c..ad1a0a9 100644 --- a/src/php_pqconn.c +++ b/src/php_pqconn.c @@ -563,7 +563,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 TSRMLS_DC) { PGresult *res = PQexec(*handle, ""); - PHP_PQclear(res); + php_pq_clear_res(res); if (CONNECTION_OK != PQstatus(*handle)) { PQreset(*handle); @@ -597,7 +597,7 @@ static int apply_unlisten(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_k PGresult *res = unlisten(obj->intern->conn, key->arKey, key->nKeyLength - 1 TSRMLS_CC); if (res) { - PHP_PQclear(res); + php_pq_clear_res(res); } return ZEND_HASH_APPLY_REMOVE; @@ -624,7 +624,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_pq_clear_res(res); } /* clean up transaction & session */ @@ -638,7 +638,7 @@ static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle } if (res) { - PHP_PQclear(res); + php_pq_clear_res(res); } if (evdata) { @@ -783,7 +783,7 @@ static PHP_METHOD(pqconn, unlisten) if (res) { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } } } @@ -882,7 +882,7 @@ static PHP_METHOD(pqconn, listen) { smart_str_appends(&cmd, quoted_channel); smart_str_0(&cmd); - res = PQexec(obj->intern->conn, cmd.c); + res = php_pq_exec(obj->intern->conn, cmd.c); smart_str_free(&cmd); PQfreemem(quoted_channel); @@ -894,7 +894,7 @@ static PHP_METHOD(pqconn, listen) { obj->intern->poller = PQconsumeInput; php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC); } - PHP_PQclear(res); + php_pq_clear_res(res); } php_pqconn_notify_listeners(obj TSRMLS_CC); @@ -979,7 +979,7 @@ static PHP_METHOD(pqconn, notify) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } php_pqconn_notify_listeners(obj TSRMLS_CC); @@ -1067,14 +1067,14 @@ static PHP_METHOD(pqconn, exec) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED TSRMLS_CC, "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 TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC); } else { - PHP_PQclear(res); + php_pq_clear_res(res); } php_pqconn_notify_listeners(obj TSRMLS_CC); @@ -1181,7 +1181,7 @@ static PHP_METHOD(pqconn, execParams) { if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC); } else { - PHP_PQclear(res); + php_pq_clear_res(res); } php_pqconn_notify_listeners(obj TSRMLS_CC); @@ -1247,14 +1247,14 @@ ZEND_RESULT_CODE php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, cons obj = zend_object_store_get_object(object TSRMLS_CC); } - 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 TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); php_pqconn_notify_listeners(obj TSRMLS_CC); } @@ -1362,14 +1362,14 @@ ZEND_RESULT_CODE php_pqconn_declare(zval *object, php_pqconn_object_t *obj, cons obj = zend_object_store_get_object(object TSRMLS_CC); } - res = PQexec(obj->intern->conn, decl); + res = php_pq_exec(obj->intern->conn, decl); if (!res) { rv = FAILURE; throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { rv = php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); php_pqconn_notify_listeners(obj TSRMLS_CC); } @@ -1600,13 +1600,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, cmd.c); + res = php_pq_exec(conn_obj->intern->conn, cmd.c); if (!res) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } else { rv = php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); php_pqconn_notify_listeners(conn_obj TSRMLS_CC); } diff --git a/src/php_pqconn.h b/src/php_pqconn.h index 03ad9c8..acec39b 100644 --- a/src/php_pqconn.h +++ b/src/php_pqconn.h @@ -19,6 +19,7 @@ #include #include "php_pq_callback.h" +#include "php_pq_object.h" #include "php_pq_params.h" typedef struct php_pqconn { diff --git a/src/php_pqconn_event.c b/src/php_pqconn_event.c index f509c57..541892f 100644 --- a/src/php_pqconn_event.c +++ b/src/php_pqconn_event.c @@ -86,7 +86,7 @@ static void php_pqconn_event_resultcreate(PGEventResultCreate *event) } /* async callback */ - if (data->obj->intern->onevent.fci.size > 0) { + if (php_pq_callback_is_enabled(&data->obj->intern->onevent)) { zval *res = NULL; php_pq_object_to_zval(obj, &res TSRMLS_CC); diff --git a/src/php_pqcopy.c b/src/php_pqcopy.c index 32e20ba..d4a042a 100644 --- a/src/php_pqcopy.c +++ b/src/php_pqcopy.c @@ -150,7 +150,7 @@ static PHP_METHOD(pqcopy, __construct) { smart_str_appendl(&cmd, opt_str, opt_len); smart_str_0(&cmd); - res = PQexec(conn_obj->intern->conn, cmd.c); + res = php_pq_exec(conn_obj->intern->conn, cmd.c); if (!res) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to start %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); @@ -164,7 +164,7 @@ static PHP_METHOD(pqcopy, __construct) { php_pq_object_addref(conn_obj TSRMLS_CC); } - PHP_PQclear(res); + php_pq_clear_res(res); } smart_str_free(&cmd); @@ -232,7 +232,7 @@ static PHP_METHOD(pqcopy, end) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } } @@ -277,7 +277,7 @@ static PHP_METHOD(pqcopy, get) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); RETVAL_FALSE; } break; diff --git a/src/php_pqcur.c b/src/php_pqcur.c index 58ffd86..cda7ebc 100644 --- a/src/php_pqcur.c +++ b/src/php_pqcur.c @@ -47,8 +47,8 @@ static void cur_close(php_pqcur_object_t *obj, zend_bool async, zend_bool silent throw_exce(EX_IO TSRMLS_CC, "Failed to close cursor (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } } else { - if ((res = PQexec(obj->intern->conn->intern->conn, cmd.c))) { - PHP_PQclear(res); + if ((res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c))) { + php_pq_clear_res(res); } else if (!silent) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to close cursor (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } @@ -133,7 +133,7 @@ static void cur_fetch_or_move(INTERNAL_FUNCTION_PARAMETERS, const char *action, obj->intern->conn->intern->poller = PQconsumeInput; } } else { - PGresult *res = PQexec(obj->intern->conn->intern->conn, cmd.c); + PGresult *res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c); if (!res) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to %s cursor (%s)", *action == 'f' ? "fetch from" : "move in", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); diff --git a/src/php_pqres.h b/src/php_pqres.h index f5f80bf..328d53e 100644 --- a/src/php_pqres.h +++ b/src/php_pqres.h @@ -62,14 +62,6 @@ extern php_pqres_fetch_t php_pqres_fetch_type(php_pqres_t *res); #include "php_pq_object.h" #include "php_pqconn_event.h" -#define PHP_PQclear(_r) do { \ - php_pqres_object_t *_o = PQresultInstanceData((_r), php_pqconn_event); \ - if (_o) { \ - php_pq_object_delref(_o TSRMLS_CC); \ - } else { \ - PQclear(_r); \ - } \ -} while(0) extern zend_class_entry *php_pqres_class_entry; extern zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern, php_pqres_object_t **ptr TSRMLS_DC); diff --git a/src/php_pqstm.c b/src/php_pqstm.c index 6d61a19..e075860 100644 --- a/src/php_pqstm.c +++ b/src/php_pqstm.c @@ -51,8 +51,8 @@ static void php_pqstm_deallocate(php_pqstm_object_t *obj, zend_bool async, zend_ } else { PGresult *res; - if ((res = PQexec(obj->intern->conn->intern->conn, cmd.c))) { - PHP_PQclear(res); + if ((res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c))) { + php_pq_clear_res(res); } else if (!silent) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to deallocate statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } @@ -262,7 +262,7 @@ static PHP_METHOD(pqstm, exec) { PGresult *res; php_pq_params_set_params(obj->intern->params, zparams ? Z_ARRVAL_P(zparams) : &obj->intern->bound); - res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, obj->intern->params->param.count, (const char *const*) obj->intern->params->param.strings, NULL, NULL, 0); + res = php_pq_exec_prepared(obj->intern->conn->intern->conn, obj->intern->name, obj->intern->params->param.count, (const char *const*) obj->intern->params->param.strings, NULL, NULL, 0); php_pq_params_set_params(obj->intern->params, NULL); if (!res) { @@ -350,7 +350,7 @@ static PHP_METHOD(pqstm, desc) { add_next_index_long(return_value, PQparamtype(res, p)); } } - PHP_PQclear(res); + php_pq_clear_res(res); php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } diff --git a/src/php_pqtxn.c b/src/php_pqtxn.c index e0574e8..4230266 100644 --- a/src/php_pqtxn.c +++ b/src/php_pqtxn.c @@ -55,10 +55,10 @@ static void php_pqtxn_object_free(void *o TSRMLS_DC) #endif if (obj->intern) { if (obj->intern->open && obj->intern->conn->intern) { - PGresult *res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK"); + PGresult *res = php_pq_exec(obj->intern->conn->intern->conn, "ROLLBACK"); if (res) { - PHP_PQclear(res); + php_pq_clear_res(res); } } php_pq_object_delref(obj->intern->conn TSRMLS_CC); @@ -146,13 +146,13 @@ static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value switch ((obj->intern->isolation = Z_LVAL_P(zisolation))) { case PHP_PQTXN_READ_COMMITTED: - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL READ COMMITED"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL READ COMMITED"); break; case PHP_PQTXN_REPEATABLE_READ: - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); break; case PHP_PQTXN_SERIALIZABLE: - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); break; default: obj->intern->isolation = orig; @@ -166,7 +166,7 @@ static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value if (res) { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } } @@ -176,14 +176,14 @@ static void php_pqtxn_object_write_readonly(zval *object, void *o, zval *value T PGresult *res; if ((obj->intern->readonly = z_is_true(value))) { - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION READ ONLY"); } else { - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION READ WRITE"); } if (res) { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } } @@ -193,14 +193,14 @@ static void php_pqtxn_object_write_deferrable(zval *object, void *o, zval *value PGresult *res; if ((obj->intern->deferrable = z_is_true(value))) { - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION DEFERRABLE"); } else { - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE"); + res = php_pq_exec(obj->intern->conn->intern->conn, "SET TRANSACTION NOT DEFERRABLE"); } if (res) { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } } @@ -291,13 +291,13 @@ static PHP_METHOD(pqtxn, savepoint) { smart_str_appends(&cmd, "\""); smart_str_0(&cmd); - res = PQexec(obj->intern->conn->intern->conn, cmd.c); + res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c); if (!res) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } smart_str_free(&cmd); @@ -361,14 +361,14 @@ static PHP_METHOD(pqtxn, commit) { smart_str cmd = {0}; if (!obj->intern->savepoint) { - res = PQexec(obj->intern->conn->intern->conn, "COMMIT"); + res = php_pq_exec(obj->intern->conn->intern->conn, "COMMIT"); } else { smart_str_appends(&cmd, "RELEASE SAVEPOINT \""); smart_str_append_unsigned(&cmd, obj->intern->savepoint--); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); - res = PQexec(obj->intern->conn->intern->conn, cmd.c); + res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c); } if (!res) { @@ -379,7 +379,7 @@ static PHP_METHOD(pqtxn, commit) { obj->intern->open = 0; } } - PHP_PQclear(res); + php_pq_clear_res(res); } smart_str_free(&cmd); @@ -457,14 +457,14 @@ static PHP_METHOD(pqtxn, rollback) { smart_str cmd = {0}; if (!obj->intern->savepoint) { - res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK"); + res = php_pq_exec(obj->intern->conn->intern->conn, "ROLLBACK"); } else { smart_str_appends(&cmd, "ROLLBACK TO SAVEPOINT \""); smart_str_append_unsigned(&cmd, obj->intern->savepoint--); smart_str_appends(&cmd, "\""); smart_str_0(&cmd); - res = PQexec(obj->intern->conn->intern->conn, cmd.c); + res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c); } if (!res) { @@ -475,7 +475,7 @@ static PHP_METHOD(pqtxn, rollback) { obj->intern->open = 0; } } - PHP_PQclear(res); + php_pq_clear_res(res); } smart_str_free(&cmd); @@ -547,7 +547,7 @@ static PHP_METHOD(pqtxn, exportSnapshot) { if (!obj->intern) { throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); } else { - PGresult *res = PQexec(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()"); + PGresult *res = php_pq_exec(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()"); if (!res) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); @@ -556,7 +556,7 @@ static PHP_METHOD(pqtxn, exportSnapshot) { RETVAL_STRING(PQgetvalue(res, 0, 0), 1); } - PHP_PQclear(res); + php_pq_clear_res(res); } php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); @@ -621,13 +621,13 @@ static PHP_METHOD(pqtxn, importSnapshot) { smart_str_appends(&cmd, sid); smart_str_0(&cmd); - res = PQexec(obj->intern->conn->intern->conn, cmd.c); + res = php_pq_exec(obj->intern->conn->intern->conn, cmd.c); if (!res) { throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to import transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); + php_pq_clear_res(res); } smart_str_free(&cmd); diff --git a/src/php_pqtypes.c b/src/php_pqtypes.c index 6cf5741..e3bc623 100644 --- a/src/php_pqtypes.c +++ b/src/php_pqtypes.c @@ -275,7 +275,7 @@ static PHP_METHOD(pqtypes, refresh) { PGresult *res; if (!nsp || !zend_hash_num_elements(nsp)) { - res = PQexec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')"); + res = php_pq_exec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')"); } else { smart_str str = {0}; php_pq_params_t *params = php_pq_params_init(&obj->intern->conn->intern->converters, NULL, NULL TSRMLS_CC); @@ -285,7 +285,7 @@ static PHP_METHOD(pqtypes, refresh) { smart_str_appendc(&str, ')'); smart_str_0(&str); - res = PQexecParams(obj->intern->conn->intern->conn, str.c, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); + res = php_pq_exec_params(obj->intern->conn->intern->conn, str.c, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0); smart_str_free(&str); php_pq_params_free(¶ms); @@ -309,7 +309,7 @@ static PHP_METHOD(pqtypes, refresh) { } } - PHP_PQclear(res); + php_pq_clear_res(res); php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } diff --git a/tests/callback001.phpt b/tests/callback001.phpt new file mode 100644 index 0000000..a47b4c2 --- /dev/null +++ b/tests/callback001.phpt @@ -0,0 +1,37 @@ +--TEST-- +callback sanity +--SKIPIF-- + +--FILE-- +execAsync("select 1; select 2", function($r) { + print_r($r->fetchAll()); +}); +$c->exec("select 3"); + +?> +===DONE=== +--EXPECT-- +Test +Array +( + [0] => Array + ( + [0] => 1 + ) + +) +Array +( + [0] => Array + ( + [0] => 2 + ) + +) +===DONE=== diff --git a/tests/callback002.phpt b/tests/callback002.phpt new file mode 100644 index 0000000..7d7903b --- /dev/null +++ b/tests/callback002.phpt @@ -0,0 +1,44 @@ +--TEST-- +callback sanity +--SKIPIF-- + +--FILE-- +execAsync("select 1; select 2", function($r) { + print_r($r->fetchAll()); +}); +try { + $c->execAsync("select 3; select 4", function($r) { + + }); +} catch (Exception $e) { + printf("%s\n", $e->getMessage()); +} +$c->exec(""); +?> +===DONE=== +--EXPECT-- +Test +Failed to execute query (another command is already in progress) +Array +( + [0] => Array + ( + [0] => 1 + ) + +) +Array +( + [0] => Array + ( + [0] => 2 + ) + +) +===DONE=== diff --git a/tests/callback003.phpt b/tests/callback003.phpt new file mode 100644 index 0000000..97b0aeb --- /dev/null +++ b/tests/callback003.phpt @@ -0,0 +1,84 @@ +--TEST-- +callback sanity +--SKIPIF-- + +--FILE-- +execAsync("select 1; select 2", function($r) use($c) { + echo "CALLBACK 1\n"; + print_r($r->fetchAll()); + $c->exec("select 'bug'"); + try { + $c->execAsync("select 3; select 4", function($r) { + echo "CALLBACK 2\n"; + print_r($r->fetchAll()); + }); + } catch (Exception $e) { + printf("%s\n", $e->getMessage()); + } +}); +$c->exec("select 'end'"); +?> +===DONE=== +--EXPECT-- +Test +CALLBACK 1 +Array +( + [0] => Array + ( + [0] => 1 + ) + +) +CALLBACK 1 +Array +( + [0] => Array + ( + [0] => 2 + ) + +) +CALLBACK 2 +Array +( + [0] => Array + ( + [0] => 3 + ) + +) +CALLBACK 2 +Array +( + [0] => Array + ( + [0] => 4 + ) + +) +CALLBACK 2 +Array +( + [0] => Array + ( + [0] => 3 + ) + +) +CALLBACK 2 +Array +( + [0] => Array + ( + [0] => 4 + ) + +) +===DONE=== \ No newline at end of file diff --git a/travis/pecl b/travis/pecl index 7d1a61d..23c2876 160000 --- a/travis/pecl +++ b/travis/pecl @@ -1 +1 @@ -Subproject commit 7d1a61ddce20446912ed1d5c988f801903972a34 +Subproject commit 23c2876aaa0808bcfedc1c5c30da6e8234341a13