diff --git a/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java b/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java
index ab25cf3b4..558de06ad 100644
--- a/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java
+++ b/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java
@@ -9,13 +9,32 @@
*/
package net.sf.jsqlparser.statement.analyze;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
public class Analyze implements Statement {
- private Table table;
+ public enum Modifier {
+ NO_WRITE_TO_BINLOG, LOCAL
+ }
+
+ public enum HistogramAction {
+ UPDATE, DROP
+ }
+
+ private final List
tables = new ArrayList<>();
+ private boolean tableKeyword;
+ private Modifier modifier;
+ private HistogramAction histogramAction;
+ private final List histogramColumns = new ArrayList<>();
+ private Integer histogramBucketCount;
@Override
public T accept(StatementVisitor statementVisitor, S context) {
@@ -23,20 +42,134 @@ public T accept(StatementVisitor statementVisitor, S context) {
}
public Table getTable() {
- return table;
+ return tables.isEmpty() ? null : tables.get(0);
}
public void setTable(Table table) {
- this.table = table;
+ tables.clear();
+ if (table != null) {
+ tables.add(table);
+ }
+ }
+
+ public List getTables() {
+ return Collections.unmodifiableList(tables);
+ }
+
+ public void setTables(Collection extends Table> tables) {
+ this.tables.clear();
+ if (tables != null) {
+ this.tables.addAll(tables);
+ }
+ }
+
+ public boolean isTableKeyword() {
+ return tableKeyword;
+ }
+
+ public void setTableKeyword(boolean tableKeyword) {
+ this.tableKeyword = tableKeyword;
+ }
+
+ public Modifier getModifier() {
+ return modifier;
+ }
+
+ public void setModifier(Modifier modifier) {
+ this.modifier = modifier;
+ }
+
+ public HistogramAction getHistogramAction() {
+ return histogramAction;
+ }
+
+ public void setHistogramAction(HistogramAction histogramAction) {
+ this.histogramAction = histogramAction;
+ }
+
+ public List getHistogramColumns() {
+ return Collections.unmodifiableList(histogramColumns);
+ }
+
+ public void setHistogramColumns(Collection extends Column> columns) {
+ histogramColumns.clear();
+ if (columns != null) {
+ histogramColumns.addAll(columns);
+ }
+ }
+
+ public Integer getHistogramBucketCount() {
+ return histogramBucketCount;
+ }
+
+ public void setHistogramBucketCount(Integer histogramBucketCount) {
+ this.histogramBucketCount = histogramBucketCount;
}
@Override
public String toString() {
- return "ANALYZE " + table.toString();
+ StringBuilder builder = new StringBuilder("ANALYZE");
+ if (modifier != null) {
+ builder.append(" ").append(modifier);
+ }
+ if (tableKeyword) {
+ builder.append(" TABLE");
+ }
+ builder.append(" ").append(tables.stream().map(Table::toString)
+ .collect(Collectors.joining(", ")));
+ if (histogramAction != null) {
+ builder.append(" ").append(histogramAction).append(" HISTOGRAM ON ")
+ .append(histogramColumns.stream().map(Column::toString)
+ .collect(Collectors.joining(", ")));
+ if (histogramBucketCount != null) {
+ builder.append(" WITH ").append(histogramBucketCount).append(" BUCKETS");
+ }
+ }
+ return builder.toString();
}
public Analyze withTable(Table table) {
this.setTable(table);
return this;
}
+
+ public Analyze withTables(Collection extends Table> tables) {
+ setTables(tables);
+ return this;
+ }
+
+ public Analyze addTables(Table... tables) {
+ Collections.addAll(this.tables, tables);
+ return this;
+ }
+
+ public Analyze withTableKeyword(boolean tableKeyword) {
+ setTableKeyword(tableKeyword);
+ return this;
+ }
+
+ public Analyze withModifier(Modifier modifier) {
+ setModifier(modifier);
+ return this;
+ }
+
+ public Analyze withHistogramAction(HistogramAction histogramAction) {
+ setHistogramAction(histogramAction);
+ return this;
+ }
+
+ public Analyze withHistogramColumns(Collection extends Column> columns) {
+ setHistogramColumns(columns);
+ return this;
+ }
+
+ public Analyze addHistogramColumns(Column... columns) {
+ Collections.addAll(histogramColumns, columns);
+ return this;
+ }
+
+ public Analyze withHistogramBucketCount(Integer histogramBucketCount) {
+ setHistogramBucketCount(histogramBucketCount);
+ return this;
+ }
}
diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
index b3d1463d0..6fe18f914 100644
--- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
+++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
@@ -1491,7 +1491,7 @@ public void visit(Insert insert) {
@Override
public Void visit(Analyze analyze, S context) {
- visit(analyze.getTable(), context);
+ analyze.getTables().forEach(table -> visit(table, context));
return null;
}
diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java
index 51d06c7f1..bd256c02e 100644
--- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java
+++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java
@@ -263,8 +263,7 @@ public StringBuilder visit(Update update, S context) {
}
public StringBuilder visit(Analyze analyzer, S context) {
- builder.append("ANALYZE ");
- builder.append(analyzer.getTable());
+ builder.append(analyzer);
return builder;
}
diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java
index ac5de0c19..f2f3a1b58 100644
--- a/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java
+++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java
@@ -19,7 +19,8 @@ public class AnalyzeValidator extends AbstractValidator {
public void validate(Analyze analyze) {
for (ValidationCapability c : getCapabilities()) {
validateFeature(c, Feature.analyze);
- validateName(c, NamedObject.table, analyze.getTable().getFullyQualifiedName(), true);
+ analyze.getTables().forEach(table -> validateName(c, NamedObject.table,
+ table.getFullyQualifiedName(), true));
}
}
}
diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
index 52994191b..c8003f881 100644
--- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
+++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
@@ -1488,6 +1488,7 @@ String NonReservedWord() :
| tk=
| tk=
| tk=
+ | tk=
| tk=
| tk=
| tk=
@@ -1592,6 +1593,7 @@ String NonReservedWord() :
| tk=
| tk=
| tk=
+ | tk=
| tk=
| tk=
| tk=
@@ -1666,6 +1668,7 @@ String NonReservedWord() :
| tk=
| tk=
| tk=
+ | tk=
| tk=
| tk=
| tk=
@@ -11958,14 +11961,40 @@ Analyze Analyze():
{
Analyze analyze = new Analyze();
Table table = null;
+ Column column = null;
+ Token modifier = null;
+ Token histogramAction = null;
+ Token bucketCount = null;
}
{
- table=Table()
+ [
+ LOOKAHEAD(2)
+ (modifier= | modifier=)
+ { analyze.setModifier(Analyze.Modifier.valueOf(modifier.image.toUpperCase(Locale.ROOT))); }
+ ]
+ [ LOOKAHEAD(2) { analyze.setTableKeyword(true); } ]
+ table=Table() { analyze.addTables(table); }
+ ( "," table=Table() { analyze.addTables(table); } )*
+ [
+ LOOKAHEAD(2)
+ (histogramAction= | histogramAction=)
+ {
+ analyze.setHistogramAction(Analyze.HistogramAction.valueOf(
+ histogramAction.image.toUpperCase(Locale.ROOT)));
+ }
+
+ column=Column() { analyze.addHistogramColumns(column); }
+ ( "," column=Column() { analyze.addHistogramColumns(column); } )*
+ [
+ LOOKAHEAD(3)
+ bucketCount=
+ { analyze.setHistogramBucketCount(Integer.valueOf(bucketCount.image)); }
+ ]
+ ]
{
- analyze.setTable(table);
- return analyze;
+ return analyze;
}
}
diff --git a/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java b/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java
index 7f19370f4..578e68fd7 100644
--- a/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java
+++ b/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java
@@ -9,17 +9,19 @@
*/
package net.sf.jsqlparser.statement.analyze;
+import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
+import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.StringReader;
+import java.util.List;
+import java.util.stream.Collectors;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
+import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import org.junit.jupiter.api.Test;
-import java.io.StringReader;
-
-import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
-import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
public class AnalyzeTest {
private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
@@ -38,4 +40,47 @@ public void testAnalyze() throws JSQLParserException {
public void testAnalyze2() throws JSQLParserException {
assertSqlCanBeParsedAndDeparsed("ANALYZE mytable");
}
+
+ @Test
+ public void testMySqlAnalyzeTableList() throws JSQLParserException {
+ String sql = "ANALYZE TABLE t2, t3";
+ Analyze analyze = (Analyze) parserManager.parse(new StringReader(sql));
+
+ assertEquals(List.of("t2", "t3"), analyze.getTables().stream()
+ .map(Table::getFullyQualifiedName).collect(Collectors.toList()));
+ assertEquals("t2", analyze.getTable().getFullyQualifiedName());
+ assertEquals(sql, analyze.toString());
+
+ assertDeparse(new Analyze().withTableKeyword(true)
+ .withTables(List.of(new Table("t2"), new Table("t3"))), sql);
+ }
+
+ @Test
+ public void testMySqlAnalyzeUpdateHistogram() throws JSQLParserException {
+ String sql = "ANALYZE TABLE t1 UPDATE HISTOGRAM ON c1, c2 WITH 64 BUCKETS";
+ Analyze analyze = (Analyze) assertSqlCanBeParsedAndDeparsed(sql);
+
+ assertEquals(Analyze.HistogramAction.UPDATE, analyze.getHistogramAction());
+ assertEquals(List.of("c1", "c2"), analyze.getHistogramColumns().stream()
+ .map(Column::getFullyQualifiedName).collect(Collectors.toList()));
+ assertEquals(64, analyze.getHistogramBucketCount());
+ }
+
+ @Test
+ public void testMySqlAnalyzeDropHistogram() throws JSQLParserException {
+ String sql = "ANALYZE LOCAL TABLE t2 DROP HISTOGRAM ON c1";
+ Analyze analyze = (Analyze) assertSqlCanBeParsedAndDeparsed(sql);
+
+ assertEquals(Analyze.Modifier.LOCAL, analyze.getModifier());
+ assertEquals(Analyze.HistogramAction.DROP, analyze.getHistogramAction());
+ assertEquals("c1", analyze.getHistogramColumns().get(0).getFullyQualifiedName());
+ }
+
+ @Test
+ public void testMySqlAnalyzeNoWriteToBinlog() throws JSQLParserException {
+ String sql = "ANALYZE NO_WRITE_TO_BINLOG TABLE t1";
+ Analyze analyze = (Analyze) assertSqlCanBeParsedAndDeparsed(sql);
+
+ assertEquals(Analyze.Modifier.NO_WRITE_TO_BINLOG, analyze.getModifier());
+ }
}