Skip to content

Commit

Permalink
Add support for Postgres placeholders to Parser
Browse files Browse the repository at this point in the history
  • Loading branch information
sweoggy committed Nov 28, 2024
1 parent e9fb8d7 commit b06005f
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/SQL/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@
*/
final class Parser
{
private const SPECIAL_CHARS = ':\?\'"`\\[\\-\\/';
private const SPECIAL_CHARS = ':\?\'"`\\[\\-\\/$';

private const BACKTICK_IDENTIFIER = '`[^`]*`';
private const BRACKET_IDENTIFIER = '(?<!\b(?i:ARRAY))\[(?:[^\]])*\]';
private const MULTICHAR = ':{2,}';
private const NAMED_PARAMETER = ':[a-zA-Z0-9_]+';
private const POSITIONAL_PARAMETER = '(?<!\\?)\\?(?!\\?)';
private const POSITIONAL_PARAMETER = '((?<!\\?)\\?(?!\\?)|\\$\d+)';
private const ONE_LINE_COMMENT = '--[^\r\n]*';
private const MULTI_LINE_COMMENT = '/\*([^*]+|\*+[^/*])*\**\*/';
private const SPECIAL = '[' . self::SPECIAL_CHARS . ']';
Expand Down
85 changes: 85 additions & 0 deletions tests/SQL/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,61 +45,121 @@ private static function getStatementsWithParameters(): iterable
'SELECT {?}',
];

yield [
'SELECT $1',
'SELECT {$1}',
];

yield [
'SELECT * FROM Foo WHERE bar IN (?, ?, ?)',
'SELECT * FROM Foo WHERE bar IN ({?}, {?}, {?})',
];

yield [
'SELECT * FROM Foo WHERE bar IN ($1, $2, $1)',
'SELECT * FROM Foo WHERE bar IN ({$1}, {$2}, {$1})',
];

yield [
'SELECT ? FROM ?',
'SELECT {?} FROM {?}',
];

yield [
'SELECT $1 FROM $2',
'SELECT {$1} FROM {$2}',
];

yield [
'SELECT "?" FROM foo WHERE bar = ?',
'SELECT "?" FROM foo WHERE bar = {?}',
];

yield [
'SELECT "$1" FROM foo WHERE bar = $1',
'SELECT "$1" FROM foo WHERE bar = {$1}',
];

yield [
"SELECT '?' FROM foo WHERE bar = ?",
"SELECT '?' FROM foo WHERE bar = {?}",
];

yield [
"SELECT '$1' FROM foo WHERE bar = $1",
"SELECT '$1' FROM foo WHERE bar = {\$1}",
];

yield [
'SELECT `?` FROM foo WHERE bar = ?',
'SELECT `?` FROM foo WHERE bar = {?}',
];

yield [
'SELECT `$1` FROM foo WHERE bar = $1',
'SELECT `$1` FROM foo WHERE bar = {$1}',
];

yield [
'SELECT [?] FROM foo WHERE bar = ?',
'SELECT [?] FROM foo WHERE bar = {?}',
];

yield [
'SELECT [$1] FROM foo WHERE bar = $1',
'SELECT [$1] FROM foo WHERE bar = {$1}',
];

yield [
'SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[?])',
'SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[{?}])',
];

yield [
'SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[$1])',
'SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[{$1}])',
];

yield [
"SELECT 'Doctrine\DBAL?' FROM foo WHERE bar = ?",
"SELECT 'Doctrine\DBAL?' FROM foo WHERE bar = {?}",
];

yield [
"SELECT 'Doctrine\DBAL$1' FROM foo WHERE bar = $1",
"SELECT 'Doctrine\DBAL$1' FROM foo WHERE bar = {\$1}",
];

yield [
'SELECT "Doctrine\DBAL?" FROM foo WHERE bar = ?',
'SELECT "Doctrine\DBAL?" FROM foo WHERE bar = {?}',
];

yield [
'SELECT "Doctrine\DBAL$1" FROM foo WHERE bar = $1',
'SELECT "Doctrine\DBAL$1" FROM foo WHERE bar = {$1}',
];

yield [
'SELECT `Doctrine\DBAL?` FROM foo WHERE bar = ?',
'SELECT `Doctrine\DBAL?` FROM foo WHERE bar = {?}',
];

yield [
'SELECT `Doctrine\DBAL$1` FROM foo WHERE bar = $1',
'SELECT `Doctrine\DBAL$1` FROM foo WHERE bar = {$1}',
];

yield [
'SELECT [Doctrine\DBAL?] FROM foo WHERE bar = ?',
'SELECT [Doctrine\DBAL?] FROM foo WHERE bar = {?}',
];

yield [
'SELECT [Doctrine\DBAL?] FROM foo WHERE bar = $1',
'SELECT [Doctrine\DBAL?] FROM foo WHERE bar = {$1}',
];

yield [
'SELECT :foo FROM :bar',
'SELECT {:foo} FROM {:bar}',
Expand Down Expand Up @@ -293,6 +353,31 @@ private static function getStatementsWithParameters(): iterable
,
];

yield 'Postgres placeholders inside comments' => [
<<<'SQL'
/*
* test placeholder $1
*/
SELECT dummy as "dummy$1"
FROM DUAL
WHERE '$1' = '$1'
-- AND dummy <> $1
AND dummy = $1
SQL
,
<<<'SQL'
/*
* test placeholder $1
*/
SELECT dummy as "dummy$1"
FROM DUAL
WHERE '$1' = '$1'
-- AND dummy <> $1
AND dummy = {$1}
SQL
,
];

yield 'Escaped question' => [
<<<'SQL'
SELECT '{"a":null}'::jsonb ?? :key
Expand Down

0 comments on commit b06005f

Please sign in to comment.