diff --git a/README.md b/README.md index 0b6917120..1d465edd0 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ SQLite works with a grammar of _167_ token types, _136_ of which are keywords. T - [ ] `analyze_stmt` - [ ] `attach_stmt` - [ ] `begin_stmt` -- [ ] `commit_stmt` +- [x] `commit_stmt` - [x] `create_table_stmt` - [ ] `create_index_stmt` - [ ] `create_trigger_stmt` diff --git a/lib/plume.rb b/lib/plume.rb index 3234a8d3c..fbff2d262 100644 --- a/lib/plume.rb +++ b/lib/plume.rb @@ -26,6 +26,7 @@ module Plume autoload :ColumnDefinition, "plume/ast/column_definition" autoload :ColumnName, "plume/ast/column_name" autoload :ColumnType, "plume/ast/column_type" + autoload :CommitStatement, "plume/ast/commit_statement" autoload :ConflictClause, "plume/ast/conflict_clause" autoload :CreateTableStatement, "plume/ast/create_table_statement" autoload :CrossJoinOperator, "plume/ast/cross_join_operator" diff --git a/lib/plume/ast/commit_statement.rb b/lib/plume/ast/commit_statement.rb new file mode 100644 index 000000000..d658e44b7 --- /dev/null +++ b/lib/plume/ast/commit_statement.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Plume + # **[SQLite Docs](https://www.sqlite.org/lang_transaction.html)** + # + # ```sql + # commmit + # ``` + class CommitStatement < Node + token :commit_kw + token :transaction_kw + + def self.concrete(*, commit_kw:, transaction_kw:, **) = super + end +end diff --git a/lib/plume/parser.rb b/lib/plume/parser.rb index 66812bc01..9f260228b 100644 --- a/lib/plume/parser.rb +++ b/lib/plume/parser.rb @@ -596,6 +596,31 @@ def select_stmt # end end + def commit_stmt + # + # Relevant `parse.y` grammar rules: + # cmd ::= COMMIT|END(X) trans_opt. {sqlite3EndTransaction(pParse,@X);} + # + # Syntax diagram: + # ◯─▶┬─▶{ COMMIT }┬─▶─┬──▶{ TRANSACTION }─┬─▶◯ + # ├▶{ End }──▶─┤ ├─────────▶─────────┤ + + # Simplified grammar: + # COMMIT [TRANSACTION] | END [TRANSACTION] + # + # Relevant SQLite documentation: + # - https://www.sqlite.org/lang_transaction.html + # + commit_kw = require_one_of :COMMIT, :END + transaction_kw = maybe :TRANSACTION + + CommitStatement.concrete( + full_source: @lexer.sql, + commit_kw: Token::Keyword(commit_kw), + transaction_kw: Token::Keyword(transaction_kw), + ) + end + # ---------- Clauses ---------- def expression(min_precedence = 0) @@ -2818,4 +2843,4 @@ def error!(token, value, expected) throw :ERROR, ErrorMessage.new(msg) end end -end \ No newline at end of file +end diff --git a/test/commit.test.rb b/test/commit.test.rb new file mode 100644 index 000000000..0addc5181 --- /dev/null +++ b/test/commit.test.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +test "commit" do + node = parse_stmt(<<~SQL) + COMMIT; + SQL + + assert_equal node.commit_kw_val, "COMMIT" + assert_equal node.transaction_kw_val, nil +end + +test "commit transaction" do + node = parse_stmt(<<~SQL) + COMMIT TRANSACTION; + SQL + + assert_equal node.commit_kw_val, "COMMIT" + assert_equal node.transaction_kw_val, "TRANSACTION" +end + +test "end" do + node = parse_stmt(<<~SQL) + end; + SQL + + assert_equal node.commit_kw_val, "end" + assert_equal node.transaction_kw_val, nil +end + +test "end transaction" do + node = parse_stmt(<<~SQL) + end transaction; + SQL + + assert_equal node.commit_kw_val, "end" + assert_equal node.transaction_kw_val, "transaction" +end