Skip to content
Merged
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
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 @@ -11,6 +11,8 @@

import net.sf.jsqlparser.statement.alter.AlterPolicy;
import net.sf.jsqlparser.statement.drop.DropPolicy;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
import net.sf.jsqlparser.statement.alter.AlterStatistics;
import net.sf.jsqlparser.statement.alter.AlterRelation;
import net.sf.jsqlparser.statement.alter.AlterTablespaceMove;
import net.sf.jsqlparser.statement.alter.database.AlterDatabase;
Expand Down Expand Up @@ -715,4 +717,20 @@ default <S> T visit(DropPolicy statement, S context) {
default void visit(DropPolicy statement) {
visit(statement, null);
}

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

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

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

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

import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;

/** PostgreSQL statistics object metadata; a null target denotes SET STATISTICS DEFAULT. */
public class AlterStatistics implements Statement {
public enum Action {
RENAME, OWNER, SET_SCHEMA, SET_STATISTICS
}

private String name;
private Action action;
private String newName;
private String owner;
private String schemaName;
private Integer statistics;

public String getName() {
return name;
}

public AlterStatistics setName(String name) {
this.name = name;
return this;
}

public Action getAction() {
return action;
}

public AlterStatistics setAction(Action action) {
this.action = action;
return this;
}

public String getNewName() {
return newName;
}

public AlterStatistics setNewName(String newName) {
this.newName = newName;
return this;
}

public String getOwner() {
return owner;
}

public AlterStatistics setOwner(String owner) {
this.owner = owner;
return this;
}

public String getSchemaName() {
return schemaName;
}

public AlterStatistics setSchemaName(String schemaName) {
this.schemaName = schemaName;
return this;
}

public Integer getStatistics() {
return statistics;
}

public AlterStatistics setStatistics(Integer statistics) {
this.statistics = statistics;
return this;
}

public StringBuilder appendTo(StringBuilder sql) {
sql.append("ALTER STATISTICS ").append(name);
if (action == Action.RENAME) {
sql.append(" RENAME TO ").append(newName);
} else if (action == Action.OWNER) {
sql.append(" OWNER TO ").append(owner);
} else if (action == Action.SET_SCHEMA) {
sql.append(" SET SCHEMA ").append(schemaName);
} else if (action == Action.SET_STATISTICS) {
sql.append(" SET STATISTICS ").append(statistics == null ? "DEFAULT" : statistics);
} else {
throw new IllegalStateException("Expected statistics alteration action");
}
return sql;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).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,111 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2025 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.create.statistics;

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

/** PostgreSQL extended statistics over columns and parenthesized expressions. */
public class CreateStatistics implements Statement {
public enum Kind {
NDISTINCT, DEPENDENCIES, MCV
}

private String name;
private boolean ifNotExists = false;
private List<Kind> kinds = new ArrayList<>();
private ExpressionList<Expression> expressions = new ExpressionList<>();
private Table table;

public String getName() {
return name;
}

public CreateStatistics setName(String name) {
this.name = name;
return this;
}

public boolean isIfNotExists() {
return ifNotExists;
}

public CreateStatistics setIfNotExists(boolean ifNotExists) {
this.ifNotExists = ifNotExists;
return this;
}

public List<Kind> getKinds() {
return kinds;
}

public CreateStatistics setKinds(List<Kind> kinds) {
this.kinds = kinds;
return this;
}

public ExpressionList<Expression> getExpressions() {
return expressions;
}

public CreateStatistics setExpressions(ExpressionList<Expression> expressions) {
this.expressions = expressions;
return this;
}

public Table getTable() {
return table;
}

public CreateStatistics setTable(Table table) {
this.table = table;
return this;
}

public StringBuilder appendTo(StringBuilder sql, Consumer<Expression> printer) {
sql.append("CREATE STATISTICS");
if (ifNotExists) {
sql.append(" IF NOT EXISTS");
}
if (name != null) {
sql.append(' ').append(name);
}
if (kinds != null && !kinds.isEmpty()) {
sql.append(" (");
for (int i = 0; i < kinds.size(); i++) {
if (i > 0) {
sql.append(", ");
}
sql.append(kinds.get(i).name().toLowerCase(java.util.Locale.ROOT));
}
sql.append(')');
}
sql.append(" ON ");
printer.accept(expressions);
return sql.append(" FROM ").append(table);
}

@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);
}
}
14 changes: 14 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

import net.sf.jsqlparser.statement.alter.AlterPolicy;
import net.sf.jsqlparser.statement.drop.DropPolicy;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
import net.sf.jsqlparser.statement.alter.AlterStatistics;
import net.sf.jsqlparser.statement.alter.AlterRelation;
import net.sf.jsqlparser.statement.alter.AlterTablespaceMove;
import net.sf.jsqlparser.statement.alter.database.AlterDatabase;
Expand Down Expand Up @@ -2954,4 +2956,16 @@ public <S> Void visit(DropPolicy statement, S context) {
visit(statement.getTable(), context);
return null;
}

@Override
public <S> Void visit(CreateStatistics statement, S context) {
visit(statement.getTable(), context);
statement.getExpressions().accept(this, context);
return null;
}

@Override
public <S> Void visit(AlterStatistics statement, S context) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

