diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java b/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java index ede810955f..627fa5401a 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLParameter.java @@ -23,6 +23,7 @@ public class SQLParameter extends SQLObjectImpl { private SQLDataType dataType; private SQLExpr defaultValue; private ParameterType paramType; + private boolean noCopy = false; public SQLExpr getDefaultValue() { return defaultValue; @@ -72,4 +73,12 @@ public class SQLParameter extends SQLObjectImpl { OUT, // out INOUT// inout } + + public boolean isNoCopy() { + return noCopy; + } + + public void setNoCopy(boolean noCopy) { + this.noCopy = noCopy; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java index 198846f432..1037effb41 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java @@ -1095,13 +1095,30 @@ public class OracleStatementParser extends SQLStatementParser { parameter.setDataType(dataType); parameter.setDefaultValue(new SQLQueryExpr(select)); + } else if (lexer.token() == Token.PROCEDURE) { + break; } else { parameter.setName(this.exprParser.name()); if (lexer.token() == Token.IN) { lexer.nextToken(); - parameter.setParamType(SQLParameter.ParameterType.IN); + + if (lexer.token() == Token.OUT) { + lexer.nextToken(); + parameter.setParamType(SQLParameter.ParameterType.INOUT); + } else { + parameter.setParamType(SQLParameter.ParameterType.IN); + } + } else if (lexer.token() == Token.OUT) { + lexer.nextToken(); + parameter.setParamType(SQLParameter.ParameterType.OUT); } + + if (identifierEquals("NOCOPY")) { + lexer.nextToken(); + parameter.setNoCopy(true); + } + parameter.setDataType(this.exprParser.parseDataType()); if (lexer.token() == Token.COLONEQ) { diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index fdf18e15bb..39cb4aaf3f 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1022,7 +1022,7 @@ public class SQLExprParser extends SQLParser { lexer.nextToken(); break; default: - throw new ParserException("error " + lexer.token()); + throw new ParserException("error " + lexer.info()); } } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index efca84a919..3607e27e90 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -3344,10 +3344,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet } else if (x.getParamType() == SQLParameter.ParameterType.OUT) { print0(ucase ? " OUT " : " out "); } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) { - print0(ucase ? " INOUT " : " inout "); + print0(ucase ? " IN OUT " : " in out "); } else { print(' '); } + + if (x.isNoCopy()) { + print0(ucase ? "NOCOPY " : "nocopy "); + } } else { if (x.getParamType() == SQLParameter.ParameterType.IN) { print0(ucase ? "IN " : "in "); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_param_inout_0.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_param_inout_0.java new file mode 100644 index 0000000000..6650dcc3a6 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/pl/Oracle_pl_param_inout_0.java @@ -0,0 +1,87 @@ +/* + * 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.bvt.sql.oracle.pl; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class Oracle_pl_param_inout_0 extends OracleTest { + + public void test_0() throws Exception { + String sql = "CREATE OR REPLACE PROCEDURE reassign (\n" + + " p IN OUT NOCOPY hr.person_typ,\n" + + " new_job VARCHAR2\n" + + ") AS\n" + + "BEGIN\n" + + " p.change_job(new_job); -- runs with privileges of OE\n" + + "END;"; // + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.ORACLE); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.ORACLE); + for (SQLStatement statement : statementList) { + statement.accept(visitor); + } + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("relationships : " + visitor.getRelationships()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + + assertEquals(0, visitor.getTables().size()); + +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("employees"))); +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("emp_name"))); + +// Assert.assertEquals(7, visitor.getColumns().size()); +// Assert.assertEquals(3, visitor.getConditions().size()); +// Assert.assertEquals(1, visitor.getRelationships().size()); + + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("employees", "salary"))); + + { + String output = SQLUtils.toOracleString(stmt); + assertEquals("CREATE OR REPLACE PROCEDURE reassign (\n" + + "\tp IN OUT NOCOPY hr.person_typ, \n" + + "\tnew_job VARCHAR2\n" + + ")\n" + + "BEGIN\n" + + "\tp.change_job(new_job);\n" + + "END", // + output); + } + { + String output = SQLUtils.toOracleString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + assertEquals("create or replace procedure reassign (\n" + + "\tp in out nocopy hr.person_typ, \n" + + "\tnew_job VARCHAR2\n" + + ")\n" + + "begin\n" + + "\tp.change_job(new_job);\n" + + "end", // + output); + } + } +}