improved sql parser.

This commit is contained in:
wenshao
2017-09-09 07:41:39 +08:00
parent 6545e23629
commit 3330643479
50 changed files with 1898 additions and 195 deletions
@@ -27,6 +27,7 @@ import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.alibaba.druid.VERSION;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterEventAdapter;
@@ -145,7 +146,7 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
try {
sql = ParameterizedOutputVisitorUtils.parameterize(sql, dbType);
} catch (Exception e) {
LOG.error("merge sql error, dbType " + dbType + ", sql : " + sql, e);
LOG.error("merge sql error, dbType " + dbType + ", druid-" + VERSION.getVersionNumber() + ", sql : " + sql, e);
}
return sql;
@@ -168,7 +168,7 @@ public class SQLTransformUtils {
dataType = new SQLDataTypeImpl("smallint");
} else if (precision < 9) {
dataType = new SQLDataTypeImpl("int");
} else if (precision < 19) {
} else if (precision <= 20) {
dataType = new SQLDataTypeImpl("bigint");
} else {
dataType = new SQLDataTypeImpl("decimal", precision);
@@ -468,7 +468,7 @@ public class SQLTransformUtils {
dataType = new SQLDataTypeImpl("smallint");
} else if (precision < 9) {
dataType = new SQLDataTypeImpl("int");
} else if (precision < 19) {
} else if (precision <= 20) {
dataType = new SQLDataTypeImpl("bigint");
} else {
dataType = new SQLDataTypeImpl("decimal", precision);
@@ -234,7 +234,9 @@ public class SQLUtils {
public static String format(String sql, String dbType, List<Object> parameters, FormatOption option) {
try {
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, true);
SQLParserFeature[] features = {SQLParserFeature.KeepComments, SQLParserFeature.EnableSQLBinaryOpExprGroup};
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType, features);
parser.setKeepComments(true);
List<SQLStatement> statementList = parser.parseStatementList();
@@ -33,4 +33,7 @@ public interface SQLDataType extends SQLObject {
boolean isWithLocalTimeZone();
SQLDataType clone();
void setDbType(String dbType);
String getDbType();
}
@@ -15,6 +15,7 @@
*/
package com.alibaba.druid.sql.ast;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.FnvHash;
@@ -24,11 +25,12 @@ import java.util.List;
public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
private String name;
private long nameHashCode64;
private String name;
private long nameHashCode64;
protected final List<SQLExpr> arguments = new ArrayList<SQLExpr>();
private Boolean withTimeZone;
private boolean withLocalTimeZone = false;
private Boolean withTimeZone;
private boolean withLocalTimeZone = false;
private String dbType;
public SQLDataTypeImpl(){
@@ -122,6 +124,14 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
this.withLocalTimeZone = withLocalTimeZone;
}
public String getDbType() {
return dbType;
}
public void setDbType(String dbType) {
this.dbType = dbType;
}
public SQLDataTypeImpl clone() {
SQLDataTypeImpl x = new SQLDataTypeImpl();
@@ -131,6 +141,7 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
}
public void cloneTo(SQLDataTypeImpl x) {
x.dbType = dbType;
x.name = name;
for (SQLExpr arg : arguments) {
@@ -140,4 +151,8 @@ public class SQLDataTypeImpl extends SQLObjectImpl implements SQLDataType {
x.withTimeZone = withTimeZone;
x.withLocalTimeZone = withLocalTimeZone;
}
public String toString() {
return SQLUtils.toSQLString(this, dbType);
}
}
@@ -45,6 +45,14 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName {
return name;
}
public String getLowerName() {
if (name == null) {
return null;
}
return name.toLowerCase();
}
public String getName() {
return this.name;
}
@@ -36,9 +36,6 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName {
}
public SQLPropertyExpr(SQLExpr owner, String name){
if (name == null) {
throw new IllegalArgumentException("name is null.");
}
setOwner(owner);
this.name = name;
}
@@ -23,6 +23,7 @@ public interface SQLForeignKeyConstraint extends SQLConstraint, SQLTableElement,
List<SQLName> getReferencingColumns();
SQLExprTableSource getReferencedTable();
SQLName getReferencedTableName();
void setReferencedTableName(SQLName value);
@@ -22,12 +22,11 @@ import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLForeignKeyImpl extends SQLConstraintImpl implements SQLForeignKeyConstraint {
private SQLName referencedTableName;
private List<SQLName> referencingColumns = new ArrayList<SQLName>();
private List<SQLName> referencedColumns = new ArrayList<SQLName>();
private boolean onDeleteCascade = false;
private boolean onDeleteSetNull = false;
private SQLExprTableSource referencedTable;
private List<SQLName> referencingColumns = new ArrayList<SQLName>();
private List<SQLName> referencedColumns = new ArrayList<SQLName>();
private boolean onDeleteCascade = false;
private boolean onDeleteSetNull = false;
public SQLForeignKeyImpl(){
@@ -38,14 +37,33 @@ public class SQLForeignKeyImpl extends SQLConstraintImpl implements SQLForeignKe
return referencingColumns;
}
@Override
public SQLExprTableSource getReferencedTable() {
return referencedTable;
}
@Override
public SQLName getReferencedTableName() {
return referencedTableName;
if (referencedTable == null) {
return null;
}
return referencedTable.getName();
}
@Override
public void setReferencedTableName(SQLName value) {
this.referencedTableName = value;
if (value == null) {
this.referencedTable = null;
return;
}
this.setReferencedTable(new SQLExprTableSource(value));
}
public void setReferencedTable(SQLExprTableSource x) {
if (x != null) {
x.setParent(this);
}
this.referencedTable = x;
}
@Override
@@ -83,8 +101,8 @@ public class SQLForeignKeyImpl extends SQLConstraintImpl implements SQLForeignKe
public void cloneTo(SQLForeignKeyImpl x) {
super.cloneTo(x);
if (referencedTableName != null) {
x.setReferencedTableName(referencedTableName.clone());
if (referencedTable != null) {
x.setReferencedTable(referencedTable.clone());
}
for (SQLName column : referencingColumns) {
@@ -102,21 +102,21 @@ public class DB2ExprParser extends SQLExprParser {
}
protected SQLExpr dotRest(SQLExpr expr) {
if (lexer.identifierEquals("NEXTVAL")) {
if (lexer.identifierEquals(FnvHash.Constants.NEXTVAL)) {
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.NextVal);
lexer.nextToken();
return seqExpr;
}
} else if (lexer.identifierEquals("PREVVAL")) {
} else if (lexer.identifierEquals(FnvHash.Constants.PREVVAL)) {
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.PrevVal);
lexer.nextToken();
return seqExpr;
}
} else if (lexer.identifierEquals("CURRVAL")) {
} else if (lexer.identifierEquals(FnvHash.Constants.CURRVAL)) {
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.CurrVal);
@@ -63,15 +63,15 @@ public class MySqlCreateTableParser extends SQLCreateTableParser {
super(exprParser);
}
public SQLCreateTableStatement parseCrateTable() {
return parseCrateTable(true);
public SQLCreateTableStatement parseCreateTable() {
return parseCreateTable(true);
}
public MySqlExprParser getExprParser() {
return (MySqlExprParser) exprParser;
}
public MySqlCreateTableStatement parseCrateTable(boolean acceptCreate) {
public MySqlCreateTableStatement parseCreateTable(boolean acceptCreate) {
MySqlCreateTableStatement stmt = new MySqlCreateTableStatement();
if (acceptCreate) {
if (lexer.hasComment() && lexer.isKeepComments()) {
@@ -120,6 +120,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser {
|| lexer.token() == Token.PRIMARY //
|| lexer.token() == Token.UNIQUE) {
SQLTableConstraint constraint = this.parseConstraint();
constraint.setParent(stmt);
stmt.getTableElementList().add(constraint);
} else if (lexer.token() == (Token.INDEX)) {
lexer.nextToken();
@@ -712,7 +712,7 @@ public class MySqlExprParser extends SQLExprParser {
}
accept(Token.LPAREN);
this.names(fk.getReferencingColumns());
this.names(fk.getReferencingColumns(), fk);
accept(Token.RPAREN);
accept(Token.REFERENCES);
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.Map;
import com.alibaba.druid.sql.parser.*;
import com.alibaba.druid.util.FnvHash;
public class MySqlLexer extends Lexer {
public static SymbolTable quoteTable = new SymbolTable(8192);
@@ -226,7 +227,8 @@ public class MySqlLexer extends Lexer {
final char first = ch;
if (ch == 'b' && charAt(pos + 1) == '\'') {
if (ch == 'b'
&& charAt(pos + 1) == '\'') {
int i = 2;
int mark = pos + 2;
for (;;++i) {
@@ -336,6 +338,7 @@ public class MySqlLexer extends Lexer {
token = Token.IDENTIFIER;
stringVal = SymbolTable.global.addSymbol(text, mark, bufPos, hash);
}
}
}
@@ -395,7 +398,9 @@ public class MySqlLexer extends Lexer {
stringVal = this.subString(mark + startHintSp, starIndex - startHintSp - mark);
token = Token.HINT;
} else {
stringVal = this.subString(mark, starIndex + 2 - mark);
if (!optimizedForParameterized) {
stringVal = this.subString(mark, starIndex + 2 - mark);
}
token = Token.MULTI_LINE_COMMENT;
commentCount++;
if (keepComments) {
@@ -114,7 +114,7 @@ public class MySqlStatementParser extends SQLStatementParser {
public SQLCreateTableStatement parseCreateTable() {
MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser);
return parser.parseCrateTable();
return parser.parseCreateTable();
}
public SQLStatement parseSelect() {
@@ -230,7 +230,7 @@ public class MySqlStatementParser extends SQLStatementParser {
lexer.reset(markBp, markChar, Token.CREATE);
}
MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser);
MySqlCreateTableStatement stmt = parser.parseCrateTable(false);
MySqlCreateTableStatement stmt = parser.parseCreateTable(false);
stmt.setHints(hints);
if (comments != null) {
@@ -200,13 +200,13 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
SQLOrderBy orderBy = x.getOrderBy();
if (orderBy != null) {
println();
orderBy.accept(this);
visit(orderBy);
}
SQLLimit limit = x.getLimit();
if (limit != null) {
println();
limit.accept(this);
visit(limit);
}
SQLName procedureName = x.getProcedureName();
@@ -1057,7 +1057,7 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
@Override
public boolean visit(MysqlForeignKey x) {
return super.visit(x);
return super.visit((SQLForeignKeyImpl) x);
}
@Override
@@ -1310,6 +1310,4 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
public void endVisit(MySqlFlushStatement x) {
}
}
@@ -118,6 +118,7 @@ public class FromSubqueryResolver extends OracleASTVisitorAdapter {
String entryName = entry.getAlias();
SQLCreateViewStatement entryStmt = new SQLCreateViewStatement();
entryStmt.setOrReplace(true);
entryStmt.setDbType(stmt.getDbType());
String entryViewName = visitor.generateSubViewName();
@@ -136,6 +137,7 @@ public class FromSubqueryResolver extends OracleASTVisitorAdapter {
String dbType = stmt.getDbType();
for (int i = 0; i < targetList.size() - 1; ++i) {
SQLCreateViewStatement targetStmt = (SQLCreateViewStatement) targetList.get(i);
targetStmt.setOrReplace(true);
targetStmt.setDbType(dbType);
targetStmt.setAfterSemi(true);
}
@@ -35,7 +35,7 @@ public class OdpsCreateTableParser extends SQLCreateTableParser {
super(exprParser);
}
public SQLCreateTableStatement parseCrateTable(boolean acceptCreate) {
public SQLCreateTableStatement parseCreateTable(boolean acceptCreate) {
OdpsCreateTableStatement stmt = new OdpsCreateTableStatement();
if (acceptCreate) {
@@ -72,7 +72,7 @@ public class OdpsStatementParser extends SQLStatementParser {
public SQLCreateTableStatement parseCreateTable() {
SQLCreateTableParser parser = new OdpsCreateTableParser(this.exprParser);
return parser.parseCrateTable();
return parser.parseCreateTable();
}
public SQLCreateTableParser getSQLCreateTableParser() {
@@ -15,19 +15,12 @@
*/
package com.alibaba.druid.sql.dialect.oracle.parser;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLPartition;
import com.alibaba.druid.sql.ast.SQLPartitionBy;
import com.alibaba.druid.sql.ast.SQLPartitionByHash;
import com.alibaba.druid.sql.ast.SQLPartitionByList;
import com.alibaba.druid.sql.ast.SQLPartitionByRange;
import com.alibaba.druid.sql.ast.SQLSubPartition;
import com.alibaba.druid.sql.ast.SQLSubPartitionBy;
import com.alibaba.druid.sql.ast.SQLSubPartitionByHash;
import com.alibaba.druid.sql.ast.SQLSubPartitionByList;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
@@ -53,8 +46,8 @@ public class OracleCreateTableParser extends SQLCreateTableParser {
return new OracleCreateTableStatement();
}
public OracleCreateTableStatement parseCrateTable(boolean acceptCreate) {
OracleCreateTableStatement stmt = (OracleCreateTableStatement) super.parseCrateTable(acceptCreate);
public OracleCreateTableStatement parseCreateTable(boolean acceptCreate) {
OracleCreateTableStatement stmt = (OracleCreateTableStatement) super.parseCreateTable(acceptCreate);
if (lexer.token() == Token.OF) {
lexer.nextToken();
@@ -216,6 +216,7 @@ public class OracleExprParser extends SQLExprParser {
if ("TIMESTAMP".equalsIgnoreCase(typeName)) {
SQLDataTypeImpl timestamp = new SQLDataTypeImpl(typeName);
timestamp.setDbType(dbType);
if (lexer.token() == Token.LPAREN) {
lexer.nextToken();
@@ -280,7 +281,8 @@ public class OracleExprParser extends SQLExprParser {
}
SQLDataType dataType = new SQLDataTypeImpl(typeName);
SQLDataTypeImpl dataType = new SQLDataTypeImpl(typeName);
dataType.setDbType(dbType);
return parseDataTypeRest(dataType);
}
@@ -700,14 +702,14 @@ public class OracleExprParser extends SQLExprParser {
return expr;
}
if (lexer.identifierEquals("NEXTVAL")) {
if (lexer.identifierEquals(FnvHash.Constants.NEXTVAL)) {
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.NextVal);
lexer.nextToken();
return seqExpr;
}
} else if (lexer.identifierEquals("CURRVAL")) {
} else if (lexer.identifierEquals(FnvHash.Constants.CURRVAL)) {
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
SQLSequenceExpr seqExpr = new SQLSequenceExpr(identExpr, SQLSequenceExpr.Function.CurrVal);
@@ -1404,12 +1406,12 @@ public class OracleExprParser extends SQLExprParser {
continue;
}
if (lexer.identifierEquals("VALIDATE")) {
if (lexer.identifierEquals(FnvHash.Constants.VALIDATE)) {
lexer.nextToken();
constraint.setValidate(Boolean.TRUE);
continue;
}
if (lexer.identifierEquals("NOVALIDATE")) {
if (lexer.identifierEquals(FnvHash.Constants.NOVALIDATE)) {
lexer.nextToken();
constraint.setValidate(Boolean.FALSE);
continue;
@@ -1431,7 +1433,7 @@ public class OracleExprParser extends SQLExprParser {
if (lexer.token() == Token.NOT) {
lexer.nextToken();
if (lexer.identifierEquals("DEFERRABLE")) {
if (lexer.identifierEquals(FnvHash.Constants.DEFERRABLE)) {
lexer.nextToken();
constraint.setDeferrable(false);
continue;
@@ -1439,11 +1441,16 @@ public class OracleExprParser extends SQLExprParser {
throw new ParserException("TODO " + lexer.info());
}
if (lexer.identifierEquals("DEFERRABLE")) {
if (lexer.identifierEquals(FnvHash.Constants.DEFERRABLE)) {
lexer.nextToken();
constraint.setDeferrable(true);
continue;
}
if (lexer.token() == Token.USING) {
OracleUsingIndexClause using = parseUsingIndex();
constraint.setUsing(using);
}
break;
}
@@ -247,7 +247,7 @@ public class OracleSelectParser extends SQLSelectParser {
}
public SQLSelectQuery query() {
if (lexer.token() == (Token.LPAREN)) {
if (lexer.token() == Token.LPAREN) {
lexer.nextToken();
SQLSelectQuery select = query();
@@ -270,13 +270,13 @@ public class OracleSelectParser extends SQLSelectParser {
parseHints(queryBlock);
if (lexer.token() == (Token.DISTINCT)) {
if (lexer.token() == Token.DISTINCT) {
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
lexer.nextToken();
} else if (lexer.token() == (Token.UNIQUE)) {
} else if (lexer.token() == Token.UNIQUE) {
queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE);
lexer.nextToken();
} else if (lexer.token() == (Token.ALL)) {
} else if (lexer.token() == Token.ALL) {
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
lexer.nextToken();
}
@@ -304,16 +304,16 @@ public class OracleSelectParser extends SQLSelectParser {
}
public SQLSelectQuery queryRest(SQLSelectQuery selectQuery) {
if (lexer.token() == (Token.UNION)) {
if (lexer.token() == Token.UNION) {
SQLUnionQuery union = new SQLUnionQuery();
union.setLeft(selectQuery);
lexer.nextToken();
if (lexer.token() == (Token.ALL)) {
if (lexer.token() == Token.ALL) {
union.setOperator(SQLUnionOperator.UNION_ALL);
lexer.nextToken();
} else if (lexer.token() == (Token.DISTINCT)) {
} else if (lexer.token() == Token.DISTINCT) {
union.setOperator(SQLUnionOperator.DISTINCT);
lexer.nextToken();
}
@@ -582,10 +582,6 @@ public class OracleSelectParser extends SQLSelectParser {
}
}
protected String as() {
return super.as();
}
@Override
public SQLTableSource parseTableSource() {
SQLTableSource tableSource = parseTableSourcePrimary();
@@ -601,11 +597,11 @@ public class OracleSelectParser extends SQLSelectParser {
if (lexer.token() == (Token.LPAREN)) {
lexer.nextToken();
OracleSelectSubqueryTableSource tableSource;
OracleSelectTableSource tableSource;
if (lexer.token() == Token.SELECT || lexer.token() == Token.WITH) {
tableSource = new OracleSelectSubqueryTableSource(select());
} else if (lexer.token() == (Token.LPAREN)) {
tableSource = new OracleSelectSubqueryTableSource(select());
} else if (lexer.token() == Token.LPAREN) {
tableSource = (OracleSelectTableSource) parseTableSource();
} else if (lexer.token() == Token.IDENTIFIER) {
SQLTableSource identTable = parseTableSource();
accept(Token.RPAREN);
@@ -613,9 +609,17 @@ public class OracleSelectParser extends SQLSelectParser {
} else {
throw new ParserException("TODO :" + lexer.info());
}
accept(Token.RPAREN);
parsePivot((OracleSelectTableSource) tableSource);
if (lexer.token() == Token.UNION && tableSource instanceof OracleSelectSubqueryTableSource) {
OracleSelectSubqueryTableSource selectSubqueryTableSource = (OracleSelectSubqueryTableSource) tableSource;
SQLSelect select = selectSubqueryTableSource.getSelect();
SQLSelectQuery selectQuery = this.queryRest(select.getQuery());
select.setQuery(selectQuery);
}
parsePivot(tableSource);
return tableSource;
}
@@ -1606,6 +1606,7 @@ public class OracleStatementParser extends SQLStatementParser {
accept(Token.CURSOR);
dataType = new SQLDataTypeImpl("REF CURSOR");
dataType.setDbType(dbType);
} else if (lexer.token() == Token.TABLE) {
lexer.nextToken();
accept(Token.OF);
@@ -1619,6 +1620,7 @@ public class OracleStatementParser extends SQLStatementParser {
String typeName = "TABLE OF " + name.toString() + "%TYPE";
dataType = new SQLDataTypeImpl(typeName);
dataType.setDbType(dbType);
} else if (lexer.identifierEquals("VARRAY")) {
lexer.nextToken();
accept(Token.LPAREN);
@@ -1630,6 +1632,7 @@ public class OracleStatementParser extends SQLStatementParser {
lexer.nextToken();
String typeName = "VARRAY(" + len + ") OF NUMBER";
dataType = new SQLDataTypeImpl(typeName);
dataType.setDbType(dbType);
} else {
throw new ParserException("TODO : " + lexer.info());
}
@@ -139,10 +139,15 @@ public class SQLServerObjectReferenceExpr extends SQLServerObjectImpl implements
@Override
public long hashCode64() {
if (hashCode64 == 0) {
hashCode64 = new SQLPropertyExpr(
new SQLPropertyExpr(server, database)
, schema)
.hashCode64();
if (server == null) {
hashCode64 = new SQLPropertyExpr(
new SQLPropertyExpr(server, database)
, schema)
.hashCode64();
} else {
hashCode64 = new SQLPropertyExpr(database, schema)
.hashCode64();
}
}
return hashCode64;
}
@@ -19,19 +19,9 @@ import static com.alibaba.druid.sql.parser.CharTypes.isFirstIdentifierChar;
import static com.alibaba.druid.sql.parser.CharTypes.isIdentifierChar;
import static com.alibaba.druid.sql.parser.CharTypes.isWhitespace;
import static com.alibaba.druid.sql.parser.LayoutCharacters.EOI;
import static com.alibaba.druid.sql.parser.Token.COLONCOLON;
import static com.alibaba.druid.sql.parser.Token.COLONEQ;
import static com.alibaba.druid.sql.parser.Token.COMMA;
import static com.alibaba.druid.sql.parser.Token.EOF;
import static com.alibaba.druid.sql.parser.Token.ERROR;
import static com.alibaba.druid.sql.parser.Token.LBRACE;
import static com.alibaba.druid.sql.parser.Token.LBRACKET;
import static com.alibaba.druid.sql.parser.Token.LITERAL_ALIAS;
import static com.alibaba.druid.sql.parser.Token.LITERAL_CHARS;
import static com.alibaba.druid.sql.parser.Token.LPAREN;
import static com.alibaba.druid.sql.parser.Token.RBRACE;
import static com.alibaba.druid.sql.parser.Token.RBRACKET;
import static com.alibaba.druid.sql.parser.Token.RPAREN;
import static com.alibaba.druid.sql.parser.SQLParserFeature.KeepComments;
import static com.alibaba.druid.sql.parser.SQLParserFeature.OptimizedForParameterized;
import static com.alibaba.druid.sql.parser.Token.*;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -49,6 +39,7 @@ import com.alibaba.druid.util.StringUtils;
* @author wenshao [szujobs@hotmail.com]
*/
public class Lexer {
protected static SymbolTable symbols_l2 = new SymbolTable(512);
protected int features = 0; //SQLParserFeature.of(SQLParserFeature.EnableSQLBinaryOpExprGroup);
protected final String text;
@@ -69,29 +60,24 @@ public class Lexer {
protected long hash;
protected int commentCount = 0;
protected List<String> comments = new ArrayList<String>(2);
protected boolean skipComment = true;
private SavePoint savePoint = null;
/*
* anti sql injection
*/
private boolean allowComment = true;
private int varIndex = -1;
protected CommentHandler commentHandler;
protected boolean endOfComment = false;
protected boolean keepComments = false;
protected int line = 0;
protected int lines = 0;
protected String dbType;
protected boolean optimizedForParameterized = false;
private int startPos;
private int posLine;
private int posColumn;
@@ -316,6 +302,12 @@ public class Lexer {
return;
}
if (ch == '.') {
scanChar();
token = DOT;
return;
}
if (ch == 'a' || ch == 'A') {
char ch_next = charAt(pos + 1);
if (ch_next == 's' || ch_next == 'S') {
@@ -837,6 +829,7 @@ public class Lexer {
protected void scanString() {
mark = pos;
boolean hasSpecial = false;
Token preToken = this.token;
for (;;) {
if (isEOF()) {
@@ -875,7 +868,11 @@ public class Lexer {
}
if (!hasSpecial) {
stringVal = subString(mark + 1, bufPos);
if (preToken == Token.AS) {
stringVal = subString(mark, bufPos + 2);
} else {
stringVal = subString(mark + 1, bufPos);
}
} else {
stringVal = new String(buf, 0, bufPos);
}
@@ -902,7 +899,12 @@ public class Lexer {
throw new ParserException("unclosed str. " + info());
}
String stringVal = subString(startIndex, endIndex - startIndex);
String stringVal;
if (token == Token.AS) {
stringVal = subString(pos, endIndex + 1 - pos);
} else {
stringVal = subString(startIndex, endIndex - startIndex);
}
// hasSpecial = stringVal.indexOf('\\') != -1;
if (!hasSpecial) {
@@ -1537,6 +1539,15 @@ public class Lexer {
return stringVal;
}
private final void stringVal(StringBuffer out) {
if (stringVal != null) {
out.append(stringVal);
return;
}
out.append(text, mark, mark + bufPos);
}
public final boolean identifierEquals(String text) {
if (token != Token.IDENTIFIER) {
return false;
@@ -1799,9 +1810,69 @@ public class Lexer {
public void config(SQLParserFeature feature, boolean state) {
features = SQLParserFeature.config(features, feature, state);
if (feature == OptimizedForParameterized) {
optimizedForParameterized = state;
} else if (feature == KeepComments) {
this.keepComments = state;
}
}
public final boolean isEnabled(SQLParserFeature feature) {
return SQLParserFeature.isEnabled(this.features, feature);
}
public static String parameterize(String sql, String dbType) {
Lexer lexer = SQLParserUtils.createLexer(sql, dbType);
lexer.optimizedForParameterized = true; // optimized
lexer.nextToken();
StringBuffer buf = new StringBuffer();
for_:
for (;;) {
Token token = lexer.token;
switch (token) {
case LITERAL_ALIAS:
case LITERAL_FLOAT:
case LITERAL_CHARS:
case LITERAL_INT:
case LITERAL_NCHARS:
case LITERAL_HEX:
case VARIANT:
if (buf.length() != 0) {
buf.append(' ');
}
buf.append('?');
break;
case COMMA:
buf.append(',');
break;
case EQ:
buf.append('=');
break;
case EOF:
break for_;
case ERROR:
return sql;
case SELECT:
buf.append("SELECT");
break;
case UPDATE:
buf.append("UPDATE");
break;
default:
if (buf.length() != 0) {
buf.append(' ');
}
lexer.stringVal(buf);
break;
}
lexer.nextToken();
}
return buf.toString();
}
}
@@ -31,13 +31,13 @@ public class SQLCreateTableParser extends SQLDDLParser {
super(exprParser);
}
public SQLCreateTableStatement parseCrateTable() {
public SQLCreateTableStatement parseCreateTable() {
List<String> comments = null;
if (lexer.isKeepComments() && lexer.hasComment()) {
comments = lexer.readAndResetComments();
}
SQLCreateTableStatement stmt = parseCrateTable(true);
SQLCreateTableStatement stmt = parseCreateTable(true);
if (comments != null) {
stmt.addBeforeComment(comments);
}
@@ -45,7 +45,7 @@ public class SQLCreateTableParser extends SQLDDLParser {
return stmt;
}
public SQLCreateTableStatement parseCrateTable(boolean acceptCreate) {
public SQLCreateTableStatement parseCreateTable(boolean acceptCreate) {
SQLCreateTableStatement createTable = newCreateStatement();
if (acceptCreate) {
@@ -237,7 +237,14 @@ public class SQLExprParser extends SQLParser {
expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.DIV, rightExp, getDbType());
expr = multiplicativeRest(expr);
} else if (lexer.identifierEquals(FnvHash.Constants.MOD)) {
Lexer.SavePoint savePoint = lexer.mark();
lexer.nextToken();
if (lexer.token == Token.COMMA) {
lexer.reset(savePoint);
return expr;
}
SQLExpr rightExp = primary();
rightExp = relationalRest(rightExp);
@@ -308,10 +315,11 @@ public class SQLExprParser extends SQLParser {
long hash_lower = lexer.hash_lower;
lexer.nextToken();
if ("DATE".equalsIgnoreCase(ident)
if (hash_lower == FnvHash.Constants.DATE
&& lexer.token == Token.LITERAL_CHARS
&& (JdbcConstants.ORACLE.equals(getDbType())
|| JdbcConstants.POSTGRESQL.equals(getDbType()))) {
&& (JdbcConstants.ORACLE.equals(dbType)
|| JdbcConstants.POSTGRESQL.equals(dbType)
|| JdbcConstants.MYSQL.equals(dbType))) {
String literal = lexer.stringVal();
lexer.nextToken();
@@ -450,6 +458,7 @@ public class SQLExprParser extends SQLParser {
case DESC:
case DO:
case GROUP:
case MOD:
sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
lexer.nextToken();
break;
@@ -1021,42 +1030,7 @@ public class SQLExprParser extends SQLParser {
}
if (lexer.token == Token.LPAREN) {
lexer.nextToken();
if (lexer.token == Token.DISTINCT) {
lexer.nextToken();
String aggreateMethodName = expr.toString() + "." + name;
SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(aggreateMethodName, SQLAggregateOption.DISTINCT);
if (lexer.token == Token.RPAREN) {
lexer.nextToken();
} else {
if (lexer.token == Token.PLUS) {
aggregateExpr.getArguments().add(new SQLIdentifierExpr("+"));
lexer.nextToken();
} else {
exprList(aggregateExpr.getArguments(), aggregateExpr);
}
accept(Token.RPAREN);
}
expr = aggregateExpr;
} else {
SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name);
methodInvokeExpr.setOwner(expr);
if (lexer.token == Token.RPAREN) {
lexer.nextToken();
} else {
if (lexer.token == Token.PLUS) {
methodInvokeExpr.addParameter(new SQLIdentifierExpr("+"));
lexer.nextToken();
} else {
exprList(methodInvokeExpr.getParameters(), methodInvokeExpr);
}
accept(Token.RPAREN);
}
expr = methodInvokeExpr;
}
expr = methodRest(expr, name);
} else {
expr = new SQLPropertyExpr(expr, name, hash_lower);
}
@@ -1066,6 +1040,46 @@ public class SQLExprParser extends SQLParser {
return expr;
}
private SQLExpr methodRest(SQLExpr expr, String name) {
lexer.nextToken();
if (lexer.token == Token.DISTINCT) {
lexer.nextToken();
String aggreateMethodName = expr.toString() + "." + name;
SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(aggreateMethodName, SQLAggregateOption.DISTINCT);
if (lexer.token == Token.RPAREN) {
lexer.nextToken();
} else {
if (lexer.token == Token.PLUS) {
aggregateExpr.getArguments().add(new SQLIdentifierExpr("+"));
lexer.nextToken();
} else {
exprList(aggregateExpr.getArguments(), aggregateExpr);
}
accept(Token.RPAREN);
}
expr = aggregateExpr;
} else {
SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name);
methodInvokeExpr.setOwner(expr);
if (lexer.token == Token.RPAREN) {
lexer.nextToken();
} else {
if (lexer.token == Token.PLUS) {
methodInvokeExpr.addParameter(new SQLIdentifierExpr("+"));
lexer.nextToken();
} else {
exprList(methodInvokeExpr.getParameters(), methodInvokeExpr);
}
accept(Token.RPAREN);
}
expr = methodInvokeExpr;
}
return expr;
}
public final SQLExpr groupComparisionRest(SQLExpr expr) {
return expr;
}
@@ -2089,7 +2103,7 @@ public class SQLExprParser extends SQLParser {
}
SQLDataType dataType = new SQLDataTypeImpl(typeName);
dataType.setDbType(dbType);
return parseDataTypeRest(dataType);
}
@@ -2576,6 +2590,39 @@ public class SQLExprParser extends SQLParser {
}
token = lexer.token;
if (token == Token.DOT) {
lexer.nextToken();
String name;
long name_hash_lower;
if (lexer.token == Token.STAR) {
name = "*";
name_hash_lower = FnvHash.Constants.STAR;
} else {
name = lexer.stringVal();
name_hash_lower = lexer.hash_lower();
}
lexer.nextTokenComma();
token = lexer.token;
if (token == Token.LPAREN) {
expr = methodRest(expr, name);
token = lexer.token;
} else {
if (name_hash_lower == FnvHash.Constants.NEXTVAL) {
expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.NextVal);
} else if (name_hash_lower == FnvHash.Constants.CURRVAL) {
expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.CurrVal);
} else if (name_hash_lower == FnvHash.Constants.PREVVAL) {
expr = new SQLSequenceExpr((SQLIdentifierExpr) expr, SQLSequenceExpr.Function.PrevVal);
} else {
expr = new SQLPropertyExpr(expr, name, name_hash_lower);
}
}
}
if (token == Token.COMMA) {
return new SQLSelectItem(expr, null, connectByRoot);
}
@@ -2583,6 +2630,7 @@ public class SQLExprParser extends SQLParser {
if (token == Token.AS) {
lexer.nextToken();
String as = lexer.stringVal();
lexer.nextTokenComma();
return new SQLSelectItem(expr, as, connectByRoot);
}
@@ -103,8 +103,8 @@ public class SQLParser {
if (token == Token.AS) {
lexer.nextToken();
alias = alias();
alias = lexer.stringVal();
lexer.nextToken();
if (alias != null) {
while (lexer.token == Token.DOT) {
@@ -142,6 +142,7 @@ public class SQLParser {
case OUTER:
case DO:
case STORE:
case MOD:
alias = lexer.stringVal();
lexer.nextToken();
break;
@@ -17,7 +17,9 @@ package com.alibaba.druid.sql.parser;
public enum SQLParserFeature {
KeepInsertValueClauseOriginalString,
EnableSQLBinaryOpExprGroup
EnableSQLBinaryOpExprGroup,
OptimizedForParameterized,
KeepComments
;
private SQLParserFeature(){
@@ -42,26 +42,37 @@ import com.alibaba.druid.util.JdbcUtils;
public class SQLParserUtils {
public static SQLStatementParser createSQLStatementParser(String sql, String dbType) {
boolean keepComments;
SQLParserFeature[] features;
if (JdbcConstants.ODPS.equals(dbType) || JdbcConstants.MYSQL.equals(dbType)) {
keepComments = true;
features = new SQLParserFeature[] {SQLParserFeature.KeepComments};
} else {
keepComments = false;
features = new SQLParserFeature[] {};
}
return createSQLStatementParser(sql, dbType, keepComments);
return createSQLStatementParser(sql, dbType, features);
}
public static SQLStatementParser createSQLStatementParser(String sql, String dbType, boolean keepComments) {
SQLParserFeature[] features;
if (keepComments) {
features = new SQLParserFeature[] {SQLParserFeature.KeepComments};
} else {
features = new SQLParserFeature[] {};
}
return createSQLStatementParser(sql, dbType, features);
}
public static SQLStatementParser createSQLStatementParser(String sql, String dbType, SQLParserFeature... features) {
if (JdbcUtils.ORACLE.equals(dbType) || JdbcUtils.ALI_ORACLE.equals(dbType)) {
return new OracleStatementParser(sql);
}
if (JdbcUtils.MYSQL.equals(dbType)) {
return new MySqlStatementParser(sql, keepComments);
return new MySqlStatementParser(sql, features);
}
if (JdbcUtils.MARIADB.equals(dbType)) {
return new MySqlStatementParser(sql, keepComments);
return new MySqlStatementParser(sql, features);
}
if (JdbcUtils.POSTGRESQL.equals(dbType)
@@ -24,7 +24,6 @@ import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.ast.statement.SQLCreateTriggerStatement.TriggerEvent;
import com.alibaba.druid.sql.ast.statement.SQLCreateTriggerStatement.TriggerType;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleExprParser;
import com.alibaba.druid.util.FnvHash;
@@ -1814,7 +1813,7 @@ public class SQLStatementParser extends SQLParser {
if (token == Token.TABLE || lexer.identifierEquals("GLOBAL")) {
SQLCreateTableParser createTableParser = getSQLCreateTableParser();
SQLCreateTableStatement stmt = createTableParser.parseCrateTable(false);
SQLCreateTableStatement stmt = createTableParser.parseCreateTable(false);
if (comments != null) {
stmt.addBeforeComment(comments);
@@ -2230,7 +2229,7 @@ public class SQLStatementParser extends SQLParser {
public SQLCreateTableStatement parseCreateTable() {
// SQLCreateTableParser parser = new SQLCreateTableParser(this.lexer);
// return parser.parseCrateTable();
// return parser.parseCreateTable();
throw new ParserException("TODO");
}
@@ -27,8 +27,6 @@ public class SymbolTable {
public SymbolTable(int tableSize){
this.indexMask = tableSize - 1;
this.entries = new Entry[tableSize];
// this.addSymbol("id", 0, 2, "id".hashCode());
}
@@ -21,6 +21,7 @@ import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ASTVisitorAdapter;
import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement;
@@ -74,6 +75,11 @@ class SchemaResolveVisitorFactory {
return true;
}
public boolean visit(MysqlForeignKey x) {
resolve(this, x);
return false;
}
public boolean visit(SQLExprTableSource x) {
resolve(this, x);
return false;
@@ -251,6 +257,11 @@ class SchemaResolveVisitorFactory {
this.options = options;
}
public boolean visit(SQLForeignKeyImpl x) {
resolve(this, x);
return false;
}
public boolean visit(SQLSelectStatement x) {
resolve(this, x.getSelect());
return false;
@@ -456,6 +467,11 @@ class SchemaResolveVisitorFactory {
return false;
}
public boolean visit(OracleForeignKey x) {
resolve(this, x);
return false;
}
public boolean visit(SQLIfStatement x) {
resolve(this, x);
return false;
@@ -665,6 +681,11 @@ class SchemaResolveVisitorFactory {
this.options = options;
}
public boolean visit(SQLForeignKeyImpl x) {
resolve(this, x);
return false;
}
public boolean visit(SQLSelectStatement x) {
resolve(this, x.getSelect());
return false;
@@ -843,6 +864,11 @@ class SchemaResolveVisitorFactory {
this.options = options;
}
public boolean visit(SQLForeignKeyImpl x) {
resolve(this, x);
return false;
}
public boolean visit(SQLSelectStatement x) {
resolve(this, x.getSelect());
return false;
@@ -1032,6 +1058,11 @@ class SchemaResolveVisitorFactory {
this.options = options;
}
public boolean visit(SQLForeignKeyImpl x) {
resolve(this, x);
return false;
}
public boolean visit(SQLSelectStatement x) {
resolve(this, x.getSelect());
return false;
@@ -1193,6 +1224,11 @@ class SchemaResolveVisitorFactory {
this.options = options;
}
public boolean visit(SQLForeignKeyImpl x) {
resolve(this, x);
return false;
}
public boolean visit(SQLSelectStatement x) {
resolve(this, x.getSelect());
return false;
@@ -2408,6 +2444,62 @@ class SchemaResolveVisitorFactory {
return false;
}
static void resolve(SchemaResolveVisitor visitor, SQLForeignKeyConstraint x) {
SchemaRepository repository = visitor.getRepository();
SQLObject parent = x.getParent();
if (parent instanceof SQLCreateTableStatement) {
SQLCreateTableStatement createTableStmt = (SQLCreateTableStatement) parent;
SQLTableSource table = createTableStmt.getTableSource();
for (SQLName item : x.getReferencingColumns()) {
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
columnName.setResolvedTableSource(table);
SQLColumnDefinition column = createTableStmt.findColumn(columnName.nameHashCode64());
if (column != null) {
columnName.setResolvedColumn(column);
}
}
} else if (parent instanceof SQLAlterTableAddConstraint) {
SQLAlterTableStatement stmt = (SQLAlterTableStatement) parent.getParent();
SQLTableSource table = stmt.getTableSource();
for (SQLName item : x.getReferencingColumns()) {
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
columnName.setResolvedTableSource(table);
}
}
if (repository == null) {
return;
}
SQLExprTableSource table = x.getReferencedTable();
for (SQLName item : x.getReferencedColumns()) {
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
columnName.setResolvedTableSource(table);
}
SQLName tableName = table.getName();
SchemaObject tableObject = repository.findTable(tableName);
if (tableObject == null) {
return;
}
SQLStatement tableStmt = tableObject.getStatement();
if (tableStmt instanceof SQLCreateTableStatement) {
SQLCreateTableStatement refCreateTableStmt = (SQLCreateTableStatement) tableStmt;
for (SQLName item : x.getReferencedColumns()) {
SQLIdentifierExpr columnName = (SQLIdentifierExpr) item;
SQLColumnDefinition column = refCreateTableStmt.findColumn(columnName.nameHashCode64());
if (column != null) {
columnName.setResolvedColumn(column);
}
}
}
}
// for performance
static void resolveExpr(SchemaResolveVisitor visitor, SQLExpr x) {
if (x == null) {
@@ -2425,4 +2517,6 @@ class SchemaResolveVisitorFactory {
x.accept(visitor);
}
}
@@ -15,30 +15,23 @@
*/
package com.alibaba.druid.sql.visitor;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2OutputVisitor;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleParameterizedOutputVisitor;
import com.alibaba.druid.sql.dialect.phoenix.visitor.PhoenixOutputVisitor;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerTop;
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
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.util.JdbcConstants;
import com.alibaba.druid.sql.parser.*;
import com.alibaba.druid.util.JdbcUtils;
public class ParameterizedOutputVisitorUtils {
public static String parameterize(String sql, String dbType) {
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType);
parser.config(SQLParserFeature.EnableSQLBinaryOpExprGroup, true);
parser.config(SQLParserFeature.OptimizedForParameterized, true);
List<SQLStatement> statementList = parser.parseStatementList();
if (statementList.size() == 0) {
return sql;
@@ -834,6 +834,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
visit((SQLVariantRefExpr) x);
} else if (clazz == SQLBinaryOpExprGroup.class) {
visit((SQLBinaryOpExprGroup) x);
} else if (clazz == SQLCaseExpr.class) {
visit((SQLCaseExpr) x);
} else if (clazz == SQLInListExpr.class) {
visit((SQLInListExpr) x);
} else if (clazz == SQLNotExpr.class) {
visit((SQLNotExpr) x);
} else {
x.accept(this);
}
@@ -861,7 +867,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
if (elExpr instanceof SQLCaseExpr) {
this.indentCount++;
println();
printExpr(elExpr);
visit((SQLCaseExpr) elExpr);
this.indentCount--;
} else {
printExpr(elExpr);
@@ -1831,14 +1837,22 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
}
public boolean visit(SQLOrderBy x) {
if (x.getItems().size() > 0) {
List<SQLSelectOrderByItem> items = x.getItems();
if (items.size() > 0) {
if (x.isSibings()) {
print0(ucase ? "ORDER SIBLINGS BY " : "order siblings by ");
} else {
print0(ucase ? "ORDER BY " : "order by ");
}
printAndAccept(x.getItems(), ", ");
for (int i = 0, size = items.size(); i < size; ++i) {
if (i != 0) {
print0(", ");
}
SQLSelectOrderByItem item = items.get(i);
visit(item);
}
}
return false;
}
@@ -1851,20 +1865,23 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
} else {
printExpr(expr);
}
if (x.getType() != null) {
SQLOrderingSpecification type = x.getType();
if (type != null) {
print(' ');
SQLOrderingSpecification type = x.getType();
print0(ucase ? type.name : type.name_lcase);
}
if (x.getCollate() != null) {
String collate = x.getCollate();
if (collate != null) {
print0(ucase ? " COLLATE " : " collate ");
print0(x.getCollate());
print0(collate);
}
if (x.getNullsOrderType() != null) {
SQLSelectOrderByItem.NullsOrderType nullsOrderType = x.getNullsOrderType();
if (nullsOrderType != null) {
print(' ');
print0(x.getNullsOrderType().toFormalString());
print0(nullsOrderType.toFormalString());
}
return false;
@@ -4887,11 +4904,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
public boolean visit(SQLLimit x) {
print0(ucase ? "LIMIT " : "limit ");
if (x.getOffset() != null) {
x.getOffset().accept(this);
SQLExpr offset = x.getOffset();
if (offset != null) {
printExpr(offset);
print0(", ");
}
x.getRowCount().accept(this);
SQLExpr rowCount = x.getRowCount();
printExpr(rowCount);
return false;
}
@@ -414,5 +414,10 @@ public final class FnvHash {
long BEFORE = fnv1a_64_lower("BEFORE");
long AFTER = fnv1a_64_lower("AFTER");
long INSTEAD = fnv1a_64_lower("INSTEAD");
long DEFERRABLE = fnv1a_64_lower("DEFERRABLE");
long AS = fnv1a_64_lower("AS");
long STAR = fnv1a_64_lower("*");
}
}