From 1c00d907c89daaec78db183a079e3304c5805207 Mon Sep 17 00:00:00 2001 From: LiZongbo Date: Sat, 4 May 2024 16:36:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A2=9E=E5=BC=BA=E8=A7=A3?= =?UTF-8?q?=E6=9E=90collate=E4=BF=A1=E6=81=AF=20#5822?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化增强解析collate信息 #5822 --- .../druid/sql/ast/expr/SQLCharExpr.java | 14 ++- .../druid/sql/ast/expr/SQLIdentifierExpr.java | 18 ++- .../dialect/mysql/parser/MySqlExprParser.java | 27 ++++- .../postgresql/visitor/PGOutputVisitor.java | 21 +++- .../druid/sql/parser/SQLExprParser.java | 42 ++++++- .../druid/sql/parser/SQLSelectParser.java | 10 ++ .../sql/visitor/SQLASTOutputVisitor.java | 26 ++--- .../mysql/alterTable/MySqlAlterTableTest.java | 42 ++++++- .../bvt/sql/postgresql/issues/Issue5822.java | 104 ++++++++++++++++++ 9 files changed, 273 insertions(+), 31 deletions(-) create mode 100644 core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5822.java diff --git a/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java b/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java index a3bb47a18b..bd3ae16fda 100644 --- a/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java +++ b/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java @@ -28,6 +28,8 @@ public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr, Comparable { public static final SQLDataType DATA_TYPE = new SQLCharacterDataType("char"); + protected String collate; + public SQLCharExpr() { } @@ -40,6 +42,14 @@ public SQLCharExpr(String text, SQLObject parent) { this.parent = parent; } + public String getCollate() { + return collate; + } + + public void setCollate(String collate) { + this.collate = collate; + } + public void output(StringBuilder buf) { this.accept(new SQLASTOutputVisitor(buf)); } @@ -59,7 +69,9 @@ public String toString() { } public SQLCharExpr clone() { - return new SQLCharExpr(this.text); + SQLCharExpr expr = new SQLCharExpr(this.text); + expr.setCollate(collate); + return expr; } public SQLDataType computeDataType() { diff --git a/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java b/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java index 8159061f50..921dd1108c 100644 --- a/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java +++ b/core/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java @@ -31,6 +31,8 @@ public final class SQLIdentifierExpr extends SQLExprImpl implements SQLName, Com private SQLObject resolvedColumn; private SQLObject resolvedOwnerObject; + protected String collate; + public SQLIdentifierExpr() { } @@ -69,6 +71,14 @@ public void setName(String name) { } } + public String getCollate() { + return collate; + } + + public void setCollate(String collate) { + this.collate = collate; + } + public long nameHashCode64() { return hashCode64(); } @@ -77,7 +87,11 @@ public long nameHashCode64() { public long hashCode64() { if (hashCode64 == 0 && name != null) { - hashCode64 = FnvHash.hashCode64(name); + if (collate != null) { + hashCode64 = FnvHash.hashCode64(name + collate); + } else { + hashCode64 = FnvHash.hashCode64(name); + } } return hashCode64; } @@ -124,7 +138,7 @@ public SQLIdentifierExpr clone() { if (hint != null) { x.hint = hint.clone(); } - + x.collate = collate; return x; } diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java index 8195c086f1..7a42b6d5a4 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java @@ -1890,7 +1890,19 @@ public boolean parseTableOptions(List assignItems, SQLDDLStatemen if (lexer.token() == Token.EQ) { lexer.nextToken(); } - assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), expr()); + if (lexer.token() == Token.IDENTIFIER) { + assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), new SQLIdentifierExpr(lexer.stringVal())); + lexer.nextToken(); + } else if (lexer.token() == Token.LITERAL_ALIAS || lexer.token() == Token.LITERAL_CHARS) { + String charset = lexer.stringVal(); + if (charset.startsWith("\"")) { + charset = charset.substring(1, charset.length() - 1); + } + assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), new SQLCharExpr(charset)); + lexer.nextToken(); + } else { + assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), expr()); + } } else if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) { lexer.nextToken(); if (lexer.token() == Token.EQ) { @@ -1904,8 +1916,19 @@ public boolean parseTableOptions(List assignItems, SQLDDLStatemen accept(Token.SET); if (lexer.token() == Token.EQ) { lexer.nextToken(); + } if (lexer.token() == Token.IDENTIFIER) { + assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), new SQLIdentifierExpr(lexer.stringVal())); + lexer.nextToken(); + } else if (lexer.token() == Token.LITERAL_ALIAS || lexer.token() == Token.LITERAL_CHARS) { + String charset = lexer.stringVal(); + if (charset.startsWith("\"")) { + charset = charset.substring(1, charset.length() - 1); + } + assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), new SQLCharExpr(charset)); + lexer.nextToken(); + } else { + assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), expr()); } - assignItem = new SQLAssignItem(new SQLIdentifierExpr("CHARACTER SET"), expr()); } else if (hash == FnvHash.Constants.DATA || lexer.token() == Token.INDEX) { // {DATA|INDEX} DIRECTORY [=] 'absolute path to directory' diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/core/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index 98429c403a..e9a6d314b6 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -2647,7 +2647,26 @@ public boolean visit(SQLCharExpr x, boolean parameterized) { if (x instanceof PGCharExpr && ((PGCharExpr) x).isCSytle()) { print('E'); } - printChars(x.getText()); + if (x.getCollate() != null) { + String collate = x.getCollate(); + if (x.isParenthesized()) { + print('('); + } + printChars(x.getText()); + print(" COLLATE "); + if (collate.startsWith("'") || collate.endsWith("\"")) { + print(collate); + } else { + print('\''); + print(collate); + print('\''); + } + if (x.isParenthesized()) { + print(')'); + } + } else { + printChars(x.getText()); + } return false; } diff --git a/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 6ceff5bde1..c0c84ceb9a 100644 --- a/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -27,6 +27,7 @@ import com.alibaba.druid.sql.parser.Lexer.SavePoint; import com.alibaba.druid.util.FnvHash; import com.alibaba.druid.util.HexBin; +import com.alibaba.druid.util.JdbcUtils; import com.alibaba.druid.util.MySqlUtils; import com.alibaba.druid.util.StringUtils; @@ -441,8 +442,18 @@ public SQLExpr primary() { } lexer.nextToken(); - - if (hash_lower == FnvHash.Constants.TRY_CAST) { + if (lexer.identifierEquals("COLLATE")) { + acceptIdentifier("COLLATE"); + String collateValue = lexer.stringVal(); + if (lexer.token == Token.IDENTIFIER || lexer.token == Token.LITERAL_ALIAS || lexer.token == Token.LITERAL_CHARS) { + SQLIdentifierExpr identifierExpr = new SQLIdentifierExpr(ident); + identifierExpr.setCollate(collateValue); + lexer.nextToken(); + sqlExpr = identifierExpr; + } else { + throw new ParserException("syntax error. " + lexer.info()); + } + } else if (hash_lower == FnvHash.Constants.TRY_CAST) { accept(Token.LPAREN); SQLCastExpr cast = new SQLCastExpr(); cast.setTry(true); @@ -607,7 +618,26 @@ public SQLExpr primary() { break; case LITERAL_CHARS: { sqlExpr = new SQLCharExpr(lexer.stringVal()); - + if (JdbcUtils.isPgsqlDbType(dbType)) { + Lexer.SavePoint savePoint = lexer.mark(); + lexer.nextToken(); + if (lexer.token() == Token.IDENTIFIER) { + String collate = lexer.stringVal(); + if (collate.equalsIgnoreCase("collate")) { + lexer.nextToken(); + String collateValue = lexer.stringVal(); + if (lexer.token == Token.IDENTIFIER || lexer.token == Token.LITERAL_ALIAS || lexer.token == Token.LITERAL_CHARS) { + ((SQLCharExpr) sqlExpr).setCollate(lexer.stringVal()); + } else { + throw new ParserException("syntax error. " + lexer.info()); + } + } else { + lexer.reset(savePoint); + } + } else { + lexer.reset(savePoint); + } + } if (DbType.mysql == dbType) { lexer.nextTokenValue(); @@ -5899,8 +5929,8 @@ public SQLSelectItem parseSelectItem() { expr = new SQLIdentifierExpr(ident); } } else if (lexer.identifierEquals(FnvHash.Constants.COLLATE) - && dbType == DbType.mysql - && lexer.stringVal().charAt(0) != '`' + && (JdbcUtils.isMysqlDbType(dbType) || JdbcUtils.isPgsqlDbType(dbType)) + && lexer.stringVal().charAt(0) != '`' ) { lexer.nextToken(); String collate = lexer.stringVal(); @@ -5909,7 +5939,7 @@ public SQLSelectItem parseSelectItem() { SQLBinaryOpExpr binaryExpr = new SQLBinaryOpExpr( new SQLIdentifierExpr(ident), SQLBinaryOperator.COLLATE, - new SQLIdentifierExpr(collate), DbType.mysql + new SQLIdentifierExpr(collate), dbType ); expr = binaryExpr; diff --git a/core/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java b/core/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java index c9df91f07a..5a4a3e2bc6 100644 --- a/core/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java +++ b/core/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java @@ -662,6 +662,16 @@ public void parseWhere(SQLSelectQueryBlock queryBlock) { } else { identExpr = new SQLIdentifierExpr(ident, hash_lower); } + } else if (lexer.identifierEquals("COLLATE")) { + acceptIdentifier("COLLATE"); + String collateValue = lexer.stringVal(); + if (lexer.token == Token.IDENTIFIER || lexer.token == Token.LITERAL_ALIAS || lexer.token == Token.LITERAL_CHARS) { + identExpr = new SQLIdentifierExpr(ident); + ((SQLIdentifierExpr) identExpr).setCollate(collateValue); + lexer.nextToken(); + } else { + throw new ParserException("syntax error. " + lexer.info()); + } } else { identExpr = new SQLIdentifierExpr(ident, hash_lower); } diff --git a/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 76ea60a05a..1ff53956a8 100644 --- a/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -1059,23 +1059,9 @@ private void visitBinaryLeft(SQLExpr left, SQLBinaryOperator op) { } } else if (left instanceof SQLBetweenExpr) { SQLBetweenExpr betweenExpr = (SQLBetweenExpr) left; - boolean quote; - if (betweenExpr.isNot()) { - quote = op.priority <= SQLBinaryOperator.Equality.priority; - } else { - quote = op.priority < SQLBinaryOperator.Equality.priority; - } -// if (quote) { -// print("(aaa"); -// } visit(betweenExpr); -// if (quote) { -// print(')'); -// } } else if (left instanceof SQLNotExpr) { -// print('('); printExpr(left); -// print(')'); } else if (left instanceof SQLUnaryExpr) { SQLUnaryExpr unary = (SQLUnaryExpr) left; @@ -1436,6 +1422,17 @@ public boolean visit(SQLIdentifierExpr x) { print('('); } printName0(x.getName()); + if (x.getCollate() != null) { + String collate = x.getCollate(); + print(" COLLATE "); + if (collate.startsWith("'") || collate.endsWith("\"")) { + print(collate); + } else { + print('\''); + print(collate); + print('\''); + } + } if (x.isParenthesized()) { print(')'); } @@ -5800,7 +5797,6 @@ public boolean visit(SQLAlterTableStatement x) { if (x.isNotClustered()) { print0(ucase ? " NOT CLUSTERED" : " not clustered"); } - return false; } diff --git a/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/alterTable/MySqlAlterTableTest.java b/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/alterTable/MySqlAlterTableTest.java index 48b56a122b..9e1a518fa2 100644 --- a/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/alterTable/MySqlAlterTableTest.java +++ b/core/src/test/java/com/alibaba/druid/bvt/sql/mysql/alterTable/MySqlAlterTableTest.java @@ -15,15 +15,22 @@ */ package com.alibaba.druid.bvt.sql.mysql.alterTable; +import java.util.List; + +import com.alibaba.druid.DbType; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; + import junit.framework.TestCase; import org.junit.Assert; public class MySqlAlterTableTest extends TestCase { + public void test_alter_0() throws Exception { String sql = "ALTER TABLE `test`.`tb1` CHANGE COLUMN `fname` `fname1` VARCHAR(45) NULL DEFAULT NULL ;"; MySqlStatementParser parser = new MySqlStatementParser(sql); @@ -40,7 +47,8 @@ public void test_alter_1() throws Exception { parser.match(Token.EOF); Assert.assertEquals("ALTER TABLE `test`.`tb1`\n\tCHARACTER SET = utf8 COLLATE = utf8_general_ci;", SQLUtils.toMySqlString(stmt)); - Assert.assertEquals("alter table `test`.`tb1`\n\tcharacter set = utf8 collate = utf8_general_ci;", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + Assert.assertEquals("alter table `test`.`tb1`\n\tcharacter set = utf8 collate = utf8_general_ci;", + SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); } public void test_alter_2() throws Exception { @@ -81,13 +89,39 @@ public void test_alter_5() throws Exception { public void test_alter_6() throws Exception { String sql = "ALTER TABLE `test`.`tb1` DEFAULT CHARACTER SET utf8 COLLATE = utf8_general_ci ;"; + MySqlStatementParser parser = new MySqlStatementParser(sql); SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); - + System.out.println(stmt.toString()); //System.out.println(SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); - Assert.assertEquals("ALTER TABLE `test`.`tb1`\n\tCHARACTER SET = utf8 COLLATE utf8_general_ci;", SQLUtils.toMySqlString(stmt)); - Assert.assertEquals("alter table `test`.`tb1`\n\tcharacter set = utf8 collate utf8_general_ci;", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + Assert.assertEquals("ALTER TABLE `test`.`tb1`\n\tCHARACTER SET = utf8 COLLATE = utf8_general_ci;", SQLUtils.toMySqlString(stmt)); + Assert.assertEquals("alter table `test`.`tb1`\n\tcharacter set = utf8 collate = utf8_general_ci;", + SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); } + public void test_alter_7() throws Exception { + for (String sql : new String[]{ + "ALTER TABLE \n" + + " `test` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;", + "ALTER TABLE \n" + + " `test` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';", + "ALTER TABLE \n" + + " `test` CHARACTER SET \"utf8mb4\" COLLATE \"utf8mb4_bin\";", + "ALTER TABLE \n" + + " `test` default CHARACTER SET utf8mb4 COLLATE =utf8mb4_bin", + }) { + System.out.println("原始的sql===" + sql); + SQLStatementParser parser1 = SQLParserUtils.createSQLStatementParser(sql, DbType.mysql); + List statementList1 = parser1.parseStatementList(); + String sqleNew = statementList1.get(0).toString(); + System.out.println("生成的sql===" + sqleNew); + SQLStatementParser parser2 = SQLParserUtils.createSQLStatementParser(sqleNew, DbType.mariadb); + List statementList2 = parser2.parseStatementList(); + String sqleNew2 = statementList2.get(0).toString(); + System.out.println("再次解析生成的sql===" + sqleNew2); + assertEquals(sqleNew, sqleNew2); + } + + } } diff --git a/core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5822.java b/core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5822.java new file mode 100644 index 0000000000..d800266d80 --- /dev/null +++ b/core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5822.java @@ -0,0 +1,104 @@ +package com.alibaba.druid.bvt.sql.postgresql.issues; + +import java.util.List; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.sql.parser.SQLStatementParser; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * PostgreSQL解析SET SCHEMA的问题 + * + * @author lizongbo + * @see Issue来源 + * @see SET SCHEMA + * @see SET NAMES 'value'; + * @see Collation Support + */ +public class Issue5822 { + + @Test + public void test_parse_postgresql_collate() { + for (String sql : new String[]{ + "SELECT a < 'foo' FROM test1;", + "SELECT a < b FROM test1;", + "SELECT a < b COLLATE \"de_DE\" FROM test1;", + "SELECT a COLLATE \"de_DE\" < b FROM test1;", + "SELECT a || b FROM test1;", + "SELECT * FROM test1 ORDER BY a || 'foo';", + "SELECT * FROM test1 ORDER BY a || b;", + "SELECT * FROM test1 ORDER BY a || b COLLATE \"fr_FR\";", + "SELECT a COLLATE \"C\" < b COLLATE \"POSIX\" FROM test1;", + + "SELECT a < ('foo' COLLATE \"zh_CN\") FROM test1;", + "SELECT a < ('foo' COLLATE 'zh_CN') FROM test1;", + "SELECT a < ('foo') FROM test1;", + "SELECT a < (bbb COLLATE \"zh_CN\") FROM test1;", + "SELECT a < (ccc COLLATE 'zh_CN') FROM test1;", + "SELECT id FROM a_product WHERE product_name COLLATE \"C\" ILIKE '%70%'" + + " AND 1=1 ORDER BY product_name,created_at DESC,id DESC LIMIT 20", + "SELECT id FROM a_product WHERE a_product.tenant_id=123 AND (tenant_id=123 AND del_flg=0 AND (product_name COLLATE \"C\" ILIKE '%70%' AND (INDEPENDENT_PRODUCT=1 AND ((1711942157815>=START_DATE AND 1711942157815< END_DATE) OR (START_DATE IS NULL AND END_DATE IS NULL) OR (START_DATE IS NULL AND 1711942157815< END_DATE) OR (1711942157815>=START_DATE AND END_DATE IS NULL))) AND id IN (SELECT dbc_relation_2 FROM p_custom_data_408 WHERE p_custom_data_408.tenant_id=123 AND (TENANT_ID=123 AND dbc_relation_1=1706133096090917 AND DELETE_FLG=0 AND dbc_select_2=1)) AND (((EXISTS (SELECT id FROM b_entity_checkbox pickvalue WHERE pickvalue.tenant_id=123 AND (a_product.id=pickvalue.object_id AND item_id=1776944933031192 AND option_code IN (1))) AND 1=1) OR (EXISTS (SELECT id FROM b_entity_checkbox pickvalue WHERE pickvalue.tenant_id=123 AND (a_product.id=pickvalue.object_id AND item_id=1776944933031192 AND option_code IN (2))) AND id=-999999999)) AND dbc_varchar_16='FERT') AND 1=1)) ORDER BY product_name,created_at DESC,id DESC LIMIT 20", + }) { + System.out.println("原始的sql===" + sql); + SQLStatementParser parser1 = SQLParserUtils.createSQLStatementParser(sql, DbType.postgresql); + List statementList1 = parser1.parseStatementList(); + String sqleNew = statementList1.get(0).toString(); + System.out.println("生成的sql===" + sqleNew); + SQLStatementParser parser2 = SQLParserUtils.createSQLStatementParser(sqleNew, DbType.greenplum); + List statementList2 = parser2.parseStatementList(); + String sqleNew2 = statementList2.get(0).toString(); + System.out.println("再次解析生成的sql===" + sqleNew2); + assertEquals(sqleNew, sqleNew2); + } + + } + + /** + * @see Using COLLATE in SQL Statements + */ + @Test + public void test_parse_mysql_collate() { + for (String sql : new String[]{ + "SELECT k\n" + + "FROM t1\n" + + "ORDER BY k COLLATE latin1_german2_ci;", + "SELECT k COLLATE latin1_german2_ci AS k1\n" + + "FROM t1\n" + + "ORDER BY k1;", + "SELECT k\n" + + "FROM t1\n" + + "GROUP BY k COLLATE latin1_german2_ci;", + "SELECT MAX(k COLLATE latin1_german2_ci)\n" + + "FROM t1;", + "SELECT DISTINCT k COLLATE latin1_german2_ci\n" + + "FROM t1;", + "SELECT *\n" + + "FROM t1\n" + + "WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;", + "SELECT *\n" + + "FROM t1\n" + + "WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci;", + "SELECT k\n" + + "FROM t1\n" + + "GROUP BY k\n" + + "HAVING k = _latin1 'Müller' COLLATE latin1_german2_ci;", + }) { + System.out.println("原始的sql===" + sql); + SQLStatementParser parser1 = SQLParserUtils.createSQLStatementParser(sql, DbType.mysql); + List statementList1 = parser1.parseStatementList(); + String sqleNew = statementList1.get(0).toString(); + System.out.println("生成的sql===" + sqleNew); + SQLStatementParser parser2 = SQLParserUtils.createSQLStatementParser(sqleNew, DbType.mariadb); + List statementList2 = parser2.parseStatementList(); + String sqleNew2 = statementList2.get(0).toString(); + System.out.println("再次解析生成的sql===" + sqleNew2); + assertEquals(sqleNew, sqleNew2); + } + + } +}