Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/net/sf/jsqlparser/parser/feature/Feature.java
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,8 @@ public enum Feature {
*/
createSequence,
/** Publication and subscription definitions. */
createRule, notifyStatement,

createPublication, alterPublication, createSubscription, alterSubscription,
/**
* Structured type, domain and extension statements.
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.statement;

import net.sf.jsqlparser.statement.create.rule.CreateRule;
import net.sf.jsqlparser.statement.notify.NotifyStatement;
import net.sf.jsqlparser.statement.alter.AlterPolicy;
import net.sf.jsqlparser.statement.drop.DropPolicy;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
Expand Down Expand Up @@ -733,4 +735,20 @@ default <S> T visit(AlterStatistics statement, S context) {
default void visit(AlterStatistics statement) {
visit(statement, null);
}

default <S> T visit(CreateRule statement, S context) {
return null;
}

default void visit(CreateRule statement) {
visit(statement, null);
}

default <S> T visit(NotifyStatement statement, S context) {
return null;
}

default void visit(NotifyStatement statement) {
visit(statement, null);
}
}
170 changes: 170 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/create/rule/CreateRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.create.rule;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;

/** PostgreSQL rewrite rule whose actions reuse ordinary statement AST nodes. */
public class CreateRule implements Statement {
public enum Event {
SELECT, INSERT, UPDATE, DELETE
}
public enum Behavior {
ALSO, INSTEAD
}

private String name;
private boolean orReplace;
private Event event;
private Table table;
private Expression whereExpression;
private Behavior behavior;
private boolean useParentheses;
private List<Statement> actions = new ArrayList<>();

public String getName() {
return name;
}

public void setName(String value) {
name = value;
}

public boolean isOrReplace() {
return orReplace;
}

public void setOrReplace(boolean value) {
orReplace = value;
}

public Event getEvent() {
return event;
}

public void setEvent(Event value) {
event = value;
}

public Table getTable() {
return table;
}

public void setTable(Table value) {
table = value;
}

public Expression getWhereExpression() {
return whereExpression;
}

public void setWhereExpression(Expression value) {
whereExpression = value;
}

public Behavior getBehavior() {
return behavior;
}

public void setBehavior(Behavior value) {
behavior = value;
}

public boolean isUseParentheses() {
return useParentheses;
}

public void setUseParentheses(boolean value) {
useParentheses = value;
}

public List<Statement> getActions() {
return actions;
}

public void setActions(List<Statement> value) {
actions = value;
}

public boolean isNothing() {
return actions.isEmpty() && !useParentheses;
}

public void setNothing(boolean nothing) {
if (nothing) {
actions.clear();
useParentheses = false;
}
}

public void visitExpressions(Consumer<Expression> visitor) {
if (whereExpression != null) {
visitor.accept(whereExpression);
}
}

public void visitTables(Consumer<Table> visitor) {
if (table != null) {
visitor.accept(table);
}
}

public StringBuilder appendTo(StringBuilder sql, Consumer<Expression> expressions,
Consumer<Statement> statements) {
sql.append("CREATE ");
if (orReplace) {
sql.append("OR REPLACE ");
}
sql.append("RULE ").append(name).append(" AS ON ").append(event).append(" TO ")
.append(table);
if (whereExpression != null) {
sql.append(" WHERE ");
expressions.accept(whereExpression);
}
sql.append(" DO ");
if (behavior != null) {
sql.append(behavior).append(' ');
}
if (isNothing()) {
return sql.append("NOTHING");
}
boolean grouped = useParentheses || actions.size() != 1;
if (grouped) {
sql.append('(');
}
for (int i = 0; i < actions.size(); i++) {
if (i > 0) {
sql.append("; ");
}
statements.accept(actions.get(i));
}
if (grouped) {
sql.append(')');
}
return sql;
}

@Override
public String toString() {
StringBuilder sql = new StringBuilder();
return appendTo(sql, sql::append, sql::append).toString();
}

@Override
public <T, S> T accept(StatementVisitor<T> visitor, S context) {
return visitor.visit(this, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.notify;

import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;

/** PostgreSQL NOTIFY, usable independently and in CREATE RULE actions. */
public class NotifyStatement implements Statement {
private String channel;
private StringValue payload;

public String getChannel() {
return channel;
}

public void setChannel(String value) {
channel = value;
}

public StringValue getPayload() {
return payload;
}

public void setPayload(StringValue value) {
payload = value;
}

public void visitExpressions(Consumer<Expression> visitor) {
if (payload != null) {
visitor.accept(payload);
}
}

public StringBuilder appendTo(StringBuilder sql, Consumer<Expression> printer) {
sql.append("NOTIFY ").append(channel);
if (payload != null) {
sql.append(", ");
printer.accept(payload);
}
return sql;
}

@Override
public String toString() {
StringBuilder sql = new StringBuilder();
return appendTo(sql, sql::append).toString();
}

@Override
public <T, S> T accept(StatementVisitor<T> visitor, S context) {
return visitor.visit(this, context);
}
}
16 changes: 16 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.util;

import net.sf.jsqlparser.statement.create.rule.CreateRule;
import net.sf.jsqlparser.statement.notify.NotifyStatement;
import net.sf.jsqlparser.statement.alter.AlterPolicy;
import net.sf.jsqlparser.statement.drop.DropPolicy;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
Expand Down Expand Up @@ -2968,4 +2970,18 @@ public <S> Void visit(CreateStatistics statement, S context) {
public <S> Void visit(AlterStatistics statement, S context) {
return null;
}

@Override
public <S> Void visit(CreateRule statement, S context) {
statement.visitExpressions(expression -> expression.accept(this, context));
statement.visitTables(table -> visit(table, context));
statement.getActions().forEach(action -> action.accept(this, context));
return null;
}

@Override
public <S> Void visit(NotifyStatement statement, S context) {
statement.visitExpressions(expression -> expression.accept(this, context));
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.util.deparser;

import net.sf.jsqlparser.statement.create.rule.CreateRule;
import net.sf.jsqlparser.statement.notify.NotifyStatement;
import net.sf.jsqlparser.statement.alter.AlterPolicy;
import net.sf.jsqlparser.statement.drop.DropPolicy;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
Expand Down Expand Up @@ -853,4 +855,17 @@ public <S> StringBuilder visit(CreateStatistics statement, S context) {
public <S> StringBuilder visit(AlterStatistics statement, S context) {
return statement.appendTo(builder);
}

@Override
public <S> StringBuilder visit(CreateRule statement, S context) {
return statement.appendTo(builder,
expression -> expression.accept(expressionDeParser, context),
action -> action.accept(this, context));
}

@Override
public <S> StringBuilder visit(NotifyStatement statement, S context) {
return statement.appendTo(builder,
expression -> expression.accept(expressionDeParser, context));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS
* all "CREATE" {@link Feature}'s
*/
public static final FeaturesAllowed CREATE = new FeaturesAllowed("CREATE", Feature.createIndex,
Feature.createRule,
Feature.createSchema, Feature.createSequence, Feature.createTable,
Feature.createTableUnlogged,
Feature.createTableCreateOptionStrings, Feature.createTableTableOptionStrings,
Expand Down Expand Up @@ -157,7 +158,8 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS
* all DML {@link Feature}'s
*/
public static final FeaturesAllowed DML =
new FeaturesAllowed("DML").add(SELECT, INSERT, UPDATE, DELETE, MERGE)
new FeaturesAllowed("DML", Feature.notifyStatement)
.add(SELECT, INSERT, UPDATE, DELETE, MERGE)
.unmodifyable();
/**
* all DDL {@link Feature}'s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public enum PostgresqlVersion implements Version {
Feature.exprLike,
Feature.exprSimilarTo, // https://www.postgresql.org/docs/current/sql-select.html
Feature.select,
Feature.tableStatement,
Feature.selectGroupBy, Feature.function, Feature.tableFunction,
Feature.lateralSubSelect,
Feature.selectHaving, // https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-GROUPING-SETS
Expand Down Expand Up @@ -97,6 +98,7 @@ public enum PostgresqlVersion implements Version {

// https://www.postgresql.org/docs/current/sql-createsequence.html
Feature.createSequence,
Feature.createRule, Feature.notifyStatement,
Feature.createPublication, Feature.alterPublication,
Feature.createSubscription, Feature.alterSubscription,
Feature.createType, Feature.alterType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package net.sf.jsqlparser.util.validation.validator;

import net.sf.jsqlparser.statement.create.rule.CreateRule;
import net.sf.jsqlparser.statement.notify.NotifyStatement;
import net.sf.jsqlparser.statement.alter.schema.AlterSchema;
import net.sf.jsqlparser.statement.oracle.OracleBlock;
import net.sf.jsqlparser.statement.oracle.OracleAssignment;
Expand Down Expand Up @@ -1024,4 +1026,20 @@ public <S> Void visit(OracleNullStatement statement, S context) {
return null;
}


@Override
public <S> Void visit(CreateRule statement, S context) {
validateFeature(Feature.createRule);
statement.visitExpressions(this::validateOptionalExpression);
statement.visitTables(this::validateOptionalFromItem);
statement.getActions().forEach(action -> action.accept(this, context));
return null;
}

@Override
public <S> Void visit(NotifyStatement statement, S context) {
validateFeature(Feature.notifyStatement);
statement.visitExpressions(this::validateOptionalExpression);
return null;
}
}
Loading
Loading