From fad4fe6a60c56ad5d5752e10abd1085884cc09c2 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 24 Apr 2013 12:24:54 +0200 Subject: [PATCH] extended result type handling with catalog/pg_type.h --- .gitignore | 1 + config.m4 | 26 ++++++++++++++++++++--- package.xml | 4 ++++ php_pq_type.awk | 29 ++++++++++++++++++++++++++ src/php_pq_misc.c | 20 +++++++++++++++++- src/php_pq_misc.h | 2 ++ src/php_pqres.c | 51 ++++++++++++++++++++++++++++++++++++++++++--- src/php_pqtypes.c | 13 +++++++++++- tests/bound001.phpt | 7 ++++++- tests/bound002.phpt | 50 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 194 insertions(+), 9 deletions(-) create mode 100755 php_pq_type.awk create mode 100644 tests/bound002.phpt diff --git a/.gitignore b/.gitignore index 902c527..11f6eda 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ /autom4te* /.dep.inc run-tests.php +php_pq_type.h diff --git a/config.m4 b/config.m4 index 8014c65..cfb995b 100644 --- a/config.m4 +++ b/config.m4 @@ -1,5 +1,7 @@ PHP_ARG_WITH(pq, [whether to enable libpq (PostgreSQL) support], -[ --with-pq Include libpq support]) +[ --with-pq Include libpq support]) +PHP_ARG_WITH(pq-postgresql, [where to find PostgreSQL server headers], +[ --with-pq-postgresql Define some standard type IODs from catalog/pg_type.h], [$PHP_PQ]) if test "$PHP_PQ" != "no"; then SEARCH_PATH="/usr/local /usr /opt" @@ -31,7 +33,7 @@ if test "$PHP_PQ" != "no"; then -L$PQ_DIR/$PHP_LIBDIR ]) PHP_CHECK_LIBRARY(pq, PQlibVersion, [AC_DEFINE(HAVE_PQLIBVERSION, 1, Have PQlibVersion)]) - + PQ_SRC="\ src/php_pq_module.c\ src/php_pq_misc.c\ @@ -51,6 +53,24 @@ if test "$PHP_PQ" != "no"; then PHP_NEW_EXTENSION(pq, $PQ_SRC, $ext_shared) PHP_ADD_BUILD_DIR($ext_builddir/src) PHP_ADD_INCLUDE($ext_srcdir/src) - PHP_ADD_EXTENSION_DEP(pq, raphf) + PHP_ADD_EXTENSION_DEP(pq, raphf) + + if test "$PHP_PQ_POSTGRESQL" != "no"; then + if test "$PHP_PQ_POSTGRESQL" != "yes"; then + SEARCH_PATH="$PHP_PQ_POSTGRESQL $SEARCH_PATH" + fi + for i in $SEARCH_PATH; do + CATALOG="$i/include/postgresql/server/catalog/pg_type.h" + AC_MSG_CHECKING(for $CATALOG) + if test -f "$CATALOG"; then + AC_MSG_RESULT(yep) + AC_PROG_AWK() + $AWK -f $ext_srcdir/php_pq_type.awk < "$CATALOG" > $ext_srcdir/php_pq_type.h + AC_DEFINE(HAVE_PHP_PQ_TYPE_H, 1, Have PostgreSQL type OID defs) + break + fi + AC_MSG_RESULT(nope) + done + fi fi diff --git a/package.xml b/package.xml index 67dfa0d..a2ef96d 100644 --- a/package.xml +++ b/package.xml @@ -30,6 +30,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> BSD, revised @@ -38,6 +40,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + @@ -77,6 +80,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + diff --git a/php_pq_type.awk b/php_pq_type.awk new file mode 100755 index 0000000..c9ed34b --- /dev/null +++ b/php_pq_type.awk @@ -0,0 +1,29 @@ +#!/usr/bin/awk -f + +BEGIN { + printf "#ifndef PHP_PQ_TYPE\n" + printf "# define PHP_PQ_TYPE(t,o)\n" + printf "#endif\n" +} + +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] + } + printf ")\n#endif\n" +} + +/^DATA/ { + oid = $4 + name = toupper($6) + if (sub("^_", "", name)) { + arrays[name] = oid + name = name "ARRAY" + } + printf "#ifndef PHP_PQ_OID_%s\n", name + printf "# define PHP_PQ_OID_%s %d\n", name, oid + printf "#endif\n" + printf "PHP_PQ_TYPE(\"%s\", %d)\n", name, oid +} diff --git a/src/php_pq_misc.c b/src/php_pq_misc.c index 2438182..943aa57 100644 --- a/src/php_pq_misc.c +++ b/src/php_pq_misc.c @@ -15,7 +15,7 @@ #endif #include - +#include #include #include "php_pq.h" @@ -174,6 +174,24 @@ Oid *php_pq_ntypes_to_array(zend_bool fill, int argc, ...) } */ +zval *php_pq_date_from_string(char *datetime_str, size_t datetime_len, zval *zv TSRMLS_DC) +{ + php_date_obj *dobj; + + if (!zv) { + MAKE_STD_ZVAL(zv); + } + + php_date_instantiate(php_date_get_date_ce(), zv TSRMLS_CC); + dobj = zend_object_store_get_object(zv TSRMLS_CC); + if (!php_date_initialize(dobj, datetime_str, datetime_len, NULL, NULL, 1 TSRMLS_CC)) { + zval_dtor(zv); + ZVAL_NULL(zv); + } + + return zv; +} + /* * Local variables: * tab-width: 4 diff --git a/src/php_pq_misc.h b/src/php_pq_misc.h index d81d3c3..3ce172d 100644 --- a/src/php_pq_misc.h +++ b/src/php_pq_misc.h @@ -33,6 +33,8 @@ int compare_index(const void *lptr, const void *rptr TSRMLS_DC); int php_pq_types_to_array(HashTable *ht, Oid **types TSRMLS_DC); int php_pq_params_to_array(HashTable *ht, char ***params, HashTable *zdtor TSRMLS_DC); +zval *php_pq_date_from_string(char *datetime_str, size_t datetime_len, zval *zv TSRMLS_DC); + #endif /* diff --git a/src/php_pqres.c b/src/php_pqres.c index 2b77dba..7535515 100644 --- a/src/php_pqres.c +++ b/src/php_pqres.c @@ -126,20 +126,65 @@ zval *php_pqres_row_to_zval(PGresult *res, unsigned row, php_pqres_fetch_t fetch break; } } 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; + } + 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; } } diff --git a/src/php_pqtypes.c b/src/php_pqtypes.c index db2c44e..7092c57 100644 --- a/src/php_pqtypes.c +++ b/src/php_pqtypes.c @@ -225,7 +225,9 @@ static PHP_METHOD(pqtypes, __construct) { "from pg_type t join pg_namespace n on t.typnamespace=n.oid " \ "where typisdefined " \ "and typrelid=0" -#define PHP_PQ_OID_TEXT 25 +#ifndef PHP_PQ_OID_TEXT +# define PHP_PQ_OID_TEXT 25 +#endif ZEND_BEGIN_ARG_INFO_EX(ai_pqtypes_refresh, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, namespaces, 1) @@ -338,6 +340,15 @@ PHP_MINIT_FUNCTION(pqtypes) ph.read = php_pqtypes_object_read_connection; zend_hash_add(&php_pqtypes_object_prophandlers, "connection", sizeof("connection"), (void *) &ph, sizeof(ph), NULL); +#ifdef HAVE_PHP_PQ_TYPE_H +# undef PHP_PQ_TYPE +# define PHP_PQ_TYPE(name, oid) zend_declare_class_constant_long(php_pqtypes_class_entry, ZEND_STRL(name), oid TSRMLS_CC); +# include "php_pq_type.h" + zend_declare_class_constant_bool(php_pqtypes_class_entry, ZEND_STRL("DEFINED"), 1 TSRMLS_CC); +#else + zend_declare_class_constant_bool(php_pqtypes_class_entry, ZEND_STRL("DEFINED"), 0 TSRMLS_CC); +#endif + return SUCCESS; } diff --git a/tests/bound001.phpt b/tests/bound001.phpt index 74cf339..9e1bc20 100644 --- a/tests/bound001.phpt +++ b/tests/bound001.phpt @@ -1,7 +1,12 @@ --TEST-- fetch bound --SKIPIF-- - + --FILE-- +--FILE-- +exec("select 1*a,2*a,3*a from generate_series(2,3) a"); +$r->bind(0, $a); +$r->bind(1, $b); +$r->bind(2, $c); +while ($s = $r->fetchBound()) { + var_dump($s,$a,$b,$c); +} +?> +DONE +--EXPECT-- +Test +array(3) { + [0]=> + &int(2) + [1]=> + &int(4) + [2]=> + &int(6) +} +int(2) +int(4) +int(6) +array(3) { + [0]=> + &int(3) + [1]=> + &int(6) + [2]=> + &int(9) +} +int(3) +int(6) +int(9) +DONE -- 2.30.2