add default propoerties to connection
[m6w6/ext-pq] / src / php_pqres.c
index aee753d0acd0c78f42272bffa8de246633e57215..b365f3d2e36a1379f40fad1745775550bf4631a2 100644 (file)
@@ -38,7 +38,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 +66,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);
 }
 
@@ -93,6 +92,7 @@ zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch
 {
        zval *data = NULL;
        int c, cols;
+       php_pqres_object_t *res_obj = PQresultInstanceData(res, php_pqconn_event);
 
        if (data_ptr) {
                data = *data_ptr;
@@ -126,20 +126,35 @@ zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch
                                        break;
                                }
                        } else {
-                               char *val = PQgetvalue(res, row, c);
-                               int len = PQgetlength(res, row, c);
+                               zval *zv, **zconv;
+
+                               if (res_obj && (SUCCESS == zend_hash_index_find(&res_obj->intern->converters, PQftype(res, c), (void *) &zconv))) {
+                                       zval *tmp = NULL;
+
+                                       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 (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);
+                               }
 
                                switch (fetch_type) {
                                case PHP_PQRES_FETCH_OBJECT:
-                                       add_property_stringl(data, PQfname(res, c), val, len, 1);
+                                       add_property_zval(data, PQfname(res, c), zv);
+                                       zval_ptr_dtor(&zv);
                                        break;
 
                                case PHP_PQRES_FETCH_ASSOC:
-                                       add_assoc_stringl(data, PQfname(res, c), val, len, 1);
+                                       add_assoc_zval(data, PQfname(res, c), zv);
                                        break;
 
                                case PHP_PQRES_FETCH_ARRAY:
-                                       add_index_stringl(data, c, val, len ,1);
+                                       add_index_zval(data, c, zv);
                                        break;
                                }
                        }
@@ -248,15 +263,19 @@ 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->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) {
@@ -283,6 +302,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;
@@ -373,7 +393,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);
        }
 }
 
@@ -441,6 +461,10 @@ static STATUS column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *co
        char *name = NULL;
 
        switch (Z_TYPE_P(zcol)) {
+       case IS_LONG:
+               index = Z_LVAL_P(zcol);
+               break;
+
        default:
                convert_to_string(zcol);
                /* no break */
@@ -450,10 +474,6 @@ static STATUS column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres_col_t *co
                        name = Z_STRVAL_P(zcol);
                }
                break;
-
-       case IS_LONG:
-               index = Z_LVAL_P(zcol);
-               break;
        }
 
        if (name) {
@@ -582,7 +602,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);
@@ -614,16 +634,17 @@ static zval **column_at(zval *row, int col TSRMLS_DC)
        return data;
 }
 
-ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 0)
-       ZEND_ARG_INFO(0, col_num)
+ZEND_BEGIN_ARG_INFO_EX(ai_pqres_fetch_col, 0, 0, 2)
+       ZEND_ARG_INFO(0, col)
+       ZEND_ARG_INFO(1, ref)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(pqres, fetchCol) {
        zend_error_handling zeh;
-       long fetch_col = 0;
+       zval *zcol, *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, "|l", &fetch_col);
+       rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z", &zcol, &zref);
        zend_restore_error_handling(&zeh TSRMLS_CC);
 
        if (SUCCESS == rv) {
@@ -636,11 +657,23 @@ static PHP_METHOD(pqres, fetchCol) {
 
                        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);
+                       if (!row) {
+                               RETVAL_FALSE;
+                       } else {
+                               php_pqres_col_t col;
 
-                               if (col) {
-                                       RETVAL_ZVAL(*col, 1, 0);
+                               if (SUCCESS != column_nn(obj, zcol, &col TSRMLS_CC)) {
+                                       RETVAL_FALSE;
+                               } else {
+                                       zval **zres = column_at(*row, col.num TSRMLS_CC);
+
+                                       if (!zres) {
+                                               RETVAL_FALSE;
+                                       } else {
+                                               zval_dtor(zref);
+                                               ZVAL_ZVAL(zref, *zres, 1, 0);
+                                               RETVAL_TRUE;
+                                       }
                                }
                        }
                        zend_restore_error_handling(&zeh TSRMLS_CC);
@@ -729,7 +762,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) {
@@ -826,7 +859,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);
@@ -851,6 +884,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)
@@ -859,9 +911,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};