mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improved sql parser.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -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);
|
||||
|
||||
+61
-2
@@ -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);
|
||||
}
|
||||
|
||||
+10
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+16
-5
@@ -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);
|
||||
|
||||
+15
-1
@@ -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 ");
|
||||
|
||||
Reference in New Issue
Block a user