2021-04-18 17:38:38 -04:00
|
|
|
/*
|
2022-01-31 13:07:22 -05:00
|
|
|
* Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
|
2021-12-06 15:30:38 +02:00
|
|
|
* Copyright (c) 2021, Mahmoud Mandour <ma.mandourr@gmail.com>
|
2021-04-18 17:38:38 -04:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2021-04-18 17:38:38 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Parser.h"
|
2021-06-08 09:22:06 -04:00
|
|
|
#include <AK/ScopeGuard.h>
|
2021-04-20 17:49:26 -04:00
|
|
|
#include <AK/TypeCasts.h>
|
2021-04-18 17:38:38 -04:00
|
|
|
|
2021-06-21 10:57:44 -04:00
|
|
|
namespace SQL::AST {
|
2021-04-18 17:38:38 -04:00
|
|
|
|
|
|
|
|
Parser::Parser(Lexer lexer)
|
|
|
|
|
: m_parser_state(move(lexer))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<Statement> Parser::next_statement()
|
2021-04-21 17:12:06 -04:00
|
|
|
{
|
2021-04-23 13:22:42 -04:00
|
|
|
auto terminate_statement = [this](auto statement) {
|
|
|
|
|
consume(TokenType::SemiColon);
|
|
|
|
|
return statement;
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-21 17:12:06 -04:00
|
|
|
if (match(TokenType::With)) {
|
|
|
|
|
auto common_table_expression_list = parse_common_table_expression_list();
|
2021-06-01 08:34:51 -04:00
|
|
|
if (!common_table_expression_list)
|
|
|
|
|
return create_ast_node<ErrorStatement>();
|
|
|
|
|
|
2021-04-23 13:22:42 -04:00
|
|
|
return terminate_statement(parse_statement_with_expression_list(move(common_table_expression_list)));
|
2021-04-21 17:12:06 -04:00
|
|
|
}
|
|
|
|
|
|
2021-04-23 13:22:42 -04:00
|
|
|
return terminate_statement(parse_statement());
|
2021-04-21 17:12:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<Statement> Parser::parse_statement()
|
2021-04-18 17:38:38 -04:00
|
|
|
{
|
|
|
|
|
switch (m_parser_state.m_token.type()) {
|
|
|
|
|
case TokenType::Create:
|
2021-06-27 21:32:22 -04:00
|
|
|
consume();
|
|
|
|
|
if (match(TokenType::Schema))
|
|
|
|
|
return parse_create_schema_statement();
|
|
|
|
|
else
|
|
|
|
|
return parse_create_table_statement();
|
2021-04-23 22:18:35 -04:00
|
|
|
case TokenType::Alter:
|
|
|
|
|
return parse_alter_table_statement();
|
2021-04-20 10:16:28 -04:00
|
|
|
case TokenType::Drop:
|
|
|
|
|
return parse_drop_table_statement();
|
2021-12-06 15:30:38 +02:00
|
|
|
case TokenType::Describe:
|
|
|
|
|
return parse_describe_table_statement();
|
2021-04-23 17:55:23 -04:00
|
|
|
case TokenType::Insert:
|
|
|
|
|
return parse_insert_statement({});
|
2021-04-23 21:40:19 -04:00
|
|
|
case TokenType::Update:
|
|
|
|
|
return parse_update_statement({});
|
2021-04-21 14:13:05 -04:00
|
|
|
case TokenType::Delete:
|
2021-04-21 17:12:06 -04:00
|
|
|
return parse_delete_statement({});
|
2021-04-22 10:11:17 -04:00
|
|
|
case TokenType::Select:
|
|
|
|
|
return parse_select_statement({});
|
2021-04-18 17:38:38 -04:00
|
|
|
default:
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("CREATE, ALTER, DROP, DESCRIBE, INSERT, UPDATE, DELETE, or SELECT"sv);
|
2021-04-18 17:38:38 -04:00
|
|
|
return create_ast_node<ErrorStatement>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 17:12:06 -04:00
|
|
|
NonnullRefPtr<Statement> Parser::parse_statement_with_expression_list(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
|
|
|
|
{
|
|
|
|
|
switch (m_parser_state.m_token.type()) {
|
2021-04-23 17:55:23 -04:00
|
|
|
case TokenType::Insert:
|
|
|
|
|
return parse_insert_statement(move(common_table_expression_list));
|
2021-04-23 21:40:19 -04:00
|
|
|
case TokenType::Update:
|
|
|
|
|
return parse_update_statement(move(common_table_expression_list));
|
2021-04-21 17:12:06 -04:00
|
|
|
case TokenType::Delete:
|
|
|
|
|
return parse_delete_statement(move(common_table_expression_list));
|
2021-04-22 10:11:17 -04:00
|
|
|
case TokenType::Select:
|
|
|
|
|
return parse_select_statement(move(common_table_expression_list));
|
2021-04-21 17:12:06 -04:00
|
|
|
default:
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("INSERT, UPDATE, DELETE, or SELECT"sv);
|
2021-04-21 17:12:06 -04:00
|
|
|
return create_ast_node<ErrorStatement>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-27 21:32:22 -04:00
|
|
|
NonnullRefPtr<CreateSchema> Parser::parse_create_schema_statement()
|
|
|
|
|
{
|
|
|
|
|
consume(TokenType::Schema);
|
|
|
|
|
|
|
|
|
|
bool is_error_if_exists = true;
|
|
|
|
|
if (consume_if(TokenType::If)) {
|
|
|
|
|
consume(TokenType::Not);
|
|
|
|
|
consume(TokenType::Exists);
|
|
|
|
|
is_error_if_exists = false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name = consume(TokenType::Identifier).value();
|
2021-06-27 21:32:22 -04:00
|
|
|
return create_ast_node<CreateSchema>(move(schema_name), is_error_if_exists);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 17:38:38 -04:00
|
|
|
NonnullRefPtr<CreateTable> Parser::parse_create_table_statement()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_createtable.html
|
|
|
|
|
|
|
|
|
|
bool is_temporary = false;
|
2021-04-21 09:38:07 -04:00
|
|
|
if (consume_if(TokenType::Temp) || consume_if(TokenType::Temporary))
|
2021-04-18 17:38:38 -04:00
|
|
|
is_temporary = true;
|
|
|
|
|
|
|
|
|
|
consume(TokenType::Table);
|
|
|
|
|
|
|
|
|
|
bool is_error_if_table_exists = true;
|
2021-04-21 09:38:07 -04:00
|
|
|
if (consume_if(TokenType::If)) {
|
2021-04-18 17:38:38 -04:00
|
|
|
consume(TokenType::Not);
|
|
|
|
|
consume(TokenType::Exists);
|
|
|
|
|
is_error_if_table_exists = false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 12:39:44 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
2021-04-18 17:38:38 -04:00
|
|
|
|
2021-04-23 13:37:47 -04:00
|
|
|
if (consume_if(TokenType::As)) {
|
|
|
|
|
auto select_statement = parse_select_statement({});
|
|
|
|
|
return create_ast_node<CreateTable>(move(schema_name), move(table_name), move(select_statement), is_temporary, is_error_if_table_exists);
|
|
|
|
|
}
|
2021-04-18 17:38:38 -04:00
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<ColumnDefinition>> column_definitions;
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(true, [&]() { column_definitions.append(parse_column_definition()); });
|
2021-04-18 17:38:38 -04:00
|
|
|
|
|
|
|
|
// FIXME: Parse "table-constraint".
|
|
|
|
|
|
|
|
|
|
return create_ast_node<CreateTable>(move(schema_name), move(table_name), move(column_definitions), is_temporary, is_error_if_table_exists);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 21:53:34 +02:00
|
|
|
NonnullRefPtr<AlterTable> Parser::parse_alter_table_statement()
|
2021-04-23 22:18:35 -04:00
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_altertable.html
|
|
|
|
|
consume(TokenType::Alter);
|
|
|
|
|
consume(TokenType::Table);
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 22:18:35 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Add)) {
|
|
|
|
|
consume_if(TokenType::Column); // COLUMN is optional.
|
|
|
|
|
auto column = parse_column_definition();
|
|
|
|
|
return create_ast_node<AddColumn>(move(schema_name), move(table_name), move(column));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Drop)) {
|
|
|
|
|
consume_if(TokenType::Column); // COLUMN is optional.
|
|
|
|
|
auto column = consume(TokenType::Identifier).value();
|
|
|
|
|
return create_ast_node<DropColumn>(move(schema_name), move(table_name), move(column));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consume(TokenType::Rename);
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::To)) {
|
|
|
|
|
auto new_table_name = consume(TokenType::Identifier).value();
|
|
|
|
|
return create_ast_node<RenameTable>(move(schema_name), move(table_name), move(new_table_name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consume_if(TokenType::Column); // COLUMN is optional.
|
|
|
|
|
auto column_name = consume(TokenType::Identifier).value();
|
|
|
|
|
consume(TokenType::To);
|
|
|
|
|
auto new_column_name = consume(TokenType::Identifier).value();
|
|
|
|
|
return create_ast_node<RenameColumn>(move(schema_name), move(table_name), move(column_name), move(new_column_name));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 10:16:28 -04:00
|
|
|
NonnullRefPtr<DropTable> Parser::parse_drop_table_statement()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_droptable.html
|
|
|
|
|
consume(TokenType::Drop);
|
|
|
|
|
consume(TokenType::Table);
|
|
|
|
|
|
|
|
|
|
bool is_error_if_table_does_not_exist = true;
|
2021-04-21 09:38:07 -04:00
|
|
|
if (consume_if(TokenType::If)) {
|
2021-04-20 10:16:28 -04:00
|
|
|
consume(TokenType::Exists);
|
|
|
|
|
is_error_if_table_does_not_exist = false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 12:39:44 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
2021-04-20 10:16:28 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<DropTable>(move(schema_name), move(table_name), is_error_if_table_does_not_exist);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-06 15:30:38 +02:00
|
|
|
NonnullRefPtr<DescribeTable> Parser::parse_describe_table_statement()
|
|
|
|
|
{
|
|
|
|
|
consume(TokenType::Describe);
|
|
|
|
|
consume(TokenType::Table);
|
|
|
|
|
|
|
|
|
|
auto table_name = parse_qualified_table_name();
|
|
|
|
|
|
|
|
|
|
return create_ast_node<DescribeTable>(move(table_name));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 21:53:34 +02:00
|
|
|
NonnullRefPtr<Insert> Parser::parse_insert_statement(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
2021-04-23 17:55:23 -04:00
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_insert.html
|
|
|
|
|
consume(TokenType::Insert);
|
2021-04-23 21:40:19 -04:00
|
|
|
auto conflict_resolution = parse_conflict_resolution();
|
2021-04-23 17:55:23 -04:00
|
|
|
consume(TokenType::Into);
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 17:55:23 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString alias;
|
2021-04-23 17:55:23 -04:00
|
|
|
if (consume_if(TokenType::As))
|
|
|
|
|
alias = consume(TokenType::Identifier).value();
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
Vector<ByteString> column_names;
|
2021-04-23 17:55:23 -04:00
|
|
|
if (match(TokenType::ParenOpen))
|
|
|
|
|
parse_comma_separated_list(true, [&]() { column_names.append(consume(TokenType::Identifier).value()); });
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<ChainedExpression>> chained_expressions;
|
2021-04-23 17:55:23 -04:00
|
|
|
RefPtr<Select> select_statement;
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Values)) {
|
|
|
|
|
parse_comma_separated_list(false, [&]() {
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto chained_expression = parse_chained_expression()) {
|
2023-04-12 23:47:00 +01:00
|
|
|
auto* chained_expr = verify_cast<ChainedExpression>(chained_expression.ptr());
|
LibSQL+SQLServer: Bare bones INSERT and SELECT statements
This patch provides very basic, bare bones implementations of the
INSERT and SELECT statements. They are *very* limited:
- The only variant of the INSERT statement that currently works is
SELECT INTO schema.table (column1, column2, ....) VALUES
(value11, value21, ...), (value12, value22, ...), ...
where the values are literals.
- The SELECT statement is even more limited, and is only provided to
allow verification of the INSERT statement. The only form implemented
is: SELECT * FROM schema.table
These statements required a bit of change in the Statement::execute
API. Originally execute only received a Database object as parameter.
This is not enough; we now pass an ExecutionContext object which
contains the Database, the current result set, and the last Tuple read
from the database. This object will undoubtedly evolve over time.
This API change dragged SQLServer::SQLStatement into the patch.
Another API addition is Expression::evaluate. This method is,
unsurprisingly, used to evaluate expressions, like the values in the
INSERT statement.
Finally, a new test file is added: TestSqlStatementExecution, which
tests the currently implemented statements. As the number and flavour of
implemented statements grows, this test file will probably have to be
restructured.
2021-07-19 19:48:46 -04:00
|
|
|
if ((column_names.size() > 0) && (chained_expr->expressions().size() != column_names.size())) {
|
|
|
|
|
syntax_error("Number of expressions does not match number of columns");
|
|
|
|
|
} else {
|
2021-09-03 19:11:51 +02:00
|
|
|
chained_expressions.append(static_ptr_cast<ChainedExpression>(chained_expression.release_nonnull()));
|
LibSQL+SQLServer: Bare bones INSERT and SELECT statements
This patch provides very basic, bare bones implementations of the
INSERT and SELECT statements. They are *very* limited:
- The only variant of the INSERT statement that currently works is
SELECT INTO schema.table (column1, column2, ....) VALUES
(value11, value21, ...), (value12, value22, ...), ...
where the values are literals.
- The SELECT statement is even more limited, and is only provided to
allow verification of the INSERT statement. The only form implemented
is: SELECT * FROM schema.table
These statements required a bit of change in the Statement::execute
API. Originally execute only received a Database object as parameter.
This is not enough; we now pass an ExecutionContext object which
contains the Database, the current result set, and the last Tuple read
from the database. This object will undoubtedly evolve over time.
This API change dragged SQLServer::SQLStatement into the patch.
Another API addition is Expression::evaluate. This method is,
unsurprisingly, used to evaluate expressions, like the values in the
INSERT statement.
Finally, a new test file is added: TestSqlStatementExecution, which
tests the currently implemented statements. As the number and flavour of
implemented statements grows, this test file will probably have to be
restructured.
2021-07-19 19:48:46 -04:00
|
|
|
}
|
|
|
|
|
} else {
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("Chained expression"sv);
|
LibSQL+SQLServer: Bare bones INSERT and SELECT statements
This patch provides very basic, bare bones implementations of the
INSERT and SELECT statements. They are *very* limited:
- The only variant of the INSERT statement that currently works is
SELECT INTO schema.table (column1, column2, ....) VALUES
(value11, value21, ...), (value12, value22, ...), ...
where the values are literals.
- The SELECT statement is even more limited, and is only provided to
allow verification of the INSERT statement. The only form implemented
is: SELECT * FROM schema.table
These statements required a bit of change in the Statement::execute
API. Originally execute only received a Database object as parameter.
This is not enough; we now pass an ExecutionContext object which
contains the Database, the current result set, and the last Tuple read
from the database. This object will undoubtedly evolve over time.
This API change dragged SQLServer::SQLStatement into the patch.
Another API addition is Expression::evaluate. This method is,
unsurprisingly, used to evaluate expressions, like the values in the
INSERT statement.
Finally, a new test file is added: TestSqlStatementExecution, which
tests the currently implemented statements. As the number and flavour of
implemented statements grows, this test file will probably have to be
restructured.
2021-07-19 19:48:46 -04:00
|
|
|
}
|
2021-04-23 17:55:23 -04:00
|
|
|
});
|
|
|
|
|
} else if (match(TokenType::Select)) {
|
|
|
|
|
select_statement = parse_select_statement({});
|
|
|
|
|
} else {
|
|
|
|
|
consume(TokenType::Default);
|
|
|
|
|
consume(TokenType::Values);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<ReturningClause> returning_clause;
|
|
|
|
|
if (match(TokenType::Returning))
|
|
|
|
|
returning_clause = parse_returning_clause();
|
|
|
|
|
|
|
|
|
|
// FIXME: Parse 'upsert-clause'.
|
|
|
|
|
|
|
|
|
|
if (!chained_expressions.is_empty())
|
|
|
|
|
return create_ast_node<Insert>(move(common_table_expression_list), conflict_resolution, move(schema_name), move(table_name), move(alias), move(column_names), move(chained_expressions));
|
|
|
|
|
if (!select_statement.is_null())
|
|
|
|
|
return create_ast_node<Insert>(move(common_table_expression_list), conflict_resolution, move(schema_name), move(table_name), move(alias), move(column_names), move(select_statement));
|
|
|
|
|
|
|
|
|
|
return create_ast_node<Insert>(move(common_table_expression_list), conflict_resolution, move(schema_name), move(table_name), move(alias), move(column_names));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 21:53:34 +02:00
|
|
|
NonnullRefPtr<Update> Parser::parse_update_statement(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
2021-04-23 21:40:19 -04:00
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_update.html
|
|
|
|
|
consume(TokenType::Update);
|
|
|
|
|
auto conflict_resolution = parse_conflict_resolution();
|
|
|
|
|
auto qualified_table_name = parse_qualified_table_name();
|
|
|
|
|
consume(TokenType::Set);
|
|
|
|
|
|
|
|
|
|
Vector<Update::UpdateColumns> update_columns;
|
|
|
|
|
parse_comma_separated_list(false, [&]() {
|
2023-12-16 17:49:34 +03:30
|
|
|
Vector<ByteString> column_names;
|
2021-04-23 21:40:19 -04:00
|
|
|
if (match(TokenType::ParenOpen)) {
|
|
|
|
|
parse_comma_separated_list(true, [&]() { column_names.append(consume(TokenType::Identifier).value()); });
|
|
|
|
|
} else {
|
|
|
|
|
column_names.append(consume(TokenType::Identifier).value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consume(TokenType::Equals);
|
|
|
|
|
update_columns.append({ move(column_names), parse_expression() });
|
|
|
|
|
});
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<TableOrSubquery>> table_or_subquery_list;
|
2021-04-23 21:40:19 -04:00
|
|
|
if (consume_if(TokenType::From)) {
|
|
|
|
|
// FIXME: Parse join-clause.
|
|
|
|
|
parse_comma_separated_list(false, [&]() { table_or_subquery_list.append(parse_table_or_subquery()); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<Expression> where_clause;
|
|
|
|
|
if (consume_if(TokenType::Where))
|
|
|
|
|
where_clause = parse_expression();
|
|
|
|
|
|
|
|
|
|
RefPtr<ReturningClause> returning_clause;
|
|
|
|
|
if (match(TokenType::Returning))
|
|
|
|
|
returning_clause = parse_returning_clause();
|
|
|
|
|
|
|
|
|
|
return create_ast_node<Update>(move(common_table_expression_list), conflict_resolution, move(qualified_table_name), move(update_columns), move(table_or_subquery_list), move(where_clause), move(returning_clause));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 17:12:06 -04:00
|
|
|
NonnullRefPtr<Delete> Parser::parse_delete_statement(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
2021-04-21 14:13:05 -04:00
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_delete.html
|
|
|
|
|
consume(TokenType::Delete);
|
|
|
|
|
consume(TokenType::From);
|
|
|
|
|
auto qualified_table_name = parse_qualified_table_name();
|
|
|
|
|
|
|
|
|
|
RefPtr<Expression> where_clause;
|
|
|
|
|
if (consume_if(TokenType::Where))
|
|
|
|
|
where_clause = parse_expression();
|
|
|
|
|
|
|
|
|
|
RefPtr<ReturningClause> returning_clause;
|
|
|
|
|
if (match(TokenType::Returning))
|
|
|
|
|
returning_clause = parse_returning_clause();
|
|
|
|
|
|
2021-04-21 16:56:19 -04:00
|
|
|
return create_ast_node<Delete>(move(common_table_expression_list), move(qualified_table_name), move(where_clause), move(returning_clause));
|
2021-04-21 14:13:05 -04:00
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:11:17 -04:00
|
|
|
NonnullRefPtr<Select> Parser::parse_select_statement(RefPtr<CommonTableExpressionList> common_table_expression_list)
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_select.html
|
|
|
|
|
consume(TokenType::Select);
|
|
|
|
|
|
|
|
|
|
bool select_all = !consume_if(TokenType::Distinct);
|
|
|
|
|
consume_if(TokenType::All); // ALL is the default, so ignore it if specified.
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<ResultColumn>> result_column_list;
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(false, [&]() { result_column_list.append(parse_result_column()); });
|
2021-04-22 10:11:17 -04:00
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<TableOrSubquery>> table_or_subquery_list;
|
2021-04-22 10:11:17 -04:00
|
|
|
if (consume_if(TokenType::From)) {
|
|
|
|
|
// FIXME: Parse join-clause.
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(false, [&]() { table_or_subquery_list.append(parse_table_or_subquery()); });
|
2021-04-22 10:11:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<Expression> where_clause;
|
|
|
|
|
if (consume_if(TokenType::Where))
|
|
|
|
|
where_clause = parse_expression();
|
|
|
|
|
|
|
|
|
|
RefPtr<GroupByClause> group_by_clause;
|
|
|
|
|
if (consume_if(TokenType::Group)) {
|
|
|
|
|
consume(TokenType::By);
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<Expression>> group_by_list;
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(false, [&]() { group_by_list.append(parse_expression()); });
|
|
|
|
|
|
|
|
|
|
if (!group_by_list.is_empty()) {
|
|
|
|
|
RefPtr<Expression> having_clause;
|
|
|
|
|
if (consume_if(TokenType::Having))
|
|
|
|
|
having_clause = parse_expression();
|
|
|
|
|
|
|
|
|
|
group_by_clause = create_ast_node<GroupByClause>(move(group_by_list), move(having_clause));
|
|
|
|
|
}
|
2021-04-22 10:11:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: Parse 'WINDOW window-name AS window-defn'.
|
|
|
|
|
// FIXME: Parse 'compound-operator'.
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<OrderingTerm>> ordering_term_list;
|
2021-04-22 10:11:17 -04:00
|
|
|
if (consume_if(TokenType::Order)) {
|
|
|
|
|
consume(TokenType::By);
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(false, [&]() { ordering_term_list.append(parse_ordering_term()); });
|
2021-04-22 10:11:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<LimitClause> limit_clause;
|
|
|
|
|
if (consume_if(TokenType::Limit)) {
|
|
|
|
|
auto limit_expression = parse_expression();
|
|
|
|
|
|
|
|
|
|
RefPtr<Expression> offset_expression;
|
|
|
|
|
if (consume_if(TokenType::Offset)) {
|
|
|
|
|
offset_expression = parse_expression();
|
2021-06-02 21:23:40 -04:00
|
|
|
} else if (consume_if(TokenType::Comma)) {
|
2021-05-17 17:48:55 +01:00
|
|
|
// Note: The limit clause may instead be defined as "offset-expression, limit-expression", effectively reversing the
|
2021-04-22 10:11:17 -04:00
|
|
|
// order of the expressions. SQLite notes "this is counter-intuitive" and "to avoid confusion, programmers are strongly
|
|
|
|
|
// encouraged to ... avoid using a LIMIT clause with a comma-separated offset."
|
2021-06-02 21:23:40 -04:00
|
|
|
syntax_error("LIMIT clauses of the form 'LIMIT <expr>, <expr>' are not supported");
|
2021-04-22 10:11:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
limit_clause = create_ast_node<LimitClause>(move(limit_expression), move(offset_expression));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return create_ast_node<Select>(move(common_table_expression_list), select_all, move(result_column_list), move(table_or_subquery_list), move(where_clause), move(group_by_clause), move(ordering_term_list), move(limit_clause));
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-01 08:34:51 -04:00
|
|
|
RefPtr<CommonTableExpressionList> Parser::parse_common_table_expression_list()
|
2021-04-21 17:12:06 -04:00
|
|
|
{
|
|
|
|
|
consume(TokenType::With);
|
|
|
|
|
bool recursive = consume_if(TokenType::Recursive);
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<CommonTableExpression>> common_table_expression;
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(false, [&]() { common_table_expression.append(parse_common_table_expression()); });
|
2021-04-21 17:12:06 -04:00
|
|
|
|
2021-06-01 08:34:51 -04:00
|
|
|
if (common_table_expression.is_empty()) {
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("Common table expression list"sv);
|
2021-06-01 08:34:51 -04:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 17:12:06 -04:00
|
|
|
return create_ast_node<CommonTableExpressionList>(recursive, move(common_table_expression));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 17:49:26 -04:00
|
|
|
NonnullRefPtr<Expression> Parser::parse_expression()
|
|
|
|
|
{
|
2021-06-05 09:55:16 -04:00
|
|
|
if (++m_parser_state.m_current_expression_depth > Limits::maximum_expression_tree_depth) {
|
2023-12-16 17:49:34 +03:30
|
|
|
syntax_error(ByteString::formatted("Exceeded maximum expression tree depth of {}", Limits::maximum_expression_tree_depth));
|
2021-06-05 09:55:16 -04:00
|
|
|
return create_ast_node<ErrorExpression>();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-20 17:49:26 -04:00
|
|
|
// https://sqlite.org/lang_expr.html
|
|
|
|
|
auto expression = parse_primary_expression();
|
|
|
|
|
|
|
|
|
|
if (match_secondary_expression())
|
|
|
|
|
expression = parse_secondary_expression(move(expression));
|
|
|
|
|
|
|
|
|
|
// FIXME: Parse 'function-name'.
|
|
|
|
|
// FIXME: Parse 'raise-function'.
|
|
|
|
|
|
2021-06-05 09:55:16 -04:00
|
|
|
--m_parser_state.m_current_expression_depth;
|
2021-04-20 17:49:26 -04:00
|
|
|
return expression;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<Expression> Parser::parse_primary_expression()
|
|
|
|
|
{
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_literal_value_expression())
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2022-12-01 22:20:55 -05:00
|
|
|
if (auto expression = parse_bind_parameter_expression())
|
|
|
|
|
return expression.release_nonnull();
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_column_name_expression())
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_unary_operator_expression())
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_cast_expression())
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_case_expression())
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2023-04-12 23:47:00 +01:00
|
|
|
if (auto invert_expression = consume_if(TokenType::Not); invert_expression || consume_if(TokenType::Exists)) {
|
|
|
|
|
if (auto expression = parse_exists_expression(invert_expression))
|
|
|
|
|
return expression.release_nonnull();
|
|
|
|
|
|
|
|
|
|
expected("Exists expression"sv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::ParenOpen)) {
|
|
|
|
|
// Encountering a Select token at this point means this must be an ExistsExpression with no EXISTS keyword.
|
|
|
|
|
if (match(TokenType::Select)) {
|
|
|
|
|
auto select_statement = parse_select_statement({});
|
|
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
return create_ast_node<ExistsExpression>(move(select_statement), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (auto expression = parse_chained_expression(false)) {
|
|
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
return expression.release_nonnull();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expected("Chained expression"sv);
|
|
|
|
|
}
|
2021-04-23 15:29:28 -04:00
|
|
|
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("Primary Expression"sv);
|
2021-04-20 17:49:26 -04:00
|
|
|
consume();
|
|
|
|
|
|
|
|
|
|
return create_ast_node<ErrorExpression>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expression> primary)
|
|
|
|
|
{
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_binary_operator_expression(primary))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_collate_expression(primary))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_is_expression(primary))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
bool invert_expression = false;
|
|
|
|
|
if (consume_if(TokenType::Not))
|
|
|
|
|
invert_expression = true;
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_match_expression(primary, invert_expression))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_null_expression(primary, invert_expression))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_between_expression(primary, invert_expression))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
if (auto expression = parse_in_expression(primary, invert_expression))
|
|
|
|
|
return expression.release_nonnull();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("Secondary Expression"sv);
|
2021-04-20 17:49:26 -04:00
|
|
|
consume();
|
|
|
|
|
|
|
|
|
|
return create_ast_node<ErrorExpression>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Parser::match_secondary_expression() const
|
|
|
|
|
{
|
|
|
|
|
return match(TokenType::Not)
|
|
|
|
|
|| match(TokenType::DoublePipe)
|
|
|
|
|
|| match(TokenType::Asterisk)
|
|
|
|
|
|| match(TokenType::Divide)
|
|
|
|
|
|| match(TokenType::Modulus)
|
|
|
|
|
|| match(TokenType::Plus)
|
|
|
|
|
|| match(TokenType::Minus)
|
|
|
|
|
|| match(TokenType::ShiftLeft)
|
|
|
|
|
|| match(TokenType::ShiftRight)
|
|
|
|
|
|| match(TokenType::Ampersand)
|
|
|
|
|
|| match(TokenType::Pipe)
|
|
|
|
|
|| match(TokenType::LessThan)
|
|
|
|
|
|| match(TokenType::LessThanEquals)
|
|
|
|
|
|| match(TokenType::GreaterThan)
|
|
|
|
|
|| match(TokenType::GreaterThanEquals)
|
|
|
|
|
|| match(TokenType::Equals)
|
|
|
|
|
|| match(TokenType::EqualsEquals)
|
|
|
|
|
|| match(TokenType::NotEquals1)
|
|
|
|
|
|| match(TokenType::NotEquals2)
|
|
|
|
|
|| match(TokenType::And)
|
|
|
|
|
|| match(TokenType::Or)
|
|
|
|
|
|| match(TokenType::Collate)
|
|
|
|
|
|| match(TokenType::Is)
|
|
|
|
|
|| match(TokenType::Like)
|
|
|
|
|
|| match(TokenType::Glob)
|
|
|
|
|
|| match(TokenType::Match)
|
|
|
|
|
|| match(TokenType::Regexp)
|
|
|
|
|
|| match(TokenType::Isnull)
|
|
|
|
|
|| match(TokenType::Notnull)
|
|
|
|
|
|| match(TokenType::Between)
|
|
|
|
|
|| match(TokenType::In);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_literal_value_expression()
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (match(TokenType::NumericLiteral)) {
|
|
|
|
|
auto value = consume().double_value();
|
|
|
|
|
return create_ast_node<NumericLiteral>(value);
|
|
|
|
|
}
|
|
|
|
|
if (match(TokenType::StringLiteral)) {
|
|
|
|
|
// TODO: Should the surrounding ' ' be removed here?
|
|
|
|
|
auto value = consume().value();
|
|
|
|
|
return create_ast_node<StringLiteral>(value);
|
|
|
|
|
}
|
|
|
|
|
if (match(TokenType::BlobLiteral)) {
|
|
|
|
|
// TODO: Should the surrounding x' ' be removed here?
|
|
|
|
|
auto value = consume().value();
|
|
|
|
|
return create_ast_node<BlobLiteral>(value);
|
|
|
|
|
}
|
2022-12-31 09:28:09 -05:00
|
|
|
if (consume_if(TokenType::True))
|
|
|
|
|
return create_ast_node<BooleanLiteral>(true);
|
|
|
|
|
if (consume_if(TokenType::False))
|
|
|
|
|
return create_ast_node<BooleanLiteral>(false);
|
2021-04-20 17:49:26 -04:00
|
|
|
if (consume_if(TokenType::Null))
|
|
|
|
|
return create_ast_node<NullLiteral>();
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-01 22:20:55 -05:00
|
|
|
// https://sqlite.org/lang_expr.html#varparam
|
|
|
|
|
RefPtr<Expression> Parser::parse_bind_parameter_expression()
|
|
|
|
|
{
|
|
|
|
|
// FIXME: Support ?NNN, :AAAA, @AAAA, and $AAAA forms.
|
|
|
|
|
if (consume_if(TokenType::Placeholder)) {
|
|
|
|
|
auto parameter = m_parser_state.m_bound_parameters;
|
|
|
|
|
if (++m_parser_state.m_bound_parameters > Limits::maximum_bound_parameters)
|
2023-12-16 17:49:34 +03:30
|
|
|
syntax_error(ByteString::formatted("Exceeded maximum number of bound parameters {}", Limits::maximum_bound_parameters));
|
2022-12-01 22:20:55 -05:00
|
|
|
|
|
|
|
|
return create_ast_node<Placeholder>(parameter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
RefPtr<Expression> Parser::parse_column_name_expression(Optional<ByteString> with_parsed_identifier, bool with_parsed_period)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
2023-10-10 15:00:58 +03:30
|
|
|
if (!with_parsed_identifier.has_value() && !match(TokenType::Identifier))
|
2021-04-20 17:49:26 -04:00
|
|
|
return {};
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString first_identifier;
|
2023-10-10 15:00:58 +03:30
|
|
|
if (!with_parsed_identifier.has_value())
|
2021-04-22 10:11:17 -04:00
|
|
|
first_identifier = consume(TokenType::Identifier).value();
|
|
|
|
|
else
|
2023-10-10 15:00:58 +03:30
|
|
|
first_identifier = with_parsed_identifier.release_value();
|
2021-04-22 10:11:17 -04:00
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
|
|
|
|
ByteString column_name;
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-04-22 10:11:17 -04:00
|
|
|
if (with_parsed_period || consume_if(TokenType::Period)) {
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString second_identifier = consume(TokenType::Identifier).value();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Period)) {
|
|
|
|
|
schema_name = move(first_identifier);
|
|
|
|
|
table_name = move(second_identifier);
|
|
|
|
|
column_name = consume(TokenType::Identifier).value();
|
|
|
|
|
} else {
|
|
|
|
|
table_name = move(first_identifier);
|
|
|
|
|
column_name = move(second_identifier);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
column_name = move(first_identifier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return create_ast_node<ColumnNameExpression>(move(schema_name), move(table_name), move(column_name));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_unary_operator_expression()
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (consume_if(TokenType::Minus))
|
|
|
|
|
return create_ast_node<UnaryOperatorExpression>(UnaryOperator::Minus, parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Plus))
|
|
|
|
|
return create_ast_node<UnaryOperatorExpression>(UnaryOperator::Plus, parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Tilde))
|
|
|
|
|
return create_ast_node<UnaryOperatorExpression>(UnaryOperator::BitwiseNot, parse_expression());
|
|
|
|
|
|
2021-04-23 15:29:28 -04:00
|
|
|
if (consume_if(TokenType::Not)) {
|
|
|
|
|
if (match(TokenType::Exists))
|
|
|
|
|
return parse_exists_expression(true);
|
|
|
|
|
else
|
|
|
|
|
return create_ast_node<UnaryOperatorExpression>(UnaryOperator::Not, parse_expression());
|
|
|
|
|
}
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_binary_operator_expression(NonnullRefPtr<Expression> lhs)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (consume_if(TokenType::DoublePipe))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Concatenate, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Asterisk))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Multiplication, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Divide))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Division, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Modulus))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Modulo, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Plus))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Plus, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Minus))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Minus, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::ShiftLeft))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::ShiftLeft, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::ShiftRight))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::ShiftRight, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Ampersand))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::BitwiseAnd, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Pipe))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::BitwiseOr, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::LessThan))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::LessThan, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::LessThanEquals))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::LessThanEquals, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::GreaterThan))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::GreaterThan, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::GreaterThanEquals))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::GreaterThanEquals, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Equals) || consume_if(TokenType::EqualsEquals))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Equals, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::NotEquals1) || consume_if(TokenType::NotEquals2))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::NotEquals, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::And))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::And, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Or))
|
|
|
|
|
return create_ast_node<BinaryOperatorExpression>(BinaryOperator::Or, move(lhs), parse_expression());
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-12 23:47:00 +01:00
|
|
|
RefPtr<Expression> Parser::parse_chained_expression(bool surrounded_by_parentheses)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
2023-04-12 23:47:00 +01:00
|
|
|
if (surrounded_by_parentheses && !consume_if(TokenType::ParenOpen))
|
2021-04-20 17:49:26 -04:00
|
|
|
return {};
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<Expression>> expressions;
|
2021-04-23 15:29:28 -04:00
|
|
|
parse_comma_separated_list(false, [&]() { expressions.append(parse_expression()); });
|
2023-04-12 23:47:00 +01:00
|
|
|
|
|
|
|
|
if (surrounded_by_parentheses)
|
|
|
|
|
consume(TokenType::ParenClose);
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<ChainedExpression>(move(expressions));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_cast_expression()
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::Cast))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
consume(TokenType::Cast);
|
|
|
|
|
consume(TokenType::ParenOpen);
|
|
|
|
|
auto expression = parse_expression();
|
|
|
|
|
consume(TokenType::As);
|
|
|
|
|
auto type_name = parse_type_name();
|
|
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
|
|
|
|
|
return create_ast_node<CastExpression>(move(expression), move(type_name));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_case_expression()
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::Case))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
consume();
|
|
|
|
|
|
|
|
|
|
RefPtr<Expression> case_expression;
|
|
|
|
|
if (!match(TokenType::When)) {
|
|
|
|
|
case_expression = parse_expression();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector<CaseExpression::WhenThenClause> when_then_clauses;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
consume(TokenType::When);
|
|
|
|
|
auto when = parse_expression();
|
|
|
|
|
consume(TokenType::Then);
|
|
|
|
|
auto then = parse_expression();
|
|
|
|
|
|
|
|
|
|
when_then_clauses.append({ move(when), move(then) });
|
|
|
|
|
|
|
|
|
|
if (!match(TokenType::When))
|
|
|
|
|
break;
|
|
|
|
|
} while (!match(TokenType::Eof));
|
|
|
|
|
|
|
|
|
|
RefPtr<Expression> else_expression;
|
|
|
|
|
if (consume_if(TokenType::Else))
|
|
|
|
|
else_expression = parse_expression();
|
|
|
|
|
|
|
|
|
|
consume(TokenType::End);
|
|
|
|
|
return create_ast_node<CaseExpression>(move(case_expression), move(when_then_clauses), move(else_expression));
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-12 23:47:00 +01:00
|
|
|
RefPtr<Expression> Parser::parse_exists_expression(bool invert_expression)
|
2021-04-23 15:29:28 -04:00
|
|
|
{
|
2023-04-12 23:47:00 +01:00
|
|
|
if (!(match(TokenType::Exists) || match(TokenType::ParenOpen)))
|
2021-04-23 15:29:28 -04:00
|
|
|
return {};
|
|
|
|
|
|
2023-04-12 23:47:00 +01:00
|
|
|
consume_if(TokenType::Exists);
|
|
|
|
|
consume(TokenType::ParenOpen);
|
|
|
|
|
|
2021-04-23 15:29:28 -04:00
|
|
|
auto select_statement = parse_select_statement({});
|
|
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
|
|
|
|
|
return create_ast_node<ExistsExpression>(move(select_statement), invert_expression);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_collate_expression(NonnullRefPtr<Expression> expression)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::Collate))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
consume();
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString collation_name = consume(TokenType::Identifier).value();
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<CollateExpression>(move(expression), move(collation_name));
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_is_expression(NonnullRefPtr<Expression> expression)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::Is))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
consume();
|
|
|
|
|
|
|
|
|
|
bool invert_expression = false;
|
|
|
|
|
if (match(TokenType::Not)) {
|
|
|
|
|
consume();
|
|
|
|
|
invert_expression = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto rhs = parse_expression();
|
|
|
|
|
return create_ast_node<IsExpression>(move(expression), move(rhs), invert_expression);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_match_expression(NonnullRefPtr<Expression> lhs, bool invert_expression)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
auto parse_escape = [this]() {
|
|
|
|
|
RefPtr<Expression> escape;
|
2021-12-29 11:48:09 -03:00
|
|
|
if (consume_if(TokenType::Escape)) {
|
2021-04-20 17:49:26 -04:00
|
|
|
escape = parse_expression();
|
2021-12-29 11:48:09 -03:00
|
|
|
}
|
2021-04-20 17:49:26 -04:00
|
|
|
return escape;
|
|
|
|
|
};
|
|
|
|
|
|
2021-12-29 11:48:09 -03:00
|
|
|
if (consume_if(TokenType::Like)) {
|
|
|
|
|
NonnullRefPtr<Expression> rhs = parse_expression();
|
|
|
|
|
RefPtr<Expression> escape = parse_escape();
|
|
|
|
|
return create_ast_node<MatchExpression>(MatchOperator::Like, move(lhs), move(rhs), move(escape), invert_expression);
|
|
|
|
|
}
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-12-29 11:48:09 -03:00
|
|
|
if (consume_if(TokenType::Glob)) {
|
|
|
|
|
NonnullRefPtr<Expression> rhs = parse_expression();
|
|
|
|
|
RefPtr<Expression> escape = parse_escape();
|
|
|
|
|
return create_ast_node<MatchExpression>(MatchOperator::Glob, move(lhs), move(rhs), move(escape), invert_expression);
|
|
|
|
|
}
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-12-29 11:48:09 -03:00
|
|
|
if (consume_if(TokenType::Match)) {
|
|
|
|
|
NonnullRefPtr<Expression> rhs = parse_expression();
|
|
|
|
|
RefPtr<Expression> escape = parse_escape();
|
|
|
|
|
return create_ast_node<MatchExpression>(MatchOperator::Match, move(lhs), move(rhs), move(escape), invert_expression);
|
|
|
|
|
}
|
2021-04-20 17:49:26 -04:00
|
|
|
|
2021-12-29 11:48:09 -03:00
|
|
|
if (consume_if(TokenType::Regexp)) {
|
|
|
|
|
NonnullRefPtr<Expression> rhs = parse_expression();
|
|
|
|
|
RefPtr<Expression> escape = parse_escape();
|
|
|
|
|
return create_ast_node<MatchExpression>(MatchOperator::Regexp, move(lhs), move(rhs), move(escape), invert_expression);
|
|
|
|
|
}
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_null_expression(NonnullRefPtr<Expression> expression, bool invert_expression)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::Isnull) && !match(TokenType::Notnull) && !(invert_expression && match(TokenType::Null)))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
auto type = consume().type();
|
|
|
|
|
invert_expression |= (type == TokenType::Notnull);
|
|
|
|
|
|
|
|
|
|
return create_ast_node<NullExpression>(move(expression), invert_expression);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_between_expression(NonnullRefPtr<Expression> expression, bool invert_expression)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::Between))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
consume();
|
|
|
|
|
|
|
|
|
|
auto nested = parse_expression();
|
|
|
|
|
if (!is<BinaryOperatorExpression>(*nested)) {
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("Binary Expression"sv);
|
2021-04-20 17:49:26 -04:00
|
|
|
return create_ast_node<ErrorExpression>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
auto const& binary_expression = static_cast<BinaryOperatorExpression const&>(*nested);
|
2021-04-20 17:49:26 -04:00
|
|
|
if (binary_expression.type() != BinaryOperator::And) {
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("AND Expression"sv);
|
2021-04-20 17:49:26 -04:00
|
|
|
return create_ast_node<ErrorExpression>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return create_ast_node<BetweenExpression>(move(expression), binary_expression.lhs(), binary_expression.rhs(), invert_expression);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-03 12:48:38 +02:00
|
|
|
RefPtr<Expression> Parser::parse_in_expression(NonnullRefPtr<Expression> expression, bool invert_expression)
|
2021-04-20 17:49:26 -04:00
|
|
|
{
|
|
|
|
|
if (!match(TokenType::In))
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
consume();
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::ParenOpen)) {
|
|
|
|
|
if (match(TokenType::Select)) {
|
2021-04-23 14:54:37 -04:00
|
|
|
auto select_statement = parse_select_statement({});
|
|
|
|
|
return create_ast_node<InSelectionExpression>(move(expression), move(select_statement), invert_expression);
|
2021-04-20 17:49:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: Consolidate this with parse_chained_expression(). That method consumes the opening paren as
|
|
|
|
|
// well, and also requires at least one expression (whereas this allows for an empty chain).
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<Expression>> expressions;
|
2021-04-23 12:33:32 -04:00
|
|
|
if (!match(TokenType::ParenClose))
|
|
|
|
|
parse_comma_separated_list(false, [&]() { expressions.append(parse_expression()); });
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
|
|
|
|
|
auto chain = create_ast_node<ChainedExpression>(move(expressions));
|
|
|
|
|
return create_ast_node<InChainedExpression>(move(expression), move(chain), invert_expression);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 12:39:44 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
2021-04-20 17:49:26 -04:00
|
|
|
|
|
|
|
|
if (match(TokenType::ParenOpen)) {
|
|
|
|
|
// FIXME: Parse "table-function".
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return create_ast_node<InTableExpression>(move(expression), move(schema_name), move(table_name), invert_expression);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 17:38:38 -04:00
|
|
|
NonnullRefPtr<ColumnDefinition> Parser::parse_column_definition()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/column-def.html
|
|
|
|
|
auto name = consume(TokenType::Identifier).value();
|
|
|
|
|
|
|
|
|
|
auto type_name = match(TokenType::Identifier)
|
|
|
|
|
? parse_type_name()
|
|
|
|
|
// https://www.sqlite.org/datatype3.html: If no type is specified then the column has affinity BLOB.
|
2023-03-06 14:17:01 +01:00
|
|
|
: create_ast_node<TypeName>("BLOB", Vector<NonnullRefPtr<SignedNumber>> {});
|
2021-04-18 17:38:38 -04:00
|
|
|
|
|
|
|
|
// FIXME: Parse "column-constraint".
|
|
|
|
|
|
|
|
|
|
return create_ast_node<ColumnDefinition>(move(name), move(type_name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<TypeName> Parser::parse_type_name()
|
|
|
|
|
{
|
|
|
|
|
// https: //sqlite.org/syntax/type-name.html
|
|
|
|
|
auto name = consume(TokenType::Identifier).value();
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<SignedNumber>> signed_numbers;
|
2021-04-18 17:38:38 -04:00
|
|
|
|
2021-04-21 09:38:07 -04:00
|
|
|
if (consume_if(TokenType::ParenOpen)) {
|
2021-04-18 17:38:38 -04:00
|
|
|
signed_numbers.append(parse_signed_number());
|
|
|
|
|
|
2021-04-21 09:38:07 -04:00
|
|
|
if (consume_if(TokenType::Comma))
|
2021-04-18 17:38:38 -04:00
|
|
|
signed_numbers.append(parse_signed_number());
|
|
|
|
|
|
|
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return create_ast_node<TypeName>(move(name), move(signed_numbers));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<SignedNumber> Parser::parse_signed_number()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/signed-number.html
|
|
|
|
|
bool is_positive = true;
|
|
|
|
|
|
2021-04-21 09:38:07 -04:00
|
|
|
if (consume_if(TokenType::Plus))
|
|
|
|
|
is_positive = true;
|
|
|
|
|
else if (consume_if(TokenType::Minus))
|
2021-04-18 17:38:38 -04:00
|
|
|
is_positive = false;
|
|
|
|
|
|
|
|
|
|
if (match(TokenType::NumericLiteral)) {
|
|
|
|
|
auto number = consume(TokenType::NumericLiteral).double_value();
|
|
|
|
|
return create_ast_node<SignedNumber>(is_positive ? number : (number * -1));
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("NumericLiteral"sv);
|
2021-04-18 17:38:38 -04:00
|
|
|
return create_ast_node<SignedNumber>(0);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 14:13:05 -04:00
|
|
|
NonnullRefPtr<CommonTableExpression> Parser::parse_common_table_expression()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/common-table-expression.html
|
|
|
|
|
auto table_name = consume(TokenType::Identifier).value();
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
Vector<ByteString> column_names;
|
2021-04-23 12:33:32 -04:00
|
|
|
if (match(TokenType::ParenOpen))
|
|
|
|
|
parse_comma_separated_list(true, [&]() { column_names.append(consume(TokenType::Identifier).value()); });
|
2021-04-21 14:13:05 -04:00
|
|
|
|
|
|
|
|
consume(TokenType::As);
|
|
|
|
|
consume(TokenType::ParenOpen);
|
2021-04-23 14:45:56 -04:00
|
|
|
auto select_statement = parse_select_statement({});
|
2021-04-21 14:13:05 -04:00
|
|
|
consume(TokenType::ParenClose);
|
|
|
|
|
|
2021-04-23 14:45:56 -04:00
|
|
|
return create_ast_node<CommonTableExpression>(move(table_name), move(column_names), move(select_statement));
|
2021-04-21 14:13:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<QualifiedTableName> Parser::parse_qualified_table_name()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/qualified-table-name.html
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 12:39:44 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
2021-04-21 14:13:05 -04:00
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString alias;
|
2021-04-21 14:13:05 -04:00
|
|
|
if (consume_if(TokenType::As))
|
|
|
|
|
alias = consume(TokenType::Identifier).value();
|
|
|
|
|
|
|
|
|
|
// Note: The qualified-table-name spec may include an "INDEXED BY index-name" or "NOT INDEXED" clause. This is a SQLite extension
|
|
|
|
|
// "designed to help detect undesirable query plan changes during regression testing", and "application developers are admonished
|
|
|
|
|
// to omit all use of INDEXED BY during application design, implementation, testing, and tuning". Our implementation purposefully
|
|
|
|
|
// omits parsing INDEXED BY for now until there is good reason to add support.
|
|
|
|
|
|
|
|
|
|
return create_ast_node<QualifiedTableName>(move(schema_name), move(table_name), move(alias));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<ReturningClause> Parser::parse_returning_clause()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/returning-clause.html
|
|
|
|
|
consume(TokenType::Returning);
|
|
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Asterisk))
|
|
|
|
|
return create_ast_node<ReturningClause>();
|
|
|
|
|
|
|
|
|
|
Vector<ReturningClause::ColumnClause> columns;
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(false, [&]() {
|
2021-04-21 14:13:05 -04:00
|
|
|
auto expression = parse_expression();
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString column_alias;
|
2021-04-23 12:02:51 -04:00
|
|
|
if (consume_if(TokenType::As) || match(TokenType::Identifier))
|
|
|
|
|
column_alias = consume(TokenType::Identifier).value();
|
2021-04-21 14:13:05 -04:00
|
|
|
|
|
|
|
|
columns.append({ move(expression), move(column_alias) });
|
2021-04-23 12:33:32 -04:00
|
|
|
});
|
2021-04-21 14:13:05 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<ReturningClause>(move(columns));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:11:17 -04:00
|
|
|
NonnullRefPtr<ResultColumn> Parser::parse_result_column()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/result-column.html
|
|
|
|
|
if (consume_if(TokenType::Asterisk))
|
|
|
|
|
return create_ast_node<ResultColumn>();
|
|
|
|
|
|
|
|
|
|
// If we match an identifier now, we don't know whether it is a table-name of the form "table-name.*", or if it is the start of a
|
2021-05-17 17:48:55 +01:00
|
|
|
// column-name-expression, until we try to parse the asterisk. So if we consume an identifier and a period, but don't find an
|
2021-04-22 10:11:17 -04:00
|
|
|
// asterisk, hold onto that information to form a column-name-expression later.
|
2023-12-16 17:49:34 +03:30
|
|
|
Optional<ByteString> table_name;
|
2021-04-22 10:11:17 -04:00
|
|
|
bool parsed_period = false;
|
|
|
|
|
|
|
|
|
|
if (match(TokenType::Identifier)) {
|
|
|
|
|
table_name = consume().value();
|
|
|
|
|
parsed_period = consume_if(TokenType::Period);
|
|
|
|
|
if (parsed_period && consume_if(TokenType::Asterisk))
|
2023-10-10 15:00:58 +03:30
|
|
|
return create_ast_node<ResultColumn>(table_name.release_value());
|
2021-04-22 10:11:17 -04:00
|
|
|
}
|
|
|
|
|
|
2023-10-10 15:00:58 +03:30
|
|
|
auto expression = !table_name.has_value()
|
2021-04-22 10:11:17 -04:00
|
|
|
? parse_expression()
|
|
|
|
|
: static_cast<NonnullRefPtr<Expression>>(*parse_column_name_expression(move(table_name), parsed_period));
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString column_alias;
|
2021-04-23 12:02:51 -04:00
|
|
|
if (consume_if(TokenType::As) || match(TokenType::Identifier))
|
|
|
|
|
column_alias = consume(TokenType::Identifier).value();
|
2021-04-22 10:11:17 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<ResultColumn>(move(expression), move(column_alias));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<TableOrSubquery> Parser::parse_table_or_subquery()
|
|
|
|
|
{
|
2021-06-08 09:22:06 -04:00
|
|
|
if (++m_parser_state.m_current_subquery_depth > Limits::maximum_subquery_depth)
|
2023-12-16 17:49:34 +03:30
|
|
|
syntax_error(ByteString::formatted("Exceeded maximum subquery depth of {}", Limits::maximum_subquery_depth));
|
2021-06-08 09:22:06 -04:00
|
|
|
|
|
|
|
|
ScopeGuard guard([&]() { --m_parser_state.m_current_subquery_depth; });
|
|
|
|
|
|
2021-04-22 10:11:17 -04:00
|
|
|
// https://sqlite.org/syntax/table-or-subquery.html
|
|
|
|
|
if (match(TokenType::Identifier)) {
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_name;
|
|
|
|
|
ByteString table_name;
|
2021-04-23 12:39:44 -04:00
|
|
|
parse_schema_and_table_name(schema_name, table_name);
|
2021-04-22 10:11:17 -04:00
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString table_alias;
|
2021-04-23 12:02:51 -04:00
|
|
|
if (consume_if(TokenType::As) || match(TokenType::Identifier))
|
|
|
|
|
table_alias = consume(TokenType::Identifier).value();
|
2021-04-22 10:11:17 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<TableOrSubquery>(move(schema_name), move(table_name), move(table_alias));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: Parse join-clause.
|
|
|
|
|
|
2023-03-06 14:17:01 +01:00
|
|
|
Vector<NonnullRefPtr<TableOrSubquery>> subqueries;
|
2021-04-23 12:33:32 -04:00
|
|
|
parse_comma_separated_list(true, [&]() { subqueries.append(parse_table_or_subquery()); });
|
2021-04-22 10:11:17 -04:00
|
|
|
|
|
|
|
|
return create_ast_node<TableOrSubquery>(move(subqueries));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<OrderingTerm> Parser::parse_ordering_term()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/syntax/ordering-term.html
|
|
|
|
|
auto expression = parse_expression();
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString collation_name;
|
2021-04-22 10:11:17 -04:00
|
|
|
if (is<CollateExpression>(*expression)) {
|
2022-04-01 20:58:27 +03:00
|
|
|
auto const& collate = static_cast<CollateExpression const&>(*expression);
|
2021-04-22 10:11:17 -04:00
|
|
|
collation_name = collate.collation_name();
|
|
|
|
|
expression = collate.expression();
|
|
|
|
|
} else if (consume_if(TokenType::Collate)) {
|
|
|
|
|
collation_name = consume(TokenType::Identifier).value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Order order = consume_if(TokenType::Desc) ? Order::Descending : Order::Ascending;
|
|
|
|
|
consume_if(TokenType::Asc); // ASC is the default, so ignore it if specified.
|
|
|
|
|
|
|
|
|
|
Nulls nulls = order == Order::Ascending ? Nulls::First : Nulls::Last;
|
|
|
|
|
if (consume_if(TokenType::Nulls)) {
|
|
|
|
|
if (consume_if(TokenType::First))
|
|
|
|
|
nulls = Nulls::First;
|
|
|
|
|
else if (consume_if(TokenType::Last))
|
|
|
|
|
nulls = Nulls::Last;
|
|
|
|
|
else
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("FIRST or LAST"sv);
|
2021-04-22 10:11:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return create_ast_node<OrderingTerm>(move(expression), move(collation_name), order, nulls);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
void Parser::parse_schema_and_table_name(ByteString& schema_name, ByteString& table_name)
|
2021-04-23 12:39:44 -04:00
|
|
|
{
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString schema_or_table_name = consume(TokenType::Identifier).value();
|
2021-04-23 12:39:44 -04:00
|
|
|
|
|
|
|
|
if (consume_if(TokenType::Period)) {
|
|
|
|
|
schema_name = move(schema_or_table_name);
|
|
|
|
|
table_name = consume(TokenType::Identifier).value();
|
|
|
|
|
} else {
|
|
|
|
|
table_name = move(schema_or_table_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-23 21:40:19 -04:00
|
|
|
ConflictResolution Parser::parse_conflict_resolution()
|
|
|
|
|
{
|
|
|
|
|
// https://sqlite.org/lang_conflict.html
|
|
|
|
|
if (consume_if(TokenType::Or)) {
|
|
|
|
|
if (consume_if(TokenType::Abort))
|
|
|
|
|
return ConflictResolution::Abort;
|
|
|
|
|
if (consume_if(TokenType::Fail))
|
|
|
|
|
return ConflictResolution::Fail;
|
|
|
|
|
if (consume_if(TokenType::Ignore))
|
|
|
|
|
return ConflictResolution::Ignore;
|
|
|
|
|
if (consume_if(TokenType::Replace))
|
|
|
|
|
return ConflictResolution::Replace;
|
|
|
|
|
if (consume_if(TokenType::Rollback))
|
|
|
|
|
return ConflictResolution::Rollback;
|
|
|
|
|
|
2022-07-11 17:32:29 +00:00
|
|
|
expected("ABORT, FAIL, IGNORE, REPLACE, or ROLLBACK"sv);
|
2021-04-23 21:40:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ConflictResolution::Abort;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 17:38:38 -04:00
|
|
|
Token Parser::consume()
|
|
|
|
|
{
|
|
|
|
|
auto old_token = m_parser_state.m_token;
|
|
|
|
|
m_parser_state.m_token = m_parser_state.m_lexer.next();
|
|
|
|
|
return old_token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Token Parser::consume(TokenType expected_type)
|
|
|
|
|
{
|
|
|
|
|
if (!match(expected_type)) {
|
|
|
|
|
expected(Token::name(expected_type));
|
|
|
|
|
}
|
|
|
|
|
return consume();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 09:38:07 -04:00
|
|
|
bool Parser::consume_if(TokenType expected_type)
|
|
|
|
|
{
|
|
|
|
|
if (!match(expected_type))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
consume();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 17:38:38 -04:00
|
|
|
bool Parser::match(TokenType type) const
|
|
|
|
|
{
|
|
|
|
|
return m_parser_state.m_token.type() == type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Parser::expected(StringView what)
|
|
|
|
|
{
|
2023-12-16 17:49:34 +03:30
|
|
|
syntax_error(ByteString::formatted("Unexpected token {}, expected {}", m_parser_state.m_token.name(), what));
|
2021-04-18 17:38:38 -04:00
|
|
|
}
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
void Parser::syntax_error(ByteString message)
|
2021-04-18 17:38:38 -04:00
|
|
|
{
|
|
|
|
|
m_parser_state.m_errors.append({ move(message), position() });
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-21 11:20:09 -04:00
|
|
|
SourcePosition Parser::position() const
|
2021-04-18 17:38:38 -04:00
|
|
|
{
|
2021-06-21 11:20:09 -04:00
|
|
|
return m_parser_state.m_token.start_position();
|
2021-04-18 17:38:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Parser::ParserState::ParserState(Lexer lexer)
|
|
|
|
|
: m_lexer(move(lexer))
|
|
|
|
|
, m_token(m_lexer.next())
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|