Skip to content

fix: parse PostgreSQL DROP CAST, DROP OPERATOR and DROP TRANSFORM - #2896

Merged
manticore-projects merged 1 commit into
JSQLParser:masterfrom
minleejae:fix/postgresql-drop-cast-operator-transform-20261105
Nov 5, 2026
Merged

manticore-projects merged 1 commit into
JSQLParser:masterfrom
minleejae:fix/postgresql-drop-cast-operator-transform-20261105

Conversation

@minleejae

Copy link
Copy Markdown
Contributor

Follows #2884, which added the PostgreSQL object types of several words to DROP. The three object types here are named by types rather than by a name, so they need their own target models.

Purpose

PostgreSQL names a cast, an operator and a transform by types rather than by a plain name:

DROP CAST IF EXISTS (bigint AS int4) CASCADE;
DROP OPERATOR IF EXISTS public.=== (integer, integer), ~ (NONE, bigint) CASCADE;
DROP TRANSFORM IF EXISTS FOR public.hstore LANGUAGE plpython3u RESTRICT;

All three fail to parse on master in every dialect: CAST is not a DROP object type, and after DROP OPERATOR and DROP TRANSFORM the parser expects object names, so === or FOR is a syntax error. pg_dump --clean writes these statements for every cast, operator and transform in a database, so such a dump fails as a script at its first DROP TRANSFORM, DROP CAST or DROP OPERATOR.

Syntax reference: PostgreSQL 18 DROP CAST, DROP OPERATOR, DROP TRANSFORM.

Current design (As-is)

  • Drop keeps its targets as typed lists: RoutineReference items for FUNCTION, PROCEDURE, ROUTINE and AGGREGATE (getRoutines()), UserAccount items for USER, ROLE, GROUP and OWNED BY (getAccounts()), and plain Table names for everything else. getNames() derives read-only names from the routines and accounts.
  • Drop() reads CAST nowhere, and reads OPERATOR and TRANSFORM as a generic identifier with object type OTHER, followed by a name list and loose trailing words. So DROP OPERATOR foo and DROP TRANSFORM hstore LANGUAGE plpython3u parse with the PostgreSQL dialect, although PostgreSQL reports both as syntax errors.
  • COMMENT ON already reads the same three references into CommentTarget: CAST (source AS target), OPERATOR [schema.]op (left | NONE, right | NONE) through the shared PostgreSqlOperatorReference() and ExtensionOperatorType() productions, and TRANSFORM FOR type LANGUAGE lang.

Target design (To-be)

  • Drop.ObjectType gains CAST, OPERATOR and TRANSFORM. DropTargets() reads their targets into three new value types in net.sf.jsqlparser.statement, next to RoutineReference:
    • CastSignature: source and target ColDataType, rendered (source AS target); Drop.getCast().
    • OperatorSignature: the ExclusionOperator reference that COMMENT ON OPERATOR and exclusion constraints use, and the left and right operand ColDataType, where null is the NONE marker of a missing operand; Drop.getOperators() holds one per operator.
    • TransformSignature: the ColDataType and the language, rendered FOR type LANGUAGE lang; Drop.getTransform().
  • The operator reference and the NONE-or-type operands reuse the COMMENT ON OPERATOR productions, including its rule that one operand must be a type. (NONE, NONE) and a single operand are rejected, as in PostgreSQL's oper_argtypes.
  • The targets exclude each other like routines and accounts: each setter replaces the other targets, and the legacy name setters switch back to plain names. getNames() also derives the operator names (public.===); a cast or transform has no name. toString() and DropDeParser render the targets through the same appendTo(). The signatures carry AST nodes spanning their source, like MaintenanceTarget and UtilityOption.
  • DROP OPERATOR takes the signature form when an operator symbol, or a schema, a dot and a symbol, follows. Otherwise it keeps a plain name, which is Oracle's DROP OPERATOR [schema.]operator. With the PostgreSQL dialect a plain name after DROP OPERATOR or DROP TRANSFORM is rejected, since PostgreSQL reports it as a syntax error. A cast, transform or operator signature can be followed only by CASCADE or RESTRICT.
  • No keyword is added. Like the object types of fix: parse PostgreSQL DROP for object types of several words #2884, the new forms are read in every dialect and without one; the readings other dialects already had are unchanged.

