prepare v2.2.3 master v2.2.3
authorMichael Wallner <mike@php.net>
Mon, 5 Feb 2024 18:56:09 +0000 (19:56 +0100)
committerMichael Wallner <mike@php.net>
Mon, 5 Feb 2024 18:56:09 +0000 (19:56 +0100)
25 files changed:
.github/workflows/ci.yml
.gitignore
README.md
config9.m4
package.xml
php_pq.h
scripts/gen_github_workflow_ci.php
src/php_pq_misc.c
src/php_pq_misc.h
src/php_pq_module.c
src/php_pq_object.c
src/php_pq_params.c
src/php_pqconn.c
src/php_pqconn_event.c
src/php_pqlob.c
src/php_pqres.c
src/php_pqres.h
tests/_skipif.inc
tests/async010.phpt [new file with mode: 0644]
tests/basic003.phpt [new file with mode: 0644]
tests/crash_cur_reverse_dep.phpt
tests/crash_stm_reverse_dep.phpt
tests/crash_txn_reverse_dep.phpt
tests/gh-issue047_jsonb.phpt [new file with mode: 0644]
tests/types002.phpt

index 62c3b3503531afe33cd705f987c46a8c69449676..fd250c617ad438e5a8f8f036ad1423a8aabed55e 100644 (file)
@@ -8,14 +8,14 @@ on:
 
 jobs:
   old-matrix-0:
-    name: old-matrix-0
+    name: "old-matrix-0 (7.0)"
     env:
       PHP: "7.0"
       enable_debug: "yes"
       enable_maintainer_zts: "yes"
       enable_json: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -44,14 +44,14 @@ jobs:
           make -f scripts/ci/Makefile test
 
   old-matrix-1:
-    name: old-matrix-1
+    name: "old-matrix-1 (7.1)"
     env:
       PHP: "7.1"
       enable_debug: "yes"
       enable_maintainer_zts: "yes"
       enable_json: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -80,14 +80,14 @@ jobs:
           make -f scripts/ci/Makefile test
 
   old-matrix-2:
-    name: old-matrix-2
+    name: "old-matrix-2 (7.2)"
     env:
       PHP: "7.2"
       enable_debug: "yes"
       enable_maintainer_zts: "yes"
       enable_json: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -116,14 +116,14 @@ jobs:
           make -f scripts/ci/Makefile test
 
   old-matrix-3:
-    name: old-matrix-3
+    name: "old-matrix-3 (7.3)"
     env:
       PHP: "7.3"
       enable_debug: "yes"
       enable_maintainer_zts: "yes"
       enable_json: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -152,14 +152,14 @@ jobs:
           make -f scripts/ci/Makefile test
 
   old-matrix-4:
-    name: old-matrix-4
+    name: "old-matrix-4 (7.4)"
     env:
       PHP: "7.4"
       enable_debug: "yes"
       enable_maintainer_zts: "yes"
       enable_json: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -187,15 +187,87 @@ jobs:
         run: |
           make -f scripts/ci/Makefile test
 
-  master-0:
-    name: master-0
+  old-matrix-5:
+    name: "old-matrix-5 (8.0)"
+    env:
+      PHP: "8.0"
+      enable_debug: "yes"
+      enable_maintainer_zts: "yes"
+      enable_json: "yes"
+      PQ_DSN: "postgres:///runner"
+    runs-on: ubuntu-22.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          submodules: true
+      - name: Install
+        run: |
+          sudo apt-get install -y \
+            php-cli \
+            php-pear \
+            libpq-dev \
+            re2c
+      - name: Prepare
+        run: |
+          make -f scripts/ci/Makefile php || make -f scripts/ci/Makefile clean php
+          make -f scripts/ci/Makefile pecl PECL=m6w6/ext-raphf.git:raphf:master
+      - name: Build
+        run: |
+          make -f scripts/ci/Makefile ext PECL=pq
+      - name: Prepare Test
+        run: |
+          sudo systemctl start postgresql
+          sudo -u postgres createuser --login runner
+          sudo -u postgres createdb -O runner runner
+      - name: Test
+        run: |
+          make -f scripts/ci/Makefile test
+
+  old-matrix-6:
+    name: "old-matrix-6 (8.1)"
+    env:
+      PHP: "8.1"
+      enable_debug: "yes"
+      enable_maintainer_zts: "yes"
+      enable_json: "yes"
+      PQ_DSN: "postgres:///runner"
+    runs-on: ubuntu-22.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          submodules: true
+      - name: Install
+        run: |
+          sudo apt-get install -y \
+            php-cli \
+            php-pear \
+            libpq-dev \
+            re2c
+      - name: Prepare
+        run: |
+          make -f scripts/ci/Makefile php || make -f scripts/ci/Makefile clean php
+          make -f scripts/ci/Makefile pecl PECL=m6w6/ext-raphf.git:raphf:master
+      - name: Build
+        run: |
+          make -f scripts/ci/Makefile ext PECL=pq
+      - name: Prepare Test
+        run: |
+          sudo systemctl start postgresql
+          sudo -u postgres createuser --login runner
+          sudo -u postgres createdb -O runner runner
+      - name: Test
+        run: |
+          make -f scripts/ci/Makefile test
+
+  next-0:
+    name: "next-0 (master)"
     continue-on-error: true
     env:
       PHP: "master"
       enable_debug: "yes"
       enable_zts: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -224,13 +296,13 @@ jobs:
           make -f scripts/ci/Makefile test
 
   cur-dbg-zts-0:
