summaryrefslogtreecommitdiff
path: root/ext/pdo_pgsql
diff options
context:
space:
mode:
authorMatteo Beccati <mbeccati@php.net>2019-07-22 19:22:07 +0200
committerMatteo Beccati <mbeccati@php.net>2019-07-22 19:35:03 +0200
commitb19fdc18a974929394c734d8b710d7a9ca3c9d3a (patch)
tree4229c2550e8806f528cfa82bf2342a8c54a72b9e /ext/pdo_pgsql
parent5d827c89cf0aa14f51e57cbe4d4e1e90475899b6 (diff)
downloadphp-git-b19fdc18a974929394c734d8b710d7a9ca3c9d3a.tar.gz
Fix FR #71885 (Allow escaping question mark placeholders)
Diffstat (limited to 'ext/pdo_pgsql')
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c46
-rw-r--r--ext/pdo_pgsql/tests/bug71885.phpt46
-rw-r--r--ext/pdo_pgsql/tests/bug71885_2.phpt57
3 files changed, 126 insertions, 23 deletions
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
index 15b2bd16c9..9c5df24ab5 100644
--- a/ext/pdo_pgsql/pgsql_driver.c
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -256,36 +256,36 @@ static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len
execute_only = H->disable_prepares;
}
- if (!emulate && PQprotocolVersion(H->server) > 2) {
+ if (!emulate && PQprotocolVersion(H->server) <= 2) {
+ emulate = 1;
+ }
+
+ if (emulate) {
+ stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
+ } else {
stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
stmt->named_rewrite_template = "$%d";
- ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len);
-
- if (ret == 1) {
- /* query was re-written */
- sql = nsql;
- } else if (ret == -1) {
- /* couldn't grok it */
- strcpy(dbh->error_code, stmt->error_code);
- return 0;
- }
+ }
- if (!execute_only) {
- /* prepared query: set the query name and defer the
- actual prepare until the first execute call */
- spprintf(&S->stmt_name, 0, "pdo_stmt_%08x", ++H->stmt_counter);
- }
+ ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len);
- if (nsql) {
- S->query = nsql;
- } else {
- S->query = estrdup(sql);
- }
+ if (ret == -1) {
+ /* couldn't grok it */
+ strcpy(dbh->error_code, stmt->error_code);
+ return 0;
+ } else if (ret == 1) {
+ /* query was re-written */
+ S->query = nsql;
+ } else {
+ S->query = estrdup(sql);
+ }
- return 1;
+ if (!emulate && !execute_only) {
+ /* prepared query: set the query name and defer the
+ actual prepare until the first execute call */
+ spprintf(&S->stmt_name, 0, "pdo_stmt_%08x", ++H->stmt_counter);
}
- stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
return 1;
}
diff --git a/ext/pdo_pgsql/tests/bug71885.phpt b/ext/pdo_pgsql/tests/bug71885.phpt
new file mode 100644
index 0000000000..ea5b1882ff
--- /dev/null
+++ b/ext/pdo_pgsql/tests/bug71885.phpt
@@ -0,0 +1,46 @@
+--TEST--
+Request #71855 (PDO placeholder escaping)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
+require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+require_once dirname(__FILE__) . '/config.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+require_once dirname(__FILE__) . '/config.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_NUM);
+
+foreach ([false, true] as $emulate) {
+ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate);
+
+ try {
+ $stmt = $db->prepare('select ?- lseg \'((-1,0),(1,0))\'');
+ $stmt->execute();
+ } catch (PDOException $e) {
+ var_dump('ERR');
+ }
+
+ $stmt = $db->prepare('select ??- lseg \'((-1,0),(1,0))\'');
+ $stmt->execute();
+
+ var_dump($stmt->fetch());
+}
+
+?>
+==OK==
+--EXPECT--
+string(3) "ERR"
+array(1) {
+ [0]=>
+ bool(true)
+}
+array(1) {
+ [0]=>
+ bool(true)
+}
+==OK==
diff --git a/ext/pdo_pgsql/tests/bug71885_2.phpt b/ext/pdo_pgsql/tests/bug71885_2.phpt
new file mode 100644
index 0000000000..f98e9ef785
--- /dev/null
+++ b/ext/pdo_pgsql/tests/bug71885_2.phpt
@@ -0,0 +1,57 @@
+--TEST--
+Request #71855 (PDO placeholder escaping, part 2)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
+require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+require_once dirname(__FILE__) . '/config.inc';
+PDOTest::skip();
+
+$db = PDOTest::factory();
+if (version_compare($db->getAttribute(PDO::ATTR_SERVER_VERSION), '9.4.0') < 0) {
+ die("skip Requires 9.4+");
+}
+
+?>
+--FILE--
+<?php
+require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+require_once dirname(__FILE__) . '/config.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_NUM);
+
+$jsonb = $db->quote(json_encode(['a' => 1]));
+
+foreach ([false, true] as $emulate) {
+ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate);
+
+ $stmt = $db->prepare("SELECT {$jsonb}::jsonb ?? ?");
+ $stmt->execute(['b']);
+ var_dump($stmt->fetch());
+
+ $stmt = $db->prepare("SELECT {$jsonb}::jsonb ???");
+ $stmt->execute(['a']);
+ var_dump($stmt->fetch());
+}
+
+?>
+==OK==
+--EXPECT--
+array(1) {
+ [0]=>
+ bool(false)
+}
+array(1) {
+ [0]=>
+ bool(true)
+}
+array(1) {
+ [0]=>
+ bool(false)
+}
+array(1) {
+ [0]=>
+ bool(true)
+}
+==OK==