Fixed array parser compatibility with arrays of boxes
authorMichael Wallner <mike@php.net>
Fri, 22 May 2015 10:31:21 +0000 (12:31 +0200)
committerMichael Wallner <mike@php.net>
Fri, 22 May 2015 10:31:21 +0000 (12:31 +0200)
TODO
package.xml
php_pq_type.awk
php_pq_type.h
src/php_pq_misc.c
src/php_pq_params.c
tests/conv001.phpt
tests/types002.phpt

diff --git a/TODO b/TODO
index be41c6c10272e2319d42b5eb41b42a5fe4d8c867..4f7fadb019014cb69009b722abbc1da9eea3da01 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,4 +3,3 @@
 * fetchInto/fetchCtor?
 * binary protocol?
 * parse explicit array dimension information in front of arrays
-* compat for box arrays
index d1a8715ba7a9575a7e8e5cd8e173553aa47dd7e7..ea94c6c79db1005b81d6aee9539dfe3c99c5323c 100644 (file)
@@ -49,6 +49,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
  <license>BSD, revised</license>
  <notes><![CDATA[
 * Fixed crash with result iterator when the iterator exists longer than the result
+* Fixed array parser compatibility with arrays of boxes 
 * Added pq\Statement::deallocate{,Async}() and pq\Statement::prepare{,Async}() methods
 * Added pq\Statement::$query and pq\Statment::$types readonly properties
 ]]></notes>
index 15ffd1b975198924334508e074ea31fac7638142..b5d07b4d53c1a6e5707a5265610ef82bbbc4b9ae 100755 (executable)
@@ -13,22 +13,32 @@ END {
                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"
+       
+       printf "#ifndef PHP_PQ_DELIM_OF_ARRAY\n"
+       printf "# define PHP_PQ_DELIM_OF_ARRAY(oid) ("
+       for (oid in delims) {
+               printf "\\\n\t(oid) == %d ? '%s' : ", oid, delims[oid]
+       }
+       printf "0 \\\n)\n#endif\n"
 }
 
 /^DATA/ {
        oid = $4
        name = toupper($6)
+       adelim = $15
        atypoid = $17
        if (sub("^_", "", name)) {
                arrays[oid] = atypoid
                name = name "ARRAY"
        }
+       delims[oid] = adelim
        printf "#ifndef PHP_PQ_OID_%s\n", name
        printf "# define PHP_PQ_OID_%s %d\n", name, oid
        printf "#endif\n"
index e0fd421d7958150ede80456ccf4619a9e3ce6351..a1b373596e1791d1621b195b2adcbadb8762ef50 100644 (file)
@@ -770,3 +770,163 @@ PHP_PQ_TYPE("ANYRANGE", 3831)
        (oid) == 3927 ? 3926 : 0 \
 )
 #endif
