diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/core/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index 7bf2643c52..d9257fd86e 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -2955,4 +2955,117 @@ public boolean visit(OracleCreateTableSpaceStatement x) { print0(ucase ? x.getSql().toUpperCase() : x.getSql().toLowerCase()); return false; } + + public void visitCursorParameters(List cursorParameters) { + for (SQLParameter cursorParameter : cursorParameters) { + print('('); + cursorParameter.getName().accept(this); + print(' '); + cursorParameter.getDataType().accept(this); + print(')'); + } + } + + @Override + public boolean visit(SQLParameter x) { + SQLName name = x.getName(); + if (x.getDataType().getName().equalsIgnoreCase("CURSOR")) { + print0(ucase ? "CURSOR " : "cursor "); + x.getName().accept(this); + // Handling cursor parameters + visitCursorParameters(x.getCursorParameters()); + print0(ucase ? " IS" : " is"); + this.indentCount++; + println(); + SQLSelect select = ((SQLQueryExpr) x.getDefaultValue()).getSubQuery(); + select.accept(this); + this.indentCount--; + + } else { + if (x.isMap()) { + print0(ucase ? "MAP MEMBER " : "map member "); + } else if (x.isOrder()) { + print0(ucase ? "ORDER MEMBER " : "order member "); + } else if (x.isMember()) { + print0(ucase ? "MEMBER " : "member "); + } + SQLDataType dataType = x.getDataType(); + + if (DbType.oracle == dbType + || dataType instanceof OracleFunctionDataType + || dataType instanceof OracleProcedureDataType) { + if (dataType instanceof OracleFunctionDataType) { + OracleFunctionDataType functionDataType = (OracleFunctionDataType) dataType; + visit(functionDataType); + return false; + } + + if (dataType instanceof OracleProcedureDataType) { + OracleProcedureDataType procedureDataType = (OracleProcedureDataType) dataType; + visit(procedureDataType); + return false; + } + + String dataTypeName = dataType.getName(); + boolean printType = (dataTypeName.startsWith("TABLE OF") && x.getDefaultValue() == null) + || dataTypeName.equalsIgnoreCase("REF CURSOR") + || dataTypeName.startsWith("VARRAY("); + if (printType) { + print0(ucase ? "TYPE " : "type "); + } + + //枚举类型特殊处理 + if ("ENUM".equals(dataTypeName)) { + dataType.accept(this); + return false; + } else { + name.accept(this); + } + if (x.getParamType() == SQLParameter.ParameterType.IN) { + print0(ucase ? " IN " : " in "); + } else if (x.getParamType() == SQLParameter.ParameterType.OUT) { + print0(ucase ? " OUT " : " out "); + } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) { + print0(ucase ? " IN OUT " : " in out "); + } else { + print(' '); + } + + if (x.isNoCopy()) { + print0(ucase ? "NOCOPY " : "nocopy "); + } + + if (x.isConstant()) { + print0(ucase ? "CONSTANT " : "constant "); + } + + if (printType) { + print0(ucase ? "IS " : "is "); + } + } else { + if (x.getParamType() == SQLParameter.ParameterType.IN) { + boolean skip = DbType.mysql == dbType + && x.getParent() instanceof SQLCreateFunctionStatement; + + if (!skip) { + print0(ucase ? "IN " : "in "); + } + } else if (x.getParamType() == SQLParameter.ParameterType.OUT) { + print0(ucase ? "OUT " : "out "); + } else if (x.getParamType() == SQLParameter.ParameterType.INOUT) { + print0(ucase ? "INOUT " : "inout "); + } + x.getName().accept(this); + print(' '); + } + + dataType.accept(this); + if (x.isNotNull()) { + print0(ucase ? " NOT NULL" : " not null"); + } + printParamDefaultValue(x); + } + + return false; + } } diff --git a/core/src/test/java/com/alibaba/druid/demo/sql/OracleCursorParamTest.java b/core/src/test/java/com/alibaba/druid/demo/sql/OracleCursorParamTest.java new file mode 100644 index 0000000000..2ea9a5c1f4 --- /dev/null +++ b/core/src/test/java/com/alibaba/druid/demo/sql/OracleCursorParamTest.java @@ -0,0 +1,26 @@ +package com.alibaba.druid.demo.sql; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import junit.framework.TestCase; + +/** + * @author LENOVO + * @date 2024/7/17 10:56 + */ +public class OracleCursorParamTest extends TestCase { + + public void test_cursor_parameters() { + String sql = "DECLARE\n" + + "CURSOR cur_param(name_str VARCHAR2) IS SELECT u.USERNAME, u.PASSWORD FROM MG_USER u WHERE ID = 1;\n" + + "op_name VARCHAR2(100);\n" + + "BEGIN\n" + + "SELECT NVL(EMP_NAME, USERNAME) INTO op_name FROM MG_USER WHERE ID = 1;\n" + + "END;"; + + SQLStatement stmt = SQLUtils.parseSingleStatement(sql, DbType.oracle); + + System.out.println(stmt); + } +}