Skip to content

Commit 9f72b55

Browse files
committed
fix(parser): support MySQL index options in CREATE INDEX and DROP INDEX
Several valid MySQL index DDL statements were rejected because their option keywords are tokens of their own and were therefore not reachable from the option lists that CREATE INDEX and DROP INDEX use: CREATE INDEX i ON t (c1) KEY_BLOCK_SIZE = 8 CREATE INDEX i ON t (c1) ALGORITHM = INPLACE LOCK = NONE CREATE FULLTEXT INDEX i ON t (body) WITH PARSER ngram CREATE SPATIAL INDEX i ON t (g) DROP INDEX i ON t ALGORITHM = INPLACE LOCK = NONE The keywords are added to the existing flat token lists of CreateParameter() and Drop() rather than as new grammar alternatives, so no new choice is introduced and the JavaCC warning count is unchanged. LOCK is the one exception: it also starts a LOCK TABLE statement, so taking it unconditionally as a DROP argument would be ambiguous with the next statement. It is guarded by a semantic lookahead that only accepts it when it is not followed by TABLE. Refs #2490
1 parent 39bd1f6 commit 9f72b55

3 files changed

Lines changed: 68 additions & 0 deletions

File tree

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11863,6 +11863,11 @@ List<String> CreateParameter():
1186311863
| tk=<K_TIME_KEY_EXPR> | tk=<K_RAW> | tk=<K_HASH> | tk=<K_FIRST> | tk=<K_LAST> | tk = <K_SIGNED> | tk = <K_UNSIGNED>
1186411864
| tk=<K_ENGINE> | tk=<K_IDENTITY> | tk=<K_MATERIALIZED> | tk=<K_SAMPLE> | tk=<K_ALWAYS>
1186511865
| tk=<K_VISIBLE> | tk=<K_INVISIBLE>
11866+
// MySQL index_option / algorithm_option / lock_option keywords, e.g. the trailing
11867+
// "KEY_BLOCK_SIZE = 8 ALGORITHM = INPLACE LOCK = NONE" of CREATE INDEX, the
11868+
// "WITH PARSER" option, and the FULLTEXT / SPATIAL index types of CREATE INDEX.
11869+
| tk=<K_KEY_BLOCK_SIZE> | tk=<K_ALGORITHM> | tk=<K_LOCK> | tk=<K_NONE>
11870+
| tk=<K_PARSER> | tk=<K_FULLTEXT> | tk=<K_SPATIAL>
1186611871
| tk="="
1186711872
)
1186811873
{ param.add(tk.image); }
@@ -12038,11 +12043,19 @@ Drop Drop():
1203812043
(
1203912044
(
1204012045
tk=<S_IDENTIFIER> | tk=<K_CASCADE> | tk=<K_RESTRICT>
12046+
// MySQL DROP INDEX accepts a trailing algorithm_option / lock_option,
12047+
// e.g. "DROP INDEX i ON t ALGORITHM = INPLACE LOCK = NONE".
12048+
| tk=<K_ALGORITHM> | tk=<K_NONE> | tk="="
1204112049
) { dropArgs.add(tk.image); }
1204212050
|
1204312051
(
1204412052
<K_ON> name = Table() { dropArgs.add("ON"); dropArgs.add(name.toString()); }
1204512053
)
12054+
|
12055+
// The lock_option of DROP INDEX. LOCK also starts a LOCK TABLE statement, so it is only
12056+
// taken as a DROP argument when it cannot be the beginning of the next statement.
12057+
LOOKAHEAD({ getToken(1).kind == K_LOCK && getToken(2).kind != K_TABLE })
12058+
tk=<K_LOCK> { dropArgs.add(tk.image); }
1204612059
)*
1204712060
{
1204812061
if (dropArgs.size() > 0) {

src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,42 @@ public void testCreateIndexKeyPartWithPrefixLengthAndDirectionIssue2490()
196196
assertSqlCanBeParsedAndDeparsed("CREATE INDEX i04 ON t (c1 (20) ASC, c2 (10) DESC)");
197197
assertSqlCanBeParsedAndDeparsed("CREATE UNIQUE INDEX i25 ON t (c1 (10) DESC)");
198198
}
199+
200+
@Test
201+
public void testCreateIndexKeyBlockSizeIssue2490() throws JSQLParserException {
202+
assertSqlCanBeParsedAndDeparsed("CREATE INDEX i08 ON t (c1) KEY_BLOCK_SIZE = 8");
203+
assertSqlCanBeParsedAndDeparsed("CREATE INDEX i09 ON t (c1) KEY_BLOCK_SIZE 8");
204+
assertSqlCanBeParsedAndDeparsed(
205+
"CREATE INDEX i14 ON t (c1) USING BTREE KEY_BLOCK_SIZE = 8 COMMENT 'combo' INVISIBLE");
206+
}
207+
208+
@Test
209+
public void testCreateIndexAlgorithmAndLockOptionsIssue2490() throws JSQLParserException {
210+
assertSqlCanBeParsedAndDeparsed(
211+
"CREATE INDEX i10 ON t (c1) ALGORITHM = INPLACE LOCK = NONE");
212+
assertSqlCanBeParsedAndDeparsed("CREATE INDEX i11 ON t (c1) ALGORITHM INPLACE LOCK NONE");
213+
assertSqlCanBeParsedAndDeparsed("CREATE INDEX i12 ON t (c1) ALGORITHM = INPLACE");
214+
assertSqlCanBeParsedAndDeparsed("CREATE INDEX i13 ON t (c1) LOCK = NONE");
215+
216+
CreateIndex createIndex = (CreateIndex) parserManager
217+
.parse(new StringReader("CREATE INDEX i10 ON t (c1) ALGORITHM=INPLACE LOCK=NONE"));
218+
assertEquals(List.of("ALGORITHM", "=", "INPLACE", "LOCK", "=", "NONE"),
219+
createIndex.getTailParameters());
220+
}
221+
222+
@Test
223+
public void testCreateFullTextAndSpatialIndexIssue2490() throws JSQLParserException {
224+
// These used to fall back to UnsupportedStatement instead of producing a CreateIndex.
225+
CreateIndex fullText = (CreateIndex) parserManager
226+
.parse(new StringReader("CREATE FULLTEXT INDEX i17 ON t (body)"));
227+
assertEquals("FULLTEXT", fullText.getIndex().getType());
228+
229+
CreateIndex spatial = (CreateIndex) parserManager
230+
.parse(new StringReader("CREATE SPATIAL INDEX i19 ON t (g)"));
231+
assertEquals("SPATIAL", spatial.getIndex().getType());
232+
233+
assertSqlCanBeParsedAndDeparsed("CREATE FULLTEXT INDEX i17 ON t (body)");
234+
assertSqlCanBeParsedAndDeparsed("CREATE FULLTEXT INDEX i18 ON t (body) WITH PARSER ngram");
235+
assertSqlCanBeParsedAndDeparsed("CREATE SPATIAL INDEX i19 ON t (g)");
236+
}
199237
}