-    name: cur-dbg-zts-0
+    name: "cur-dbg-zts-0 (8.2)"
     env:
-      PHP: "8.0"
+      PHP: "8.2"
       enable_debug: "yes"
       enable_zts: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -259,13 +331,13 @@ jobs:
           make -f scripts/ci/Makefile test
 
   cur-dbg-zts-1:
-    name: cur-dbg-zts-1
+    name: "cur-dbg-zts-1 (8.2)"
     env:
-      PHP: "8.0"
+      PHP: "8.2"
       enable_debug: "no"
       enable_zts: "yes"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -294,13 +366,13 @@ jobs:
           make -f scripts/ci/Makefile test
 
   cur-dbg-zts-2:
-    name: cur-dbg-zts-2
+    name: "cur-dbg-zts-2 (8.2)"
     env:
-      PHP: "8.0"
+      PHP: "8.2"
       enable_debug: "yes"
       enable_zts: "no"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -329,13 +401,13 @@ jobs:
           make -f scripts/ci/Makefile test
 
   cur-dbg-zts-3:
-    name: cur-dbg-zts-3
+    name: "cur-dbg-zts-3 (8.2)"
     env:
-      PHP: "8.0"
+      PHP: "8.2"
       enable_debug: "no"
       enable_zts: "no"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -364,13 +436,13 @@ jobs:
           make -f scripts/ci/Makefile test
 
   cur-cov-0:
-    name: cur-cov-0
+    name: "cur-cov-0 (8.2)"
     env:
       CFLAGS: "-O0 -g --coverage"
       CXXFLAGS: "-O0 -g --coverage"
