* COPY: getAsync & putAsync
+* CURSOR: *Async()
* fetchInto/fetchCtor?
* unlisten?
* unregister event handler?
src/php_pqstm.c\
src/php_pqtxn.c\
src/php_pqtypes.c\
+ src/php_pqcur.c\
"
PHP_NEW_EXTENSION(pq, $PQ_SRC, $ext_shared)
PHP_ADD_BUILD_DIR($ext_builddir/src)
#ifdef PHP_WIN32
# define PHP_PQ_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
-# define PHP_PQ_API __attribute__ ((visibility("default")))
+# define PHP_PQ_API extern __attribute__ ((visibility("default")))
#else
-# define PHP_PQ_API
+# define PHP_PQ_API extern
#endif
#ifdef ZTS
#endif
#include <php.h>
+#include <Zend/zend_closures.h>
#include "php_pq_callback.h"
void php_pq_callback_dtor(php_pq_callback_t *cb)
{
+ if (cb->recursion) {
+ php_pq_callback_dtor(cb->recursion);
+ efree(cb->recursion);
+ cb->recursion = NULL;
+ }
if (cb->fci.size > 0) {
zend_fcall_info_args_clear(&cb->fci, 1);
zval_ptr_dtor(&cb->fci.function_name);
if (cb->fci.object_ptr) {
zval_ptr_dtor(&cb->fci.object_ptr);
}
+ cb->fci.size = 0;
}
- cb->fci.size = 0;
}
void php_pq_callback_addref(php_pq_callback_t *cb)
return zcb;
}
+
+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 (closure->type == ZEND_USER_FUNCTION) {
+ zend_execute_data *ex = EG(current_execute_data);
+
+ while (ex) {
+ if (ex->op_array == &closure->op_array) {
+ return 1;
+ }
+ ex = ex->prev_execute_data;
+ }
+ }
+ }
+ return 0;
+}
+
+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;
+ } else {
+ php_pq_callback_dtor(old);
+ }
+}
+
/*
* Local variables:
* tab-width: 4
typedef struct php_pq_callback {
zend_fcall_info fci;
zend_fcall_info_cache fcc;
- void *data;
+ struct php_pq_callback *recursion;
} php_pq_callback_t;
void php_pq_callback_dtor(php_pq_callback_t *cb);
void php_pq_callback_addref(php_pq_callback_t *cb);
zval *php_pq_callback_to_zval(php_pq_callback_t *cb);
+zend_bool php_pq_callback_is_locked(php_pq_callback_t *cb);
+void php_pq_callback_recurse(php_pq_callback_t *old, php_pq_callback_t *new TSRMLS_DC);
#endif
PHP_MINIT_CALL(pqres);
PHP_MINIT_CALL(pqstm);
PHP_MINIT_CALL(pqtxn);
+ PHP_MINIT_CALL(pqcur);
PHP_MINIT_CALL(pqcopy);
PHP_MINIT_CALL(pqlob);
#include "php_pqres.h"
#include "php_pqstm.h"
#include "php_pqtxn.h"
+#include "php_pqcur.h"
zend_class_entry *php_pqconn_class_entry;
static zend_object_handlers php_pqconn_object_handlers;
fprintf(stderr, "FREE conn(#%d) %p\n", obj->zv.handle, obj);
#endif
if (obj->intern) {
+ php_pq_callback_dtor(&obj->intern->onevent);
php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn TSRMLS_CC);
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);
zend_hash_apply_with_arguments(&evdata->obj->intern->listeners TSRMLS_CC, apply_unlisten, 1, evdata->obj);
/* release instance data */
- memset(evdata, 0, sizeof(*evdata));
+ //memset(evdata, 0, sizeof(*evdata));
efree(evdata);
}
}
zend_error_handling zeh;
char *channel_str = NULL;
int channel_len = 0;
- php_pq_callback_t listener;
+ php_pq_callback_t listener = {{0}};
STATUS rv;
zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
zend_error_handling zeh;
char *channel_str = NULL;
int channel_len = 0;
- php_pq_callback_t listener;
+ php_pq_callback_t listener = {{0}};
STATUS rv;
zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
}
ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare, 0, 0, 2)
- ZEND_ARG_INFO(0, type)
+ ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, query)
ZEND_ARG_ARRAY_INFO(0, types, 1)
ZEND_END_ARG_INFO();
}
ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_prepare_async, 0, 0, 2)
-ZEND_ARG_INFO(0, type)
+ ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, query)
ZEND_ARG_ARRAY_INFO(0, types, 1)
ZEND_END_ARG_INFO();
}
}
+static inline char *declare_str(const char *name_str, size_t name_len, unsigned flags, const char *query_str, size_t query_len)
+{
+ size_t decl_len = name_len + query_len + sizeof("DECLARE BINARY INSENSITIVE NO SCROLL CURSOR WITHOUT HOLD FOR ");
+ char *decl_str;
+
+ decl_str = emalloc(decl_len);
+ decl_len = slprintf(decl_str, decl_len, "DECLARE %s %s %s %s CURSOR %s FOR %s",
+ name_str,
+ (flags & PHP_PQ_DECLARE_BINARY) ? "BINARY" : "",
+ (flags & PHP_PQ_DECLARE_INSENSITIVE) ? "INSENSITIVE" : "",
+ (flags & PHP_PQ_DECLARE_NO_SCROLL) ? "NO SCROLL" :
+ (flags & PHP_PQ_DECLARE_SCROLL) ? "SCROLL" : "",
+ (flags & PHP_PQ_DECLARE_WITH_HOLD) ? "WITH HOLD" : "",
+ query_str
+ );
+ return decl_str;
+}
+
+STATUS php_pqconn_declare(zval *object, php_pqconn_object_t *obj, const char *decl TSRMLS_DC)
+{
+ PGresult *res;
+ STATUS rv;
+
+ if (!obj) {
+ obj = zend_object_store_get_object(object TSRMLS_CC);
+ }
+
+ res = PQexec(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_pqconn_notify_listeners(obj TSRMLS_CC);
+ }
+
+ return rv;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare, 0, 0, 3)
+ ZEND_ARG_INFO(0, name)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, query)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, declare) {
+ zend_error_handling zeh;
+ char *name_str, *query_str;
+ int name_len, query_len;
+ long flags;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls", &name_str, &name_len, &flags, &query_str, &query_len);
+ 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 {
+ char *decl = declare_str(name_str, name_len, flags, query_str, query_len);
+
+ if (SUCCESS != php_pqconn_declare(getThis(), obj, decl TSRMLS_CC)) {
+ efree(decl);
+ } else {
+ php_pqcur_t *cur = ecalloc(1, sizeof(*cur));
+
+ php_pq_object_addref(obj TSRMLS_CC);
+ cur->conn = obj;
+ cur->open = 1;
+ cur->name = estrdup(name_str);
+ cur->decl = decl;
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqcur_create_object_ex(php_pqcur_class_entry, cur, NULL TSRMLS_CC);
+ }
+ }
+ }
+}
+
+STATUS php_pqconn_declare_async(zval *object, php_pqconn_object_t *obj, const char *decl TSRMLS_DC)
+{
+ STATUS rv;
+
+ if (!obj) {
+ obj = zend_object_store_get_object(object TSRMLS_CC);
+ }
+
+ if (!PQsendQuery(obj->intern->conn, decl)) {
+ rv = FAILURE;
+ throw_exce(EX_IO TSRMLS_CC, "Failed to declare cursor (%s)", PHP_PQerrorMessage(obj->intern->conn));
+ } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) {
+ rv = FAILURE;
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn));
+ } else {
+ rv = SUCCESS;
+ obj->intern->poller = PQconsumeInput;
+ php_pqconn_notify_listeners(obj TSRMLS_CC);
+ }
+
+ return rv;
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_declare_async, 0, 0, 2)
+ ZEND_ARG_INFO(0, name)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, query)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqconn, declareAsync) {
+ zend_error_handling zeh;
+ char *name_str, *query_str;
+ int name_len, query_len;
+ long flags;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sls", &name_str, &name_len, &flags, &query_str, &query_len);
+ 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 {
+ char *decl = declare_str(name_str, name_len, flags, query_str, query_len);
+
+ if (SUCCESS != php_pqconn_declare_async(getThis(), obj, decl TSRMLS_CC)) {
+ efree(decl);
+ } else {
+ php_pqcur_t *cur = ecalloc(1, sizeof(*cur));
+
+ php_pq_object_addref(obj TSRMLS_CC);
+ cur->conn = obj;
+ cur->open = 1;
+ cur->name = estrdup(name_str);
+ cur->decl = decl;
+
+ return_value->type = IS_OBJECT;
+ return_value->value.obj = php_pqcur_create_object_ex(php_pqcur_class_entry, cur, NULL TSRMLS_CC);
+ }
+ }
+ }
+}
+
ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1)
ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO();
zend_error_handling zeh;
char *type_str;
int type_len;
- php_pq_callback_t cb;
+ php_pq_callback_t cb = {{0}};
STATUS rv;
zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
PHP_ME(pqconn, execParamsAsync, ai_pqconn_exec_params_async, ZEND_ACC_PUBLIC)
PHP_ME(pqconn, prepare, ai_pqconn_prepare, ZEND_ACC_PUBLIC)
PHP_ME(pqconn, prepareAsync, ai_pqconn_prepare_async, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, declare, ai_pqconn_declare, ZEND_ACC_PUBLIC)
+ PHP_ME(pqconn, declareAsync, ai_pqconn_declare_async, ZEND_ACC_PUBLIC)
PHP_ME(pqconn, listen, ai_pqconn_listen, ZEND_ACC_PUBLIC)
PHP_ME(pqconn, listenAsync, ai_pqconn_listen_async, ZEND_ACC_PUBLIC)
PHP_ME(pqconn, notify, ai_pqconn_notify, ZEND_ACC_PUBLIC)
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 php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC);
STATUS php_pqconn_start_transaction_async(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC);
+STATUS php_pqconn_declare(zval *object, php_pqconn_object_t *obj, const char *decl TSRMLS_DC);
+STATUS php_pqconn_declare_async(zval *object, php_pqconn_object_t *obj, const char *decl TSRMLS_DC);
PHP_MINIT_FUNCTION(pqconn);
PHP_MSHUTDOWN_FUNCTION(pqconn);
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: pq |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2013, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <php.h>
+#include <ext/standard/php_smart_str.h>
+
+#include "php_pq.h"
+#include "php_pq_misc.h"
+#include "php_pq_object.h"
+#include "php_pqexc.h"
+#include "php_pqconn.h"
+#include "php_pqres.h"
+#include "php_pqcur.h"
+
+zend_class_entry *php_pqcur_class_entry;
+static zend_object_handlers php_pqcur_object_handlers;
+static HashTable php_pqcur_object_prophandlers;
+
+static void cur_close(php_pqcur_object_t *obj TSRMLS_DC)
+{
+ if (obj->intern->open) {
+ PGresult *res;
+ smart_str cmd = {0};
+
+ smart_str_appends(&cmd, "CLOSE ");
+ smart_str_appends(&cmd, obj->intern->name);
+ smart_str_0(&cmd);
+
+ if ((res = PQexec(obj->intern->conn->intern->conn, cmd.c))) {
+ PHP_PQclear(res);
+ }
+ smart_str_free(&cmd);
+
+ obj->intern->open = 0;
+ }
+}
+
+static void cur_fetch_or_move(INTERNAL_FUNCTION_PARAMETERS, const char *action, zend_bool async)
+{
+ char *spec_str = "1";
+ int spec_len = 1;
+ STATUS rv;
+ php_pq_callback_t resolver = {{0}};
+ zend_error_handling zeh;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, async ? "|sf" : "|s", &spec_str, &spec_len, &resolver.fci, &resolver.fcc);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (SUCCESS == rv) {
+ php_pqcur_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Cursor not initialized");
+ } else {
+ smart_str cmd = {0};
+
+ smart_str_appends(&cmd, *action == 'f' ? "FETCH " : "MOVE ");
+ smart_str_appendl(&cmd, spec_str, spec_len);
+ smart_str_appends(&cmd, " FROM ");
+ smart_str_appends(&cmd, obj->intern->name);
+ smart_str_0(&cmd);
+
+ if (async) {
+ int rc = PQsendQuery(obj->intern->conn->intern->conn, cmd.c);
+
+ if (!rc) {
+ throw_exce(EX_IO TSRMLS_CC, "Failed to %s cursor (%s)", *action == 'f' ? "fetch from" : "move in", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ } else if (obj->intern->conn->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn->intern->conn)) {
+ throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn));
+ } else {
+ php_pq_callback_recurse(&obj->intern->conn->intern->onevent, &resolver);
+ obj->intern->conn->intern->poller = PQconsumeInput;
+ }
+ } else {
+ PGresult *res = PQexec(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));
+ } 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);
+
+ }
+ }
+ smart_str_free(&cmd);
+ php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC);
+ }
+ }
+}
+
+static void php_pqcur_object_free(void *o TSRMLS_DC)
+{
+ php_pqcur_object_t *obj = o;
+#if DBG_GC
+ fprintf(stderr, "FREE cur(#%d) %p (conn: %p)\n", obj->zv.handle, obj, obj->intern->conn);
+#endif
+ if (obj->intern) {
+ //cur_close(obj TSRMLS_CC);
+ //php_pq_object_delref(obj->intern->conn TSRMLS_CC);
+ efree(obj->intern->decl);
+ efree(obj->intern->name);
+ efree(obj->intern);
+ obj->intern = NULL;
+ }
+ zend_object_std_dtor((zend_object *) o TSRMLS_CC);
+ efree(obj);
+}
+
+zend_object_value php_pqcur_create_object_ex(zend_class_entry *ce, php_pqcur_t *intern, php_pqcur_object_t **ptr TSRMLS_DC)
+{
+ php_pqcur_object_t *o;
+
+ o = ecalloc(1, sizeof(*o));
+ zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
+ object_properties_init((zend_object *) o, ce);
+ o->prophandler = &php_pqcur_object_prophandlers;
+
+ if (ptr) {
+ *ptr = o;
+ }
+
+ if (intern) {
+ o->intern = intern;
+ }
+
+ o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqcur_object_free, NULL TSRMLS_CC);
+ o->zv.handlers = &php_pqcur_object_handlers;
+
+ return o->zv;
+}
+
+static zend_object_value php_pqcur_create_object(zend_class_entry *class_type TSRMLS_DC)
+{
+ return php_pqcur_create_object_ex(class_type, NULL, NULL TSRMLS_CC);
+}
+
+static void php_pqcur_object_read_name(zval *object, void *o, zval *return_value TSRMLS_DC)
+{
+ php_pqcur_object_t *obj = o;
+
+ RETVAL_STRING(obj->intern->name, 1);
+}
+
+static void php_pqcur_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC)
+{
+ php_pqcur_object_t *obj = o;
+
+ php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_open, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcur, open)
+{
+ zend_error_handling zeh;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters_none();
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (rv == SUCCESS) {
+ php_pqcur_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED, "pq\\Cursor not initialized");
+ } else if (!obj->intern->open) {
+ if (SUCCESS == php_pqconn_declare(NULL, obj->intern->conn, obj->intern->decl)) {
+ obj->intern->open = 1;
+ }
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_close, 0, 0, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcur, close)
+{
+ zend_error_handling zeh;
+ STATUS rv;
+
+ zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC);
+ rv = zend_parse_parameters_none();
+ zend_restore_error_handling(&zeh TSRMLS_CC);
+
+ if (rv == SUCCESS) {
+ php_pqcur_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!obj->intern) {
+ throw_exce(EX_UNINITIALIZED, "pq\\Cursor not initialized");
+ } else {
+ cur_close(obj TSRMLS_CC);
+ }
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_fetch, 0, 0, 1)
+ ZEND_ARG_INFO(0, spec)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcur, fetch)
+{
+ cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "fetch", 0);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_move, 0, 0, 0)
+ ZEND_ARG_INFO(0, spec)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcur, move)
+{
+ cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "move", 0);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_fetchAsync, 0, 0, 0)
+ ZEND_ARG_INFO(0, spec)
+ ZEND_ARG_INFO(0, callback)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcur, fetchAsync)
+{
+ cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "fetch", 1);
+}
+
+ZEND_BEGIN_ARG_INFO_EX(ai_pqcur_moveAsync, 0, 0, 0)
+ ZEND_ARG_INFO(0, spec)
+ ZEND_ARG_INFO(0, callback)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(pqcur, moveAsync)
+{
+ cur_fetch_or_move(INTERNAL_FUNCTION_PARAM_PASSTHRU, "move", 1);
+}
+
+static zend_function_entry php_pqcur_methods[] = {
+ PHP_ME(pqcur, open, ai_pqcur_open, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcur, close, ai_pqcur_close, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcur, fetch, ai_pqcur_fetch, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcur, move, ai_pqcur_move, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcur, fetchAsync, ai_pqcur_fetchAsync, ZEND_ACC_PUBLIC)
+ PHP_ME(pqcur, moveAsync, ai_pqcur_moveAsync, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+
+PHP_MSHUTDOWN_FUNCTION(pqcur)
+{
+ zend_hash_destroy(&php_pqcur_object_prophandlers);
+ return SUCCESS;
+}
+
+PHP_MINIT_FUNCTION(pqcur)
+{
+ zend_class_entry ce = {0};
+ php_pq_object_prophandler_t ph = {0};
+
+ INIT_NS_CLASS_ENTRY(ce, "pq", "Cursor", php_pqcur_methods);
+ php_pqcur_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
+ php_pqcur_class_entry->create_object = php_pqcur_create_object;
+
+ memcpy(&php_pqcur_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_pqcur_object_handlers.read_property = php_pq_object_read_prop;
+ php_pqcur_object_handlers.write_property = php_pq_object_write_prop;
+ php_pqcur_object_handlers.clone_obj = NULL;
+ php_pqcur_object_handlers.get_property_ptr_ptr = NULL;
+ php_pqcur_object_handlers.get_gc = NULL;
+ php_pqcur_object_handlers.get_properties = php_pq_object_properties;
+ php_pqcur_object_handlers.get_debug_info = php_pq_object_debug_info;
+
+ zend_hash_init(&php_pqcur_object_prophandlers, 2, NULL, NULL, 1);
+
+ zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("BINARY"), PHP_PQ_DECLARE_BINARY TSRMLS_CC);
+ zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("INSENSITIVE"), PHP_PQ_DECLARE_INSENSITIVE TSRMLS_CC);
+ zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("WITH_HOLD"), PHP_PQ_DECLARE_WITH_HOLD TSRMLS_CC);
+ zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("SCROLL"), PHP_PQ_DECLARE_SCROLL TSRMLS_CC);
+ zend_declare_class_constant_long(php_pqcur_class_entry, ZEND_STRL("NO_SCROLL"), PHP_PQ_DECLARE_NO_SCROLL TSRMLS_CC);
+
+ zend_declare_property_null(php_pqcur_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ ph.read = php_pqcur_object_read_name;
+ zend_hash_add(&php_pqcur_object_prophandlers, "name", sizeof("name"), (void *) &ph, sizeof(ph), NULL);
+
+ zend_declare_property_null(php_pqcur_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC);
+ ph.read = php_pqcur_object_read_connection;
+ zend_hash_add(&php_pqcur_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL);
+
+ return SUCCESS;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +--------------------------------------------------------------------+
+ | PECL :: pq |
+ +--------------------------------------------------------------------+
+ | Redistribution and use in source and binary forms, with or without |
+ | modification, are permitted provided that the conditions mentioned |
+ | in the accompanying LICENSE file are met. |
+ +--------------------------------------------------------------------+
+ | Copyright (c) 2013, Michael Wallner <mike@php.net> |
+ +--------------------------------------------------------------------+
+*/
+
+#ifndef PHP_PQCUR_H
+#define PHP_PQCUR_H
+
+#include "php_pqconn.h"
+
+#define PHP_PQ_DECLARE_BINARY 0x01
+#define PHP_PQ_DECLARE_INSENSITIVE 0x02
+#define PHP_PQ_DECLARE_WITH_HOLD 0x04
+
+#define PHP_PQ_DECLARE_SCROLL 0x10
+#define PHP_PQ_DECLARE_NO_SCROLL 0x20
+
+typedef struct php_pqcur {
+ php_pqconn_object_t *conn;
+ char *name;
+ char *decl;
+ unsigned open:1;
+} php_pqcur_t;
+
+typedef struct php_pqcur_object {
+ zend_object zo;
+ zend_object_value zv;
+ HashTable *prophandler;
+ php_pqcur_t *intern;
+} php_pqcur_object_t;
+
+zend_class_entry *php_pqcur_class_entry;
+zend_object_value php_pqcur_create_object_ex(zend_class_entry *ce, php_pqcur_t *intern, php_pqcur_object_t **ptr TSRMLS_DC);
+
+PHP_MINIT_FUNCTION(pqcur);
+PHP_MSHUTDOWN_FUNCTION(pqcur);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
RETVAL_FALSE;
} else {
zval_dtor(zref);
- ZVAL_ZVAL(zref, *zres, 1, 1);
+ ZVAL_ZVAL(zref, *zres, 1, 0);
RETVAL_TRUE;
}
}
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
- | Copyright (c) 2013, Michael Wallner <mike@php.net> |
+ | Copyright (c) 2013, Michael Wallner <mike@php.net> |
+--------------------------------------------------------------------+
*/
--- /dev/null
+--TEST--
+async cursor
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php
+echo "Test\n";
+include "_setup.inc";
+
+function complete($c) {
+ do {
+ while ($c->busy) {
+ $r = array($c->socket);
+ $w = $e = null;
+ if (stream_select($r, $w, $e, null)) {
+ $c->poll();
+ }
+ }
+ } while ($c->getResult());
+}
+
+$c = new pq\Connection(PQ_DSN);
+$p = $c->declareAsync("mycursor", pq\Cursor::WITH_HOLD,
+ "SELECT * FROM generate_series(0,29) s WHERE (s%2)=0");
+complete($c);
+
+do {
+ $p->fetchAsync(2, function ($r) {
+ foreach ($r as $row) {
+ foreach ($row as $col) {
+ echo " $col";
+ }
+ echo "\n";
+ }
+ });
+ complete($p->connection);
+ $p->moveAsync(1, function ($r) use(&$keep_going) {
+ $keep_going = $r->affectedRows;
+ });
+ complete($p->connection);
+} while ($keep_going);
+
+?>
+===DONE===
+--EXPECT--
+Test
+ 0
+ 2
+ 6
+ 8
+ 12
+ 14
+ 18
+ 20
+ 24
+ 26
+===DONE===
--- /dev/null
+--TEST--
+cursor
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php
+echo "Test\n";
+
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+$p = $c->declare("mycursor", pq\Cursor::WITH_HOLD,
+ "SELECT * FROM generate_series(0,29) s WHERE (s%2)=0");
+for ($r = $p->fetch(2); $r->numRows; $p->move(1), $r = $p->fetch(2)) {
+ foreach ($r as $row) {
+ foreach ($row as $col) {
+ echo " $col";
+ }
+ echo "\n";
+ }
+}
+?>
+===DONE===
+--EXPECT--
+Test
+ 0
+ 2
+ 6
+ 8
+ 12
+ 14
+ 18
+ 20
+ 24
+ 26
+===DONE===