Skip to content

Commit 8b4149b

Browse files
minleejaemj-db
andauthored
Fix issue 2089: Enhance MySQL CONVERT Statement Parsing (#2117)
* fix convert toString * fix mysql convert --------- Co-authored-by: mj-db <[email protected]>
1 parent fee2f90 commit 8b4149b

File tree

3 files changed

+116
-29
lines changed

3 files changed

+116
-29
lines changed

src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java

+51
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public class AlterExpression implements Serializable {
5353
private List<PartitionDefinition> partitionDefinitions;
5454
private List<ConstraintState> constraints;
5555
private List<String> parameters;
56+
57+
private ConvertType convertType;
58+
private boolean hasEqualForCharacterSet;
59+
private boolean hasEqualForCollate;
60+
5661
private String characterSet;
5762
private String collation;
5863
private String lockOption;
@@ -401,6 +406,14 @@ public List<String> getParameters() {
401406
return parameters;
402407
}
403408

409+
public ConvertType getConvertType() {
410+
return convertType;
411+
}
412+
413+
public void setConvertType(ConvertType convertType) {
414+
this.convertType = convertType;
415+
}
416+
404417
public String getCharacterSet() {
405418
return characterSet;
406419
}
@@ -485,6 +498,32 @@ public String toString() {
485498
} else if (operation == AlterOperation.DROP_PRIMARY_KEY) {
486499

487500
b.append("DROP PRIMARY KEY ");
501+
} else if (operation == AlterOperation.CONVERT) {
502+
if (convertType == ConvertType.CONVERT_TO) {
503+
b.append("CONVERT TO CHARACTER SET ");
504+
} else if (convertType == ConvertType.DEFAULT_CHARACTER_SET) {
505+
b.append("DEFAULT CHARACTER SET ");
506+
if (hasEqualForCharacterSet) {
507+
b.append("= ");
508+
}
509+
} else if (convertType == ConvertType.CHARACTER_SET) {
510+
b.append("CHARACTER SET ");
511+
if (hasEqualForCharacterSet) {
512+
b.append("= ");
513+
}
514+
}
515+
516+
if (getCharacterSet() != null) {
517+
b.append(getCharacterSet());
518+
}
519+
520+
if (getCollation() != null) {
521+
b.append(" COLLATE ");
522+
if (hasEqualForCollate) {
523+
b.append("= ");
524+
}
525+
b.append(getCollation());
526+
}
488527
} else if (operation == AlterOperation.DROP_UNIQUE) {
489528

490529
b.append("DROP UNIQUE (").append(PlainSelect.getStringList(pkColumns)).append(')');
@@ -797,6 +836,14 @@ public void setPartitionDefinitions(List<PartitionDefinition> partitionDefinitio
797836
this.partitionDefinitions = partitionDefinition;
798837
}
799838

839+
public void setHasEqualForCharacterSet(boolean hasEqualForCharacterSet) {
840+
this.hasEqualForCharacterSet = hasEqualForCharacterSet;
841+
}
842+
843+
public void setHasEqualForCollate(boolean hasEqualForCollate) {
844+
this.hasEqualForCollate = hasEqualForCollate;
845+
}
846+
800847
public static final class ColumnDataType extends ColumnDefinition {
801848

802849
private final boolean withType;
@@ -890,4 +937,8 @@ public String toString() {
890937
return columnName + " DROP DEFAULT";
891938
}
892939
}
940+
941+
public enum ConvertType {
942+
CONVERT_TO, DEFAULT_CHARACTER_SET, CHARACTER_SET
943+
}
893944
}

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

+23-3
Original file line numberDiff line numberDiff line change
@@ -7430,11 +7430,31 @@ AlterExpression AlterExpression():
74307430
<K_RENAME> <K_TO> {alterExp.setOperation(AlterOperation.RENAME_TABLE);}
74317431
(tk2=<S_IDENTIFIER> | tk2=<S_QUOTED_IDENTIFIER>) { alterExp.setNewTableName(tk2.image);}
74327432
)
7433-
|
7434-
(<K_CONVERT> { alterExp.setOperation(AlterOperation.CONVERT); }
7433+
| (<K_CONVERT> {
7434+
alterExp.setOperation(AlterOperation.CONVERT);
7435+
alterExp.setConvertType(AlterExpression.ConvertType.CONVERT_TO);
7436+
}
74357437
<K_TO> <K_CHARACTER> <K_SET> tk=<S_IDENTIFIER> { alterExp.setCharacterSet(tk.image); }
74367438
[<K_COLLATE> tk2=<S_IDENTIFIER> { alterExp.setCollation(tk2.image); }]
7437-
)
7439+
)
7440+
| (<K_DEFAULT> {
7441+
alterExp.setOperation(AlterOperation.CONVERT);
7442+
alterExp.setConvertType(AlterExpression.ConvertType.DEFAULT_CHARACTER_SET);
7443+
}
7444+
<K_CHARACTER> <K_SET> [ "=" { alterExp.setHasEqualForCharacterSet(true); } ]
7445+
tk=<S_IDENTIFIER> { alterExp.setCharacterSet(tk.image); }
7446+
[<K_COLLATE> [ "=" { alterExp.setHasEqualForCollate(true); } ]
7447+
tk2=<S_IDENTIFIER> { alterExp.setCollation(tk2.image); }]
7448+
)
7449+
| (<K_CHARACTER> <K_SET> [ "=" { alterExp.setHasEqualForCharacterSet(true); } ]
7450+
tk=<S_IDENTIFIER> {
7451+
alterExp.setOperation(AlterOperation.CONVERT);
7452+
alterExp.setConvertType(AlterExpression.ConvertType.CHARACTER_SET);
7453+
alterExp.setCharacterSet(tk.image);
7454+
}
7455+
[<K_COLLATE> [ "=" { alterExp.setHasEqualForCollate(true); } ]
7456+
tk2=<S_IDENTIFIER> { alterExp.setCollation(tk2.image); }]
7457+
)
74387458
|
74397459
(<K_COMMENT> {alterExp.setOperation(AlterOperation.COMMENT);}
74407460
["=" {alterExp.setOperation(AlterOperation.COMMENT_WITH_EQUAL_SIGN);} ]

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

+42-26
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
2424
import net.sf.jsqlparser.statement.create.table.*;
2525
import net.sf.jsqlparser.statement.create.table.Index.ColumnParams;
2626
import org.junit.jupiter.api.Test;
27+
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.Arguments;
29+
import org.junit.jupiter.params.provider.MethodSource;
2730

2831
import java.util.Arrays;
2932
import java.util.Collections;
3033
import java.util.List;
34+
import java.util.stream.Stream;
3135

3236
import static net.sf.jsqlparser.test.TestUtils.*;
33-
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
3437
import static org.junit.jupiter.api.Assertions.*;
3538

3639
public class AlterTest {
@@ -1093,41 +1096,54 @@ public void testIssue2090LockExclusive() throws JSQLParserException {
10931096
assertEquals("EXCLUSIVE", lockExp.getLockOption());
10941097
}
10951098

1096-
@Test
1097-
public void testIssue2089() throws JSQLParserException {
1098-
String sql = "ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4";
1099+
@ParameterizedTest
1100+
@MethodSource("provideMySQLConvertTestCases")
1101+
public void testIssue2089(String sql, String expectedCharacterSet, String expectedCollation)
1102+
throws JSQLParserException {
10991103
Statement stmt = CCJSqlParserUtil.parse(sql);
1100-
assertTrue(stmt instanceof Alter);
1104+
assertTrue(stmt instanceof Alter,
1105+
"Expected instance of Alter but got: " + stmt.getClass().getSimpleName());
1106+
11011107
Alter alter = (Alter) stmt;
11021108
assertEquals("test_table", alter.getTable().getFullyQualifiedName());
11031109

11041110
List<AlterExpression> alterExpressions = alter.getAlterExpressions();
1105-
assertNotNull(alterExpressions);
1106-
assertEquals(1, alterExpressions.size());
1111+
assertNotNull(alterExpressions, "Alter expressions should not be null for SQL: " + sql);
1112+
assertEquals(1, alterExpressions.size(), "Expected 1 alter expression for SQL: " + sql);
11071113

11081114
AlterExpression convertExp = alterExpressions.get(0);
11091115
assertEquals(AlterOperation.CONVERT, convertExp.getOperation());
1110-
assertEquals("utf8mb4", convertExp.getCharacterSet());
1111-
assertNull(convertExp.getCollation());
1112-
}
1113-
1114-
@Test
1115-
public void testIssue2089WithCollation() throws JSQLParserException {
1116-
String sql =
1117-
"ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci";
1118-
Statement stmt = CCJSqlParserUtil.parse(sql);
1119-
assertTrue(stmt instanceof Alter);
1120-
Alter alter = (Alter) stmt;
1121-
assertEquals("test_table", alter.getTable().getFullyQualifiedName());
11221116

1123-
List<AlterExpression> alterExpressions = alter.getAlterExpressions();
1124-
assertNotNull(alterExpressions);
1125-
assertEquals(1, alterExpressions.size());
1117+
assertEquals(expectedCharacterSet, convertExp.getCharacterSet(),
1118+
"CHARACTER SET mismatch for SQL: " + sql);
1119+
assertEquals(expectedCollation, convertExp.getCollation(),
1120+
"COLLATE mismatch for SQL: " + sql);
1121+
assertSqlCanBeParsedAndDeparsed(sql);
1122+
}
11261123

1127-
AlterExpression convertExp = alterExpressions.get(0);
1128-
assertEquals(AlterOperation.CONVERT, convertExp.getOperation());
1129-
assertEquals("utf8mb4", convertExp.getCharacterSet());
1130-
assertEquals("utf8mb4_general_ci", convertExp.getCollation());
1124+
private static Stream<Arguments> provideMySQLConvertTestCases() {
1125+
return Stream.of(
1126+
Arguments.of("ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4", "utf8mb4",
1127+
null),
1128+
Arguments.of(
1129+
"ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci",
1130+
"utf8mb4", "utf8mb4_general_ci"),
1131+
Arguments.of(
1132+
"ALTER TABLE test_table DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci",
1133+
"utf8mb4", "utf8mb4_general_ci"),
1134+
Arguments.of(
1135+
"ALTER TABLE test_table DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci",
1136+
"utf8mb4", "utf8mb4_general_ci"),
1137+
Arguments.of(
1138+
"ALTER TABLE test_table CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci",
1139+
"utf8mb4", "utf8mb4_general_ci"),
1140+
Arguments.of(
1141+
"ALTER TABLE test_table CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci",
1142+
"utf8mb4", "utf8mb4_general_ci"),
1143+
Arguments.of("ALTER TABLE test_table DEFAULT CHARACTER SET utf8mb4", "utf8mb4",
1144+
null),
1145+
Arguments.of("ALTER TABLE test_table DEFAULT CHARACTER SET = utf8mb4", "utf8mb4",
1146+
null));
11311147
}
11321148

11331149
@Test

0 commit comments

Comments
 (0)