Skip to content

Commit 7048831

Browse files
committed
Add support MySQL functional index key parts in ALTER/CREATE INDEX
1 parent 126c1a1 commit 7048831

File tree

11 files changed

+179
-22
lines changed

11 files changed

+179
-22
lines changed

src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import static java.util.stream.Collectors.joining;
1313

1414
import java.util.*;
15-
1615
import net.sf.jsqlparser.schema.*;
1716
import net.sf.jsqlparser.statement.*;
1817
import net.sf.jsqlparser.statement.create.table.*;
@@ -106,9 +105,7 @@ public String toString() {
106105

107106
buffer.append(
108107
index.getColumns().stream()
109-
.map(cp -> cp.columnName + (cp.getParams() != null
110-
? " " + String.join(" ", cp.getParams())
111-
: ""))
108+
.map(Index.ColumnParams::toString)
112109
.collect(joining(", ")));
113110

114111
buffer.append(")");

src/main/java/net/sf/jsqlparser/statement/create/table/Index.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import java.util.Collections;
1818
import java.util.List;
1919
import java.util.Optional;
20-
20+
import net.sf.jsqlparser.expression.Expression;
2121
import net.sf.jsqlparser.statement.select.PlainSelect;
2222

2323
public class Index implements Serializable {
@@ -32,7 +32,7 @@ public class Index implements Serializable {
3232

3333
public List<String> getColumnsNames() {
3434
return columns.stream()
35-
.map(col -> col.columnName)
35+
.map(ColumnParams::getColumnName)
3636
.collect(toList());
3737
}
3838

@@ -202,28 +202,52 @@ public void setCommentText(String commentText) {
202202
public static class ColumnParams implements Serializable {
203203
public final String columnName;
204204
public final List<String> params;
205+
private final Expression expression;
205206

206207
public ColumnParams(String columnName) {
207208
this.columnName = columnName;
208209
this.params = null;
210+
this.expression = null;
209211
}
210212

211213
public ColumnParams(String columnName, List<String> params) {
212214
this.columnName = columnName;
213215
this.params = params;
216+
this.expression = null;
217+
}
218+
219+
public ColumnParams(Expression expression) {
220+
this.columnName = null;
221+
this.params = null;
222+
this.expression = expression;
223+
}
224+
225+
public ColumnParams(Expression expression, List<String> params) {
226+
this.columnName = null;
227+
this.params = params;
228+
this.expression = expression;
214229
}
215230

216231
public String getColumnName() {
217-
return columnName;
232+
return expression != null ? expression.toString() : columnName;
218233
}
219234

220235
public List<String> getParams() {
221236
return params;
222237
}
223238

239+
public Expression getExpression() {
240+
return expression;
241+
}
242+
243+
public boolean isExpression() {
244+
return expression != null;
245+
}
246+
224247
@Override
225248
public String toString() {
226-
return columnName + (params != null ? " " + String.join(" ", params) : "");
249+
String head = expression != null ? "(" + expression + ")" : columnName;
250+
return head + (params != null ? " " + String.join(" ", params) : "");
227251
}
228252
}
229253
}

src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ public void deParse(CreateIndex createIndex) {
5454
if (index.getColumnsNames() != null) {
5555
builder.append(" (");
5656
builder.append(index.getColumnWithParams().stream()
57-
.map(cp -> cp.columnName
58-
+ (cp.getParams() != null ? " " + String.join(" ", cp.getParams())
59-
: ""))
57+
.map(Index.ColumnParams::toString)
6058
.collect(joining(", ")));
6159
builder.append(")");
6260
}

src/main/java/net/sf/jsqlparser/util/validation/validator/AlterValidator.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
*/
1010
package net.sf.jsqlparser.util.validation.validator;
1111

12-
import java.util.EnumSet;
12+
import static java.util.stream.Collectors.toList;
1313

14+
import java.util.EnumSet;
1415
import net.sf.jsqlparser.parser.feature.Feature;
1516
import net.sf.jsqlparser.statement.alter.Alter;
1617
import net.sf.jsqlparser.statement.alter.AlterExpression;
@@ -74,7 +75,11 @@ public void validate(Alter alter, AlterExpression e) {
7475
if (e.getIndex() != null) {
7576
validateName(c, NamedObject.index, e.getIndex().getName());
7677
if (e.getIndex().getColumns() != null) {
77-
validateOptionalColumnNames(c, e.getIndex().getColumnsNames(),
78+
validateOptionalColumnNames(c,
79+
e.getIndex().getColumns().stream()
80+
.filter(cp -> !cp.isExpression())
81+
.map(cp -> cp.getColumnName())
82+
.collect(toList()),
7883
NamedObject.index);
7984
}
8085
}

src/main/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidator.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
*/
1010
package net.sf.jsqlparser.util.validation.validator;
1111

12+
import static java.util.stream.Collectors.toList;
13+
1214
import net.sf.jsqlparser.parser.feature.Feature;
1315
import net.sf.jsqlparser.statement.create.index.CreateIndex;
1416
import net.sf.jsqlparser.statement.create.table.Index;
15-
import net.sf.jsqlparser.util.validation.metadata.NamedObject;
1617
import net.sf.jsqlparser.util.validation.ValidationCapability;
18+
import net.sf.jsqlparser.util.validation.metadata.NamedObject;
1719

1820
/**
1921
* @author gitmotte
@@ -27,7 +29,14 @@ public void validate(CreateIndex createIndex) {
2729
validateFeature(c, Feature.createIndex);
2830
validateName(c, NamedObject.table, createIndex.getTable().getFullyQualifiedName());
2931
validateName(c, NamedObject.index, index.getName(), false);
30-
validateOptionalColumnNames(c, index.getColumnsNames(), NamedObject.table);
32+
if (index.getColumns() != null) {
33+
validateOptionalColumnNames(c,
34+
index.getColumns().stream()
35+
.filter(cp -> !cp.isExpression())
36+
.map(Index.ColumnParams::getColumnName)
37+
.collect(toList()),
38+
NamedObject.table);
39+
}
3140
}
3241
}
3342

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

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9206,6 +9206,57 @@ List<Index.ColumnParams> ColumnNamesWithParamsList() : {
92069206
{ return colNames; }
92079207
}
92089208

9209+
Index.ColumnParams IndexColumnWithParams(): {
9210+
String columnName = null;
9211+
List<String> parameter = null;
9212+
Expression expression = null;
9213+
Index.ColumnParams column = null;
9214+
}
9215+
{
9216+
(
9217+
columnName=RelObjectName()
9218+
{ parameter = null; }
9219+
[ parameter = CreateParameter() ]
9220+
{
9221+
column = new Index.ColumnParams(columnName, parameter);
9222+
}
9223+
|
9224+
"(" expression=Expression() ")"
9225+
{ parameter = null; }
9226+
[ LOOKAHEAD(2) parameter = CreateParameter() ]
9227+
{
9228+
column = new Index.ColumnParams(expression, parameter);
9229+
}
9230+
)
9231+
{
9232+
return column;
9233+
}
9234+
}
9235+
9236+
List<Index.ColumnParams> IndexColumnsWithParamsList() : {
9237+
List<Index.ColumnParams> colNames = new ArrayList<Index.ColumnParams>();
9238+
Index.ColumnParams column = null;
9239+
}
9240+
{
9241+
"("
9242+
column=IndexColumnWithParams()
9243+
{
9244+
colNames.add(column);
9245+
}
9246+
9247+
(
9248+
","
9249+
column=IndexColumnWithParams()
9250+
{
9251+
colNames.add(column);
9252+
}
9253+
)*
9254+
9255+
")"
9256+
9257+
{ return colNames; }
9258+
}
9259+
92099260
Index Index(): {
92109261
ObjectNames name;
92119262
}
@@ -9245,7 +9296,7 @@ CreateIndex CreateIndex():
92459296
<K_ON> table=Table()
92469297
)
92479298
)
9248-
colNames = ColumnNamesWithParamsList()
9299+
colNames = IndexColumnsWithParamsList()
92499300
( LOOKAHEAD(2) parameter=CreateParameter() { tailParameters.addAll(parameter); } )*
92509301
{
92519302
index.setColumns(colNames);
@@ -9404,7 +9455,7 @@ CreateTable CreateTable(boolean isUsingOrReplace):
94049455
}
94059456
tk=<K_INDEX>
94069457
sk3=RelObjectName()
9407-
colNames = ColumnNamesWithParamsList()
9458+
colNames = IndexColumnsWithParamsList()
94089459
( parameter=CreateParameter() { idxSpec.addAll(parameter); } )*
94099460
{
94109461
index = new Index().withType(tk.image).withName(sk3).withColumns(colNames).withIndexSpec(new ArrayList<String>(idxSpec));
@@ -9447,7 +9498,7 @@ CreateTable CreateTable(boolean isUsingOrReplace):
94479498
[ tk=<K_UNIQUE> ]
94489499
[ tk3=<K_FULLTEXT> | tk3=<K_SPATIAL> ] tk2=<K_KEY>
94499500
sk3=RelObjectName()
9450-
colNames = ColumnNamesWithParamsList()
9501+
colNames = IndexColumnsWithParamsList()
94519502
( parameter=CreateParameter() { idxSpec.addAll(parameter); } )*
94529503
{
94539504
index = new Index()
@@ -10377,6 +10428,7 @@ AlterExpression AlterExpression():
1037710428
String sk4 = null;
1037810429
ColDataType dataType;
1037910430
List<String> columnNames = null;
10431+
List<Index.ColumnParams> indexColumnNames = null;
1038010432
List<ConstraintState> constraints = null;
1038110433
ForeignKeyIndex fkIndex = null;
1038210434
Index index = null;
@@ -10426,18 +10478,18 @@ AlterExpression AlterExpression():
1042610478
LOOKAHEAD(3)
1042710479
sk3 = RelObjectName()
1042810480
[ LOOKAHEAD(2) sk4 = UsingIndexType() ]
10429-
[ LOOKAHEAD(2) columnNames = ColumnsNamesList() ]
10481+
[ LOOKAHEAD(2) indexColumnNames = IndexColumnsWithParamsList() ]
1043010482
|
1043110483
[ LOOKAHEAD(2) sk4 = UsingIndexType() ]
10432-
[ LOOKAHEAD(2) columnNames = ColumnsNamesList() ]
10484+
[ LOOKAHEAD(2) indexColumnNames = IndexColumnsWithParamsList() ]
1043310485
)
1043410486
IndexOptionList(indexSpec = new ArrayList<String>())
1043510487
{
1043610488
index = new Index()
1043710489
.withIndexKeyword(tk.image)
1043810490
.withName(sk3)
1043910491
.withUsing(sk4)
10440-
.withColumnsNames(columnNames)
10492+
.withColumns(indexColumnNames)
1044110493
.withIndexSpec(indexSpec);
1044210494

1044310495
alterExp.setIndex(index);

src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,6 +2036,33 @@ public void testAlterTableAddIndex_UsingBeforeColumns() throws JSQLParserExcepti
20362036
assertSqlCanBeParsedAndDeparsed(sql);
20372037
}
20382038

2039+
@Test
2040+
public void testAlterTableAddFunctionalIndexes() throws JSQLParserException {
2041+
String sql = "ALTER TABLE PPK_OLPN ADD INDEX fAdd ((b + c)), "
2042+
+ "ADD INDEX fCoalesce ((COALESCE(PK, b)) DESC)";
2043+
2044+
Alter alter = (Alter) CCJSqlParserUtil.parse(sql);
2045+
assertEquals("PPK_OLPN", alter.getTable().getFullyQualifiedName());
2046+
assertEquals(2, alter.getAlterExpressions().size());
2047+
2048+
AlterExpression addExpression = alter.getAlterExpressions().get(0);
2049+
assertEquals(AlterOperation.ADD, addExpression.getOperation());
2050+
assertEquals("fAdd", addExpression.getIndex().getName());
2051+
assertTrue(addExpression.getIndex().getColumns().get(0).isExpression());
2052+
assertEquals("b + c", addExpression.getIndex().getColumns().get(0).getColumnName());
2053+
2054+
AlterExpression coalesceExpression = alter.getAlterExpressions().get(1);
2055+
assertEquals(AlterOperation.ADD, coalesceExpression.getOperation());
2056+
assertEquals("fCoalesce", coalesceExpression.getIndex().getName());
2057+
assertTrue(coalesceExpression.getIndex().getColumns().get(0).isExpression());
2058+
assertEquals("COALESCE(PK, b)",
2059+
coalesceExpression.getIndex().getColumns().get(0).getColumnName());
2060+
assertEquals(List.of("DESC"),
2061+
coalesceExpression.getIndex().getColumns().get(0).getParams());
2062+
2063+
assertSqlCanBeParsedAndDeparsed(sql);
2064+
}
2065+
20392066
@Test
20402067
public void testAlterTableSetDefaultWithAlgorithm() throws JSQLParserException {
20412068
String sql = "ALTER TABLE t2 ALTER COLUMN b SET DEFAULT 100, ALGORITHM = INSTANT";

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
1313
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertNotNull;
1415
import static org.junit.jupiter.api.Assertions.assertNull;
16+
import static org.junit.jupiter.api.Assertions.assertTrue;
1517

1618
import java.io.StringReader;
1719
import java.util.List;
@@ -148,4 +150,22 @@ void testCreateIndexIssue1814() throws JSQLParserException {
148150
"CREATE INDEX idx_operationlog_operatetime_regioncode USING BTREE ON operation_log (operate_time,region_biz_code)";
149151
assertSqlCanBeParsedAndDeparsed(sqlStr, true);
150152
}
153+
154+
@Test
155+
public void testCreateIndexWithFunctionalKeyParts() throws JSQLParserException {
156+
String statement =
157+
"CREATE INDEX fAdd ON PPK_OLPN ((b + c), (COALESCE(PK, b)) DESC)";
158+
CreateIndex createIndex = (CreateIndex) parserManager.parse(new StringReader(statement));
159+
160+
assertEquals(2, createIndex.getIndex().getColumns().size());
161+
assertTrue(createIndex.getIndex().getColumns().get(0).isExpression());
162+
assertEquals("b + c", createIndex.getIndex().getColumns().get(0).getColumnName());
163+
assertTrue(createIndex.getIndex().getColumns().get(1).isExpression());
164+
assertEquals("COALESCE(PK, b)", createIndex.getIndex().getColumns().get(1).getColumnName());
165+
assertNotNull(createIndex.getIndex().getColumns().get(1).getParams());
166+
assertEquals("DESC", createIndex.getIndex().getColumns().get(1).getParams().get(0));
167+
assertEquals(statement, createIndex.toString());
168+
169+
assertSqlCanBeParsedAndDeparsed(statement);
170+
}
151171
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,24 @@ public void testCreateTableIssue924_2() throws JSQLParserException {
807807
"CREATE TABLE test_descending_indexes (c1 INT, c2 INT, INDEX idx1 (c1 ASC, c2 ASC), INDEX idx2 (c1 ASC, c2 DESC), INDEX idx3 (c1 DESC, c2 ASC), INDEX idx4 (c1 DESC, c2 DESC))");
808808
}
809809

810+
@Test
811+
public void testCreateTableWithFunctionalIndex() throws JSQLParserException {
812+
String sql =
813+
"CREATE TABLE t (PK INT, b INT, c INT, INDEX fAdd ((b + c), (COALESCE(PK, b)) DESC))";
814+
CreateTable createTable = (CreateTable) CCJSqlParserUtil.parse(sql);
815+
816+
assertNotNull(createTable.getIndexes());
817+
assertEquals(1, createTable.getIndexes().size());
818+
assertEquals("fAdd", createTable.getIndexes().get(0).getName());
819+
assertTrue(createTable.getIndexes().get(0).getColumns().get(0).isExpression());
820+
assertEquals("b + c", createTable.getIndexes().get(0).getColumns().get(0).getColumnName());
821+
assertTrue(createTable.getIndexes().get(0).getColumns().get(1).isExpression());
822+
assertEquals("COALESCE(PK, b)",
823+
createTable.getIndexes().get(0).getColumns().get(1).getColumnName());
824+
825+
assertSqlCanBeParsedAndDeparsed(sql);
826+
}
827+
810828
@Test
811829
public void testCreateTableIssue921() throws JSQLParserException {
812830
String statement = "CREATE TABLE binary_test (c1 binary (10))";

src/test/java/net/sf/jsqlparser/util/validation/validator/AlterValidatorTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public void testAlterTableAddColumn_ColumnKeyWordImplicit() throws JSQLParserExc
2828
validateNoErrors(sql, 1, DatabaseType.DATABASES);
2929
}
3030

31+
@Test
32+
public void testAlterTableAddFunctionalIndex() throws JSQLParserException {
33+
String sql = "ALTER TABLE PPK_OLPN ADD INDEX fAdd ((b + c))";
34+
validateNoErrors(sql, 1, DatabaseType.DATABASES);
35+
}
36+
3137
@Test
3238
public void testAlterTablePrimaryKey() throws JSQLParserException {
3339
validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id)", 1, DatabaseType.DATABASES);

0 commit comments

Comments
 (0)