1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:38:11 +00:00

LibSQL: Parse (most of) SELECT statement

This doesn't yet parse join clauses, windowing functions, or compound
SELECT statements.
This commit is contained in:
Timothy Flynn 2021-04-22 10:11:17 -04:00 committed by Andreas Kling
parent 9331293e44
commit ac0e387beb
5 changed files with 555 additions and 7 deletions

View file

@ -234,4 +234,168 @@ TEST_CASE(delete_)
validate("WITH RECURSIVE table AS () DELETE FROM table;", { true, { { "table", {} } } }, {}, "table", {}, false, false, {});
}
TEST_CASE(select)
{
EXPECT(parse("SELECT").is_error());
EXPECT(parse("SELECT;").is_error());
EXPECT(parse("SELECT DISTINCT;").is_error());
EXPECT(parse("SELECT ALL;").is_error());
EXPECT(parse("SELECT *").is_error());
EXPECT(parse("SELECT * FROM;").is_error());
EXPECT(parse("SELECT table. FROM table;").is_error());
EXPECT(parse("SELECT * FROM (").is_error());
EXPECT(parse("SELECT * FROM ()").is_error());
EXPECT(parse("SELECT * FROM ();").is_error());
EXPECT(parse("SELECT * FROM (table1)").is_error());
EXPECT(parse("SELECT * FROM (table1, )").is_error());
EXPECT(parse("SELECT * FROM (table1, table2)").is_error());
EXPECT(parse("SELECT * FROM table").is_error());
EXPECT(parse("SELECT * FROM table WHERE;").is_error());
EXPECT(parse("SELECT * FROM table WHERE 1 ==1").is_error());
EXPECT(parse("SELECT * FROM table GROUP;").is_error());
EXPECT(parse("SELECT * FROM table GROUP BY;").is_error());
EXPECT(parse("SELECT * FROM table GROUP BY column").is_error());
EXPECT(parse("SELECT * FROM table ORDER:").is_error());
EXPECT(parse("SELECT * FROM table ORDER BY column").is_error());
EXPECT(parse("SELECT * FROM table ORDER BY column COLLATE:").is_error());
EXPECT(parse("SELECT * FROM table ORDER BY column COLLATE collation").is_error());
EXPECT(parse("SELECT * FROM table ORDER BY column NULLS;").is_error());
EXPECT(parse("SELECT * FROM table ORDER BY column NULLS SECOND;").is_error());
EXPECT(parse("SELECT * FROM table LIMIT;").is_error());
EXPECT(parse("SELECT * FROM table LIMIT 12").is_error());
EXPECT(parse("SELECT * FROM table LIMIT 12 OFFSET;").is_error());
EXPECT(parse("SELECT * FROM table LIMIT 12 OFFSET 15").is_error());
struct Type {
SQL::ResultType type;
StringView table_name_or_column_alias {};
};
struct From {
StringView schema_name;
StringView table_name;
StringView table_alias;
};
struct Ordering {
String collation_name;
SQL::Order order;
SQL::Nulls nulls;
};
auto validate = [](StringView sql, Vector<Type> expected_columns, Vector<From> expected_from_list, bool expect_where_clause, size_t expected_group_by_size, bool expect_having_clause, Vector<Ordering> expected_ordering, bool expect_limit_clause, bool expect_offset_clause) {
auto result = parse(sql);
EXPECT(!result.is_error());
auto statement = result.release_value();
EXPECT(is<SQL::Select>(*statement));
const auto& select = static_cast<const SQL::Select&>(*statement);
const auto& result_column_list = select.result_column_list();
EXPECT_EQ(result_column_list.size(), expected_columns.size());
for (size_t i = 0; i < result_column_list.size(); ++i) {
const auto& result_column = result_column_list[i];
const auto& expected_column = expected_columns[i];
EXPECT_EQ(result_column.type(), expected_column.type);
switch (result_column.type()) {
case SQL::ResultType::All:
EXPECT(expected_column.table_name_or_column_alias.is_null());
break;
case SQL::ResultType::Table:
EXPECT_EQ(result_column.table_name(), expected_column.table_name_or_column_alias);
break;
case SQL::ResultType::Expression:
EXPECT_EQ(result_column.column_alias(), expected_column.table_name_or_column_alias);
break;
}
}
const auto& table_or_subquery_list = select.table_or_subquery_list();
EXPECT_EQ(table_or_subquery_list.size(), expected_from_list.size());
for (size_t i = 0; i < table_or_subquery_list.size(); ++i) {
const auto& result_from = table_or_subquery_list[i];
const auto& expected_from = expected_from_list[i];
EXPECT_EQ(result_from.schema_name(), expected_from.schema_name);
EXPECT_EQ(result_from.table_name(), expected_from.table_name);
EXPECT_EQ(result_from.table_alias(), expected_from.table_alias);
}
const auto& where_clause = select.where_clause();
EXPECT_EQ(where_clause.is_null(), !expect_where_clause);
if (where_clause)
EXPECT(!is<SQL::ErrorExpression>(*where_clause));
const auto& group_by_clause = select.group_by_clause();
EXPECT_EQ(group_by_clause.is_null(), (expected_group_by_size == 0));
if (group_by_clause) {
const auto& group_by_list = group_by_clause->group_by_list();
EXPECT_EQ(group_by_list.size(), expected_group_by_size);
for (size_t i = 0; i < group_by_list.size(); ++i)
EXPECT(!is<SQL::ErrorExpression>(group_by_list[i]));
const auto& having_clause = group_by_clause->having_clause();
EXPECT_EQ(having_clause.is_null(), !expect_having_clause);
if (having_clause)
EXPECT(!is<SQL::ErrorExpression>(*having_clause));
}
const auto& ordering_term_list = select.ordering_term_list();
EXPECT_EQ(ordering_term_list.size(), expected_ordering.size());
for (size_t i = 0; i < ordering_term_list.size(); ++i) {
const auto& result_order = ordering_term_list[i];
const auto& expected_order = expected_ordering[i];
EXPECT(!is<SQL::ErrorExpression>(*result_order.expression()));
EXPECT_EQ(result_order.collation_name(), expected_order.collation_name);
EXPECT_EQ(result_order.order(), expected_order.order);
EXPECT_EQ(result_order.nulls(), expected_order.nulls);
}
const auto& limit_clause = select.limit_clause();
EXPECT_EQ(limit_clause.is_null(), !expect_limit_clause);
if (limit_clause) {
const auto& limit_expression = limit_clause->limit_expression();
EXPECT(!is<SQL::ErrorExpression>(*limit_expression));
const auto& offset_expression = limit_clause->offset_expression();
EXPECT_EQ(offset_expression.is_null(), !expect_offset_clause);
if (offset_expression)
EXPECT(!is<SQL::ErrorExpression>(*offset_expression));
}
};
Vector<Type> all { { SQL::ResultType::All } };
Vector<From> from { { {}, "table", {} } };
validate("SELECT * FROM table;", { { SQL::ResultType::All } }, from, false, 0, false, {}, false, false);
validate("SELECT table.* FROM table;", { { SQL::ResultType::Table, "table" } }, from, false, 0, false, {}, false, false);
validate("SELECT column AS alias FROM table;", { { SQL::ResultType::Expression, "alias" } }, from, false, 0, false, {}, false, false);
validate("SELECT table.column AS alias FROM table;", { { SQL::ResultType::Expression, "alias" } }, from, false, 0, false, {}, false, false);
validate("SELECT schema.table.column AS alias FROM table;", { { SQL::ResultType::Expression, "alias" } }, from, false, 0, false, {}, false, false);
validate("SELECT column AS alias, *, table.* FROM table;", { { SQL::ResultType::Expression, "alias" }, { SQL::ResultType::All }, { SQL::ResultType::Table, "table" } }, from, false, 0, false, {}, false, false);
validate("SELECT * FROM table;", all, { { {}, "table", {} } }, false, 0, false, {}, false, false);
validate("SELECT * FROM schema.table;", all, { { "schema", "table", {} } }, false, 0, false, {}, false, false);
validate("SELECT * FROM schema.table AS alias;", all, { { "schema", "table", "alias" } }, false, 0, false, {}, false, false);
validate("SELECT * FROM schema.table AS alias, table2, table3 AS table4;", all, { { "schema", "table", "alias" }, { {}, "table2", {} }, { {}, "table3", "table4" } }, false, 0, false, {}, false, false);
validate("SELECT * FROM table WHERE column IS NOT NULL;", all, from, true, 0, false, {}, false, false);
validate("SELECT * FROM table GROUP BY column;", all, from, false, 1, false, {}, false, false);
validate("SELECT * FROM table GROUP BY column1, column2, column3;", all, from, false, 3, false, {}, false, false);
validate("SELECT * FROM table GROUP BY column HAVING 'abc';", all, from, false, 1, true, {}, false, false);
validate("SELECT * FROM table ORDER BY column;", all, from, false, 0, false, { { {}, SQL::Order::Ascending, SQL::Nulls::First } }, false, false);
validate("SELECT * FROM table ORDER BY column COLLATE collation;", all, from, false, 0, false, { { "collation", SQL::Order::Ascending, SQL::Nulls::First } }, false, false);
validate("SELECT * FROM table ORDER BY column ASC;", all, from, false, 0, false, { { {}, SQL::Order::Ascending, SQL::Nulls::First } }, false, false);
validate("SELECT * FROM table ORDER BY column DESC;", all, from, false, 0, false, { { {}, SQL::Order::Descending, SQL::Nulls::Last } }, false, false);
validate("SELECT * FROM table ORDER BY column ASC NULLS LAST;", all, from, false, 0, false, { { {}, SQL::Order::Ascending, SQL::Nulls::Last } }, false, false);
validate("SELECT * FROM table ORDER BY column DESC NULLS FIRST;", all, from, false, 0, false, { { {}, SQL::Order::Descending, SQL::Nulls::First } }, false, false);
validate("SELECT * FROM table ORDER BY column1, column2 DESC, column3 NULLS LAST;", all, from, false, 0, false, { { {}, SQL::Order::Ascending, SQL::Nulls::First }, { {}, SQL::Order::Descending, SQL::Nulls::Last }, { {}, SQL::Order::Ascending, SQL::Nulls::Last } }, false, false);
validate("SELECT * FROM table LIMIT 15;", all, from, false, 0, false, {}, true, false);
validate("SELECT * FROM table LIMIT 15 OFFSET 16;", all, from, false, 0, false, {}, true, true);
}
TEST_MAIN(SqlStatementParser)