Skip to content

Commit 5320066

Browse files
authored
Model MySQL ANALYZE TABLE statements (#2542)
* feat(parser): model MySQL ANALYZE TABLE * test: keep ANALYZE assertions Java 11 compatible
1 parent a645052 commit 5320066

6 files changed

Lines changed: 224 additions & 17 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java‎

Lines changed: 137 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,167 @@
99
*/
1010
package net.sf.jsqlparser.statement.analyze;
1111

12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.stream.Collectors;
17+
import net.sf.jsqlparser.schema.Column;
1218
import net.sf.jsqlparser.schema.Table;
1319
import net.sf.jsqlparser.statement.Statement;
1420
import net.sf.jsqlparser.statement.StatementVisitor;
1521

1622
public class Analyze implements Statement {
1723

18-
private Table table;
24+
public enum Modifier {
25+
NO_WRITE_TO_BINLOG, LOCAL
26+
}
27+
28+
public enum HistogramAction {
29+
UPDATE, DROP
30+
}
31+
32+
private final List<Table> tables = new ArrayList<>();
33+
private boolean tableKeyword;
34+
private Modifier modifier;
35+
private HistogramAction histogramAction;
36+
private final List<Column> histogramColumns = new ArrayList<>();
37+
private Integer histogramBucketCount;
1938

2039
@Override
2140
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
2241
return statementVisitor.visit(this, context);
2342
}
2443

2544
public Table getTable() {
26-
return table;
45+
return tables.isEmpty() ? null : tables.get(0);
2746
}
2847

2948
public void setTable(Table table) {
30-
this.table = table;
49+
tables.clear();
50+
if (table != null) {
51+
tables.add(table);
52+
}
53+
}
54+
55+
public List<Table> getTables() {
56+
return Collections.unmodifiableList(tables);
57+
}
58+
59+
public void setTables(Collection<? extends Table> tables) {
60+
this.tables.clear();
61+
if (tables != null) {
62+
this.tables.addAll(tables);
63+
}
64+
}
65+
66+
public boolean isTableKeyword() {
67+
return tableKeyword;
68+
}
69+
70+
public void setTableKeyword(boolean tableKeyword) {
71+
this.tableKeyword = tableKeyword;
72+
}
73+
74+
public Modifier getModifier() {
75+
return modifier;
76+
}
77+
78+
public void setModifier(Modifier modifier) {
79+
this.modifier = modifier;
80+
}
81+
82+
public HistogramAction getHistogramAction() {
83+
return histogramAction;
84+
}
85+
86+
public void setHistogramAction(HistogramAction histogramAction) {
87+
this.histogramAction = histogramAction;
88+
}
89+
90+
public List<Column> getHistogramColumns() {
91+
return Collections.unmodifiableList(histogramColumns);
92+
}
93+
94+
public void setHistogramColumns(Collection<? extends Column> columns) {
95+
histogramColumns.clear();
96+
if (columns != null) {
97+
histogramColumns.addAll(columns);
98+
}
99+
}
100+
101+
public Integer getHistogramBucketCount() {
102+
return histogramBucketCount;
103+
}
104+
105+
public void setHistogramBucketCount(Integer histogramBucketCount) {
106+
this.histogramBucketCount = histogramBucketCount;
31107
}
32108

33109
@Override
34110
public String toString() {
35-
return "ANALYZE " + table.toString();
111+
StringBuilder builder = new StringBuilder("ANALYZE");
112+
if (modifier != null) {
113+
builder.append(" ").append(modifier);
114+
}
115+
if (tableKeyword) {
116+
builder.append(" TABLE");
117+
}
118+
builder.append(" ").append(tables.stream().map(Table::toString)
119+
.collect(Collectors.joining(", ")));
120+
if (histogramAction != null) {
121+
builder.append(" ").append(histogramAction).append(" HISTOGRAM ON ")
122+
.append(histogramColumns.stream().map(Column::toString)
123+
.collect(Collectors.joining(", ")));
124+
if (histogramBucketCount != null) {
125+
builder.append(" WITH ").append(histogramBucketCount).append(" BUCKETS");
126+
}
127+
}
128+
return builder.toString();
36129
}
37130

38131
public Analyze withTable(Table table) {
39132
this.setTable(table);
40133
return this;
41134
}
135+
136+
public Analyze withTables(Collection<? extends Table> tables) {
137+
setTables(tables);
138+
return this;
139+
}
140+
141+
public Analyze addTables(Table... tables) {
142+
Collections.addAll(this.tables, tables);
143+
return this;
144+
}
145+
146+
public Analyze withTableKeyword(boolean tableKeyword) {
147+
setTableKeyword(tableKeyword);
148+
return this;
149+
}
150+
151+
public Analyze withModifier(Modifier modifier) {
152+
setModifier(modifier);
153+
return this;
154+
}
155+
156+
public Analyze withHistogramAction(HistogramAction histogramAction) {
157+
setHistogramAction(histogramAction);
158+
return this;
159+
}
160+
161+
public Analyze withHistogramColumns(Collection<? extends Column> columns) {
162+
setHistogramColumns(columns);
163+
return this;
164+
}
165+
166+
public Analyze addHistogramColumns(Column... columns) {
167+
Collections.addAll(histogramColumns, columns);
168+
return this;
169+
}
170+
171+
public Analyze withHistogramBucketCount(Integer histogramBucketCount) {
172+
setHistogramBucketCount(histogramBucketCount);
173+
return this;
174+
}
42175
}

