diff --git a/dibi/drivers/DibiPdoDriver.php b/dibi/drivers/DibiPdoDriver.php index e0bc6d63..f049c011 100644 --- a/dibi/drivers/DibiPdoDriver.php +++ b/dibi/drivers/DibiPdoDriver.php @@ -318,8 +318,9 @@ class DibiPdoDriver extends DibiObject implements IDibiDriver, IDibiResultDriver return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); case 'pgsql': + $bs = substr($this->connection->quote('\\', PDO::PARAM_STR), 1, -1); // standard_conforming_strings = on/off $value = substr($this->connection->quote($value, PDO::PARAM_STR), 1, -1); - $value = strtr($value, array( '%' => '\\\\%', '_' => '\\\\_')); + $value = strtr($value, array('%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\')); return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); case 'sqlite': diff --git a/dibi/drivers/DibiPostgreDriver.php b/dibi/drivers/DibiPostgreDriver.php index 915f1f73..90eccfa5 100644 --- a/dibi/drivers/DibiPostgreDriver.php +++ b/dibi/drivers/DibiPostgreDriver.php @@ -310,8 +310,9 @@ class DibiPostgreDriver extends DibiObject implements IDibiDriver, IDibiResultDr */ public function escapeLike($value, $pos) { + $bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off $value = pg_escape_string($this->connection, $value); - $value = strtr($value, array( '%' => '\\\\%', '_' => '\\\\_')); + $value = strtr($value, array('%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\')); return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); } diff --git a/tests/dibi/DibiTranslator.phpt b/tests/dibi/DibiTranslator.phpt index fce89076..659c55db 100644 --- a/tests/dibi/DibiTranslator.phpt +++ b/tests/dibi/DibiTranslator.phpt @@ -198,15 +198,36 @@ Assert::same( // like -if ($config['driver'] !== 'sqlite') { // sqlite2 +$args = array( + "SELECT * FROM products WHERE (title LIKE %like~ AND title LIKE %~like) OR title LIKE %~like~", + 'C', + 'r', + "a\n%_\\'\"" +); + +if ($config['system'] === 'pgsql') { + $conn->query('SET escape_string_warning = off'); // do not log warnings + + $conn->query('SET standard_conforming_strings = off'); + Assert::same( + "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\n\\\\%\\\\_\\\\\\\\''\"%'", + $conn->translate($args[0], $args[1], $args[2], $args[3]) + ); + + $conn->query('SET standard_conforming_strings = on'); + Assert::same( + "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\n\\%\\_\\\\''\"%'", + $conn->translate($args[0], $args[1], $args[2], $args[3]) + ); + +} elseif ($config['driver'] !== 'sqlite') { // sqlite2 Assert::same( reformat(array( 'sqlite' => "SELECT * FROM products WHERE (title LIKE 'C%' ESCAPE '\\' AND title LIKE '%r' ESCAPE '\\') OR title LIKE '%a\n\\%\\_\\\\''\"%' ESCAPE '\\'", 'odbc' => "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\n[%][_]\\''\"%'", - 'pgsql' => "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\n\\\\%\\\\_\\''\"%'", "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\\n\\%\\_\\\\\\\\\'\"%'", )), - $conn->translate("SELECT * FROM products WHERE (title LIKE %like~ AND title LIKE %~like) OR title LIKE %~like~", 'C', 'r', "a\n%_\\'\"") + $conn->translate($args[0], $args[1], $args[2], $args[3]) ); } diff --git a/tests/dibi/Postgre.like.phpt b/tests/dibi/Postgre.like.phpt new file mode 100644 index 00000000..72e87856 --- /dev/null +++ b/tests/dibi/Postgre.like.phpt @@ -0,0 +1,34 @@ +query("SELECT 'AAxBB' LIKE %~like~", 'A_B')->fetchSingle()); + Assert::true( $conn->query("SELECT 'AA_BB' LIKE %~like~", 'A_B')->fetchSingle()); + + Assert::false($conn->query("SELECT 'AAxBB' LIKE %~like~", 'A%B')->fetchSingle()); + Assert::true( $conn->query("SELECT 'AA%BB' LIKE %~like~", 'A%B')->fetchSingle()); + + Assert::same('AA\\BB', $conn->query("SELECT 'AA\\BB'")->fetchSingle()); + Assert::false($conn->query("SELECT 'AAxBB' LIKE %~like~", 'A\\B')->fetchSingle()); + Assert::true( $conn->query("SELECT 'AA\\BB' LIKE %~like~", 'A\\B')->fetchSingle()); +}; + +$conn = new DibiConnection($config); +$conn->query('SET escape_string_warning = off'); // do not log warnings + +$conn->query('SET standard_conforming_strings = on'); +$tests($conn); +$conn->query('SET standard_conforming_strings = off'); +$tests($conn);