Repository navigation
Conversation
…greSQL END and ABORT MySQL SET [scope] TRANSACTION, PostgreSQL SET [scope] TRANSACTION, SET TRANSACTION SNAPSHOT, SET SESSION CHARACTERISTICS AS TRANSACTION, SET CONSTRAINTS, MySQL COMMIT/ROLLBACK ... [NO] RELEASE and PostgreSQL END and ABORT failed to parse; SET CONSTRAINTS c1, c2 IMMEDIATE was read as two variable assignments. Move the transaction characteristics to a top-level TransactionMode enum, parsed by one TransactionModeList production whose context (BEGIN, START TRANSACTION, SET TRANSACTION) selects the dialect rules. Add SetTransactionStatement and SetConstraintsStatement, dispatched before the generic SET, which keeps variable assignments. They reuse TransactionMode, a new SetScope enum that also types the scope of SetStatement, and ConstraintAttributes.Initially. SET TRANSACTION takes the scopes of each server's grammar: GLOBAL, SESSION, LOCAL, PERSIST and PERSIST_ONLY in MySQL, the first three in MariaDB, and SESSION and LOCAL in PostgreSQL, where they also precede SNAPSHOT and SESSION CHARACTERISTICS. Commit and RollbackStatement share TransactionCompletionStatement for the keyword, chain and the new TransactionRelease, and record the END and ABORT spellings in Command enums. END is a statement only with the PostgreSQL dialect and outside BEGIN ... END blocks. The new statements and TransactionCompletionStatement extend ASTNodeAccessImpl, so each parsed statement keeps the node spanning its source. Wire the statements into the deparser, visitors, table finder, feature analysis and validation, adding the rollback and savepoint features and the MySQL and PostgreSQL capabilities. Signed-off-by: minleejae <mmj9808@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Applications and replication tools send transaction control statements that JSqlParser cannot parse today:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED,SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ ONLY,SET GLOBAL TRANSACTION READ ONLY,SET LOCAL TRANSACTION READ ONLY,SET PERSIST TRANSACTION READ ONLYandSET PERSIST_ONLY TRANSACTION ISOLATION LEVEL READ COMMITTED;SET TRANSACTION ISOLATION LEVEL …,SET LOCAL TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY,SET TRANSACTION SNAPSHOT '00000003-0000001B-1',SET SESSION TRANSACTION SNAPSHOT '…',SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY,SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLEandSET LOCAL SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;COMMIT AND NO CHAIN NO RELEASE,COMMIT RELEASEandROLLBACK WORK AND CHAIN NO RELEASE;ENDandABORT(END WORK AND CHAIN,ABORT TRANSACTION);SET CONSTRAINTS ALL DEFERRED.SET CONSTRAINTS c1, c2 IMMEDIATEparses, but as the two variable assignmentsCONSTRAINTS = c1andc2 = IMMEDIATE.References: MySQL 8.4 SET TRANSACTION, SET for variable assignment (its scope keywords) and START TRANSACTION, COMMIT and ROLLBACK; MariaDB SET TRANSACTION; PostgreSQL 18 SET TRANSACTION, SET (
SESSIONandLOCAL), SET CONSTRAINTS, END and ABORT.The pages document fewer scopes than the servers accept. The MySQL 8.4 grammar takes every scope of
SETassignments beforeTRANSACTION(GLOBAL,SESSION,LOCAL,PERSIST,PERSIST_ONLY), MariaDB's takesGLOBAL,SESSIONandLOCAL, and PostgreSQL'sSET [SESSION | LOCAL]prefix applies toTRANSACTION,TRANSACTION SNAPSHOTandSESSION CHARACTERISTICS AS TRANSACTIONalike. The parser follows the grammars.Current design (As-is)
StartTransaction.Mode(Support typed transaction starts, chaining and savepoint release #2729) holds the characteristics ofBEGINandSTART TRANSACTION.TransactionMode()raises errors that only hold forSTART TRANSACTION, such as "MySQL START TRANSACTION does not accept ISOLATION LEVEL"; in MySQLSET TRANSACTIONthe isolation level is the main clause.READ ONLY+READ WRITEcheck sit inline inStartTransaction(), so another statement cannot reuse the list.StatementValidatormaps the modes to features in a switch that onlyStartTransactioncan use.SETthat is not a SQL Server option or a MySQLSET ROLE,SET DEFAULT ROLEorSET PASSWORDgoes toSetStatement.SET TRANSACTION …fails, becauseTRANSACTIONis read as a variable name.SetStatement.effectParameteris a rawString(LOCALorSESSIONas written), andSetStatement.NameExpris package-private although the publicgetKeyValuePairs()returns it.CommitandRollbackStatementeach holdTransactionKeywordandTransactionChainand render them with their own code. There is no[NO] RELEASE, and no spelling other thanCOMMITandROLLBACK.ENDclosesBEGIN … ENDblocks andCASEexpressions; it never starts a statement.ABORTis not a statement.RollbackStatementchecks onlytransactionChain, andSavepointStatementchecks nothing (a TODO).Target design (To-be)
TransactionMode: a top-level enum replacesStartTransaction.Mode, withisIsolationLevel(),isAccessMode()andisDeferrability().StartTransaction.Modecame with Support typed transaction starts, chaining and savepoint release #2729 (merged 2026-09-28); the latest release, 5.4, is from 2026-09-13 and nothing has been released since, so replacing it does not break a released API.TransactionModeList(modes, context)production parses the list forBEGIN,START TRANSACTIONandSET TRANSACTION(TransactionMode.Context).TransactionMode()itself has no dialect checks.BEGINtakes no modes, MySQLSTART TRANSACTIONno isolation level and not both access modes, MySQLSET TRANSACTIONone isolation level and one access mode, MySQL neverDEFERRABLE; onlySTART TRANSACTIONtakesWITH CONSISTENT SNAPSHOT, and PostgreSQL never.SET TRANSACTIONthe isolation level is not a separate feature.SetTransactionStatementforSET [scope] TRANSACTION modes,SET [scope] SESSION CHARACTERISTICS AS TRANSACTION modesandSET [scope] TRANSACTION SNAPSHOT 'id':getScope()returns the scope keyword written afterSETas the newSetScopeenum (NONE,GLOBAL,SESSION,LOCAL,PERSIST,PERSIST_ONLY), shared withSetStatement.isSessionCharacteristics()marks the PostgreSQL form independently of the scope, soSET SESSION CHARACTERISTICS …(scopeNONE),SET LOCAL SESSION CHARACTERISTICS …andSET SESSION SESSION CHARACTERISTICS …each print back as written.getModes()is theTransactionModelist, andgetSnapshotId()aStringValue.Dialect rules, following each server's grammar:
SET [scope] TRANSACTION modesGLOBAL,SESSION,LOCAL,PERSIST,PERSIST_ONLYGLOBAL,SESSION,LOCALSESSION,LOCALSET [scope] TRANSACTION SNAPSHOT 'id'SESSION,LOCALSESSION,LOCALSET [scope] SESSION CHARACTERISTICS AS TRANSACTION modesSESSION,LOCALSESSION,LOCALSESSION CHARACTERISTICSnever takesSNAPSHOT. MySQL and MariaDB also require commas and at most one isolation level and one access mode.SetConstraintsStatementforSET CONSTRAINTS {ALL | name [, …]} {DEFERRED | IMMEDIATE}:getConstraintNames()keeps each name as written (qualified, quoted); an empty list meansALL(isAll()).getTiming()reusesConstraintAttributes.Initially, the enum ofINITIALLY DEFERRED | IMMEDIATE.SingleStatementbeforeSet(), after the MySQLSET ROLE,SET DEFAULT ROLEandSET PASSWORDchecks, by token checks.SET [scope] TRANSACTIONneeds a mode orSNAPSHOT 'id'after it, andSET CONSTRAINTSno=,:=orTO, so assignments such asSET transaction_isolation = 'READ-COMMITTED',SET PERSIST transaction_isolation = 'READ-COMMITTED',SET LOCAL transaction = 1,SET SESSION work_mem TO DEFAULT,SET @@SESSION.sql_mode = …andSET LOCAL statement_timeout = '5s'remainSetStatement.SetStatement:getScope()/setScope()type the scope.getEffectParameter()andsetEffectParameter(String)remain, derived from the scope.NameExpris public, withgetAssignmentOperator()/setAssignmentOperator().TablesNamesFinderkeeps finding tables inSETvalues (fix: find tables in SET values instead of throwing #2873).TransactionCompletionStatement, which holdskeyword,chainand the newTransactionRelease(RELEASE,NO_RELEASE) and renders them once.TransactionCompletionStatementextendsASTNodeAccessImpl, soCommitandRollbackStatementkeep the AST node fix: give every parsed object a node spanning its source #2870 gave them.Commit.Command(COMMIT,END) andRollbackStatement.Command(ROLLBACK,ABORT) record the spelling, mirroringStartTransaction.Command, so consumers see one model per completion;isPostgresSpelling()reportsENDandABORT.[NO] RELEASEfollows the chain;AND CHAIN RELEASE,RELEASEafterTO SAVEPOINT, andRELEASEin PostgreSQL are rejected.RELEASE SAVEPOINT spandRELEASE spremain separate statements.END [WORK | TRANSACTION] [AND [NO] CHAIN]is a statement only with the PostgreSQL dialect, at the start of a statement, likeisBeginTransactionAhead. The statement list of aBEGIN … ENDblock stops atENDfirst, so blocks,CASE … END,IF … BEGIN … END ELSEandBEGIN ATOMIC … ENDbodies keep their reading.ABORT [WORK | TRANSACTION] [AND [NO] CHAIN]is read with the PostgreSQL dialect and without a dialect. It is not a token, soabortstays an identifier; a JAVACODE production consumes it, so identifiers do not join the tokens that can start or end a statement.isStatementStartAheadlists both, so they end a preceding statement and are not captured as unsupported statements.SetTransactionStatementandSetConstraintsStatementextendASTNodeAccessImpl. Like every statement, they get the nodeSingleStatementlinks, from the first token to the last; the snapshotStringValuegets the node of its literal.rollback,savepoint,setTransaction,setTransactionGlobal,setTransactionPersist(PERSISTandPERSIST_ONLY),setTransactionSessionCharacteristics,setTransactionSnapshot,setConstraints,transactionReleaseandtransactionEndAbort.LOCALandSESSIONneed no feature, since MySQL and PostgreSQL both accept them.ROLLBACKchecksrollback, andSAVEPOINTandROLLBACK TOchecksavepoint. Both are added to every capability set that hascommit(savepointnot for SQL Server, which usesSAVE TRANSACTION).setTransaction,setTransactionGlobal,setTransactionPersistandtransactionRelease; PostgreSQL 10 addssetTransaction,setTransactionSessionCharacteristics,setTransactionSnapshot,setConstraintsandtransactionEndAbort.StatementVisitor(default methods),StatementVisitorAdapter,StatementDeParser,TablesNamesFinder(no tables),StatementFeatureVisitor(MODIFIES_TRANSACTION) andusage.rst.StartTransaction.getModes()now returnsList<TransactionMode>;StartTransaction.Modeis gone. It was added by Support typed transaction starts, chaining and savepoint release #2729 after the 5.4 release and is in no release.SetStatementrenders the scope keyword in upper case (set local x = 1becomesSET LOCAL x = 1), andsetEffectParameterrejects a word that is not aSetScopewithIllegalArgumentException.CommitandRollbackStatementkeep their getters, setters and fluent methods; the shared ones moved to the superclass, which also carries their AST node.SET CONSTRAINTS c1, c2 IMMEDIATEis now aSetConstraintsStatement, not aSetStatement, in every dialect but MySQL and MariaDB, where it is rejected.H2Versioncapability list is reformatted byspotlessApplybecause the file is touched; onlyrollbackandsavepointare added.usage.rstdocuments the statements, the shared models and the validator features.Validation
TransactionStatementTest(54 new):[NO] RELEASEwith and withoutAND [NO] CHAIN, AST fields, and rejectedAND CHAIN RELEASE,RELEASEafterTO SAVEPOINTand PostgreSQLRELEASE;END/ABORTwithWORK/TRANSACTIONand chains,ABORTwithout a dialect, rejection in MySQL, MariaDB, Oracle and SQL Server, andEND TO SAVEPOINT,ABORT TO spandEND garbage;BEGIN … ENDblocks with every dialect,CASE … END,IF … BEGIN … END ELSE,BEGIN ATOMIC … END, andabort/endas identifiers;END,ABORT,COMMIT … RELEASE,ROLLBACK RELEASE, theSET … TRANSACTIONforms with and without a scope,SET CONSTRAINTS) ends a precedingCOMMITwithout a semicolon, with and without unsupported-statement capture, and both statements' AST nodes span exactly their own text;rollback,savepoint,transactionReleaseandtransactionEndAbort.SetTransactionStatementTest(67): the MySQL forms withDialect.MYSQL,Dialect.MARIADBand no dialect; every scope in every dialect (LOCAL,SESSION,GLOBAL,PERSIST,PERSIST_ONLY), accepted or rejected as in the table above; PostgreSQL characteristics with spaces or commas,SESSION CHARACTERISTICSwith no scope,SESSIONorLOCAL, andSNAPSHOTwith no scope,SESSIONorLOCAL; combinations that no server accepts (SET GLOBAL TRANSACTION SNAPSHOT 'x',SET PERSIST SESSION CHARACTERISTICS AS TRANSACTION READ ONLY,SESSION CHARACTERISTICS … SNAPSHOT); parse, AST node range (the statement and the snapshot literal),toString, deparser, reparse, AST fields, feature analysis and table finder; MySQL- and PostgreSQL-only forms rejected in the other dialect; malformed forms; variable assignments that staySetStatement, includingSET PERSIST transaction_isolation = …,SET LOCAL transaction = 1and the other scopes; edits; visitors, boundaries and validation.SetConstraintsStatementTest(13):ALLand named, qualified and quoted constraints with PostgreSQL, Oracle and no dialect, each with its AST node range; the former assignment reading; rejected forms and MySQL; edits; visitors, boundaries and validation.SetStatementTest(2): the typed scope behindgetEffectParameter()/setEffectParameter(), and the publicNameExpr.TransactionStatementTestalso checks that every transaction statement it parses (including the existingBEGIN,START TRANSACTION,SAVEPOINTandRELEASEforms) has a node spanning its whole text.spotlessApply cleanTest check jar: 12,568 tests, 12,543 passed, 25 skipped, zero failures/errors.ASTNodeCoverageTestpasses; a one-off run of its coverage walk over scripts of every new form, in the PostgreSQL, MySQL and default dialects, reported no problem. The grammar choice conflict check, Checkstyle, PMD, SpotBugs and JaCoCo pass.SET … TRANSACTION,SET CONSTRAINTS,COMMIT/ROLLBACK … [NO] RELEASE,ENDandABORTforms were run against MySQL 8.4.11 and PostgreSQL 18: every form the parser accepts in a dialect is accepted by that server's grammar, and every form it rejects in a dialect is a syntax error on that server. The one exception isSET TRANSACTION SNAPSHOTwithout an identifier, which PostgreSQL rejects but which still parses as aSetStatementassignment, as on master. The MariaDB rules follow MariaDB's grammar (option_typeisGLOBAL | LOCAL | SESSION).master(7123d25a1) on a corpus of MySQL 8.4 and PostgreSQL 18 non-DDL statements, each accepted by the server:Dialect.MYSQLand without a dialect:COMMIT AND NO CHAIN NO RELEASE,SET TRANSACTION ISOLATION LEVEL READ COMMITTED,SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ ONLYandSET GLOBAL TRANSACTION READ WRITE.Dialect.POSTGRESQL:END,ABORT,SET TRANSACTION ISOLATION LEVEL READ COMMITTED,SET TRANSACTION SNAPSHOT '00000003-0000001B-1',SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLYandSET CONSTRAINTS ALL DEFERRED; the same without a dialect exceptEND, which stays rejected there.SET CONSTRAINTS c1, c2 IMMEDIATEis now aSetConstraintsStatementinstead of two assignments, withDialect.POSTGRESQLand without a dialect.SET GLOBAL TRANSACTION READ ONLY,SET LOCAL TRANSACTION READ ONLY,SET PERSIST TRANSACTION READ ONLYandSET PERSIST_ONLY TRANSACTION ISOLATION LEVEL READ COMMITTED(MySQL),SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE,SET LOCAL SESSION CHARACTERISTICS AS TRANSACTION READ ONLYandSET SESSION TRANSACTION SNAPSHOT '…'(PostgreSQL),ROLLBACK WORK AND CHAIN NO RELEASE(MySQL) andCOMMIT RELEASE(MariaDB) fail onmasterand parse here;PREPARE TRANSACTION,COMMIT PREPAREDandXAstill fail, as before.PREPARE TRANSACTION,COMMIT PREPARED/ROLLBACK PREPAREDand MySQLXAstatements.AI assistance: prepared with Claude Code.