diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlForceIndexHint.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlForceIndexHint.java new file mode 100644 index 0000000000..c3ff626975 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlForceIndexHint.java @@ -0,0 +1,17 @@ +package com.alibaba.druid.sql.dialect.mysql.ast; + +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; + +public class MySqlForceIndexHint extends MySqlIndexHintImpl { + + private static final long serialVersionUID = 1L; + + @Override + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, getIndexList()); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java new file mode 100644 index 0000000000..b889d01e22 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java @@ -0,0 +1,51 @@ +package com.alibaba.druid.sql.dialect.mysql.ast.statement; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; + +public class MySqlAlterTableChangeColumn extends MySqlObjectImpl implements SQLAlterTableItem { + + private static final long serialVersionUID = 1L; + + private SQLName columnName; + + private SQLColumnDefinition newColumnDefinition; + + private Boolean first; + + @Override + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, columnName); + acceptChild(visitor, newColumnDefinition); + } + } + + public SQLName getColumnName() { + return columnName; + } + + public void setColumnName(SQLName columnName) { + this.columnName = columnName; + } + + public SQLColumnDefinition getNewColumnDefinition() { + return newColumnDefinition; + } + + public void setNewColumnDefinition(SQLColumnDefinition newColumnDefinition) { + this.newColumnDefinition = newColumnDefinition; + } + + public Boolean getFirst() { + return first; + } + + public void setFirst(Boolean first) { + this.first = first; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableCharacter.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableCharacter.java new file mode 100644 index 0000000000..8d0e9cc765 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableCharacter.java @@ -0,0 +1,40 @@ +package com.alibaba.druid.sql.dialect.mysql.ast.statement; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; + +public class MySqlAlterTableCharacter extends MySqlObjectImpl implements SQLAlterTableItem { + + private static final long serialVersionUID = 1L; + + private SQLExpr characterSet; + private SQLExpr collate; + + @Override + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, characterSet); + acceptChild(visitor, collate); + } + visitor.endVisit(this); + } + + public SQLExpr getCharacterSet() { + return characterSet; + } + + public void setCharacterSet(SQLExpr characterSet) { + this.characterSet = characterSet; + } + + public SQLExpr getCollate() { + return collate; + } + + public void setCollate(SQLExpr collate) { + this.collate = collate; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java index 07ff99633d..40179873c6 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLTableSource; import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIndexHintImpl; @@ -272,6 +273,13 @@ public class MySqlSelectParser extends SQLSelectParser { parseIndexHint(hint); tableSource.getHints().add(hint); } + + if (identifierEquals("FORCE")) { + lexer.nextToken(); + MySqlForceIndexHint hint = new MySqlForceIndexHint(); + parseIndexHint(hint); + tableSource.getHints().add(hint); + } return super.parseTableSourceRest(tableSource); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index e464ce8938..ddb7715c86 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -40,6 +40,8 @@ import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -2052,7 +2054,21 @@ public class MySqlStatementParser extends SQLStatementParser { } else if (identifierEquals("ALTER")) { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } else if (identifierEquals("CHANGE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + lexer.nextToken(); + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + } + MySqlAlterTableChangeColumn item = new MySqlAlterTableChangeColumn(); + item.setColumnName(this.exprParser.name()); + item.setNewColumnDefinition(this.exprParser.parseColumn()); + if (identifierEquals("FIRST")) { + lexer.nextToken(); + item.setFirst(true); + } else if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setFirst(false); + } + stmt.getItems().add(item); } else if (identifierEquals("MODIFY")) { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } else if (lexer.token() == Token.DROP) { @@ -2102,6 +2118,19 @@ public class MySqlStatementParser extends SQLStatementParser { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } else if (identifierEquals("REMOVE")) { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("CHARACTER")) { + lexer.nextToken(); + accept(Token.SET); + accept(Token.EQ); + MySqlAlterTableCharacter item = new MySqlAlterTableCharacter(); + item.setCharacterSet(this.exprParser.primary()); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + acceptIdentifier("COLLATE"); + accept(Token.EQ); + item.setCollate(this.exprParser.primary()); + } + stmt.getItems().add(item); } else { break; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java index 86de5f0569..6bfa873082 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.dialect.mysql.visitor; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; @@ -28,6 +29,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -470,4 +473,16 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlUnlockTablesStatement x); void endVisit(MySqlUnlockTablesStatement x); + + boolean visit(MySqlForceIndexHint x); + + void endVisit(MySqlForceIndexHint x); + + boolean visit(MySqlAlterTableChangeColumn x); + + void endVisit(MySqlAlterTableChangeColumn x); + + boolean visit(MySqlAlterTableCharacter x); + + void endVisit(MySqlAlterTableCharacter x); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java index 077fe4a1dd..4155a13864 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java @@ -1,5 +1,6 @@ package com.alibaba.druid.sql.dialect.mysql.visitor; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; @@ -13,6 +14,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -1024,4 +1027,34 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements public void endVisit(MySqlUnlockTablesStatement x) { } + + @Override + public boolean visit(MySqlForceIndexHint x) { + return true; + } + + @Override + public void endVisit(MySqlForceIndexHint x) { + + } + + @Override + public boolean visit(MySqlAlterTableChangeColumn x) { + return true; + } + + @Override + public void endVisit(MySqlAlterTableChangeColumn x) { + + } + + @Override + public boolean visit(MySqlAlterTableCharacter x) { + return true; + } + + @Override + public void endVisit(MySqlAlterTableCharacter x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index d17355de9c..e047a19a34 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -31,6 +31,7 @@ import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; @@ -45,6 +46,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -2457,7 +2460,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public void endVisit(MySqlLockTableStatement x) { - + } @Override @@ -2468,6 +2471,65 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public void endVisit(MySqlUnlockTablesStatement x) { + + } + + @Override + public boolean visit(MySqlForceIndexHint x) { + print("FORCE INDEX "); + if (x.getOption() != null) { + print("FOR "); + print(x.getOption().name); + print(' '); + } + print('('); + printAndAccept(x.getIndexList(), ", "); + print(')'); + return false; + } + + @Override + public void endVisit(MySqlForceIndexHint x) { + + } + + @Override + public boolean visit(MySqlAlterTableChangeColumn x) { + print("CHANGE COLUMN "); + x.getColumnName().accept(this); + print(' '); + x.getNewColumnDefinition().accept(this); + if (x.getFirst() != null) { + if (x.getFirst().booleanValue()) { + print(" FIRST"); + } else { + print(" AFTER"); + } + } + + return false; + } + + @Override + public void endVisit(MySqlAlterTableChangeColumn x) { + + } + + @Override + public boolean visit(MySqlAlterTableCharacter x) { + print("CHARACTER SET = "); + x.getCharacterSet().accept(this); + if (x.getCollate() != null) { + print(", COLLATE = "); + x.getCollate().accept(this); + } + + return false; + } + + @Override + public void endVisit(MySqlAlterTableCharacter x) { + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java index e2b13f7d3e..e0ef33886d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java @@ -10,6 +10,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; @@ -23,6 +24,8 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -1088,4 +1091,34 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public void endVisit(MySqlUnlockTablesStatement x) { } + + @Override + public boolean visit(MySqlForceIndexHint x) { + return false; + } + + @Override + public void endVisit(MySqlForceIndexHint x) { + + } + + @Override + public boolean visit(MySqlAlterTableChangeColumn x) { + return false; + } + + @Override + public void endVisit(MySqlAlterTableChangeColumn x) { + + } + + @Override + public boolean visit(MySqlAlterTableCharacter x) { + return false; + } + + @Override + public void endVisit(MySqlAlterTableCharacter x) { + + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java index 27fe83001c..a9866aa337 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java @@ -237,4 +237,32 @@ public class DMLSelectParserTest extends TestCase { String output = SQLUtils.toMySqlString(stmt); Assert.assertEquals("SELECT t1.id, t2.*\nFROM t1, test.t2\nWHERE test.t1.id = '中''‘文'\n\tAND t1.id = test.t2.id", output); } + + public void test_select_19() throws Exception { + String sql = "select * from offer a straight_join wp_image b force index for join(t1,t2) on a.member_id=b.member_id inner join product_visit c where a.member_id=c.member_id and c.member_id='abc' "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("SELECT *\n" + + // + "FROM offer a STRAIGHT_JOIN wp_image b FORCE INDEX FOR JOIN (t1, t2) ON a.member_id = b.member_id INNER JOIN product_visit c\n" + + // + "WHERE a.member_id = c.member_id\n" + // + "\tAND c.member_id = 'abc'", output); + } + + public void test_select_20() throws Exception { + String sql = "select * from offer a straight_join wp_image b ignore index for join(t1,t2) on a.member_id=b.member_id inner join product_visit c where a.member_id=c.member_id and c.member_id='abc' "; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("SELECT *\n" + + // + "FROM offer a STRAIGHT_JOIN wp_image b IGNORE INDEX FOR JOIN (t1, t2) ON a.member_id = b.member_id INNER JOIN product_visit c\n" + + // + "WHERE a.member_id = c.member_id\n" + // + "\tAND c.member_id = 'abc'", output); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest.java new file mode 100644 index 0000000000..4fbd6811c3 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlAlterTableTest.java @@ -0,0 +1,31 @@ +package com.alibaba.druid.bvt.sql.mysql; + +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.Token; + +import junit.framework.Assert; +import junit.framework.TestCase; + + +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); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE `test`.`tb1`\n\tCHANGE COLUMN `fname` `fname1` VARCHAR(45) NULL", output); + } + + public void test_alter_1() throws Exception { + String sql = "ALTER TABLE `test`.`tb1` CHARACTER SET = utf8 , COLLATE = utf8_general_ci ;"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("ALTER TABLE `test`.`tb1`\n\tCHARACTER SET = utf8, COLLATE = utf8_general_ci", output); + } + +}