src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import java.io.StringReader;
1313
import net.sf.jsqlparser.JSQLParserException;
1414
import net.sf.jsqlparser.parser.CCJSqlParserManager;
15+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
1516
import net.sf.jsqlparser.schema.Table;
1617
import net.sf.jsqlparser.statement.Statement;
18+
import net.sf.jsqlparser.statement.Statements;
1719
import static net.sf.jsqlparser.test.TestUtils.*;
1820
import static org.junit.jupiter.api.Assertions.assertEquals;
1921
import org.junit.jupiter.api.Test;
@@ -152,4 +154,19 @@ void dropTemporaryTableTestIssue1712() throws JSQLParserException {
152154
String sqlStr = "drop temporary table if exists tmp_MwYT8N0z";
153155
assertSqlCanBeParsedAndDeparsed(sqlStr, true);
154156
}
157+
158+
@Test
159+
public void testDropIndexAlgorithmAndLockOptionsIssue2490() throws JSQLParserException {
160+
assertSqlCanBeParsedAndDeparsed("DROP INDEX i15 ON t ALGORITHM = INPLACE LOCK = NONE");
161+
assertSqlCanBeParsedAndDeparsed("DROP INDEX i16 ON t ALGORITHM INPLACE");
162+
assertSqlCanBeParsedAndDeparsed("DROP INDEX i17 ON t LOCK = NONE");
163+
}
164+
165+
@Test
166+
public void testDropTableFollowedByLockTableIssue2490() throws JSQLParserException {
167+
// LOCK must not be swallowed as a DROP argument when it starts the next statement.
168+
Statements statements = CCJSqlParserUtil.parseStatements(
169+
"DROP TABLE t1; LOCK TABLE t2 IN SHARE MODE;");
170+
assertEquals(2, statements.size());
171+
}
155172
}

0 commit comments

Comments
 (0)