diff --git a/src/cst/Transaction.ts b/src/cst/Transaction.ts index 187bcaaf..d6c3cc82 100644 --- a/src/cst/Transaction.ts +++ b/src/cst/Transaction.ts @@ -1,11 +1,12 @@ import { BaseNode, Keyword } from "./Base"; -import { Identifier } from "./Expr"; +import { Identifier, ListExpr } from "./Expr"; export type AllTransactionNodes = | AllTransactionStatements | RollbackToSavepoint | TransactionChainClause - | TransactionNoChainClause; + | TransactionNoChainClause + | TransactionMode; export type AllTransactionStatements = | StartTransactionStmt @@ -19,6 +20,44 @@ export interface StartTransactionStmt extends BaseNode { startKw: Keyword<"START" | "BEGIN">; behaviorKw?: Keyword<"DEFERRED" | "IMMEDIATE" | "EXCLUSIVE">; transactionKw?: Keyword<"TRANSACTION" | "WORK">; + modes?: ListExpr; +} + +type TransactionMode = + | TransactionModeDeferrable + | TransactionModeNotDeferrable + | TransactionModeReadWrite + | TransactionModeReadOnly + | TransactionModeIsolationLevel; + +export interface TransactionModeDeferrable extends BaseNode { + type: "transaction_mode_deferrable"; + deferrableKw: Keyword<"DEFERRABLE">; +} + +export interface TransactionModeNotDeferrable extends BaseNode { + type: "transaction_mode_not_deferrable"; + notDeferrableKw: [Keyword<"NOT">, Keyword<"DEFERRABLE">]; +} + +export interface TransactionModeReadWrite extends BaseNode { + type: "transaction_mode_read_write"; + readWriteKw: [Keyword<"READ">, Keyword<"WRITE">]; +} + +export interface TransactionModeReadOnly extends BaseNode { + type: "transaction_mode_read_only"; + readOnlyKw: [Keyword<"READ">, Keyword<"ONLY">]; +} + +export interface TransactionModeIsolationLevel extends BaseNode { + type: "transaction_mode_isolation_level"; + isolationLevelKw: [Keyword<"ISOLATION">, Keyword<"LEVEL">]; + levelKw: + | Keyword<"SERIALIZABLE"> + | [Keyword<"REPEATABLE">, Keyword<"READ">] + | [Keyword<"READ">, Keyword<"COMMITTED">] + | [Keyword<"READ">, Keyword<"UNCOMMITTED">]; } export interface CommitTransactionStmt extends BaseNode { diff --git a/src/parser.pegjs b/src/parser.pegjs index b7c3d71d..74886e9f 100644 --- a/src/parser.pegjs +++ b/src/parser.pegjs @@ -4688,11 +4688,12 @@ start_transaction_stmt transactionKw: read(tKw), }); } - / &postgres kw:BEGIN tKw:(__ (TRANSACTION / WORK))? { + / &postgres kw:BEGIN tKw:(__ (TRANSACTION / WORK))? modes:(__ list$transaction_mode)? { return loc({ type: "start_transaction_stmt", startKw: kw, transactionKw: read(tKw), + modes: read(modes), }); } / &mysql kw:BEGIN tKw:(__ WORK)? { @@ -4702,14 +4703,57 @@ start_transaction_stmt transactionKw: read(tKw), }); } - / (&mysql / &postgres) kw:START tKw:(__ TRANSACTION) { + / (&mysql / &postgres) kw:START tKw:(__ TRANSACTION) modes:(__ list$transaction_mode)? { return loc({ type: "start_transaction_stmt", startKw: kw, transactionKw: read(tKw), + modes: read(modes), }); } +transaction_mode + = transaction_mode_deferrable + / transaction_mode_not_deferrable + / transaction_mode_read_write + / transaction_mode_read_only + / transaction_mode_isolation_level + +transaction_mode_deferrable + = kw:(DEFERRABLE) { + return loc({ type: "transaction_mode_deferrable", deferrableKw: kw }); + } + +transaction_mode_not_deferrable + = kw:(NOT __ DEFERRABLE) { + return loc({ type: "transaction_mode_not_deferrable", notDeferrableKw: read(kw) }); + } + +transaction_mode_read_write + = kw:(READ __ WRITE) { + return loc({ type: "transaction_mode_read_write", readWriteKw: read(kw) }); + } + +transaction_mode_read_only + = kw:(READ __ ONLY) { + return loc({ type: "transaction_mode_read_only", readOnlyKw: read(kw) }); + } + +transaction_mode_isolation_level + = kw:(ISOLATION __ LEVEL __) levelKw:isolation_level_kw { + return loc({ + type: "transaction_mode_isolation_level", + isolationLevelKw: read(kw), + levelKw: read(levelKw), + }); + } + +isolation_level_kw + = SERIALIZABLE + / REPEATABLE __ READ + / READ __ COMMITTED + / READ __ UNCOMMITTED + commit_transaction_stmt = kw:commit_kw tKw:(__ transaction_kw)? chain:(__ transaction_chain_clause)? { return loc({ @@ -7616,6 +7660,7 @@ list$string_literal = . list$table_func_call = . list$table_option_postgresql = . list$tablesample_arg = . +list$transaction_mode = . list$transform_type = . list$trigger_transition = . list$type_param = . @@ -8629,6 +8674,7 @@ COLUMNS = kw:"COLUMNS"i !ident_part { return loc(createK COMMENT = kw:"COMMENT"i !ident_part { return loc(createKeyword(kw)); } COMMENTS = kw:"COMMENTS"i !ident_part { return loc(createKeyword(kw)); } COMMIT = kw:"COMMIT"i !ident_part { return loc(createKeyword(kw)); } +COMMITTED = kw:"COMMITTED"i !ident_part { return loc(createKeyword(kw)); } COMPACT = kw:"COMPACT"i !ident_part { return loc(createKeyword(kw)); } COMPRESSED = kw:"COMPRESSED"i !ident_part { return loc(createKeyword(kw)); } COMPRESSION = kw:"COMPRESSION"i !ident_part { return loc(createKeyword(kw)); } @@ -8813,6 +8859,7 @@ INVOKER = kw:"INVOKER"i !ident_part { return loc(createK IS = kw:"IS"i !ident_part { return loc(createKeyword(kw)); } ISNULL = kw:"ISNULL" !ident_part { return loc(createKeyword(kw)); } ISODOW = kw:"ISODOW"i !ident_part { return loc(createKeyword(kw)); } +ISOLATION = kw:"ISOLATION"i !ident_part { return loc(createKeyword(kw)); } ISOWEEK = kw:"ISOWEEK"i !ident_part { return loc(createKeyword(kw)); } ISOYEAR = kw:"ISOYEAR"i !ident_part { return loc(createKeyword(kw)); } ITERATE = kw:"ITERATE"i !ident_part { return loc(createKeyword(kw)); } @@ -9028,6 +9075,7 @@ SECURITY = kw:"SECURITY"i !ident_part { return loc(createK SELECT = kw:"SELECT"i !ident_part { return loc(createKeyword(kw)); } SEQUENCE = kw:"SEQUENCE"i !ident_part { return loc(createKeyword(kw)); } SEQUENCES = kw:"SEQUENCES"i !ident_part { return loc(createKeyword(kw)); } +SERIALIZABLE = kw:"SERIALIZABLE"i !ident_part { return loc(createKeyword(kw)); } SERVER = kw:"SERVER"i !ident_part { return loc(createKeyword(kw)); } SESSION = kw:"SESSION"i !ident_part { return loc(createKeyword(kw)); } SESSION_USER = kw:"SESSION_USER"i !ident_part { return loc(createKeyword(kw)); } @@ -9107,6 +9155,7 @@ TUESDAY = kw:"TUESDAY"i !ident_part { return loc(createK TYPE = kw:"TYPE"i !ident_part { return loc(createKeyword(kw)); } UESCAPE = kw:"UESCAPE"i !ident_part { return loc(createKeyword(kw)); } UNBOUNDED = kw:"UNBOUNDED"i !ident_part { return loc(createKeyword(kw)); } +UNCOMMITTED = kw:"UNCOMMITTED"i !ident_part { return loc(createKeyword(kw)); } UNDEFINED = kw:"UNDEFINED"i !ident_part { return loc(createKeyword(kw)); } UNION = kw:"UNION"i !ident_part { return loc(createKeyword(kw)); } UNIQUE = kw:"UNIQUE"i !ident_part { return loc(createKeyword(kw)); } diff --git a/src/showNode/transaction.ts b/src/showNode/transaction.ts index b54a815a..c0ba3470 100644 --- a/src/showNode/transaction.ts +++ b/src/showNode/transaction.ts @@ -4,7 +4,7 @@ import { FullTransformMap } from "../cstTransformer"; export const transactionMap: FullTransformMap = { start_transaction_stmt: (node) => - show([node.startKw, node.behaviorKw, node.transactionKw]), + show([node.startKw, node.behaviorKw, node.transactionKw, node.modes]), commit_transaction_stmt: (node) => show([node.commitKw, node.transactionKw, node.chain]), rollback_transaction_stmt: (node) => @@ -16,4 +16,10 @@ export const transactionMap: FullTransformMap = { show([node.releaseKw, node.savepointKw, node.savepoint]), transaction_chain_clause: (node) => show([node.andChainKw]), transaction_no_chain_clause: (node) => show([node.andNoChainKw]), + transaction_mode_deferrable: (node) => show([node.deferrableKw]), + transaction_mode_not_deferrable: (node) => show([node.notDeferrableKw]), + transaction_mode_read_write: (node) => show([node.readWriteKw]), + transaction_mode_read_only: (node) => show([node.readOnlyKw]), + transaction_mode_isolation_level: (node) => + show([node.isolationLevelKw, node.levelKw]), }; diff --git a/test/transactions.test.ts b/test/transactions.test.ts index e990fb7c..6d40be79 100644 --- a/test/transactions.test.ts +++ b/test/transactions.test.ts @@ -32,6 +32,29 @@ describe("transactions", () => { testWc("BEGIN WORK"); }); }); + + dialect("postgresql", () => { + it("supports [NOT] DEFERRABLE", () => { + testWc("BEGIN NOT DEFERRABLE"); + testWc("BEGIN DEFERRABLE"); + }); + + it("supports READ {WRITE | ONLY}", () => { + testWc("BEGIN READ WRITE"); + testWc("BEGIN READ ONLY"); + }); + + it("supports ISOLATION LEVEL", () => { + testWc("BEGIN ISOLATION LEVEL SERIALIZABLE"); + testWc("BEGIN ISOLATION LEVEL REPEATABLE READ"); + testWc("BEGIN ISOLATION LEVEL READ COMMITTED"); + testWc("BEGIN ISOLATION LEVEL READ UNCOMMITTED"); + }); + + it("supports multiple transaction modes", () => { + testWc("BEGIN READ ONLY, ISOLATION LEVEL SERIALIZABLE, DEFERRABLE"); + }); + }); }); describe("committing transaction", () => {