X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-pq;a=blobdiff_plain;f=src%2Fphp_pqres.c;h=849f8bff65f22cbdc3ef2f42e9a511e227c992d1;hp=b365f3d2e36a1379f40fad1745775550bf4631a2;hb=5ba3107011d4050d5ae5877dae80e382dc228e6a;hpb=d613997b3072b8093bca3fe9d8aca115e2a579aa diff --git a/src/php_pqres.c b/src/php_pqres.c index b365f3d..849f8bf 100644 --- a/src/php_pqres.c +++ b/src/php_pqres.c @@ -17,6 +17,10 @@ #include #include +#if PHP_PQ_HAVE_PHP_JSON_H +#include /* we've added the include directory to INCLUDES */ +#endif + #include #include "php_pq.h" @@ -24,59 +28,87 @@ #include "php_pq_object.h" #include "php_pqexc.h" #include "php_pqres.h" +#undef PHP_PQ_TYPE +#include "php_pq_type.h" zend_class_entry *php_pqres_class_entry; static zend_object_handlers php_pqres_object_handlers; static HashTable php_pqres_object_prophandlers; static zend_object_iterator_funcs php_pqres_iterator_funcs; -static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) +static inline zend_object_iterator *php_pqres_iterator_init_ex(zend_class_entry *ce, zval *object, int by_ref) { php_pqres_iterator_t *iter; - zval *prop, *zfetch_type; + zval tmp, *zfetch_type; iter = ecalloc(1, sizeof(*iter)); iter->zi.funcs = &php_pqres_iterator_funcs; - iter->zi.data = object; - /* do not addref, because the iterator lives inside this object anyway */ - - zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC); - if (Z_TYPE_P(zfetch_type) != IS_LONG) { - convert_to_long_ex(&zfetch_type); - } - iter->fetch_type = Z_LVAL_P(zfetch_type); - if (zfetch_type != prop) { - zval_ptr_dtor(&zfetch_type); - } - if (Z_REFCOUNT_P(prop)) { - zval_ptr_dtor(&prop); - } else { - zval_dtor(prop); - FREE_ZVAL(prop); - } + ZVAL_COPY_VALUE(&iter->zi.data, object); + zfetch_type = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0, &tmp); + iter->fetch_type = zval_get_long(zfetch_type); +#if DBG_GC + fprintf(stderr, "INIT iter(#%d) %p res(#%d) %p\n", iter->zi.std.handle, iter, Z_OBJ_HANDLE_P(object), PHP_PQ_OBJ(object, NULL)); +#endif return (zend_object_iterator *) iter; } -static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC) +static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval *object, int by_ref) +{ + zend_object_iterator *iter = php_pqres_iterator_init_ex(ce, object, by_ref); + + zend_iterator_init(iter); + Z_ADDREF_P(object); + + return iter; +} +static void php_pqres_internal_iterator_init(zval *zobj) +{ + php_pqres_object_t *obj = PHP_PQ_OBJ(zobj, NULL); + + obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init_ex(Z_OBJCE_P(zobj), zobj, 0); + obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter); + +} + +static inline void php_pqres_iterator_dtor_ex(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; - if (iter->current_val) { +#if DBG_GC + fprintf(stderr, "FREE iter(#%d) rc=%d %p\n", iter->zi.std.handle, GC_REFCOUNT(&iter->zi.std), iter); +#endif + if (!Z_ISUNDEF(iter->current_val)) { zval_ptr_dtor(&iter->current_val); - iter->current_val = NULL; + ZVAL_UNDEF(&iter->current_val); } - efree(iter); } -static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC) +static void php_pqres_iterator_dtor(zend_object_iterator *i) +{ + php_pqres_iterator_dtor_ex(i); + zval_ptr_dtor(&i->data); +} + +static void php_pqres_internal_iterator_dtor(php_pqres_object_t *obj) +{ + if (obj->intern && obj->intern->iter) { + php_pqres_iterator_dtor_ex((zend_object_iterator *) obj->intern->iter); + efree(obj->intern->iter); + obj->intern->iter = NULL; + } +} + +static ZEND_RESULT_CODE php_pqres_iterator_valid(zend_object_iterator *i) { 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); + php_pqres_object_t *obj = PHP_PQ_OBJ(&i->data, NULL); switch (PQresultStatus(obj->intern->res)) { case PGRES_TUPLES_OK: +#ifdef HAVE_PGRES_SINGLE_TUPLE case PGRES_SINGLE_TUPLE: +#endif if (PQntuples(obj->intern->res) <= iter->index) { return FAILURE; } @@ -88,134 +120,247 @@ static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC) return SUCCESS; } -zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval **data_ptr TSRMLS_DC) +#define PHP_PQRES_JSON_OPTIONS(res) \ + (php_pqres_fetch_type(res) != PHP_PQRES_FETCH_OBJECT ? PHP_JSON_OBJECT_AS_ARRAY:0) + +zval *php_pqres_typed_zval(php_pqres_t *res, Oid typ, zval *zv) { - zval *data = NULL; - int c, cols; - php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event); + zval *zconv; + HashTable *ht; + zend_string *str; + + if ((zconv = zend_hash_index_find(&res->converters, typ))) { + zval ztype, rv; + + ZVAL_NULL(&rv); + ZVAL_LONG(&ztype, typ); + zend_call_method_with_2_params(zconv, NULL, NULL, "convertfromstring", &rv, zv, &ztype); + + zval_ptr_dtor(zv); + ZVAL_ZVAL(zv, &rv, 0, 0); - if (data_ptr) { - data = *data_ptr; + return zv; } - if (!data) { - MAKE_STD_ZVAL(data); - if (PHP_PQRES_FETCH_OBJECT == fetch_type) { - object_init(data); - } else { - array_init(data); + + str = zval_get_string(zv); + zval_ptr_dtor(zv); + + switch (typ) { + case PHP_PQ_OID_BOOL: + if (!(res->auto_convert & PHP_PQRES_CONV_BOOL)) { + goto noconversion; } - if (data_ptr) { - *data_ptr = data; + ZVAL_BOOL(zv, *str->val == 't'); + break; + + case PHP_PQ_OID_INT8: + case PHP_PQ_OID_TID: + case PHP_PQ_OID_INT4: + case PHP_PQ_OID_INT2: + case PHP_PQ_OID_XID: + case PHP_PQ_OID_OID: + if (!(res->auto_convert & PHP_PQRES_CONV_INT)) { + goto noconversion; } - } + { + zend_long lval; + double dval; - if (PQntuples(res) > row) { - for (c = 0, cols = PQnfields(res); c < cols; ++c) { - if (PQgetisnull(res, row, c)) { - switch (fetch_type) { - case PHP_PQRES_FETCH_OBJECT: - add_property_null(data, PQfname(res, c)); + switch (is_numeric_str_function(str, &lval, &dval)) { + case IS_LONG: + ZVAL_LONG(zv, lval); break; - - case PHP_PQRES_FETCH_ASSOC: - add_assoc_null(data, PQfname(res, c)); + case IS_DOUBLE: + ZVAL_DOUBLE(zv, dval); break; + default: + goto noconversion; + } + } + break; - case PHP_PQRES_FETCH_ARRAY: - add_index_null(data, c); - break; - } - } else { - zval *zv, **zconv; + case PHP_PQ_OID_FLOAT4: + case PHP_PQ_OID_FLOAT8: + if (!(res->auto_convert & PHP_PQRES_CONV_FLOAT)) { + goto noconversion; + } + ZVAL_DOUBLE(zv, zend_strtod(str->val, NULL)); + break; + + case PHP_PQ_OID_DATE: + if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { + goto noconversion; + } + php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d", NULL); + break; +#ifdef PHP_PQ_OID_ABSTIME + case PHP_PQ_OID_ABSTIME: + if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { + goto noconversion; + } + php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s", NULL); + break; +#endif + case PHP_PQ_OID_TIMESTAMP: + if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { + goto noconversion; + } + php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.u", NULL); + break; - if (res_obj && (SUCCESS == zend_hash_index_find(&res_obj->intern->converters, PQftype(res, c), (void *) &zconv))) { - zval *tmp = NULL; + case PHP_PQ_OID_TIMESTAMPTZ: + if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) { + goto noconversion; + } + php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.uO", NULL); + break; - MAKE_STD_ZVAL(zv); - ZVAL_STRINGL(zv, PQgetvalue(res, row, c), PQgetlength(res, row, c), 1); - zend_call_method_with_1_params(zconv, NULL, NULL, "convertfromstring", &tmp, zv); +#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON) +# ifdef PHP_PQ_OID_JSONB + case PHP_PQ_OID_JSONB: +# endif + case PHP_PQ_OID_JSON: + if (!(res->auto_convert & PHP_PQRES_CONV_JSON)) { + goto noconversion; + } + php_json_decode_ex(zv, str->val, str->len, PHP_PQRES_JSON_OPTIONS(res), 512 /* PHP_JSON_DEFAULT_DEPTH */); + break; +#endif - if (tmp) { - zval_ptr_dtor(&zv); - zv = tmp; - } - } else { - zv = php_pq_typed_zval(PQgetvalue(res, row, c), PQgetlength(res, row, c), PQftype(res, c) TSRMLS_CC); - } + default: + if (!(res->auto_convert & PHP_PQRES_CONV_ARRAY)) { + goto noconversion; + } + if (PHP_PQ_TYPE_IS_ARRAY(typ) && (ht = php_pq_parse_array(res, str->val, str->len, PHP_PQ_TYPE_OF_ARRAY(typ)))) { + ZVAL_ARR(zv, ht); + } else { + goto noconversion; + } + break; + } - switch (fetch_type) { - case PHP_PQRES_FETCH_OBJECT: - add_property_zval(data, PQfname(res, c), zv); - zval_ptr_dtor(&zv); - break; + zend_string_release(str); + return zv; - case PHP_PQRES_FETCH_ASSOC: - add_assoc_zval(data, PQfname(res, c), zv); - break; + noconversion: + ZVAL_STR(zv, str); + return zv; +} - case PHP_PQRES_FETCH_ARRAY: - add_index_zval(data, c, zv); - break; - } - } - } +static inline zval *php_pqres_get_col(php_pqres_t *r, unsigned row, unsigned col, zval *zv) +{ + if (PQgetisnull(r->res, row, col)) { + ZVAL_NULL(zv); + } else { + ZVAL_STRINGL(zv, PQgetvalue(r->res, row, col), PQgetlength(r->res, row, col)); + zv = php_pqres_typed_zval(r, PQftype(r->res, col), zv); } - return data; + return zv; } -static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr TSRMLS_DC) +static inline void php_pqres_add_col_to_zval(php_pqres_t *r, unsigned row, unsigned col, php_pqres_fetch_t fetch_type, zval *data) { - 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 (PQgetisnull(r->res, row, col)) { + switch (fetch_type) { + case PHP_PQRES_FETCH_OBJECT: + add_property_null(data, PQfname(r->res, col)); + break; + + case PHP_PQRES_FETCH_ASSOC: + add_assoc_null(data, PQfname(r->res, col)); + break; + + case PHP_PQRES_FETCH_ARRAY: + add_index_null(data, col); + break; + } + } else { + zval zv; + + ZVAL_STRINGL(&zv, PQgetvalue(r->res, row, col), PQgetlength(r->res, row, col)); + php_pqres_typed_zval(r, PQftype(r->res, col), &zv); + + switch (fetch_type) { + case PHP_PQRES_FETCH_OBJECT: + add_property_zval(data, PQfname(r->res, col), &zv); + zval_ptr_dtor(&zv); + break; + + case PHP_PQRES_FETCH_ASSOC: + add_assoc_zval(data, PQfname(r->res, col), &zv); + break; - if (!iter->current_val) { - iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC); + case PHP_PQRES_FETCH_ARRAY: + add_index_zval(data, col, &zv); + break; + } } - *data_ptr = &iter->current_val; } -#if PHP_VERSION_ID >= 50500 -static void php_pqres_iterator_key(zend_object_iterator *i, zval *key TSRMLS_DC) +zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval *data) { - php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; + int c, cols = PQnfields(res); + php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event); - ZVAL_LONG(key, iter->index); + if (Z_TYPE_P(data) != IS_OBJECT && Z_TYPE_P(data) != IS_ARRAY) { + if (PHP_PQRES_FETCH_OBJECT == fetch_type) { + object_init(data); + } else { + array_init_size(data, cols); + } + } + + if (PQntuples(res) > row) { + for (c = 0; c < cols; ++c) { + php_pqres_add_col_to_zval(res_obj->intern, row, c, fetch_type, data); + } + } + + return data; } -#else -static int php_pqres_iterator_key(zend_object_iterator *i, char **key_str, uint *key_len, ulong *key_num TSRMLS_DC) + +static zval *php_pqres_iterator_current(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; + php_pqres_object_t *obj = PHP_PQ_OBJ(&i->data, NULL); - *key_num = (ulong) iter->index; + if (Z_ISUNDEF(iter->current_val)) { + php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, &iter->current_val); + } + return &iter->current_val; +} - return HASH_KEY_IS_LONG; +static void php_pqres_iterator_key(zend_object_iterator *i, zval *key) +{ + php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; + + ZVAL_LONG(key, iter->index); } -#endif -static void php_pqres_iterator_invalidate(zend_object_iterator *i TSRMLS_DC) +static void php_pqres_iterator_invalidate(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; - if (iter->current_val) { + if (!Z_ISUNDEF(iter->current_val)) { zval_ptr_dtor(&iter->current_val); - iter->current_val = NULL; + ZVAL_UNDEF(&iter->current_val); } } -static void php_pqres_iterator_next(zend_object_iterator *i TSRMLS_DC) +static void php_pqres_iterator_next(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; - php_pqres_iterator_invalidate(i TSRMLS_CC); + php_pqres_iterator_invalidate(i); ++iter->index; } -static void php_pqres_iterator_rewind(zend_object_iterator *i TSRMLS_DC) +static void php_pqres_iterator_rewind(zend_object_iterator *i) { php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i; - php_pqres_iterator_invalidate(i TSRMLS_CC); + php_pqres_iterator_invalidate(i); iter->index = 0; } @@ -235,9 +380,9 @@ static zend_object_iterator_funcs php_pqres_iterator_funcs = { php_pqres_iterator_invalidate }; -static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC) +static ZEND_RESULT_CODE php_pqres_count_elements(zval *object, long *count) { - php_pqres_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); + php_pqres_object_t *obj = PHP_PQ_OBJ(object, NULL); if (!obj->intern) { return FAILURE; @@ -247,48 +392,50 @@ static int php_pqres_count_elements(zval *object, long *count TSRMLS_DC) } } -STATUS php_pqres_success(PGresult *res TSRMLS_DC) +ZEND_RESULT_CODE php_pqres_success(PGresult *res) { - zval *zexc; + zval zexc; switch (PQresultStatus(res)) { case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: - zexc = throw_exce(EX_SQL TSRMLS_CC, "%s", PHP_PQresultErrorMessage(res)); - zend_update_property_string(Z_OBJCE_P(zexc), zexc, ZEND_STRL("sqlstate"), PQresultErrorField(res, PG_DIAG_SQLSTATE) TSRMLS_CC); + ZVAL_OBJ(&zexc, throw_exce(EX_SQL, "%s", PHP_PQresultErrorMessage(res))); + zend_update_property_string(Z_OBJCE(zexc), &zexc, ZEND_STRL("sqlstate"), PQresultErrorField(res, PG_DIAG_SQLSTATE)); return FAILURE; default: return SUCCESS; } } -void php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *conn_obj, php_pqres_object_t **ptr TSRMLS_DC) +php_pqres_object_t *php_pqres_init_instance_data(PGresult *res, php_pqconn_object_t *conn_obj) { php_pqres_object_t *obj; php_pqres_t *r = ecalloc(1, sizeof(*r)); r->res = res; zend_hash_init(&r->bound, 0, 0, ZVAL_PTR_DTOR, 0); - zend_hash_init(&r->converters, 0, 0, ZVAL_PTR_DTOR, 0); - zend_hash_copy(&r->converters, &conn_obj->intern->converters, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + zend_hash_init(&r->converters, zend_hash_num_elements(&conn_obj->intern->converters), 0, ZVAL_PTR_DTOR, 0); + zend_hash_copy(&r->converters, &conn_obj->intern->converters, (copy_ctor_func_t) zval_add_ref); + r->auto_convert = conn_obj->intern->default_auto_convert; r->default_fetch_type = conn_obj->intern->default_fetch_type; - php_pqres_create_object_ex(php_pqres_class_entry, r, &obj TSRMLS_CC); + obj = php_pqres_create_object_ex(php_pqres_class_entry, r); PQresultSetInstanceData(res, php_pqconn_event, obj); - if (ptr) { - *ptr = obj; - } + return obj; } -static void php_pqres_object_free(void *o TSRMLS_DC) +php_pqres_fetch_t php_pqres_fetch_type(php_pqres_t *res) { - php_pqres_object_t *obj = o; -#if DBG_GC - fprintf(stderr, "FREE res(#%d) %p\n", obj->zv.handle, obj); -#endif + return res->iter ? res->iter->fetch_type : res->default_fetch_type; +} + +static void php_pqres_object_free(zend_object *o) +{ + php_pqres_object_t *obj = PHP_PQ_OBJ(NULL, o); + if (obj->intern) { if (obj->intern->res) { PQresultSetInstanceData(obj->intern->res, php_pqconn_event, NULL); @@ -296,10 +443,7 @@ static void php_pqres_object_free(void *o TSRMLS_DC) obj->intern->res = NULL; } - if (obj->intern->iter) { - php_pqres_iterator_dtor((zend_object_iterator *) obj->intern->iter TSRMLS_CC); - obj->intern->iter = NULL; - } + php_pqres_internal_iterator_dtor(obj); zend_hash_destroy(&obj->intern->bound); zend_hash_destroy(&obj->intern->converters); @@ -307,143 +451,190 @@ static void php_pqres_object_free(void *o TSRMLS_DC) efree(obj->intern); obj->intern = NULL; } - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(obj); + php_pq_object_dtor(o); } -zend_object_value php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern, php_pqres_object_t **ptr TSRMLS_DC) +php_pqres_object_t *php_pqres_create_object_ex(zend_class_entry *ce, php_pqres_t *intern) { - php_pqres_object_t *o; - - o = ecalloc(1, sizeof(*o)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - o->prophandler = &php_pqres_object_prophandlers; - - if (ptr) { - *ptr = o; - } - - if (intern) { - o->intern = intern; - } - - o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_pqres_object_free, NULL TSRMLS_CC); - o->zv.handlers = &php_pqres_object_handlers; - - return o->zv; + return php_pq_object_create(ce, intern, sizeof(php_pqres_object_t), + &php_pqres_object_handlers, &php_pqres_object_prophandlers); } -static zend_object_value php_pqres_create_object(zend_class_entry *class_type TSRMLS_DC) +static zend_object *php_pqres_create_object(zend_class_entry *class_type) { - return php_pqres_create_object_ex(class_type, NULL, NULL TSRMLS_CC); + return &php_pqres_create_object_ex(class_type, NULL)->zo; } -static void php_pqres_object_read_status(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_status(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(PQresultStatus(obj->intern->res)); } -static void php_pqres_object_read_status_message(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_status_message(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; - RETVAL_STRING(PQresStatus(PQresultStatus(obj->intern->res))+sizeof("PGRES"), 1); + RETVAL_STRING(PQresStatus(PQresultStatus(obj->intern->res))+sizeof("PGRES")); } -static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_error_message(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; char *error = PHP_PQresultErrorMessage(obj->intern->res); if (error) { - RETVAL_STRING(error, 1); + RETVAL_STRING(error); } else { RETVAL_NULL(); } } -static void php_pqres_object_read_num_rows(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_diag(zval *object, void *o, zval *return_value) +{ + php_pqres_object_t *obj = o; + int i; + struct { + char code; + const char *const name; + } diag[] = { +#ifdef PG_DIAG_SEVERITY + {PG_DIAG_SEVERITY, "severity"}, +#endif +#ifdef PG_DIAG_SQLSTATE + {PG_DIAG_SQLSTATE, "sqlstate"}, +#endif +#ifdef PG_DIAG_MESSAGE_PRIMARY + {PG_DIAG_MESSAGE_PRIMARY, "message_primary"}, +#endif +#ifdef PG_DIAG_MESSAGE_DETAIL + {PG_DIAG_MESSAGE_DETAIL, "message_detail"}, +#endif +#ifdef PG_DIAG_MESSAGE_HINT + {PG_DIAG_MESSAGE_HINT, "message_hint"}, +#endif +#ifdef PG_DIAG_STATEMENT_POSITION + {PG_DIAG_STATEMENT_POSITION,"statement_position"}, +#endif +#ifdef PG_DIAG_INTERNAL_POSITION + {PG_DIAG_INTERNAL_POSITION, "internal_position"}, +#endif +#ifdef PG_DIAG_INTERNAL_QUERY + {PG_DIAG_INTERNAL_QUERY, "internal_query"}, +#endif +#ifdef PG_DIAG_CONTEXT + {PG_DIAG_CONTEXT, "context"}, +#endif +#ifdef PG_DIAG_SCHEMA_NAME + {PG_DIAG_SCHEMA_NAME, "schema_name"}, +#endif +#ifdef PG_DIAG_TABLE_NAME + {PG_DIAG_TABLE_NAME, "table_name"}, +#endif +#ifdef PG_DIAG_COLUMN_NAME + {PG_DIAG_COLUMN_NAME, "column_name"}, +#endif +#ifdef PG_DIAG_DATATYPE_NAME + {PG_DIAG_DATATYPE_NAME, "datatype_name"}, +#endif +#ifdef PG_DIAG_CONSTRAINT_NAME + {PG_DIAG_CONSTRAINT_NAME, "constraint_name"}, +#endif +#ifdef PG_DIAG_SOURCE_FILE + {PG_DIAG_SOURCE_FILE, "source_file"}, +#endif +#ifdef PG_DIAG_SOURCE_LINE + {PG_DIAG_SOURCE_LINE, "source_line"}, +#endif +#ifdef PG_DIAG_SOURCE_FUNCTION + {PG_DIAG_SOURCE_FUNCTION, "source_function"}, +#endif + }; + + array_init_size(return_value, 32); + for (i = 0; i < sizeof(diag)/sizeof(diag[0]); ++i) { + char *value = PQresultErrorField(obj->intern->res, diag[i].code); + + if (value) { + add_assoc_string(return_value, diag[i].name, value); + } else { + add_assoc_null(return_value, diag[i].name); + } + } +} + +static void php_pqres_object_read_num_rows(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(PQntuples(obj->intern->res)); } -static void php_pqres_object_read_num_cols(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_num_cols(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(PQnfields(obj->intern->res)); } -static void php_pqres_object_read_affected_rows(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_affected_rows(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; RETVAL_LONG(atoi(PQcmdTuples(obj->intern->res))); } -static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return_value TSRMLS_DC) +static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return_value) { php_pqres_object_t *obj = o; - if (obj->intern->iter) { - RETVAL_LONG(obj->intern->iter->fetch_type); - } else { - RETVAL_LONG(obj->intern->default_fetch_type); - } + RETVAL_LONG(php_pqres_fetch_type(obj->intern)); } -static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value TSRMLS_DC) +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(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) { - obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(object), object, 0 TSRMLS_CC); - obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC); + php_pqres_internal_iterator_init(object); } - obj->intern->iter->fetch_type = Z_LVAL_P(zfetch_type); + obj->intern->iter->fetch_type = zval_get_long(value); +} - if (zfetch_type != value) { - zval_ptr_dtor(&zfetch_type); - } +static void php_pqres_object_read_auto_conv(zval *object, void *o, zval *return_value) +{ + php_pqres_object_t *obj = o; + + RETVAL_LONG(obj->intern->auto_convert); } -static STATUS php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval ***row TSRMLS_DC) +static void php_pqres_object_write_auto_conv(zval *object, void *o, zval *value) { - STATUS rv; + php_pqres_object_t *obj = o; + + obj->intern->auto_convert = zval_get_long(value); +} + +static ZEND_RESULT_CODE php_pqres_iteration(zval *zobj, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval *row) +{ + ZEND_RESULT_CODE rv; php_pqres_fetch_t orig_fetch; if (!obj) { - obj = zend_object_store_get_object(getThis() TSRMLS_CC); + obj = PHP_PQ_OBJ(zobj, NULL); } if (obj->intern->iter) { - obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter TSRMLS_CC); + obj->intern->iter->zi.funcs->move_forward((zend_object_iterator *) obj->intern->iter); } else { - obj->intern->iter = (php_pqres_iterator_t *) php_pqres_iterator_init(Z_OBJCE_P(getThis()), getThis(), 0 TSRMLS_CC); - obj->intern->iter->zi.funcs->rewind((zend_object_iterator *) obj->intern->iter TSRMLS_CC); + php_pqres_internal_iterator_init(zobj); } orig_fetch = obj->intern->iter->fetch_type; obj->intern->iter->fetch_type = fetch_type; - if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter TSRMLS_CC))) { - obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter, row TSRMLS_CC); + if (SUCCESS == (rv = obj->intern->iter->zi.funcs->valid((zend_object_iterator *) obj->intern->iter))) { + zval *tmp = obj->intern->iter->zi.funcs->get_current_data((zend_object_iterator *) obj->intern->iter); + ZVAL_COPY_VALUE(row, tmp); } obj->intern->iter->fetch_type = orig_fetch; @@ -455,25 +646,33 @@ typedef struct php_pqres_col { int num; } php_pqres_col_t; -static STATUS column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *col TSRMLS_DC) +static ZEND_RESULT_CODE column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *col) { - long index = -1; + zend_long index = -1; char *name = NULL; - switch (Z_TYPE_P(zcol)) { - case IS_LONG: - index = Z_LVAL_P(zcol); - break; - - default: - convert_to_string(zcol); - /* no break */ - - case IS_STRING: - if (!is_numeric_string(Z_STRVAL_P(zcol), Z_STRLEN_P(zcol), &index, NULL, 0)) { - name = Z_STRVAL_P(zcol); + if (!zcol) { + index = 0; + } else { + switch (Z_TYPE_P(zcol)) { + case IS_NULL: + index = 0; + break; + + case IS_LONG: + index = Z_LVAL_P(zcol); + break; + + default: + convert_to_string(zcol); + /* no break */ + + case IS_STRING: + if (!is_numeric_string(Z_STRVAL_P(zcol), Z_STRLEN_P(zcol), &index, NULL, 0)) { + name = Z_STRVAL_P(zcol); + } + break; } - break; } if (name) { @@ -485,11 +684,11 @@ static STATUS column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *co } if (!col->name) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column at index %ld", index); + php_error_docref(NULL, E_WARNING, "Failed to find column at index %ld", index); return FAILURE; } if (col->num == -1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to find column with name '%s'", name); + php_error_docref(NULL, E_WARNING, "Failed to find column with name '%s'", name); return FAILURE; } return SUCCESS; @@ -501,25 +700,31 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqres_bind, 0, 0, 2) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, bind) { zval *zcol, *zref; + zend_error_handling zeh; + ZEND_RESULT_CODE rv; - 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); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z/z", &zcol, &zref); + zend_restore_error_handling(&zeh); + + if (SUCCESS == rv) { + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "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)) { RETVAL_FALSE; } else { - Z_ADDREF_P(zref); + Z_TRY_ADDREF_P(zref); - 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); + if (!zend_hash_index_update(&obj->intern->bound, col.num, zref)) { + php_error_docref(NULL, 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); + zend_hash_sort(&obj->intern->bound, php_pq_compare_index, 0); RETVAL_TRUE; } } @@ -527,23 +732,20 @@ static PHP_METHOD(pqres, bind) { } } -static int apply_bound(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) +static int apply_bound(zval *zbound, int argc, va_list argv, zend_hash_key *key) { - zval **zvalue, **zbound = p; - zval **zrow = va_arg(argv, zval **); - STATUS *rv = va_arg(argv, STATUS *); + zval *zvalue; + zval *zrow = va_arg(argv, zval *); + ZEND_RESULT_CODE *rv = va_arg(argv, ZEND_RESULT_CODE *); - 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); + if (!(zvalue = zend_hash_index_find(Z_ARRVAL_P(zrow), key->h))) { + php_error_docref(NULL, 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; + ZVAL_DEREF(zbound); + zval_dtor(zbound); + ZVAL_COPY(zbound, zvalue); *rv = SUCCESS; return ZEND_HASH_APPLY_KEEP; } @@ -553,31 +755,29 @@ 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_RESULT_CODE rv; - zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); rv = zend_parse_parameters_none(); - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_restore_error_handling(&zeh); if (SUCCESS == rv) { - php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { - zval **row = NULL; + zval 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); + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); + if (SUCCESS == php_pqres_iteration(getThis(), obj, PHP_PQRES_FETCH_ARRAY, &row)) { + zend_hash_apply_with_arguments(&obj->intern->bound, apply_bound, 2, &row, &rv); - if (SUCCESS != rv) { - zval_ptr_dtor(row); - } else { - RETVAL_ZVAL(*row, 1, 0); + if (SUCCESS == rv) { + RETVAL_ZVAL(&row, 1, 0); } } + zend_restore_error_handling(&zeh); } } } @@ -587,131 +787,165 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_row, 0, 0, 0) ZEND_END_ARG_INFO(); 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; + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); + zend_long fetch_type = -1; + ZEND_RESULT_CODE rv; - 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); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type); + zend_restore_error_handling(&zeh); if (SUCCESS == rv) { if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { - zval **row = NULL; + zval row; if (fetch_type == -1) { - fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : obj->intern->default_fetch_type; + fetch_type = php_pqres_fetch_type(obj->intern); } - 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); + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); + if (SUCCESS == php_pqres_iteration(getThis(), obj, fetch_type, &row)) { + RETVAL_ZVAL(&row, 1, 0); } + zend_restore_error_handling(&zeh); } } } -static zval **column_at(zval *row, int col TSRMLS_DC) +static zval *column_at(zval *row, int col) { - zval **data = NULL; + zval *data = NULL; HashTable *ht = HASH_OF(row); int count = zend_hash_num_elements(ht); if (col >= count) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column index %d exceeds column count %d", col, count); + php_error_docref(NULL, 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); + data = zend_hash_get_current_data(ht); } return data; } -ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 2) - ZEND_ARG_INFO(0, col) +ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 1) ZEND_ARG_INFO(1, ref) + ZEND_ARG_INFO(0, col) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchCol) { zend_error_handling zeh; - zval *zcol, *zref; - STATUS rv; + zval *zcol = NULL, *zref; + ZEND_RESULT_CODE 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", &zcol, &zref); - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters(ZEND_NUM_ARGS(), "z|z/!", &zref, &zcol); + zend_restore_error_handling(&zeh); if (SUCCESS == rv) { - php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { - zval **row = NULL; + zval row; - 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) { - RETVAL_FALSE; - } else { + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); + if (SUCCESS == php_pqres_iteration(getThis(), obj, php_pqres_fetch_type(obj->intern), &row)) { php_pqres_col_t col; - if (SUCCESS != column_nn(obj, zcol, &col TSRMLS_CC)) { + if (SUCCESS != column_nn(obj, zcol, &col)) { RETVAL_FALSE; } else { - zval **zres = column_at(*row, col.num TSRMLS_CC); + zval *zres = column_at(&row, col.num); if (!zres) { RETVAL_FALSE; } else { + ZVAL_DEREF(zref); zval_dtor(zref); - ZVAL_ZVAL(zref, *zres, 1, 0); + ZVAL_ZVAL(zref, zres, 1, 0); RETVAL_TRUE; } } } - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_restore_error_handling(&zeh); } } } -static int apply_to_col(void *p TSRMLS_DC, int argc, va_list argv, zend_hash_key *key) -{ - zval **c = p; - php_pqres_object_t *obj = va_arg(argv, php_pqres_object_t *); - php_pqres_col_t *col, **cols = va_arg(argv, php_pqres_col_t **); - STATUS *rv = va_arg(argv, STATUS *); +ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all_cols, 0, 0, 0) + ZEND_ARG_INFO(0, col) +ZEND_END_ARG_INFO(); +static PHP_METHOD(pqres, fetchAllCols) { + zend_error_handling zeh; + zval *zcol = NULL; + ZEND_RESULT_CODE rv; - col = *cols; + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zcol); + zend_restore_error_handling(&zeh); - if (SUCCESS != column_nn(obj, *c, col TSRMLS_CC)) { - *rv = FAILURE; + if (SUCCESS == rv) { + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); + + if (!obj->intern) { + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); + } else { + php_pqres_col_t col; + + zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh); + if (SUCCESS == column_nn(obj, zcol, &col)) { + int r, rows = PQntuples(obj->intern->res); + zval tmp; + + array_init(return_value); + for (r = 0; r < rows; ++r) { + add_next_index_zval(return_value, php_pqres_get_col(obj->intern, r, col.num, &tmp)); + } + } + zend_restore_error_handling(&zeh); + } + } +} + +struct apply_to_col_arg { + php_pqres_object_t *obj; + php_pqres_col_t *cols; + ZEND_RESULT_CODE status; +}; + +static int apply_to_col(zval *c, void *a) +{ + struct apply_to_col_arg *arg = a; + + if (SUCCESS != column_nn(arg->obj, c, arg->cols)) { + arg->status = FAILURE; return ZEND_HASH_APPLY_STOP; } else { - *rv = SUCCESS; - ++*cols; + arg->status = SUCCESS; + ++arg->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) +static php_pqres_col_t *php_pqres_convert_to_cols(php_pqres_object_t *obj, HashTable *ht) { - php_pqres_col_t *tmp, *cols = ecalloc(zend_hash_num_elements(ht), sizeof(*cols)); - STATUS rv = SUCCESS; + struct apply_to_col_arg arg = {NULL}; + php_pqres_col_t *tmp; - tmp = cols; - zend_hash_apply_with_arguments(ht TSRMLS_CC, apply_to_col, 2, obj, &tmp, &rv); + arg.obj = obj; + arg.cols = ecalloc(zend_hash_num_elements(ht), sizeof(*tmp)); + tmp = arg.cols; + zend_hash_apply_with_argument(ht, apply_to_col, &arg); - if (SUCCESS == rv) { - return cols; + if (SUCCESS == arg.status) { + return tmp; } else { - efree(cols); + efree(tmp); return NULL; } } @@ -724,18 +958,18 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, map) { zend_error_handling zeh; zval *zkeys = 0, *zvals = 0; - long fetch_type = -1; - STATUS rv; + zend_long fetch_type = -1; + ZEND_RESULT_CODE 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, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|z/!z/!l", &zkeys, &zvals, &fetch_type); + zend_restore_error_handling(&zeh); if (SUCCESS == rv) { - php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "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; @@ -744,7 +978,7 @@ static PHP_METHOD(pqres, map) { convert_to_array(zkeys); if ((ks = zend_hash_num_elements(Z_ARRVAL_P(zkeys)))) { - keys = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zkeys) TSRMLS_CC); + keys = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zkeys)); } else { ks = 1; keys = &def; @@ -757,17 +991,17 @@ static PHP_METHOD(pqres, map) { convert_to_array(zvals); if ((vs = zend_hash_num_elements(Z_ARRVAL_P(zvals)))) { - vals = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zvals) TSRMLS_CC); + vals = php_pqres_convert_to_cols(obj, Z_ARRVAL_P(zvals)); } } if (fetch_type == -1) { - fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : obj->intern->default_fetch_type; + fetch_type = php_pqres_fetch_type(obj->intern); } if (keys) { int rows, r; - zval **cur; + zval *cur; switch (fetch_type) { case PHP_PQRES_FETCH_ARRAY: @@ -780,30 +1014,32 @@ static PHP_METHOD(pqres, map) { } for (r = 0, rows = PQntuples(obj->intern->res); r < rows; ++r) { int k, v; + zval *ptr; - cur = &return_value; + cur = return_value; for (k = 0; k < ks; ++k) { char *key = PQgetvalue(obj->intern->res, r, keys[k].num); int len = PQgetlength(obj->intern->res, r, keys[k].num); - if (SUCCESS != zend_symtable_find(HASH_OF(*cur), key, len + 1, (void *) &cur)) { - zval *tmp; + if (!(ptr = zend_symtable_str_find(HASH_OF(cur), key, len))) { + zval tmp; - MAKE_STD_ZVAL(tmp); switch (fetch_type) { case PHP_PQRES_FETCH_ARRAY: case PHP_PQRES_FETCH_ASSOC: - array_init(tmp); + array_init(&tmp); break; case PHP_PQRES_FETCH_OBJECT: - object_init(tmp); + object_init(&tmp); break; } - if (SUCCESS != zend_symtable_update(HASH_OF(*cur), key, len + 1, (void *) &tmp, sizeof(zval *), (void *) &cur)) { - throw_exce(EX_RUNTIME TSRMLS_CC, "Failed to create map"); + if (!(ptr = zend_symtable_str_update(HASH_OF(cur), key, len, &tmp))) { + throw_exce(EX_RUNTIME, "Failed to create map"); goto err; } + cur = ptr; } + cur = ptr; } if (vals && vs) { for (v = 0; v < vs; ++v) { @@ -812,18 +1048,18 @@ static PHP_METHOD(pqres, map) { switch (fetch_type) { case PHP_PQRES_FETCH_ARRAY: - add_index_stringl(*cur, vals[v].num, val, len, 1); + add_index_stringl(cur, vals[v].num, val, len); break; case PHP_PQRES_FETCH_ASSOC: - add_assoc_stringl(*cur, vals[v].name, val, len, 1); + add_assoc_stringl(cur, vals[v].name, val, len); break; case PHP_PQRES_FETCH_OBJECT: - add_property_stringl(*cur, vals[v].name, val, len, 1); + add_property_stringl(cur, vals[v].name, val, len); break; } } } else { - php_pqres_row_to_zval(obj->intern->res, r, fetch_type, cur TSRMLS_CC); + php_pqres_row_to_zval(obj->intern->res, r, fetch_type, cur); } } } @@ -844,27 +1080,30 @@ ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, fetchAll) { zend_error_handling zeh; - long fetch_type = -1; - STATUS rv; + zend_long fetch_type = -1; + ZEND_RESULT_CODE rv; - 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); + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &fetch_type); + zend_restore_error_handling(&zeh); if (SUCCESS == rv) { - php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); + if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { int r, rows = PQntuples(obj->intern->res); + zval tmp; if (fetch_type == -1) { - fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : obj->intern->default_fetch_type; + fetch_type = php_pqres_fetch_type(obj->intern); } array_init(return_value); for (r = 0; r < rows; ++r) { - add_next_index_zval(return_value, php_pqres_row_to_zval(obj->intern->res, r, fetch_type, NULL TSRMLS_CC)); + ZVAL_NULL(&tmp); + add_next_index_zval(return_value, php_pqres_row_to_zval(obj->intern->res, r, fetch_type, &tmp)); } } } @@ -873,11 +1112,18 @@ static PHP_METHOD(pqres, fetchAll) { ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, count) { - if (SUCCESS == zend_parse_parameters_none()) { + zend_error_handling zeh; + ZEND_RESULT_CODE rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters_none(); + zend_restore_error_handling(&zeh); + + if (SUCCESS == rv) { long count; - if (SUCCESS != php_pqres_count_elements(getThis(), &count TSRMLS_CC)) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + if (SUCCESS != php_pqres_count_elements(getThis(), &count)) { + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { RETVAL_LONG(count); } @@ -887,11 +1133,18 @@ static PHP_METHOD(pqres, count) { ZEND_BEGIN_ARG_INFO_EX(ai_pqres_desc, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(pqres, desc) { - if (SUCCESS == zend_parse_parameters_none()) { - php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + zend_error_handling zeh; + ZEND_RESULT_CODE rv; + + zend_replace_error_handling(EH_THROW, exce(EX_INVALID_ARGUMENT), &zeh); + rv = zend_parse_parameters_none(); + zend_restore_error_handling(&zeh); + + if (SUCCESS == rv) { + php_pqres_object_t *obj = PHP_PQ_OBJ(getThis(), NULL); if (!obj->intern) { - throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized"); + throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized"); } else { int p, params; @@ -909,6 +1162,7 @@ static zend_function_entry php_pqres_methods[] = { PHP_ME(pqres, fetchRow, ai_pqres_fetch_row, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchCol, ai_pqres_fetch_col, ZEND_ACC_PUBLIC) PHP_ME(pqres, fetchAll, ai_pqres_fetch_all, ZEND_ACC_PUBLIC) + PHP_ME(pqres, fetchAllCols, ai_pqres_fetch_all_cols, ZEND_ACC_PUBLIC) PHP_ME(pqres, count, ai_pqres_count, ZEND_ACC_PUBLIC) PHP_ME(pqres, map, ai_pqres_map, ZEND_ACC_PUBLIC) PHP_ME(pqres, desc, ai_pqres_desc, ZEND_ACC_PUBLIC) @@ -927,68 +1181,94 @@ PHP_MINIT_FUNCTION(pqres) php_pq_object_prophandler_t ph = {0}; INIT_NS_CLASS_ENTRY(ce, "pq", "Result", php_pqres_methods); - php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC); + php_pqres_class_entry = zend_register_internal_class_ex(&ce, NULL); php_pqres_class_entry->create_object = php_pqres_create_object; - php_pqres_class_entry->iterator_funcs.funcs = &php_pqres_iterator_funcs; php_pqres_class_entry->get_iterator = php_pqres_iterator_init; - zend_class_implements(php_pqres_class_entry TSRMLS_CC, 2, zend_ce_traversable, spl_ce_Countable); + zend_class_implements(php_pqres_class_entry, 2, zend_ce_traversable, spl_ce_Countable); memcpy(&php_pqres_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_pqres_object_handlers.offset = XtOffsetOf(php_pqres_object_t, zo); + php_pqres_object_handlers.free_obj = php_pqres_object_free; php_pqres_object_handlers.read_property = php_pq_object_read_prop; php_pqres_object_handlers.write_property = php_pq_object_write_prop; php_pqres_object_handlers.clone_obj = NULL; - php_pqres_object_handlers.get_property_ptr_ptr = NULL; - php_pqres_object_handlers.get_gc = NULL; + php_pqres_object_handlers.get_property_ptr_ptr = php_pq_object_get_prop_ptr_null; + php_pqres_object_handlers.get_gc = php_pq_object_get_gc; php_pqres_object_handlers.get_debug_info = php_pq_object_debug_info; php_pqres_object_handlers.get_properties = php_pq_object_properties; php_pqres_object_handlers.count_elements = php_pqres_count_elements; - zend_hash_init(&php_pqres_object_prophandlers, 6, NULL, NULL, 1); + zend_hash_init(&php_pqres_object_prophandlers, 9, NULL, php_pq_object_prophandler_dtor, 1); - zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_status; - zend_hash_add(&php_pqres_object_prophandlers, "status", sizeof("status"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "status", sizeof("status")-1, (void *) &ph, sizeof(ph)); - zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("statusMessage"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_status_message; - zend_hash_add(&php_pqres_object_prophandlers, "statusMessage", sizeof("statusMessage"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "statusMessage", sizeof("statusMessage")-1, (void *) &ph, sizeof(ph)); - zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("errorMessage"), ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_error_message; - zend_hash_add(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "errorMessage", sizeof("errorMessage")-1, (void *) &ph, sizeof(ph)); - zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("diag"), ZEND_ACC_PUBLIC); + ph.read = php_pqres_object_read_diag; + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "diag", sizeof("diag")-1, (void *) &ph, sizeof(ph)); + + zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numRows"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_num_rows; - zend_hash_add(&php_pqres_object_prophandlers, "numRows", sizeof("numRows"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "numRows", sizeof("numRows")-1, (void *) &ph, sizeof(ph)); - zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("numCols"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_num_cols; - zend_hash_add(&php_pqres_object_prophandlers, "numCols", sizeof("numCols"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "numCols", sizeof("numCols")-1, (void *) &ph, sizeof(ph)); - zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("affectedRows"), 0, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_affected_rows; - zend_hash_add(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "affectedRows", sizeof("affectedRows")-1, (void *) &ph, sizeof(ph)); - zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC); + zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("fetchType"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC); ph.read = php_pqres_object_read_fetch_type; ph.write = php_pqres_object_write_fetch_type; - zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL); + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType")-1, (void *) &ph, sizeof(ph)); + ph.write = NULL; + + zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("autoConvert"), PHP_PQRES_CONV_ALL, ZEND_ACC_PUBLIC); + ph.read = php_pqres_object_read_auto_conv; + ph.write = php_pqres_object_write_auto_conv; + zend_hash_str_add_mem(&php_pqres_object_prophandlers, "autoConvert", sizeof("autoConvert")-1, (void *) &ph, sizeof(ph)); ph.write = NULL; - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC); - - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC TSRMLS_CC); - zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT TSRMLS_CC); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("EMPTY_QUERY"), PGRES_EMPTY_QUERY); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COMMAND_OK"), PGRES_COMMAND_OK); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("TUPLES_OK"), PGRES_TUPLES_OK); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_OUT"), PGRES_COPY_OUT); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_IN"), PGRES_COPY_IN); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("BAD_RESPONSE"), PGRES_BAD_RESPONSE); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("NONFATAL_ERROR"), PGRES_NONFATAL_ERROR); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FATAL_ERROR"), PGRES_FATAL_ERROR); +#ifdef HAVE_PGRES_COPY_BOTH + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH); +#endif +#ifdef HAVE_PGRES_SINGLE_TUPLE + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE); +#endif + + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ARRAY"), PHP_PQRES_FETCH_ARRAY); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_ASSOC"), PHP_PQRES_FETCH_ASSOC); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("FETCH_OBJECT"), PHP_PQRES_FETCH_OBJECT); + + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_BOOL"), PHP_PQRES_CONV_BOOL); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_INT"), PHP_PQRES_CONV_INT); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_FLOAT"), PHP_PQRES_CONV_FLOAT); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY); + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME); +#if PHP_PQ_HAVE_PHP_JSON_H + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_JSON"), PHP_PQRES_CONV_JSON); +#endif + zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL); return SUCCESS; }