From 6227b0b63067e7492b8056818cde46fdbbe515ed Mon Sep 17 00:00:00 2001 From: mj-db Date: Mon, 25 Nov 2024 20:37:18 +0900 Subject: [PATCH 1/2] fix convert toString --- .../statement/alter/AlterExpression.java | 14 +++++++++++--- .../sf/jsqlparser/statement/alter/AlterTest.java | 7 ++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java index 1f26a70c7..90122634e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java @@ -196,7 +196,7 @@ public boolean isOnDeleteCascade() { /** * @param onDeleteCascade * @deprecated use - * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} + * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} */ @Deprecated public void setOnDeleteCascade(boolean onDeleteCascade) { @@ -216,7 +216,7 @@ public boolean isOnDeleteRestrict() { /** * @param onDeleteRestrict * @deprecated use - * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} + * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} */ @Deprecated public void setOnDeleteRestrict(boolean onDeleteRestrict) { @@ -236,7 +236,7 @@ public boolean isOnDeleteSetNull() { /** * @param onDeleteSetNull * @deprecated use - * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} + * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} */ @Deprecated public void setOnDeleteSetNull(boolean onDeleteSetNull) { @@ -485,6 +485,14 @@ public String toString() { } else if (operation == AlterOperation.DROP_PRIMARY_KEY) { b.append("DROP PRIMARY KEY "); + } else if (operation == AlterOperation.CONVERT) { + b.append("CONVERT TO CHARACTER SET "); + if (getCharacterSet() != null) { + b.append(getCharacterSet()); + } + if (getCollation() != null) { + b.append(" COLLATE ").append(getCollation()); + } } else if (operation == AlterOperation.DROP_UNIQUE) { b.append("DROP UNIQUE (").append(PlainSelect.getStringList(pkColumns)).append(')'); diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java index 005961a3d..2d9736b82 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java @@ -30,7 +30,6 @@ import java.util.List; import static net.sf.jsqlparser.test.TestUtils.*; -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static org.junit.jupiter.api.Assertions.*; public class AlterTest { @@ -835,7 +834,7 @@ public void testAlterTableDefaultValueTrueIssue926() throws JSQLParserException } private void assertReferentialActionOnConstraint(Alter parsed, Action onUpdate, - Action onDelete) { + Action onDelete) { AlterExpression alterExpression = parsed.getAlterExpressions().get(0); ForeignKeyIndex index = (ForeignKeyIndex) alterExpression.getIndex(); @@ -1112,7 +1111,7 @@ public void testIssue2089() throws JSQLParserException { } @Test - public void testIssue2089WithCollation() throws JSQLParserException { + public void testIssue2089ConvertWithCollation() throws JSQLParserException { String sql = "ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"; Statement stmt = CCJSqlParserUtil.parse(sql); @@ -1128,6 +1127,8 @@ public void testIssue2089WithCollation() throws JSQLParserException { assertEquals(AlterOperation.CONVERT, convertExp.getOperation()); assertEquals("utf8mb4", convertExp.getCharacterSet()); assertEquals("utf8mb4_general_ci", convertExp.getCollation()); + + assertSqlCanBeParsedAndDeparsed(sql); } @Test From 0562417b7c1abc4be75677dcc0d8a395664e1029 Mon Sep 17 00:00:00 2001 From: mj-db Date: Tue, 26 Nov 2024 14:12:51 +0900 Subject: [PATCH 2/2] fix mysql convert --- .../statement/alter/AlterExpression.java | 53 ++++++++++++-- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 26 ++++++- .../jsqlparser/statement/alter/AlterTest.java | 69 +++++++++++-------- 3 files changed, 113 insertions(+), 35 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java index 90122634e..4fd1f4209 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java @@ -53,6 +53,11 @@ public class AlterExpression implements Serializable { private List partitionDefinitions; private List constraints; private List parameters; + + private ConvertType convertType; + private boolean hasEqualForCharacterSet; + private boolean hasEqualForCollate; + private String characterSet; private String collation; private String lockOption; @@ -196,7 +201,7 @@ public boolean isOnDeleteCascade() { /** * @param onDeleteCascade * @deprecated use - * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} + * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} */ @Deprecated public void setOnDeleteCascade(boolean onDeleteCascade) { @@ -216,7 +221,7 @@ public boolean isOnDeleteRestrict() { /** * @param onDeleteRestrict * @deprecated use - * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} + * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} */ @Deprecated public void setOnDeleteRestrict(boolean onDeleteRestrict) { @@ -236,7 +241,7 @@ public boolean isOnDeleteSetNull() { /** * @param onDeleteSetNull * @deprecated use - * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} + * {@link #setReferentialAction(ReferentialAction.Type, ReferentialAction.Action, boolean)} */ @Deprecated public void setOnDeleteSetNull(boolean onDeleteSetNull) { @@ -401,6 +406,14 @@ public List getParameters() { return parameters; } + public ConvertType getConvertType() { + return convertType; + } + + public void setConvertType(ConvertType convertType) { + this.convertType = convertType; + } + public String getCharacterSet() { return characterSet; } @@ -486,12 +499,30 @@ public String toString() { b.append("DROP PRIMARY KEY "); } else if (operation == AlterOperation.CONVERT) { - b.append("CONVERT TO CHARACTER SET "); + if (convertType == ConvertType.CONVERT_TO) { + b.append("CONVERT TO CHARACTER SET "); + } else if (convertType == ConvertType.DEFAULT_CHARACTER_SET) { + b.append("DEFAULT CHARACTER SET "); + if (hasEqualForCharacterSet) { + b.append("= "); + } + } else if (convertType == ConvertType.CHARACTER_SET) { + b.append("CHARACTER SET "); + if (hasEqualForCharacterSet) { + b.append("= "); + } + } + if (getCharacterSet() != null) { b.append(getCharacterSet()); } + if (getCollation() != null) { - b.append(" COLLATE ").append(getCollation()); + b.append(" COLLATE "); + if (hasEqualForCollate) { + b.append("= "); + } + b.append(getCollation()); } } else if (operation == AlterOperation.DROP_UNIQUE) { @@ -805,6 +836,14 @@ public void setPartitionDefinitions(List partitionDefinitio this.partitionDefinitions = partitionDefinition; } + public void setHasEqualForCharacterSet(boolean hasEqualForCharacterSet) { + this.hasEqualForCharacterSet = hasEqualForCharacterSet; + } + + public void setHasEqualForCollate(boolean hasEqualForCollate) { + this.hasEqualForCollate = hasEqualForCollate; + } + public static final class ColumnDataType extends ColumnDefinition { private final boolean withType; @@ -898,4 +937,8 @@ public String toString() { return columnName + " DROP DEFAULT"; } } + + public enum ConvertType { + CONVERT_TO, DEFAULT_CHARACTER_SET, CHARACTER_SET + } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index f124a2ea9..4d26413b5 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -7430,11 +7430,31 @@ AlterExpression AlterExpression(): {alterExp.setOperation(AlterOperation.RENAME_TABLE);} (tk2= | tk2=) { alterExp.setNewTableName(tk2.image);} ) - | - ( { alterExp.setOperation(AlterOperation.CONVERT); } + | ( { + alterExp.setOperation(AlterOperation.CONVERT); + alterExp.setConvertType(AlterExpression.ConvertType.CONVERT_TO); + } tk= { alterExp.setCharacterSet(tk.image); } [ tk2= { alterExp.setCollation(tk2.image); }] - ) + ) + | ( { + alterExp.setOperation(AlterOperation.CONVERT); + alterExp.setConvertType(AlterExpression.ConvertType.DEFAULT_CHARACTER_SET); + } + [ "=" { alterExp.setHasEqualForCharacterSet(true); } ] + tk= { alterExp.setCharacterSet(tk.image); } + [ [ "=" { alterExp.setHasEqualForCollate(true); } ] + tk2= { alterExp.setCollation(tk2.image); }] + ) + | ( [ "=" { alterExp.setHasEqualForCharacterSet(true); } ] + tk= { + alterExp.setOperation(AlterOperation.CONVERT); + alterExp.setConvertType(AlterExpression.ConvertType.CHARACTER_SET); + alterExp.setCharacterSet(tk.image); + } + [ [ "=" { alterExp.setHasEqualForCollate(true); } ] + tk2= { alterExp.setCollation(tk2.image); }] + ) | ( {alterExp.setOperation(AlterOperation.COMMENT);} ["=" {alterExp.setOperation(AlterOperation.COMMENT_WITH_EQUAL_SIGN);} ] diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java index 2d9736b82..03ec3e85e 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java @@ -24,10 +24,14 @@ import net.sf.jsqlparser.statement.create.table.*; import net.sf.jsqlparser.statement.create.table.Index.ColumnParams; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import static net.sf.jsqlparser.test.TestUtils.*; import static org.junit.jupiter.api.Assertions.*; @@ -834,7 +838,7 @@ public void testAlterTableDefaultValueTrueIssue926() throws JSQLParserException } private void assertReferentialActionOnConstraint(Alter parsed, Action onUpdate, - Action onDelete) { + Action onDelete) { AlterExpression alterExpression = parsed.getAlterExpressions().get(0); ForeignKeyIndex index = (ForeignKeyIndex) alterExpression.getIndex(); @@ -1092,45 +1096,56 @@ public void testIssue2090LockExclusive() throws JSQLParserException { assertEquals("EXCLUSIVE", lockExp.getLockOption()); } - @Test - public void testIssue2089() throws JSQLParserException { - String sql = "ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4"; + @ParameterizedTest + @MethodSource("provideMySQLConvertTestCases") + public void testIssue2089(String sql, String expectedCharacterSet, String expectedCollation) + throws JSQLParserException { Statement stmt = CCJSqlParserUtil.parse(sql); - assertTrue(stmt instanceof Alter); - Alter alter = (Alter) stmt; - assertEquals("test_table", alter.getTable().getFullyQualifiedName()); - - List alterExpressions = alter.getAlterExpressions(); - assertNotNull(alterExpressions); - assertEquals(1, alterExpressions.size()); - - AlterExpression convertExp = alterExpressions.get(0); - assertEquals(AlterOperation.CONVERT, convertExp.getOperation()); - assertEquals("utf8mb4", convertExp.getCharacterSet()); - assertNull(convertExp.getCollation()); - } + assertTrue(stmt instanceof Alter, + "Expected instance of Alter but got: " + stmt.getClass().getSimpleName()); - @Test - public void testIssue2089ConvertWithCollation() throws JSQLParserException { - String sql = - "ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"; - Statement stmt = CCJSqlParserUtil.parse(sql); - assertTrue(stmt instanceof Alter); Alter alter = (Alter) stmt; assertEquals("test_table", alter.getTable().getFullyQualifiedName()); List alterExpressions = alter.getAlterExpressions(); - assertNotNull(alterExpressions); - assertEquals(1, alterExpressions.size()); + assertNotNull(alterExpressions, "Alter expressions should not be null for SQL: " + sql); + assertEquals(1, alterExpressions.size(), "Expected 1 alter expression for SQL: " + sql); AlterExpression convertExp = alterExpressions.get(0); assertEquals(AlterOperation.CONVERT, convertExp.getOperation()); - assertEquals("utf8mb4", convertExp.getCharacterSet()); - assertEquals("utf8mb4_general_ci", convertExp.getCollation()); + assertEquals(expectedCharacterSet, convertExp.getCharacterSet(), + "CHARACTER SET mismatch for SQL: " + sql); + assertEquals(expectedCollation, convertExp.getCollation(), + "COLLATE mismatch for SQL: " + sql); assertSqlCanBeParsedAndDeparsed(sql); } + private static Stream provideMySQLConvertTestCases() { + return Stream.of( + Arguments.of("ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4", "utf8mb4", + null), + Arguments.of( + "ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of("ALTER TABLE test_table DEFAULT CHARACTER SET utf8mb4", "utf8mb4", + null), + Arguments.of("ALTER TABLE test_table DEFAULT CHARACTER SET = utf8mb4", "utf8mb4", + null)); + } + @Test public void testIssue2106AlterTableAddPartition1() throws JSQLParserException { String sql = "ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2002));";