Skip to content

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

Closed

Conversation

nickvergessen
Copy link
Contributor

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 is ESCAPE "\\" in php. The unit test accidently used ESCAPE "\\\\" 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.

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]>
@MorrisJobke
Copy link
Contributor

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')),
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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 '\\'",
Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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);
Copy link
Member

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()
Copy link
Member

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 \'\\\'',
Copy link
Member

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]>
* @param string $query
* @param bool $ignorePostgres
*/
public function testNamedParametersAfterEscapeFirstMatches($query, $ignorePostgres)
Copy link
Member

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],
Copy link
Member

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 ? '\\' : '\\\\';
Copy link
Member

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]>
@nickvergessen nickvergessen force-pushed the fix-like-escape-for-sqlite branch from 33f9555 to e016b51 Compare April 14, 2018 18:25
*/
public function testNamedParametersAfterEscape(array $params)
{
$escapeChar = $this->_conn->getDatabasePlatform()->quoteStringLiteral('\\');
Copy link
Contributor Author

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

Copy link
Member

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.

Base automatically changed from master to 4.0.x January 22, 2021 07:44
@morozov morozov closed this Jul 26, 2021
@nickvergessen nickvergessen deleted the fix-like-escape-for-sqlite branch July 26, 2021 13:06
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants