fix issue #9 @github: execAsync - gets another result
authorMichael Wallner <mike@php.net>
Tue, 3 May 2016 12:19:26 +0000 (14:19 +0200)
committerMichael Wallner <mike@php.net>
Tue, 3 May 2016 12:21:15 +0000 (14:21 +0200)
20 files changed:
package.xml
php_pq.h
src/php_pq_callback.c
src/php_pq_callback.h
src/php_pq_misc.c
src/php_pq_misc.h
src/php_pq_module.c
src/php_pqconn.c
src/php_pqconn.h
src/php_pqconn_event.c
src/php_pqcopy.c
src/php_pqcur.c
src/php_pqres.h
src/php_pqstm.c
src/php_pqtxn.c
src/php_pqtypes.c
tests/callback001.phpt [new file with mode: 0644]
tests/callback002.phpt [new file with mode: 0644]
tests/callback003.phpt [new file with mode: 0644]
travis/pecl

index 0b5fb18..ab2f642 100644 (file)
@@ -46,7 +46,7 @@
  </stability>
  <license uri="http://copyfree.org/content/standard/licenses/2bsd/license.txt">BSD-2-Clause</license>
  <notes><![CDATA[
-* 
+* Fix github issue #9 (execAsync - gets another result)
 ]]></notes>
  <contents>
   <dir name="/">
     <file role="test" name="basic001.phpt" />
     <file role="test" name="basic002.phpt" />
     <file role="test" name="bound002.phpt" />
+    <file role="test" name="callback001.phpt" />
+    <file role="test" name="callback002.phpt" />
+    <file role="test" name="callback003.phpt" />
     <file role="test" name="cancel001.phpt" />
     <file role="test" name="conv001.phpt" />
     <file role="test" name="copy001.phpt" />
index 8fd0a11..1462be0 100644 (file)
--- 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)
index 63f2edc..de01c37 100644 (file)
@@ -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;
+               }
+
+               closure = zend_get_closure_method_def(cb->fci.function_name TSRMLS_CC);
+               if (closure->type != ZEND_USER_FUNCTION) {
+                       return 0;
+               }
 
-                       while (ex) {
-                               if (ex->op_array == &closure->op_array) {
-                                       return 1;
-                               }
-                               ex = ex->prev_execute_data;
+               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) {
+       if (php_pq_callback_is_locked(old TSRMLS_CC)) {
+               php_pq_callback_recurse_ex(old, new TSRMLS_CC);
+       } else {
                php_pq_callback_dtor(old);
-               php_pq_callback_addref(new);
+               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));
-               new->fci.size = 0;
+               old->recursion = tmp;
+
+               php_pq_callback_addref(old);
+               php_pq_callback_disable(tmp TSRMLS_CC);
        } else {
-               php_pq_callback_dtor(old);
+               memcpy(tmp, old, sizeof(*tmp));
+               memset(old, 0, sizeof(*old));
+               old->recursion = tmp;
        }
 }
 
index 2edf6d5..412d5ed 100644 (file)
@@ -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
 
index a3db8bb..296c6b5 100644 (file)
 
 #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);
index 9fc086a..c4fed18 100644 (file)
@@ -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)
index 989b7c8..b567b4b 100644 (file)
@@ -18,7 +18,7 @@
 #include <php.h>
 #include <ext/standard/info.h>
 
-#include <libpq-fe.h>
+#include <libpq-events.h>
 
 #include "php_pq.h"
 #include "php_pq_misc.h"
index e753c7c..ad1a0a9 100644 (file)
@@ -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);
                }
 
index 03ad9c8..acec39b 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <ext/raphf/php_raphf.h>
 #include "php_pq_callback.h"
+#include "php_pq_object.h"
 #include "php_pq_params.h"
 
 typedef struct php_pqconn {
index f509c57..541892f 100644 (file)
@@ -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);
index 32e20ba..d4a042a 100644 (file)
@@ -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;
index 58ffd86..cda7ebc 100644 (file)
@@ -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));
index f5f80bf..328d53e 100644 (file)
@@ -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);
index 6d61a19..e075860 100644 (file)
@@ -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);
                        }
                }
index e0574e8..4230266 100644 (file)
@@ -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);
index 6cf5741..e3bc623 100644 (file)
@@ -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(&params);
@@ -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 (file)
index 0000000..a47b4c2
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+callback sanity
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php 
+echo "Test\n";
+
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+$c->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 (file)
index 0000000..7d7903b
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+callback sanity
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php 
+echo "Test\n";
+
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+$c->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 (file)
index 0000000..97b0aeb
--- /dev/null
@@ -0,0 +1,84 @@
+--TEST--
+callback sanity
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php 
+echo "Test\n";
+
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+$c->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
index 7d1a61d..23c2876 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7d1a61ddce20446912ed1d5c988f801903972a34
+Subproject commit 23c2876aaa0808bcfedc1c5c30da6e8234341a13