X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-pq;a=blobdiff_plain;f=src%2Fphp_pq.c;h=a0d18a510023f7aa5944ad106f447ded84392ea6;hp=64d59af36d06f8f417fc6e33bf2ad986616981b4;hb=3024b0b5a903a2bcb082b01e1787410dc9508a9d;hpb=86e7a4a14c80824b25074743e1acae0c2f0fc0e8 diff --git a/src/php_pq.c b/src/php_pq.c index 64d59af..a0d18a5 100644 --- a/src/php_pq.c +++ b/src/php_pq.c @@ -18,9 +18,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -47,8 +49,12 @@ static int php_pqconn_event(PGEventId id, void *e, void *data); #define PHP_PQclear(_r) \ do { \ - zval *_resinszv = PQresultInstanceData((_r), php_pqconn_event); \ - if (!_resinszv) PQclear((_r)); \ + php_pqres_object_t *_o = PQresultInstanceData((_r), php_pqconn_event); \ + if (_o) { \ + php_pq_object_delref(_o TSRMLS_CC); \ + } else { \ + PQclear(_r); \ + } \ } while (0) /* @@ -86,6 +92,60 @@ static zend_class_entry *php_pqevent_class_entry; static zend_class_entry *php_pqlob_class_entry; static zend_class_entry *php_pqcopy_class_entry; +typedef enum php_pqexc_type { + EX_INVALID_ARGUMENT, + EX_RUNTIME, + EX_CONNECTION_FAILED, + EX_IO, + EX_ESCAPE, + EX_BAD_METHODCALL, + EX_UNINITIALIZED, + EX_DOMAIN, + EX_SQL +} php_pqexc_type_t; + +static zend_class_entry *php_pqexc_interface_class_entry; +static zend_class_entry *php_pqexc_invalid_argument_class_entry; +static zend_class_entry *php_pqexc_runtime_class_entry; +static zend_class_entry *php_pqexc_bad_methodcall_class_entry; +static zend_class_entry *php_pqexc_domain_class_entry; + +static zend_class_entry *exce(php_pqexc_type_t type) +{ + switch (type) { + default: + case EX_INVALID_ARGUMENT: + return php_pqexc_invalid_argument_class_entry; + case EX_RUNTIME: + case EX_CONNECTION_FAILED: + case EX_IO: + case EX_ESCAPE: + return php_pqexc_runtime_class_entry; + case EX_UNINITIALIZED: + case EX_BAD_METHODCALL: + return php_pqexc_bad_methodcall_class_entry; + case EX_DOMAIN: + case EX_SQL: + return php_pqexc_domain_class_entry; + } +} + +static zval *throw_exce(php_pqexc_type_t type TSRMLS_DC, const char *fmt, ...) +{ + char *msg; + zval *zexc; + va_list argv; + + va_start(argv, fmt); + vspprintf(&msg, 0, fmt, argv); + va_end(argv); + + zexc = zend_throw_exception(exce(type), msg, type TSRMLS_CC); + efree(msg); + + return zexc; +} + static zend_object_handlers php_pqconn_object_handlers; static zend_object_handlers php_pqtypes_object_handlers; static zend_object_handlers php_pqres_object_handlers; @@ -197,6 +257,7 @@ typedef struct php_pqtxn { php_pqconn_object_t *conn; php_pqtxn_isolation_t isolation; unsigned savepoint; + unsigned open:1; unsigned readonly:1; unsigned deferrable:1; } php_pqtxn_t; @@ -222,8 +283,8 @@ typedef struct php_pqcancel_object { typedef struct php_pqevent { php_pq_callback_t cb; - php_pqconn_object_t *conn; char *type; + ulong h; } php_pqevent_t; typedef struct php_pqevent_object { @@ -335,10 +396,14 @@ static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC) 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 (PQresultStatus(obj->intern->res) != PGRES_TUPLES_OK) { - return FAILURE; - } - if (PQntuples(obj->intern->res) <= iter->index) { + switch (PQresultStatus(obj->intern->res)) { + case PGRES_TUPLES_OK: + case PGRES_SINGLE_TUPLE: + if (PQntuples(obj->intern->res) <= iter->index) { + return FAILURE; + } + break; + default: return FAILURE; } @@ -458,27 +523,64 @@ static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC) { php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + return FAILURE; + } else { *count = (long) PQntuples(obj->intern->res); return SUCCESS; - } else { - return FAILURE; } } static STATUS php_pqres_success(PGresult *res TSRMLS_DC) { + zval *zexc; + switch (PQresultStatus(res)) { case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PHP_PQresultErrorMessage(res)); + zexc = throw_exce(EX_SQL TSRMLS_CC, "%s", PHP_PQresultErrorMessage(res)); + zend_update_property_string(php_pqexc_domain_class_entry, zexc, ZEND_STRL("sqlstate"), PQresultErrorField(res, PG_DIAG_SQLSTATE) TSRMLS_CC); return FAILURE; default: return SUCCESS; } } +/* +static void php_pqconn_del_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, ulong id TSRMLS_DC) +{ + zval **evhs; + + if (SUCCESS == zend_hash_find(&obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) { + zend_hash_index_del(Z_ARRVAL_PP(evhs), id); + } +} +*/ + +static ulong php_pqconn_add_eventhandler(php_pqconn_object_t *obj, const char *type_str, size_t type_len, zval *zevent TSRMLS_DC) +{ + zval **evhs; + ulong h; + + 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; + + 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); + } + + 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); @@ -512,6 +614,20 @@ static void php_pq_object_to_zval(void *o, zval **zv TSRMLS_DC) (*zv)->value.obj = obj->zv; } +static void php_pq_object_to_zval_no_addref(void *o, zval **zv TSRMLS_DC) +{ + php_pq_object_t *obj = o; + + if (!*zv) { + MAKE_STD_ZVAL(*zv); + } + + /* no add ref */ + + (*zv)->type = IS_OBJECT; + (*zv)->value.obj = obj->zv; +} + static void php_pq_object_addref(void *o TSRMLS_DC) { php_pq_object_t *obj = o; @@ -527,7 +643,9 @@ static void php_pq_object_delref(void *o TSRMLS_DC) static void php_pqconn_object_free(void *o TSRMLS_DC) { php_pqconn_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE conn(#%d) %p\n", obj->zv.handle, obj); +#endif if (obj->intern) { php_resource_factory_handle_dtor(&obj->intern->factory, obj->intern->conn TSRMLS_CC); php_resource_factory_dtor(&obj->intern->factory); @@ -544,7 +662,9 @@ static void php_pqconn_object_free(void *o TSRMLS_DC) static void php_pqtypes_object_free(void *o TSRMLS_DC) { php_pqtypes_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE types(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn); +#endif if (obj->intern) { zend_hash_destroy(&obj->intern->types); php_pq_object_delref(obj->intern->conn TSRMLS_CC); @@ -558,19 +678,14 @@ static void php_pqtypes_object_free(void *o TSRMLS_DC) static void php_pqres_object_free(void *o TSRMLS_DC) { php_pqres_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE res(#%d) %p\n", obj->zv.handle, obj); +#endif if (obj->intern) { if (obj->intern->res) { - zval *res = PQresultInstanceData(obj->intern->res, php_pqconn_event); - if (res) { - if (1 == Z_REFCOUNT_P(res)) { - PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL); - } - zval_ptr_dtor(&res); - } else { - PQclear(obj->intern->res); - obj->intern->res = NULL; - } + PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL); + PQclear(obj->intern->res); + obj->intern->res = NULL; } if (obj->intern->iter) { @@ -590,8 +705,29 @@ static void php_pqres_object_free(void *o TSRMLS_DC) static void php_pqstm_object_free(void *o TSRMLS_DC) { php_pqstm_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE stm(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn); +#endif if (obj->intern) { + char *quoted_name = PQescapeIdentifier(obj->intern->conn->intern->conn, obj->intern->name, strlen(obj->intern->name)); + + php_pq_callback_dtor(&obj->intern->conn->intern->onevent); + + if (quoted_name) { + PGresult *res; + smart_str cmd = {0}; + + smart_str_appends(&cmd, "DEALLOCATE "); + smart_str_appends(&cmd, quoted_name); + smart_str_0(&cmd); + PQfreemem(quoted_name); + + if ((res = PQexec(obj->intern->conn->intern->conn, cmd.c))) { + PHP_PQclear(res); + } + smart_str_free(&cmd); + } + php_pq_object_delref(obj->intern->conn TSRMLS_CC); efree(obj->intern->name); zend_hash_destroy(&obj->intern->bound); @@ -605,8 +741,17 @@ static void php_pqstm_object_free(void *o TSRMLS_DC) static void php_pqtxn_object_free(void *o TSRMLS_DC) { php_pqtxn_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE txn(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn); +#endif if (obj->intern) { + if (obj->intern->open) { + PGresult *res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK"); + + if (res) { + PHP_PQclear(res); + } + } php_pq_object_delref(obj->intern->conn TSRMLS_CC); efree(obj->intern); obj->intern = NULL; @@ -618,7 +763,9 @@ static void php_pqtxn_object_free(void *o TSRMLS_DC) static void php_pqcancel_object_free(void *o TSRMLS_DC) { php_pqcancel_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE cancel(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn); +#endif if (obj->intern) { PQfreeCancel(obj->intern->cancel); php_pq_object_delref(obj->intern->conn TSRMLS_CC); @@ -632,10 +779,11 @@ static void php_pqcancel_object_free(void *o TSRMLS_DC) 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); - php_pq_object_delref(obj->intern->conn TSRMLS_CC); efree(obj->intern->type); efree(obj->intern); obj->intern = NULL; @@ -647,7 +795,9 @@ static void php_pqevent_object_free(void *o TSRMLS_DC) static void php_pqlob_object_free(void *o TSRMLS_DC) { php_pqlob_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE lob(#%d) %p (txn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->txn->zv.handle, obj->intern->txn); +#endif if (obj->intern) { if (obj->intern->lofd) { lo_close(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd); @@ -663,7 +813,9 @@ static void php_pqlob_object_free(void *o TSRMLS_DC) static void php_pqcopy_object_free(void *o TSRMLS_DC) { php_pqcopy_object_t *obj = o; - +#if DBG_GC + fprintf(stderr, "FREE copy(#%d) %p (conn(#%d): %p)\n", obj->zv.handle, obj, obj->intern->conn->zv.handle, obj->intern->conn); +#endif if (obj->intern) { efree(obj->intern->expression); efree(obj->intern->options); @@ -927,36 +1079,16 @@ static zend_object_value php_pqcopy_create_object(zend_class_entry *class_type T return php_pqcopy_create_object_ex(class_type, NULL, NULL TSRMLS_CC); } -static int apply_ph_to_debug(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) -{ - php_pq_object_prophandler_t *ph = p; - HashTable *ht = va_arg(argv, HashTable *); - zval **return_value, *object = va_arg(argv, zval *); - php_pq_object_t *obj = va_arg(argv, php_pq_object_t *); - - if (SUCCESS == zend_hash_find(ht, key->arKey, key->nKeyLength, (void *) &return_value)) { - - if (ph->read) { - zval_ptr_dtor(return_value); - MAKE_STD_ZVAL(*return_value); - ZVAL_NULL(*return_value); - - ph->read(object, obj, *return_value TSRMLS_CC); - } - } - - return ZEND_HASH_APPLY_KEEP; -} - -static int apply_pi_to_debug(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +static int apply_pi_to_ht(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) { zend_property_info *pi = p; HashTable *ht = va_arg(argv, HashTable *); zval *object = va_arg(argv, zval *); php_pq_object_t *obj = va_arg(argv, php_pq_object_t *); + int addref = va_arg(argv, int); zval *property = zend_read_property(obj->zo.ce, object, pi->name, pi->name_length, 0 TSRMLS_CC); - if (1||!Z_REFCOUNT_P(property)) { + if (addref) { Z_ADDREF_P(property); } zend_hash_add(ht, pi->name, pi->name_length + 1, (void *) &property, sizeof(zval *), NULL); @@ -973,8 +1105,7 @@ static HashTable *php_pq_object_debug_info(zval *object, int *temp TSRMLS_DC) ALLOC_HASHTABLE(ht); ZEND_INIT_SYMTABLE(ht); - zend_hash_apply_with_arguments(&obj->zo.ce->properties_info TSRMLS_CC, apply_pi_to_debug, 3, ht, object, obj); - zend_hash_apply_with_arguments(obj->prophandler TSRMLS_CC, apply_ph_to_debug, 3, ht, object, obj); + zend_hash_apply_with_arguments(&obj->zo.ce->properties_info TSRMLS_CC, apply_pi_to_ht, 4, ht, object, obj, 1); return ht; } @@ -1070,7 +1201,15 @@ static void php_pqconn_object_write_encoding(zval *object, void *o, zval *value zval *zenc = value; if (Z_TYPE_P(value) != IS_STRING) { - convert_to_string_ex(&zenc); + if (Z_REFCOUNT_P(value) > 1) { + zval *tmp; + MAKE_STD_ZVAL(tmp); + ZVAL_ZVAL(tmp, zenc, 1, 0); + convert_to_string(tmp); + zenc = tmp; + } else { + convert_to_string_ex(&zenc); + } } if (0 > PQsetClientEncoding(obj->intern->conn, Z_STRVAL_P(zenc))) { @@ -1096,7 +1235,7 @@ static void php_pqconn_object_write_unbuffered(zval *object, void *o, zval *valu obj->intern->unbuffered = zend_is_true(value); } -static void php_pqconn_object_read_db(zval *objec, void *o, zval *return_value TSRMLS_DC) +static void php_pqconn_object_read_db(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; char *db = PQdb(obj->intern->conn); @@ -1108,7 +1247,7 @@ static void php_pqconn_object_read_db(zval *objec, void *o, zval *return_value T } } -static void php_pqconn_object_read_user(zval *objec, void *o, zval *return_value TSRMLS_DC) +static void php_pqconn_object_read_user(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; char *user = PQuser(obj->intern->conn); @@ -1120,7 +1259,7 @@ static void php_pqconn_object_read_user(zval *objec, void *o, zval *return_value } } -static void php_pqconn_object_read_pass(zval *objec, void *o, zval *return_value TSRMLS_DC) +static void php_pqconn_object_read_pass(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; char *pass = PQpass(obj->intern->conn); @@ -1132,7 +1271,7 @@ static void php_pqconn_object_read_pass(zval *objec, void *o, zval *return_value } } -static void php_pqconn_object_read_host(zval *objec, void *o, zval *return_value TSRMLS_DC) +static void php_pqconn_object_read_host(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; char *host = PQhost(obj->intern->conn); @@ -1144,7 +1283,7 @@ static void php_pqconn_object_read_host(zval *objec, void *o, zval *return_value } } -static void php_pqconn_object_read_port(zval *objec, void *o, zval *return_value TSRMLS_DC) +static void php_pqconn_object_read_port(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; char *port = PQport(obj->intern->conn); @@ -1156,7 +1295,7 @@ static void php_pqconn_object_read_port(zval *objec, void *o, zval *return_value } } -static void php_pqconn_object_read_options(zval *objec, void *o, zval *return_value TSRMLS_DC) +static void php_pqconn_object_read_options(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqconn_object_t *obj = o; char *options = PQoptions(obj->intern->conn); @@ -1168,6 +1307,14 @@ static void php_pqconn_object_read_options(zval *objec, void *o, zval *return_va } } +static void php_pqconn_object_read_event_handlers(zval *object, void *o, zval *return_value TSRMLS_DC) +{ + php_pqconn_object_t *obj = o; + + array_init(return_value); + zend_hash_copy(Z_ARRVAL_P(return_value), &obj->intern->eventhandlers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); +} + static void php_pqtypes_object_read_connection(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqtypes_object_t *obj = o; @@ -1175,7 +1322,7 @@ static void php_pqtypes_object_read_connection(zval *object, void *o, zval *retu php_pq_object_to_zval(obj->intern->conn, &return_value TSRMLS_CC); } -static int has_dimension(HashTable *ht, zval *member, char **key_str, int *key_len, long *index TSRMLS_DC) +static int has_dimension(HashTable *ht, zval *member, char **key_str, int *key_len, ulong *index TSRMLS_DC) { long lval = 0; zval *tmp = member; @@ -1186,18 +1333,21 @@ static int has_dimension(HashTable *ht, zval *member, char **key_str, int *key_l /* no break */ case IS_STRING: if (!is_numeric_string(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &lval, NULL, 0)) { - if (member != tmp) { - zval_ptr_dtor(&tmp); - } + int exists = zend_hash_exists(ht, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp) + 1); + if (key_str) { *key_str = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); if (key_len) { *key_len = Z_STRLEN_P(tmp) + 1; } } - return zend_hash_exists(ht, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp) + 1); + if (member != tmp) { + zval_ptr_dtor(&tmp); + } + + return exists; } - /* no break */ + break; case IS_LONG: lval = Z_LVAL_P(member); break; @@ -1217,7 +1367,7 @@ static int php_pqtypes_object_has_dimension(zval *object, zval *member, int chec php_pqtypes_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); char *key_str = NULL; int key_len = 0; - long index = 0; + ulong index = 0; if (check_empty) { if (has_dimension(&obj->intern->types, member, &key_str, &key_len, &index TSRMLS_CC)) { @@ -1230,11 +1380,14 @@ static int php_pqtypes_object_has_dimension(zval *object, zval *member, int chec } efree(key_str); } else { - if (SUCCESS == zend_hash_index_find(&obj->intern->types, index, (void *) data)) { + if (SUCCESS == zend_hash_index_find(&obj->intern->types, index, (void *) &data)) { return Z_TYPE_PP(data) != IS_NULL; } } } + if (key_str) { + efree(key_str); + } } else { return has_dimension(&obj->intern->types, member, NULL, NULL, NULL TSRMLS_CC); } @@ -1244,7 +1397,7 @@ static int php_pqtypes_object_has_dimension(zval *object, zval *member, int chec static zval *php_pqtypes_object_read_dimension(zval *object, zval *member, int type TSRMLS_DC) { - long index = 0; + ulong index = 0; char *key_str = NULL; int key_len = 0; php_pqtypes_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); @@ -1262,6 +1415,9 @@ static zval *php_pqtypes_object_read_dimension(zval *object, zval *member, int t return *data; } } + if (key_str) { + efree(key_str); + } } return NULL; @@ -1274,6 +1430,13 @@ static void php_pqres_object_read_status(zval *object, void *o, zval *return_val RETVAL_LONG(PQresultStatus(obj->intern->res)); } +static void php_pqres_object_read_status_message(zval *object, void *o, zval *return_value TSRMLS_DC) +{ + php_pqres_object_t *obj = o; + + RETVAL_STRING(PQresStatus(PQresultStatus(obj->intern->res))+sizeof("PGRES"), 1); +} + static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqres_object_t *obj = o; @@ -1323,8 +1486,16 @@ static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value php_pqres_object_t *obj = o; zval *zfetch_type = value; - if (Z_TYPE_P(zfetch_type) != IS_LONG) { - convert_to_long_ex(&zfetch_type); + if (Z_TYPE_P(value) != IS_LONG) { + if (Z_REFCOUNT_P(value) > 1) { + zval *tmp; + MAKE_STD_ZVAL(tmp); + ZVAL_ZVAL(tmp, zfetch_type, 1, 0); + convert_to_long(tmp); + zfetch_type = tmp; + } else { + convert_to_long_ex(&zfetch_type); + } } if (!obj->intern->iter) { @@ -1370,14 +1541,14 @@ static void php_pqtxn_object_read_readonly(zval *object, void *o, zval *return_v { php_pqtxn_object_t *obj = o; - RETVAL_LONG(obj->intern->readonly); + RETVAL_BOOL(obj->intern->readonly); } static void php_pqtxn_object_read_deferrable(zval *object, void *o, zval *return_value TSRMLS_DC) { php_pqtxn_object_t *obj = o; - RETVAL_LONG(obj->intern->deferrable); + RETVAL_BOOL(obj->intern->deferrable); } static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value TSRMLS_DC) @@ -1388,18 +1559,26 @@ static void php_pqtxn_object_write_isolation(zval *object, void *o, zval *value PGresult *res; if (Z_TYPE_P(zisolation) != IS_LONG) { - convert_to_long_ex(&zisolation); + if (Z_REFCOUNT_P(value) > 1) { + zval *tmp; + MAKE_STD_ZVAL(tmp); + ZVAL_ZVAL(tmp, zisolation, 1, 0); + convert_to_long(tmp); + zisolation = tmp; + } else { + convert_to_long_ex(&zisolation); + } } switch ((obj->intern->isolation = Z_LVAL_P(zisolation))) { case PHP_PQTXN_READ_COMMITTED: - res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION READ COMMITED"); + res = PQexec(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 REPEATABLE READ"); + res = PQexec(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 SERIALIZABLE"); + res = PQexec(obj->intern->conn->intern->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); break; default: obj->intern->isolation = orig; @@ -1458,13 +1637,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_connection(zval *object, void *o, zval *return_value TSRMLS_DC) -{ - php_pqevent_object_t *obj = o; - - 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; @@ -1635,24 +1807,20 @@ static void php_pqconn_event_connreset(PGEventConnReset *event) } } -static zval *result_instance_zval(PGresult *res TSRMLS_DC) +static void php_pqres_init_instance_data(PGresult *res, php_pqres_object_t **ptr TSRMLS_DC) { - zval *rid = PQresultInstanceData(res, php_pqconn_event); + php_pqres_object_t *obj; + php_pqres_t *r = ecalloc(1, sizeof(*r)); - if (!rid) { - php_pqres_t *r = ecalloc(1, sizeof(*r)); + r->res = res; + ZEND_INIT_SYMTABLE(&r->bound); + php_pqres_create_object_ex(php_pqres_class_entry, r, &obj TSRMLS_CC); - MAKE_STD_ZVAL(rid); - r->res = res; - ZEND_INIT_SYMTABLE(&r->bound); - rid->type = IS_OBJECT; - rid->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC); + PQresultSetInstanceData(res, php_pqconn_event, obj); - PQresultSetInstanceData(res, php_pqconn_event, rid); + if (ptr) { + *ptr = obj; } - - Z_ADDREF_P(rid); - return rid; } static void php_pqconn_event_resultcreate(PGEventResultCreate *event) @@ -1660,17 +1828,21 @@ static void php_pqconn_event_resultcreate(PGEventResultCreate *event) php_pqconn_event_data_t *data = PQinstanceData(event->conn, php_pqconn_event); if (data) { + php_pqres_object_t *obj; zval **evhs; TSRMLS_DF(data); + php_pqres_init_instance_data(event->result, &obj TSRMLS_CC); + /* event listener */ if (SUCCESS == zend_hash_find(&data->obj->intern->eventhandlers, ZEND_STRS("result"), (void *) &evhs)) { - zval *args, *connection = NULL, *res = result_instance_zval(event->result TSRMLS_CC); + zval *args, *connection = NULL, *res = NULL; MAKE_STD_ZVAL(args); array_init(args); php_pq_object_to_zval(data->obj, &connection TSRMLS_CC); 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); zval_ptr_dtor(&args); @@ -1678,12 +1850,23 @@ static void php_pqconn_event_resultcreate(PGEventResultCreate *event) /* async callback */ if (data->obj->intern->onevent.fci.size > 0) { - zval *res = result_instance_zval(event->result TSRMLS_CC); + zval *res = NULL; + php_pq_object_to_zval(obj, &res TSRMLS_CC); zend_fcall_info_argn(&data->obj->intern->onevent.fci TSRMLS_CC, 1, &res); zend_fcall_info_call(&data->obj->intern->onevent.fci, &data->obj->intern->onevent.fcc, NULL, NULL TSRMLS_CC); zval_ptr_dtor(&res); } + + } +} + +static void php_pqconn_event_resultdestroy(PGEventResultDestroy *event) +{ + php_pqres_object_t *obj = PQresultInstanceData(event->result, php_pqconn_event); + + if (obj) { + obj->intern->res = NULL; } } @@ -1696,6 +1879,9 @@ static int php_pqconn_event(PGEventId id, void *e, void *data) case PGEVT_RESULTCREATE: php_pqconn_event_resultcreate(e); break; + case PGEVT_RESULTDESTROY: + php_pqconn_event_resultdestroy(e); + break; default: break; } @@ -1762,7 +1948,7 @@ static void php_pqconn_resource_factory_dtor(void *opaque, void *handle TSRMLS_D { php_pqconn_event_data_t *evdata = PQinstanceData(handle, php_pqconn_event); - /* we don't care for anthing, except free'ing evdata */ + /* we don't care for anything, except free'ing evdata */ if (evdata) { PQsetInstanceData(handle, php_pqconn_event, NULL); memset(evdata, 0, sizeof(*evdata)); @@ -1780,6 +1966,7 @@ static php_resource_factory_ops_t php_pqconn_resource_factory_ops = { static void php_pqconn_wakeup(php_persistent_handle_factory_t *f, void **handle TSRMLS_DC) { + // FIXME: ping server } static int apply_unlisten(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) @@ -1821,7 +2008,9 @@ static void php_pqconn_retire(php_persistent_handle_factory_t *f, void **handle /* cancel async queries */ if (PQisBusy(*handle) && (cancel = PQgetCancel(*handle))) { - PQcancel(cancel, ZEND_STRL("retiring persistent connection")); + char err[256] = {0}; + + PQcancel(cancel, err, sizeof(err)); PQfreeCancel(cancel); } /* clean up async results */ @@ -1862,77 +2051,100 @@ static PHP_METHOD(pqconn, __construct) { char *dsn_str = ""; int dsn_len = 0; long flags = 0; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &dsn_str, &dsn_len, &flags); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &dsn_str, &dsn_len, &flags)) { + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj TSRMLS_CC); - php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags}; - obj->intern = ecalloc(1, sizeof(*obj->intern)); + if (obj->intern) { + throw_exce(EX_BAD_METHODCALL TSRMLS_CC, "pq\\Connection already initialized"); + } else { + php_pqconn_event_data_t *evdata = php_pqconn_event_data_init(obj TSRMLS_CC); + php_pqconn_resource_factory_data_t rfdata = {dsn_str, flags}; + + 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->listeners, 0, NULL, (dtor_func_t) zend_hash_destroy, 0); + zend_hash_init(&obj->intern->eventhandlers, 0, NULL, ZVAL_PTR_DTOR, 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); - php_resource_factory_init(&obj->intern->factory, php_persistent_handle_get_resource_factory_ops(), phf, (void (*)(void*)) php_persistent_handle_abandon); - } else { - php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL); - } + 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); + php_resource_factory_init(&obj->intern->factory, php_persistent_handle_get_resource_factory_ops(), phf, (void (*)(void*)) php_persistent_handle_abandon); + } else { + php_resource_factory_init(&obj->intern->factory, &php_pqconn_resource_factory_ops, NULL, NULL); + } - if (flags & PHP_PQCONN_ASYNC) { - obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll; - } + if (flags & PHP_PQCONN_ASYNC) { + obj->intern->poller = (int (*)(PGconn*)) PQconnectPoll; + } - obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata TSRMLS_CC); + obj->intern->conn = php_resource_factory_handle_ctor(&obj->intern->factory, &rfdata TSRMLS_CC); - PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata); - PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata); + PQsetInstanceData(obj->intern->conn, php_pqconn_event, evdata); + PQsetNoticeReceiver(obj->intern->conn, php_pqconn_notice_recv, evdata); - if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn)); + if (SUCCESS != php_pqconn_update_socket(getThis(), obj TSRMLS_CC)) { + throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection failed (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, reset) { - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { PQreset(obj->intern->conn); - if (CONNECTION_OK == PQstatus(obj->intern->conn)) { - RETURN_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn)); + if (CONNECTION_OK != PQstatus(obj->intern->conn)) { + throw_exce(EX_CONNECTION_FAILED TSRMLS_CC, "Connection reset failed: (%s)", PHP_PQerrorMessage(obj->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + + php_pqconn_notify_listeners(obj TSRMLS_CC); } - RETURN_FALSE; } } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_reset_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, resetAsync) { - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (PQresetStart(obj->intern->conn)) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { + if (!PQresetStart(obj->intern->conn)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to start connection reset (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else { obj->intern->poller = (int (*)(PGconn*)) PQresetPoll; - RETURN_TRUE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + + php_pqconn_notify_listeners(obj TSRMLS_CC); } - RETURN_FALSE; } } @@ -1956,48 +2168,51 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen, 0, 0, 0) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, listen) { + zend_error_handling zeh; char *channel_str = NULL; int channel_len = 0; php_pq_callback_t listener; + STATUS rv; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc)) { - php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc); + zend_restore_error_handling(&zeh TSRMLS_CC); - obj->intern->poller = PQconsumeInput; + if (SUCCESS == rv) { + php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len); - if (quoted_channel) { + if (!quoted_channel) { + throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else { PGresult *res; - char *cmd; + smart_str cmd = {0}; - spprintf(&cmd, 0, "LISTEN %s", quoted_channel); - res = PQexec(obj->intern->conn, cmd); + smart_str_appends(&cmd, "LISTEN "); + smart_str_appends(&cmd, quoted_channel); + smart_str_0(&cmd); - efree(cmd); + res = PQexec(obj->intern->conn, cmd.c); + + smart_str_free(&cmd); PQfreemem(quoted_channel); - if (res) { + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else { if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { + obj->intern->poller = PQconsumeInput; php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC); - RETVAL_TRUE; - } else { - RETVAL_FALSE; } PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not install listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; } php_pqconn_notify_listeners(obj TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2007,42 +2222,44 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_listen_async, 0, 0, 0) ZEND_ARG_INFO(0, callable) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, listenAsync) { + zend_error_handling zeh; char *channel_str = NULL; int channel_len = 0; php_pq_callback_t listener; + STATUS rv; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc)) { - php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sf", &channel_str, &channel_len, &listener.fci, &listener.fcc); + zend_restore_error_handling(&zeh TSRMLS_CC); - obj->intern->poller = PQconsumeInput; + if (SUCCESS == rv) { + php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { char *quoted_channel = PQescapeIdentifier(obj->intern->conn, channel_str, channel_len); - if (quoted_channel) { - char *cmd; + if (!quoted_channel) { + throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else { + smart_str cmd = {0}; - obj->intern->poller = PQconsumeInput; + smart_str_appends(&cmd, "LISTEN "); + smart_str_appends(&cmd, quoted_channel); + smart_str_0(&cmd); - spprintf(&cmd, 0, "LISTEN %s", channel_str); - if (PQsendQuery(obj->intern->conn, cmd)) { - php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC); - RETVAL_TRUE; + if (!PQsendQuery(obj->intern->conn, cmd.c)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to install listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not install listener (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; + obj->intern->poller = PQconsumeInput; + php_pqconn_add_listener(obj, channel_str, channel_len, &listener TSRMLS_CC); } - efree(cmd); + smart_str_free(&cmd); PQfreemem(quoted_channel); - php_pqconn_notify_listeners(obj TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape channel identifier (%s)", PHP_PQerrorMessage(obj->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2052,35 +2269,34 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify, 0, 0, 2) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, notify) { + zend_error_handling zeh; char *channel_str, *message_str; int channel_len, message_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len)) { + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { PGresult *res; char *params[2] = {channel_str, message_str}; res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0); - if (res) { - if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { - RETVAL_TRUE; - } else { - RETVAL_FALSE; - } - PHP_PQclear(res); + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; + php_pqres_success(res TSRMLS_CC); + PHP_PQclear(res); } php_pqconn_notify_listeners(obj TSRMLS_CC); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2090,29 +2306,30 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_notify_async, 0, 0, 2) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, notifyAsync) { + zend_error_handling zeh; char *channel_str, *message_str; int channel_len, message_len; + STATUS rv; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_len)) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &channel_str, &channel_len, &message_str, &message_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) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { char *params[2] = {channel_str, message_str}; - obj->intern->poller = PQconsumeInput; - - if (PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) { - RETVAL_TRUE; + if (!PQsendQueryParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; + obj->intern->poller = PQconsumeInput; } php_pqconn_notify_listeners(obj TSRMLS_CC); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2120,25 +2337,28 @@ static PHP_METHOD(pqconn, notifyAsync) { ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_poll, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, poll) { - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (obj->intern->poller) { - if (obj->intern->poller == PQconsumeInput) { - RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK); - php_pqconn_notify_listeners(obj TSRMLS_CC); - return; - } else { - RETURN_LONG(obj->intern->poller(obj->intern->conn)); - } + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else if (!obj->intern->poller) { + throw_exce(EX_RUNTIME TSRMLS_CC, "No asynchronous operation active"); + } else { + if (obj->intern->poller == PQconsumeInput) { + RETVAL_LONG(obj->intern->poller(obj->intern->conn) * PGRES_POLLING_OK); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "No asynchronous operation active"); + RETVAL_LONG(obj->intern->poller(obj->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + php_pqconn_notify_listeners(obj TSRMLS_CC); } - RETURN_FALSE; } } @@ -2149,57 +2369,58 @@ static PHP_METHOD(pqconn, exec) { zend_error_handling zeh; char *query_str; int query_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query_str, &query_len)) { + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { PGresult *res = PQexec(obj->intern->conn, query_str); - php_pqconn_notify_listeners(obj TSRMLS_CC); - - if (res) { - if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { - php_pqres_t *r = ecalloc(1, sizeof(*r)); - - r->res = res; - ZEND_INIT_SYMTABLE(&r->bound); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC); - } + 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_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); + PHP_PQclear(res); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + + php_pqconn_notify_listeners(obj TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_get_result, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqconn, getResult) { - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connectio not initialized"); + } else { PGresult *res = PQgetResult(obj->intern->conn); - if (res) { - php_pqres_t *r = ecalloc(1, sizeof(*r)); - - r->res = res; - ZEND_INIT_SYMTABLE(&r->bound); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC); - } else { + if (!res) { RETVAL_NULL(); + } else { + php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; + + php_pqconn_notify_listeners(obj TSRMLS_CC); } } } @@ -2213,37 +2434,31 @@ static PHP_METHOD(pqconn, execAsync) { php_pq_callback_t resolver = {{0}}; char *query_str; int query_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f", &query_str, &query_len, &resolver.fci, &resolver.fcc)) { + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else if (!PQsendQuery(obj->intern->conn, query_str)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else { + obj->intern->poller = PQconsumeInput; php_pq_callback_dtor(&obj->intern->onevent); if (resolver.fci.size > 0) { obj->intern->onevent = resolver; php_pq_callback_addref(&obj->intern->onevent); } - - obj->intern->poller = PQconsumeInput; - - if (PQsendQuery(obj->intern->conn, query_str)) { - if (obj->intern->unbuffered) { - if (!PQsetSingleRowMode(obj->intern->conn)) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); - } - } - RETVAL_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; - } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; + php_pqconn_notify_listeners(obj TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } static int apply_to_oid(void *p, void *arg TSRMLS_DC) @@ -2354,12 +2569,18 @@ static PHP_METHOD(pqconn, execParams) { int query_len; zval *zparams; zval *ztypes = NULL; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes)) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!", &query_str, &query_len, &zparams, &ztypes); + 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) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { PGresult *res; int count; Oid *types = NULL; @@ -2383,27 +2604,19 @@ static PHP_METHOD(pqconn, execParams) { efree(params); } - php_pqconn_notify_listeners(obj TSRMLS_CC); - - if (res) { + 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_pqres_t *r = ecalloc(1, sizeof(*r)); - - r->res = res; - ZEND_INIT_SYMTABLE(&r->bound); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC); + php_pq_object_to_zval_no_addref(PQresultInstanceData(res, php_pqconn_event), &return_value TSRMLS_CC); + } else { + PHP_PQclear(res); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; + + php_pqconn_notify_listeners(obj TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_exec_params_async, 0, 0, 2) @@ -2419,12 +2632,18 @@ static PHP_METHOD(pqconn, execParamsAsync) { int query_len; zval *zparams; zval *ztypes = NULL; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.fcc)) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|a/!f", &query_str, &query_len, &zparams, &ztypes, &resolver.fci, &resolver.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) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { int count; Oid *types = NULL; char **params = NULL; @@ -2437,24 +2656,18 @@ static PHP_METHOD(pqconn, execParamsAsync) { php_pq_types_to_array(Z_ARRVAL_P(ztypes), &types TSRMLS_CC); } - php_pq_callback_dtor(&obj->intern->onevent); - if (resolver.fci.size > 0) { - obj->intern->onevent = resolver; - php_pq_callback_addref(&obj->intern->onevent); - } - - obj->intern->poller = PQconsumeInput; - - if (PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) { - if (obj->intern->unbuffered) { - if (!PQsetSingleRowMode(obj->intern->conn)) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); - } - } - RETVAL_TRUE; + if (!PQsendQueryParams(obj->intern->conn, query_str, count, types, (const char *const*) params, NULL, NULL, 0)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute query (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; + obj->intern->poller = PQconsumeInput; + php_pq_callback_dtor(&obj->intern->onevent); + if (resolver.fci.size > 0) { + obj->intern->onevent = resolver; + php_pq_callback_addref(&obj->intern->onevent); + } + php_pqconn_notify_listeners(obj TSRMLS_CC); } zend_hash_destroy(&zdtor); @@ -2464,12 +2677,6 @@ static PHP_METHOD(pqconn, execParamsAsync) { if (params) { efree(params); } - - php_pqconn_notify_listeners(obj TSRMLS_CC); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } zend_restore_error_handling(&zeh TSRMLS_CC); @@ -2497,12 +2704,13 @@ static STATUS php_pqconn_prepare(zval *object, php_pqconn_object_t *obj, const c efree(types); } - if (res) { + 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); - } else { - rv = FAILURE; - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); + php_pqconn_notify_listeners(obj TSRMLS_CC); } return rv; @@ -2518,29 +2726,29 @@ static PHP_METHOD(pqconn, prepare) { zval *ztypes = NULL; char *name_str, *query_str; int name_len, *query_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) { + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) { - php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else if (SUCCESS == php_pqconn_prepare(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) { + php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); - php_pq_object_addref(obj TSRMLS_CC); - stm->conn = obj; - stm->name = estrdup(name_str); - ZEND_INIT_SYMTABLE(&stm->bound); + php_pq_object_addref(obj TSRMLS_CC); + stm->conn = obj; + stm->name = estrdup(name_str); + ZEND_INIT_SYMTABLE(&stm->bound); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); - } - php_pqconn_notify_listeners(obj TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + return_value->type = IS_OBJECT; + return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } static STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, const char *name, const char *query, HashTable *typest TSRMLS_DC) @@ -2557,16 +2765,16 @@ static STATUS php_pqconn_prepare_async(zval *object, php_pqconn_object_t *obj, c count = php_pq_types_to_array(typest, &types TSRMLS_CC); } - if (PQsendPrepare(obj->intern->conn, name, query, count, types)) { - if (obj->intern->unbuffered) { - if (!PQsetSingleRowMode(obj->intern->conn)) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn)); - } - } - rv = SUCCESS; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); + if (!PQsendPrepare(obj->intern->conn, name, query, count, types)) { rv = FAILURE; + throw_exce(EX_IO TSRMLS_CC, "Failed to prepare statement (%s)", PHP_PQerrorMessage(obj->intern->conn)); + } else if (obj->intern->unbuffered && !PQsetSingleRowMode(obj->intern->conn)) { + 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); } if (types) { @@ -2586,30 +2794,29 @@ static PHP_METHOD(pqconn, prepareAsync) { zval *ztypes = NULL; char *name_str, *query_str; int name_len, *query_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!", &name_str, &name_len, &query_str, &query_len, &ztypes)) { + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - obj->intern->poller = PQconsumeInput; - if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) { - php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else if (SUCCESS == php_pqconn_prepare_async(getThis(), obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC)) { + php_pqstm_t *stm = ecalloc(1, sizeof(*stm)); - php_pq_object_addref(obj TSRMLS_CC); - stm->conn = obj; - stm->name = estrdup(name_str); - ZEND_INIT_SYMTABLE(&stm->bound); + php_pq_object_addref(obj TSRMLS_CC); + stm->conn = obj; + stm->name = estrdup(name_str); + ZEND_INIT_SYMTABLE(&stm->bound); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); - } - php_pqconn_notify_listeners(obj TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + return_value->type = IS_OBJECT; + return_value->value.obj = php_pqstm_create_object_ex(php_pqstm_class_entry, stm, NULL TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_quote, 0, 0, 1) @@ -2622,19 +2829,18 @@ static PHP_METHOD(pqconn, quote) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { char *quoted = PQescapeLiteral(obj->intern->conn, str, len); - if (quoted) { + if (!quoted) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote string (%s)", PHP_PQerrorMessage(obj->intern->conn)); + RETVAL_FALSE; + } else { RETVAL_STRING(quoted, 1); PQfreemem(quoted); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote string (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2649,19 +2855,18 @@ static PHP_METHOD(pqconn, quoteName) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { char *quoted = PQescapeIdentifier(obj->intern->conn, str, len); - if (quoted) { + if (!quoted) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote name (%s)", PHP_PQerrorMessage(obj->intern->conn)); + RETVAL_FALSE; + } else { RETVAL_STRING(quoted, 1); PQfreemem(quoted); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not quote name (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2676,20 +2881,19 @@ static PHP_METHOD(pqconn, escapeBytea) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { size_t escaped_len; char *escaped_str = (char *) PQescapeByteaConn(obj->intern->conn, (unsigned char *) str, len, &escaped_len); - if (escaped_str) { + if (!escaped_str) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn)); + RETVAL_FALSE; + } else { RETVAL_STRINGL(escaped_str, escaped_len - 1, 1); PQfreemem(escaped_str); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not escape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2704,20 +2908,19 @@ static PHP_METHOD(pqconn, unescapeBytea) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len)) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { size_t unescaped_len; char *unescaped_str = (char *) PQunescapeBytea((unsigned char *)str, &unescaped_len); - if (unescaped_str) { + if (!unescaped_str) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn)); + RETVAL_FALSE; + } else { RETVAL_STRINGL(unescaped_str, unescaped_len, 1); PQfreemem(unescaped_str); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not unescape bytea (%s)", PHP_PQerrorMessage(obj->intern->conn)); - RETVAL_FALSE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2738,61 +2941,79 @@ static const char *isolation_level(long *isolation) { static STATUS php_pqconn_start_transaction(zval *zconn, php_pqconn_object_t *conn_obj, long isolation, zend_bool readonly, zend_bool deferrable TSRMLS_DC) { + STATUS rv = FAILURE; + if (!conn_obj) { conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); } - if (conn_obj->intern) { + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { PGresult *res; - char *cmd; - - spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE", - isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT"); - - res = PQexec(conn_obj->intern->conn, cmd); - - efree(cmd); - - if (res) { - STATUS rv = php_pqres_success(res TSRMLS_CC); - - PHP_PQclear(res); - return rv; + smart_str cmd = {0}; + const char *il = isolation_level(&isolation); + + smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL "); + smart_str_appends(&cmd, il); + smart_str_appends(&cmd, ", READ "); + smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE"); + smart_str_appends(&cmd, ","); + smart_str_appends(&cmd, deferrable ? "" : " NOT"); + smart_str_appends(&cmd, " DEFERRABLE"); + smart_str_0(&cmd); + + res = PQexec(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 { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); - return FAILURE; + rv = php_pqres_success(res TSRMLS_CC); + PHP_PQclear(res); + php_pqconn_notify_listeners(conn_obj TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - return FAILURE; + + smart_str_free(&cmd); } + + return rv; } static 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 rv = FAILURE; + if (!conn_obj) { conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); } - if (conn_obj->intern->conn) { - char *cmd; - - spprintf(&cmd, 0, "START TRANSACTION ISOLATION LEVEL %s, READ %s, %s DEFERRABLE", - isolation_level(&isolation), readonly ? "ONLY" : "WRITE", deferrable ? "": "NOT"); - - if (PQsendQuery(conn_obj->intern->conn, cmd)) { - conn_obj->intern->poller = PQconsumeInput; - efree(cmd); - return SUCCESS; + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { + smart_str cmd = {0}; + const char *il = isolation_level(&isolation); + + smart_str_appends(&cmd, "START TRANSACTION ISOLATION LEVEL "); + smart_str_appends(&cmd, il); + smart_str_appends(&cmd, ", READ "); + smart_str_appends(&cmd, readonly ? "ONLY" : "WRITE"); + smart_str_appends(&cmd, ","); + smart_str_appends(&cmd, deferrable ? "" : "NOT "); + smart_str_appends(&cmd, " DEFERRABLE"); + smart_str_0(&cmd); + + if (!PQsendQuery(conn_obj->intern->conn, cmd.c)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } else { - efree(cmd); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not start transaction (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); - return FAILURE; + rv = SUCCESS; + conn_obj->intern->poller = PQconsumeInput; + php_pqconn_notify_listeners(conn_obj TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - return FAILURE; + + smart_str_free(&cmd); } + + return rv; } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction, 0, 0, 0) @@ -2804,10 +3025,13 @@ static PHP_METHOD(pqconn, startTransaction) { zend_error_handling zeh; long isolation = PHP_PQTXN_READ_COMMITTED; zend_bool readonly = 0, deferrable = 0; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) { - STATUS rv; + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); rv = php_pqconn_start_transaction(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC); @@ -2817,6 +3041,7 @@ static PHP_METHOD(pqconn, startTransaction) { php_pq_object_addref(obj TSRMLS_CC); txn->conn = obj; + txn->open = 1; txn->isolation = isolation; txn->readonly = readonly; txn->deferrable = deferrable; @@ -2825,10 +3050,8 @@ static PHP_METHOD(pqconn, startTransaction) { return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } - ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_start_transaction_async, 0, 0, 0) ZEND_ARG_INFO(0, isolation) ZEND_ARG_INFO(0, readonly) @@ -2838,10 +3061,12 @@ static PHP_METHOD(pqconn, startTransactionAsync) { zend_error_handling zeh; long isolation = PHP_PQTXN_READ_COMMITTED; zend_bool readonly = 0, deferrable = 0; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable)) { - STATUS rv; + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lbb", &isolation, &readonly, &deferrable); + zend_restore_error_handling(&zeh TSRMLS_CC); + if (SUCCESS == rv) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); rv = php_pqconn_start_transaction_async(getThis(), obj, isolation, readonly, deferrable TSRMLS_CC); @@ -2859,7 +3084,6 @@ static PHP_METHOD(pqconn, startTransactionAsync) { return_value->value.obj = php_pqtxn_create_object_ex(php_pqtxn_class_entry, txn, NULL TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqconn_trace, 0, 0, 0) @@ -2870,27 +3094,27 @@ static PHP_METHOD(pqconn, trace) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r!", &zstream)) { php_pqconn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (zstream) { + + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { + if (!zstream) { + PQuntrace(obj->intern->conn); + RETVAL_TRUE; + } else { FILE *fp; php_stream *stream = NULL; php_stream_from_zval(stream, &zstream); - if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) { + if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS)) { + RETVAL_FALSE; + } else { stream->flags |= PHP_STREAM_FLAG_NO_CLOSE; PQtrace(obj->intern->conn, fp); RETVAL_TRUE; - } else { - RETVAL_FALSE; } - } else { - PQuntrace(obj->intern->conn); - RETVAL_TRUE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; } } } @@ -2928,14 +3152,20 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqtypes, __construct) { zend_error_handling zeh; zval *zconn, *znsp = NULL; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a!", &zconn, php_pqconn_class_entry, &znsp); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a!", &zconn, php_pqconn_class_entry, &znsp)) { + if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); - if (conn_obj->intern) { - zval *retval = NULL; + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { php_pqtypes_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zval *retval = NULL; obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->conn = conn_obj; @@ -2947,14 +3177,12 @@ static PHP_METHOD(pqtypes, __construct) { } else { zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "refresh", &retval); } + if (retval) { zval_ptr_dtor(&retval); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } #define PHP_PQ_TYPES_QUERY \ @@ -2969,14 +3197,24 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtypes, refresh) { HashTable *nsp = NULL; + zend_error_handling zeh; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H/!", &nsp); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H/!", &nsp)) { + if (SUCCESS == rv) { php_pqtypes_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Types not initialized"); + } else { PGresult *res; - if (nsp && zend_hash_num_elements(nsp)) { + if (!nsp || !zend_hash_num_elements(nsp)) { + res = PQexec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')"); + } else { int i, count; Oid *oids; char **params = NULL; @@ -3004,14 +3242,12 @@ static PHP_METHOD(pqtypes, refresh) { efree(oids); efree(params); zend_hash_destroy(&zdtor); - } else { - res = PQexec(obj->intern->conn->intern->conn, PHP_PQ_TYPES_QUERY " and nspname in ('public', 'pg_catalog')"); } - php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); - - if (res) { - if (PGRES_TUPLES_OK == PQresultStatus(res)) { + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch types (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { + if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { int r, rows; for (r = 0, rows = PQntuples(res); r < rows; ++r) { @@ -3024,16 +3260,11 @@ static PHP_METHOD(pqtypes, refresh) { zend_hash_index_update(&obj->intern->types, oid, (void *) &row, sizeof(zval *), NULL); zend_hash_add(&obj->intern->types, name, strlen(name) + 1, (void *) &row, sizeof(zval *), NULL); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types (%s)", PHP_PQresultErrorMessage(res)); } + PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch types (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Types not initialized"); } } } @@ -3137,24 +3368,24 @@ static PHP_METHOD(pqres, bind) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z", &zcol, &zref)) { php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + } else { php_pqres_col_t col; - if (SUCCESS == column_nn(obj, zcol, &col TSRMLS_CC)) { + if (SUCCESS != column_nn(obj, zcol, &col TSRMLS_CC)) { + RETVAL_FALSE; + } else { Z_ADDREF_P(zref); - if (SUCCESS == zend_hash_index_update(&obj->intern->bound, col.num, (void *) &zref, sizeof(zval *), NULL)) { - zend_hash_sort(&obj->intern->bound, zend_qsort, compare_index, 0 TSRMLS_CC); - RETVAL_TRUE; - } else { + + if (SUCCESS != zend_hash_index_update(&obj->intern->bound, col.num, (void *) &zref, sizeof(zval *), NULL)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to bind column %s@%d", col.name, col.num); RETVAL_FALSE; + } else { + zend_hash_sort(&obj->intern->bound, zend_qsort, compare_index, 0 TSRMLS_CC); + RETVAL_TRUE; } - } else { - RETVAL_FALSE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized"); - RETVAL_FALSE; } } } @@ -3163,18 +3394,21 @@ static int apply_bound(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key { zval **zvalue, **zbound = p; zval **zrow = va_arg(argv, zval **); + STATUS *rv = va_arg(argv, STATUS *); - if (SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(zrow), key->h, (void *) &zvalue)) { + if (SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrow), key->h, (void *) &zvalue)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column ad index %lu", key->h); + *rv = FAILURE; + return ZEND_HASH_APPLY_STOP; + } else { zval_dtor(*zbound); ZVAL_COPY_VALUE(*zbound, *zvalue); ZVAL_NULL(*zvalue); zval_ptr_dtor(zvalue); Z_ADDREF_P(*zbound); *zvalue = *zbound; + *rv = SUCCESS; return ZEND_HASH_APPLY_KEEP; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column ad index %lu", key->h); - return ZEND_HASH_APPLY_STOP; } } @@ -3182,23 +3416,33 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_bound, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchBound) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + } else { zval **row = NULL; - if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row TSRMLS_CC)) { - if (row) { - zend_hash_apply_with_arguments(&obj->intern->bound TSRMLS_CC, apply_bound, 1, row); + if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row TSRMLS_CC) && row) { + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC); + zend_hash_apply_with_arguments(&obj->intern->bound TSRMLS_CC, apply_bound, 2, row, &rv); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (SUCCESS != rv) { + zval_ptr_dtor(row); + } else { RETVAL_ZVAL(*row, 1, 0); } } } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0) @@ -3208,25 +3452,31 @@ static PHP_METHOD(pqres, fetchRow) { zend_error_handling zeh; php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); long fetch_type = -1; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type)) { - if (obj->intern) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_type); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (SUCCESS == rv) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + } else { zval **row = NULL; if (fetch_type == -1) { fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY; } + + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC); php_pqres_iteration(getThis(), obj, fetch_type, &row TSRMLS_CC); + zend_restore_error_handling(&zeh TSRMLS_CC); if (row) { RETVAL_ZVAL(*row, 1, 0); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } static zval **column_at(zval *row, int col TSRMLS_DC) @@ -3235,14 +3485,14 @@ static zval **column_at(zval *row, int col TSRMLS_DC) HashTable *ht = HASH_OF(row); int count = zend_hash_num_elements(ht); - if (col < count) { + if (col >= count) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count); + } else { zend_hash_internal_pointer_reset(ht); while (col-- > 0) { zend_hash_move_forward(ht); } zend_hash_get_current_data(ht, (void *) &data); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count); } return data; } @@ -3253,16 +3503,22 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchCol) { zend_error_handling zeh; long fetch_col = 0; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col)) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &fetch_col); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (SUCCESS == rv) { php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + } else { zval **row = NULL; + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC); php_pqres_iteration(getThis(), obj, obj->intern->iter ? obj->intern->iter->fetch_type : 0, &row TSRMLS_CC); - if (row) { zval **col = column_at(*row, fetch_col TSRMLS_CC); @@ -3270,11 +3526,9 @@ static PHP_METHOD(pqres, fetchCol) { RETVAL_ZVAL(*col, 1, 0); } } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized"); + zend_restore_error_handling(&zeh TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } static int apply_to_col(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) @@ -3285,15 +3539,15 @@ static int apply_to_col(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key STATUS *rv = va_arg(argv, STATUS *); col = *cols; - if (SUCCESS == column_nn(obj, *c, col TSRMLS_CC)) { - *rv = SUCCESS; - } else { + + if (SUCCESS != column_nn(obj, *c, col TSRMLS_CC)) { *rv = FAILURE; return ZEND_HASH_APPLY_STOP; + } else { + *rv = SUCCESS; + ++*cols; + return ZEND_HASH_APPLY_KEEP; } - ++*cols; - - return ZEND_HASH_APPLY_KEEP; } static php_pqres_col_t *php_pqres_convert_to_cols(php_pqres_object_t *obj, HashTable *ht TSRMLS_DC) @@ -3321,13 +3575,18 @@ static PHP_METHOD(pqres, map) { zend_error_handling zeh; zval *zkeys = 0, *zvals = 0; long fetch_type = -1; + STATUS rv; + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/!z/!l", &zkeys, &zvals, &fetch_type); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/!z/!l", &zkeys, &zvals, &fetch_type)) { + if (SUCCESS == rv) { php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + } else { int ks = 0, vs = 0; php_pqres_col_t def = {PQfname(obj->intern->res, 0), 0}, *keys = NULL, *vals = NULL; @@ -3391,7 +3650,7 @@ static PHP_METHOD(pqres, map) { break; } if (SUCCESS != zend_symtable_update(HASH_OF(*cur), key, len + 1, (void *) &tmp, sizeof(zval *), (void *) &cur)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create map"); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create map"); goto err; } } @@ -3426,11 +3685,8 @@ static PHP_METHOD(pqres, map) { if (vals) { efree(vals); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count, 0, 0, 0) @@ -3439,10 +3695,10 @@ static PHP_METHOD(pqres, count) { if (SUCCESS == zend_parse_parameters_none()) { long count; - if (SUCCESS == php_pqres_count_elements(getThis(), &count TSRMLS_CC)) { - RETVAL_LONG(count); + if (SUCCESS != php_pqres_count_elements(getThis(), &count TSRMLS_CC)) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Result not initialized"); + RETVAL_LONG(count); } } } @@ -3470,20 +3726,23 @@ static PHP_METHOD(pqstm, __construct) { char *name_str, *query_str; int name_len, *query_len; zend_bool async = 0; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|a/!b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes, &async); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oss|a/!b", &zconn, php_pqconn_class_entry, &name_str, &name_len, &query_str, &query_len, &ztypes, &async)) { + if (SUCCESS == rv) { php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); - if (conn_obj->intern) { - STATUS rv; + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { if (async) { - conn_obj->intern->poller = PQconsumeInput; rv = php_pqconn_prepare_async(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC); } else { rv = php_pqconn_prepare(zconn, conn_obj, name_str, query_str, ztypes ? Z_ARRVAL_P(ztypes) : NULL TSRMLS_CC); - php_pqconn_notify_listeners(conn_obj TSRMLS_CC); } if (SUCCESS == rv) { @@ -3495,11 +3754,8 @@ static PHP_METHOD(pqstm, __construct) { ZEND_INIT_SYMTABLE(&stm->bound); obj->intern = stm; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_bind, 0, 0, 2) ZEND_ARG_INFO(0, param_no) @@ -3512,12 +3768,12 @@ static PHP_METHOD(pqstm, bind) { if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", ¶m_no, ¶m_ref)) { php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized"); + } else { Z_ADDREF_P(param_ref); zend_hash_index_update(&obj->intern->bound, param_no, (void *) ¶m_ref, sizeof(zval *), NULL); zend_hash_sort(&obj->intern->bound, zend_qsort, compare_index, 0 TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized"); } } } @@ -3528,55 +3784,46 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, exec) { zend_error_handling zeh; zval *zparams = NULL; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &zparams)) { + if (SUCCESS == rv) { php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (obj->intern->conn->intern) { - int count = 0; - char **params = NULL; - HashTable zdtor; - PGresult *res; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized"); + } else { + int count = 0; + char **params = NULL; + HashTable zdtor; + PGresult *res; - ZEND_INIT_SYMTABLE(&zdtor); + ZEND_INIT_SYMTABLE(&zdtor); - if (zparams) { - count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC); - } else { - count = php_pq_params_to_array(&obj->intern->bound, ¶ms, &zdtor TSRMLS_CC); - } + if (zparams) { + count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC); + } else { + count = php_pq_params_to_array(&obj->intern->bound, ¶ms, &zdtor TSRMLS_CC); + } - res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0); + res = PQexecPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0); - if (params) { - efree(params); - } - zend_hash_destroy(&zdtor); + if (params) { + efree(params); + } + zend_hash_destroy(&zdtor); + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to execute statement (%s)", 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); php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); - - if (res) { - if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { - php_pqres_t *r = ecalloc(1, sizeof(*r)); - - r->res = res; - ZEND_INIT_SYMTABLE(&r->bound); - return_value->type = IS_OBJECT; - return_value->value.obj = php_pqres_create_object_ex(php_pqres_class_entry, r, NULL TSRMLS_CC); - } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_exec_async, 0, 0, 0) @@ -3587,131 +3834,112 @@ static PHP_METHOD(pqstm, execAsync) { zend_error_handling zeh; zval *zparams = NULL; php_pq_callback_t resolver = {{0}}; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!f", &zparams, &resolver.fci, &resolver.fcc)) { + if (SUCCESS == rv) { php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (obj->intern->conn->intern) { - int count; - char **params = NULL; - HashTable zdtor; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized"); + } else { + int count; + char **params = NULL; + HashTable zdtor; - if (zparams) { - ZEND_INIT_SYMTABLE(&zdtor); - count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC); - } + if (zparams) { + ZEND_INIT_SYMTABLE(&zdtor); + count = php_pq_params_to_array(Z_ARRVAL_P(zparams), ¶ms, &zdtor TSRMLS_CC); + } + if (!PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to execute statement (%s)", 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_dtor(&obj->intern->conn->intern->onevent); if (resolver.fci.size > 0) { obj->intern->conn->intern->onevent = resolver; php_pq_callback_addref(&obj->intern->conn->intern->onevent); } - obj->intern->conn->intern->poller = PQconsumeInput; + } - if (PQsendQueryPrepared(obj->intern->conn->intern->conn, obj->intern->name, count, (const char *const*) params, NULL, NULL, 0)) { - if (obj->intern->conn->intern->unbuffered) { - if (!PQsetSingleRowMode(obj->intern->conn->intern->conn)) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not enable unbuffered mode (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } - } - RETVAL_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - RETVAL_FALSE; - } - - if (params) { - efree(params); - } - if (zparams) { - zend_hash_destroy(&zdtor); - } - - php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); - RETVAL_FALSE; + if (params) { + efree(params); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized"); - RETVAL_FALSE; + if (zparams) { + zend_hash_destroy(&zdtor); + } + + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, desc) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { - php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + 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 (obj->intern) { - if (obj->intern->conn->intern) { - PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name); + if (SUCCESS == rv) { + php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized"); + } else { + PGresult *res = PQdescribePrepared(obj->intern->conn->intern->conn, obj->intern->name); - if (res) { - if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { - int p, params; + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to describe statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { + if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { + int p, params; - array_init(return_value); - for (p = 0, params = PQnparams(res); p < params; ++p) { - add_next_index_long(return_value, PQparamtype(res, p)); - } + array_init(return_value); + for (p = 0, params = PQnparams(res); p < params; ++p) { + add_next_index_long(return_value, PQparamtype(res, p)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + PHP_PQclear(res); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Statement not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqstm_desc_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqstm, descAsync) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { - php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + 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 (obj->intern) { + if (SUCCESS == rv) { + php_pqstm_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Statement not initialized"); + } else if (!PQsendDescribePrepared(obj->intern->conn->intern->conn, obj->intern->name)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to describe statement: %s", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { obj->intern->conn->intern->poller = PQconsumeInput; - - if (PQsendDescribePrepared(obj->intern->conn->intern->conn, obj->intern->name)) { - RETVAL_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not describe statement: %s", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - RETVAL_FALSE; - } - php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Statement not initialized"); - RETVAL_FALSE; } } - zend_restore_error_handling(&zeh TSRMLS_CC); } - static zend_function_entry php_pqstm_methods[] = { PHP_ME(pqstm, __construct, ai_pqstm_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) PHP_ME(pqstm, bind, ai_pqstm_bind, ZEND_ACC_PUBLIC) @@ -3734,14 +3962,18 @@ static PHP_METHOD(pqtxn, __construct) { zval *zconn; long isolation = PHP_PQTXN_READ_COMMITTED; zend_bool async = 0, readonly = 0, deferrable = 0; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|blbb", &zconn, php_pqconn_class_entry, &async, &isolation, &readonly, &deferrable)) { - STATUS rv; - php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|blbb", &zconn, php_pqconn_class_entry, &async, &isolation, &readonly, &deferrable); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); - if (conn_obj->intern) { + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { if (async) { rv = php_pqconn_start_transaction_async(zconn, conn_obj, isolation, readonly, deferrable TSRMLS_CC); } else { @@ -3749,277 +3981,342 @@ static PHP_METHOD(pqtxn, __construct) { } if (SUCCESS == rv) { + php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + obj->intern = ecalloc(1, sizeof(*obj->intern)); php_pq_object_addref(conn_obj TSRMLS_CC); obj->intern->conn = conn_obj; + obj->intern->open = 1; obj->intern->isolation = isolation; obj->intern->readonly = readonly; obj->intern->deferrable = deferrable; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, savepoint) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - char *cmd; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed"); + } else { PGresult *res; + smart_str cmd = {0}; - spprintf(&cmd, 0, "SAVEPOINT \"%u\"", ++obj->intern->savepoint); - res = PQexec(obj->intern->conn->intern->conn, cmd); + smart_str_appends(&cmd, "SAVEPOINT \""); + smart_str_append_unsigned(&cmd, ++obj->intern->savepoint); + smart_str_appends(&cmd, "\""); + smart_str_0(&cmd); - if (res) { + res = PQexec(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); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } - efree(cmd); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + smart_str_free(&cmd); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_savepoint_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, savepointAsync) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - char *cmd; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed"); + } else { + smart_str cmd = {0}; + + smart_str_appends(&cmd, "SAVEPOINT \""); + smart_str_append_unsigned(&cmd, ++obj->intern->savepoint); + smart_str_appends(&cmd, "\""); + smart_str_0(&cmd); - spprintf(&cmd, 0, "SAVEPOINT \"%u\"", ++obj->intern->savepoint); - if (!PQsendQuery(obj->intern->conn->intern->conn, cmd)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + if (!PQsendQuery(obj->intern->conn->intern->conn, cmd.c)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to create %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } - efree(cmd); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + smart_str_free(&cmd); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, commit) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transacation not initialized"); + } else if (!obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transacation already closed"); + } else { PGresult *res; + smart_str cmd = {0}; - if (obj->intern->savepoint) { - char *cmd; - - spprintf(&cmd, 0, "RELEASE SAVEPOINT \"%u\"", obj->intern->savepoint--); - res = PQexec(obj->intern->conn->intern->conn, cmd); + if (!obj->intern->savepoint) { + res = PQexec(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); - if (res) { - php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } + res = PQexec(obj->intern->conn->intern->conn, cmd.c); + } - efree(cmd); + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "commit transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - res = PQexec(obj->intern->conn->intern->conn, "COMMIT"); - - if (res) { - php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to commit transaction (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { + if (!cmd.c) { + obj->intern->open = 0; + } } + PHP_PQclear(res); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + smart_str_free(&cmd); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_commit_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, commitAsync) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - obj->intern->conn->intern->poller = PQconsumeInput; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed"); + } else { + int rc; + smart_str cmd = {0}; - if (obj->intern->savepoint) { - char *cmd; + if (!obj->intern->savepoint) { + rc = PQsendQuery(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); - spprintf(&cmd, 0, "RELEASE SAVEPOINT \"%u\"", obj->intern->savepoint--); - if (!PQsendQuery(obj->intern->conn->intern->conn, cmd)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } + rc = PQsendQuery(obj->intern->conn->intern->conn, cmd.c); + } - efree(cmd); + if (!rc) { + throw_exce(EX_IO TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "commmit transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - if (!PQsendQuery(obj->intern->conn->intern->conn, "COMMIT")) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to commit transaction (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + if (!cmd.c) { + obj->intern->open = 0; } + obj->intern->conn->intern->poller = PQconsumeInput; + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + smart_str_free(&cmd); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, rollback) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed"); + } else { PGresult *res; + smart_str cmd = {0}; - if (obj->intern->savepoint) { - char *cmd; - - spprintf(&cmd, 0, "ROLLBACK TO SAVEPOINT \"%u\"", obj->intern->savepoint--); - res = PQexec(obj->intern->conn->intern->conn, cmd); + if (!obj->intern->savepoint) { + res = PQexec(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); - if (res) { - php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } + res = PQexec(obj->intern->conn->intern->conn, cmd.c); + } - efree(cmd); + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "rollback transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - res = PQexec(obj->intern->conn->intern->conn, "ROLLBACK"); - - if (res) { - php_pqres_success(res TSRMLS_CC); - PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to rollback transaction (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { + if (!cmd.c) { + obj->intern->open = 0; + } } + PHP_PQclear(res); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + smart_str_free(&cmd); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_rollback_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, rollbackAsync) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - obj->intern->conn->intern->poller = PQconsumeInput; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction already closed"); + } else { + int rc; + smart_str cmd = {0}; - if (obj->intern->savepoint) { - char *cmd; + if (!obj->intern->savepoint) { + rc = PQsendQuery(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); - spprintf(&cmd, 0, "ROLLBACK TO SAVEPOINT \"%u\"", obj->intern->savepoint--); - if (!PQsendQuery(obj->intern->conn->intern->conn, cmd)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } + rc = PQsendQuery(obj->intern->conn->intern->conn, cmd.c); + } - efree(cmd); + if (!rc) { + throw_exce(EX_IO TSRMLS_CC, "Failed to %s (%s)", cmd.c ? cmd.c : "rollback transaction", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - if (!PQsendQuery(obj->intern->conn->intern->conn, "ROLLBACK")) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not rollback transaction (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + if (!cmd.c) { + obj->intern->open = 0; } + obj->intern->conn->intern->poller = PQconsumeInput; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + smart_str_free(&cmd); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, exportSnapshot) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + 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()"); - if (res) { + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { RETVAL_STRING(PQgetvalue(res, 0, 0), 1); } PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_export_snapshot_async, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, exportSnapshotAsync) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { - php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + 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 (obj->intern) { - obj->intern->conn->intern->poller = PQconsumeInput; + if (SUCCESS == rv) { + php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (!PQsendQuery(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()")) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!PQsendQuery(obj->intern->conn->intern->conn, "SELECT pg_export_snapshot()")) { + throw_exce(EX_IO TSRMLS_CC, "Failed to export transaction snapshot (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + obj->intern->conn->intern->poller = PQconsumeInput; + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot, 0, 0, 1) @@ -4029,33 +4326,46 @@ static PHP_METHOD(pqtxn, importSnapshot) { zend_error_handling zeh; char *snapshot_str; int snapshot_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &snapshot_str, &snapshot_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &snapshot_str, &snapshot_len)) { + if (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (obj->intern->isolation >= PHP_PQTXN_REPEATABLE_READ) { - char *cmd, *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len); + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (obj->intern->isolation < PHP_PQTXN_REPEATABLE_READ) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot"); + } else { + char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len); + + if (!sid) { + throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { PGresult *res; + smart_str cmd = {0}; + + smart_str_appends(&cmd, "SET TRANSACTION SNAPSHOT "); + smart_str_appends(&cmd, sid); + smart_str_0(&cmd); - spprintf(&cmd, 0, "SET TRANSACTION SNAPSHOT %s", sid); - res = PQexec(obj->intern->conn->intern->conn, cmd); + res = PQexec(obj->intern->conn->intern->conn, cmd.c); - if (res) { + 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); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "A transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot"); + + smart_str_free(&cmd); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_import_snapshot_async, 0, 0, 1) @@ -4065,35 +4375,56 @@ static PHP_METHOD(pqtxn, importSnapshotAsync) { zend_error_handling zeh; char *snapshot_str; int snapshot_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &snapshot_str, &snapshot_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &snapshot_str, &snapshot_len)) { + if (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (obj->intern->isolation >= PHP_PQTXN_REPEATABLE_READ) { - char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len); + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (obj->intern->isolation < PHP_PQTXN_REPEATABLE_READ) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot"); + } else { + char *sid = PQescapeLiteral(obj->intern->conn->intern->conn, snapshot_str, snapshot_len); - if (sid) { - char *cmd; - obj->intern->conn->intern->poller = PQconsumeInput; + if (!sid) { + throw_exce(EX_ESCAPE TSRMLS_CC, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { + smart_str cmd = {0}; - spprintf(&cmd, 0, "SET TRANSACTION SNAPSHOT %s", sid); - if (!PQsendQuery(obj->intern->conn->intern->conn, cmd)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to %s (%s)", cmd, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } - efree(cmd); + smart_str_appends(&cmd, "SET TRANSACTION SNAPSHOT "); + smart_str_appends(&cmd, sid); + smart_str_0(&cmd); + + if (!PQsendQuery(obj->intern->conn->intern->conn, cmd.c)) { + throw_exce(EX_IO TSRMLS_CC, "Failed to %s (%s)", cmd.c, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to quote snapshot identifier (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + obj->intern->conn->intern->poller = PQconsumeInput; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "A transaction must have at least isolation level REPEATABLE READ to be able to import a snapshot"); + + smart_str_free(&cmd); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); +} + +static const char *strmode(long mode) +{ + switch (mode & (INV_READ|INV_WRITE)) { + case INV_READ|INV_WRITE: + return "rw"; + case INV_READ: + return "r"; + case INV_WRITE: + return "w"; + default: + return "-"; + } } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_open_lob, 0, 0, 1) @@ -4103,15 +4434,23 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, openLOB) { zend_error_handling zeh; long mode = INV_WRITE|INV_READ, loid; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &loid, &mode)) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &loid, &mode); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else { int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode); - if (lofd >= 0) { + 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)); + } else { php_pqlob_t *lob = ecalloc(1, sizeof(*lob)); lob->lofd = lofd; @@ -4121,19 +4460,11 @@ static PHP_METHOD(pqtxn, openLOB) { return_value->type = IS_OBJECT; return_value->value.obj = php_pqlob_create_object_ex(php_pqlob_class_entry, lob, NULL TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open large object with mode '%s' (%s)", - (mode & (INV_READ|INV_WRITE) ? "rw" : - (mode & INV_READ ? "r" : - (mode & INV_WRITE ? "w" : "-"))), - PHP_PQerrorMessage(obj->intern->conn->intern->conn) - ); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_create_lob, 0, 0, 0) @@ -4142,19 +4473,30 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, createLOB) { zend_error_handling zeh; long mode = INV_WRITE|INV_READ; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &mode)) { + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &mode); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else { Oid loid = lo_creat(obj->intern->conn->intern->conn, mode); - if (loid != InvalidOid) { + if (loid == InvalidOid) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create large object with mode '%s' (%s)", strmode(mode), PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { int lofd = lo_open(obj->intern->conn->intern->conn, loid, mode); - if (lofd >= 0) { + 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)); + } else { php_pqlob_t *lob = ecalloc(1, sizeof(*lob)); + lob->lofd = lofd; lob->loid = loid; php_pq_object_addref(obj TSRMLS_CC); @@ -4162,48 +4504,39 @@ static PHP_METHOD(pqtxn, createLOB) { return_value->type = IS_OBJECT; return_value->value.obj = php_pqlob_create_object_ex(php_pqlob_class_entry, lob, NULL TSRMLS_CC); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open large object with mode '%s': %s", - (mode & (INV_READ|INV_WRITE) ? "rw" : - (mode & INV_READ ? "r" : - (mode & INV_WRITE ? "w" : "-"))), - PHP_PQerrorMessage(obj->intern->conn->intern->conn) - ); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create large object with mode '%s': %s", - (mode & (INV_READ|INV_WRITE) ? "rw" : - (mode & INV_READ ? "r" : - (mode & INV_WRITE ? "w" : "-"))), - PHP_PQerrorMessage(obj->intern->conn->intern->conn) - ); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqtxn_unlink_lob, 0, 0, 1) ZEND_ARG_INFO(0, oid) ZEND_END_ARG_INFO(); static PHP_METHOD(pqtxn, unlinkLOB) { + zend_error_handling zeh; long loid; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &loid); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &loid)) { + if (SUCCESS == rv) { php_pqtxn_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (1 == lo_unlink(obj->intern->conn->intern->conn, loid)) { - RETVAL_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to unlink LOB (oid=%ld): %s", loid, PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - RETVAL_FALSE; - } + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); - RETVAL_FALSE; + 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)); + } + + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } } @@ -4232,51 +4565,57 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqcancel, __construct) { zend_error_handling zeh; zval *zconn; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zconn, php_pqconn_class_entry); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zconn, php_pqconn_class_entry)) { + if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); - if (conn_obj->intern) { + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { PGcancel *cancel = PQgetCancel(conn_obj->intern->conn); - if (cancel) { + if (!cancel) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to acquire cancel (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); + } else { php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->cancel = cancel; php_pq_object_addref(conn_obj TSRMLS_CC); obj->intern->conn = conn_obj; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not acquire cancel (%s)", PHP_PQerrorMessage(conn_obj->intern->conn)); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcancel_cancel, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqcancel, cancel) { zend_error_handling zeh; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqcancel_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - char err[256]; + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Cancel not initialized"); + } else { + char err[256] = {0}; if (!PQcancel(obj->intern->cancel, err, sizeof(err))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not request cancellation: %s", err); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to request cancellation (%s)", err); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Cancel not initialized"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } static zend_function_entry php_pqcancel_methods[] = { @@ -4285,24 +4624,6 @@ static zend_function_entry php_pqcancel_methods[] = { {0} }; -static void php_pqconn_add_eventhandler(zval *zconn, php_pqconn_object_t *conn_obj, const char *type_str, size_t type_len, zval *zevent TSRMLS_DC) -{ - zval **evhs; - - if (SUCCESS == zend_hash_find(&conn_obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evhs)) { - Z_ADDREF_P(zevent); - add_next_index_zval(*evhs, zevent); - } else { - zval *evh; - - MAKE_STD_ZVAL(evh); - array_init(evh); - Z_ADDREF_P(zevent); - add_next_index_zval(evh, zevent); - zend_hash_add(&conn_obj->intern->eventhandlers, type_str, type_len + 1, (void *) &evh, sizeof(zval *), NULL); - } -} - 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) @@ -4314,52 +4635,58 @@ static PHP_METHOD(pqevent, __construct) { 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, "Osf", &zconn, php_pqconn_class_entry, &type_str, &type_len, &cb.fci, &cb.fcc); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osf", &zconn, php_pqconn_class_entry, &type_str, &type_len, &cb.fci, &cb.fcc)) { + if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); - if (conn_obj->intern) { + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); obj->intern = ecalloc(1, sizeof(*obj->intern)); php_pq_callback_addref(&cb); obj->intern->cb = cb; - php_pq_object_addref(conn_obj TSRMLS_CC); - obj->intern->conn = conn_obj; obj->intern->type = estrdup(type_str); - - php_pqconn_add_eventhandler(zconn, conn_obj, type_str, type_len, getThis() TSRMLS_CC); - - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + obj->intern->h = php_pqconn_add_eventhandler(conn_obj, type_str, type_len, getThis() TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } 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; + + 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); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &args)) { + if (SUCCESS == rv) { php_pqevent_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Event not initialized"); + } else { zval *rv = NULL; - if (SUCCESS == zend_fcall_info_call(&obj->intern->cb.fci, &obj->intern->cb.fcc, &rv, args TSRMLS_CC)) { + 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; } } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Event not initialized"); - RETVAL_FALSE; } } } @@ -4379,21 +4706,32 @@ static PHP_METHOD(pqlob, __construct) { zend_error_handling zeh; zval *ztxn; long mode = INV_WRITE|INV_READ, loid = InvalidOid; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &ztxn, php_pqtxn_class_entry, &loid, &mode)) { - php_pqtxn_object_t *txn_obj = zend_object_store_get_object(ztxn TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &ztxn, php_pqtxn_class_entry, &loid, &mode); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (txn_obj->intern) { + if (SUCCESS == rv) { + php_pqtxn_object_t *txn_obj = zend_object_store_get_object(ztxn TSRMLS_CC); + if (!txn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Transaction not initialized"); + } else if (!txn_obj->intern->open) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\Transation already closed"); + } else { if (loid == InvalidOid) { loid = lo_creat(txn_obj->intern->conn->intern->conn, mode); } - if (loid != InvalidOid) { + if (loid == InvalidOid) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create large object with mode '%s' (%s)", strmode(mode), PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn)); + } else { int lofd = lo_open(txn_obj->intern->conn->intern->conn, loid, mode); - if (lofd >= 0) { + 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)); + } else { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); obj->intern = ecalloc(1, sizeof(*obj->intern)); @@ -4401,52 +4739,42 @@ static PHP_METHOD(pqlob, __construct) { obj->intern->loid = loid; php_pq_object_addref(txn_obj TSRMLS_CC); obj->intern->txn = txn_obj; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to open large object with mode '%s' (%s)", - (mode & (INV_READ|INV_WRITE) ? "rw" : - (mode & INV_READ ? "r" : - (mode & INV_WRITE ? "w" : "-"))), - PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn) - ); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create large object with mode '%s' (%s)", - (mode & (INV_READ|INV_WRITE) ? "rw" : - (mode & INV_READ ? "r" : - (mode & INV_WRITE ? "w" : "-"))), - PHP_PQerrorMessage(txn_obj->intern->conn->intern->conn) - ); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Transaction not initialized"); + + php_pqconn_notify_listeners(txn_obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_write, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, write) { + zend_error_handling zeh; char *data_str; int data_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) { + if (SUCCESS == rv) { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized"); + } else { int written = lo_write(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, data_str, data_len); - if (written >= 0) { - RETVAL_LONG(written); + 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)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write to LOB, oid=%d (%s)", obj->intern->loid, - PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); - RETVAL_FALSE; + RETVAL_LONG(written); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized"); - RETVAL_FALSE; + + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); } } } @@ -4456,33 +4784,37 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_read, 0, 0, 0) ZEND_ARG_INFO(1, read) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, read) { + zend_error_handling zeh; long length = 0x1000; zval *zread = NULL; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lz!", &length, &zread); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lz!", &length, &zread)) { + if (SUCCESS == rv) { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized"); + } else { char *buffer = emalloc(length + 1); int read = lo_read(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, buffer, length); - if (read >= 0) { + if (read < 0) { + efree(buffer); + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to read from LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); + } else { if (zread) { zval_dtor(zread); ZVAL_LONG(zread, read); } buffer[read] = '\0'; RETVAL_STRINGL(buffer, read, 0); - } else { - efree(buffer); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to read from LOB, oid=%d (%s)", obj->intern->loid, - PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); - RETVAL_FALSE; } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized"); - RETVAL_FALSE; + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); } } } @@ -4492,24 +4824,29 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_seek, 0, 0, 1) ZEND_ARG_INFO(0, whence) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, seek) { + zend_error_handling zeh; long offset, whence = SEEK_SET; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &offset, &whence); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &offset, &whence)) { + if (SUCCESS == rv) { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized"); + } else { int position = lo_lseek(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, offset, whence); - if (position >= 0) { - RETVAL_LONG(position); + if (position < 0) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to seek offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek offset in LOB, oid=%d (%s)", obj->intern->loid, - PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); - RETVAL_FALSE; + RETVAL_LONG(position); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized"); - RETVAL_FALSE; + + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); } } } @@ -4517,22 +4854,28 @@ static PHP_METHOD(pqlob, seek) { ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_tell, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, tell) { - if (SUCCESS == zend_parse_parameters_none()) { + 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 (SUCCESS == rv) { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized"); + } else { int position = lo_tell(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd); - if (position >= 0) { - RETVAL_LONG(position); + if (position < 0) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to tell offset in LOB with oid=%d (%s)", obj->intern->loid, PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to tell offset in LOB (oid=%d): %s", obj->intern->loid, - PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); - RETVAL_FALSE; + RETVAL_LONG(position); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized"); - RETVAL_FALSE; + + php_pqconn_notify_listeners(obj->intern->txn->intern->conn TSRMLS_CC); } } } @@ -4541,22 +4884,27 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqlob_truncate, 0, 0, 0) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO(); static PHP_METHOD(pqlob, truncate) { + zend_error_handling zeh; long length = 0; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &length); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &length)) { + if (SUCCESS == rv) { php_pqlob_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (0 == lo_truncate(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, length)) { - RETVAL_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to truncate LOB (oid=%d): %s", obj->intern->loid, - PHP_PQerrorMessage(obj->intern->txn->intern->conn->intern->conn)); - RETVAL_FALSE; - } + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\LOB not initialized"); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\LOB not initialized"); - RETVAL_FALSE; + int rc = lo_truncate(obj->intern->txn->intern->conn->intern->conn, obj->intern->lofd, length); + + if (rc != 0) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to truncate 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); } } } @@ -4583,35 +4931,45 @@ static PHP_METHOD(pqcopy, __construct) { char *expr_str, *opt_str = ""; int expr_len, opt_len = 0; long direction; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osl|s", &zconn, php_pqconn_class_entry, &expr_str, &expr_len, &direction, &opt_str, &opt_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Osl|s", &zconn, php_pqconn_class_entry, &expr_str, &expr_len, &direction, &opt_str, &opt_len)) { + if (SUCCESS == rv) { php_pqconn_object_t *conn_obj = zend_object_store_get_object(zconn TSRMLS_CC); - if (conn_obj->intern) { - char *copy = NULL; + if (!conn_obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Connection not initialized"); + } else { + php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + smart_str cmd = {0}; + PGresult *res; + + smart_str_appends(&cmd, "COPY "); + smart_str_appendl(&cmd, expr_str, expr_len); switch (direction) { case PHP_PQCOPY_FROM_STDIN: - spprintf(©, 0, "COPY %s %s %s", expr_str, "FROM STDIN", opt_str); + smart_str_appends(&cmd, " FROM STDIN "); break; - case PHP_PQCOPY_TO_STDOUT: - spprintf(©, 0, "COPY %s %s %s", expr_str, "TO STDOUT", opt_str); + smart_str_appends(&cmd, " TO STDOUT "); break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid COPY direction, expected one of FROM_STDIN (%d) TO_STDOUT (%d), got %ld", - PHP_PQCOPY_FROM_STDIN, PHP_PQCOPY_TO_STDOUT, direction); - break; + throw_exce(EX_RUNTIME TSRMLS_CC, "Invalid COPY direction, expected one of FROM_STDIN (%d) TO_STDOUT (%d), got %ld", PHP_PQCOPY_FROM_STDIN, PHP_PQCOPY_TO_STDOUT, direction); + smart_str_free(&cmd); + return; } + smart_str_appendl(&cmd, opt_str, opt_len); + smart_str_0(&cmd); - if (copy) { - php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - PGresult *res = PQexec(conn_obj->intern->conn, copy); - - efree(copy); + res = PQexec(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)); + } else { if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { obj->intern = ecalloc(1, sizeof(*obj->intern)); obj->intern->direction = direction; @@ -4623,11 +4981,11 @@ static PHP_METHOD(pqcopy, __construct) { PHP_PQclear(res); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\Connection not initialized"); + + smart_str_free(&cmd); + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_put, 0, 0, 1) @@ -4637,26 +4995,26 @@ static PHP_METHOD(pqcopy, put) { zend_error_handling zeh; char *data_str; int data_len; + STATUS rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data_str, &data_len)) { + if (SUCCESS == rv) { php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (obj->intern) { - if (PHP_PQCOPY_FROM_STDIN == obj->intern->direction) { - if (1 == PQputCopyData(obj->intern->conn->intern->conn, data_str, data_len)) { - RETVAL_TRUE; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to send COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY was not initialized with FROM_STDIN"); - } + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\COPY not initialized"); + } else if (obj->intern->direction != PHP_PQCOPY_FROM_STDIN) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY was not initialized with FROM_STDIN"); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY not initialized"); + if (1 != PQputCopyData(obj->intern->conn->intern->conn, data_str, data_len)) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to put COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_end, 0, 0, 0) @@ -4666,36 +5024,36 @@ static PHP_METHOD(pqcopy, end) { zend_error_handling zeh; char *error_str = NULL; int error_len = 0; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &error_str, &error_len)) { - php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &error_str, &error_len); + zend_restore_error_handling(&zeh TSRMLS_CC); - if (obj->intern) { - if (PHP_PQCOPY_FROM_STDIN == obj->intern->direction) { - if (1 == PQputCopyEnd(obj->intern->conn->intern->conn, error_str)) { - PGresult *res = PQgetResult(obj->intern->conn->intern->conn); + if (SUCCESS == rv) { + php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (res) { - if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { - RETVAL_TRUE; - } + if (!obj->intern) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY not intitialized"); + } else if (obj->intern->direction != PHP_PQCOPY_FROM_STDIN) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY was not intitialized with FROM_STDIN"); + } else { + if (1 != PQputCopyEnd(obj->intern->conn->intern->conn, error_str)) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to end COPY (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + } else { + PGresult *res = PQgetResult(obj->intern->conn->intern->conn); - PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } + if (!res) { + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to end COPY (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + php_pqres_success(res TSRMLS_CC); + PHP_PQclear(res); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY was not initialized with FROM_STDIN"); } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "pq\\COPY not initialized"); + + php_pqconn_notify_listeners(obj->intern->conn TSRMLS_CC); } } - zend_restore_error_handling(&zeh TSRMLS_CC); } ZEND_BEGIN_ARG_INFO_EX(ai_pqcopy_get, 0, 0, 1) @@ -4704,54 +5062,57 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqcopy, get) { zend_error_handling zeh; zval *zdata; + STATUS rv; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata)) { - php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - char *buffer = NULL; - - if (obj->intern) { - if (PHP_PQCOPY_TO_STDOUT == obj->intern->direction) { - PGresult *res; - int bytes = PQgetCopyData(obj->intern->conn->intern->conn, &buffer, 0); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata); + zend_restore_error_handling(&zeh TSRMLS_CC); - switch (bytes) { - case -1: - res = PQgetResult(obj->intern->conn->intern->conn); + if (SUCCESS == rv) { + php_pqcopy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - if (res) { - if (SUCCESS == php_pqres_success(res TSRMLS_CC)) { - RETVAL_FALSE; - } + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\COPY not initialized"); + } else if (obj->intern->direction != PHP_PQCOPY_TO_STDOUT) { + throw_exce(EX_RUNTIME TSRMLS_CC, "pq\\COPY was not intialized with TO_STDOUT"); + } else { + PGresult *res; + char *buffer = NULL; + int bytes = PQgetCopyData(obj->intern->conn->intern->conn, &buffer, 0); - PHP_PQclear(res); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get COPY result (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - } - break; + switch (bytes) { + case -2: + throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to fetch COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); + break; - case -2: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get COPY data (%s)", PHP_PQerrorMessage(obj->intern->conn->intern->conn)); - break; + case -1: + res = PQgetResult(obj->intern->conn->intern->conn); - default: - zval_dtor(zdata); - if (buffer) { - ZVAL_STRINGL(zdata, buffer, bytes, 1); - } else { - ZVAL_EMPTY_STRING(zdata); - } - RETVAL_TRUE; - break; + if (!res) { + 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); + RETVAL_FALSE; } + break; + default: + zval_dtor(zdata); if (buffer) { - PQfreemem(buffer); + ZVAL_STRINGL(zdata, buffer, bytes, 1); + } else { + ZVAL_EMPTY_STRING(zdata); } + RETVAL_TRUE; + break; + } + + if (buffer) { + PQfreemem(buffer); } } } - zend_restore_error_handling(&zeh TSRMLS_CC); } static zend_function_entry php_pqcopy_methods[] = { @@ -4762,6 +5123,10 @@ static zend_function_entry php_pqcopy_methods[] = { {0} }; +static zend_function_entry php_pqexc_methods[] = { + {0} +}; + /* {{{ PHP_MINIT_FUNCTION */ static PHP_MINIT_FUNCTION(pq) @@ -4769,6 +5134,41 @@ static PHP_MINIT_FUNCTION(pq) zend_class_entry ce = {0}; php_pq_object_prophandler_t ph = {0}; + INIT_NS_CLASS_ENTRY(ce, "pq", "Exception", php_pqexc_methods); + php_pqexc_interface_class_entry = zend_register_internal_interface(&ce TSRMLS_CC); + + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("INVALID_ARGUMENT"), EX_INVALID_ARGUMENT TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("RUNTIME"), EX_RUNTIME TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("CONNECTION_FAILED"), EX_CONNECTION_FAILED TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("IO"), EX_IO TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("ESCAPE"), EX_ESCAPE TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("BAD_METHODCALL"), EX_BAD_METHODCALL TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("UNINITIALIZED"), EX_UNINITIALIZED TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("DOMAIN"), EX_DOMAIN TSRMLS_CC); + zend_declare_class_constant_long(php_pqexc_interface_class_entry, ZEND_STRL("SQL"), EX_SQL TSRMLS_CC); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "InvalidArgumentException", php_pqexc_methods); + php_pqexc_invalid_argument_class_entry = zend_register_internal_class_ex(&ce, spl_ce_InvalidArgumentException, "InvalidArgumentException" TSRMLS_CC); + zend_class_implements(php_pqexc_invalid_argument_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "RuntimeException", php_pqexc_methods); + php_pqexc_runtime_class_entry = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException, "RuntimeException" TSRMLS_CC); + zend_class_implements(php_pqexc_runtime_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "BadMethodCallException", php_pqexc_methods); + php_pqexc_bad_methodcall_class_entry = zend_register_internal_class_ex(&ce, spl_ce_BadMethodCallException, "BadMethodCallException" TSRMLS_CC); + zend_class_implements(php_pqexc_bad_methodcall_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry); + + memset(&ce, 0, sizeof(ce)); + INIT_NS_CLASS_ENTRY(ce, "pq\\Exception", "DomainException", php_pqexc_methods); + php_pqexc_domain_class_entry = zend_register_internal_class_ex(&ce, spl_ce_DomainException, "DomainException" TSRMLS_CC); + zend_class_implements(php_pqexc_domain_class_entry TSRMLS_CC, 1, php_pqexc_interface_class_entry); + zend_declare_property_null(php_pqexc_domain_class_entry, ZEND_STRL("sqlstate"), ZEND_ACC_PUBLIC TSRMLS_CC); + + memset(&ce, 0, sizeof(ce)); INIT_NS_CLASS_ENTRY(ce, "pq", "Connection", php_pqconn_methods); php_pqconn_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); php_pqconn_class_entry->create_object = php_pqconn_create_object; @@ -4780,7 +5180,7 @@ static PHP_MINIT_FUNCTION(pq) php_pqconn_object_handlers.get_property_ptr_ptr = NULL; php_pqconn_object_handlers.get_debug_info = php_pq_object_debug_info; - zend_hash_init(&php_pqconn_object_prophandlers, 13, NULL, NULL, 1); + zend_hash_init(&php_pqconn_object_prophandlers, 14, NULL, NULL, 1); zend_declare_property_long(php_pqconn_class_entry, ZEND_STRL("status"), CONNECTION_BAD, ZEND_ACC_PUBLIC TSRMLS_CC); ph.read = php_pqconn_object_read_status; @@ -4838,6 +5238,10 @@ static PHP_MINIT_FUNCTION(pq) ph.read = php_pqconn_object_read_options; zend_hash_add(&php_pqconn_object_prophandlers, "options", sizeof("options"), (void *) &ph, sizeof(ph), NULL); + zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("eventHandlers"), ZEND_ACC_PUBLIC TSRMLS_CC); + ph.read = php_pqconn_object_read_event_handlers; + zend_hash_add(&php_pqconn_object_prophandlers, "eventHandlers", sizeof("eventHandlers"), (void *) &ph, sizeof(ph), NULL); + zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK TSRMLS_CC); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD TSRMLS_CC); zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED TSRMLS_CC); @@ -4904,6 +5308,10 @@ static PHP_MINIT_FUNCTION(pq) ph.read = php_pqres_object_read_status; zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL); + zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC TSRMLS_CC); + ph.read = php_pqres_object_read_status_message; + zend_hash_add(&php_pqres_object_prophandlers, "statusMessage", sizeof("statusMessage"), (void *) &ph, sizeof(ph), NULL); + zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC); ph.read = php_pqres_object_read_error_message; zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL); @@ -4986,19 +5394,19 @@ static PHP_MINIT_FUNCTION(pq) ph.write = php_pqtxn_object_write_isolation; zend_hash_add(&php_pqtxn_object_prophandlers, "isolation", sizeof("isolation"), (void *) &ph, sizeof(ph), NULL); - zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("readonly"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_bool(php_pqtxn_class_entry, ZEND_STRL("readonly"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); ph.read = php_pqtxn_object_read_readonly; ph.write = php_pqtxn_object_write_readonly; zend_hash_add(&php_pqtxn_object_prophandlers, "readonly", sizeof("readonly"), (void *) &ph, sizeof(ph), NULL); - zend_declare_property_null(php_pqtxn_class_entry, ZEND_STRL("deferrable"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_bool(php_pqtxn_class_entry, ZEND_STRL("deferrable"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); ph.read = php_pqtxn_object_read_deferrable; ph.write = php_pqtxn_object_write_deferrable; zend_hash_add(&php_pqtxn_object_prophandlers, "deferrable", sizeof("deferrable"), (void *) &ph, sizeof(ph), NULL); ph.write = NULL; zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("READ_COMMITTED"), PHP_PQTXN_READ_COMMITTED TSRMLS_CC); - zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("REPEATABLE READ"), PHP_PQTXN_REPEATABLE_READ TSRMLS_CC); + zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("REPEATABLE_READ"), PHP_PQTXN_REPEATABLE_READ TSRMLS_CC); zend_declare_class_constant_long(php_pqtxn_class_entry, ZEND_STRL("SERIALIZABLE"), PHP_PQTXN_SERIALIZABLE TSRMLS_CC); memset(&ce, 0, sizeof(ce)); @@ -5031,11 +5439,7 @@ static PHP_MINIT_FUNCTION(pq) 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, 2, NULL, NULL, 1); - - zend_declare_property_null(php_pqevent_class_entry, ZEND_STRL("connection"), ZEND_ACC_PUBLIC TSRMLS_CC); - ph.read = php_pqevent_object_read_connection; - zend_hash_add(&php_pqevent_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL); + 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;