Repository navigation
feat: parse PostgreSQL CREATE CAST, CREATE TRANSFORM, CREATE CONVERSION and ALTER CONVERSION - #2918
Merged
manticore-projects merged 2 commits intoNov 14, 2026
Conversation
…ON and ALTER CONVERSION CREATE CAST (source AS target) WITH FUNCTION f(args) | WITHOUT FUNCTION | WITH INOUT [AS ASSIGNMENT | AS IMPLICIT], CREATE [OR REPLACE] TRANSFORM FOR type LANGUAGE lang (FROM SQL WITH FUNCTION f, TO SQL WITH FUNCTION g), CREATE [DEFAULT] CONVERSION name FOR 'enc' TO 'enc' FROM function and ALTER CONVERSION name RENAME TO | OWNER TO | SET SCHEMA were unsupported statements. They parse to CreateCast, CreateTransform, CreateConversion and AlterConversion. A cast and a transform are named by the CastSignature and TransformSignature of DROP CAST and DROP TRANSFORM, and functions are RoutineReference objects, read by the existing productions. The statements are wired into the deparser, visitors, table finder, validation (createCast, createTransform, createConversion and alterConversion, enabled for PostgreSQL) and feature analysis. With the PostgreSQL dialect these words start only these statements, so forms the server reports as syntax errors are parse errors. In another dialect and without one, a statement is read this way when it has PostgreSQL's form, and statements of other products that start with the same words, such as CREATE CAST (a AS b) WITH SPECIFIC FUNCTION f, stay unsupported statements. Signed-off-by: minleejae <mmj9808@gmail.com>
Preserve cast, transform, and conversion support alongside upstream operator, aggregate, and spatial DDL. Cover both feature groups in the existing statement-boundary regression test. Validation: mvn --batch-mode --no-transfer-progress test 15,973 tests; zero failures/errors; 25 existing skips. JavaCC reports no choice conflicts.
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.
Follows #2896, which typed
DROP CASTandDROP TRANSFORM. This adds the statements that create those objects, and the conversion statements, on the same signature models.Purpose
PostgreSQL defines casts, transforms and encoding conversions with their own statements:
On
mastereach of them comes back as anUnsupportedStatement: the text is kept, but the types, functions, encodings and names cannot be inspected, validators report onlyallowUnsupportedStatements, and with the PostgreSQL dialect any text afterCREATE CASTis accepted.pg_dumpwritesCREATE CASTandCREATE TRANSFORMfor every user-defined cast and transform, and the matchingDROP CAST,DROP TRANSFORMandCOMMENT ON CASTare already typed.Syntax reference: PostgreSQL 18 CREATE CAST, CREATE TRANSFORM, CREATE CONVERSION, ALTER CONVERSION, and the
CreateCastStmt,CreateTransformStmt,CreateConversionStmt,RenameStmt,AlterOwnerStmtandAlterObjectSchemaStmtproductions ofgram.y.Current design (As-is)
Create()has no branch forCAST,TRANSFORMorCONVERSION. ACREATEstatement that names none ofTABLE,INDEX,VIEWandPOLICYfalls back toUnsupportedStatement, in every dialect.Alter()has no branch forCONVERSION, soALTER CONVERSION …ends in thecaptureRest()fallback, also as anUnsupportedStatement.Dropalready names a cast by aCastSignature((source AS target)) and a transform by aTransformSignature(FOR type LANGUAGE lang), read by theCastSignature()andTransformSignature()productions, and function signatures areRoutineReferenceobjects read byRoutineReference()(DROP FUNCTION,ALTER FUNCTION,COMMENT ON FUNCTION).Target design (To-be)
appendTo()shared bytoString()andStatementDeParser:CreateCast(statement.create.cast):getCast()is theCastSignatureofDROP CAST;getMethod()isWITH_FUNCTION,WITHOUT_FUNCTIONorWITH_INOUT;getFunction()is theRoutineReferenceofWITH FUNCTION, withnullarguments when the function is named without an argument list;getContext()isASSIGNMENT,IMPLICITornull. Method and function stay consistent: setting a function selectsWITH_FUNCTION, another method clears the function.CreateTransform(statement.create.transform):isOrReplace(),getTransform()is theTransformSignatureofDROP TRANSFORM,getFromSqlFunction()andgetToSqlFunction()areRoutineReferenceobjects, andisToSqlFirst()keeps the order of the two items. The grammar followstransform_element_list: one item, or oneFROM SQLand oneTO SQLitem in either order.CreateConversion(statement.create.conversion):isDefaultConversion(),getName(),getSourceEncoding()andgetDestinationEncoding()asStringValue,getFunction().AlterConversion(statement.alter):getName(),getAction()(RENAME,OWNER,SET_SCHEMA) andgetNewName(),getOwner()orgetSchemaName(), likeAlterCollation.CastSignature(),TransformSignature()andRoutineReference(); no production is duplicated and no keyword is added. The wordsTRANSFORM,CONVERSION,INOUT,ASSIGNMENT,IMPLICIT,SQLandOWNERare matched contextually.Dialect.POSTGRESQL,CREATE CAST,CREATE [OR REPLACE] TRANSFORM,CREATE [DEFAULT] CONVERSION,CREATE DEFAULTandALTER CONVERSIONstart only these statements, so the forms PostgreSQL reports as syntax errors are parse errors:CREATE OR REPLACE CAST,CREATE OR REPLACE CONVERSION, twoFROM SQLitems, an encoding that is not a string constant (N'…',B'…', an identifier), a reserved word as the conversion, schema or new name, or as the owner other thanCURRENT_ROLE,CURRENT_USERandSESSION_USER.CAST (…)followed byWITH FUNCTION,WITH INOUTorWITHOUT FUNCTION,TRANSFORM FOR type LANGUAGE,[DEFAULT] CONVERSION name FOR, andALTER CONVERSION namefollowed byRENAME,OWNERorSET. Statements of other products that start with the same words keep today's result, anUnsupportedStatement:CREATE CAST (a AS b) WITH SPECIFIC FUNCTION f, Informix'sCREATE CAST (percent AS decimal), Db2'sCREATE TRANSFORM FOR type group (…),CREATE OR REPLACE CAST ….StatementVisitordefault methods,StatementVisitorAdapter,TablesNamesFinder(no tables),StatementFeatureVisitor(schema change), the featurescreateCast,createTransform,createConversionandalterConversioninFeaturesAllowed.CREATE/ALTERandPostgresqlVersion,StatementValidator, README,index.rstandusage.rst. The statements and their signatures carry AST nodes.Behaviour changes:
UnsupportedStatementobjects and are nowCreateCast,CreateTransform,CreateConversionandAlterConversion. Code that matched them byinstanceof UnsupportedStatementhas to match the new classes.toString()now renders them in the usual spacing,CREATE CAST (int AS text) WITH INOUTinstead of the token listCREATE CAST ( int AS text ) WITH INOUT.UnsupportedStatement. Without that dialect, text that has PostgreSQL's form up to the point described above and then differs from it is a parse error too.Not covered: a type written with
SETOF(CREATE CAST (SETOF int AS text) …), which PostgreSQL's grammar takes wherever a type name is allowed. The sharedCastSignature,TransformSignatureandRoutineReferenceread a plain type, asDROP CASTandCOMMENT ON CASTdo onmaster.Validation
PostgreSqlCastTransformConversionTestadds 148 test cases: 40 statements parsed with the PostgreSQL dialect, without a dialect and with another one, checked againsttoString()and the deparser, parsed again, validated for PostgreSQL and forFeaturesAllowed.DDL, with no tables, a schema-change feature set and an AST node spanning the statement; the fields of each statement and their edits; lower-case keywords; a script that mixes them withDROP CASTandDROP TRANSFORM; visitors; validation; 84 forms rejected with the PostgreSQL dialect; and 10 statements of other forms that stayUnsupportedStatementwithout it.ASTNodeCoverageTestwalks four of the statements andStatementFeatureVisitorMetadataDdlTestcovers the four classes. Onmaster(cf057dd33) every accepted statement is anUnsupportedStatement, and 83 of the 84 rejected forms parse as one.Java 17 Gradle
check: 14,618 tests, 0 failures, 25 skipped. Grammar ambiguity, formatting (Spotless ratchet againstupstream/master), Checkstyle, PMD, SpotBugs and JaCoCo pass.Compared with
master(cf057dd33) on the DDL/DCL survey corpora and the non-DDL corpora: no case is fixed, regressed or changed, since the corpora have none of these statements; the rendered statements and AST dumps are identical.PostgreSQL 18.6: of 141 statements, 45 of the 47 whose syntax the server accepts are typed with
Dialect.POSTGRESQL(they stop only at execution, for example with a missing function, type or language), and all 94 it rejects are parse errors; onmaster93 of those 94 are anUnsupportedStatement. The two that differ are theSETOFforms listed under "Not covered" (CREATE CAST (setof int AS text) WITH INOUT,DROP CAST (setof int AS text)).AI assistance: prepared with Claude Code.