+#ifndef PHP_PQ_DELIM_OF_ARRAY
+# define PHP_PQ_DELIM_OF_ARRAY(oid) (\
+       (oid) == 16 ? '\054' : \
+       (oid) == 17 ? '\054' : \
+       (oid) == 18 ? '\054' : \
+       (oid) == 19 ? '\054' : \
+       (oid) == 20 ? '\054' : \
+       (oid) == 21 ? '\054' : \
+       (oid) == 22 ? '\054' : \
+       (oid) == 23 ? '\054' : \
+       (oid) == 24 ? '\054' : \
+       (oid) == 25 ? '\054' : \
+       (oid) == 26 ? '\054' : \
+       (oid) == 27 ? '\054' : \
+       (oid) == 28 ? '\054' : \
+       (oid) == 29 ? '\054' : \
+       (oid) == 30 ? '\054' : \
+       (oid) == 71 ? '\054' : \
+       (oid) == 75 ? '\054' : \
+       (oid) == 81 ? '\054' : \
+       (oid) == 83 ? '\054' : \
+       (oid) == 114 ? '\054' : \
+       (oid) == 142 ? '\054' : \
+       (oid) == 143 ? '\054' : \
+       (oid) == 194 ? '\054' : \
+       (oid) == 199 ? '\054' : \
+       (oid) == 210 ? '\054' : \
+       (oid) == 600 ? '\054' : \
+       (oid) == 601 ? '\054' : \
+       (oid) == 602 ? '\054' : \
+       (oid) == 603 ? '\073' : \
+       (oid) == 604 ? '\054' : \
+       (oid) == 628 ? '\054' : \
+       (oid) == 629 ? '\054' : \
+       (oid) == 650 ? '\054' : \
+       (oid) == 651 ? '\054' : \
+       (oid) == 700 ? '\054' : \
+       (oid) == 701 ? '\054' : \
+       (oid) == 702 ? '\054' : \
+       (oid) == 703 ? '\054' : \
+       (oid) == 704 ? '\054' : \
+       (oid) == 705 ? '\054' : \
+       (oid) == 718 ? '\054' : \
+       (oid) == 719 ? '\054' : \
+       (oid) == 790 ? '\054' : \
+       (oid) == 791 ? '\054' : \
+       (oid) == 829 ? '\054' : \
+       (oid) == 869 ? '\054' : \
+       (oid) == 1000 ? '\054' : \
+       (oid) == 1001 ? '\054' : \
+       (oid) == 1002 ? '\054' : \
+       (oid) == 1003 ? '\054' : \
+       (oid) == 1005 ? '\054' : \
+       (oid) == 1006 ? '\054' : \
+       (oid) == 1007 ? '\054' : \
+       (oid) == 1008 ? '\054' : \
+       (oid) == 1009 ? '\054' : \
+       (oid) == 1010 ? '\054' : \
+       (oid) == 1011 ? '\054' : \
+       (oid) == 1012 ? '\054' : \
+       (oid) == 1013 ? '\054' : \
+       (oid) == 1014 ? '\054' : \
+       (oid) == 1015 ? '\054' : \
+       (oid) == 1016 ? '\054' : \
+       (oid) == 1017 ? '\054' : \
+       (oid) == 1018 ? '\054' : \
+       (oid) == 1019 ? '\054' : \
+       (oid) == 1020 ? '\073' : \
+       (oid) == 1021 ? '\054' : \
+       (oid) == 1022 ? '\054' : \
+       (oid) == 1023 ? '\054' : \
+       (oid) == 1024 ? '\054' : \
+       (oid) == 1025 ? '\054' : \
+       (oid) == 1027 ? '\054' : \
+       (oid) == 1028 ? '\054' : \
+       (oid) == 1033 ? '\054' : \
+       (oid) == 1034 ? '\054' : \
+       (oid) == 1040 ? '\054' : \
+       (oid) == 1041 ? '\054' : \
+       (oid) == 1042 ? '\054' : \
+       (oid) == 1043 ? '\054' : \
+       (oid) == 1082 ? '\054' : \
+       (oid) == 1083 ? '\054' : \
+       (oid) == 1114 ? '\054' : \
+       (oid) == 1115 ? '\054' : \
+       (oid) == 1182 ? '\054' : \
+       (oid) == 1183 ? '\054' : \
+       (oid) == 1184 ? '\054' : \
+       (oid) == 1185 ? '\054' : \
+       (oid) == 1186 ? '\054' : \
+       (oid) == 1187 ? '\054' : \
+       (oid) == 1231 ? '\054' : \
+       (oid) == 1263 ? '\054' : \
+       (oid) == 1266 ? '\054' : \
+       (oid) == 1270 ? '\054' : \
+       (oid) == 1560 ? '\054' : \
+       (oid) == 1561 ? '\054' : \
+       (oid) == 1562 ? '\054' : \
+       (oid) == 1563 ? '\054' : \
+       (oid) == 1700 ? '\054' : \
+       (oid) == 1790 ? '\054' : \
+       (oid) == 2201 ? '\054' : \
+       (oid) == 2202 ? '\054' : \
+       (oid) == 2203 ? '\054' : \
+       (oid) == 2204 ? '\054' : \
+       (oid) == 2205 ? '\054' : \
+       (oid) == 2206 ? '\054' : \
+       (oid) == 2207 ? '\054' : \
+       (oid) == 2208 ? '\054' : \
+       (oid) == 2209 ? '\054' : \
+       (oid) == 2210 ? '\054' : \
+       (oid) == 2211 ? '\054' : \
+       (oid) == 2249 ? '\054' : \
+       (oid) == 2275 ? '\054' : \
+       (oid) == 2276 ? '\054' : \
+       (oid) == 2277 ? '\054' : \
+       (oid) == 2278 ? '\054' : \
+       (oid) == 2279 ? '\054' : \
+       (oid) == 2280 ? '\054' : \
+       (oid) == 2281 ? '\054' : \
+       (oid) == 2282 ? '\054' : \
+       (oid) == 2283 ? '\054' : \
+       (oid) == 2287 ? '\054' : \
+       (oid) == 2776 ? '\054' : \
+       (oid) == 2949 ? '\054' : \
+       (oid) == 2950 ? '\054' : \
+       (oid) == 2951 ? '\054' : \
+       (oid) == 2970 ? '\054' : \
+       (oid) == 3115 ? '\054' : \
+       (oid) == 3220 ? '\054' : \
+       (oid) == 3221 ? '\054' : \
+       (oid) == 3500 ? '\054' : \
+       (oid) == 3614 ? '\054' : \
+       (oid) == 3615 ? '\054' : \
+       (oid) == 3642 ? '\054' : \
+       (oid) == 3643 ? '\054' : \
+       (oid) == 3644 ? '\054' : \
+       (oid) == 3645 ? '\054' : \
+       (oid) == 3734 ? '\054' : \
+       (oid) == 3735 ? '\054' : \
+       (oid) == 3769 ? '\054' : \
+       (oid) == 3770 ? '\054' : \
+       (oid) == 3802 ? '\054' : \
+       (oid) == 3807 ? '\054' : \
+       (oid) == 3831 ? '\054' : \
+       (oid) == 3838 ? '\054' : \
+       (oid) == 3904 ? '\054' : \
+       (oid) == 3905 ? '\054' : \
+       (oid) == 3906 ? '\054' : \
+       (oid) == 3907 ? '\054' : \
+       (oid) == 3908 ? '\054' : \
+       (oid) == 3909 ? '\054' : \
+       (oid) == 3910 ? '\054' : \
+       (oid) == 3911 ? '\054' : \
+       (oid) == 3912 ? '\054' : \
+       (oid) == 3913 ? '\054' : \
+       (oid) == 3926 ? '\054' : \
+       (oid) == 3927 ? '\054' : 0 \
+)
+#endif
index af36c33d15dd1c2c6c7b06acb34c87879de0ce46..a3db8bbcd52827c0f1258d4a841a77fa55975042 100644 (file)
@@ -25,6 +25,8 @@
 #include "php_pq.h"
 #include "php_pqexc.h"
 #include "php_pq_misc.h"
