diff --git a/docs/generated/sql/bnf/BUILD.bazel b/docs/generated/sql/bnf/BUILD.bazel index ad6e3b7f0f54..c7a2f7cc65e6 100644 --- a/docs/generated/sql/bnf/BUILD.bazel +++ b/docs/generated/sql/bnf/BUILD.bazel @@ -86,6 +86,7 @@ FILES = [ "col_qualification", "column_table_def", "comment", + "commit_prepared_stmt", "commit_transaction", "copy_stmt", "copy_to_stmt", @@ -183,6 +184,7 @@ FILES = [ "pause_stmt", "preparable_stmt", "prepare_stmt", + "prepare_transaction_stmt", "primary_key_column_level", "primary_key_table_level", "reassign_owned_by_stmt", @@ -204,6 +206,7 @@ FILES = [ "resume_schedule", "resume_stmt", "revoke_stmt", + "rollback_prepared_stmt", "rollback_transaction", "routine_body_stmt", "routine_return_stmt", diff --git a/docs/generated/sql/bnf/commit_prepared_stmt.bnf b/docs/generated/sql/bnf/commit_prepared_stmt.bnf new file mode 100644 index 000000000000..83c66a25a07b --- /dev/null +++ b/docs/generated/sql/bnf/commit_prepared_stmt.bnf @@ -0,0 +1,2 @@ +commit_prepared_stmt ::= + 'COMMIT' 'PREPARED' 'SCONST' diff --git a/docs/generated/sql/bnf/prepare_transaction_stmt.bnf b/docs/generated/sql/bnf/prepare_transaction_stmt.bnf new file mode 100644 index 000000000000..29f1fac86799 --- /dev/null +++ b/docs/generated/sql/bnf/prepare_transaction_stmt.bnf @@ -0,0 +1,2 @@ +prepare_transaction_stmt ::= + 'PREPARE' 'TRANSACTION' 'SCONST' diff --git a/docs/generated/sql/bnf/rollback_prepared_stmt.bnf b/docs/generated/sql/bnf/rollback_prepared_stmt.bnf new file mode 100644 index 000000000000..0c89356ba55f --- /dev/null +++ b/docs/generated/sql/bnf/rollback_prepared_stmt.bnf @@ -0,0 +1,2 @@ +rollback_prepared_stmt ::= + 'ROLLBACK' 'PREPARED' 'SCONST' diff --git a/docs/generated/sql/bnf/stmt_block.bnf b/docs/generated/sql/bnf/stmt_block.bnf index b36af937b7a2..dba709512714 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -153,6 +153,9 @@ transaction_stmt ::= | commit_stmt | rollback_stmt | abort_stmt + | prepare_transaction_stmt + | commit_prepared_stmt + | rollback_prepared_stmt close_cursor_stmt ::= 'CLOSE' 'ALL' @@ -470,6 +473,15 @@ rollback_stmt ::= abort_stmt ::= 'ABORT' opt_abort_mod +prepare_transaction_stmt ::= + 'PREPARE' 'TRANSACTION' 'SCONST' + +commit_prepared_stmt ::= + 'COMMIT' 'PREPARED' 'SCONST' + +rollback_prepared_stmt ::= + 'ROLLBACK' 'PREPARED' 'SCONST' + cursor_name ::= name @@ -1337,6 +1349,7 @@ unreserved_keyword ::= | 'POLYGONZM' | 'PRECEDING' | 'PREPARE' + | 'PREPARED' | 'PRESERVE' | 'PRIOR' | 'PRIORITY' @@ -4074,6 +4087,7 @@ bare_label_keywords ::= | 'POSITION' | 'PRECEDING' | 'PREPARE' + | 'PREPARED' | 'PRESERVE' | 'PRIMARY' | 'PRIOR' diff --git a/docs/generated/sql/bnf/transaction_stmt.bnf b/docs/generated/sql/bnf/transaction_stmt.bnf index bd4bd638aecb..a2c2c71209a4 100644 --- a/docs/generated/sql/bnf/transaction_stmt.bnf +++ b/docs/generated/sql/bnf/transaction_stmt.bnf @@ -3,3 +3,6 @@ transaction_stmt ::= | commit_stmt | rollback_stmt | abort_stmt + | prepare_transaction_stmt + | commit_prepared_stmt + | rollback_prepared_stmt diff --git a/pkg/gen/bnf.bzl b/pkg/gen/bnf.bzl index f6c941eb5453..1ba81b284b4f 100644 --- a/pkg/gen/bnf.bzl +++ b/pkg/gen/bnf.bzl @@ -86,6 +86,7 @@ BNF_SRCS = [ "//docs/generated/sql/bnf:col_qualification.bnf", "//docs/generated/sql/bnf:column_table_def.bnf", "//docs/generated/sql/bnf:comment.bnf", + "//docs/generated/sql/bnf:commit_prepared_stmt.bnf", "//docs/generated/sql/bnf:commit_transaction.bnf", "//docs/generated/sql/bnf:copy_stmt.bnf", "//docs/generated/sql/bnf:copy_to_stmt.bnf", @@ -183,6 +184,7 @@ BNF_SRCS = [ "//docs/generated/sql/bnf:pause_stmt.bnf", "//docs/generated/sql/bnf:preparable_stmt.bnf", "//docs/generated/sql/bnf:prepare_stmt.bnf", + "//docs/generated/sql/bnf:prepare_transaction_stmt.bnf", "//docs/generated/sql/bnf:primary_key_column_level.bnf", "//docs/generated/sql/bnf:primary_key_table_level.bnf", "//docs/generated/sql/bnf:reassign_owned_by_stmt.bnf", @@ -204,6 +206,7 @@ BNF_SRCS = [ "//docs/generated/sql/bnf:resume_schedule.bnf", "//docs/generated/sql/bnf:resume_stmt.bnf", "//docs/generated/sql/bnf:revoke_stmt.bnf", + "//docs/generated/sql/bnf:rollback_prepared_stmt.bnf", "//docs/generated/sql/bnf:rollback_transaction.bnf", "//docs/generated/sql/bnf:routine_body_stmt.bnf", "//docs/generated/sql/bnf:routine_return_stmt.bnf", diff --git a/pkg/gen/diagrams.bzl b/pkg/gen/diagrams.bzl index b6e79cdbcc2a..585bb9c19ec1 100644 --- a/pkg/gen/diagrams.bzl +++ b/pkg/gen/diagrams.bzl @@ -86,6 +86,7 @@ DIAGRAMS_SRCS = [ "//docs/generated/sql/bnf:col_qualification.html", "//docs/generated/sql/bnf:column_table_def.html", "//docs/generated/sql/bnf:comment.html", + "//docs/generated/sql/bnf:commit_prepared.html", "//docs/generated/sql/bnf:commit_transaction.html", "//docs/generated/sql/bnf:copy.html", "//docs/generated/sql/bnf:copy_to.html", @@ -183,6 +184,7 @@ DIAGRAMS_SRCS = [ "//docs/generated/sql/bnf:pause_schedule.html", "//docs/generated/sql/bnf:preparable.html", "//docs/generated/sql/bnf:prepare.html", + "//docs/generated/sql/bnf:prepare_transaction.html", "//docs/generated/sql/bnf:primary_key_column_level.html", "//docs/generated/sql/bnf:primary_key_table_level.html", "//docs/generated/sql/bnf:reassign_owned_by.html", @@ -204,6 +206,7 @@ DIAGRAMS_SRCS = [ "//docs/generated/sql/bnf:resume_job.html", "//docs/generated/sql/bnf:resume_schedule.html", "//docs/generated/sql/bnf:revoke.html", + "//docs/generated/sql/bnf:rollback_prepared.html", "//docs/generated/sql/bnf:rollback_transaction.html", "//docs/generated/sql/bnf:routine_body.html", "//docs/generated/sql/bnf:routine_return.html", diff --git a/pkg/gen/docs.bzl b/pkg/gen/docs.bzl index 1bc6f1ce8310..075b7d78d77a 100644 --- a/pkg/gen/docs.bzl +++ b/pkg/gen/docs.bzl @@ -99,6 +99,7 @@ DOCS_SRCS = [ "//docs/generated/sql/bnf:col_qualification.bnf", "//docs/generated/sql/bnf:column_table_def.bnf", "//docs/generated/sql/bnf:comment.bnf", + "//docs/generated/sql/bnf:commit_prepared_stmt.bnf", "//docs/generated/sql/bnf:commit_transaction.bnf", "//docs/generated/sql/bnf:copy_stmt.bnf", "//docs/generated/sql/bnf:copy_to_stmt.bnf", @@ -196,6 +197,7 @@ DOCS_SRCS = [ "//docs/generated/sql/bnf:pause_stmt.bnf", "//docs/generated/sql/bnf:preparable_stmt.bnf", "//docs/generated/sql/bnf:prepare_stmt.bnf", + "//docs/generated/sql/bnf:prepare_transaction_stmt.bnf", "//docs/generated/sql/bnf:primary_key_column_level.bnf", "//docs/generated/sql/bnf:primary_key_table_level.bnf", "//docs/generated/sql/bnf:reassign_owned_by_stmt.bnf", @@ -217,6 +219,7 @@ DOCS_SRCS = [ "//docs/generated/sql/bnf:resume_schedule.bnf", "//docs/generated/sql/bnf:resume_stmt.bnf", "//docs/generated/sql/bnf:revoke_stmt.bnf", + "//docs/generated/sql/bnf:rollback_prepared_stmt.bnf", "//docs/generated/sql/bnf:rollback_transaction.bnf", "//docs/generated/sql/bnf:routine_body_stmt.bnf", "//docs/generated/sql/bnf:routine_return_stmt.bnf", diff --git a/pkg/sql/parser/help_test.go b/pkg/sql/parser/help_test.go index 21cf4d680994..8072cf6f34b9 100644 --- a/pkg/sql/parser/help_test.go +++ b/pkg/sql/parser/help_test.go @@ -158,6 +158,8 @@ func TestContextualHelp(t *testing.T) { {`CANCEL SESSIONS IF EXISTS ??`, `CANCEL SESSIONS`}, {`CANCEL ALL ??`, `CANCEL ALL JOBS`}, + {`COMMIT PREPARED 'foo' ??`, `COMMIT PREPARED`}, + {`CREATE UNIQUE ??`, `CREATE`}, {`CREATE UNIQUE INDEX ??`, `CREATE INDEX`}, {`CREATE INDEX IF NOT ??`, `CREATE INDEX`}, @@ -274,6 +276,8 @@ func TestContextualHelp(t *testing.T) { {`PREPARE foo AS DELETE FROM xx ??`, `DELETE`}, {`PREPARE foo AS UPDATE xx SET x = y ??`, `UPDATE`}, + {`PREPARE TRANSACTION 'foo' ??`, `PREPARE TRANSACTION`}, + {`EXECUTE foo ??`, `EXECUTE`}, {`EXECUTE foo (??`, `EXECUTE`}, @@ -340,6 +344,8 @@ func TestContextualHelp(t *testing.T) { {`REVOKE ALL ON foo FROM ??`, `REVOKE`}, {`REVOKE ALL ON foo FROM bar ??`, `REVOKE`}, + {`ROLLBACK PREPARED 'foo' ??`, `ROLLBACK PREPARED`}, + {`SELECT * FROM ??`, ``}, {`SELECT * FROM (??`, ``}, // not ! joins are allowed. {`SELECT * FROM [SHOW ??`, `SHOW`}, diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index 508aa82678d8..f3af8e717c73 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -1008,7 +1008,7 @@ func (u *sqlSymUnion) triggerForEach() tree.TriggerForEach { %token PARALLEL PARENT PARTIAL PARTITION PARTITIONS PASSWORD PAUSE PAUSED PER PHYSICAL PLACEMENT PLACING %token PLAN PLANS POINT POINTM POINTZ POINTZM POLYGON POLYGONM POLYGONZ POLYGONZM -%token POSITION PRECEDING PRECISION PREPARE PRESERVE PRIMARY PRIOR PRIORITY PRIVILEGES +%token POSITION PRECEDING PRECISION PREPARE PREPARED PRESERVE PRIMARY PRIOR PRIORITY PRIVILEGES %token PROCEDURAL PROCEDURE PROCEDURES PUBLIC PUBLICATION %token QUERIES QUERY QUOTE @@ -1293,6 +1293,9 @@ func (u *sqlSymUnion) triggerForEach() tree.TriggerForEach { %type abort_stmt %type rollback_stmt %type savepoint_stmt +%type prepare_transaction_stmt +%type commit_prepared_stmt +%type rollback_prepared_stmt %type preparable_set_stmt nonpreparable_set_stmt %type set_local_stmt @@ -12501,12 +12504,15 @@ savepoint_stmt: } | SAVEPOINT error // SHOW HELP: SAVEPOINT -// BEGIN / START / COMMIT / END / ROLLBACK / ... +// BEGIN / START / COMMIT / END / ROLLBACK / PREPARE TRANSACTION / COMMIT PREPARED / ROLLBACK PREPARED / ... transaction_stmt: - begin_stmt // EXTEND WITH HELP: BEGIN -| commit_stmt // EXTEND WITH HELP: COMMIT -| rollback_stmt // EXTEND WITH HELP: ROLLBACK -| abort_stmt /* SKIP DOC */ + begin_stmt // EXTEND WITH HELP: BEGIN +| commit_stmt // EXTEND WITH HELP: COMMIT +| rollback_stmt // EXTEND WITH HELP: ROLLBACK +| abort_stmt /* SKIP DOC */ +| prepare_transaction_stmt // EXTEND WITH HELP: PREPARE TRANSACTION +| commit_prepared_stmt // EXTEND WITH HELP: COMMIT PREPARED +| rollback_prepared_stmt // EXTEND WITH HELP: ROLLBACK PREPARED // %Help: BEGIN - start a transaction // %Category: Txn @@ -12692,6 +12698,36 @@ transaction_deferrable_mode: $$.val = tree.NotDeferrable } +// %Help: PREPARE TRANSACTION - prepare the current transaction for two-phase commit +// %Category: Txn +// %Text: PREPARE TRANSACTION +// %SeeAlso: COMMIT PREPARED, ROLLBACK PREPARED +prepare_transaction_stmt: + PREPARE TRANSACTION SCONST + { + $$.val = &tree.PrepareTransaction{Transaction: tree.NewStrVal($3)} + } + +// %Help: COMMIT PREPARED - commit the named transaction as part of two-phase commit +// %Category: Txn +// %Text: COMMIT PREPARED +// %SeeAlso: PREPARE TRANSACTION, ROLLBACK PREPARED +commit_prepared_stmt: + COMMIT PREPARED SCONST + { + $$.val = &tree.CommitPrepared{Transaction: tree.NewStrVal($3)} + } + +// %Help: ROLLBACK PREPARED - rollback the named transaction as part of two-phase commit +// %Category: Txn +// %Text: ROLLBACK PREPARED +// %SeeAlso: PREPARE TRANSACTION, COMMIT PREPARED +rollback_prepared_stmt: + ROLLBACK PREPARED SCONST + { + $$.val = &tree.RollbackPrepared{Transaction: tree.NewStrVal($3)} + } + // %Help: CREATE DATABASE - create a new database // %Category: DDL // %Text: CREATE DATABASE [IF NOT EXISTS] @@ -17763,6 +17799,7 @@ unreserved_keyword: | POLYGONZM | PRECEDING | PREPARE +| PREPARED | PRESERVE | PRIOR | PRIORITY @@ -18333,6 +18370,7 @@ bare_label_keywords: | POSITION | PRECEDING | PREPARE +| PREPARED | PRESERVE | PRIMARY | PRIOR diff --git a/pkg/sql/parser/testdata/two_phase_commit b/pkg/sql/parser/testdata/two_phase_commit new file mode 100644 index 000000000000..9479bc4b8f7e --- /dev/null +++ b/pkg/sql/parser/testdata/two_phase_commit @@ -0,0 +1,23 @@ +parse +PREPARE TRANSACTION 'id' +---- +PREPARE TRANSACTION 'id' +PREPARE TRANSACTION ('id') -- fully parenthesized +PREPARE TRANSACTION '_' -- literals removed +PREPARE TRANSACTION 'id' -- identifiers removed + +parse +COMMIT PREPARED 'id' +---- +COMMIT PREPARED 'id' +COMMIT PREPARED ('id') -- fully parenthesized +COMMIT PREPARED '_' -- literals removed +COMMIT PREPARED 'id' -- identifiers removed + +parse +ROLLBACK PREPARED 'id' +---- +ROLLBACK PREPARED 'id' +ROLLBACK PREPARED ('id') -- fully parenthesized +ROLLBACK PREPARED '_' -- literals removed +ROLLBACK PREPARED 'id' -- identifiers removed diff --git a/pkg/sql/sem/tree/stmt.go b/pkg/sql/sem/tree/stmt.go index a1e1929a2f23..bee96ae1c59d 100644 --- a/pkg/sql/sem/tree/stmt.go +++ b/pkg/sql/sem/tree/stmt.go @@ -819,6 +819,15 @@ func (*CommentOnType) StatementType() StatementType { return TypeDDL } // StatementTag returns a short string identifying the type of statement. func (*CommentOnType) StatementTag() string { return CommentOnTypeTag } +// StatementReturnType implements the Statement interface. +func (*CommitPrepared) StatementReturnType() StatementReturnType { return Ack } + +// StatementType implements the Statement interface. +func (*CommitPrepared) StatementType() StatementType { return TypeTCL } + +// StatementTag returns a short string identifying the type of statement. +func (*CommitPrepared) StatementTag() string { return "COMMIT PREPARED" } + // StatementReturnType implements the Statement interface. func (*CommitTransaction) StatementReturnType() StatementReturnType { return Ack } @@ -1290,6 +1299,15 @@ func (*Prepare) StatementType() StatementType { return TypeTCL } // StatementTag returns a short string identifying the type of statement. func (*Prepare) StatementTag() string { return "PREPARE" } +// StatementReturnType implements the Statement interface. +func (*PrepareTransaction) StatementReturnType() StatementReturnType { return Ack } + +// StatementType implements the Statement interface. +func (*PrepareTransaction) StatementType() StatementType { return TypeTCL } + +// StatementTag returns a short string identifying the type of statement. +func (*PrepareTransaction) StatementTag() string { return "PREPARE TRANSACTION" } + // StatementReturnType implements the Statement interface. func (*ReassignOwnedBy) StatementReturnType() StatementReturnType { return DDL } @@ -1438,6 +1456,15 @@ func (*RevokeRole) StatementType() StatementType { return TypeDCL } // StatementTag returns a short string identifying the type of statement. func (*RevokeRole) StatementTag() string { return "REVOKE" } +// StatementReturnType implements the Statement interface. +func (*RollbackPrepared) StatementReturnType() StatementReturnType { return Ack } + +// StatementType implements the Statement interface. +func (*RollbackPrepared) StatementType() StatementType { return TypeTCL } + +// StatementTag returns a short string identifying the type of statement. +func (*RollbackPrepared) StatementTag() string { return "ROLLBACK PREPARED" } + // StatementReturnType implements the Statement interface. func (*RollbackToSavepoint) StatementReturnType() StatementReturnType { return Ack } @@ -2399,6 +2426,7 @@ func (n *CommentOnSchema) String() string { return AsString( func (n *CommentOnIndex) String() string { return AsString(n) } func (n *CommentOnTable) String() string { return AsString(n) } func (n *CommentOnType) String() string { return AsString(n) } +func (n *CommitPrepared) String() string { return AsString(n) } func (n *CommitTransaction) String() string { return AsString(n) } func (n *CopyFrom) String() string { return AsString(n) } func (n *CopyTo) String() string { return AsString(n) } @@ -2447,6 +2475,7 @@ func (n *Import) String() string { return AsString( func (n *LiteralValuesClause) String() string { return AsString(n) } func (n *ParenSelect) String() string { return AsString(n) } func (n *Prepare) String() string { return AsString(n) } +func (n *PrepareTransaction) String() string { return AsString(n) } func (n *ReassignOwnedBy) String() string { return AsString(n) } func (n *ReleaseSavepoint) String() string { return AsString(n) } func (n *Relocate) String() string { return AsString(n) } @@ -2461,6 +2490,7 @@ func (n *Restore) String() string { return AsString( func (n *RoutineReturn) String() string { return AsString(n) } func (n *Revoke) String() string { return AsString(n) } func (n *RevokeRole) String() string { return AsString(n) } +func (n *RollbackPrepared) String() string { return AsString(n) } func (n *RollbackToSavepoint) String() string { return AsString(n) } func (n *RollbackTransaction) String() string { return AsString(n) } func (n *Savepoint) String() string { return AsString(n) } diff --git a/pkg/sql/sem/tree/txn.go b/pkg/sql/sem/tree/txn.go index f92f95aaa7e3..0781bd690af7 100644 --- a/pkg/sql/sem/tree/txn.go +++ b/pkg/sql/sem/tree/txn.go @@ -370,3 +370,39 @@ func (node *RollbackToSavepoint) Format(ctx *FmtCtx) { ctx.WriteString("ROLLBACK TRANSACTION TO SAVEPOINT ") ctx.FormatNode(&node.Savepoint) } + +// PrepareTransaction represents a PREPARE TRANSACTION +// statement, used for the first phase of a two-phase commit. +type PrepareTransaction struct { + Transaction *StrVal +} + +// Format implements the NodeFormatter interface. +func (node *PrepareTransaction) Format(ctx *FmtCtx) { + ctx.WriteString("PREPARE TRANSACTION ") + ctx.FormatNode(node.Transaction) +} + +// CommitPrepared represents a COMMIT PREPARED statement, used +// for the second phase of a two-phase commit. +type CommitPrepared struct { + Transaction *StrVal +} + +// Format implements the NodeFormatter interface. +func (node *CommitPrepared) Format(ctx *FmtCtx) { + ctx.WriteString("COMMIT PREPARED ") + ctx.FormatNode(node.Transaction) +} + +// RollbackPrepared represents a ROLLBACK PREPARED statement, +// used for the second phase of a two-phase rollback. +type RollbackPrepared struct { + Transaction *StrVal +} + +// Format implements the NodeFormatter interface. +func (node *RollbackPrepared) Format(ctx *FmtCtx) { + ctx.WriteString("ROLLBACK PREPARED ") + ctx.FormatNode(node.Transaction) +}