diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/clause/MySqlParameter.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/clause/MySqlParameter.java index a2e88da6d7..df9f3e1621 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/clause/MySqlParameter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/clause/MySqlParameter.java @@ -32,8 +32,17 @@ public class MySqlParameter extends MySqlObjectImpl { private SQLExpr name; private SQLDataType dataType; private SQLExpr defaultValue; + private ParameterType paramType; - public SQLExpr getDefaultValue() { + public ParameterType getParamType() { + return paramType; + } + + public void setParamType(ParameterType paramType) { + this.paramType = paramType; + } + + public SQLExpr getDefaultValue() { return defaultValue; } @@ -66,5 +75,15 @@ public class MySqlParameter extends MySqlObjectImpl { } visitor.endVisit(this); } + /** + * mysql procedure parameter type + */ + public static enum ParameterType + { + DEFAULT, + IN,//in + OUT,//out + INOUT//inout + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index 05d54819e6..c096f330b5 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -73,6 +73,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIterateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlLeaveStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlLoopStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlParameter; +import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlParameter.ParameterType; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlSelectIntoStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlWhileStatement; @@ -2785,7 +2786,28 @@ public class MySqlStatementParser extends SQLStatementParser { parameter.setDataType(dataType); parameter.setDefaultValue(new SQLQueryExpr(select)); + + } else if (lexer.token() == Token.IN || lexer.token() == Token.OUT || lexer.token() == Token.INOUT) { + + if(lexer.token()==Token.IN) + { + parameter.setParamType(ParameterType.IN); + } + else if(lexer.token()==Token.OUT) + { + parameter.setParamType(ParameterType.OUT); + } + else if(lexer.token()==Token.INOUT) + { + parameter.setParamType(ParameterType.INOUT); + } + lexer.nextToken(); + + parameter.setName(this.exprParser.name()); + + parameter.setDataType(this.exprParser.parseDataType()); } else { + parameter.setParamType(ParameterType.DEFAULT);//default parameter type is in parameter.setName(this.exprParser.name()); parameter.setDataType(this.exprParser.parseDataType()); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index 5ef99443f0..12e0b106ab 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -59,6 +59,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlIterateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlLeaveStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlLoopStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlParameter; +import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlParameter.ParameterType; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlRepeatStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlSelectIntoStatement; import com.alibaba.druid.sql.dialect.mysql.ast.clause.MySqlWhileStatement; @@ -3277,6 +3278,19 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV decrementIndent(); } else { + + if(x.getParamType()==ParameterType.IN) + { + print("IN "); + } + else if(x.getParamType()==ParameterType.OUT) + { + print("OUT "); + } + else if(x.getParamType()==ParameterType.INOUT) + { + print("INOUT "); + } x.getName().accept(this); print(" "); diff --git a/src/main/java/com/alibaba/druid/sql/parser/Keywords.java b/src/main/java/com/alibaba/druid/sql/parser/Keywords.java index 5b0eb2f6cd..5bcc6f3dab 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Keywords.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Keywords.java @@ -135,7 +135,7 @@ public class Keywords { map.put("GRANT", Token.GRANT); map.put("REVOKE", Token.REVOKE); - // MySql procedure by:zz + // MySql procedure: add by zz map.put("WHILE", Token.WHILE); map.put("DO", Token.DO); map.put("DECLARE", Token.DECLARE); @@ -148,6 +148,8 @@ public class Keywords { map.put("CLOSE", Token.CLOSE); map.put("CURSOR", Token.CURSOR); map.put("FETCH", Token.FETCH); + map.put("OUT", Token.OUT); + map.put("INOUT", Token.INOUT); DEFAULT_KEYWORDS = new Keywords(map); } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Token.java b/src/main/java/com/alibaba/druid/sql/parser/Token.java index 8e0d0e3b80..c3e97136bb 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -128,7 +128,7 @@ public enum Token { SHOW("SHOW"), REPLACE("REPLACE"), - // MySql procedure by:zz + // MySql procedure add by zz WHILE("WHILE"), DO("DO"), LEAVE("LEAVE"), @@ -137,6 +137,8 @@ public enum Token { UNTIL("UNTIL"), OPEN("OPEN"), CLOSE("CLOSE"), + OUT("OUT"), + INOUT("INOUT"), //postgresql WINDOW("WINDOW"), diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateProcedureTest6.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateProcedureTest6.java new file mode 100644 index 0000000000..026eea9d66 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlCreateProcedureTest6.java @@ -0,0 +1,155 @@ +/* + * 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: create procedure parameter type support + * @author zz email:455910092@qq.com + * @date 2015-9-14 + * @version V1.0 + */ +public class MySqlCreateProcedureTest6 extends MysqlTest { + + public void test_0() throws Exception { + String sql="create or replace procedure sp_name(level int,age int)"+ + " begin"+ + " insert into test values(id,age);"+ + " end"; + + MySqlStatementParser parser=new MySqlStatementParser(sql); + List 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"))); + } + public void test_1() throws Exception { + String sql="create or replace procedure sp_name(in level int,in age int)"+ + " begin"+ + " insert into test values(id,age);"+ + " end"; + + MySqlStatementParser parser=new MySqlStatementParser(sql); + List 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"))); + } + public void test_2() throws Exception { + String sql="create or replace procedure sp_name(out level int,out age int)"+ + " begin"+ + " insert into test values(id,age);"+ + " end"; + + MySqlStatementParser parser=new MySqlStatementParser(sql); + List 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"))); + } + public void test_3() throws Exception { + String sql="create or replace procedure sp_name(inout level int,inout age int)"+ + " begin"+ + " insert into test values(id,age);"+ + " end"; + + MySqlStatementParser parser=new MySqlStatementParser(sql); + List 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"))); + } + +}