+#undef PHP_PQ_TYPE
+#include "php_pq_type.h"
 
 char *php_pq_rtrim(char *e)
 {
@@ -267,7 +269,7 @@ static ZEND_RESULT_CODE add_element(ArrayParserState *a, const char *start)
 
 static ZEND_RESULT_CODE parse_array(ArrayParserState *a);
 
-static ZEND_RESULT_CODE parse_element(ArrayParserState *a)
+static ZEND_RESULT_CODE parse_element(ArrayParserState *a, char delim)
 {
        const char *el;
        TSRMLS_FETCH_FROM_CTX(a->ts);
@@ -284,6 +286,10 @@ static ZEND_RESULT_CODE parse_element(ArrayParserState *a)
 
        for (el = a->ptr; a->ptr < a->end; ++a->ptr) {
                switch (*a->ptr) {
+               case '\\':
+                       a->escaped = !a->escaped;
+                       break;
+
                case '"':
                        if (a->escaped) {
                                a->escaped = 0;
@@ -300,20 +306,18 @@ static ZEND_RESULT_CODE parse_element(ArrayParserState *a)
                        }
                        break;
 
-               case ',':
+               default:
+                       if (delim != *a->ptr) {
+                               a->escaped = 0;
+                               break;
+                       }
+                       /* no break */
                case '}':
                        if (!a->quotes) {
                                return add_element(a, el);
                        }
                        break;
 
-               case '\\':
-                       a->escaped = !a->escaped;
-                       break;
-
-               default:
-                       a->escaped = 0;
-                       break;
                }
        }
 
@@ -323,10 +327,11 @@ static ZEND_RESULT_CODE parse_element(ArrayParserState *a)
 
 static ZEND_RESULT_CODE parse_elements(ArrayParserState *a)
 {
+       char delims[] = {'}', PHP_PQ_DELIM_OF_ARRAY(a->typ), 0};
        TSRMLS_FETCH_FROM_CTX(a->ts);
 
-       while (SUCCESS == parse_element(a)) {
-               switch (caa(a, ",}", 0)) {
+       while (SUCCESS == parse_element(a, delims[1])) {
+               switch (caa(a, delims, 0)) {
                case 0:
                        return FAILURE;
 
index 9554ef70f23e6f59442b0af7fbab4496a6b76f93..1ae7dd654ad1a54fb674b306c449ebc16436ea62 100644 (file)
@@ -134,6 +134,7 @@ struct apply_to_param_from_array_arg {
        unsigned index;
        smart_str *buffer;
        Oid type;
+       char delim;
        zval **zconv;
 };
 
@@ -146,7 +147,7 @@ static int apply_to_param_from_array(void *ptr, void *arg_ptr TSRMLS_DC)
        int tmp_len;
 
        if (arg->index++) {
-               smart_str_appendc(arg->buffer, ',');
+               smart_str_appendc(arg->buffer, arg->delim);
        }
 
        if (arg->zconv) {
@@ -241,6 +242,7 @@ static zval *array_param_to_string(php_pq_params_t *p, zval *zarr, Oid type TSRM
                arg.params = p;
                arg.buffer = &s;
                arg.type = PHP_PQ_TYPE_OF_ARRAY(type);
+               arg.delim = PHP_PQ_DELIM_OF_ARRAY(type);
                zend_hash_index_find(&p->type.conv, PHP_PQ_TYPE_OF_ARRAY(type), (void *) &arg.zconv);
                smart_str_appendc(arg.buffer, '{');
                MAKE_STD_ZVAL(zcopy);
index 6e794aa6af7896c122d299b18893553053848176..64488b5164e95c2ae11e6495697942e47b80af23 100644 (file)
@@ -78,6 +78,43 @@ class JSONConverter extends Converter
        }
 }
 
+class Point {
+       public $x;
+       public $y;
+       function __construct($x, $y) {
+               $this->x = $x;
+               $this->y = $y;
+       }
+}
+
+class Box {
+       public $p1;
+       public $p2;
+       function __construct(Point $p1, Point $p2) {
+               $this->p1 = $p1;
+               $this->p2 = $p2;
+       }
+}
+
+class BoxConverter extends Converter
+{
+       function convertTypes() {
+               return [ $this->types["box"]->oid ];
+       }
+
+       function convertToString($box, $type) {
+               return sprintf("(%F,%F),(%F,%F)",
+                               $box->p1->x, $box->p1->y,
+                               $box->p2->x, $box->p2->y
+               );
+       }
+
+       function convertFromString($data, $type) {
+               list($p1x, $p1y, $p2x, $p2y) = sscanf($data, "(%f,%f),(%f,%f)");
+               return new Box(new Point($p1x, $p1y), new Point($p2x, $p2y));
+       }
+}
+
 class Text {
        private $data;
        function __construct($data) {
@@ -97,8 +134,10 @@ $c->setConverter(new IntVectorConverter($t));
 if (!defined("pq\\Types::JSON")) {
        $c->setConverter(new JSONConverter($t));
 }
+$c->setConverter(new BoxConverter($t));
+
 $r = $c->execParams("SELECT \$1 as hs, \$2 as iv, \$3 as oids, \$4 as js, \$5 as ia, \$6 as ta, \$7 as ba, \$8 as da, \$9 as dbl, \$10 as bln, ".
-               "\$11 as dt1, \$12 as dt2, \$13 as dt3, \$14 as dt4, \$15 as dt5, \$16 as dt6, \$17 as dt7, \$18 as dt8, \$19 as txta ",
+               "\$11 as dt1, \$12 as dt2, \$13 as dt3, \$14 as dt4, \$15 as dt5, \$16 as dt6, \$17 as dt7, \$18 as dt8, \$19 as txta, \$20 as boxa",
        array(
                // hstore
                array(
@@ -141,7 +180,10 @@ $r = $c->execParams("SELECT \$1 as hs, \$2 as iv, \$3 as oids, \$4 as js, \$5 as
                new pq\Datetime,
                new pq\Datetime,
                new pq\Datetime,
+               // text array
                [new Text(0), new Text(" or "), new Text(true)],
+               // box array
+               [new Box(new Point(1,2), new Point(2,3)), new Box(new Point(3,4), new Point(4,5))],
        ),
        array(
                $t["hstore"]->oid,
@@ -162,7 +204,8 @@ $r = $c->execParams("SELECT \$1 as hs, \$2 as iv, \$3 as oids, \$4 as js, \$5 as
                $t["abstime"]->oid,
                $t["timestamp"]->oid,
                $t["timestamptz"]->oid,
-               $t["_text"]->oid
+               $t["_text"]->oid,
+               $t["_box"]->oid
        )
 );
 
@@ -366,6 +409,43 @@ array(1) {
       [2]=>
       string(1) "1"
     }
+    [19]=>
+    array(2) {
+      [0]=>
+      object(Box)#%d (2) {
+        ["p1"]=>
+        object(Point)#%d (2) {
+          ["x"]=>
+          float(2)
+          ["y"]=>
+          float(3)
+        }
+        ["p2"]=>
+        object(Point)#%d (2) {
+          ["x"]=>
+          float(1)
+          ["y"]=>
+          float(2)
+        }
+      }
+      [1]=>
+      object(Box)#%d (2) {
+        ["p1"]=>
+        object(Point)#%d (2) {
+          ["x"]=>
+          float(4)
+          ["y"]=>
+          float(5)
+        }
+        ["p2"]=>
+        object(Point)#%d (2) {
+          ["x"]=>
+          float(3)
+          ["y"]=>
+          float(4)
+        }
+      }
+    }
   }
 }
 Done
index 431ee3e1408734a74f688c0c06bb53d08b8a71be..7122cf1e3891a5bce26fcb1a1a6df75b0ea3d4b0 100644 (file)
@@ -25,14 +25,15 @@ true as bool,
 1::abstime as abstime,
 '2013-01-01 01:01:01'::timestamp as timestamp,
 '2013-01-01 01:01:01 UTC'::timestamptz as timestamptz,
-array[array[1,2,3],array[4,5,6],array[NULL::int,NULL::int,NULL::int]] as intarray  
+array[array[1,2,3],array[4,5,6],array[NULL::int,NULL::int,NULL::int]] as intarray,
+array[box(point(1,2),point(2,3)),box(point(4,5),point(5,6))] as boxarray
 ");
 var_dump($r->fetchRow(pq\Result::FETCH_ASSOC));
 ?>
 DONE
 --EXPECTF--
 Test
-array(12) {
+array(13) {
   ["null"]=>
   NULL
   ["bool"]=>
@@ -121,5 +122,12 @@ array(12) {
       NULL
     }
   }
+  ["boxarray"]=>
+  array(2) {
+    [0]=>
+    string(11) "(2,3),(1,2)"
+    [1]=>
+    string(11) "(5,6),(4,5)"
+  }
 }
 DONE
\ No newline at end of file