Skip to content

Commit 266da47

Browse files
committed
Fix MySQL SELECT modifier AST and consolidate legacy flags
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 0de0e09 commit 266da47

10 files changed

Lines changed: 390 additions & 86 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ public enum Feature {
796796

797797
// MYSQL
798798

799-
mySqlHintStraightJoin, mysqlSqlCacheFlag, mysqlCalcFoundRows,
799+
mySqlHintStraightJoin, mysqlSqlCacheFlag, mysqlCalcFoundRows, mysqlSelectModifiers,
800800

801801
// SQLSERVER
802802

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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.select;
11+
12+
/**
13+
* MySQL SELECT modifiers, in rendering order. SQL_CACHE is retained for older MySQL releases and
14+
* MariaDB. DISTINCT and ALL remain part of the common SELECT grammar.
15+
*/
16+
public enum MySqlSelectModifier {
17+
HIGH_PRIORITY, STRAIGHT_JOIN, SQL_SMALL_RESULT, SQL_BIG_RESULT, SQL_BUFFER_RESULT, SQL_CACHE, SQL_NO_CACHE, SQL_CALC_FOUND_ROWS
18+
}

‎src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java‎

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
import java.util.Arrays;
1616
import java.util.Collection;
1717
import java.util.Collections;
18+
import java.util.EnumSet;
1819
import java.util.Iterator;
1920
import java.util.List;
2021
import java.util.Optional;
22+
import java.util.Set;
2123
import net.sf.jsqlparser.expression.Alias;
2224
import net.sf.jsqlparser.expression.Expression;
2325
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
@@ -45,14 +47,13 @@ public class PlainSelect extends Select {
4547
private Expression qualify;
4648
private OptimizeFor optimizeFor;
4749
private Skip skip;
48-
private boolean mySqlHintStraightJoin;
50+
private final EnumSet<MySqlSelectModifier> mySqlSelectModifiers =
51+
EnumSet.noneOf(MySqlSelectModifier.class);
4952
private First first;
5053
private Top top;
5154
private OracleHierarchicalExpression oracleHierarchical = null;
5255
private PreferringClause preferringClause = null;
5356
private OracleHint oracleHint = null;
54-
private boolean mySqlSqlCalcFoundRows = false;
55-
private MySqlSqlCacheFlags mySqlCacheFlag = null;
5657
private String forXmlPath;
5758
private KSQLWindow ksqlWindow = null;
5859
private EmitMode emitMode = EmitMode.NONE;
@@ -397,11 +398,11 @@ public void setSkip(Skip skip) {
397398
}
398399

399400
public boolean getMySqlHintStraightJoin() {
400-
return this.mySqlHintStraightJoin;
401+
return mySqlSelectModifiers.contains(MySqlSelectModifier.STRAIGHT_JOIN);
401402
}
402403

403404
public void setMySqlHintStraightJoin(boolean mySqlHintStraightJoin) {
404-
this.mySqlHintStraightJoin = mySqlHintStraightJoin;
405+
setMySqlSelectModifier(MySqlSelectModifier.STRAIGHT_JOIN, mySqlHintStraightJoin);
405406
}
406407

407408
public First getFirst() {
@@ -616,15 +617,11 @@ private void appendSelectClauseTo(StringBuilder builder) {
616617
builder.append("SELECT ");
617618
appendSelectHintsTo(builder);
618619
appendSelectQualifiersTo(builder);
619-
appendMySqlSelectFlagsTo(builder);
620+
appendMySqlSelectModifiersTo(builder);
620621
builder.append(getStringList(selectItems));
621622
}
622623

623624
private void appendSelectHintsTo(StringBuilder builder) {
624-
if (this.mySqlHintStraightJoin) {
625-
builder.append("STRAIGHT_JOIN ");
626-
}
627-
628625
if (oracleHint != null) {
629626
builder.append(oracleHint).append(" ");
630627
}
@@ -659,13 +656,48 @@ private void appendSelectQualifiersTo(StringBuilder builder) {
659656
}
660657
}
661658

662-
private void appendMySqlSelectFlagsTo(StringBuilder builder) {
663-
if (mySqlCacheFlag != null) {
664-
builder.append(mySqlCacheFlag.name()).append(" ");
659+
/** Appends the typed modifiers in MySQL's documented SELECT order. */
660+
public void appendMySqlSelectModifiersTo(StringBuilder builder) {
661+
for (MySqlSelectModifier modifier : mySqlSelectModifiers) {
662+
builder.append(modifier).append(" ");
665663
}
664+
}
665+
666+
/** Returns the modifiers independently of the selected expressions and aliases. */
667+
public Set<MySqlSelectModifier> getMySqlSelectModifiers() {
668+
return Collections.unmodifiableSet(mySqlSelectModifiers);
669+
}
670+
671+
public void setMySqlSelectModifiers(Collection<MySqlSelectModifier> modifiers) {
672+
EnumSet<MySqlSelectModifier> copy = EnumSet.noneOf(MySqlSelectModifier.class);
673+
if (modifiers != null) {
674+
copy.addAll(modifiers);
675+
}
676+
if (copy.contains(MySqlSelectModifier.SQL_CACHE)
677+
&& copy.contains(MySqlSelectModifier.SQL_NO_CACHE)) {
678+
throw new IllegalArgumentException("SQL_CACHE and SQL_NO_CACHE cannot be combined");
679+
}
680+
mySqlSelectModifiers.clear();
681+
mySqlSelectModifiers.addAll(copy);
682+
}
666683

667-
if (mySqlSqlCalcFoundRows) {
668-
builder.append("SQL_CALC_FOUND_ROWS").append(" ");
684+
public PlainSelect addMySqlSelectModifiers(MySqlSelectModifier... modifiers) {
685+
EnumSet<MySqlSelectModifier> copy = mySqlSelectModifiers.clone();
686+
Collections.addAll(copy, modifiers);
687+
setMySqlSelectModifiers(copy);
688+
return this;
689+
}
690+
691+
public PlainSelect withMySqlSelectModifiers(Collection<MySqlSelectModifier> modifiers) {
692+
setMySqlSelectModifiers(modifiers);
693+
return this;
694+
}
695+
696+
private void setMySqlSelectModifier(MySqlSelectModifier modifier, boolean enabled) {
697+
if (enabled) {
698+
mySqlSelectModifiers.add(modifier);
699+
} else {
700+
mySqlSelectModifiers.remove(modifier);
669701
}
670702
}
671703

@@ -759,19 +791,28 @@ public PlainSelect withMySqlSqlNoCache(MySqlSqlCacheFlags mySqlCacheFlag) {
759791
}
760792

761793
public boolean getMySqlSqlCalcFoundRows() {
762-
return this.mySqlSqlCalcFoundRows;
794+
return mySqlSelectModifiers.contains(MySqlSelectModifier.SQL_CALC_FOUND_ROWS);
763795
}
764796

765797
public void setMySqlSqlCalcFoundRows(boolean mySqlCalcFoundRows) {
766-
this.mySqlSqlCalcFoundRows = mySqlCalcFoundRows;
798+
setMySqlSelectModifier(MySqlSelectModifier.SQL_CALC_FOUND_ROWS, mySqlCalcFoundRows);
767799
}
768800

769801
public MySqlSqlCacheFlags getMySqlSqlCacheFlag() {
770-
return this.mySqlCacheFlag;
802+
if (mySqlSelectModifiers.contains(MySqlSelectModifier.SQL_CACHE)) {
803+
return MySqlSqlCacheFlags.SQL_CACHE;
804+
}
805+
return mySqlSelectModifiers.contains(MySqlSelectModifier.SQL_NO_CACHE)
806+
? MySqlSqlCacheFlags.SQL_NO_CACHE
807+
: null;
771808
}
772809

773810
public void setMySqlSqlCacheFlag(MySqlSqlCacheFlags sqlCacheFlag) {
774-
this.mySqlCacheFlag = sqlCacheFlag;
811+
mySqlSelectModifiers.remove(MySqlSelectModifier.SQL_CACHE);
812+
mySqlSelectModifiers.remove(MySqlSelectModifier.SQL_NO_CACHE);
813+
if (sqlCacheFlag != null) {
814+
mySqlSelectModifiers.add(MySqlSelectModifier.valueOf(sqlCacheFlag.name()));
815+
}
775816
}
776817

777818
public PlainSelect withDistinct(Distinct distinct) {

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

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,6 @@ public <S> StringBuilder visit(PlainSelect plainSelect, S context) {
340340
private <S> void deparseSelectClause(PlainSelect plainSelect, S context) {
341341
builder.append("SELECT ");
342342

343-
if (plainSelect.getMySqlHintStraightJoin()) {
344-
builder.append("STRAIGHT_JOIN ");
345-
}
346-
347343
OracleHint hint = plainSelect.getOracleHint();
348344
if (hint != null) {
349345
builder.append(hint).append(" ");
@@ -377,13 +373,7 @@ private <S> void deparseSelectClause(PlainSelect plainSelect, S context) {
377373
visit(top);
378374
}
379375

380-
if (plainSelect.getMySqlSqlCacheFlag() != null) {
381-
builder.append(plainSelect.getMySqlSqlCacheFlag().name()).append(" ");
382-
}
383-
384-
if (plainSelect.getMySqlSqlCalcFoundRows()) {
385-
builder.append("SQL_CALC_FOUND_ROWS").append(" ");
386-
}
376+
plainSelect.appendMySqlSelectModifiersTo(builder);
387377

388378
deparseSelectItemsClause(plainSelect.getSelectItems());
389379

‎src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public enum MariaDbVersion implements Version {
124124
Feature.grant, // https://mariadb.com/kb/en/commit/
125125
Feature.commit, // https://mariadb.com/kb/en/optimizer-hints/
126126
Feature.mySqlHintStraightJoin,
127-
Feature.mysqlCalcFoundRows,
127+
Feature.mysqlSelectModifiers, Feature.mysqlCalcFoundRows,
128128
Feature.mysqlSqlCacheFlag)),
129129

130130
ORACLE_MODE("oracle_mode", V10_5_4.copy().add(Feature.selectUnique).getFeatures());

‎src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java‎

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,10 @@
2424
*/
2525
public enum MySqlVersion implements Version {
2626
V8_0("8.0",
27-
EnumSet.of(
28-
// supported if used with jdbc
27+
EnumSet.of(// supported if used with jdbc
2928
Feature.jdbcParameter,
30-
Feature.jdbcNamedParameter,
31-
// expressions
32-
Feature.exprLike,
33-
// https://dev.mysql.com/doc/refman/8.0/en/select.html
29+
Feature.jdbcNamedParameter, // expressions
30+
Feature.exprLike, // https://dev.mysql.com/doc/refman/8.0/en/select.html
3431
Feature.select,
3532
Feature.selectGroupBy, Feature.selectHaving,
3633
Feature.limit, Feature.limitOffset, Feature.offset, Feature.offsetParam,
@@ -42,8 +39,7 @@ public enum MySqlVersion implements Version {
4239
Feature.selectForShare,
4340
Feature.distinct,
4441

45-
Feature.setOperation,
46-
// https://dev.mysql.com/doc/refman/8.0/en/union.html
42+
Feature.setOperation, // https://dev.mysql.com/doc/refman/8.0/en/union.html
4743
Feature.setOperationUnion,
4844

4945
// https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions
@@ -82,61 +78,43 @@ public enum MySqlVersion implements Version {
8278
// https://dev.mysql.com/doc/refman/8.0/en/call.html
8379
Feature.execute, Feature.executeCall,
8480

85-
Feature.drop,
86-
// https://dev.mysql.com/doc/refman/8.0/en/drop-table.html
87-
Feature.dropTable,
88-
// https://dev.mysql.com/doc/refman/8.0/en/drop-index.html
89-
Feature.dropIndex,
90-
// https://dev.mysql.com/doc/refman/8.0/en/drop-view.html
91-
Feature.dropView,
92-
// https://dev.mysql.com/doc/refman/8.0/en/drop-database.html
81+
Feature.drop, // https://dev.mysql.com/doc/refman/8.0/en/drop-table.html
82+
Feature.dropTable, // https://dev.mysql.com/doc/refman/8.0/en/drop-index.html
83+
Feature.dropIndex, // https://dev.mysql.com/doc/refman/8.0/en/drop-view.html
84+
Feature.dropView, // https://dev.mysql.com/doc/refman/8.0/en/drop-database.html
9385
Feature.dropSchema,
9486
Feature.dropTableIfExists, Feature.dropViewIfExists,
9587
Feature.dropSchemaIfExists, Feature.dropSequenceIfExists,
9688

9789
// https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
98-
Feature.alterTable,
99-
// https://dev.mysql.com/doc/refman/8.0/en/alter-view.html
90+
Feature.alterTable, // https://dev.mysql.com/doc/refman/8.0/en/alter-view.html
10091
Feature.alterView,
10192

10293
// https://dev.mysql.com/doc/refman/8.0/en/create-database.html
103-
Feature.createSchema,
104-
// https://dev.mysql.com/doc/refman/8.0/en/create-view.html
94+
Feature.createSchema, // https://dev.mysql.com/doc/refman/8.0/en/create-view.html
10595
Feature.createView,
10696
Feature.createViewWithComment,
107-
Feature.createOrReplaceView,
108-
// https://dev.mysql.com/doc/refman/8.0/en/create-table.html
97+
Feature.createOrReplaceView, // https://dev.mysql.com/doc/refman/8.0/en/create-table.html
10998
Feature.createTable, Feature.createTableCreateOptionStrings,
11099
Feature.createTableTableOptionStrings,
111-
Feature.createTableFromSelect, Feature.createTableIfNotExists,
112-
// https://dev.mysql.com/doc/refman/8.0/en/create-index.html
113-
Feature.createIndex,
114-
// https://dev.mysql.com/doc/refman/8.0/en/create-trigger.html
100+
Feature.createTableFromSelect, Feature.createTableIfNotExists, // https://dev.mysql.com/doc/refman/8.0/en/create-index.html
101+
Feature.createIndex, // https://dev.mysql.com/doc/refman/8.0/en/create-trigger.html
115102
Feature.createTrigger,
116103

117104
// https://dev.mysql.com/doc/refman/8.0/en/describe.html
118105
Feature.describe,
119-
Feature.desc,
120-
// https://dev.mysql.com/doc/refman/8.0/en/explain.html
121-
Feature.explain,
122-
// https://dev.mysql.com/doc/refman/8.0/en/show.html
123-
Feature.show,
124-
// https://dev.mysql.com/doc/refman/8.0/en/show-tables.html
125-
Feature.showTables,
126-
// https://dev.mysql.com/doc/refman/8.0/en/show-columns.html
127-
Feature.showColumns,
128-
// https://dev.mysql.com/doc/refman/8.0/en/show-index.html
129-
Feature.showIndex,
130-
// https://dev.mysql.com/doc/refman/8.0/en/grant.html
131-
Feature.grant,
132-
// https://dev.mysql.com/doc/refman/8.0/en/use.html
133-
Feature.use,
134-
// https://dev.mysql.com/doc/refman/8.0/en/commit.html
135-
Feature.commit,
136-
//
106+
Feature.desc, // https://dev.mysql.com/doc/refman/8.0/en/explain.html
107+
Feature.explain, // https://dev.mysql.com/doc/refman/8.0/en/show.html
108+
Feature.show, // https://dev.mysql.com/doc/refman/8.0/en/show-tables.html
109+
Feature.showTables, // https://dev.mysql.com/doc/refman/8.0/en/show-columns.html
110+
Feature.showColumns, // https://dev.mysql.com/doc/refman/8.0/en/show-index.html
111+
Feature.showIndex, // https://dev.mysql.com/doc/refman/8.0/en/grant.html
112+
Feature.grant, // https://dev.mysql.com/doc/refman/8.0/en/use.html
113+
Feature.use, // https://dev.mysql.com/doc/refman/8.0/en/commit.html
114+
Feature.commit, //
137115
Feature.mySqlHintStraightJoin,
138116
Feature.mysqlSqlCacheFlag,
139-
Feature.mysqlCalcFoundRows));
117+
Feature.mysqlSelectModifiers, Feature.mysqlCalcFoundRows));
140118

141119
private Set<Feature> features;
142120
private String versionString;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import net.sf.jsqlparser.statement.select.LateralSubSelect;
3030
import net.sf.jsqlparser.statement.select.MinusOp;
3131
import net.sf.jsqlparser.statement.select.MySqlSelectIntoClause;
32+
import net.sf.jsqlparser.statement.select.MySqlSelectModifier;
3233
import net.sf.jsqlparser.statement.select.Offset;
3334
import net.sf.jsqlparser.statement.select.OptionClause;
3435
import net.sf.jsqlparser.statement.select.OptionHint;
@@ -107,6 +108,12 @@ public <S> Void visit(PlainSelect plainSelect, S context) {
107108
validateFeature(c, plainSelect.getMySqlSqlCacheFlag() != null,
108109
Feature.mysqlSqlCacheFlag);
109110
validateFeature(c, plainSelect.getMySqlSqlCalcFoundRows(), Feature.mysqlCalcFoundRows);
111+
validateFeature(c, plainSelect.getMySqlSelectModifiers().stream()
112+
.anyMatch(modifier -> modifier == MySqlSelectModifier.HIGH_PRIORITY
113+
|| modifier == MySqlSelectModifier.SQL_SMALL_RESULT
114+
|| modifier == MySqlSelectModifier.SQL_BIG_RESULT
115+
|| modifier == MySqlSelectModifier.SQL_BUFFER_RESULT),
116+
Feature.mysqlSelectModifiers);
110117
validateOptionalFeature(c, plainSelect.getIntoTables(), Feature.selectInto);
111118
validateOptionalFeature(c, plainSelect.getKsqlWindow(), Feature.kSqlWindow);
112119
validateFeature(c,

0 commit comments

Comments
 (0)