LibSQL: Separate parsing of common-table-expression list
Statements like SELECT, INSERT, and UPDATE also optionally include this list, so move its parsing out of parse_delete_statement(). Since it will appear before the actual statement, parse it first in next_statement(); then only parse for statements that are allowed to include the list.
This commit is contained in:
parent
6a7d7624a7
commit
9331293e44
Notes:
sideshowbarker
2024-07-18 19:14:44 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/9331293e441 Pull-request: https://github.com/SerenityOS/serenity/pull/6551
3 changed files with 46 additions and 21 deletions
|
@ -15,6 +15,16 @@ Parser::Parser(Lexer lexer)
|
|||
}
|
||||
|
||||
NonnullRefPtr<Statement> Parser::next_statement()
|
||||
{
|
||||
if (match(TokenType::With)) {
|
||||
auto common_table_expression_list = parse_common_table_expression_list();
|
||||
return parse_statement_with_expression_list(move(common_table_expression_list));
|
||||
}
|
||||
|
||||
return parse_statement();
|
||||
}
|
||||
|
||||
NonnullRefPtr<Statement> Parser::parse_statement()
|
||||
{
|
||||
switch (m_parser_state.m_token.type()) {
|
||||
case TokenType::Create:
|
||||
|
@ -22,14 +32,24 @@ NonnullRefPtr<Statement> Parser::next_statement()
|
|||
case TokenType::Drop:
|
||||
return parse_drop_table_statement();
|
||||
case TokenType::Delete:
|
||||
case TokenType::With:
|
||||
return parse_delete_statement();
|
||||
return parse_delete_statement({});
|
||||
default:
|
||||
expected("CREATE, DROP, or DELETE");
|
||||
return create_ast_node<ErrorStatement>();
|
||||
}
|
||||
}
|
||||
|
||||
NonnullRefPtr<Statement> Parser::parse_statement_with_expression_list(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
||||
{
|
||||
switch (m_parser_state.m_token.type()) {
|
||||
case TokenType::Delete:
|
||||
return parse_delete_statement(move(common_table_expression_list));
|
||||
default:
|
||||
expected("DELETE");
|
||||
return create_ast_node<ErrorStatement>();
|
||||
}
|
||||
}
|
||||
|
||||
NonnullRefPtr<CreateTable> Parser::parse_create_table_statement()
|
||||
{
|
||||
// https://sqlite.org/lang_createtable.html
|
||||
|
@ -108,26 +128,9 @@ NonnullRefPtr<DropTable> Parser::parse_drop_table_statement()
|
|||
return create_ast_node<DropTable>(move(schema_name), move(table_name), is_error_if_table_does_not_exist);
|
||||
}
|
||||
|
||||
NonnullRefPtr<Delete> Parser::parse_delete_statement()
|
||||
NonnullRefPtr<Delete> Parser::parse_delete_statement(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
||||
{
|
||||
// https://sqlite.org/lang_delete.html
|
||||
|
||||
RefPtr<CommonTableExpressionList> common_table_expression_list;
|
||||
if (consume_if(TokenType::With)) {
|
||||
NonnullRefPtrVector<CommonTableExpression> common_table_expression;
|
||||
bool recursive = consume_if(TokenType::Recursive);
|
||||
|
||||
do {
|
||||
common_table_expression.append(parse_common_table_expression());
|
||||
if (!match(TokenType::Comma))
|
||||
break;
|
||||
|
||||
consume(TokenType::Comma);
|
||||
} while (!match(TokenType::Eof));
|
||||
|
||||
common_table_expression_list = create_ast_node<CommonTableExpressionList>(recursive, move(common_table_expression));
|
||||
}
|
||||
|
||||
consume(TokenType::Delete);
|
||||
consume(TokenType::From);
|
||||
auto qualified_table_name = parse_qualified_table_name();
|
||||
|
@ -145,6 +148,23 @@ NonnullRefPtr<Delete> Parser::parse_delete_statement()
|
|||
return create_ast_node<Delete>(move(common_table_expression_list), move(qualified_table_name), move(where_clause), move(returning_clause));
|
||||
}
|
||||
|
||||
NonnullRefPtr<CommonTableExpressionList> Parser::parse_common_table_expression_list()
|
||||
{
|
||||
consume(TokenType::With);
|
||||
bool recursive = consume_if(TokenType::Recursive);
|
||||
|
||||
NonnullRefPtrVector<CommonTableExpression> common_table_expression;
|
||||
do {
|
||||
common_table_expression.append(parse_common_table_expression());
|
||||
if (!match(TokenType::Comma))
|
||||
break;
|
||||
|
||||
consume(TokenType::Comma);
|
||||
} while (!match(TokenType::Eof));
|
||||
|
||||
return create_ast_node<CommonTableExpressionList>(recursive, move(common_table_expression));
|
||||
}
|
||||
|
||||
NonnullRefPtr<Expression> Parser::parse_expression()
|
||||
{
|
||||
// https://sqlite.org/lang_expr.html
|
||||
|
|
|
@ -50,9 +50,12 @@ private:
|
|||
Vector<Error> m_errors;
|
||||
};
|
||||
|
||||
NonnullRefPtr<Statement> parse_statement();
|
||||
NonnullRefPtr<Statement> parse_statement_with_expression_list(RefPtr<CommonTableExpressionList>);
|
||||
NonnullRefPtr<CreateTable> parse_create_table_statement();
|
||||
NonnullRefPtr<DropTable> parse_drop_table_statement();
|
||||
NonnullRefPtr<Delete> parse_delete_statement();
|
||||
NonnullRefPtr<Delete> parse_delete_statement(RefPtr<CommonTableExpressionList>);
|
||||
NonnullRefPtr<CommonTableExpressionList> parse_common_table_expression_list();
|
||||
|
||||
NonnullRefPtr<Expression> parse_primary_expression();
|
||||
NonnullRefPtr<Expression> parse_secondary_expression(NonnullRefPtr<Expression> primary);
|
||||
|
|
|
@ -54,6 +54,7 @@ TEST_CASE(create_table)
|
|||
EXPECT(parse("CREATE TABLE test ( column1 varchar(.abc) )").is_error());
|
||||
EXPECT(parse("CREATE TABLE test ( column1 varchar(0x) )").is_error());
|
||||
EXPECT(parse("CREATE TABLE test ( column1 varchar(0xzzz) )").is_error());
|
||||
EXPECT(parse("WITH table AS () CREATE TABLE test ( column1 );").is_error());
|
||||
|
||||
struct Column {
|
||||
StringView name;
|
||||
|
@ -118,6 +119,7 @@ TEST_CASE(drop_table)
|
|||
EXPECT(parse("DROP TABLE").is_error());
|
||||
EXPECT(parse("DROP TABLE test").is_error());
|
||||
EXPECT(parse("DROP TABLE IF test;").is_error());
|
||||
EXPECT(parse("WITH table AS () DROP TABLE test;").is_error());
|
||||
|
||||
auto validate = [](StringView sql, StringView expected_schema, StringView expected_table, bool expected_is_error_if_table_does_not_exist = true) {
|
||||
auto result = parse(sql);
|
||||
|
|
Loading…
Add table
Reference in a new issue