diff --git a/readme.md b/readme.md index cc2fd79f..bd122698 100644 --- a/readme.md +++ b/readme.md @@ -199,6 +199,7 @@ Three special modifiers are available for LIKE: | `%like~` | the expression starts with a string | `%~like` | the expression ends with a string | `%~like~` | the expression contains a string +| `%like` | the expression matches a string Search for names beginning with a string: diff --git a/src/Dibi/Drivers/FirebirdDriver.php b/src/Dibi/Drivers/FirebirdDriver.php index cf6890f6..a09b6ca2 100644 --- a/src/Dibi/Drivers/FirebirdDriver.php +++ b/src/Dibi/Drivers/FirebirdDriver.php @@ -271,7 +271,7 @@ class FirebirdDriver implements Dibi\Driver public function escapeLike(string $value, int $pos): string { $value = addcslashes($this->escapeText($value), '%_\\'); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'"; + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'"; } diff --git a/src/Dibi/Drivers/MySqliDriver.php b/src/Dibi/Drivers/MySqliDriver.php index 771f8248..e9a2dbbf 100644 --- a/src/Dibi/Drivers/MySqliDriver.php +++ b/src/Dibi/Drivers/MySqliDriver.php @@ -317,7 +317,7 @@ class MySqliDriver implements Dibi\Driver public function escapeLike(string $value, int $pos): string { $value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_"); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); } diff --git a/src/Dibi/Drivers/OdbcDriver.php b/src/Dibi/Drivers/OdbcDriver.php index a235df56..d092de4f 100644 --- a/src/Dibi/Drivers/OdbcDriver.php +++ b/src/Dibi/Drivers/OdbcDriver.php @@ -250,7 +250,7 @@ class OdbcDriver implements Dibi\Driver public function escapeLike(string $value, int $pos): string { $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); } diff --git a/src/Dibi/Drivers/OracleDriver.php b/src/Dibi/Drivers/OracleDriver.php index 4d7aa74c..9b8e472f 100644 --- a/src/Dibi/Drivers/OracleDriver.php +++ b/src/Dibi/Drivers/OracleDriver.php @@ -270,7 +270,7 @@ class OracleDriver implements Dibi\Driver { $value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_"); $value = str_replace("'", "''", $value); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); } diff --git a/src/Dibi/Drivers/PdoDriver.php b/src/Dibi/Drivers/PdoDriver.php index d35e1265..adacb2f3 100644 --- a/src/Dibi/Drivers/PdoDriver.php +++ b/src/Dibi/Drivers/PdoDriver.php @@ -324,29 +324,29 @@ class PdoDriver implements Dibi\Driver switch ($this->driverName) { case 'mysql': $value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_"); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); case 'oci': $value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_"); $value = str_replace("'", "''", $value); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); 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, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); case 'sqlite': $value = addcslashes(substr($this->connection->quote($value, PDO::PARAM_STR), 1, -1), '%_\\'); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'"; + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'"; case 'odbc': case 'mssql': case 'dblib': case 'sqlsrv': $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); default: throw new Dibi\NotImplementedException; diff --git a/src/Dibi/Drivers/PostgreDriver.php b/src/Dibi/Drivers/PostgreDriver.php index fdade5d4..f8ce5c62 100644 --- a/src/Dibi/Drivers/PostgreDriver.php +++ b/src/Dibi/Drivers/PostgreDriver.php @@ -318,7 +318,7 @@ class PostgreDriver implements Dibi\Driver $bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off $value = pg_escape_string($this->connection, $value); $value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); } diff --git a/src/Dibi/Drivers/SqliteDriver.php b/src/Dibi/Drivers/SqliteDriver.php index db900797..1b06d317 100644 --- a/src/Dibi/Drivers/SqliteDriver.php +++ b/src/Dibi/Drivers/SqliteDriver.php @@ -254,7 +254,7 @@ class SqliteDriver implements Dibi\Driver public function escapeLike(string $value, int $pos): string { $value = addcslashes($this->connection->escapeString($value), '%_\\'); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'"; + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'"; } diff --git a/src/Dibi/Drivers/SqlsrvDriver.php b/src/Dibi/Drivers/SqlsrvDriver.php index f939a49a..bb178570 100644 --- a/src/Dibi/Drivers/SqlsrvDriver.php +++ b/src/Dibi/Drivers/SqlsrvDriver.php @@ -243,7 +243,7 @@ class SqlsrvDriver implements Dibi\Driver public function escapeLike(string $value, int $pos): string { $value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']); - return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'"); + return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'"); } diff --git a/src/Dibi/Translator.php b/src/Dibi/Translator.php index 157f3b54..6ed3fadd 100644 --- a/src/Dibi/Translator.php +++ b/src/Dibi/Translator.php @@ -415,12 +415,15 @@ final class Translator return (string) $value; case 'like~': // LIKE string% - return $this->driver->escapeLike($value, 1); + return $this->driver->escapeLike($value, 2); case '~like': // LIKE %string - return $this->driver->escapeLike($value, -1); + return $this->driver->escapeLike($value, 1); case '~like~': // LIKE %string% + return $this->driver->escapeLike($value, 3); + + case 'like': // LIKE string return $this->driver->escapeLike($value, 0); case 'and': diff --git a/tests/dibi/Translator.like.phpt b/tests/dibi/Translator.like.phpt index d8e75a3f..d2661695 100644 --- a/tests/dibi/Translator.like.phpt +++ b/tests/dibi/Translator.like.phpt @@ -71,3 +71,9 @@ Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'baa', 'aa')); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'aab', 'aa')); Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like~', 'bba', '%a')); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'b%a', '%a')); + + +// matches +Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like', 'a', 'a')); +Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like', 'a', 'aa')); +Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like', 'a', 'b'));