#include <php.h>
#include <ext/spl/spl_iterators.h>
+#if PHP_PQ_HAVE_PHP_JSON_H
+#include <php_json.h> /* we've added the include directory to INCLUDES */
+#endif
+
#include <libpq-events.h>
#include "php_pq.h"
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 */
+ iter->zi.data = zend_object_store_get_object(object TSRMLS_CC);
+ zend_objects_store_add_ref(object TSRMLS_CC);
zfetch_type = prop = zend_read_property(ce, object, ZEND_STRL("fetchType"), 0 TSRMLS_CC);
if (Z_TYPE_P(zfetch_type) != IS_LONG) {
static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
{
php_pqres_iterator_t *iter = (php_pqres_iterator_t *) i;
+ php_pqres_object_t *obj = i->data;
if (iter->current_val) {
zval_ptr_dtor(&iter->current_val);
iter->current_val = NULL;
}
+ zend_objects_store_del_ref_by_handle_ex(obj->zv.handle, obj->zv.handlers TSRMLS_CC);
efree(iter);
}
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);
+ php_pqres_object_t *obj = i->data;
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;
}
return SUCCESS;
}
+#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, char *val, size_t len, Oid typ TSRMLS_DC)
{
zval *zv, **zconv;
MAKE_STD_ZVAL(zv);
if (SUCCESS == zend_hash_index_find(&res->converters, typ, (void *) &zconv)) {
- zval *tmp = NULL;
+ zval *ztype, *tmp = NULL;
+ MAKE_STD_ZVAL(ztype);
+ ZVAL_LONG(ztype, typ);
ZVAL_STRINGL(zv, val, len, 1);
- zend_call_method_with_1_params(zconv, NULL, NULL, "convertfromstring", &tmp, zv);
+ zend_call_method_with_2_params(zconv, NULL, NULL, "convertfromstring", &tmp, zv, ztype);
+ zval_ptr_dtor(&ztype);
if (tmp) {
zval_ptr_dtor(&zv);
}
ZVAL_BOOL(zv, *val == 't');
break;
-#if SIZEOF_LONG >= 8
+
case PHP_PQ_OID_INT8:
case PHP_PQ_OID_TID:
-#endif
case PHP_PQ_OID_INT4:
case PHP_PQ_OID_INT2:
case PHP_PQ_OID_XID:
if (!(res->auto_convert & PHP_PQRES_CONV_INT)) {
goto noconversion;
}
- ZVAL_LONG(zv, zend_atol(val, len));
+ {
+ long lval;
+ double dval;
+
+ switch (is_numeric_string(val, len, &lval, &dval, 0)) {
+ case IS_LONG:
+ ZVAL_LONG(zv, lval);
+ break;
+ case IS_DOUBLE:
+ ZVAL_DOUBLE(zv, dval);
+ break;
+ default:
+ goto noconversion;
+ }
+ }
break;
case PHP_PQ_OID_FLOAT4:
if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
goto noconversion;
}
- php_pqdt_from_string(val, len, "Y-m-d", zv TSRMLS_CC);
+ php_pqdt_from_string(zv, NULL, val, len, "Y-m-d", NULL TSRMLS_CC);
break;
case PHP_PQ_OID_ABSTIME:
if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
goto noconversion;
}
- php_pqdt_from_string(val, len, "Y-m-d H:i:s", zv TSRMLS_CC);
+ php_pqdt_from_string(zv, NULL, val, len, "Y-m-d H:i:s", NULL TSRMLS_CC);
break;
case PHP_PQ_OID_TIMESTAMP:
if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
goto noconversion;
}
- php_pqdt_from_string(val, len, "Y-m-d H:i:s.u", zv TSRMLS_CC);
+ php_pqdt_from_string(zv, NULL, val, len, "Y-m-d H:i:s.u", NULL TSRMLS_CC);
break;
case PHP_PQ_OID_TIMESTAMPTZ:
if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
goto noconversion;
}
- php_pqdt_from_string(val, len, "Y-m-d H:i:s.uO", zv TSRMLS_CC);
+ php_pqdt_from_string(zv, NULL, val, len, "Y-m-d H:i:s.uO", NULL TSRMLS_CC);
break;
+#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, val, len, PHP_PQRES_JSON_OPTIONS(res), 512 /* PHP_JSON_DEFAULT_DEPTH */ TSRMLS_CC);
+ break;
+#endif
+
default:
if (!(res->auto_convert & PHP_PQRES_CONV_ARRAY)) {
goto noconversion;
static void php_pqres_iterator_current(zend_object_iterator *i, zval ***data_ptr 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);
+ php_pqres_object_t *obj = i->data;
if (!iter->current_val) {
iter->current_val = php_pqres_row_to_zval(obj->intern->res, iter->index, iter->fetch_type, NULL TSRMLS_CC);
}
}
+php_pqres_fetch_t php_pqres_fetch_type(php_pqres_t *res)
+{
+ return res->iter ? res->iter->fetch_type : res->default_fetch_type;
+}
+
static void php_pqres_object_free(void *o TSRMLS_DC)
{
php_pqres_object_t *obj = o;
{
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)
long index = -1;
char *name = NULL;
- switch (Z_TYPE_P(zcol)) {
- case IS_LONG:
- index = Z_LVAL_P(zcol);
- break;
+ if (!zcol) {
+ index = 0;
+ } else {
+ switch (Z_TYPE_P(zcol)) {
+ case IS_NULL:
+ index = 0;
+ break;
- default:
- convert_to_string(zcol);
- /* no 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);
+ 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) {
ZEND_END_ARG_INFO();
static PHP_METHOD(pqres, bind) {
zval *zcol, *zref;
+ 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, "z/z", &zcol, &zref);
+ zend_restore_error_handling(&zeh TSRMLS_CC);
- if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z", &zcol, &zref)) {
+ if (SUCCESS == rv) {
php_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
if (!obj->intern) {
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);
+ zend_hash_sort(&obj->intern->bound, zend_qsort, php_pq_compare_index, 0 TSRMLS_CC);
RETVAL_TRUE;
}
}
zval **row = NULL;
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);
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;
+ zval *zcol = NULL, *zref;
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", &zcol, &zref);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z/!", &zref, &zcol);
zend_restore_error_handling(&zeh TSRMLS_CC);
if (SUCCESS == rv) {
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) {
- RETVAL_FALSE;
- } else {
+ php_pqres_iteration(getThis(), obj, php_pqres_fetch_type(obj->intern), &row TSRMLS_CC);
+ if (row) {
php_pqres_col_t col;
if (SUCCESS != column_nn(obj, zcol, &col TSRMLS_CC)) {
}
}
-ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_all_cols, 0, 0, 1)
+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;
+ zval *zcol = 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, "z", &zcol);
+ rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!", &zcol);
zend_restore_error_handling(&zeh TSRMLS_CC);
if (SUCCESS == rv) {
php_pqres_col_t col;
zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC);
-
if (SUCCESS == column_nn(obj, zcol, &col TSRMLS_CC)) {
int r, rows = PQntuples(obj->intern->res);
add_next_index_zval(return_value, php_pqres_get_col(obj->intern, r, col.num 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)
+struct apply_to_col_arg {
+ php_pqres_object_t *obj;
+ php_pqres_col_t *cols;
+ STATUS status;
+};
+
+static int apply_to_col(void *p, void *a TSRMLS_DC)
{
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 *);
-
- col = *cols;
+ struct apply_to_col_arg *arg = a;
- if (SUCCESS != column_nn(obj, *c, col TSRMLS_CC)) {
- *rv = FAILURE;
+ if (SUCCESS != column_nn(arg->obj, *c, arg->cols TSRMLS_CC)) {
+ 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)
{
- 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 TSRMLS_CC);
- if (SUCCESS == rv) {
- return cols;
+ if (SUCCESS == arg.status) {
+ return tmp;
} else {
- efree(cols);
+ efree(tmp);
return NULL;
}
}
}
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 r, rows = PQntuples(obj->intern->res);
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);
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;
+ 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) {
long count;
if (SUCCESS != php_pqres_count_elements(getThis(), &count TSRMLS_CC)) {
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()) {
+ 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_pqres_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
if (!obj->intern) {
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, 8, NULL, NULL, 1);
zend_declare_property_null(php_pqres_class_entry, ZEND_STRL("status"), ZEND_ACC_PUBLIC TSRMLS_CC);
ph.read = php_pqres_object_read_status;
zend_hash_add(&php_pqres_object_prophandlers, "fetchType", sizeof("fetchType"), (void *) &ph, sizeof(ph), NULL);
ph.write = NULL;
- zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("autoConvert"), PHP_PQRES_FETCH_ARRAY, ZEND_ACC_PUBLIC TSRMLS_CC);
+ zend_declare_property_long(php_pqres_class_entry, ZEND_STRL("autoConvert"), PHP_PQRES_CONV_ALL, ZEND_ACC_PUBLIC TSRMLS_CC);
ph.read = php_pqres_object_read_auto_conv;
ph.write = php_pqres_object_write_auto_conv;
zend_hash_add(&php_pqres_object_prophandlers, "autoConvert", sizeof("autoConvert"), (void *) &ph, sizeof(ph), NULL);
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);
+#ifdef HAVE_PGRES_COPY_BOTH
zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("COPY_BOTH"), PGRES_COPY_BOTH TSRMLS_CC);
+#endif
+#ifdef HAVE_PGRES_SINGLE_TUPLE
zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("SINGLE_TUPLE"), PGRES_SINGLE_TUPLE TSRMLS_CC);
+#endif
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("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR TSRMLS_CC);
zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY TSRMLS_CC);
zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME TSRMLS_CC);
+#if PHP_PQ_HAVE_PHP_JSON_H
+ zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_JSON"), PHP_PQRES_CONV_JSON TSRMLS_CC);
+#endif
zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL TSRMLS_CC);
return SUCCESS;