‎src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,7 @@ public void visit(Insert insert) {
14911491

14921492
@Override
14931493
public <S> Void visit(Analyze analyze, S context) {
1494-
visit(analyze.getTable(), context);
1494+
analyze.getTables().forEach(table -> visit(table, context));
14951495
return null;
14961496
}
14971497

‎src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,7 @@ public <S> StringBuilder visit(Update update, S context) {
263263
}
264264

265265
public <S> StringBuilder visit(Analyze analyzer, S context) {
266-
builder.append("ANALYZE ");
267-
builder.append(analyzer.getTable());
266+
builder.append(analyzer);
268267
return builder;
269268
}
270269

‎src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public class AnalyzeValidator extends AbstractValidator<Analyze> {
1919
public void validate(Analyze analyze) {
2020
for (ValidationCapability c : getCapabilities()) {
2121
validateFeature(c, Feature.analyze);
22-
validateName(c, NamedObject.table, analyze.getTable().getFullyQualifiedName(), true);
22+
analyze.getTables().forEach(table -> validateName(c, NamedObject.table,
23+
table.getFullyQualifiedName(), true));
2324
}
2425
}
2526
}

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,7 @@ String NonReservedWord() :
15431543
| tk=<K_BREADTH:"BREADTH">
15441544
| tk=<K_BRANCH:"BRANCH">
15451545
| tk=<K_BROWSE:"BROWSE">
1546+
| tk=<K_BUCKETS:"BUCKETS">
15461547
| tk=<K_BY:"BY">
15471548
| tk=<K_BYTES: "BYTES">
15481549
| tk=<K_CACHE: "CACHE">
@@ -1647,6 +1648,7 @@ String NonReservedWord() :
16471648
| tk=<K_HIGH : "HIGH">
16481649
| tk=<K_HIGH_PRIORITY : "HIGH_PRIORITY">
16491650
| tk=<K_HISTORY : "HISTORY">
1651+
| tk=<K_HISTOGRAM: "HISTOGRAM">
16501652
| tk=<K_HOPPING:"HOPPING">
16511653
| tk=<K_IDENTIFIED:"IDENTIFIED">
16521654
| tk=<K_IDENTITY:"IDENTITY">
@@ -1721,6 +1723,7 @@ String NonReservedWord() :
17211723
| tk=<K_NOCACHE:"NOCACHE">
17221724
| tk=<K_NOKEEP:"NOKEEP">
17231725
| tk=<K_NOLOCK:"NOLOCK">
1726+
| tk=<K_NO_WRITE_TO_BINLOG:"NO_WRITE_TO_BINLOG">
17241727
| tk=<K_NOMAXVALUE:"NOMAXVALUE">
17251728
| tk=<K_NOMINVALUE:"NOMINVALUE">
17261729
| tk=<K_NONE:"NONE">
@@ -12212,14 +12215,40 @@ Analyze Analyze():
1221212215
{
1221312216
Analyze analyze = new Analyze();
1221412217
Table table = null;
12218+
Column column = null;
12219+
Token modifier = null;
12220+
Token histogramAction = null;
12221+
Token bucketCount = null;
1221512222
}
1221612223
{
1221712224
<K_ANALYZE>
12218-
table=Table()
12225+
[
12226+
LOOKAHEAD(2)
12227+
(modifier=<K_NO_WRITE_TO_BINLOG> | modifier=<K_LOCAL>)
12228+
{ analyze.setModifier(Analyze.Modifier.valueOf(modifier.image.toUpperCase(Locale.ROOT))); }
12229+
]
12230+
[ LOOKAHEAD(2) <K_TABLE> { analyze.setTableKeyword(true); } ]
12231+
table=Table() { analyze.addTables(table); }
12232+
( "," table=Table() { analyze.addTables(table); } )*
12233+
[
12234+
LOOKAHEAD(2)
12235+
(histogramAction=<K_UPDATE> | histogramAction=<K_DROP>)
12236+
{
12237+
analyze.setHistogramAction(Analyze.HistogramAction.valueOf(
12238+
histogramAction.image.toUpperCase(Locale.ROOT)));
12239+
}
12240+
<K_HISTOGRAM> <K_ON>
12241+
column=Column() { analyze.addHistogramColumns(column); }
12242+
( "," column=Column() { analyze.addHistogramColumns(column); } )*
12243+
[
12244+
LOOKAHEAD(3)
12245+
<K_WITH> bucketCount=<S_LONG> <K_BUCKETS>
12246+
{ analyze.setHistogramBucketCount(Integer.valueOf(bucketCount.image)); }
12247+
]
12248+
]
1221912249

1222012250
{
12221-
analyze.setTable(table);
12222-
return analyze;
12251+
return analyze;
1222312252
}
1222412253
}
1222512254

‎src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java‎

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@
99
*/
1010
package net.sf.jsqlparser.statement.analyze;
1111

12+
import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
13+
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
16+
import java.io.StringReader;
17+
import java.util.List;
18+
import java.util.stream.Collectors;
1219
import net.sf.jsqlparser.JSQLParserException;
1320
import net.sf.jsqlparser.parser.CCJSqlParserManager;
21+
import net.sf.jsqlparser.schema.Column;
1422
import net.sf.jsqlparser.schema.Table;
1523
import org.junit.jupiter.api.Test;
1624

17-
import java.io.StringReader;
18-
19-
import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
20-
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
21-
import static org.junit.jupiter.api.Assertions.assertEquals;
22-
2325
public class AnalyzeTest {
2426

2527
private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
@@ -38,4 +40,47 @@ public void testAnalyze() throws JSQLParserException {
3840
public void testAnalyze2() throws JSQLParserException {
3941
assertSqlCanBeParsedAndDeparsed("ANALYZE mytable");
4042
}
43+
44+
@Test
45+
public void testMySqlAnalyzeTableList() throws JSQLParserException {
46+
String sql = "ANALYZE TABLE t2, t3";
47+
Analyze analyze = (Analyze) parserManager.parse(new StringReader(sql));
48+
49+
assertEquals(List.of("t2", "t3"), analyze.getTables().stream()
50+
.map(Table::getFullyQualifiedName).collect(Collectors.toList()));
51+
assertEquals("t2", analyze.getTable().getFullyQualifiedName());
52+
assertEquals(sql, analyze.toString());
53+
54+
assertDeparse(new Analyze().withTableKeyword(true)
55+
.withTables(List.of(new Table("t2"), new Table("t3"))), sql);
56+
}
57+
58+
@Test
59+
public void testMySqlAnalyzeUpdateHistogram() throws JSQLParserException {
60+
String sql = "ANALYZE TABLE t1 UPDATE HISTOGRAM ON c1, c2 WITH 64 BUCKETS";
61+
Analyze analyze = (Analyze) assertSqlCanBeParsedAndDeparsed(sql);
62+
63+
assertEquals(Analyze.HistogramAction.UPDATE, analyze.getHistogramAction());
64+
assertEquals(List.of("c1", "c2"), analyze.getHistogramColumns().stream()
65+
.map(Column::getFullyQualifiedName).collect(Collectors.toList()));
66+
assertEquals(64, analyze.getHistogramBucketCount());
67+
}
68+
69+
@Test
70+
public void testMySqlAnalyzeDropHistogram() throws JSQLParserException {
71+
String sql = "ANALYZE LOCAL TABLE t2 DROP HISTOGRAM ON c1";
72+
Analyze analyze = (Analyze) assertSqlCanBeParsedAndDeparsed(sql);
73+
74+
assertEquals(Analyze.Modifier.LOCAL, analyze.getModifier());
75+
assertEquals(Analyze.HistogramAction.DROP, analyze.getHistogramAction());
76+
assertEquals("c1", analyze.getHistogramColumns().get(0).getFullyQualifiedName());
77+
}
78+
79+
@Test
80+
public void testMySqlAnalyzeNoWriteToBinlog() throws JSQLParserException {
81+
String sql = "ANALYZE NO_WRITE_TO_BINLOG TABLE t1";
82+
Analyze analyze = (Analyze) assertSqlCanBeParsedAndDeparsed(sql);
83+
84+
assertEquals(Analyze.Modifier.NO_WRITE_TO_BINLOG, analyze.getModifier());
85+
}
4186
}

0 commit comments

Comments
 (0)