-      PHP: "8.0"
+      PHP: "8.2"
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
index 902c527ccc93308b404f4d1178ab046d1b3f4f5d..9f531088a4c57f1fb41a04f29a4da4c7c8ec13e9 100644 (file)
@@ -3,6 +3,8 @@
 *~
 /*.tgz
 .deps
+*.dep
+*.o
 *.lo
 *.la
 /config.[^m]*
index a7d54c38b399acc935d11e7941b701571d9584f1..c823ddd998ebf5988c50bf72a5b4b96ef689b51a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -9,8 +9,8 @@ This is a modern binding to the mature [libpq](http://www.postgresql.org/docs/cu
 
 ### Highlights:
 
-* Nearly 100% support for [asynchronous usage](https://mdref.m6w6.name/pq/Connection/:+Asynchronous+Usage).
-* Extended [type support by pg_type](https://mdref.m6w6.name/pq/Types/:+Overview).
+* Nearly 100% support for [asynchronous usage](https://mdref.m6w6.name/pq/Connection/:%20Asynchronous%20Usage).
+* Extended [type support by pg_type](https://mdref.m6w6.name/pq/Types/:%20Overview).
 * Fetching simple [multi-dimensional array maps](https://mdref.m6w6.name/pq/Result/map).
 * Working [Gateway implementation](https://github.com/m6w6/pq-gateway).
 
index 9782d185720f6307f13784b6064e10ce1902fb18..d845e282d4652f321c27b1bf8d637656b80058ee 100644 (file)
@@ -7,7 +7,7 @@ if test "$PHP_PQ" != "no"; then
        if test "$PHP_PQ" != "yes"; then
                SEARCH_PATH="$PHP_PQ $SEARCH_PATH"
        fi
-       
+
        AC_MSG_CHECKING(for pg_config)
        for i in $SEARCH_PATH; do
                if test -x "$i/bin/pg_config"; then
@@ -15,20 +15,20 @@ if test "$PHP_PQ" != "no"; then
                        break
                fi
        done
-       
+
        if test -z "$PG_CONFIG"; then
                AC_PATH_PROG(PG_CONFIG, pg_config, no)
        fi
-       
+
        AC_MSG_RESULT($PG_CONFIG)
-       
+
        if test "$PG_CONFIG" = "no"; then
                AC_MSG_ERROR(could not find a usable pg_config in $SEARCH_PATH)
        else
                if test "$PHP_PQ" != "yes" -a "$PHP_PQ/bin/pg_config" != "$PG_CONFIG"; then
                        AC_MSG_WARN(Found pg_config is not in $PHP_PQ)
                fi
-               
+
                AC_MSG_CHECKING(for PostgreSQL version)
                PQ_VERSION=$($PG_CONFIG --version | $SED 's/PostgreSQL //')
 
@@ -39,7 +39,7 @@ if test "$PHP_PQ" != "no"; then
                        AC_MSG_RESULT($PQ_VERSION)
                        AC_DEFINE_UNQUOTED(PHP_PQ_LIBVERSION, "$PQ_VERSION", [ ])
                fi
-               
+
                PQ_INCDIR=$($PG_CONFIG --includedir)
                PQ_LIBDIR=$($PG_CONFIG --libdir)
        fi
@@ -76,19 +76,22 @@ if test "$PHP_PQ" != "no"; then
        dnl PQ_CHECK_FUNC(sym, fail-hard)
        dnl
        AC_DEFUN([PQ_CHECK_FUNC], [
+               PQ_SYM=$1
                FAIL_HARD=$2
-
+               save_LIBS="$LIBS"
+               LIBS=
                PHP_CHECK_LIBRARY(pq, $1, [
                        AC_DEFINE([HAVE_]translit($1,a-z,A-Z), 1, Have $1)
                ], [
                        if test -n "$FAIL_HARD"; then
-                               if "$FAIL_HARD"; then
-                                       AC_MSG_ERROR(could not find $PQ_SYM in -lpq)
+                               if $FAIL_HARD; then
+                                       AC_MSG_ERROR(could not find $PQ_SYM in -lpq -L$PQ_LIBDIR)
                                fi
                        fi
                ], [
                        -L$PQ_LIBDIR
                ])
+               LIBS="$save_LIBS"
        ])
 
        PQ_CHECK_FUNC(PQregisterEventProc, true)
@@ -96,6 +99,8 @@ if test "$PHP_PQ" != "no"; then
        PHP_SUBST(PQ_SHARED_LIBADD)
 
        PQ_CHECK_FUNC(PQlibVersion)
+       PQ_CHECK_FUNC(PQprotocolVersion)
+       PQ_CHECK_FUNC(PQserverVersion)
        PQ_CHECK_FUNC(PQconninfo)
        PQ_CHECK_FUNC(PQsetSingleRowMode)
 
@@ -175,26 +180,4 @@ if test "$PHP_PQ" != "no"; then
                AC_MSG_ERROR([Please install pecl/raphf and activate extension=raphf.$SHLIB_DL_SUFFIX_NAME in your php.ini])
        ])
        PHP_ADD_EXTENSION_DEP(pq, raphf, true)
-       PQ_HAVE_PHP_EXT([json], [
-               AC_MSG_CHECKING([for php_json.h])
-               PQ_EXT_JSON_INCDIR=
-               for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../json ../jsonc ../jsond; do
-                       if test -d $i; then
-                               if test -f $i/php_json.h; then
-                                       PQ_EXT_JSON_INCDIR=$i
-                                       break
-                               elif test -f $i/ext/json/php_json.h; then
-                                       PQ_EXT_JSON_INCDIR=$i/ext/json
-                                       break
-                               fi
-                       fi
-               done
-               if test "x$PQ_EXT_JSON_INCDIR" = "x"; then
-                       AC_MSG_ERROR([not found])
-               else
-                       AC_MSG_RESULT([$PQ_EXT_JSON_INCDIR])
-                       AC_DEFINE([PHP_PQ_HAVE_PHP_JSON_H], [1], [Have ext/json support])
-                       PHP_ADD_INCLUDE([$PQ_EXT_JSON_INCDIR])
-               fi
-       ])
 fi
index 400c5afe40adde305b16b404df12eb7807d17638..e6b668e4234908f8ccdf42539e89204d5b38bc51 100644 (file)
@@ -41,9 +41,9 @@
   <email>remi@php.net</email>
   <active>yes</active>
  </developer>
- <date>2020-09-24</date>
+ <date>2024-02-05</date>
  <version>
-  <release>2.1.9dev</release>
+  <release>2.2.3</release>
   <api>2.1.0</api>
  </version>
  <stability>
@@ -52,7 +52,7 @@
  </stability>
  <license uri="http://copyfree.org/content/standard/licenses/2bsd/license.txt">BSD-2-Clause</license>
  <notes><![CDATA[
-  *
+  * Fix incompatible pointer types (32-bit) (see hg issue #52)
 ]]></notes>
  <contents>
   <dir name="/">
     <file role="test" name="async007.phpt" />
     <file role="test" name="async008.phpt" />
     <file role="test" name="async009.phpt" />
+    <file role="test" name="async010.phpt" />
     <file role="test" name="basic001.phpt" />
     <file role="test" name="basic002.phpt" />
+    <file role="test" name="basic003.phpt" />
     <file role="test" name="bound002.phpt" />
     <file role="test" name="callback001.phpt" />
     <file role="test" name="callback002.phpt" />
     <file role="test" name="flush001.phpt" />
     <file role="test" name="gh-issue015_listeners.phpt" />
     <file role="test" name="gh-issue015_statements.phpt" />
+    <file role="test" name="gh-issue047_jsonb.phpt" />
     <file role="test" name="info001.phpt" />
     <file role="test" name="info002.phpt" />
     <file role="test" name="lob001.phpt" />
index a422b6a31d526b75c537ee2f9c388e6e7234391e..022c5535adec096828322c78d3c8f7950fe1e0e1 100644 (file)
--- a/php_pq.h
+++ b/php_pq.h
@@ -14,7 +14,7 @@
 #ifndef PHP_PQ_H
 #define PHP_PQ_H
 
-#define PHP_PQ_VERSION "2.1.9dev"
+#define PHP_PQ_VERSION "2.2.3"
 
 #ifdef PHP_WIN32
 #      define PHP_PQ_API __declspec(dllexport)
index 4b95237006c5541c5ca6a35edbcc8315867801b3..78d770a0fc33ea4e43c8165c32c768f6326b7e26 100755 (executable)
@@ -11,24 +11,24 @@ jobs:
 <?php
 
 $gen = include __DIR__ . "/ci/gen-matrix.php";
-$cur = "8.0";
+$cur = "8.2";
 $job = $gen->github([
 "old-matrix" => [
-       "PHP" => ["7.0", "7.1", "7.2", "7.3", "7.4"],
+       "PHP" => ["7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1"],
        "enable_debug" => "yes",
        "enable_maintainer_zts" => "yes",
        "enable_json" => "yes",
-], 
-"master" => [
+],
+"next" => [
     "PHP" => ["master"],
     "enable_debug" => "yes",
     "enable_zts" => "yes",
-], 
+],
 "cur-dbg-zts" => [
     "PHP" => $cur,
     "enable_debug",
     "enable_zts",
-], 
+],
 "cur-cov" => [
     "CFLAGS" => "-O0 -g --coverage",
     "CXXFLAGS" => "-O0 -g --coverage",
@@ -36,7 +36,7 @@ $job = $gen->github([
 ]]);
 foreach ($job as $id => $env) {
     printf("  %s:\n", $id);
-    printf("    name: %s\n", $id);
+    printf("    name: \"%s (%s)\"\n", $id, $env["PHP"]);
     if ($env["PHP"] == "master") {
         printf("    continue-on-error: true\n");
     }
@@ -46,7 +46,7 @@ foreach ($job as $id => $env) {
     }
 ?>
       PQ_DSN: "postgres:///runner"
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v2
         with:
index 3e334c6e5e6fcbbe47c1804bf9aac6275131e968..4d251d2b5415c1b0846a2a1dd89969a296ee416b 100644 (file)
 #undef PHP_PQ_TYPE
 #include "php_pq_type.h"
 
+/* convert version to string */
+extern void php_pq_version_to_string(int version, char *buffer, int len) {
+       if (version < 100000) {
+               slprintf(buffer, len, "%d.%d.%d", version/10000, version/100%100, version%100);
+       } else { /* since version 10 */
+               slprintf(buffer, len, "%d.%d", version/10000, version%100);
+       }
+}
 
 /* clear result object associated with a result handle */
 void php_pqres_clear(PGresult *r) {
@@ -131,7 +139,18 @@ void php_pq_hash_ptr_dtor(zval *p)
 
 zend_class_entry *php_pqdt_class_entry;
 
+#if PHP_VERSION_ID >= 80100
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_pqdt_jsonserialize, 0, 0, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+#else
+#define ai_pqdt_jsonserialize ai_pqdt_to_string
+#endif
+
+#if PHP_VERSION_ID >= 80200
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(ai_pqdt_to_string, 0, 0, IS_STRING, 0)
+#else
 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_to_string, 0, 0, 0)
