extended result type handling with catalog/pg_type.h
authorMichael Wallner <mike@php.net>
Wed, 24 Apr 2013 10:24:54 +0000 (12:24 +0200)
committerMichael Wallner <mike@php.net>
Wed, 24 Apr 2013 10:24:54 +0000 (12:24 +0200)
.gitignore
config.m4
package.xml
php_pq_type.awk [new file with mode: 0755]
src/php_pq_misc.c
src/php_pq_misc.h
src/php_pqres.c
src/php_pqtypes.c
tests/bound001.phpt
tests/bound002.phpt [new file with mode: 0644]

index 902c527..11f6eda 100644 (file)
@@ -21,3 +21,4 @@
 /autom4te*
 /.dep.inc
 run-tests.php
+php_pq_type.h
index 8014c65..cfb995b 100644 (file)
--- 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
 
index 67dfa0d..a2ef96d 100644 (file)
@@ -30,6 +30,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
  </stability>
  <license>BSD, revised</license>
  <notes><![CDATA[
+* Fixed type handling of boolean/double input parameters.
+* Added extented type handling of result parameters if PostgreSQL server headers are present.
 * Implemented get_properties() object handler.
 ]]></notes>
  <contents>
@@ -38,6 +40,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <file role="doc" name="LICENSE" />
    <file role="src" name="config.m4" />
    <file role="src" name="php_pq.h" />
+   <file role="src" name="php_pq_type.awk" />
    <dir name="src">
     <file role="src" name="php_pq_callback.c" />
     <file role="src" name="php_pq_callback.h" />
@@ -77,6 +80,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
     <file role="test" name="basic001.phpt" />
     <file role="test" name="basic002.phpt" />
     <file role="test" name="bound001.phpt" />
+    <file role="test" name="bound002.phpt" />
     <file role="test" name="cancel001.phpt" />
     <file role="test" name="copy001.phpt" />
     <file role="test" name="encoding001.phpt" />
diff --git a/php_pq_type.awk b/php_pq_type.awk
new file mode 100755 (executable)
index 0000000..c9ed34b
--- /dev/null
@@ -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
+}
index 2438182..943aa57 100644 (file)
@@ -15,7 +15,7 @@
 #endif
 
 #include <php.h>
-
+#include <ext/date/php_date.h>
 #include <libpq/libpq-fs.h>
 
 #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
index d81d3c3..3ce172d 100644 (file)
@@ -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
 
 /*
index 2b77dba..7535515 100644 (file)
@@ -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;
                                }
                        }
index db2c44e..7092c57 100644 (file)
@@ -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;
 }
 
index 74cf339..9e1bc20 100644 (file)
@@ -1,7 +1,12 @@
 --TEST--
 fetch bound
 --SKIPIF--
-<?php include "_skipif.inc"; ?>
+<?php 
+include "_skipif.inc";
+if (pq\Types::DEFINED) {
+       die("skip pq\Types::DEFINED == true");
+} 
+?>
 --FILE--
 <?php
 echo "Test\n";
diff --git a/tests/bound002.phpt b/tests/bound002.phpt
new file mode 100644 (file)
index 0000000..d6521ba
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+fetch bound
+--SKIPIF--
+<?php 
+include "_skipif.inc";
+if (!pq\Types::DEFINED) {
+       die("skip pq\Types::DEFINED == false");
+} 
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+$r = $c->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