fix package.xml
[m6w6/ext-pq] / src / php_pqres.c
index 75355154acc971ed4aa79ffc1f767707ddef1d24..8233d6623b718694eb2d900aa277506f46a858a3 100644 (file)
@@ -24,6 +24,8 @@
 #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;
@@ -38,7 +40,7 @@ static zend_object_iterator *php_pqres_iterator_init(zend_class_entry *ce, zval
        iter = ecalloc(1, sizeof(*iter));
        iter->zi.funcs = &php_pqres_iterator_funcs;
        iter->zi.data = object;
-       Z_ADDREF_P(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) {
@@ -66,7 +68,6 @@ static void php_pqres_iterator_dtor(zend_object_iterator *i TSRMLS_DC)
                zval_ptr_dtor(&iter->current_val);
                iter->current_val = NULL;
        }
-       zval_ptr_dtor((zval **) &iter->zi.data);
        efree(iter);
 }
 
@@ -89,10 +90,104 @@ static STATUS php_pqres_iterator_valid(zend_object_iterator *i TSRMLS_DC)
        return SUCCESS;
 }
 
+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_STRINGL(zv, val, len, 1);
+               zend_call_method_with_1_params(zconv, NULL, NULL, "convertfromstring", &tmp, zv);
+
+               if (tmp) {
+                       zval_ptr_dtor(&zv);
+                       zv = tmp;
+               }
+
+               return zv;
+       }
+
+       switch (typ) {
+       case PHP_PQ_OID_BOOL:
+               if (!(res->auto_convert & PHP_PQRES_CONV_BOOL)) {
+                       goto noconversion;
+               }
+               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:
+       case PHP_PQ_OID_OID:
+               if (!(res->auto_convert & PHP_PQRES_CONV_INT)) {
+                       goto noconversion;
+               }
+               ZVAL_LONG(zv, zend_atol(val, len));
+               break;
+
+       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(val, NULL));
+               break;
+
+       case PHP_PQ_OID_DATE:
+               if (!(res->auto_convert & PHP_PQRES_CONV_DATETIME)) {
+                       goto noconversion;
+               }
+               php_pqdt_from_string(val, len, "Y-m-d", zv 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);
+               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);
+               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);
+               break;
+
+       default:
+               if (!(res->auto_convert & PHP_PQRES_CONV_ARRAY)) {
+                       goto noconversion;
+               }
+               if (PHP_PQ_TYPE_IS_ARRAY(typ) && (Z_ARRVAL_P(zv) = php_pq_parse_array(res, val, len, PHP_PQ_TYPE_OF_ARRAY(typ) TSRMLS_CC))) {
+                       Z_TYPE_P(zv) = IS_ARRAY;
+               } else {
+                       noconversion:
+                       ZVAL_STRINGL(zv, val, len, 1);
+               }
+               break;
+       }
+
+       return zv;
+}
+
 zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch_type, zval **data_ptr TSRMLS_DC)
 {
        zval *data = NULL;
        int c, cols;
+       php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event);
 
        if (data_ptr) {
                data = *data_ptr;
@@ -127,51 +222,8 @@ zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch
                                }
                        } else {
                                zval *zv;
-                               char *val = PQgetvalue(res, row, c);
-                               int len = PQgetlength(res, row, c);
-
-                               MAKE_STD_ZVAL(zv);
-
-                               switch (PQftype(res, c)) {
-#ifdef HAVE_PHP_PQ_TYPE_H
-#      undef PHP_PQ_TYPE
-#      include "php_pq_type.h"
-                               case PHP_PQ_OID_BOOL:
-                                       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:
-                               case PHP_PQ_OID_OID:
-                                       ZVAL_LONG(zv, zend_atol(val, len));
-                                       break;
-
-                               case PHP_PQ_OID_FLOAT4:
-                               case PHP_PQ_OID_FLOAT8:
-                                       ZVAL_DOUBLE(zv, zend_strtod(val, NULL));
-                                       break;
-
-                               case PHP_PQ_OID_ABSTIME:
-                               case PHP_PQ_OID_DATE:
-                               case PHP_PQ_OID_TIMESTAMP:
-                               case PHP_PQ_OID_TIMESTAMPTZ:
-                                       php_pq_date_from_string(val, len, zv TSRMLS_CC);
-                                       break;
 
-
-#else
-                               case 18: /* BOOL */
-                                       ZVAL_BOOL(zv, *val == 't');
-                                       break;
-#endif
-                               default:
-                                       ZVAL_STRINGL(zv, val, len, 1);
-                                       break;
-                               }
+                               zv = php_pqres_typed_zval(res_obj->intern, PQgetvalue(res, row, c), PQgetlength(res, row, c), PQftype(res, c) TSRMLS_CC);
 
                                switch (fetch_type) {
                                case PHP_PQRES_FETCH_OBJECT:
@@ -293,15 +345,20 @@ STATUS php_pqres_success(PGresult *res TSRMLS_DC)
        }
 }
 
-void php_pqres_init_instance_data(PGresult *res, php_pqres_object_t **ptr TSRMLS_DC)
+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 *obj;
        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);
+       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 *));
+
+       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);
        PQresultSetInstanceData(res, php_pqconn_event, obj);
 
        if (ptr) {
@@ -328,6 +385,7 @@ static void php_pqres_object_free(void *o TSRMLS_DC)
                }
 
                zend_hash_destroy(&obj->intern->bound);
