improved sql parser.

This commit is contained in:
wenshao
2017-09-22 23:21:42 +08:00
parent ee6e9879bb
commit aa957fab13
34 changed files with 1861 additions and 20 deletions
@@ -49,6 +49,7 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLC
private boolean parallelEnable;
private boolean aggregate;
private SQLName using;
private boolean pipelined;
public SQLCreateFunctionStatement clone() {
SQLCreateFunctionStatement x = new SQLCreateFunctionStatement();
@@ -78,6 +79,7 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLC
}
x.comment = comment;
x.deterministic = deterministic;
x.pipelined = pipelined;
return x;
}
@@ -238,4 +240,12 @@ public class SQLCreateFunctionStatement extends SQLStatementImpl implements SQLC
public void setUsing(SQLName using) {
this.using = using;
}
public boolean isPipelined() {
return pipelined;
}
public void setPipelined(boolean pipelined) {
this.pipelined = pipelined;
}
}
@@ -16,8 +16,13 @@
package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author zz [455910092@qq.com]
@@ -27,7 +32,13 @@ public class SQLOpenStatement extends SQLStatementImpl{
//cursor name
private String cursorName;
private final List<SQLName> columns = new ArrayList<SQLName>();
private SQLExpr forExpr;
public SQLOpenStatement() {
}
public String getCursorName() {
return cursorName;
@@ -41,6 +52,7 @@ public class SQLOpenStatement extends SQLStatementImpl{
protected void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, forExpr);
acceptChild(visitor, columns);
}
visitor.endVisit(this);
}
@@ -55,4 +67,8 @@ public class SQLOpenStatement extends SQLStatementImpl{
}
this.forExpr = forExpr;
}
public List<SQLName> getColumns() {
return columns;
}
}
@@ -1015,4 +1015,14 @@ public class OracleToMySqlOutputVisitor extends MySqlOutputVisitor implements Or
public void endVisit(OracleCreateTypeStatement x) {
}
@Override
public boolean visit(OraclePipeRowStatement x) {
return false;
}
@Override
public void endVisit(OraclePipeRowStatement x) {
}
}
@@ -0,0 +1,38 @@
/*
* 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.dialect.oracle.ast.stmt;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
import java.util.ArrayList;
import java.util.List;
public class OraclePipeRowStatement extends OracleStatementImpl {
private final List<SQLExpr> parameters = new ArrayList<SQLExpr>();
@Override
public void accept0(OracleASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, parameters);
}
visitor.endVisit(this);
}
public List<SQLExpr> getParameters() {
return parameters;
}
}
@@ -400,7 +400,7 @@ public class OracleExprParser extends SQLExprParser {
lexer.nextToken();
break;
case LITERAL_FLOAT:
sqlExpr = lexer.numberExpr();
sqlExpr = lexer.numberExpr(true);
lexer.nextToken();
break;
case BINARY_FLOAT:
@@ -1022,6 +1022,11 @@ public class OracleSelectParser extends SQLSelectParser {
protected void parseInto(OracleSelectQueryBlock x) {
if (lexer.token() == Token.INTO) {
lexer.nextToken();
if (lexer.token() == Token.FROM) {
return;
}
SQLExpr expr = expr();
if (lexer.token() != Token.COMMA) {
x.setInto(expr);
@@ -294,6 +294,21 @@ public class OracleStatementParser extends SQLStatementParser {
continue;
}
if (strVal.equalsIgnoreCase("PIPE")) {
Lexer.SavePoint savePoint = lexer.mark();
lexer.nextToken();
if (lexer.token() == Token.ROW) {
lexer.reset(savePoint);
SQLStatement stmt = this.parsePipeRow();
stmt.setParent(parent);
statementList.add(stmt);
} else {
lexer.reset(savePoint);
}
continue;
}
SQLExpr expr = exprParser.expr();
if (expr instanceof SQLBinaryOpExpr) {
@@ -624,10 +639,27 @@ public class OracleStatementParser extends SQLStatementParser {
continue;
}
if (lexer.token() == Token.TRIGGER) {
SQLStatement stmt = this.parseCreateTrigger();
stmt.setParent(parent);
statementList.add(stmt);
continue;
}
throw new ParserException("TODO : " + lexer.info());
}
}
public SQLStatement parsePipeRow() {
OraclePipeRowStatement stmt = new OraclePipeRowStatement();
acceptIdentifier("PIPE");
accept(Token.ROW);
accept(Token.LPAREN);
this.exprParser.exprList(stmt.getParameters(), stmt);
accept(Token.RPAREN);
return stmt;
}
public SQLStatement parseExecute() {
acceptIdentifier("EXECUTE");
@@ -791,6 +823,16 @@ public class OracleStatementParser extends SQLStatementParser {
SQLDataType returnDataType = this.exprParser.parseDataType(false);
stmt.setReturnDataType(returnDataType);
if (identifierEquals("PIPELINED")) {
lexer.nextToken();
stmt.setPipelined(true);
}
if (identifierEquals("DETERMINISTIC")) {
lexer.nextToken();
stmt.setDeterministic(true);
}
if (lexer.identifierEquals("AUTHID")) {
lexer.nextToken();
String strVal = lexer.stringVal();
@@ -1641,7 +1683,9 @@ public class OracleStatementParser extends SQLStatementParser {
}
if (lexer.token() == Token.FUNCTION) {
lexer.reset(savePoint);
if (savePoint.token == Token.DECLARE) {
lexer.reset(savePoint);
}
return this.parseCreateFunction();
}
@@ -1731,6 +1775,17 @@ public class OracleStatementParser extends SQLStatementParser {
String typeName = "VARRAY(" + len + ") OF NUMBER";
dataType = new SQLDataTypeImpl(typeName);
dataType.setDbType(dbType);
} else if (lexer.identifierEquals("VARCHAR2")) {
lexer.nextToken();
String typeName = "VARRAY(" + len + ") OF VARCHAR2";
dataType = new SQLDataTypeImpl(typeName);
dataType.setDbType(dbType);
if (lexer.token() == Token.LPAREN) {
lexer.nextToken();
this.exprParser.exprList(dataType.getArguments(), dataType);
accept(Token.RPAREN);
}
} else {
throw new ParserException("TODO : " + lexer.info());
}
@@ -1804,7 +1859,11 @@ public class OracleStatementParser extends SQLStatementParser {
}
token = lexer.token();
if (token != Token.BEGIN && token != Token.RPAREN && token != Token.EOF) {
if (token != Token.BEGIN
&& token != Token.RPAREN
&& token != Token.EOF
&& token != Token.FUNCTION
&& !lexer.identifierEquals("DETERMINISTIC")) {
continue;
}
@@ -433,4 +433,8 @@ public interface OracleASTVisitor extends SQLASTVisitor {
boolean visit(OracleCreateTypeStatement x);
void endVisit(OracleCreateTypeStatement x);
boolean visit(OraclePipeRowStatement x);
void endVisit(OraclePipeRowStatement x);
}
@@ -1073,4 +1073,14 @@ public class OracleASTVisitorAdapter extends SQLASTVisitorAdapter implements Ora
public void endVisit(OracleCreateTypeStatement x) {
}
@Override
public boolean visit(OraclePipeRowStatement x) {
return true;
}
@Override
public void endVisit(OraclePipeRowStatement x) {
}
}
@@ -2654,6 +2654,14 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
print(ucase ? "RETURN " : "return ");
x.getReturnDataType().accept(this);
if (x.isPipelined()) {
print(ucase ? "PIPELINED " : "pipelined ");
}
if (x.isDeterministic()) {
print(ucase ? "DETERMINISTIC " : "deterministic ");
}
SQLName authid = x.getAuthid();
if (authid != null) {
print(ucase ? " AUTHID " : " authid ");
@@ -3331,4 +3339,17 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
public void endVisit(OracleCreateTypeStatement x) {
}
@Override
public boolean visit(OraclePipeRowStatement x) {
print0(ucase ? "PIPE ROW(" : "pipe row(");
printAndAccept(x.getParameters(), ", ");
print(')');
return false;
}
@Override
public void endVisit(OraclePipeRowStatement x) {
}
}
@@ -1365,4 +1365,14 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
public void endVisit(OracleCreateTypeStatement x) {
}
@Override
public boolean visit(OraclePipeRowStatement x) {
return false;
}
@Override
public void endVisit(OraclePipeRowStatement x) {
}
}
@@ -20,10 +20,7 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
@@ -89,8 +86,22 @@ public class SQLServerExprParser extends SQLExprParser {
}
public SQLExpr primaryRest(SQLExpr expr) {
if (lexer.token() == Token.DOTDOT) {
final Token token = lexer.token();
if (token == Token.DOTDOT) {
expr = nameRest((SQLName) expr);
} else if (lexer.identifierEquals(FnvHash.Constants.VALUE)
&& expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr;
if (identExpr.nameHashCode64() == FnvHash.Constants.NEXT) {
lexer.nextToken();
accept(Token.FOR);
SQLName name = this.name();
SQLSequenceExpr seq = new SQLSequenceExpr();
seq.setSequence(name);
seq.setFunction(SQLSequenceExpr.Function.NextVal);
expr = seq;
}
}
return super.primaryRest(expr);
@@ -17,6 +17,7 @@ package com.alibaba.druid.sql.dialect.sqlserver.visitor;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerOutput;
import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock;
@@ -29,6 +30,7 @@ import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerRollbackStateme
import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerSetTransactionIsolationLevelStatement;
import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerUpdateStatement;
import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerWaitForStatement;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.util.FnvHash;
import com.alibaba.druid.util.JdbcConstants;
@@ -586,7 +588,6 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe
@Override
public boolean visit(SQLStartTransactionStatement x) {
print0(ucase ? "BEGIN TRANSACTION" : "begin transaction");
if (x.getName() != null) {
print(' ');
x.getName().accept(this);
@@ -619,4 +620,17 @@ public class SQLServerOutputVisitor extends SQLASTOutputVisitor implements SQLSe
return false;
}
public boolean visit(SQLSequenceExpr x) {
SQLSequenceExpr.Function function = x.getFunction();
switch (function) {
case NextVal:
print0(ucase ? "NEXT VALUE FOR " : "next value for ");
break;
default:
throw new ParserException("not support function : " + function);
}
printExpr(x.getSequence());
return false;
}
}
@@ -174,7 +174,7 @@ public class Lexer {
char ch;
long hash;
long hash_lower;
Token token;
public Token token;
String stringVal;
}
@@ -1705,11 +1705,19 @@ public class SQLStatementParser extends SQLParser {
if (lexer.token == Token.VALUES) {
lexer.nextToken();
for (;;) {
accept(Token.LPAREN);
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
this.exprParser.exprList(values.getValues(), values);
insertStatement.addValueCause(values);
accept(Token.RPAREN);
if (lexer.token == Token.LPAREN) {
lexer.nextToken();
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
this.exprParser.exprList(values.getValues(), values);
insertStatement.addValueCause(values);
accept(Token.RPAREN);
} else { // oracle
SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause();
SQLExpr value = this.exprParser.expr();
values.addValue(value);
insertStatement.addValueCause(values);
}
if (lexer.token == Token.COMMA) {
lexer.nextToken();
@@ -2051,15 +2059,17 @@ public class SQLStatementParser extends SQLParser {
}
public SQLStatement parseCreateTrigger() {
accept(Token.CREATE);
SQLCreateTriggerStatement stmt = new SQLCreateTriggerStatement(getDbType());
if (lexer.token == Token.OR) {
if (lexer.token == Token.CREATE) {
lexer.nextToken();
accept(Token.REPLACE);
stmt.setOrReplace(true);
if (lexer.token == Token.OR) {
lexer.nextToken();
accept(Token.REPLACE);
stmt.setOrReplace(true);
}
}
accept(Token.TRIGGER);
@@ -2613,6 +2623,12 @@ public class SQLStatementParser extends SQLParser {
accept(Token.OPEN);
stmt.setCursorName(exprParser.name().getSimpleName());
if (lexer.token == Token.LPAREN) {
lexer.nextToken();
this.exprParser.names(stmt.getColumns(), stmt);
accept(Token.RPAREN);
}
if (lexer.token == Token.FOR) {
lexer.nextToken();
if (lexer.token == Token.SELECT) {
@@ -4112,6 +4112,13 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
print0(ucase ? "OPEN " : "open ");
print0(x.getCursorName());
List<SQLName> columns = x.getColumns();
if (columns.size() > 0) {
print('(');
printAndAccept(columns, ", ");
print(')');
}
SQLExpr forExpr = x.getFor();
if (forExpr != null) {
print0(ucase ? " FOR " : "for ");