+#endif
 ZEND_END_ARG_INFO();
 static PHP_METHOD(pqdt, __toString)
 {
@@ -142,7 +161,11 @@ static PHP_METHOD(pqdt, __toString)
        RETVAL_ZVAL(&rv, 1, 1);
 }
 
+#if PHP_VERSION_ID >= 80100
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(ai_pqdt_create_from_format, 0, 2, DateTime, MAY_BE_FALSE)
+#else
 ZEND_BEGIN_ARG_INFO_EX(ai_pqdt_create_from_format, 0, 0, 2)
+#endif
        ZEND_ARG_INFO(0, format)
        ZEND_ARG_INFO(0, datetime)
 #if PHP_VERSION_ID >= 70200
@@ -171,7 +194,7 @@ static PHP_METHOD(pqdt, createFromFormat)
 static zend_function_entry php_pqdt_methods[] = {
        PHP_ME(pqdt, createFromFormat, ai_pqdt_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
        PHP_ME(pqdt, __toString, ai_pqdt_to_string, ZEND_ACC_PUBLIC)
-       PHP_MALIAS(pqdt, jsonSerialize, __toString, ai_pqdt_to_string, ZEND_ACC_PUBLIC)
+       PHP_MALIAS(pqdt, jsonSerialize, __toString, ai_pqdt_jsonserialize, ZEND_ACC_PUBLIC)
        {0}
 };
 
index 7ccda3e302b25a34bae39f5bbafd21ef00a2d208..dab24ec7d1ee7231d34ca33778e9a1ecbc5b51d5 100644 (file)
@@ -33,6 +33,8 @@ extern PGresult *php_pq_exec_params(PGconn *conn, const char *command, int nPara
 extern PGresult *php_pq_prepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes);
 extern PGresult *php_pq_exec_prepared(PGconn *conn, const char *stmtName, int nParams, const char *const * paramValues, const int *paramLengths, const int *paramFormats, int resultFormat);
 
+/* convert version to string */
+extern void php_pq_version_to_string(int version, char *buffer, int len);
 
 /* trim LF from EOL */
 extern char *php_pq_rtrim(char *e);
@@ -75,7 +77,7 @@ extern int php_pq_compare_index(Bucket *lptr, Bucket *rptr);
 
 extern int php_pq_compare_index(const void *lptr, const void *rptr);
 
-# define zend_ze_countable spl_ce_Countable
+# define zend_ce_countable spl_ce_Countable
 
 # define php_pq_call_method(objval_ptr, method_name, num_args, ...) \
                zend_call_method_with_ ## num_args ## _params( \
@@ -92,8 +94,16 @@ extern int php_pq_compare_index(const void *lptr, const void *rptr);
                                SUCCESS == Z_OBJ_HT_P(objval_ptr)->cast_object(objval_ptr, (retval_ptr), (cast_type)))
 #endif
 
+#if PHP_VERSION_ID < 80100
+# define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
+                ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args)
+# define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
+                ZEND_BEGIN_ARG_INFO_EX(name, 0, return_reference, required_num_args)
+#endif
 
-
+#ifndef ZEND_ACC_READONLY
+#define ZEND_ACC_READONLY 0
+#endif
 
 extern PHP_MINIT_FUNCTION(pq_misc);
 
index cd992172d9e524bc9c6ccdd15d151fcdf43c806e..7385b0b378f234f861da3c0b8cb161432c6b11c6 100644 (file)
@@ -105,7 +105,7 @@ static PHP_MINFO_FUNCTION(pq)
        php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
 #ifdef HAVE_PQLIBVERSION
        libpq_v = PQlibVersion();
