Repository navigation
feat: parse PostgreSQL SELECT INTO persistence, JOIN USING alias, AT LOCAL, IS NORMALIZED and XMLATTRIBUTES - #2914
Open
minleejae wants to merge 1 commit into
Conversation
…T LOCAL, IS NORMALIZED and XMLATTRIBUTES
Read SELECT ... INTO [[LOCAL | GLOBAL] {TEMPORARY | TEMP} | UNLOGGED] [TABLE] table
into a SelectIntoClause that also backs getIntoTables() and the trailing
INTO TEMP table, the alias of JOIN ... USING (...) AS alias, expr AT LOCAL,
expr IS [NOT] [NFC | NFD | NFKC | NFKD] NORMALIZED and
XMLELEMENT(NAME name, XMLATTRIBUTES(value [AS name], ...), ...).
AT TIME ZONE chains now associate from left to right, and the PostgreSQL
dialect rejects SELECT INTO forms the server rejects.
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
Several PostgreSQL 18 SELECT forms fail to parse with
Dialect.POSTGRESQL:This change reads them, following
gram.y(into_clause/OptTempTableName,join_using_alias,a_expr AT LOCAL,IS [NOT] unicode_normal_form NORMALIZED,xml_attributes) and the manual: SELECT INTO, SELECT, AT LOCAL, IS NORMALIZED and xmlelement.Current design (As-is)
PlainSelectkeeps the INTO target in two unrelated fields:intoTablesforSELECT … INTO tafter the select list, andintoTempTablefor Informix's… INTO TEMP tat the end of the query. Each has its own rendering intoString()and inSelectDeParser. There is no place for a persistence, soINTO TEMP t FROM …,INTO UNLOGGED tandINTO TABLE tare rejected.JoinrendersUSING (…)once intoString()and once inSelectDeParser, and has no alias for the USING columns.TimezoneExpressionholds a list of zones, but the zone operand reads a followingAT TIME ZONEitself, soa AT TIME ZONE 'UTC' AT TIME ZONE 'CET'is stored asa AT TIME ZONE ('UTC' AT TIME ZONE 'CET').AT LOCALis rejected.IS [NOT] [form] NORMALIZEDis rejected.xmlattributes(a AS x)is rejected, becauseXMLATTRIBUTESis read as a plain function call.GROUP BY ALL | DISTINCTalready parses withDialect.POSTGRESQL.Target design (To-be)
SelectIntoClausevalue object is the only storage of the clause inPlainSelect(getIntoClause()/setIntoClause()/withIntoClause()).Persistence(TEMP,TEMPORARY,LOCAL_TEMP,LOCAL_TEMPORARY,GLOBAL_TEMP,GLOBAL_TEMPORARY,UNLOGGED, or null), the optionalTABLEkeyword and thePosition(BEFORE_FROMorTRAILING).getIntoTables()/setIntoTables()/addIntoTables()andgetIntoTempTable()/setIntoTempTable()remain and are views of the clause.toString()andSelectDeParserrender it through oneappendTo.TABLEkeywords are read withDialect.POSTGRESQLand without a dialect. As on the server, a persistence word that no table name follows is the table itself:SELECT * INTO temp FROM tcreates the tabletemp.Dialect.POSTGRESQL, an empty select list may precede INTO (SELECT INTO t2 FROM t), and forms the server rejects are rejected: several targets (INTO a, b),INTO TABLE FROM tand a trailingINTO TEMP t. Other dialects keep these readings.SELECT a INTO x FROM t INTO TEMP y, which parsed before, is rejected.Feature.selectIntois added to the PostgreSQL validation capabilities.Join.getUsingAlias()holds the alias ofa JOIN b USING (id) AS j.ASis required, the join must be a qualified join and the USING columns plain names, as ingram.y.Join.appendUsingTois shared bytoString()and the deparser.TimezoneExpression.isAtLocal().AT TIME ZONEandAT LOCALnow chain from left to right: oneTimezoneExpressionholds a run of zones and theAT LOCALthat ends it, and a conversion afterAT LOCALwraps that expression. A cast may follow (ts AT LOCAL::date).toString()andExpressionDeParsershareappendTo.IsNormalizedExpressionwithisNot()andgetNormalForm()(NFC,NFD,NFKC,NFKD, or null when omitted). It chains with the other postfixIStests (s IS NORMALIZED IS TRUE).ExpressionVisitorgets default methods, so existing visitors compile unchanged; the deparser,TablesNamesFinder, the validator andExpressionVisitorAdaptervisit the operand.XMLELEMENT, directly after the element name,xmlattributes(value [AS name], …)is aFunctionoverAliasedExpressionarguments, the modelXMLFORESTuses. It is not read anywhere else, as on the server. WithDialect.POSTGRESQLtheNAMEkeyword and an identifier as the element name are required; other dialects also readXMLELEMENT("Emp", XMLATTRIBUTES(e.id AS "id")).gram.yitem after the quantifier (expressions,(),ROLLUP,CUBE,GROUPING SETS).NFC,NFD,NFKC,NFKD,NORMALIZEDandXMLATTRIBUTESare matched as contextual keywords;AT,LOCAL,TEMP,UNLOGGEDstay usable as names and aliases.PlainSelectholds one INTO clause:setIntoTempTable(table)replaces a clause set throughsetIntoTables(…), and the other way roundsetIntoTables(…)replaces a trailing clause.a AT TIME ZONE x AT TIME ZONE ynow gives oneTimezoneExpressionwith two zones instead of a nested one in the zone operand. Its zone list spans the text from the firstAT.AliasedExpressionarguments ofXMLFORESTnow carry an AST node.Not covered: a reserved word as the element or attribute name (
xmlelement(name table, …),AS select),GROUPING SETSas an item of a longer GROUP BY list or nested in anotherGROUPING SETS, and operators directly afterIS NORMALIZED(s IS NORMALIZED = true), which the otherIStests do not accept either.Validation
PostgreSqlSelectFormsTest:postgresql/select-forms.sql: parse,toString,StatementDeParserand reparse withDialect.POSTGRESQLand without a dialect, and PostgreSQL validation; the file is also walked byASTNodeCoverageTest;TablesNamesFinder, statement features andFeature.selectInto;SELECT a, b INTO x, y,INTO #tmp, InformixINTO TEMP … WITH NO LOG, OracleXMLELEMENT), statement boundaries in a script, and the GROUP BY quantifier forms.spotlessApply cleanTest check: 13,545 tests, 13,520 passed, 25 skipped, zero failures/errors. The grammar choice conflict check passes.master(e27929f76) on the MySQL 8.4 and PostgreSQL 18 DDL/DCL and non-DDL statement corpora:SELECT * INTO TEMP t2 FROM t,SELECT * FROM a JOIN b USING (id) AS j,SELECT ts AT LOCAL FROM t,SELECT s IS NFC NORMALIZED FROM tandSELECT xmlelement(name foo, xmlattributes(a AS x, b)) FROM t, each withDialect.POSTGRESQLand without a dialect.masterrejects; some stop only at execution. It reports a syntax error for 69 statements that this branch rejects, including the 67 rejected forms of the tests. Twenty statements differ, none of them changed by this branch:master:INTOinside a sub-select or aUNIONbranch (gram.yaccepts it and the analyzer reports it),USINGafterNATURAL JOINorCROSS JOIN, andxmlelement(name),xmlelement(name 'foo'),xmlelement(name foo, s ORDER BY a),xmlattributes(a)andxmlattributes(*), which are read as plain function calls.master: the forms listed under "Not covered",ts AT LOCAL COLLATE "C",s IS NORMALIZED::textands IS NULL = true.AI assistance: prepared with Claude Code.