Repository navigation
Conversation
PostgreSQL cursor statements failed to parse: DECLARE took only the SQL Server DECLARE @variable, and FETCH, MOVE and CLOSE started no statement, so scripts that page through a query with a cursor failed. Add the statement.cursor package. DeclareCursorStatement keeps the cursor options in their order (CursorOption), the holdability and the query. FetchCursorStatement covers FETCH and MOVE with an optional FetchDirection keyword, a signed 32-bit count or ALL, and FROM or IN. CloseCursorStatement covers CLOSE name and CLOSE ALL. As in PostgreSQL's grammar, a direction word that ends the statement names the cursor, and reserved words name none. Dialect.POSTGRESQL reads these statements. Without a dialect they parse when they take the PostgreSQL form, so other products' FETCH ... INTO stays an unsupported statement. Other dialects and DECLARE @variable are unchanged. MOVE becomes a non-reserved keyword. Wire the statements into the deparser, visitors, table finder, validation (declareCursor, fetchCursor, closeCursor) and feature analysis. 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
PostgreSQL scripts and statement logs that page through a query with a cursor fail to parse. On
master(12548b9da) every cursor statement fails withDialect.POSTGRESQLand without a dialect, for example:DECLARE c CURSOR FOR SELECT * FROM t,DECLARE c BINARY INSENSITIVE NO SCROLL CURSOR WITH HOLD FOR SELECT 1,DECLARE c CURSOR FOR VALUES (1), (2),DECLARE c CURSOR FOR TABLE tFETCH NEXT FROM c,FETCH ABSOLUTE -1 FROM c,FETCH FORWARD 10 IN c,FETCH ALL c,FETCH 5 FROM cMOVE ABSOLUTE 2 IN c,MOVE BACKWARD ALL FROM cCLOSE c,CLOSE ALLPostgreSQL 18 references: DECLARE, FETCH, MOVE, CLOSE.
Current design (As-is)
DECLAREparses only SQL Server'sDECLARE @variable …(DeclareStatement, withDeclareTypeTYPE,TABLEandAS), soDECLARE c CURSOR …fails at the name. WithDialect.ORACLE,DECLAREstarts a PL/SQL block.FETCHis a reserved keyword used only bySELECT … FETCH {FIRST | NEXT} n ROWS ONLY.CLOSEis a non-reserved keyword used by Oracle'sALTER SESSION CLOSE DATABASE LINK.MOVEis a plain identifier. None of them starts a statement: they fail, or become anUnsupportedStatementwithallowUnsupportedStatements.Target design (To-be)
A new package
net.sf.jsqlparser.statement.cursorholds the statements, following PostgreSQL 18'sDeclareCursorStmt,FetchStmtandClosePortalStmt.DeclareStatementkeeps its API and its reading.DECLARE name [BINARY] [ASENSITIVE | INSENSITIVE] [[NO] SCROLL] CURSOR [{WITH | WITHOUT} HOLD] FOR queryparses toDeclareCursorStatement.getOptions()lists theCursorOptionvalues (BINARY,ASENSITIVE,INSENSITIVE,SCROLL,NO_SCROLL) in their order. PostgreSQL'scursor_optionstakes them in any order and repeated, and the server rejects contradicting ones such asSCROLL NO SCROLLwhen it runs the statement, so the parser accepts them as the grammar does.getHoldability()isWITH_HOLD,WITHOUT_HOLDor null.getQuery()is theSelectread by the sharedSelect()production: a SELECT,VALUES,TABLE t, a set operation, a parenthesized query or a query withWITH.INSERT,UPDATEandDELETEare rejected, as in PostgreSQL.{FETCH | MOVE} [direction] [FROM | IN] cursorparses toFetchCursorStatement, whosegetKind()isFETCHorMOVE(PostgreSQL'sFetchStmtcovers both).FetchDirectionkeyword (NEXT,PRIOR,FIRST,LAST,ABSOLUTE,RELATIVE,FORWARD,BACKWARD) withgetCount()orisAll().ABSOLUTEandRELATIVEtake a count,FORWARDandBACKWARDan optional count orALL, and a count orALLcan stand alone;FetchDirection.isCountRequired()andisCountOptional()describe this. Every direction may omitFROM/IN, whichgetFromKeyword()keeps.SignedIconst: a signed 32-bit integer.FETCH ABSOLUTE 2147483648 FROM cis rejected, as PostgreSQL reads that number as a numeric constant.FETCH nextfetches from a cursor namednext, whileFETCH NEXT nextuses theNEXTdirection.CLOSE {name | ALL}parses toCloseCursorStatement;isAll()is true when it has no cursor name.ColId: a name, but not one of PostgreSQL's reserved words or type and function name keywords, soCLOSE tableandDECLARE binary CURSOR …are rejected. It is not qualified.Dialect.POSTGRESQLreadsFETCH,MOVE,CLOSE, andDECLAREfollowed by a name, as cursor statements.DECLAREneeds a name, the cursor options andCURSOR, andFETCH,MOVEandCLOSEmust end at a semicolon or the end of the input. The forms are the SQL standard's or PostgreSQL's own, and no other reading of them exists, while other products' variants such as SQL Server'sFETCH NEXT FROM c INTO @xandCLOSE GLOBAL cremain unsupported statements.DECLARE @x INTstill parses toDeclareStatementin every dialect that read it before.MOVEbecomes a non-reserved keyword, as a statement must start with a token; it remains usable as a name, as doCLOSE,CURSORand the option and direction words.SELECT … FETCH FIRST,OFFSET … FETCH NEXTand Oracle'sALTER SESSION CLOSE DATABASE LINKkeep their readings.Declare(), andisStatementStartAhead()listsFETCH,MOVEandCLOSE, so they end at the statement boundary in scripts and after an unsupported statement.toString()andStatementDeParsershareappendTo; the query ofDECLAREis rendered through theSelectDeParser.StatementVisitorhas default methods for the three statements, andStatementVisitorAdaptervisits the query ofDECLARE.TablesNamesFinderreports the tables of the query ofDECLARE, without itsWITHnames, and none forFETCH,MOVEandCLOSE, whose cursor name is not a table.declareCursor,fetchCursor(FETCHandMOVE) andcloseCursor, enabled by the PostgreSQL capabilities; the query ofDECLAREis validated like a SELECT.MODIFIES_SESSIONfor all of them,READS_DATAfor aDECLAREwhose query reads a table,RETURNS_RESULT_SETforFETCH, and a possibleREADS_DATAforFETCHandMOVE, which run the query of the cursor.ASTNodeCoverageTestwalks them.Featureconstants.Validation
PostgreSqlCursorTest135 andCursorValidatorTest4;ASTNodeCoverageTestwalks the new forms. They fail onmaster.toString(),StatementDeParserand reparse withDialect.POSTGRESQLand without a dialect, and the AST fields (options, holdability, query class, kind, direction, count,ALL,FROM/IN, cursor name). Signs, leading zeros, digit separators and keyword case are normalized.DECLARE,FETCH,MOVEandCLOSE,SENSITIVEorHOLDas options, options afterCURSOR,WITHOUT HOLD WITH HOLD,DECLARE … FOR INSERT/UPDATE/DELETE,NEXT 5,PRIOR ALL,ABSOLUTEwithout a count,RELATIVE ALL,1.5, counts outside 32 bits,INTO, two cursors, qualified names, reserved words as names,CLOSE ALL c.DECLARE @x …in SQL Server, PostgreSQL and without a dialect; SQL Server, MySQL, MariaDB, Oracle, H2 and CockroachDB reject the new forms, andFETCH/MOVE/CLOSEthere remain unsupported statements; other products' variants remain unsupported statements without a dialect;SELECT … FETCH FIRST,ALTER SESSION CLOSE DATABASE LINKandmove,close,cursorand the option and direction words as names.masterrejects. Some fail only when run, for examplecursor "c" does not exist,DECLARE CURSOR can only be used in transaction blocksorcannot specify both SCROLL and NO SCROLL. It reports a syntax error for all 53 statements the tests reject, includingFETCH ABSOLUTE 2147483648 c.spotlessApply cleanTest check jar: 12,928 tests, 12,903 passed, 25 skipped, zero failures/errors. The grammar choice conflict check, Checkstyle, PMD and SpotBugs pass.master(12548b9da) on a corpus of 188 MySQL 8.4 and 166 PostgreSQL 18 statements other than DDL/DCL, each accepted by the server, with the MySQL or PostgreSQL dialect and without a dialect:Dialect.POSTGRESQLand without a dialect:DECLARE c BINARY INSENSITIVE NO SCROLL CURSOR WITH HOLD FOR SELECT 1,FETCH NEXT FROM c,FETCH FORWARD 10 IN c,FETCH ALL c,MOVE ABSOLUTE 2 IN candCLOSE ALL.master(12548b9da) on a corpus of 635 MySQL 8.4 and PostgreSQL 18 DDL/DCL statements, each accepted by the server, plus variants, scripts and the keyword sweeps (includingmove,closeanddeclareas names): 0 regressed, 0 changed.AI assistance: prepared with Claude Code.