From 8f0022e027a5412e5d404ee62a0c0346481748b4 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 29 Apr 2013 14:23:56 +0200 Subject: [PATCH] type coercion for the array parser --- package.xml | 1 + php_pq_type.awk | 13 ++++-- src/php_pq_misc.c | 102 +++++++++++++++++++++++++++++++++++++--------- src/php_pq_misc.h | 3 +- src/php_pqres.c | 61 +-------------------------- 5 files changed, 97 insertions(+), 83 deletions(-) diff --git a/package.xml b/package.xml index f622d0c..b730774 100644 --- a/package.xml +++ b/package.xml @@ -112,6 +112,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + diff --git a/php_pq_type.awk b/php_pq_type.awk index c9ed34b..15ffd1b 100755 --- a/php_pq_type.awk +++ b/php_pq_type.awk @@ -9,17 +9,24 @@ BEGIN { END { printf "#ifndef PHP_PQ_TYPE_IS_ARRAY\n" printf "# define PHP_PQ_TYPE_IS_ARRAY(oid) (\\\n\t\t0 \\\n" - for (name in arrays) { - printf "\t||\t((oid) == %d) \\\n", arrays[name] + for (oid in arrays) { + printf "\t||\t((oid) == %d) \\\n", oid } printf ")\n#endif\n" + printf "#ifndef PHP_PQ_TYPE_OF_ARRAY\n" + printf "# define PHP_PQ_TYPE_OF_ARRAY(oid) (" + for (oid in arrays) { + printf "\\\n\t(oid) == %d ? %s : ", oid, arrays[oid] + } + printf "0 \\\n)\n#endif\n" } /^DATA/ { oid = $4 name = toupper($6) + atypoid = $17 if (sub("^_", "", name)) { - arrays[name] = oid + arrays[oid] = atypoid name = name "ARRAY" } printf "#ifndef PHP_PQ_OID_%s\n", name diff --git a/src/php_pq_misc.c b/src/php_pq_misc.c index 72fa07b..e8de5d2 100644 --- a/src/php_pq_misc.c +++ b/src/php_pq_misc.c @@ -248,6 +248,7 @@ typedef struct _ArrayParserState { #ifdef ZTS void ***ts; #endif + Oid typ; unsigned quotes:1; unsigned escaped:1; } ArrayParserState; @@ -271,31 +272,28 @@ static char caa(ArrayParserState *a, const char *any, unsigned advance) static STATUS add_element(ArrayParserState *a, const char *start) { zval *zelem; + size_t el_len = a->ptr - start; + char *el_str = estrndup(start, el_len); TSRMLS_FETCH_FROM_CTX(a->ts); - MAKE_STD_ZVAL(zelem); if (a->quotes) { - ZVAL_STRINGL(zelem, start, a->ptr - start, 1); - php_stripslashes(Z_STRVAL_P(zelem), &Z_STRLEN_P(zelem) TSRMLS_CC); + int tmp_len; + + php_stripslashes(el_str, &tmp_len TSRMLS_CC); + el_len = tmp_len; } else if ((a->ptr - start == 4) && !strncmp(start, "NULL", 4)) { + efree(el_str); + el_str = NULL; + el_len = 0; + } + + if (!el_str) { + MAKE_STD_ZVAL(zelem); ZVAL_NULL(zelem); } else { - long lval = 0; - double dval = 0; - - switch (is_numeric_string(start, a->ptr - start, &lval, &dval, 0)) { - case IS_LONG: - ZVAL_LONG(zelem, lval); - break; + zelem = php_pq_typed_zval(el_str, el_len, a->typ TSRMLS_CC); - case IS_DOUBLE: - ZVAL_DOUBLE(zelem, dval); - break; - - default: - ZVAL_STRINGL(zelem, start, a->ptr - start, 1); - break; - } + efree(el_str); } return zend_hash_next_index_insert(&a->list->ht, &zelem, sizeof(zval *), NULL); @@ -420,12 +418,13 @@ static STATUS parse_array(ArrayParserState *a) return SUCCESS; } -HashTable *php_pq_parse_array(const char *val_str, size_t val_len TSRMLS_DC) +HashTable *php_pq_parse_array(const char *val_str, size_t val_len, Oid typ TSRMLS_DC) { HashTable *ht = NULL; ArrayParserState a = {0}; TSRMLS_SET_CTX(a.ts); + a.typ = typ; a.ptr = val_str; a.end = val_str + val_len; @@ -451,6 +450,71 @@ HashTable *php_pq_parse_array(const char *val_str, size_t val_len TSRMLS_DC) return ht; } +zval *php_pq_typed_zval(char *val, size_t len, Oid typ TSRMLS_DC) +{ + zval *zv; + + MAKE_STD_ZVAL(zv); + + switch (typ) { +#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_DATE: + php_pqdt_from_string(val, len, "Y-m-d", zv TSRMLS_CC); + break; + + case PHP_PQ_OID_ABSTIME: + php_pqdt_from_string(val, len, "Y-m-d H:i:s", zv TSRMLS_CC); + break; + + case PHP_PQ_OID_TIMESTAMP: + php_pqdt_from_string(val, len, "Y-m-d H:i:s.u", zv TSRMLS_CC); + break; + + case PHP_PQ_OID_TIMESTAMPTZ: + php_pqdt_from_string(val, len, "Y-m-d H:i:s.uO", zv TSRMLS_CC); + break; + + default: + if (PHP_PQ_TYPE_IS_ARRAY(typ) && (Z_ARRVAL_P(zv) = php_pq_parse_array(val, len, PHP_PQ_TYPE_OF_ARRAY(typ) TSRMLS_CC))) { + Z_TYPE_P(zv) = IS_ARRAY; + } else { + ZVAL_STRINGL(zv, val, len, 1); + } + break; + } +#else + case 16: /* BOOL */ + ZVAL_BOOL(zv, *val == 't'); + break; + + default: + ZVAL_STRINGL(zv, val, len, 1); +#endif + + return zv; +} + /* * Local variables: * tab-width: 4 diff --git a/src/php_pq_misc.h b/src/php_pq_misc.h index b7438de..07f75a3 100644 --- a/src/php_pq_misc.h +++ b/src/php_pq_misc.h @@ -36,7 +36,8 @@ int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRML zend_class_entry *php_pqdt_class_entry; zval *php_pqdt_from_string(char *datetime_str, size_t datetime_len, char *fmt, zval *zv TSRMLS_DC); -HashTable *php_pq_parse_array(const char *val_str, size_t val_len TSRMLS_DC); +HashTable *php_pq_parse_array(const char *val_str, size_t val_len, Oid typ TSRMLS_DC); +zval *php_pq_typed_zval(char *val_str, size_t val_len, Oid typ TSRMLS_DC); PHP_MINIT_FUNCTION(pq_misc); diff --git a/src/php_pqres.c b/src/php_pqres.c index 2ebcf74..782589d 100644 --- a/src/php_pqres.c +++ b/src/php_pqres.c @@ -126,66 +126,7 @@ zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch break; } } else { - zval *zv; - Oid typ = PQftype(res, c); - char *val = PQgetvalue(res, row, c); - int len = PQgetlength(res, row, c); - - MAKE_STD_ZVAL(zv); - - switch (typ) { -#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_DATE: - php_pqdt_from_string(val, len, "Y-m-d", zv TSRMLS_CC); - break; - - case PHP_PQ_OID_ABSTIME: - php_pqdt_from_string(val, len, "Y-m-d H:i:s", zv TSRMLS_CC); - break; - - case PHP_PQ_OID_TIMESTAMP: - php_pqdt_from_string(val, len, "Y-m-d H:i:s.u", zv TSRMLS_CC); - break; - - case PHP_PQ_OID_TIMESTAMPTZ: - php_pqdt_from_string(val, len, "Y-m-d H:i:s.uO", zv TSRMLS_CC); - break; - - -#else - case 16: /* BOOL */ - ZVAL_BOOL(zv, *val == 't'); - break; -#endif - default: - if (PHP_PQ_TYPE_IS_ARRAY(typ) && (Z_ARRVAL_P(zv) = php_pq_parse_array(val, len TSRMLS_CC))) { - Z_TYPE_P(zv) = IS_ARRAY; - } else { - ZVAL_STRINGL(zv, val, len, 1); - } - break; - } + zval *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: -- 2.30.2