Support WITH clause for inner select statements

This commit is contained in:
Simon Binder 2019-10-27 10:47:21 +01:00
parent bf1e174ca3
commit 591e1b2bff
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 30 additions and 11 deletions

View File

@ -3,7 +3,7 @@ part of '../ast.dart';
/// A subquery, which is an expression. It is expected that the inner query
/// only returns one column and one row.
class SubQuery extends Expression {
final SelectStatement select;
final BaseSelectStatement select;
SubQuery({this.select});
@ -18,7 +18,7 @@ class SubQuery extends Expression {
}
class ExistsExpression extends Expression {
final SelectStatement select;
final BaseSelectStatement select;
ExistsExpression({@required this.select});

View File

@ -66,11 +66,8 @@ mixin CrudParser on ParserBase {
..withToken = withToken;
}
/// Parses a select statement as defined in [the sqlite documentation][s-d],
/// which means that compound selects and a with clause is supported.
///
/// [s-d]: https://sqlite.org/syntax/select-stmt.html
BaseSelectStatement _defaultSelect() {
@override
BaseSelectStatement _fullSelect() {
final clause = _withClause();
return select(withClause: clause);
}
@ -82,6 +79,17 @@ mixin CrudParser on ParserBase {
} else {
final firstTokenOfBase = _peek;
final first = _selectNoCompound(withClause);
if (first == null) {
// _selectNoCompound returns null if there's no select statement at the
// current position. That's fine if we didn't encounter an with clause
// already
if (withClause != null) {
_error('Expected a SELECT statement to follow the WITH clause here');
}
return null;
}
final parts = <CompoundSelectPart>[];
while (true) {
@ -631,7 +639,7 @@ mixin CrudParser on ParserBase {
return const DefaultValues();
} else {
return SelectInsertSource(
_defaultSelect() ?? _error('Expeced a select statement'));
_fullSelect() ?? _error('Expeced a select statement'));
}
}

View File

@ -194,7 +194,7 @@ mixin ExpressionParser on ParserBase {
final existsToken = _previous;
_consume(
TokenType.leftParen, 'Expected opening parenthesis after EXISTS');
final selectStmt = select(noCompound: true) as SelectStatement;
final selectStmt = _fullSelect() ?? _error('Expected a select statement');
_consume(TokenType.rightParen,
'Expected closing paranthesis to finish EXISTS expression');
return ExistsExpression(select: selectStmt)
@ -263,7 +263,9 @@ mixin ExpressionParser on ParserBase {
if (_matchOne(TokenType.leftParen)) {
final left = _previous;
if (_peek.type == TokenType.select) {
final selectStmt = _fullSelect(); // returns null if there's no select
if (selectStmt != null) {
final stmt = select(noCompound: true) as SelectStatement;
_consume(TokenType.rightParen, 'Expected a closing bracket');
return SubQuery(select: stmt)..setSpan(left, _previous);
@ -380,7 +382,7 @@ mixin ExpressionParser on ParserBase {
_consume(TokenType.leftParen, 'Expected opening parenthesis for tuple');
final expressions = <Expression>[];
final subQuery = select(noCompound: true) as SelectStatement;
final subQuery = _fullSelect();
if (subQuery == null) {
// no sub query found. read expressions that form the tuple.
// tuples can be empty `()`, so only start parsing values when it's not

View File

@ -169,10 +169,19 @@ abstract class ParserBase {
/// [CompoundSelectStatement]. If [noCompound] is set to true, the parser will
/// only attempt to parse a [SelectStatement].
///
/// This method doesn't parse WITH clauses, most users would probably want to
/// use [_fullSelect] instead.
///
/// See also:
/// https://www.sqlite.org/lang_select.html
BaseSelectStatement select({bool noCompound});
/// Parses a select statement as defined in [the sqlite documentation][s-d],
/// which means that compound selects and a with clause is supported.
///
/// [s-d]: https://sqlite.org/syntax/select-stmt.html
BaseSelectStatement _fullSelect();
Literal _literalOrNull();
OrderingMode _orderingModeOrNull();