diff --git a/Userland/Libraries/LibSQL/AST.h b/Userland/Libraries/LibSQL/AST.h index ca6553e4a6..74d2619eb7 100644 --- a/Userland/Libraries/LibSQL/AST.h +++ b/Userland/Libraries/LibSQL/AST.h @@ -125,4 +125,23 @@ private: bool m_is_error_if_table_exists; }; +class DropTable : public Statement { +public: + DropTable(String schema_name, String table_name, bool is_error_if_table_does_not_exist) + : m_schema_name(move(schema_name)) + , m_table_name(move(table_name)) + , m_is_error_if_table_does_not_exist(is_error_if_table_does_not_exist) + { + } + + const String& schema_name() const { return m_schema_name; } + const String& table_name() const { return m_table_name; } + bool is_error_if_table_does_not_exist() const { return m_is_error_if_table_does_not_exist; } + +private: + String m_schema_name; + String m_table_name; + bool m_is_error_if_table_does_not_exist; +}; + } diff --git a/Userland/Libraries/LibSQL/Parser.cpp b/Userland/Libraries/LibSQL/Parser.cpp index cc76b3d17a..f5e4f94896 100644 --- a/Userland/Libraries/LibSQL/Parser.cpp +++ b/Userland/Libraries/LibSQL/Parser.cpp @@ -38,8 +38,10 @@ NonnullRefPtr Parser::next_statement() switch (m_parser_state.m_token.type()) { case TokenType::Create: return parse_create_table_statement(); + case TokenType::Drop: + return parse_drop_table_statement(); default: - expected("CREATE"); + expected("CREATE or DROP"); return create_ast_node(); } } @@ -98,6 +100,36 @@ NonnullRefPtr Parser::parse_create_table_statement() return create_ast_node(move(schema_name), move(table_name), move(column_definitions), is_temporary, is_error_if_table_exists); } +NonnullRefPtr 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; + if (match(TokenType::If)) { + consume(TokenType::If); + consume(TokenType::Exists); + is_error_if_table_does_not_exist = false; + } + + String schema_or_table_name = consume(TokenType::Identifier).value(); + String schema_name; + String table_name; + + if (match(TokenType::Period)) { + consume(); + schema_name = move(schema_or_table_name); + table_name = consume(TokenType::Identifier).value(); + } else { + table_name = move(schema_or_table_name); + } + + consume(TokenType::SemiColon); + + return create_ast_node(move(schema_name), move(table_name), is_error_if_table_does_not_exist); +} + NonnullRefPtr Parser::parse_column_definition() { // https://sqlite.org/syntax/column-def.html diff --git a/Userland/Libraries/LibSQL/Parser.h b/Userland/Libraries/LibSQL/Parser.h index 6efdd5bba7..379ddef1d5 100644 --- a/Userland/Libraries/LibSQL/Parser.h +++ b/Userland/Libraries/LibSQL/Parser.h @@ -67,8 +67,9 @@ private: Vector m_errors; }; - NonnullRefPtr parse_column_definition(); NonnullRefPtr parse_create_table_statement(); + NonnullRefPtr parse_drop_table_statement(); + NonnullRefPtr parse_column_definition(); NonnullRefPtr parse_type_name(); NonnullRefPtr parse_signed_number(); diff --git a/Userland/Libraries/LibSQL/Tests/TestSqlParser.cpp b/Userland/Libraries/LibSQL/Tests/TestSqlParser.cpp index d6b3b82b0b..c7701c641d 100644 --- a/Userland/Libraries/LibSQL/Tests/TestSqlParser.cpp +++ b/Userland/Libraries/LibSQL/Tests/TestSqlParser.cpp @@ -132,4 +132,29 @@ TEST_CASE(create_table) validate("CREATE TABLE test ( column1 varchar(1e3) );", {}, "test", { { "column1", "varchar", { 1000 } } }); } +TEST_CASE(drop_table) +{ + EXPECT(parse("DROP").is_error()); + EXPECT(parse("DROP TABLE").is_error()); + EXPECT(parse("DROP TABLE test").is_error()); + EXPECT(parse("DROP TABLE IF 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); + EXPECT(!result.is_error()); + + auto statement = result.release_value(); + EXPECT(is(*statement)); + + const auto& table = static_cast(*statement); + EXPECT_EQ(table.schema_name(), expected_schema); + EXPECT_EQ(table.table_name(), expected_table); + EXPECT_EQ(table.is_error_if_table_does_not_exist(), expected_is_error_if_table_does_not_exist); + }; + + validate("DROP TABLE test;", {}, "test"); + validate("DROP TABLE schema.test;", "schema", "test"); + validate("DROP TABLE IF EXISTS test;", {}, "test", false); +} + TEST_MAIN(SqlParser)