Skip to content

Commit

Permalink
Provide limited support for NO_BACKSLASH_ESCAPES SQL mode
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Aug 20, 2021
1 parent 648174d commit 9c5a8c6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 23 deletions.
17 changes: 11 additions & 6 deletions src/Io/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ class Query
* Note that this mapping assumes an ASCII-compatible charset encoding such
* as UTF-8, ISO 8859 and others.
*
* Note that `'` will be escaped as `''` instead of `\'` to provide some
* limited support for the `NO_BACKSLASH_ESCAPES` SQL mode. This assumes all
* strings will always be enclosed in `'` instead of `"` which is guaranteed
* as long as this class is only used internally for the `query()` method.
*
* @var array<string,string>
* @see \React\MySQL\Commands\AuthenticateCommand::$charsetMap
*/
private $escapeChars = [
"\x00" => "\\0",
"\r" => "\\r",
"\n" => "\\n",
"\t" => "\\t",
//"\x00" => "\\0",
//"\r" => "\\r",
//"\n" => "\\n",
//"\t" => "\\t",
//"\b" => "\\b",
//"\x1a" => "\\Z",
"'" => "\'",
'"' => '\"',
"'" => "''",
//'"' => '\"',
"\\" => "\\\\",
//"%" => "\\%",
//"_" => "\\_",
Expand Down
9 changes: 3 additions & 6 deletions tests/Io/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,9 @@ public function testEscapeChars()
{
$query = new Query('');
$this->assertEquals('\\\\', $query->escape('\\'));
$this->assertEquals('\"', $query->escape('"'));
$this->assertEquals("\'", $query->escape("'"));
$this->assertEquals("\\n", $query->escape("\n"));
$this->assertEquals("\\r", $query->escape("\r"));
$this->assertEquals("foo\\0bar", $query->escape("foo" . chr(0) . "bar"));
$this->assertEquals("''", $query->escape("'"));
$this->assertEquals("foo\0bar", $query->escape("foo" . chr(0) . "bar"));
$this->assertEquals("n%3A", $query->escape("n%3A"));
//$this->assertEquals('§ä¨ì¥H¤U¤º®e\\\\§ä¨ì¥H¤U¤º®e', $query->escape('§ä¨ì¥H¤U¤º®e\\§ä¨ì¥H¤U¤º®e'));
$this->assertEquals('§ä¨ì¥H¤U¤º®e\\\\§ä¨ì¥H¤U¤º®e', $query->escape('§ä¨ì¥H¤U¤º®e\\§ä¨ì¥H¤U¤º®e'));
}
}
51 changes: 40 additions & 11 deletions tests/ResultQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,71 @@ public function provideValuesThatWillBeReturnedAsIs()
'hello?',
'FööBär',
'pile of 💩',
'<>&--\\\'";',
"\0\1\2\3\4\5\6\7\8\xff",
'Dave\'s Diner',
'Robert "Bobby"',
"first\r\nsecond",
'<>&--\'";',
"\0\1\2\3\4\5\6\7\10\xff",
implode('', range("\x00", "\x2F")) . implode('', range("\x7f", "\xFF")),
'',
null
]);
}

public function provideValuesThatWillBeConvertedToString()
/**
* @dataProvider provideValuesThatWillBeReturnedAsIs
*/
public function testSelectStaticValueWillBeReturnedAsIs($value)
{
return [
[1, '1'],
[1.5, '1.5'],
[true, '1'],
[false, '0']
];
$connection = $this->createConnection(Loop::get());

$expected = $value;

$connection->query('select ?', [$value])->then(function (QueryResult $command) use ($expected) {
$this->assertCount(1, $command->resultRows);
$this->assertCount(1, $command->resultRows[0]);
$this->assertSame($expected, reset($command->resultRows[0]));
})->then(null, 'printf');

$connection->quit();
Loop::run();
}

/**
* @dataProvider provideValuesThatWillBeReturnedAsIs
*/
public function testSelectStaticValueWillBeReturnedAsIs($value)
public function testSelectStaticValueWillBeReturnedAsIsWithNoBackslashEscapesSqlMode($value)
{
if (strpos($value, '\\') !== false) {
// TODO: strings such as '%\\' work as-is when string contains percent?!
$this->markTestIncomplete('Escaping backslash not supported when using NO_BACKSLASH_ESCAPES SQL mode');
}

$connection = $this->createConnection(Loop::get());

$expected = $value;

$connection->query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"');
$connection->query('select ?', [$value])->then(function (QueryResult $command) use ($expected) {
$this->assertCount(1, $command->resultRows);
$this->assertCount(1, $command->resultRows[0]);
$this->assertSame($expected, reset($command->resultRows[0]));
});
})->then(null, 'printf');

$connection->quit();
Loop::run();
}

public function provideValuesThatWillBeConvertedToString()
{
return [
[1, '1'],
[1.5, '1.5'],
[true, '1'],
[false, '0']
];
}

/**
* @dataProvider provideValuesThatWillBeConvertedToString
*/
Expand Down

0 comments on commit 9c5a8c6

Please sign in to comment.