Skip to content

Commit e5808b0

Browse files
committed
feat: parse PostgreSQL CREATE/ALTER OPERATOR, OPERATOR CLASS/FAMILY and AGGREGATE
CREATE and ALTER OPERATOR, OPERATOR CLASS, OPERATOR FAMILY and AGGREGATE were unsupported statements, whose text broke an operator such as === into "== =". They parse to CreateOperator, AlterOperator, CreateOperatorClass, AlterOperatorClass, CreateOperatorFamily, AlterOperatorFamily, CreateAggregate and AlterAggregate. These reuse the models DROP OPERATOR, DROP AGGREGATE and CREATE TYPE have: ExclusionOperator and OperatorSignature for an operator, RoutineReference for an aggregate signature and DefinitionElement for a definition list. OperatorClassItem is a member of an operator class or family. The statements are wired into the deparser, visitors, table finder, validation (eight features, enabled for PostgreSQL) and feature analysis. An operator name follows PostgreSQL's lexer wherever DDL names an operator: <==> and @#@ are one name, a name such as +- or => alone is rejected, and a database may precede the schema. An aggregate signature needs * or an argument, so DROP AGGREGATE agg() is now a parse error. Without the PostgreSQL dialect, CREATE and ALTER OPERATOR are read this way when an operator symbol follows, so Oracle's CREATE OPERATOR name BINDING stays unsupported, as do MySQL's CREATE AGGREGATE FUNCTION and SQL Server's CREATE AGGREGATE name (@parameter type). Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent cf057dd commit e5808b0

28 files changed

Lines changed: 2903 additions & 14 deletions

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J
162162
| **MySQL utility statements** | `EXPLAIN`/`DESCRIBE [ANALYZE] FORMAT = …` · `EXPLAIN FOR CONNECTION` · `DESCRIBE t col` · `PREPARE … FROM` · `EXECUTE … USING` · `DROP PREPARE` · `DO` |
163163
| **PostgreSQL administration** | `CREATE`/`ALTER EVENT TRIGGER` · `REINDEX` · `SECURITY LABEL` |
164164
| **PostgreSQL types and rules** | `CREATE TYPE` (shell, composite, enum, range and base types) · `ALTER TYPE` · `CREATE RULE` · `ALTER RULE` |
165+
| **PostgreSQL operators and aggregates** | `CREATE`/`ALTER OPERATOR` · `CREATE`/`ALTER OPERATOR CLASS` · `CREATE`/`ALTER OPERATOR FAMILY` · `CREATE`/`ALTER AGGREGATE` |
165166
| **Informix constraints** | `ALTER TABLE … ADD CONSTRAINT` with trailing constraint names for primary, unique, foreign and check constraints; enable with `parser.withDialect(Dialect.INFORMIX)` |
166167
| **Salesforce SOQL** | `INCLUDES` · `EXCLUDES` |
167168

