diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java index b8ab93d3c2..96669f9e2f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java @@ -24,9 +24,11 @@ import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.SQLPartitioningClause; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; @SuppressWarnings("serial") -public class MySqlCreateTableStatement extends SQLCreateTableStatement { +public class MySqlCreateTableStatement extends SQLCreateTableStatement implements MySqlStatement { private boolean ifNotExiists = false; @@ -111,4 +113,21 @@ public class MySqlCreateTableStatement extends SQLCreateTableStatement { this.ifNotExiists = ifNotExiists; } + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor instanceof MySqlASTVisitor) { + accept0((MySqlASTVisitor) visitor); + } else { + throw new IllegalArgumentException("not support visitor type : " + visitor.getClass().getName()); + } + } + + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + this.acceptChild(visitor, getHints()); + this.acceptChild(visitor, getTableSource()); + this.acceptChild(visitor, getTableElementList()); + } + visitor.endVisit(this); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlSelectQueryBlock.java index c34e49abec..d2a8fc0e39 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlSelectQueryBlock.java @@ -18,6 +18,7 @@ package com.alibaba.druid.sql.dialect.mysql.ast.statement; import java.util.ArrayList; import java.util.List; +import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLObjectImpl; @@ -30,29 +31,39 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; @SuppressWarnings("serial") public class MySqlSelectQueryBlock extends SQLSelectQueryBlock implements MySqlObject { - private boolean hignPriority; - private boolean straightJoin; + private boolean hignPriority; + private boolean straightJoin; - private boolean smallResult; - private boolean bigResult; - private boolean bufferResult; - private Boolean cache; - private boolean calcFoundRows; + private boolean smallResult; + private boolean bigResult; + private boolean bufferResult; + private Boolean cache; + private boolean calcFoundRows; - private SQLOrderBy orderBy; + private SQLOrderBy orderBy; - private Limit limit; + private Limit limit; - private SQLName procedureName; - private List procedureArgumentList = new ArrayList(); + private SQLName procedureName; + private List procedureArgumentList = new ArrayList(); - private boolean forUpdate = false; - private boolean lockInShareMode = false; + private boolean forUpdate = false; + private boolean lockInShareMode = false; + + private List hints = new ArrayList(); public MySqlSelectQueryBlock(){ } + public List getHints() { + return hints; + } + + public void setHints(List hints) { + this.hints = hints; + } + public boolean isForUpdate() { return forUpdate; } @@ -163,7 +174,7 @@ public class MySqlSelectQueryBlock extends SQLSelectQueryBlock implements MySqlO accept0((MySqlASTVisitor) visitor); return; } - + if (visitor.visit(this)) { acceptChild(visitor, this.selectList); acceptChild(visitor, this.from); @@ -178,7 +189,7 @@ public class MySqlSelectQueryBlock extends SQLSelectQueryBlock implements MySqlO visitor.endVisit(this); } - + @Override public void accept0(MySqlASTVisitor visitor) { if (visitor.visit(this)) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java index b9f218a543..c0acc9f5d3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java @@ -389,7 +389,7 @@ public class MySqlLexer extends Lexer { } if (isHint) { - stringVal = new String(buf, np + startHintSp, (sp - startHintSp) - 2).trim(); + stringVal = new String(buf, np + startHintSp, (sp - startHintSp) - 1); token = Token.HINT; } else { stringVal = new String(buf, np, sp); 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 40179873c6..6a0c6fa9a8 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 @@ -64,6 +64,10 @@ public class MySqlSelectParser extends SQLSelectParser { if (lexer.token() == Token.SELECT) { lexer.nextToken(); + + if (lexer.token() == Token.HINT) { + this.createExprParser().parseHints(queryBlock.getHints()); + } if (lexer.token() == (Token.DISTINCT)) { queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT); 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 101802a554..f48fc9bc90 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 @@ -37,6 +37,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatemen import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateIndexStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement; @@ -495,4 +496,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlAlterTableOption x); void endVisit(MySqlAlterTableOption x); + + boolean visit(MySqlCreateTableStatement x); + + void endVisit(MySqlCreateTableStatement 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 59564c039f..32adaf97fb 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 @@ -22,6 +22,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatemen import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateIndexStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement.UserSpecification; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; @@ -1079,4 +1080,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements public void endVisit(MySqlAlterTableOption x) { } + + @Override + public boolean visit(MySqlCreateTableStatement x) { + return true; + } + + @Override + public void endVisit(MySqlCreateTableStatement 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 32e359870d..d90a15ad1b 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 @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.dialect.mysql.visitor; import java.util.Map; +import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLSetQuantifier; @@ -161,6 +162,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } print("SELECT "); + + + for (SQLCommentHint hint : x.getHints()) { + hint.accept(this); + print(' '); + } if (SQLSetQuantifier.ALL == x.getDistionOption()) print("ALL "); else if (SQLSetQuantifier.DISTINCT == x.getDistionOption()) print("DISTINCT "); @@ -359,20 +366,22 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV return false; } - public boolean visit(SQLCreateTableStatement x) { + public boolean visit(MySqlCreateTableStatement x) { - MySqlCreateTableStatement mysqlCreateTableStatement = null; - if (x instanceof MySqlCreateTableStatement) { - mysqlCreateTableStatement = (MySqlCreateTableStatement) x; + print("CREATE "); + + for (SQLCommentHint hint : x.getHints()) { + hint.accept(this); + print(' '); } if (SQLCreateTableStatement.Type.GLOBAL_TEMPORARY.equals(x.getType())) { - print("CREATE TEMPORARY TABLE "); + print("TEMPORARY TABLE "); } else { - print("CREATE TABLE "); + print("TABLE "); } - if (mysqlCreateTableStatement != null && mysqlCreateTableStatement.isIfNotExiists()) { + if (x.isIfNotExiists()) { print("IF NOT EXISTS "); } @@ -391,20 +400,18 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); print(")"); - if (mysqlCreateTableStatement != null) { - for (Map.Entry option : mysqlCreateTableStatement.getTableOptions().entrySet()) { - print(" "); - print(option.getKey()); - print(" = "); - print(option.getValue()); - } + for (Map.Entry option : x.getTableOptions().entrySet()) { + print(" "); + print(option.getKey()); + print(" = "); + print(option.getValue()); } - if (mysqlCreateTableStatement != null && mysqlCreateTableStatement.getQuery() != null) { + if (x.getQuery() != null) { print(" "); incrementIndent(); println(); - mysqlCreateTableStatement.getQuery().accept(this); + x.getQuery().accept(this); decrementIndent(); } @@ -2525,12 +2532,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV public boolean visit(MySqlAlterTableCharacter x) { print("CHARACTER SET = "); x.getCharacterSet().accept(this); - + if (x.getCollate() != null) { print(", COLLATE = "); x.getCollate().accept(this); } - + return false; } @@ -2563,7 +2570,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public void endVisit(MySqlAlterTableAddIndex x) { - + } @Override @@ -2576,6 +2583,11 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public void endVisit(MySqlAlterTableOption x) { - + + } + + @Override + public void endVisit(MySqlCreateTableStatement 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 d261bb4e99..dd04eae6c5 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 @@ -4,6 +4,7 @@ import java.util.Map; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; @@ -32,6 +33,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatemen import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateIndexStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement.UserSpecification; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; @@ -1143,4 +1145,14 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public void endVisit(MySqlAlterTableOption x) { } + + @Override + public boolean visit(MySqlCreateTableStatement x) { + return super.visit((SQLCreateTableStatement) x); + } + + @Override + public void endVisit(MySqlCreateTableStatement x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java index e0da7f3583..292686f47a 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java @@ -239,7 +239,7 @@ public class OracleLexer extends Lexer { } if (isHint) { - stringVal = new String(buf, np + startHintSp, (sp - startHintSp) - 2).trim(); + stringVal = new String(buf, np + startHintSp, (sp - startHintSp) - 1); token = Token.HINT; } else { stringVal = new String(buf, np, sp); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java index 06ea421419..b0b6f519a3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleASTVisitor.java @@ -15,7 +15,6 @@ */ package com.alibaba.druid.sql.dialect.oracle.visitor; -import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.expr.SQLObjectCreateExpr; import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy; import com.alibaba.druid.sql.dialect.oracle.ast.clause.CycleClause; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index 0391cded3e..d36d120b78 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -17,7 +17,6 @@ package com.alibaba.druid.sql.dialect.oracle.visitor; import java.util.List; -import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLHint; @@ -906,11 +905,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } - @Override - public void endVisit(SQLCommentHint x) { - - } - @Override public void endVisit(OracleIntervalExpr x) { @@ -2181,7 +2175,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS print(x.getType()); print(" "); } - + print("INDEX "); x.getName().accept(this); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 62eff614b3..ce562d9e52 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -1092,7 +1092,9 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { } public boolean visit(SQLCommentHint x) { + print("/*"); print(x.getText()); + print("*/"); return false; } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/HintsTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/HintsTest.java index 96fd534653..29bfdd12f5 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/HintsTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/HintsTest.java @@ -17,6 +17,15 @@ public class HintsTest extends TestCase { SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); String output = SQLUtils.toMySqlString(stmt); - Assert.assertEquals("CREATE TABLE t (\n\ta INT\n)", output); + Assert.assertEquals("CREATE /*!32302 TEMPORARY */ TABLE t (\n\ta INT\n)", output); + } + + public void test_hints_1() throws Exception { + String sql = "SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(stmt); + Assert.assertEquals("SELECT /*! STRAIGHT_JOIN */ col1\nFROM table1, table2", output); } }