-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Fix like escape for sqlite #3104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix like escape for sqlite #3104
Conversation
So it must be a single backslash, 2 to escape it as a php string. Double escape is not necessary. Signed-off-by: Joas Schilling <[email protected]>
Signed-off-by: Joas Schilling <[email protected]>
Maybe @Ocramius can have a look at this as well 🤔 |
array('SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\") AND (data.description LIKE :condition_1 ESCAPE "\\") ORDER BY id ASC', false, array(121 => 'condition_0', 173 => 'condition_1')), | ||
array('SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\") AND (data.description LIKE :condition_1 ESCAPE \'\\\') ORDER BY id ASC', false, array(121 => 'condition_0', 173 => 'condition_1')), | ||
array('SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE `\\`) AND (data.description LIKE :condition_1 ESCAPE `\\`) ORDER BY id ASC', false, array(121 => 'condition_0', 173 => 'condition_1')), | ||
array('SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE \'\\\') AND (data.description LIKE :condition_1 ESCAPE `\\`) ORDER BY id ASC', false, array(121 => 'condition_0', 173 => 'condition_1')), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if that is also the case for other DBs […]
Is it possible to convert this (at least the relevant parts) to a functional test to make sure it does work on a real DB. Otherwise, we may end up changing tests after implementation w/o any evidence that the query is actually valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you tell me a file where i should put them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added to tests/Doctrine/Tests/DBAL/Functional/NamedParametersTest.php
public function ticketGitHub3104Provider() | ||
{ | ||
$escapes = [ | ||
"ESCAPE '\\'", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So SQLite needs \\
and all others need \\\\
…
How to best adjust the test for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question is, how to write a portable query which will work on SQLite and others using the DBAL? If there's no proper solution now, then there's nothing to be fixed or tested: no matter how it's implemented, it's not portable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay found a way, please have a look again.
And well, the databases require a different query, that is exactly what this PR is fixing. SQLite is broken at the moment, all others work. With this PR SQLite and all others work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nickvergessen now Postgres is broken. Please take a look at the build.
['param_0' => 'bar', 'param_1' => 'foo', 'find' => '%a%'], | ||
['param_0' => 2, 'param_1' => 2, 'find' => 2] | ||
); | ||
$result = $stmt->fetchAll(FetchMode::ASSOCIATIVE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If FetchMode::COLUMN
is used instead, you could avoid using the query_matched
column alias and array_change_key_case()
conversion.
self::assertEquals($expected, $result); | ||
} | ||
|
||
public function ticketGitHub3104Provider() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid test names attached to ticket numbers. Please describe them in terms of features/requirements instead.
$escapes = [ | ||
"ESCAPE '\\'", | ||
'ESCAPE "\\"', | ||
'ESCAPE \'\\\'', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is identical to the one 2 lines above. By testing two different "spellings", we only test the PHP engine which is not the purpose of this test.
Signed-off-by: Joas Schilling <[email protected]>
c285d3a
to
d9e60bd
Compare
Signed-off-by: Joas Schilling <[email protected]>
* @param string $query | ||
* @param bool $ignorePostgres | ||
*/ | ||
public function testNamedParametersAfterEscapeFirstMatches($query, $ignorePostgres) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The functional test should only only cover the literals quoted according to the platform rules: AbstractPlatform::quoteStringLiteral()
. The fact that the parser supports other quote characters than the current platform supports will be covered in the unit test for the parser.
public function namedParametersAfterEscapeProvider() | ||
{ | ||
return [ | ||
["SELECT 1 FROM ddc1372_foobar WHERE (:param_0 LIKE :find ESCAPE '{{escape}}') OR (:param_1 LIKE :find ESCAPE '{{escape}}') LIMIT 1", false], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to remove the duplicating code from the data set (SELECT 1 FROM...
) and focus on the fragments which make the difference? We may end up having just one data set if AbstractPlatform::quoteStringLiteral()
is used instead of the combinations.
$this->markTestSkipped('PostgreSql uses double quotes for column names, therefor it is not a valid query'); | ||
} | ||
|
||
$escapeChar = $this->_conn->getDatabasePlatform() instanceof SqlitePlatform || $this->_conn->getDatabasePlatform() instanceof PostgreSqlPlatform ? '\\' : '\\\\'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instanceof
is a bad sign here. The code should be portable by means of using the DBAL APIs, not by introspecting its implementation details.
Signed-off-by: Joas Schilling <[email protected]>
33f9555
to
e016b51
Compare
*/ | ||
public function testNamedParametersAfterEscape(array $params) | ||
{ | ||
$escapeChar = $this->_conn->getDatabasePlatform()->quoteStringLiteral('\\'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@morozov the problem is, PostgreSqlPlatform escapes \
, but the string in ESCAPE '…'
must not be escaped for PostgreSql
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nickvergessen please see if you can use the API introduced in #3013.
Follow up to #2720 from @mondrake approved by @deeky666 ("I simply trust you guys on this one" 😿)
Not sure if that is also the case for other DBs, but at least for SQLite
ESCAPE "…"
must only contain one char. So that isESCAPE "\\"
in php. The unit test accidently usedESCAPE "\\\\"
and therefor didn't match the actual syntax and broke for SQLite.In case
ESCAPE "\\\\"
is needed for another DB, we should just add both unit tests.