X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-pq;a=blobdiff_plain;f=php_pq.c;h=171b1d17e10e274569e274911d0d2ce8dbf30c98;hp=6743cf60dda2744e0341d7d5375eb40d25e470ee;hb=9746180a4d53f167dd4fd15e0cde34cd348ecb30;hpb=daf2e8ab5eb324b0a0447e87a92afb6788a722a7 diff --git a/php_pq.c b/php_pq.c index 6743cf6..171b1d1 100644 --- a/php_pq.c +++ b/php_pq.c @@ -88,7 +88,6 @@ static zend_class_entry *php_pqres_class_entry; static zend_class_entry *php_pqstm_class_entry; static zend_class_entry *php_pqtxn_class_entry; static zend_class_entry *php_pqcancel_class_entry; -static zend_class_entry *php_pqevent_class_entry; static zend_class_entry *php_pqlob_class_entry; static zend_class_entry *php_pqcopy_class_entry; @@ -152,7 +151,6 @@ static zend_object_handlers php_pqres_object_handlers; static zend_object_handlers php_pqstm_object_handlers; static zend_object_handlers php_pqtxn_object_handlers; static zend_object_handlers php_pqcancel_object_handlers; -static zend_object_handlers php_pqevent_object_handlers; static zend_object_handlers php_pqlob_object_handlers; static zend_object_handlers php_pqcopy_object_handlers; @@ -297,6 +295,7 @@ typedef struct php_pqevent_object { typedef struct php_pqlob { int lofd; Oid loid; + int stream; php_pqtxn_object_t *txn; } php_pqlob_t; @@ -338,7 +337,6 @@ static HashTable php_pqres_object_prophandlers; static HashTable php_pqstm_object_prophandlers; static HashTable php_pqtxn_object_prophandlers; static HashTable php_pqcancel_object_prophandlers; -static HashTable php_pqevent_object_prophandlers; static HashTable php_pqlob_object_prophandlers; static HashTable php_pqcopy_object_prophandlers; @@ -430,37 +428,39 @@ static zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_ } } - for (c = 0, cols = PQnfields(res); c < cols; ++c) { - if (PQgetisnull(res, row, c)) { - switch (fetch_type) { - case PHP_PQRES_FETCH_OBJECT: - add_property_null(data, PQfname(res, c)); - break; + if (PQntuples(res) > row) { + for (c = 0, cols = PQnfields(res); c < cols; ++c) { + if (PQgetisnull(res, row, c)) { + switch (fetch_type) { + case PHP_PQRES_FETCH_OBJECT: + add_property_null(data, PQfname(res, c)); + break; - case PHP_PQRES_FETCH_ASSOC: - add_assoc_null(data, PQfname(res, c)); - break; + case PHP_PQRES_FETCH_ASSOC: + add_assoc_null(data, PQfname(res, c)); + break; - case PHP_PQRES_FETCH_ARRAY: - add_index_null(data, c); - break; - } - } else { - char *val = PQgetvalue(res, row, c); - int len = PQgetlength(res, row, c); + case PHP_PQRES_FETCH_ARRAY: + add_index_null(data, c); + break; + } + } else { + char *val = PQgetvalue(res, row, c); + int len = PQgetlength(res, row, c); - switch (fetch_type) { - case PHP_PQRES_FETCH_OBJECT: - add_property_stringl(data, PQfname(res, c), val, len, 1); - break; + switch (fetch_type) { + case PHP_PQRES_FETCH_OBJECT: + add_property_stringl(data, PQfname(res, c), val, len, 1); + break; - case PHP_PQRES_FETCH_ASSOC: - add_assoc_stringl(data, PQfname(res, c), val, len, 1); - break; + case PHP_PQRES_FETCH_ASSOC: + add_assoc_stringl(data, PQfname(res, c), val, len, 1); + break; - case PHP_PQRES_FETCH_ARRAY: - add_index_stringl(data, c, val, len ,1); - break; + case PHP_PQRES_FETCH_ARRAY: + add_index_stringl(data, c, val, len ,1); + break; + } } } } @@ -473,10 +473,9 @@ static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; php_pqres_object_t *obj = zend_object_store_get_object(iter->zi.data TSRMLS_CC); - if (iter->current_val) { - zval_ptr_dtor(&iter->current_val); + if (!iter->current_val) { + iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC); } - iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC); *data_ptr = &iter->current_val; } @@ -489,10 +488,21 @@ static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint return HASH_KEY_IS_LONG; } +static void php_pqres_iterator_invalidate(zend_object_iterator *i TSRMLS_DC) +{ + php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; + + if (iter->current_val) { + zval_ptr_dtor(&iter->current_val); + iter->current_val = NULL; + } +} + static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; + php_pqres_iterator_invalidate(i TSRMLS_CC); ++iter->index; } @@ -500,6 +510,7 @@ static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; + php_pqres_iterator_invalidate(i TSRMLS_CC); iter->index = 0; } @@ -516,7 +527,7 @@ static zend_object_iterator_funcs php_pqres_iterator_funcs = { /* rewind to start of data (optional, may be NULL) */ php_pqres_iterator_rewind, /* invalidate current value/key (optional, may be NULL) */ - NULL + php_pqres_iterator_invalidate }; static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC) @@ -547,6 +558,25 @@ static STATUS php_pqres_success(PGresult *res TSRMLS_DC) } } +static void php_pq_callback_dtor(php_pq_callback_t *cb) { + 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; +} + +static void php_pq_callback_addref(php_pq_callback_t *cb) +{ + Z_ADDREF_P(cb->fci.function_name); + if (cb->fci.object_ptr) { + Z_ADDREF_P(cb->fci.object_ptr); + } +} + /* static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC) { @@ -558,46 +588,23 @@ static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *ty } */ -static ulong php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, zval *zevent TSRMLS_DC) +static ulong php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, php_pq_callback_t *cb TSRMLS_DC) { - zval **evhs; ulong h; + HashTable *evhs; - if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) { - Z_ADDREF_P(zevent); - h = zend_hash_next_free_element(Z_ARRVAL_PP(evhs)); - add_next_index_zval(*evhs, zevent); - } else { - zval *evh; + if (SUCCESS != zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) { + HashTable evh; - MAKE_STD_ZVAL(evh); - array_init(evh); - Z_ADDREF_P(zevent); - h = zend_hash_next_free_element(Z_ARRVAL_P(evh)); - add_next_index_zval(evh, zevent); - zend_hash_add(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(zval *), NULL); + zend_hash_init(&evh, 1, NULL, (dtor_func_t) php_pq_callback_dtor, 0); + zend_hash_add(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(evh), (void *) &evhs); } - return h; -} - -static void php_pq_callback_dtor(php_pq_callback_t *cb) { - 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; -} + php_pq_callback_addref(cb); + h = zend_hash_next_free_element(evhs); + zend_hash_index_update(evhs, h, (void *) cb, sizeof(*cb), NULL); -static void php_pq_callback_addref(php_pq_callback_t *cb) -{ - Z_ADDREF_P(cb->fci.function_name); - if (cb->fci.object_ptr) { - Z_ADDREF_P(cb->fci.object_ptr); - } + return h; } static void php_pq_object_to_zval(void *o, zval **zv TSRMLS_DC) @@ -776,22 +783,6 @@ static void php_pqcancel_object_free(void *o TSRMLS_DC) efree(obj); } -static void php_pqevent_object_free(void *o TSRMLS_DC) -{ - php_pqevent_object_t *obj = o; -#if DBG_GC - fprintf(stderr, "FREE event(#%d) %p\n", obj->zv.handle, obj); -#endif - if (obj->intern) { - php_pq_callback_dtor(&obj->intern->cb); - efree(obj->intern->type); - efree(obj->intern); - obj->intern = NULL; - } - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(obj); -} - static void php_pqlob_object_free(void *o TSRMLS_DC) { php_pqlob_object_t *obj = o; @@ -802,6 +793,11 @@ static void php_pqlob_object_free(void *o TSRMLS_DC) if (obj->intern->lofd) { lo_close(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd); } + /* invalidate the stream */ + if (obj->intern->stream) { + zend_list_delete(obj->intern->stream); + obj->intern->stream = 0; + } php_pq_object_delref(obj->intern->txn TSRMLS_CC); efree(obj->intern); obj->intern = NULL; @@ -965,29 +961,6 @@ static zend_object_value php_pqcancel_create_object_ex(zend_class_entry *ce, php return o->zv; } -static zend_object_value php_pqevent_create_object_ex(zend_class_entry *ce, php_pqevent_t *intern, php_pqevent_object_t **ptr TSRMLS_DC) -{ - php_pqevent_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_pqevent_object_prophandlers; - - if (ptr) { - *ptr = o; - } - - if (intern) { - o->intern = intern; - } - - o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqevent_object_free, NULL TSRMLS_CC); - o->zv.handlers = &php_pqevent_object_handlers; - - return o->zv; -} - static zend_object_value php_pqlob_create_object_ex(zend_class_entry *ce, php_pqlob_t *intern, php_pqlob_object_t **ptr TSRMLS_DC) { php_pqlob_object_t *o; @@ -1064,11 +1037,6 @@ static zend_object_value php_pqcancel_create_object(zend_class_entry *class_type return php_pqcancel_create_object_ex(class_type, NULL, NULL TSRMLS_CC); } -static zend_object_value php_pqevent_create_object(zend_class_entry *class_type TSRMLS_DC) -{ - return php_pqevent_create_object_ex(class_type, NULL, NULL TSRMLS_CC); -} - static zend_object_value php_pqlob_create_object(zend_class_entry *class_type TSRMLS_DC) { return php_pqlob_create_object_ex(class_type, NULL, NULL TSRMLS_CC); @@ -1637,13 +1605,6 @@ static void php_pqcancel_object_read_connection(zval *object, void *o, zval *ret php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC); } -static void php_pqevent_object_read_type(zval *object, void *o, zval *return_value TSRMLS_DC) -{ - php_pqevent_object_t *obj = o; - - RETVAL_STRING(obj->intern->type, 1); -} - static void php_pqlob_object_read_transaction(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqlob_object_t *obj = o; @@ -1658,6 +1619,23 @@ static void php_pqlob_object_read_oid(zval *object, void *o, zval *return_value RETVAL_LONG(obj->intern->loid); } +static void php_pqlob_object_update_stream(zval *this_ptr, php_pqlob_object_t *obj, zval **zstream TSRMLS_DC); + +static void php_pqlob_object_read_stream(zval *object, void *o, zval *return_value TSRMLS_DC) +{ + php_pqlob_object_t *obj = o; + + if (!obj->intern->stream) { + zval *zstream; + + php_pqlob_object_update_stream(object, obj, &zstream TSRMLS_CC); + RETVAL_ZVAL(zstream, 1, 1); + } else { + RETVAL_RESOURCE(obj->intern->stream); + zend_list_addref(obj->intern->stream); + } +} + static void php_pqcopy_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqcopy_object_t *obj = o; @@ -1774,11 +1752,12 @@ static STATUS php_pqconn_update_socket(zval *this_ptr, php_pqconn_object_t *obj static int apply_event(void *p, void *a TSRMLS_DC) { - zval **evh = p; + php_pq_callback_t *cb = p; zval *args = a; zval *retval = NULL; - zend_call_method_with_1_params(evh, Z_OBJCE_PP(evh), NULL, "trigger", &retval, args); + zend_fcall_info_args(&cb->fci, args TSRMLS_CC); + zend_fcall_info_call(&cb->fci, &cb->fcc, &retval, NULL TSRMLS_CC); if (retval) { zval_ptr_dtor(&retval); } @@ -1791,7 +1770,7 @@ static void php_pqconn_event_connreset(PGEventConnReset *event) php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event); if (data) { - zval **evhs; + HashTable *evhs; TSRMLS_DF(data); if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("reset"), (void *) &evhs)) { @@ -1801,7 +1780,7 @@ static void php_pqconn_event_connreset(PGEventConnReset *event) array_init(args); php_pq_object_to_zval(data->obj, &connection TSRMLS_CC); add_next_index_zval(args, connection); - zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC); + zend_hash_apply_with_argument(evhs, apply_event, args TSRMLS_CC); zval_ptr_dtor(&args); } } @@ -1829,7 +1808,7 @@ static void php_pqconn_event_resultcreate(PGEventResultCreate *event) if (data) { php_pqres_object_t *obj; - zval **evhs; + HashTable *evhs; TSRMLS_DF(data); php_pqres_init_instance_data(event->result, &obj TSRMLS_CC); @@ -1844,7 +1823,7 @@ static void php_pqconn_event_resultcreate(PGEventResultCreate *event) add_next_index_zval(args, connection); php_pq_object_to_zval(obj, &res TSRMLS_CC); add_next_index_zval(args, res); - zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC); + zend_hash_apply_with_argument(evhs, apply_event, args TSRMLS_CC); zval_ptr_dtor(&args); } @@ -1904,7 +1883,7 @@ static void php_pqconn_notice_recv(void *p, const PGresult *res) php_pqconn_event_data_t *data = p; if (data) { - zval **evhs; + HashTable *evhs; TSRMLS_DF(data); if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("notice"), (void *) &evhs)) { @@ -1915,7 +1894,7 @@ static void php_pqconn_notice_recv(void *p, const PGresult *res) php_pq_object_to_zval(data->obj, &connection TSRMLS_CC); add_next_index_zval(args, connection); add_next_index_string(args, PHP_PQresultErrorMessage(res), 1); - zend_hash_apply_with_argument(Z_ARRVAL_PP(evhs), apply_event, args TSRMLS_CC); + zend_hash_apply_with_argument(evhs, apply_event, args TSRMLS_CC); zval_ptr_dtor(&args); } } @@ -2069,7 +2048,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->eventhandlers, 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) { php_persistent_handle_factory_t *phf = php_persistent_handle_concede(NULL, ZEND_STRL("pq\\Connection"), dsn_str, dsn_len, php_pqconn_wakeup, php_pqconn_retire TSRMLS_CC); @@ -2410,7 +2389,7 @@ static PHP_METHOD(pqconn, getResult) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connectio not initialized"); + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); } else { PGresult *res = PQgetResult(obj->intern->conn); @@ -3119,6 +3098,34 @@ static PHP_METHOD(pqconn, trace) { } } +ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_on, 0, 0, 2) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, callable) +ZEND_END_ARG_INFO(); +static PHP_METHOD(pqconn, on) { + zend_error_handling zeh; + char *type_str; + int type_len; + php_pq_callback_t cb; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &type_str, &type_len, &cb.fci, &cb.fcc); + 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 { + php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + + RETVAL_LONG(php_pqconn_add_eventhandler(obj, type_str, type_len, &cb TSRMLS_CC)); + } + } +} + 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) @@ -3142,6 +3149,7 @@ static zend_function_entry php_pqconn_methods[] = { PHP_ME(pqconn, startTransaction, ai_pqconn_start_transaction, ZEND_ACC_PUBLIC) 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) {0} }; @@ -3284,7 +3292,9 @@ static STATUS php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_p obj = zend_object_store_get_object(getThis() TSRMLS_CC); } - if (!obj->intern->iter) { + if (obj->intern->iter) { + obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC); + } else { obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC); obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC); } @@ -3292,7 +3302,6 @@ static STATUS php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_p obj->intern->iter->fetch_type = fetch_type; if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC))) { obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, row TSRMLS_CC); - obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC); } obj->intern->iter->fetch_type = orig_fetch; @@ -4481,7 +4490,7 @@ static PHP_METHOD(pqtxn, openLOB) { int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode); if (lofd < 0) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%u with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqlob_t *lob = ecalloc(1, sizeof(*lob)); @@ -4525,7 +4534,7 @@ static PHP_METHOD(pqtxn, createLOB) { int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode); if (lofd < 0) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s': %s", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%u with mode '%s': %s", loid, strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { php_pqlob_t *lob = ecalloc(1, sizeof(*lob)); @@ -4565,7 +4574,7 @@ static PHP_METHOD(pqtxn, unlinkLOB) { int rc = lo_unlink(obj->intern->conn->intern->conn, loid); if (rc != 1) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to unlink LOB (oid=%ld): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to unlink LOB (oid=%u): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); @@ -4656,79 +4665,123 @@ static zend_function_entry php_pqcancel_methods[] = { {0} }; -ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_construct, 0, 0, 3) - ZEND_ARG_OBJ_INFO(0, connection, pq\\Connection, 0) - ZEND_ARG_INFO(0, type) - ZEND_ARG_INFO(0, callable) -ZEND_END_ARG_INFO(); -static PHP_METHOD(pqevent, __construct) { - zend_error_handling zeh; - zval *zconn; - char *type_str; - int type_len; - php_pq_callback_t cb; - STATUS rv; +static size_t php_pqlob_stream_write(php_stream *stream, const char *buffer, size_t length TSRMLS_DC) +{ + php_pqlob_object_t *obj = stream->abstract; + int written = 0; - zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); - rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osf", &zconn, php_pqconn_class_entry, &type_str, &type_len, &cb.fci, &cb.fcc); - zend_restore_error_handling(&zeh TSRMLS_CC); + if (obj) { + written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length); - if (SUCCESS == rv) { - php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); + if (written < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write to LOB with oid=%u (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); + } - if (!conn_obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); + } + + return written; +} + +static size_t php_pqlob_stream_read(php_stream *stream, char *buffer, size_t length TSRMLS_DC) +{ + php_pqlob_object_t *obj = stream->abstract; + int read = 0; + + if (obj) { + + if (!buffer && !length) { + if (lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd) == lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, 0, SEEK_CUR)) { + return EOF; + } } else { - php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length); - obj->intern = ecalloc(1, sizeof(*obj->intern)); - php_pq_callback_addref(&cb); - obj->intern->cb = cb; - obj->intern->type = estrdup(type_str); - obj->intern->h = php_pqconn_add_eventhandler(conn_obj, type_str, type_len, getThis() TSRMLS_CC); + if (read < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read from LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); + } } + + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); } + + return read; } -ZEND_BEGIN_ARG_INFO_EX(ai_pqevent_trigger, 0, 0, 1) - ZEND_ARG_ARRAY_INFO(0, args, 1) -ZEND_END_ARG_INFO(); -static PHP_METHOD(pqevent, trigger) { - zend_error_handling zeh; - zval *args; - STATUS rv; +static STATUS php_pqlob_stream_close(php_stream *stream, int close_handle TSRMLS_DC) +{ + return SUCCESS; +} - zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); - rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &args); - zend_restore_error_handling(&zeh TSRMLS_CC); +static int php_pqlob_stream_flush(php_stream *stream TSRMLS_DC) +{ + return SUCCESS; +} - if (SUCCESS == rv) { - php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); +static STATUS php_pqlob_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) +{ + STATUS rv = FAILURE; + php_pqlob_object_t *obj = stream->abstract; - if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Event not initialized"); - } else { - zval *rv = NULL; + if (obj) { + int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence); - if (SUCCESS != zend_fcall_info_call(&obj->intern->cb.fci, &obj->intern->cb.fcc, &rv, args TSRMLS_CC)) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to trigger event"); - } else { - if (rv) { - RETVAL_ZVAL(rv, 0, 1); - } else { - RETVAL_TRUE; - } - } + if (position < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); + rv = FAILURE; + } else { + *newoffset = position; + rv = SUCCESS; } + + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); } + + return rv; } -static zend_function_entry php_pqevent_methods[] = { - PHP_ME(pqevent, __construct, ai_pqevent_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - PHP_ME(pqevent, trigger, ai_pqevent_trigger, ZEND_ACC_PUBLIC) - {0} +static php_stream_ops php_pqlob_stream_ops = { + /* stdio like functions - these are mandatory! */ + php_pqlob_stream_write, + php_pqlob_stream_read, + php_pqlob_stream_close, + php_pqlob_stream_flush, + + "pq\\LOB stream", + + /* these are optional */ + php_pqlob_stream_seek, + NULL, /* cast */ + NULL, /* stat */ + NULL, /* set_option */ }; +static void php_pqlob_object_update_stream(zval *this_ptr, php_pqlob_object_t *obj, zval **zstream_ptr TSRMLS_DC) +{ + zval *zstream, zmember; + php_stream *stream; + + INIT_PZVAL(&zmember); + ZVAL_STRINGL(&zmember, "stream", sizeof("stream")-1, 0); + + MAKE_STD_ZVAL(zstream); + if (!obj) { + obj = zend_object_store_get_object(getThis() TSRMLS_CC); + } + stream = php_stream_alloc(&php_pqlob_stream_ops, obj, NULL, "r+b"); + stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; + zend_list_addref(obj->intern->stream = stream->rsrc_id); + php_stream_to_zval(stream, zstream); + + zend_get_std_object_handlers()->write_property(getThis(), &zmember, zstream, NULL TSRMLS_CC); + + if (zstream_ptr) { + *zstream_ptr = zstream; + } else { + zval_ptr_dtor(&zstream); + } +} + ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_construct, 0, 0, 1) ZEND_ARG_OBJ_INFO(0, transaction, pq\\Transaction, 0) ZEND_ARG_INFO(0, oid) @@ -4762,7 +4815,7 @@ static PHP_METHOD(pqlob, __construct) { int lofd = lo_open(txn_obj->intern->conn->intern->conn, loid, mode); if (lofd < 0) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%ld with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to open large object with oid=%u with mode '%s' (%s)", loid, strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)); } else { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); @@ -4801,7 +4854,7 @@ static PHP_METHOD(pqlob, write) { int written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, data_str, data_len); if (written < 0) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to write to LOB with oid=%ld (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to write to LOB with oid=%u (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { RETVAL_LONG(written); } @@ -5294,8 +5347,13 @@ static PHP_MINIT_FUNCTION(pq) zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_WRITING"), PGRES_POLLING_WRITING TSRMLS_CC); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("POLLING_OK"), PGRES_POLLING_OK TSRMLS_CC); + zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_NOTICE"), ZEND_STRL("notice") TSRMLS_CC); + zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESULT"), ZEND_STRL("result") TSRMLS_CC); + zend_declare_class_constant_stringl(php_pqconn_class_entry, ZEND_STRL("EVENT_RESET"), ZEND_STRL("reset") TSRMLS_CC); + zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("ASYNC"), 0x1 TSRMLS_CC); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("PERSISTENT"), 0x2 TSRMLS_CC); + memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq", "Types", php_pqtypes_methods); php_pqtypes_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); @@ -5459,28 +5517,6 @@ static PHP_MINIT_FUNCTION(pq) ph.read = php_pqcancel_object_read_connection; zend_hash_add(&php_pqcancel_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL); - memset(&ce, 0, sizeof(ce)); - INIT_NS_CLASS_ENTRY(ce, "pq", "Event", php_pqevent_methods); - php_pqevent_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); - php_pqevent_class_entry->create_object = php_pqevent_create_object; - - memcpy(&php_pqevent_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - php_pqevent_object_handlers.read_property = php_pq_object_read_prop; - php_pqevent_object_handlers.write_property = php_pq_object_write_prop; - php_pqevent_object_handlers.clone_obj = NULL; - php_pqevent_object_handlers.get_property_ptr_ptr = NULL; - php_pqevent_object_handlers.get_debug_info = php_pq_object_debug_info; - - zend_hash_init(&php_pqevent_object_prophandlers, 1, NULL, NULL, 1); - - zend_declare_property_null(php_pqevent_class_entry, ZEND_STRL("type"), ZEND_ACC_PUBLIC TSRMLS_CC); - ph.read = php_pqevent_object_read_type; - zend_hash_add(&php_pqevent_object_prophandlers, "type", sizeof("type"), (void *) &ph, sizeof(ph), NULL); - - zend_declare_class_constant_stringl(php_pqevent_class_entry, ZEND_STRL("NOTICE"), ZEND_STRL("notice") TSRMLS_CC); - zend_declare_class_constant_stringl(php_pqevent_class_entry, ZEND_STRL("RESULT"), ZEND_STRL("result") TSRMLS_CC); - zend_declare_class_constant_stringl(php_pqevent_class_entry, ZEND_STRL("RESET"), ZEND_STRL("reset") TSRMLS_CC); - memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq", "LOB", php_pqlob_methods); php_pqlob_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); @@ -5493,7 +5529,7 @@ static PHP_MINIT_FUNCTION(pq) php_pqlob_object_handlers.get_property_ptr_ptr = NULL; php_pqlob_object_handlers.get_debug_info = php_pq_object_debug_info; - zend_hash_init(&php_pqlob_object_prophandlers, 2, NULL, NULL, 1); + zend_hash_init(&php_pqlob_object_prophandlers, 3, NULL, NULL, 1); zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("transaction"), ZEND_ACC_PUBLIC TSRMLS_CC); ph.read = php_pqlob_object_read_transaction; @@ -5503,6 +5539,10 @@ static PHP_MINIT_FUNCTION(pq) ph.read = php_pqlob_object_read_oid; zend_hash_add(&php_pqlob_object_prophandlers, "oid", sizeof("oid"), (void *) &ph, sizeof(ph), NULL); + zend_declare_property_null(php_pqlob_class_entry, ZEND_STRL("stream"), ZEND_ACC_PUBLIC TSRMLS_CC); + ph.read = php_pqlob_object_read_stream; + zend_hash_add(&php_pqlob_object_prophandlers, "stream", sizeof("stream"), (void *) &ph, sizeof(ph), NULL); + zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("INVALID_OID"), InvalidOid TSRMLS_CC); zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("R"), INV_READ TSRMLS_CC); zend_declare_class_constant_long(php_pqlob_class_entry, ZEND_STRL("W"), INV_WRITE TSRMLS_CC);