+               zend_hash_destroy(&obj->intern->converters);
 
                efree(obj->intern);
                obj->intern = NULL;
@@ -418,7 +476,7 @@ static void php_pqres_object_read_fetch_type(zval *object, void *o, zval *return
        if (obj->intern->iter) {
                RETVAL_LONG(obj->intern->iter->fetch_type);
        } else {
-               RETVAL_LONG(PHP_PQRES_FETCH_ARRAY);
+               RETVAL_LONG(obj->intern->default_fetch_type);
        }
 }
 
@@ -450,6 +508,37 @@ static void php_pqres_object_write_fetch_type(zval *object, void *o, zval *value
        }
 }
 
+static void php_pqres_object_read_auto_conv(zval *object, void *o, zval *return_value TSRMLS_DC)
+{
+       php_pqres_object_t *obj = o;
+
+       RETVAL_LONG(obj->intern->auto_convert);
+}
+
+static void php_pqres_object_write_auto_conv(zval *object, void *o, zval *value TSRMLS_DC)
+{
+       php_pqres_object_t *obj = o;
+       zval *zauto_conv = value;
+
+       if (Z_TYPE_P(value) != IS_LONG) {
+               if (Z_REFCOUNT_P(value) > 1) {
+                       zval *tmp;
+                       MAKE_STD_ZVAL(tmp);
+                       ZVAL_ZVAL(tmp, zauto_conv, 1, 0);
+                       convert_to_long(tmp);
+                       zauto_conv = tmp;
+               } else {
+                       convert_to_long_ex(&zauto_conv);
+               }
+       }
+
+       obj->intern->auto_convert = Z_LVAL_P(zauto_conv);
+
+       if (zauto_conv != value) {
+               zval_ptr_dtor(&zauto_conv);
+       }
+}
+
 static STATUS php_pqres_iteration(zval *this_ptr, php_pqres_object_t *obj, php_pqres_fetch_t fetch_type, zval ***row TSRMLS_DC)
 {
        STATUS rv;
@@ -627,7 +716,7 @@ static PHP_METHOD(pqres, fetchRow) {
                        zval **row = NULL;
 
                        if (fetch_type == -1) {
-                                fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
+                                fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : obj->intern->default_fetch_type;
                        }
 
                        zend_replace_error_handling(EH_THROW, exce(EX_RUNTIME), &zeh TSRMLS_CC);
@@ -696,7 +785,7 @@ static PHP_METHOD(pqres, fetchCol) {
                                                RETVAL_FALSE;
                                        } else {
                                                zval_dtor(zref);
-                                               ZVAL_ZVAL(zref, *zres, 1, 1);
+                                               ZVAL_ZVAL(zref, *zres, 1, 0);
                                                RETVAL_TRUE;
                                        }
                                }
@@ -787,7 +876,7 @@ static PHP_METHOD(pqres, map) {
                        }
 
                        if (fetch_type == -1) {
-                               fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
+                               fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : obj->intern->default_fetch_type;
                        }
 
                        if (keys) {
@@ -884,7 +973,7 @@ static PHP_METHOD(pqres, fetchAll) {
                        int r, rows = PQntuples(obj->intern->res);
 
                        if (fetch_type == -1) {
-                                fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : PHP_PQRES_FETCH_ARRAY;
+                                fetch_type = obj->intern->iter ? obj->intern->iter->fetch_type : obj->intern->default_fetch_type;
                        }
 
                        array_init(return_value);
@@ -909,6 +998,25 @@ 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);
+
+               if (!obj->intern) {
+                       throw_exce(EX_UNINITIALIZED TSRMLS_CC, "pq\\Result not initialized");
+               } else {
+                       int p, params;
+
+                       array_init(return_value);
+                       for (p = 0, params = PQnparams(obj->intern->res); p < params; ++p) {
+                               add_next_index_long(return_value, PQparamtype(obj->intern->res, p));
+                       }
+               }
+       }
+}
+
 static zend_function_entry php_pqres_methods[] = {
        PHP_ME(pqres, bind, ai_pqres_bind, ZEND_ACC_PUBLIC)
        PHP_ME(pqres, fetchBound, ai_pqres_fetch_bound, ZEND_ACC_PUBLIC)
@@ -917,9 +1025,16 @@ static zend_function_entry php_pqres_methods[] = {
        PHP_ME(pqres, fetchAll, ai_pqres_fetch_all, 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)
        {0}
 };
 
+PHP_MSHUTDOWN_FUNCTION(pqres)
+{
+       zend_hash_destroy(&php_pqres_object_prophandlers);
+       return SUCCESS;
+}
+
 PHP_MINIT_FUNCTION(pqres)
 {
        zend_class_entry ce = {0};
@@ -974,6 +1089,12 @@ PHP_MINIT_FUNCTION(pqres)
        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);
+       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);
+       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);
@@ -989,6 +1110,14 @@ PHP_MINIT_FUNCTION(pqres)
        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("CONV_BOOL"), PHP_PQRES_CONV_BOOL TSRMLS_CC);
+       zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_INT"), PHP_PQRES_CONV_INT TSRMLS_CC);
+       zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_FLOAT"), PHP_PQRES_CONV_FLOAT 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);
+       zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL TSRMLS_CC);
+
        return SUCCESS;
 }