‎src/main/java/net/sf/jsqlparser/parser/feature/Feature.java‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,54 @@ public enum Feature {
10011001
* @see net.sf.jsqlparser.statement.alter.AlterRule
10021002
*/
10031003
alterRule,
1004+
/**
1005+
* PostgreSQL "CREATE OPERATOR" statement is allowed
1006+
*
1007+
* @see net.sf.jsqlparser.statement.create.operator.CreateOperator
1008+
*/
1009+
createOperator,
1010+
/**
1011+
* PostgreSQL "CREATE OPERATOR CLASS" statement is allowed
1012+
*
1013+
* @see net.sf.jsqlparser.statement.create.operator.CreateOperatorClass
1014+
*/
1015+
createOperatorClass,
1016+
/**
1017+
* PostgreSQL "CREATE OPERATOR FAMILY" statement is allowed
1018+
*
1019+
* @see net.sf.jsqlparser.statement.create.operator.CreateOperatorFamily
1020+
*/
1021+
createOperatorFamily,
1022+
/**
1023+
* PostgreSQL "CREATE AGGREGATE" statement is allowed
1024+
*
1025+
* @see net.sf.jsqlparser.statement.create.aggregate.CreateAggregate
1026+
*/
1027+
createAggregate,
1028+
/**
1029+
* PostgreSQL "ALTER OPERATOR" statement is allowed
1030+
*
1031+
* @see net.sf.jsqlparser.statement.alter.AlterOperator
1032+
*/
1033+
alterOperator,
1034+
/**
1035+
* PostgreSQL "ALTER OPERATOR CLASS" statement is allowed
1036+
*
1037+
* @see net.sf.jsqlparser.statement.alter.AlterOperatorClass
1038+
*/
1039+
alterOperatorClass,
1040+
/**
1041+
* PostgreSQL "ALTER OPERATOR FAMILY" statement is allowed
1042+
*
1043+
* @see net.sf.jsqlparser.statement.alter.AlterOperatorFamily
1044+
*/
1045+
alterOperatorFamily,
1046+
/**
1047+
* PostgreSQL "ALTER AGGREGATE" statement is allowed
1048+
*
1049+
* @see net.sf.jsqlparser.statement.alter.AlterAggregate
1050+
*/
1051+
alterAggregate,
10041052
/**
10051053
* SQL block starting with "BEGIN" and ends with "END" statement is allowed
10061054
*

‎src/main/java/net/sf/jsqlparser/statement/DefinitionElement.java‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
/**
1717
* One element of a PostgreSQL definition list, {@code name [= value]}, as in
18-
* {@code CREATE TYPE name (INPUT = fn, PASSEDBYVALUE)} or
19-
* {@code ALTER TYPE name SET (SEND = NONE)}. The name keeps its spelling and quoting.
18+
* {@code CREATE TYPE name (INPUT = fn, PASSEDBYVALUE)}, {@code ALTER TYPE name SET (SEND = NONE)},
19+
* {@code CREATE OPERATOR} or {@code CREATE AGGREGATE}. The name keeps its spelling and quoting.
2020
*/
2121
public class DefinitionElement implements Serializable {
2222
private String name;
@@ -62,6 +62,18 @@ public static String toString(List<DefinitionElement> elements) {
6262
return elements.stream().map(Object::toString).collect(Collectors.joining(", ", "(", ")"));
6363
}
6464

65+
/**
66+
* Finds an element of a definition list by its name, ignoring case.
67+
*
68+
* @param elements the elements
69+
* @param name the name, such as {@code INPUT}
70+
* @return the first element of that name, or {@code null}
71+
*/
72+
public static DefinitionElement find(List<DefinitionElement> elements, String name) {
73+
return elements.stream().filter(element -> name.equalsIgnoreCase(element.getName()))
74+
.findFirst().orElse(null);
75+
}
76+
6577
@Override
6678
public String toString() {
6779
return argument == null ? name : name + " = " + argument;

‎src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@
3636
import net.sf.jsqlparser.statement.alter.AlterPolicy;
3737
import net.sf.jsqlparser.statement.alter.AlterPublication;
3838
import net.sf.jsqlparser.statement.alter.AlterRelation;
39+
import net.sf.jsqlparser.statement.create.operator.CreateOperator;
40+
import net.sf.jsqlparser.statement.create.operator.CreateOperatorClass;
41+
import net.sf.jsqlparser.statement.create.operator.CreateOperatorFamily;
42+
import net.sf.jsqlparser.statement.create.aggregate.CreateAggregate;
43+
import net.sf.jsqlparser.statement.alter.AlterOperator;
44+
import net.sf.jsqlparser.statement.alter.AlterOperatorClass;
45+
import net.sf.jsqlparser.statement.alter.AlterOperatorFamily;
46+
import net.sf.jsqlparser.statement.alter.AlterAggregate;
3947
import net.sf.jsqlparser.statement.alter.AlterRule;
4048
import net.sf.jsqlparser.statement.alter.AlterServer;
4149
import net.sf.jsqlparser.statement.alter.AlterSession;
@@ -1557,4 +1565,44 @@ public <S> Void visit(CreateCollation statement, S context) {
15571565
public <S> Void visit(AlterRule statement, S context) {
15581566
return schemaOnly();
15591567
}
1568+
1569+
@Override
1570+
public <S> Void visit(CreateOperator statement, S context) {
1571+
return schemaOnly();
1572+
}
1573+
1574+
@Override
1575+
public <S> Void visit(CreateOperatorClass statement, S context) {
1576+
return schemaOnly();
1577+
}
1578+
1579+
@Override
1580+
public <S> Void visit(CreateOperatorFamily statement, S context) {
1581+
return schemaOnly();
1582+
}
1583+
1584+
@Override
1585+
public <S> Void visit(CreateAggregate statement, S context) {
1586+
return schemaOnly();
1587+
}
1588+
1589+
@Override
1590+
public <S> Void visit(AlterOperator statement, S context) {
1591+
return schemaOnly();
1592+
}
1593+
1594+
@Override
1595+
public <S> Void visit(AlterOperatorClass statement, S context) {
1596+
return schemaOnly();
1597+
}
1598+
1599+
@Override
1600+
public <S> Void visit(AlterOperatorFamily statement, S context) {
1601+
return schemaOnly();
1602+
}
1603+
1604+
@Override
1605+
public <S> Void visit(AlterAggregate statement, S context) {
1606+
return schemaOnly();
1607+
}
15601608
}

‎src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
import net.sf.jsqlparser.statement.notify.NotifyStatement;
2525
import net.sf.jsqlparser.statement.create.collation.CreateCollation;
2626
import net.sf.jsqlparser.statement.alter.AlterCollation;
27+
import net.sf.jsqlparser.statement.create.operator.CreateOperator;
28+
import net.sf.jsqlparser.statement.create.operator.CreateOperatorClass;
29+
import net.sf.jsqlparser.statement.create.operator.CreateOperatorFamily;
30+
import net.sf.jsqlparser.statement.create.aggregate.CreateAggregate;
31+
import net.sf.jsqlparser.statement.alter.AlterOperator;
32+
import net.sf.jsqlparser.statement.alter.AlterOperatorClass;
33+
import net.sf.jsqlparser.statement.alter.AlterOperatorFamily;
34+
import net.sf.jsqlparser.statement.alter.AlterAggregate;
2735
import net.sf.jsqlparser.statement.alter.AlterRule;
2836
import net.sf.jsqlparser.statement.alter.AlterRoutine;
2937
import net.sf.jsqlparser.statement.alter.AlterTrigger;
@@ -1182,4 +1190,68 @@ default <S> T visit(AlterRule statement, S context) {
11821190
default void visit(AlterRule statement) {
11831191
visit(statement, null);
11841192
}
1193+
1194+
default <S> T visit(CreateOperator statement, S context) {
1195+
return null;
1196+
}
1197+
1198+
default void visit(CreateOperator statement) {
1199+
visit(statement, null);
1200+
}
1201+
1202+
default <S> T visit(CreateOperatorClass statement, S context) {
1203+
return null;
1204+
}
1205+
1206+
default void visit(CreateOperatorClass statement) {
1207+
visit(statement, null);
1208+
}
1209+
1210+
default <S> T visit(CreateOperatorFamily statement, S context) {
1211+
return null;
1212+
}
1213+
1214+
default void visit(CreateOperatorFamily statement) {
1215+
visit(statement, null);
1216+
}
1217+
1218+
default <S> T visit(CreateAggregate statement, S context) {
1219+
return null;
1220+
}
1221+
1222+
default void visit(CreateAggregate statement) {
1223+
visit(statement, null);
1224+
}
1225+
1226+
default <S> T visit(AlterOperator statement, S context) {
1227+
return null;
1228+
}
1229+
1230+
default void visit(AlterOperator statement) {
1231+
visit(statement, null);
1232+
}
1233+
1234+
default <S> T visit(AlterOperatorClass statement, S context) {
1235+
return null;
1236+
}
1237+
1238+
default void visit(AlterOperatorClass statement) {
1239+
visit(statement, null);
1240+
}
1241+
1242+
default <S> T visit(AlterOperatorFamily statement, S context) {
1243+
return null;
1244+
}
1245+
1246+
default void visit(AlterOperatorFamily statement) {
1247+
visit(statement, null);
1248+
}
1249+
1250+
default <S> T visit(AlterAggregate statement, S context) {
1251+
return null;
1252+
}
1253+
1254+
default void visit(AlterAggregate statement) {
1255+
visit(statement, null);
1256+
}
11851257
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.alter;
11+
12+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
13+
import net.sf.jsqlparser.statement.RoutineReference;
14+
import net.sf.jsqlparser.statement.Statement;
15+
import net.sf.jsqlparser.statement.StatementVisitor;
16+
17+
/**
18+
* PostgreSQL {@code ALTER AGGREGATE name (arguments)} with one of {@code RENAME TO new_name},
19+
* {@code OWNER TO role} and {@code SET SCHEMA schema}.
20+
*/
21+
public class AlterAggregate extends ASTNodeAccessImpl implements Statement {
22+
public enum Action {
23+
RENAME, OWNER, SET_SCHEMA
24+
}
25+
26+
private RoutineReference aggregate;
27+
private Action action;
28+
private String newName;
29+
30+
/**
31+
* The name and the argument signature, read as in DROP AGGREGATE.
32+
*
33+
* @return the aggregate
34+
*/
35+
public RoutineReference getAggregate() {
36+
return aggregate;
37+
}
38+
39+
public void setAggregate(RoutineReference aggregate) {
40+
this.aggregate = aggregate;
41+
}
42+
43+
public Action getAction() {
44+
return action;
45+
}
46+
47+
public void setAction(Action action) {
48+
this.action = action;
49+
}
50+
51+
/**
52+
* The new name of {@code RENAME TO}, the role of {@code OWNER TO} or the schema of
53+
* {@code SET SCHEMA}.
54+
*
55+
* @return the name, or {@code null} for another action
56+
*/
57+
public String getNewName() {
58+
return newName;
59+
}
60+
61+
public void setNewName(String newName) {
62+
this.newName = newName;
63+
}
64+
65+
@Override
66+
public StringBuilder appendTo(StringBuilder builder) {
67+
builder.append("ALTER AGGREGATE ").append(aggregate);
68+
switch (action) {
69+
case RENAME:
70+
return builder.append(" RENAME TO ").append(newName);
71+
case OWNER:
72+
return builder.append(" OWNER TO ").append(newName);
73+
case SET_SCHEMA:
74+
return builder.append(" SET SCHEMA ").append(newName);
75+
default:
76+
throw new IllegalStateException("Unknown aggregate alteration: " + action);
77+
}
78+
}
79+
80+
@Override
81+
public String toString() {
82+
return appendTo(new StringBuilder()).toString();
83+
}
84+
85+
@Override
86+
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
87+
return statementVisitor.visit(this, context);
88+
}
89+
}

0 commit comments

Comments
 (0)