Public method signatures are retained. getObjectType() reports OPERATOR or TRANSFORM for the name forms DROP OPERATOR name and DROP TRANSFORM name, where it reported OTHER. A catalog-qualified operator (db.schema.===) is still rejected: the shared operator reference takes one schema, as in COMMENT ON OPERATOR. CommentTarget and ExtensionObject keep their own fields for the same references; they could move to the new types in a separate change.

Validation

  • DropSignatureTargetTest adds 19 statements. Each is checked against toString() and the deparser, parsed again, parsed with and without the PostgreSQL dialect and inside a script, and has no tables. Further tests check the cast, operator and transform fields and their edits, the source span of each signature, how the target kinds replace each other, Oracle's DROP OPERATOR name and other identifiers that start with an operator character or a quote, schemas named class or family, 26 rejected forms, and a pg_dump --clean --if-exists style script. ASTNodeCoverageTest walks three of the statements, and DropValidatorTest validates them for PostgreSQL. On master (4a970a34e) all 19 statements fail, and 3 of the 26 rejected forms parse (DROP OPERATOR foo, DROP TRANSFORM foo, DROP TRANSFORM hstore LANGUAGE plpython3u).

  • A pg_dump --clean --if-exists style script with a transform, a cast, two operators and the objects they use (29 statements, from SET through COMMENT ON OPERATOR) fails on master at its first DROP TRANSFORM and parses with this change.

  • Java 17 Gradle check: 12,691 tests, 0 failures, 25 skipped. Grammar ambiguity, formatting (Spotless ratchet against upstream/master), Checkstyle, PMD, SpotBugs and JaCoCo pass.

  • Compared with master (4a970a34e) on the DDL/DCL survey corpora and the non-DDL corpora: no case is fixed, regressed or changed, since the corpora have no DROP CAST, DROP OPERATOR or DROP TRANSFORM; the rendered statements and AST dumps are identical.

  • The statements of the tests were run against PostgreSQL 18.3 (37 accepted and 28 rejected forms). Every form the parser accepts with the PostgreSQL dialect is accepted by the server's grammar, and every form it rejects is a syntax error there. DROP OPERATOR ! (bigint, NONE) passes the grammar and fails only when the operator is looked up, since PostgreSQL 14 removed postfix operators; DROP OPERATOR IF EXISTS ! (bigint, NONE) succeeds with a notice. The catalog-qualified DROP OPERATOR a.b.=== (int, int) is accepted by the server's grammar (it then fails with "cross-database references are not implemented") and stays rejected here, as noted above.

AI assistance: prepared with Claude Code.

DROP CAST (source AS target), DROP OPERATOR op (left, right) and DROP
TRANSFORM FOR type LANGUAGE lang failed in every dialect. pg_dump
--clean writes them for every cast, operator and transform, so such a
dump could not be parsed as a script.

Drop.ObjectType gains CAST, OPERATOR and TRANSFORM, and their targets
are typed: getCast() is a CastSignature, getOperators() holds an
OperatorSignature per operator, with the operator reference COMMENT ON
OPERATOR uses and null as the NONE marker of a missing operand, and
getTransform() is a TransformSignature. toString() and the deparser
render them through the same appendTo(), and they carry AST nodes
spanning their source.

Oracle's DROP OPERATOR name keeps a plain name. With the PostgreSQL
dialect DROP OPERATOR and DROP TRANSFORM require their signatures, and a
signature is followed only by CASCADE or RESTRICT.

Signed-off-by: minleejae <mmj9808@gmail.com>
@manticore-projects
manticore-projects merged commit 12548b9 into JSQLParser:master Nov 5, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants