Split SQL batches correctly around dollar quotes and comments
splitStatements() only knew 'strings' and "identifiers", so a DO block or function body ($$ ... ; ... $$) was cut at its inner semicolons and failed, and a quote inside a comment (-- don't) opened a string that never closed. It now also skips dollar-quoted bodies, E'...' strings with backslash escapes, and comments. It moves to SqlGuard so it is tested with the other checks. OccController::run() now catches Throwable, so an Error thrown by a command is logged and returned like an Exception instead of ending in an HTTP 500. Not changed on purpose: showing rows for statements with RETURNING or data-modifying CTEs, and failure handling in the Makefile release targets. Both came up in the same review but are unrelated to the security fixes in this release.
This commit is contained in:
@@ -125,4 +125,29 @@ class SqlGuardTest extends TestCase
|
||||
$this->assertSame('SELECT', SqlGuard::statementType('(SELECT 1)'));
|
||||
$this->assertSame('', SqlGuard::statementType(''));
|
||||
}
|
||||
|
||||
public static function splitProvider(): array
|
||||
{
|
||||
return [
|
||||
['SELECT 1; SELECT 2', ['SELECT 1', 'SELECT 2']],
|
||||
["SELECT ';'; SELECT 2", ["SELECT ';'", 'SELECT 2']],
|
||||
["SELECT 'it''s; x'", ["SELECT 'it''s; x'"]],
|
||||
['SELECT "a;b" FROM t', ['SELECT "a;b" FROM t']],
|
||||
["SELECT E'it\\'s; x'; SELECT 2", ["SELECT E'it\\'s; x'", 'SELECT 2']],
|
||||
["DO \$\$BEGIN PERFORM 1; PERFORM 2; END\$\$; SELECT 3", ["DO \$\$BEGIN PERFORM 1; PERFORM 2; END\$\$", 'SELECT 3']],
|
||||
["SELECT \$f\$a;\$\$;b\$f\$; SELECT 2", ["SELECT \$f\$a;\$\$;b\$f\$", 'SELECT 2']],
|
||||
["-- don't; split\nSELECT 1; SELECT 2", ["-- don't; split\nSELECT 1", 'SELECT 2']],
|
||||
["/* it's; here */ SELECT 1; SELECT 2", ["/* it's; here */ SELECT 1", 'SELECT 2']],
|
||||
['SELECT \$1; SELECT 2', ['SELECT \$1', 'SELECT 2']],
|
||||
[' ; ;SELECT 1;', ['SELECT 1']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider splitProvider
|
||||
*/
|
||||
public function testSplitStatements(string $sql, array $expected): void
|
||||
{
|
||||
$this->assertSame($expected, SqlGuard::splitStatements($sql));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user