-       slprintf(libpq_version, sizeof(libpq_version), "%d.%d.%d", libpq_v/10000%100, libpq_v/100%100, libpq_v%100);
+       php_pq_version_to_string(libpq_v, libpq_version, sizeof(libpq_version));
 #endif
        php_info_print_table_row(3, "libpq", PHP_PQ_LIBVERSION, libpq_version);
        php_info_print_table_end();
index c8d1e50bc73d4b1df3c119c48dabf396b4223e2e..5b3f217a95f7e7bb4c9561a7d954a34359787089 100644 (file)
@@ -176,9 +176,11 @@ static inline HashTable *php_pq_object_get_gc_ex(zend_object *object, HashTable
        arg.ht = &arg.pq_obj->gc;
        arg.gc = 1;
 
-       zend_hash_clean(arg.ht);
-       zend_hash_copy(arg.ht, props, NULL);
-       zend_hash_apply_with_argument(&arg.pq_obj->zo.ce->properties_info, apply_pi_to_ht, &arg);
+       if (GC_REFCOUNT(arg.ht) == 1) {
+               zend_hash_clean(arg.ht);
+               zend_hash_copy(arg.ht, props, NULL);
+               zend_hash_apply_with_argument(&arg.pq_obj->zo.ce->properties_info, apply_pi_to_ht, &arg);
+       }
 
        *table = NULL;
        *n = 0;
index 259fbb9a13b1c4b6e3c2d243e5106f39c1e9763d..9e92226f7b3f83b5fe07e03cb4681768bbd2fa60 100644 (file)
@@ -16,9 +16,7 @@
 
 #include <php.h>
 #include <ext/standard/php_string.h>
-#if PHP_PQ_HAVE_PHP_JSON_H
-#include <php_json.h> /* we've added the include directory to INCLUDES */
-#endif
+#include <ext/json/php_json.h>
 
 #include <Zend/zend_smart_str.h>
 #include <Zend/zend_interfaces.h>
@@ -75,12 +73,12 @@ unsigned php_pq_params_add_type_oid(php_pq_params_t *p, Oid type)
 
 static zend_string *object_param_to_string(php_pq_params_t *p, zval *zobj, Oid type)
 {
-#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
+#ifdef PHP_PQ_OID_JSON
        smart_str str = {0};
 #endif
 
        switch (type) {
-#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
+#ifdef PHP_PQ_OID_JSON
 # ifdef PHP_PQ_OID_JSONB
        case PHP_PQ_OID_JSONB:
 # endif
@@ -207,7 +205,7 @@ static zend_string *array_param_to_string(php_pq_params_t *p, zval *zarr, Oid ty
        struct apply_to_param_from_array_arg arg = {NULL};
 
        switch (type) {
-#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
+#ifdef PHP_PQ_OID_JSON
 # ifdef PHP_PQ_OID_JSONB
        case PHP_PQ_OID_JSONB:
 # endif
index 3a44a952a944548d4d5c94945874c1aa9f546877..19ea6f05ebcaebd0abb059d475c7bad802f29128 100644 (file)
@@ -491,6 +491,34 @@ static void php_pqconn_object_write_def_auto_conv(void *o, zval *value)
        obj->intern->default_auto_convert = zval_get_long(value) & PHP_PQRES_CONV_ALL;
 }
 
+#ifdef HAVE_PQLIBVERSION
+static void php_pqconn_object_read_lib_version(void *o, zval *return_value)
+{
+       char ver[16];
+
+       php_pq_version_to_string(PQlibVersion(), ver, sizeof(ver));
+       RETVAL_STRING(ver);
+}
+#endif
+#ifdef HAVE_PQPROTOCOLVERSION
+static void php_pqconn_object_read_protocol_version(void *o, zval *return_value)
+{
+       php_pqconn_object_t *obj = o;
+
+       RETVAL_LONG(PQprotocolVersion(obj->intern->conn));
+}
+#endif
+#ifdef HAVE_PQSERVERVERSION
+static void php_pqconn_object_read_server_version(void *o, zval *return_value)
+{
+       php_pqconn_object_t *obj = o;
+       char ver[16];
+
+       php_pq_version_to_string(PQserverVersion(obj->intern->conn), ver, sizeof(ver));
+       RETVAL_STRING(ver);
+}
+#endif
+
 static ZEND_RESULT_CODE php_pqconn_update_socket(zval *zobj, php_pqconn_object_t *obj)
 {
        zval zsocket, zmember;
@@ -590,7 +618,7 @@ static inline PGresult *unlisten(PGconn *conn, const char *channel_str, size_t c
                smart_str_appends(&cmd, quoted_channel);
                smart_str_0(&cmd);
 
-               res = PQexec(conn, smart_str_v(&cmd));
+               res = php_pq_exec(conn, smart_str_v(&cmd));
 
                smart_str_free(&cmd);
                PQfreemem(quoted_channel);
@@ -990,7 +1018,7 @@ static PHP_METHOD(pqconn, notify) {
                        PGresult *res;
                        char *params[2] = {channel_str, message_str};
 
-                       res = PQexecParams(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
+                       res = php_pq_exec_params(obj->intern->conn, "select pg_notify($1, $2)", 2, NULL, (const char *const*) params, NULL, NULL, 0);
 
                        if (!res) {
                                throw_exce(EX_RUNTIME, "Failed to notify listeners (%s)", PHP_PQerrorMessage(obj->intern->conn));
@@ -1224,7 +1252,7 @@ static PHP_METHOD(pqconn, execParams) {
                        php_pq_params_t *params;
 
                        params = php_pq_params_init(&obj->intern->converters, ztypes ? Z_ARRVAL_P(ztypes) : NULL, Z_ARRVAL_P(zparams));
-                       res = PQexecParams(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
+                       res = php_pq_exec_params(obj->intern->conn, query_str, params->param.count, params->type.oids, (const char *const*) params->param.strings, NULL, NULL, 0);
                        php_pq_params_free(&params);
 
                        if (!res) {
@@ -2131,6 +2159,24 @@ PHP_MINIT_FUNCTION(pqconn)
        zend_hash_str_add_mem(&php_pqconn_object_prophandlers, "defaultAutoConvert", sizeof("defaultAutoConvert")-1, (void *) &ph, sizeof(ph));
        ph.write = NULL;
 
+#ifdef HAVE_PQLIBVERSION
+       zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("libraryVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY);
+       ph.read = php_pqconn_object_read_lib_version;
+       zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("libraryVersion"), (void *) &ph, sizeof(ph));
+#endif
+
+#ifdef HAVE_PQPROTOCOLVERSION
+       zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("protocolVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY);
+       ph.read = php_pqconn_object_read_protocol_version;
+       zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("protocolVersion"), (void *) &ph, sizeof(ph));
+#endif
+
+#ifdef HAVE_PQSERVERVERSION
+       zend_declare_property_null(php_pqconn_class_entry, ZEND_STRL("serverVersion"), ZEND_ACC_PUBLIC|ZEND_ACC_READONLY);
+       ph.read = php_pqconn_object_read_server_version;
+       zend_hash_str_add_mem(&php_pqconn_object_prophandlers, ZEND_STRL("serverVersion"), (void *) &ph, sizeof(ph));
+#endif
+
        zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("OK"), CONNECTION_OK);
        zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("BAD"), CONNECTION_BAD);
        zend_declare_class_constant_long(php_pqconn_class_entry, ZEND_STRL("STARTED"), CONNECTION_STARTED);
index 802a9e482914235a3eeb39a081261b014871de4d..13e790a2cc3605472b11edcfde794e411d65472c 100644 (file)
@@ -55,7 +55,7 @@ static inline PGresult *relisten(PGconn *conn, const char *channel_str, size_t c
                smart_str_appends(&cmd, quoted_channel);
                smart_str_0(&cmd);
 
-               res = PQexec(conn, smart_str_v(&cmd));
+               res = php_pq_exec(conn, smart_str_v(&cmd));
 
                smart_str_free(&cmd);
                PQfreemem(quoted_channel);
index 0cb44a896875669ca4b4f5e42359117252b9a7a8..a419390119d1f7aa23b0e63f38f305b517b54da6 100644 (file)
@@ -169,7 +169,7 @@ static int php_pqlob_stream_flush(php_stream *stream)
        return SUCCESS;
 }
 
-static ZEND_RESULT_CODE php_pqlob_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset)
+static ZEND_RESULT_CODE php_pqlob_stream_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
 {
        ZEND_RESULT_CODE rv = FAILURE;
        php_pqlob_object_t *obj = stream->abstract;
index be3d039e9699e5142903f548fe7570009fd047e1..802fcf4a85484b506ed1c87cc58126869b7704df 100644 (file)
@@ -17,9 +17,7 @@
 #include <php.h>
 
 #include <ext/spl/spl_iterators.h>
-#if PHP_PQ_HAVE_PHP_JSON_H
-#include <php_json.h> /* we've added the include directory to INCLUDES */
-#endif
+#include <ext/json/php_json.h>
 
 #include <libpq-events.h>
 
@@ -215,7 +213,7 @@ zval *php_pqres_typed_zval(php_pqres_t *res, Oid typ, zval *zv)
                php_pqdt_from_string(zv, NULL, str->val, str->len, "Y-m-d H:i:s.uO", NULL);
                break;
 
-#if PHP_PQ_HAVE_PHP_JSON_H && defined(PHP_PQ_OID_JSON)
+#ifdef PHP_PQ_OID_JSON
 # ifdef PHP_PQ_OID_JSONB
        case PHP_PQ_OID_JSONB:
 # endif
@@ -227,6 +225,23 @@ zval *php_pqres_typed_zval(php_pqres_t *res, Oid typ, zval *zv)
                break;
 #endif
 
+       case PHP_PQ_OID_BYTEA:
+               if (!(res->auto_convert & PHP_PQRES_CONV_BYTEA)) {
+                       goto noconversion;
+               } else {
+                       size_t to_len;
+                       char *to_str = (char *) PQunescapeBytea((unsigned char *) str->val, &to_len);
+
+                       if (!to_str) {
+                               ZVAL_NULL(zv);
+                               php_error_docref(NULL, E_WARNING, "Failed to unsescape BYTEA: '%s'", str->val);
+                       } else {
+                               ZVAL_STRINGL(zv, to_str, to_len);
+                               PQfreemem(to_str);
+                       }
+               }
+               break;
+
        default:
                if (!(res->auto_convert & PHP_PQRES_CONV_ARRAY)) {
                        goto noconversion;
@@ -383,24 +398,24 @@ static zend_object_iterator_funcs php_pqres_iterator_funcs = {
 #endif
 };
 
-static inline ZEND_RESULT_CODE php_pqres_count_elements_ex(zend_object *object, long *count)
+static inline ZEND_RESULT_CODE php_pqres_count_elements_ex(zend_object *object, zend_long *count)
 {
        php_pqres_object_t *obj = PHP_PQ_OBJ(NULL, object);
 
        if (!obj->intern) {
                return FAILURE;
        } else {
-               *count = (long) PQntuples(obj->intern->res);
+               *count = (zend_long) PQntuples(obj->intern->res);
                return SUCCESS;
        }
 }
 #if PHP_VERSION_ID >= 80000
-static ZEND_RESULT_CODE php_pqres_count_elements(zend_object *object, long *count)
+static ZEND_RESULT_CODE php_pqres_count_elements(zend_object *object, zend_long *count)
 {
        return php_pqres_count_elements_ex(object, count);
 }
 #else
-static ZEND_RESULT_CODE php_pqres_count_elements(zval *object, long *count)
+static ZEND_RESULT_CODE php_pqres_count_elements(zval *object, zend_long *count)
 {
        return php_pqres_count_elements_ex(Z_OBJ_P(object), count);
 }
@@ -721,7 +736,7 @@ static ZEND_RESULT_CODE column_nn(php_pqres_object_t *obj, zval *zcol, php_pqres
        }
 
        if (!col->name) {
-               php_error_docref(NULL, E_WARNING, "Failed to find column at index %ld", index);
+               php_error_docref(NULL, E_WARNING, "Failed to find column at index " ZEND_LONG_FMT, index);
                return FAILURE;
        }
        if (col->num == -1) {
@@ -776,7 +791,7 @@ static int apply_bound(zval *zbound, int argc, va_list argv, zend_hash_key *key)
        ZEND_RESULT_CODE *rv = va_arg(argv, ZEND_RESULT_CODE *);
 
        if (!(zvalue = zend_hash_index_find(Z_ARRVAL_P(zrow), key->h))) {
-               php_error_docref(NULL, E_WARNING, "Failed to find column ad index %lu", key->h);
+               php_error_docref(NULL, E_WARNING, "Failed to find column ad index " ZEND_ULONG_FMT, key->h);
                *rv = FAILURE;
                return ZEND_HASH_APPLY_STOP;
        } else {
@@ -1146,7 +1161,7 @@ static PHP_METHOD(pqres, fetchAll) {
        }
 }
 
-ZEND_BEGIN_ARG_INFO_EX(ai_pqres_count, 0, 0, 0)
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_pqres_count, 0, 0, IS_LONG, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(pqres, count) {
        zend_error_handling zeh;
@@ -1157,7 +1172,7 @@ static PHP_METHOD(pqres, count) {
        zend_restore_error_handling(&zeh);
 
        if (SUCCESS == rv) {
-               long count;
+               zend_long count;
 
                if (SUCCESS != php_pqres_count_elements_ex(Z_OBJ_P(getThis()), &count)) {
                        throw_exce(EX_UNINITIALIZED, "pq\\Result not initialized");
@@ -1194,7 +1209,7 @@ static PHP_METHOD(pqres, desc) {
 }
 
 #if PHP_VERSION_ID >= 80000
-ZEND_BEGIN_ARG_INFO_EX(ai_pqres_getIterator, 0, 0, 0)
+ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(ai_pqres_getIterator, 0, 0, Traversable, 0)
 ZEND_END_ARG_INFO();
 static PHP_METHOD(pqres, getIterator)
 {
@@ -1333,9 +1348,8 @@ PHP_MINIT_FUNCTION(pqres)
        zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_SCALAR"), PHP_PQRES_CONV_SCALAR);
        zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ARRAY"), PHP_PQRES_CONV_ARRAY);
        zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_DATETIME"), PHP_PQRES_CONV_DATETIME);
-#if PHP_PQ_HAVE_PHP_JSON_H
        zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_JSON"), PHP_PQRES_CONV_JSON);
-#endif
+       zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_BYTEA"), PHP_PQRES_CONV_BYTEA);
        zend_declare_class_constant_long(php_pqres_class_entry, ZEND_STRL("CONV_ALL"), PHP_PQRES_CONV_ALL);
 
        return SUCCESS;
index cc20ddbbc764e15524f71e0f494b40ac21c84611..79507fdf1fa9ca5b1aac9c77cf930e98786cedfc 100644 (file)
@@ -25,6 +25,7 @@ typedef enum php_pqres_fetch {
 #define PHP_PQRES_CONV_BOOL            0x0001
 #define PHP_PQRES_CONV_INT             0x0002
 #define PHP_PQRES_CONV_FLOAT   0x0004
+#define PHP_PQRES_CONV_BYTEA   0x0008
 #define PHP_PQRES_CONV_SCALAR  0x000f
 #define PHP_PQRES_CONV_ARRAY   0x0010
 #define PHP_PQRES_CONV_DATETIME        0x0020
index 9bf235c5fa17ec595b7fcd8bd6939e8ba4a48656..0391d77e059a5fd4359defca669f6961a639a934 100644 (file)
@@ -6,7 +6,10 @@ _ext("pq");
 include "_setup.inc";
 defined("PQ_DSN") or die("skip PQ_DSN undefined");
 try {
-       new pq\Connection(PQ_DSN);
+       $c = new pq\Connection(PQ_DSN);
+       if (defined("SERVER_MIN") && version_compare(SERVER_MIN, $c->serverVersion) > 0) {
+               die("skip server {$c->serverVersion} is too old, needed " . SERVER_MIN);
+       }
 } catch (pq\Exception $e) {
        die("skip could not connect to PQ_DSN ".$e->getMessage());
 }
diff --git a/tests/async010.phpt b/tests/async010.phpt
new file mode 100644 (file)
index 0000000..a38b66d
--- /dev/null
@@ -0,0 +1,67 @@
+--TEST--
+asnyc query not cleaned before sync exec
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php
+echo "Test\n";
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+
+var_dump([
+       "async" => $c->execAsync("select clock_timestamp(), pg_sleep(0.1), clock_timestamp()", function($r) {
+               var_dump([
+                       "cb" => $r->fetchRow()
+               ]);
+       })
+]);
+
+var_dump([
+       "execParams" => $c->execParams("select \$1::int4", [123])->fetchRow()
+]);
+?>
+DONE
+--EXPECTF--
+Test
+array(1) {
+  ["async"]=>
+  NULL
+}
+array(1) {
+  ["cb"]=>
+  array(3) {
+    [0]=>
+    object(pq\DateTime)#%d (4) {
+      ["format"]=>
+      string(14) "Y-m-d H:i:s.uO"
+      ["date"]=>
+      string(26) "%s"
+      ["timezone_type"]=>
+      int(1)
+      ["timezone"]=>
+      string(6) "%s"
+    }
+    [1]=>
+    string(0) ""
+    [2]=>
+    object(pq\DateTime)#%d (4) {
+      ["format"]=>
+      string(14) "Y-m-d H:i:s.uO"
+      ["date"]=>
+      string(26) "%s"
+      ["timezone_type"]=>
+      int(1)
+      ["timezone"]=>
+      string(6) "%s"
+    }
+  }
+}
+array(1) {
+  ["execParams"]=>
+  array(1) {
+    [0]=>
+    int(123)
+  }
+}
+DONE
diff --git a/tests/basic003.phpt b/tests/basic003.phpt
new file mode 100644 (file)
index 0000000..4645e8c
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+basic functionality
+--SKIPIF--
+<?php include "_skipif.inc"; ?>
+--FILE--
+<?php
+echo "Test\n";
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+
+var_dump($c->libraryVersion);
+var_dump($c->protocolVersion);
+var_dump($c->serverVersion);
+?>
+DONE
+--EXPECTF--
+Test
+string(%d) "%s"
+int(%d)
+string(%d) "%s"
+DONE
index a9f4d1909ba4ff1bf4f7b3e4cbcec4212fe7faea..c97d73aa34b2102128a2d6e006061bd3b1a9a9a8 100644 (file)
@@ -3,6 +3,8 @@ crash txn reverse dependency from connection
 --SKIPIF--
 <?php
 include "_skipif.inc";
+if (version_compare(PHP_VERSION, "8.2", ">="))
+       echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n";
 ?>
 --FILE--
 <?php
index 4110f59d6d4392b840d8dd6476cb780bc104db18..3f5fa08a594959841700a41a276c947960038b2e 100644 (file)
@@ -1,11 +1,13 @@
 --TEST--
 crash stm reverse dependency from connection
 --SKIPIF--
-<?php 
+<?php
 include "_skipif.inc";
+if (version_compare(PHP_VERSION, "8.2", ">="))
+       echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n";
 ?>
 --FILE--
-<?php 
+<?php
 echo "Test\n";
 
 include "_setup.inc";
index d1a5cf181527d1e6dd570720f7b15aafd9babbc4..cddb5dfc161628357f055a7bb210a13323cc3cdf 100644 (file)
@@ -3,6 +3,8 @@ crash txn reverse dependency from connection
 --SKIPIF--
 <?php
 include "_skipif.inc";
+if (version_compare(PHP_VERSION, "8.2", ">="))
+       echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n";
 ?>
 --FILE--
 <?php
diff --git a/tests/gh-issue047_jsonb.phpt b/tests/gh-issue047_jsonb.phpt
new file mode 100644 (file)
index 0000000..5e145fb
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+json conv broken since 2.2.1
+--SKIPIF--
+<?php
+define("SERVER_MIN", "9.4");
+include "_skipif.inc";
+?>
+--INI--
+date.timezone=UTC
+--FILE--
+<?php
+echo "Test\n";
+
+include "_setup.inc";
+
+$c = new pq\Connection(PQ_DSN);
+$c->defaultFetchType = \pq\Result::FETCH_ASSOC;
+
+$q = <<<EOF
+    SELECT '0'::jsonb UNION SELECT '"text"'::jsonb;
+EOF;
+$r = $c->exec($q);
+
+var_dump($r->fetchAll());
+?>
+===DONE===
+--EXPECT--
+Test
+array(2) {
+  [0]=>
+  array(1) {
+    ["jsonb"]=>
+    string(4) "text"
+  }
+  [1]=>
+  array(1) {
+    ["jsonb"]=>
+    int(0)
+  }
+}
+===DONE===
index 9d36788706311b8a414e5d3f8de8b2fca0288071..c288ec15869ab71cb82227d0ec22b73f11f4705b 100644 (file)
@@ -26,14 +26,16 @@ true as bool,
 '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[box(point(1,2),point(2,3)),box(point(4,5),point(5,6))] as boxarray,
-array[]::text[] as emptyarray
+array[]::text[] as emptyarray,
+'foo\n'::bytea as bytea,
+'foo\n'::bytea::text as bytea_text
 ");
 var_dump($r->fetchRow(pq\Result::FETCH_ASSOC));
 ?>
 DONE
 --EXPECTF--
 Test
-array(13) {
+array(15) {
   ["null"]=>
   NULL
   ["bool"]=>
@@ -121,5 +123,10 @@ array(13) {
   ["emptyarray"]=>
   array(0) {
   }
+  ["bytea"]=>
+  string(4) "foo
+"
+  ["bytea_text"]=>
+  string(10) "\x666f6f0a"
 }
-DONE
\ No newline at end of file
+DONE