Don't allow aliases for sources in `IN` expression

This commit is contained in:
Simon Binder 2024-04-24 18:59:10 +02:00
parent d57e383ad2
commit 2777ca47e1
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
3 changed files with 45 additions and 7 deletions

View File

@ -1,6 +1,8 @@
## 0.36.0-dev
- Add support for the geopoly module.
- Fix `IN` expressions accepting aliases, causing some queries to get parsed
incorrectly.
## 0.35.0

View File

@ -517,7 +517,7 @@ class Parser {
} else if (_check(TokenType.leftParen)) {
inside = _consumeTuple(orSubQuery: true) as InExpressionTarget;
} else {
final target = _tableOrSubquery();
final target = _tableOrSubquery(allowAlias: false);
// TableOrSubquery is either a table reference, a table-valued function,
// or a Subquery. We don't support subqueries, but they can't be parsed
// here because we would have entered the tuple case above.
@ -1383,18 +1383,18 @@ class Parser {
return _joinClause(start) ?? start;
}
TableOrSubquery _tableOrSubquery() {
TableOrSubquery _tableOrSubquery({bool allowAlias = true}) {
// this is what we're parsing: https://www.sqlite.org/syntax/table-or-subquery.html
// we currently only support regular tables, table functions and nested
// selects
final tableRef = _tableReferenceOrNull();
final tableRef = _tableReferenceOrNull(allowAlias: allowAlias);
if (tableRef != null) {
// this is a bit hacky. If the table reference only consists of one
// identifer and it's followed by a (, it's a table-valued function
if (tableRef.as == null && _matchOne(TokenType.leftParen)) {
final params = _functionParameters();
_consume(TokenType.rightParen, 'Expected closing parenthesis');
final alias = _as();
final alias = allowAlias ? _as() : null;
return TableValuedFunction(tableRef.tableName, params,
as: alias?.identifier)
@ -1408,7 +1408,7 @@ class Parser {
_consume(TokenType.rightParen,
'Expected a right bracket to terminate the inner select');
final alias = _as();
final alias = allowAlias ? _as() : null;
return SelectStatementAsSource(
statement: innerStmt, as: alias?.identifier)
..setSpan(first, _previous);
@ -1417,9 +1417,11 @@ class Parser {
_error('Expected a table name or a nested select statement');
}
TableReference? _tableReferenceOrNull() {
TableReference? _tableReferenceOrNull({bool allowAlias = true}) {
_suggestHint(const TableNameDescription());
if (_check(TokenType.identifier)) return _tableReference();
if (_check(TokenType.identifier)) {
return _tableReference(allowAlias: allowAlias);
}
return null;
}

View File

@ -54,6 +54,40 @@ final Map<String, AstNode> testCases = {
],
from: TableReference('tbl'),
),
'SELECT col IN tbl AS in_tbl': SelectStatement(columns: [
ExpressionResultColumn(
expression: InExpression(
left: Reference(columnName: 'col'),
inside: TableReference('tbl'),
),
as: 'in_tbl',
),
]),
'SELECT col IN (SELECT 2) AS in_select': SelectStatement(columns: [
ExpressionResultColumn(
expression: InExpression(
left: Reference(columnName: 'col'),
inside: SubQuery(
select: SelectStatement(
columns: [ExpressionResultColumn(expression: NumericLiteral(2))],
),
),
),
as: 'in_select',
),
]),
'SELECT col IN tbl_valued() AS in_select': SelectStatement(columns: [
ExpressionResultColumn(
expression: InExpression(
left: Reference(columnName: 'col'),
inside: TableValuedFunction(
'tbl_valued',
ExprFunctionParameters(parameters: []),
),
),
as: 'in_select',
),
]),
};
void main() {