support cursor in mysql's procedure

This commit is contained in:
zhujunxxxxx
2015-09-16 23:42:11 +08:00
parent 02a8376f09
commit c6b5890fed
12 changed files with 611 additions and 1 deletions
@@ -0,0 +1,48 @@
/*
* Copyright 1999-2101 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.mysql.ast.clause;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStatementImpl;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
/**
*
* @Description: MySql cursor close statement
* @author zz email:455910092@qq.com
* @date 2015-9-14
* @version V1.0
*/
public class MySqlCursorCloseStatement extends MySqlStatementImpl{
//cursor name
private String cursorName;
public String getCursorName() {
return cursorName;
}
public void setCursorName(String cursorName) {
this.cursorName = cursorName;
}
@Override
public void accept0(MySqlASTVisitor visitor) {
// TODO Auto-generated method stub
visitor.visit(this);
visitor.endVisit(this);
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 1999-2101 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.mysql.ast.clause;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStatementImpl;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
/**
*
* @Description: MySql cursor declare statement
* @author zz email:455910092@qq.com
* @date 2015-9-14
* @version V1.0
*/
public class MySqlCursorDeclareStatement extends MySqlStatementImpl{
//cursor name
private String cursorName;
//select statement
private SQLSelectStatement select;
public String getCursorName() {
return cursorName;
}
public void setCursorName(String cursorName) {
this.cursorName = cursorName;
}
public SQLSelectStatement getSelect() {
return select;
}
public void setSelect(SQLSelectStatement select) {
this.select = select;
}
@Override
public void accept0(MySqlASTVisitor visitor) {
// TODO Auto-generated method stub
if (visitor.visit(this)) {
acceptChild(visitor, select);
}
visitor.endVisit(this);
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 1999-2101 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.mysql.ast.clause;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStatementImpl;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
import com.alibaba.druid.sql.ast.SQLExpr;
/**
*
* @Description: MySql procedure cursor fetch into statement
* @author zz email:455910092@qq.com
* @date 2015-9-14
* @version V1.0
*/
public class MySqlCursorFetchIntoStatement extends MySqlStatementImpl{
//cursor name
private String cursorName;
//var list
private List<SQLExpr> varList=new ArrayList<SQLExpr>();
public String getCursorName() {
return cursorName;
}
public void setCursorName(String cursorName) {
this.cursorName = cursorName;
}
public List<SQLExpr> getVarList() {
return varList;
}
public void setVarList(List<SQLExpr> varList) {
this.varList = varList;
}
@Override
public void accept0(MySqlASTVisitor visitor) {
// TODO Auto-generated method stub
if (visitor.visit(this)) {
acceptChild(visitor, varList);
}
visitor.endVisit(this);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 1999-2101 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.mysql.ast.clause;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStatementImpl;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
/**
*
* @Description: MySql cursor open statement
* @author zz email:455910092@qq.com
* @date 2015-9-14
* @version V1.0
*/
public class MySqlCursorOpenStatement extends MySqlStatementImpl{
//cursor name
private String cursorName;
public String getCursorName() {
return cursorName;
}
public void setCursorName(String cursorName) {
this.cursorName = cursorName;
}
@Override
public void accept0(MySqlASTVisitor visitor) {
// TODO Auto-generated method stub
visitor.visit(this);
visitor.endVisit(this);
}
}
@@ -64,6 +64,10 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement.MySqlWhenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorCloseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorFetchIntoStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorOpenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlElseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIfStatement;
@@ -2957,7 +2961,20 @@ public class MySqlStatementParser extends SQLStatementParser {
// declare statement
if (lexer.token() == Token.DECLARE) {
statementList.add(this.parseDeclare());
char markChar = lexer.current();
int markBp = lexer.bp();
lexer.nextToken();
lexer.nextToken();
if(lexer.token()==Token.CURSOR)// cursor declare statement
{
lexer.reset(markBp, markChar, Token.DECLARE);
statementList.add(this.parseCursorDeclare());
}
else
{
lexer.reset(markBp, markChar, Token.DECLARE);
statementList.add(this.parseDeclare());
}
continue;
}
@@ -2979,6 +2996,24 @@ public class MySqlStatementParser extends SQLStatementParser {
continue;
}
// open cursor
if (lexer.token() == Token.OPEN) {
statementList.add(this.parseCursorOpen());
continue;
}
// close cursor
if (lexer.token() == Token.CLOSE) {
statementList.add(this.parseCursorClose());
continue;
}
// fetch cursor into
if (lexer.token() == Token.FETCH) {
statementList.add(this.parseCursorFetchInto());
continue;
}
if(lexer.token() == Token.IDENTIFIER)
{
String label=lexer.stringVal();
@@ -3342,4 +3377,94 @@ public class MySqlStatementParser extends SQLStatementParser {
accept(Token.SEMI);
return repeatStmt;
}
/**
* parse cursor declare statement
* @return
*/
public MySqlCursorDeclareStatement parseCursorDeclare()
{
MySqlCursorDeclareStatement stmt=new MySqlCursorDeclareStatement();
accept(Token.DECLARE);
stmt.setCursorName(exprParser.name().getSimpleName());
accept(Token.CURSOR);
accept(Token.FOR);
stmt.setSelect(parseSelect());
accept(Token.SEMI);
return stmt;
}
/**
* parse cursor open statement
* @return
*/
public MySqlCursorOpenStatement parseCursorOpen()
{
MySqlCursorOpenStatement stmt=new MySqlCursorOpenStatement();
accept(Token.OPEN);
stmt.setCursorName(exprParser.name().getSimpleName());
accept(Token.SEMI);
return stmt;
}
/**
* parse cursor close statement
* @return
*/
public MySqlCursorCloseStatement parseCursorClose()
{
MySqlCursorCloseStatement stmt=new MySqlCursorCloseStatement();
accept(Token.CLOSE);
stmt.setCursorName(exprParser.name().getSimpleName());
accept(Token.SEMI);
return stmt;
}
/**
* parse cursor fetch into statement
* @return
*/
public MySqlCursorFetchIntoStatement parseCursorFetchInto()
{
MySqlCursorFetchIntoStatement stmt=new MySqlCursorFetchIntoStatement();
accept(Token.FETCH);
stmt.setCursorName(exprParser.name().getSimpleName());
stmt.setVarList(parseIntoArgs());
return stmt;
}
/**
* parse fetch into var list
* @return
*/
protected List<SQLExpr> parseIntoArgs() {
List<SQLExpr> args=new ArrayList<SQLExpr>();
if (lexer.token() == (Token.INTO)) {
accept(Token.INTO);
//lexer.nextToken();
for (;;) {
SQLExpr var = exprParser.primary();
if (var instanceof SQLIdentifierExpr) {
var = new SQLVariantRefExpr(
((SQLIdentifierExpr) var).getName());
}
args.add(var);
if (lexer.token() == Token.COMMA) {
accept(Token.COMMA);
continue;
}
else
{
break;
}
}
}
return args;
}
}
@@ -25,6 +25,10 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement.MySqlWhenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorCloseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorFetchIntoStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorOpenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlElseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIfStatement;
@@ -645,4 +649,20 @@ public interface MySqlASTVisitor extends SQLASTVisitor {
boolean visit(MySqlRepeatStatement x);
void endVisit(MySqlRepeatStatement x);
boolean visit(MySqlCursorDeclareStatement x);
void endVisit(MySqlCursorDeclareStatement x);
boolean visit(MySqlCursorOpenStatement x);
void endVisit(MySqlCursorOpenStatement x);
boolean visit(MySqlCursorCloseStatement x);
void endVisit(MySqlCursorCloseStatement x);
boolean visit(MySqlCursorFetchIntoStatement x);
void endVisit(MySqlCursorFetchIntoStatement x);
} //
@@ -25,6 +25,10 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement.MySqlWhenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorCloseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorFetchIntoStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorOpenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlElseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIfStatement;
@@ -1454,4 +1458,52 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements MySq
}
@Override
public boolean visit(MySqlCursorDeclareStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorDeclareStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorOpenStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorOpenStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorCloseStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorCloseStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorFetchIntoStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorFetchIntoStatement x) {
// TODO Auto-generated method stub
}
} //
@@ -47,6 +47,10 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement.MySqlWhenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorCloseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorFetchIntoStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorOpenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlElseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIfStatement;
@@ -3555,4 +3559,64 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
@Override
public boolean visit(MySqlCursorDeclareStatement x) {
print("DECLARE ");
print(x.getCursorName());
print(" CURSOR FOR ");
x.getSelect().accept(this);
return false;
}
@Override
public void endVisit(MySqlCursorDeclareStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorOpenStatement x) {
print("OPEN ");
print(x.getCursorName());
return false;
}
@Override
public void endVisit(MySqlCursorOpenStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorCloseStatement x) {
print("CLOSE ");
print(x.getCursorName());
return false;
}
@Override
public void endVisit(MySqlCursorCloseStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorFetchIntoStatement x) {
print("FETCH ");
print(x.getCursorName());
print(" INTO ");
for (int i = 0; i < x.getVarList().size(); i++) {
x.getVarList().get(i).accept(this);
if(i!=x.getVarList().size()-1)
print(",");
}
return false;
}
@Override
public void endVisit(MySqlCursorFetchIntoStatement x) {
// TODO Auto-generated method stub
}
} //
@@ -40,6 +40,10 @@ import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCaseStatement.MySqlWhenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorCloseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorFetchIntoStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlCursorOpenStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlDeclareStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlElseStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIfStatement;
@@ -1558,4 +1562,52 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
}
@Override
public boolean visit(MySqlCursorDeclareStatement x) {
accept(x.getSelect());
return false;
}
@Override
public void endVisit(MySqlCursorDeclareStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorOpenStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorOpenStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorCloseStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorCloseStatement x) {
// TODO Auto-generated method stub
}
@Override
public boolean visit(MySqlCursorFetchIntoStatement x) {
// TODO Auto-generated method stub
return false;
}
@Override
public void endVisit(MySqlCursorFetchIntoStatement x) {
// TODO Auto-generated method stub
}
}
@@ -144,6 +144,10 @@ public class Keywords {
map.put("ITERATE", Token.ITERATE);
map.put("REPEAT", Token.REPEAT);
map.put("UNTIL", Token.UNTIL);
map.put("OPEN", Token.OPEN);
map.put("CLOSE", Token.CLOSE);
map.put("CURSOR", Token.CURSOR);
map.put("FETCH", Token.FETCH);
DEFAULT_KEYWORDS = new Keywords(map);
}
@@ -135,6 +135,8 @@ public enum Token {
ITERATE("ITERATE"),
REPEAT("REPEAT"),
UNTIL("UNTIL"),
OPEN("OPEN"),
CLOSE("CLOSE"),
//postgresql
WINDOW("WINDOW"),
@@ -0,0 +1,71 @@
/*
* Copyright 1999-2101 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.bvt.sql.mysql;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.MysqlTest;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Column;
/**
*
* @Description: procedure begin-end, loop, while use label
* @author zz email:455910092@qq.com
* @date 2015-9-14
* @version V1.0
*/
public class MySqlCreateProcedureTest5 extends MysqlTest {
public void test_0() throws Exception {
String sql="create or replace procedure sp_name(level int,age int)"+
" begin"+
" declare c1 cursor for select id,age from test;"+
" open c1;"+
" fetch c1 into x;"+
" close c1;"+
" end";
MySqlStatementParser parser=new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement statemen = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
statemen.accept(visitor);
System.out.println("Tables : " + visitor.getTables());
System.out.println("fields : " + visitor.getColumns());
System.out.println("coditions : " + visitor.getConditions());
System.out.println("orderBy : " + visitor.getOrderByColumns());
Assert.assertEquals(1, visitor.getTables().size());
Assert.assertEquals(2, visitor.getColumns().size());
Assert.assertEquals(0, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("test")));
Assert.assertTrue(visitor.getColumns().contains(new Column("test", "id")));
Assert.assertTrue(visitor.getColumns().contains(new Column("test", "age")));
}
}