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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
*~
/*.tgz
.deps
+*.dep
+*.o
*.lo
*.la
/config.[^m]*
### 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).
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
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 //')
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
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)
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)
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
<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>
</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" />
#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)
<?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",
]]);
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");
}
}
?>
PQ_DSN: "postgres:///runner"
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
with:
#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) {
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)
{
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
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}
};
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);
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( \
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);
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();
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;
#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>
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
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
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;
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);
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));
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(¶ms);
if (!res) {
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);
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);
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;
#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>
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
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;
#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);
}
}
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) {
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 {
}
}
-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;
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");
}
#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)
{
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;
#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
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());
}
--- /dev/null
+--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
--- /dev/null
+--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
--SKIPIF--
<?php
include "_skipif.inc";
+if (version_compare(PHP_VERSION, "8.2", ">="))
+ echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n";
?>
--FILE--
<?php
--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";
--SKIPIF--
<?php
include "_skipif.inc";
+if (version_compare(PHP_VERSION, "8.2", ">="))
+ echo "skip PHP_VERSION>=8.2 (dynamic properties deprecated)\n";
?>
--FILE--
<?php
--- /dev/null
+--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===
'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"]=>
["emptyarray"]=>
array(0) {
}
+ ["bytea"]=>
+ string(4) "foo
+"
+ ["bytea_text"]=>
+ string(10) "\x666f6f0a"
}
-DONE
\ No newline at end of file
+DONE