动态调用带有输出变量的PL/SQL存储过程

3

我正在尝试使用动态SQL来执行存储过程并检索输出参数:

v_sql := 'BEGIN ' || p_procname || '(''' || p_input1 || ''', ''' || p_input2 || ''', v_output1); END;';
DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql;

我声明了v_output1变量,但是我收到了以下错误信息:

PLS-00201: identifier 'V_ISSUE' must be declared 

如果我用v_sql中的 dbms_output 代码替换上述代码,该过程可以正常工作,所以该过程不是问题所在,问题在于我尝试动态调用它的方式。

我不知道我尝试的做法是否可行。有没有一种通过动态SQL检索此过程调用的输出参数的方法?

2个回答

11

不要使用字符串拼接来传递参数到动态SQL语句中。这被认为是一种不良实践,不仅适用于Oracle。

这是一个不好的实践,但主要失败点是在动态SQL字符串中使用局部变量的名称,因为它在此变量被引入的代码块之外不可见。

你的代码应该像这样:

declare 
  v_sql varchar2(4000);
  p_procname varchar2(100);
  p_input1 number;
  p_input2 number;
  v_output1 number;   
begin

  v_sql := 'begin ' || p_procname || '(:p_input1, :p_input2, :v_output); end;';

  execute immediate v_sql 
  using in p_input1, in p_input2, out v_output1;

end;

p_procname也是一个变量,但你不能将其绑定,所以你必须像Paul在他的回答中所做的那样进行连接。 - Alex Poole

4

Found my answer here.

v_sql := 'BEGIN ' || p_procname || '(:a, :b, :c); END;';

EXECUTE IMMEDIATE v_sql
USING IN p_input1, IN p_input2, OUT v_output1;

1
恭喜你自己找到了答案 *8-) 然而,使用绑定变量而不是字符串拼接的主要原因之一是为了防止 SQL 注入。由于无法绑定过程名称,如果您确实必须将其作为传入变量,则需要通过检查数据字典中是否存在该名称的过程,并在查询中将其用作绑定变量来验证未尝试注入。 - Alex Poole
1
@AlexPoole,dbms_utility.name_resolve 可能需要处理这个。 - Kirill Leontev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接