import net.sf.jsqlparser.statement.alter.AlterPolicy;
import net.sf.jsqlparser.statement.drop.DropPolicy;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
import net.sf.jsqlparser.statement.alter.AlterStatistics;
import net.sf.jsqlparser.statement.alter.AlterRelation;
import net.sf.jsqlparser.statement.alter.AlterTablespaceMove;
import net.sf.jsqlparser.statement.alter.database.AlterDatabase;
Expand Down Expand Up @@ -840,4 +842,15 @@ public <S> StringBuilder visit(AlterPolicy statement, S context) {
public <S> StringBuilder visit(DropPolicy statement, S context) {
return statement.appendTo(builder);
}

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

@Override
public <S> StringBuilder visit(AlterStatistics statement, S context) {
return statement.appendTo(builder);
}
}
50 changes: 50 additions & 0 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import net.sf.jsqlparser.statement.create.event.*;
import net.sf.jsqlparser.statement.create.function.*;
import net.sf.jsqlparser.statement.create.index.*;
import net.sf.jsqlparser.statement.create.macro.*;
import net.sf.jsqlparser.statement.create.statistics.CreateStatistics;
import net.sf.jsqlparser.statement.create.policy.*;
import net.sf.jsqlparser.statement.create.procedure.*;
import net.sf.jsqlparser.statement.create.schema.*;
Expand Down Expand Up @@ -18303,6 +18304,8 @@ Statement Alter():
(
<K_ALTER>
(
LOOKAHEAD({ isKeywordAhead("STATISTICS") }) statement = AlterStatistics()
|
LOOKAHEAD(<K_POLICY>) statement = AlterPolicy()
|
LOOKAHEAD({ isKeywordAhead("ROLE") || isKeywordAhead("USER") || isKeywordAhead("GROUP") })
Expand Down Expand Up @@ -19478,6 +19481,8 @@ Statement Create():
{
<K_CREATE> [ <K_OR> <K_REPLACE> { isUsingOrReplace = true; } ]
(
LOOKAHEAD({ isKeywordAhead("STATISTICS") }) statement = CreateStatistics()
|
LOOKAHEAD({ isPostgreSqlRoleAhead() }) statement = CreateRole()
{ requireAccessSyntax(!isUsingOrReplace, "CREATE ROLE does not accept OR REPLACE"); }
|
Expand Down Expand Up @@ -20733,3 +20738,48 @@ String TimeTravelAfterAlias():
return builder.toString();
}
}

CreateStatistics CreateStatistics():
{
CreateStatistics statement = new CreateStatistics();
String name; CreateStatistics.Kind kind; Expression expression; Table table;
}
{
ContextualKeyword("STATISTICS")
[ LOOKAHEAD(2) <K_IF> <K_NOT> <K_EXISTS> { statement.setIfNotExists(true); } ]
[ LOOKAHEAD({ getToken(1).kind != K_ON && getToken(1).kind != OPENING_BRACKET })
name=TypeDdlName() { statement.setName(name); } ]
[ "(" name=RelObjectName() { kind=accessEnum(CreateStatistics.Kind.class,name); statement.getKinds().add(kind); }
( "," name=RelObjectName() { kind=accessEnum(CreateStatistics.Kind.class,name);
requireDdlSyntax(!statement.getKinds().contains(kind),"Duplicate statistics kind"); statement.getKinds().add(kind); } )* ")" ]
<K_ON> expression=PostgreSqlStatisticsExpression() { statement.getExpressions().add(expression); }
( "," expression=PostgreSqlStatisticsExpression() { statement.getExpressions().add(expression); } )*
<K_FROM> table=Table() { statement.setTable(table); }
{
requireDdlSyntax(!statement.isIfNotExists() || statement.getName()!=null,"IF NOT EXISTS requires a statistics name");
requireDdlSyntax(statement.getExpressions().size()>1 || statement.getKinds().isEmpty()
&& statement.getExpressions().get(0) instanceof ParenthesedExpressionList,
"Single-expression statistics require a parenthesized expression and no explicit kinds");
return statement;
}
}
Expression PostgreSqlStatisticsExpression():
{ Expression expression; String name; }
{
( "(" expression=Expression() ")" { expression = new ParenthesedExpressionList<Expression>(expression); }
| name=RelObjectName() { expression = createColumn(name); } )
{ return expression; }
}
AlterStatistics AlterStatistics():
{ AlterStatistics statement = new AlterStatistics(); String name; Long target; }
{
ContextualKeyword("STATISTICS") name=TypeDdlName() { statement.setName(name); }
( <K_RENAME> <K_TO> name=RelObjectName() { statement.setAction(AlterStatistics.Action.RENAME); statement.setNewName(name); }
| ContextualKeyword("OWNER") <K_TO> name=RelObjectName() { statement.setAction(AlterStatistics.Action.OWNER); statement.setOwner(name); }
| <K_SET> ( <K_SCHEMA> name=RelObjectName() { statement.setAction(AlterStatistics.Action.SET_SCHEMA); statement.setSchemaName(name); }
| ContextualKeyword("STATISTICS") { statement.setAction(AlterStatistics.Action.SET_STATISTICS); }
( <K_DEFAULT> | target=SequenceParameterValue() {
requireDdlSyntax(target>=-1 && target<=10000,"Statistics target must be DEFAULT or between -1 and 10000");
statement.setStatistics(target.intValue()); } ) ) )
{ return statement; }
}
Loading
Loading