diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index 58c319e438..1cde04911c 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -37,13 +37,15 @@ import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisito import com.alibaba.druid.sql.parser.*; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.sql.visitor.VisitorFeature; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.*; public class SQLUtils { public static FormatOption DEFAULT_FORMAT_OPTION = new FormatOption(true, true); - public static FormatOption DEFAULT_LCASE_FORMAT_OPTION = new FormatOption(false, true); + public static FormatOption DEFAULT_LCASE_FORMAT_OPTION + = new FormatOption(false, true); private final static Log LOG = LogFactory.getLog(SQLUtils.class); @@ -61,6 +63,7 @@ public class SQLUtils { visitor.setUppCase(option.isUppCase()); visitor.setPrettyFormat(option.isPrettyFormat()); visitor.setParameterized(option.isParameterized()); + visitor.setFeatures(option.features); sqlObject.accept(visitor); @@ -85,7 +88,11 @@ public class SQLUtils { } public static String toMySqlString(SQLObject sqlObject) { - return toMySqlString(sqlObject, null); + return toMySqlString(sqlObject, (FormatOption) null); + } + + public static String toMySqlString(SQLObject sqlObject, VisitorFeature... features) { + return toMySqlString(sqlObject, new FormatOption(features)); } public static String toMySqlString(SQLObject sqlObject, FormatOption option) { @@ -269,10 +276,7 @@ public class SQLUtils { if (option == null) { option = DEFAULT_FORMAT_OPTION; } - visitor.setUppCase(option.isUppCase()); - visitor.setPrettyFormat(option.prettyFormat); - visitor.setParameterized(option.parameterized); - visitor.setDesensitize(option.desensitize); + visitor.setFeatures(option.features); if (tableMapping != null) { visitor.setTableMapping(tableMapping); @@ -621,16 +625,17 @@ public class SQLUtils { } public static class FormatOption { - - private boolean ucase = true; - private boolean prettyFormat = true; - private boolean parameterized = false; - private boolean desensitize = false; + private int features = VisitorFeature.of(VisitorFeature.OutputUCase + , VisitorFeature.OutputPrettyFormat); public FormatOption() { } + public FormatOption(VisitorFeature... features) { + this.features = VisitorFeature.of(features); + } + public FormatOption(boolean ucase) { this(ucase, true); } @@ -640,41 +645,49 @@ public class SQLUtils { } public FormatOption(boolean ucase, boolean prettyFormat, boolean parameterized) { - this.ucase = ucase; - this.prettyFormat = prettyFormat; - this.parameterized = parameterized; + this.features = VisitorFeature.config(this.features, VisitorFeature.OutputUCase, ucase); + this.features = VisitorFeature.config(this.features, VisitorFeature.OutputPrettyFormat, prettyFormat); + this.features = VisitorFeature.config(this.features, VisitorFeature.OutputParameterized, parameterized); } public boolean isDesensitize() { - return desensitize; + return isEnabled(VisitorFeature.OutputDesensitize); } - public void setDesensitize(boolean desensitize) { - this.desensitize = desensitize; + public void setDesensitize(boolean val) { + config(VisitorFeature.OutputDesensitize, val); } public boolean isUppCase() { - return ucase; + return isEnabled(VisitorFeature.OutputUCase); } public void setUppCase(boolean val) { - this.ucase = val; + config(VisitorFeature.OutputUCase, val); } public boolean isPrettyFormat() { - return prettyFormat; + return isEnabled(VisitorFeature.OutputPrettyFormat); } public void setPrettyFormat(boolean prettyFormat) { - this.prettyFormat = prettyFormat; + config(VisitorFeature.OutputPrettyFormat, prettyFormat); } public boolean isParameterized() { - return parameterized; + return isEnabled(VisitorFeature.OutputParameterized); } public void setParameterized(boolean parameterized) { - this.parameterized = parameterized; + config(VisitorFeature.OutputParameterized, parameterized); + } + + public void config(VisitorFeature feature, boolean state) { + features = VisitorFeature.config(features, feature, state); + } + + public final boolean isEnabled(VisitorFeature feature) { + return VisitorFeature.isEnabled(this.features, feature); } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLInsertStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLInsertStatement.java index 3f4b9aab74..ad6a5b7039 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLInsertStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLInsertStatement.java @@ -71,6 +71,8 @@ public class SQLInsertStatement extends SQLInsertInto implements SQLStatement { private final List values; + private transient String originalString; + public ValuesClause(){ this(new ArrayList()); } @@ -118,6 +120,14 @@ public class SQLInsertStatement extends SQLInsertInto implements SQLStatement { visitor.endVisit(this); } + + public String getOriginalString() { + return originalString; + } + + public void setOriginalString(String originalString) { + this.originalString = originalString; + } } @Override 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 055cd38109..dd8859c9f6 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 @@ -44,11 +44,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlSelectIntoStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.*; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement.LockType; -import com.alibaba.druid.sql.parser.Lexer; -import com.alibaba.druid.sql.parser.ParserException; -import com.alibaba.druid.sql.parser.SQLSelectParser; -import com.alibaba.druid.sql.parser.SQLStatementParser; -import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.sql.parser.*; import com.alibaba.druid.util.JdbcConstants; import java.util.ArrayList; @@ -2229,6 +2225,8 @@ public class MySqlStatementParser extends SQLStatementParser { private void parseValueClause(List valueClauseList, int columnSize) { for (int i = 0; ; ++i) { + int startPos = lexer.pos() - 1; + if (lexer.token() != Token.LPAREN) { throw new ParserException("syntax error, expect ')', " + lexer.info()); } @@ -2281,6 +2279,13 @@ public class MySqlStatementParser extends SQLStatementParser { } SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList); + + if (lexer.isEnabled(SQLParserFeature.KeepInsertValueClauseOriginalString)) { + int endPos = lexer.pos(); + String orginalString = lexer.subString(startPos, endPos - startPos); + values.setOriginalString(orginalString); + } + valueClauseList.add(values); } else { SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); 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 a10b4d0d57..b6e2d7e9a5 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 @@ -47,10 +47,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.*; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement.TableSpaceOption; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement.UserSpecification; -import com.alibaba.druid.sql.visitor.ExportParameterVisitor; -import com.alibaba.druid.sql.visitor.ExportParameterVisitorUtils; -import com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils; -import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; +import com.alibaba.druid.sql.visitor.*; import com.alibaba.druid.util.JdbcConstants; import java.io.IOException; @@ -81,7 +78,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } public void configFromProperty(Properties properties) { - if (parameterized) { + if (isEnabled(VisitorFeature.OutputParameterized)) { String property = properties.getProperty("druid.parameterized.shardingSupport"); if ("true".equals(property)) { this.setShardingSupport(true); @@ -92,7 +89,8 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } public boolean isShardingSupport() { - return parameterized && shardingSupport; + return isEnabled(VisitorFeature.OutputParameterized) + && shardingSupport; } public void setShardingSupport(boolean shardingSupport) { @@ -573,7 +571,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } try { - if (this.parameterized + if (this.isEnabled(VisitorFeature.OutputParameterized) && ParameterizedOutputVisitorUtils.checkParameterize(x)) { this.appender.append('?'); incrementReplaceCunt(); @@ -1001,7 +999,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV protected void printValuesList(List valuesList) { - if (parameterized) { + if (isEnabled(VisitorFeature.OutputParameterized)) { print0(ucase ? "VALUES " : "values "); incrementIndent(); valuesList.get(0).accept(this); @@ -2774,7 +2772,8 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlCharExpr x) { - if (parameterized && ParameterizedOutputVisitorUtils.checkParameterize(x)) { + if (isEnabled(VisitorFeature.OutputParameterized) + && ParameterizedOutputVisitorUtils.checkParameterize(x)) { print('?'); incrementReplaceCunt(); if (this instanceof ExportParameterVisitor || this.parameters != null) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleParameterizedOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleParameterizedOutputVisitor.java index f837c69877..0e975d2c40 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleParameterizedOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleParameterizedOutputVisitor.java @@ -22,26 +22,23 @@ import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLNCharExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; -import com.alibaba.druid.sql.visitor.ExportParameterVisitor; -import com.alibaba.druid.sql.visitor.ExportParameterVisitorUtils; -import com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils; -import com.alibaba.druid.sql.visitor.ParameterizedVisitor; +import com.alibaba.druid.sql.visitor.*; public class OracleParameterizedOutputVisitor extends OracleOutputVisitor implements ParameterizedVisitor { public OracleParameterizedOutputVisitor(){ this(new StringBuilder()); - this.parameterized = true; + this.config(VisitorFeature.OutputParameterized, true); } public OracleParameterizedOutputVisitor(Appendable appender){ super(appender); - this.parameterized = true; + this.config(VisitorFeature.OutputParameterized, true); } public OracleParameterizedOutputVisitor(Appendable appender, boolean printPostSemi){ super(appender, printPostSemi); - this.parameterized = true; + this.config(VisitorFeature.OutputParameterized, true); } public boolean visit(SQLBinaryOpExpr x) { diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index b2b605db3a..ee6606caee 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -47,7 +47,7 @@ import com.alibaba.druid.util.StringUtils; * @author wenshao [szujobs@hotmail.com] */ public class Lexer { - + protected int features; protected final String text; protected int pos; protected int mark; @@ -1644,4 +1644,12 @@ public class Lexer { public int getPosColumn() { return posColumn; } + + public void config(SQLParserFeature feature, boolean state) { + features = SQLParserFeature.config(features, feature, state); + } + + public final boolean isEnabled(SQLParserFeature feature) { + return SQLParserFeature.isEnabled(this.features, feature); + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java index 7645c78564..748406b56d 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLParser.java @@ -21,6 +21,8 @@ public class SQLParser { protected String dbType; + + public SQLParser(String sql, String dbType){ this(new Lexer(sql, null, dbType), dbType); this.lexer.nextToken(); @@ -316,4 +318,11 @@ public class SQLParser { } } + public void config(SQLParserFeature feature, boolean state) { + this.lexer.config(feature, state); + } + + public final boolean isEnabled(SQLParserFeature feature) { + return lexer.isEnabled(feature); + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLParserFeature.java b/src/main/java/com/alibaba/druid/sql/parser/SQLParserFeature.java new file mode 100644 index 0000000000..73f8b6ee5e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLParserFeature.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.sql.parser; + +public enum SQLParserFeature { + KeepInsertValueClauseOriginalString + ; + + private SQLParserFeature(){ + mask = (1 << ordinal()); + } + + public final int mask; + + + public static boolean isEnabled(int features, SQLParserFeature feature) { + return (features & feature.mask) != 0; + } + + public static int config(int features, SQLParserFeature feature, boolean state) { + if (state) { + features |= feature.mask; + } else { + features &= ~feature.mask; + } + + return features; + } + + public static int of(SQLParserFeature[] features) { + if (features == null) { + return 0; + } + + int value = 0; + + for (SQLParserFeature feature: features) { + value |= feature.mask; + } + + return value; + } +} 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 258008c1ac..3a46f8de99 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -39,6 +39,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.OracleSegmentAttributes; import com.alibaba.druid.sql.ast.statement.SQLDeclareStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreatePackageStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleForStatement; +import com.alibaba.druid.sql.visitor.functions.Ucase; import com.alibaba.druid.util.JdbcConstants; import com.alibaba.druid.util.JdbcUtils; @@ -54,7 +55,6 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet protected final Appendable appender; private String indent = "\t"; protected int indentCount = 0; - private boolean prettyFormat = true; protected boolean ucase = true; protected int selectListNumberOfLine = 5; @@ -72,17 +72,19 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet protected int replaceCount; - protected boolean parameterized = false; protected boolean parameterizedMergeInList = false; protected boolean shardingSupport = false; protected transient int lines = 0; - protected boolean desensitize = false; protected Boolean printStatementAfterSemi = defaultPrintStatementAfterSemi; + { + features |= VisitorFeature.OutputPrettyFormat.mask; + } + public SQLASTOutputVisitor(Appendable appender){ this.appender = appender; } @@ -94,7 +96,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet public SQLASTOutputVisitor(Appendable appender, boolean parameterized){ this.appender = appender; - this.parameterized = parameterized; + this.config(VisitorFeature.OutputParameterized, parameterized); } public int getReplaceCount() { @@ -125,11 +127,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean isDesensitize() { - return desensitize; + return isEnabled(VisitorFeature.OutputDesensitize); } public void setDesensitize(boolean desensitize) { - this.desensitize = desensitize; + config(VisitorFeature.OutputDesensitize, desensitize); } public Set getTables() { @@ -158,11 +160,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean isPrettyFormat() { - return prettyFormat; + return isEnabled(VisitorFeature.OutputPrettyFormat); } public void setPrettyFormat(boolean prettyFormat) { - this.prettyFormat = prettyFormat; + config(VisitorFeature.OutputPrettyFormat, prettyFormat); } public void decrementIndent() { @@ -174,11 +176,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean isParameterized() { - return parameterized; + return isEnabled(VisitorFeature.OutputParameterized); } public void setParameterized(boolean parameterized) { - this.parameterized = parameterized; + config(VisitorFeature.OutputParameterized, parameterized); } public boolean isParameterizedMergeInList() { @@ -315,7 +317,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } protected void printSelectList(List selectList) { - incrementIndent(); + this.indentCount++; for (int i = 0, lineItemCount = 0, size = selectList.size() ; i < size; ++i, ++lineItemCount) { SQLSelectItem selectItem = selectList.get(i); @@ -361,7 +363,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet printlnComment(selectItem.getAfterCommentsDirect()); } } - decrementIndent(); + this.indentCount--; } protected void printlnAndAccept(List nodes, String seperator) { @@ -420,7 +422,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLBinaryOpExpr x) { - if (this.parameterized) { + if (this.isEnabled(VisitorFeature.OutputParameterized)) { x = ParameterizedOutputVisitorUtils.merge(this, x); } @@ -701,7 +703,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLCharExpr x) { - if (this.parameterized + if (this.isEnabled(VisitorFeature.OutputParameterized) && ParameterizedOutputVisitorUtils.checkParameterize(x)) { print('?'); incrementReplaceCunt(); @@ -789,7 +791,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet public boolean visit(SQLIdentifierExpr x) { final String name = x.getName(); - if (!parameterized) { + if (!this.isEnabled(VisitorFeature.OutputParameterized)) { print0(x.getName()); return false; } @@ -798,7 +800,8 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } private boolean printName(SQLName x, String name) { - boolean shardingSupport = this.shardingSupport && parameterized; + boolean shardingSupport = this.shardingSupport + && this.isEnabled(VisitorFeature.OutputParameterized); return printName(x, name, shardingSupport); } @@ -885,7 +888,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLInListExpr x) { - if (this.parameterized) { + if (this.isEnabled(VisitorFeature.OutputParameterized)) { List targetList = x.getTargetList(); boolean allLiteral = true; @@ -995,7 +998,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } } } - if (this.parameterized + if (this.isEnabled(VisitorFeature.OutputParameterized) && ParameterizedOutputVisitorUtils.checkParameterize(x)) { if (!ParameterizedOutputVisitorUtils.checkParameterize(x)) { print(val); @@ -1032,7 +1035,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } SQLExpr param = x.getParameters().get(i); - if (parameterized) { + if (isEnabled(VisitorFeature.OutputParameterized)) { if (size == 2 && i == 1 && param instanceof SQLCharExpr) { if (JdbcUtils.ORACLE.equals(dbType)) { if ("TO_CHAR".equalsIgnoreCase(function) @@ -1126,7 +1129,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLNCharExpr x) { - if (this.parameterized + if (this.isEnabled(VisitorFeature.OutputParameterized) && ParameterizedOutputVisitorUtils.checkParameterize(x)) { print('?'); incrementReplaceCunt(); @@ -1170,7 +1173,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLNullExpr x) { - if (this.parameterized + if (this.isEnabled(VisitorFeature.OutputParameterized) && ParameterizedOutputVisitorUtils.checkParameterize(x)) { SQLObject parent = x.getParent(); if (parent instanceof ValuesClause) { @@ -1189,7 +1192,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } public boolean visit(SQLNumberExpr x) { - if (this.parameterized + if (this.isEnabled(VisitorFeature.OutputParameterized) && ParameterizedOutputVisitorUtils.checkParameterize(x)) { print('?'); incrementReplaceCunt(); @@ -1578,7 +1581,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet addTable(expr.toString()); } - if (desensitize) { + if (isEnabled(VisitorFeature.OutputDesensitize)) { SQLExpr owner = null; String ident = null; if (expr instanceof SQLIdentifierExpr) { @@ -2208,7 +2211,8 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(SQLHexExpr x) { - if (this.parameterized && ParameterizedOutputVisitorUtils.checkParameterize(x)) { + if (this.isEnabled(VisitorFeature.OutputParameterized) + && ParameterizedOutputVisitorUtils.checkParameterize(x)) { print('?'); incrementReplaceCunt(); @@ -2348,6 +2352,13 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(ValuesClause x) { + if ((!isEnabled(VisitorFeature.OutputParameterized)) + && isEnabled(VisitorFeature.OutputUseInsertValueClauseOriginalString) + && x.getOriginalString() != null) { + print0(x.getOriginalString()); + return false; + } + print('('); this.indentCount++; @@ -4839,4 +4850,16 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet public void setPrintStatementAfterSemi(Boolean printStatementAfterSemi) { this.printStatementAfterSemi = printStatementAfterSemi; } + + public void config(VisitorFeature feature, boolean state) { + super.config(feature, state); + if (feature == VisitorFeature.OutputUCase) { + this.ucase = state; + } + } + + public void setFeatures(int features) { + super.setFeatures(features); + this.ucase = isEnabled(VisitorFeature.OutputUCase); + } } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java index 04e6a2b9d1..aa32275cf8 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -24,8 +24,10 @@ import com.alibaba.druid.sql.ast.statement.SQLMergeStatement.MergeUpdateClause; import com.alibaba.druid.sql.ast.statement.SQLWhileStatement; import com.alibaba.druid.sql.ast.statement.SQLDeclareStatement; import com.alibaba.druid.sql.ast.statement.SQLCommitStatement; +import com.alibaba.druid.sql.parser.SQLParserFeature; public class SQLASTVisitorAdapter implements SQLASTVisitor { + protected int features; public void endVisit(SQLAllColumnExpr x) { } @@ -1672,4 +1674,20 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { public void endVisit(SQLCreateMaterializedViewStatement x) { } + + public void config(VisitorFeature feature, boolean state) { + features = VisitorFeature.config(features, feature, state); + } + + public final boolean isEnabled(VisitorFeature feature) { + return VisitorFeature.isEnabled(this.features, feature); + } + + public int getFeatures() { + return features; + } + + public void setFeatures(int features) { + this.features = features; + } } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/VisitorFeature.java b/src/main/java/com/alibaba/druid/sql/visitor/VisitorFeature.java new file mode 100644 index 0000000000..07dd21cf15 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/visitor/VisitorFeature.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.sql.visitor; + +public enum VisitorFeature { + OutputUCase, + OutputPrettyFormat, + OutputParameterized, + OutputDesensitize, + OutputUseInsertValueClauseOriginalString + + ; + + private VisitorFeature(){ + mask = (1 << ordinal()); + } + + public final int mask; + + + public static boolean isEnabled(int features, VisitorFeature feature) { + return (features & feature.mask) != 0; + } + + public static int config(int features, VisitorFeature feature, boolean state) { + if (state) { + features |= feature.mask; + } else { + features &= ~feature.mask; + } + + return features; + } + + public static int of(VisitorFeature... features) { + if (features == null) { + return 0; + } + + int value = 0; + + for (VisitorFeature feature: features) { + value |= feature.mask; + } + + return value; + } +} diff --git a/src/test/java/com/alibaba/druid/benckmark/sql/MySqlInsertBenchmark_2.java b/src/test/java/com/alibaba/druid/benckmark/sql/MySqlInsertBenchmark_2.java index 4d0487718f..6d022dc133 100644 --- a/src/test/java/com/alibaba/druid/benckmark/sql/MySqlInsertBenchmark_2.java +++ b/src/test/java/com/alibaba/druid/benckmark/sql/MySqlInsertBenchmark_2.java @@ -2,6 +2,10 @@ package com.alibaba.druid.benckmark.sql; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.parser.SQLParserFeature; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.sql.parser.SQLStatementParser; +import com.alibaba.druid.sql.visitor.VisitorFeature; import com.alibaba.druid.util.JdbcConstants; import junit.framework.TestCase; @@ -16,15 +20,17 @@ public class MySqlInsertBenchmark_2 extends TestCase { List stmtList; protected void setUp() throws Exception { - stmtList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL); - + SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, JdbcConstants.MYSQL); + parser.config(SQLParserFeature.KeepInsertValueClauseOriginalString, true); + stmtList = parser.parseStatementList(); } public void test_perf() throws Exception { System.out.println(sql); for (int i = 0; i < 5; ++i) { - perf(); // 5043 +// perf(); // 5043 // perf_toString(); // 2101 + perf_toString_featured(); } } @@ -32,6 +38,7 @@ public class MySqlInsertBenchmark_2 extends TestCase { long startMillis = System.currentTimeMillis(); for (int i = 0; i < 1000 * 1000; ++i) { + List stmt = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL); // stmt.toString(); } @@ -39,6 +46,19 @@ public class MySqlInsertBenchmark_2 extends TestCase { System.out.println("millis : " + millis); } + public void perf_keepInsertValueClauseStrinng() { + long startMillis = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + + SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, JdbcConstants.MYSQL); + parser.config(SQLParserFeature.KeepInsertValueClauseOriginalString, true); + List stmtList = parser.parseStatementList(); +// stmt.toString(); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("millis : " + millis); + } + public void perf_toString() { long startMillis = System.currentTimeMillis(); for (int i = 0; i < 1000 * 1000; ++i) { @@ -47,4 +67,13 @@ public class MySqlInsertBenchmark_2 extends TestCase { long millis = System.currentTimeMillis() - startMillis; System.out.println("millis : " + millis); } + + public void perf_toString_featured() { + long startMillis = System.currentTimeMillis(); + for (int i = 0; i < 1000 * 1000; ++i) { + SQLUtils.toMySqlString(stmtList.get(0), VisitorFeature.OutputUseInsertValueClauseOriginalString); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("millis : " + millis); + } }