【问题标题】:Invoking a function call in a string in an Oracle Procedure在 Oracle 过程中调用字符串中的函数调用
【发布时间】:2011-02-24 12:56:05
【问题描述】:

我使用 Oracle 10g 编写应用程序。

我目前正面临这个问题。我将“文件名”作为 varchar2 类型的参数。

文件名可能包含的示例值是:'TEST || to_char(sysdate, 'DDD')'.

在程序中,我想获取这个文件名的值,如 TEST147 中的值。 当我写:

select filename
into ffilename
from dual;

我得到值 ffilename = TEST || to_char(sysdate, 'DDD') 这很有意义。但是我怎样才能绕过这个问题并在字符串值中调用函数呢?

帮助表示赞赏。 谢谢。

【问题讨论】:

    标签: oracle plsql oracle10g dynamic-sql plsqldeveloper


    【解决方案1】:

    您示例中的字符串值是无效表达式;它应该是:'TEST' || to_char(sysdate, 'DDD')

    评估您是否可以这样做:

    execute immediate 'begin :result := ' || filename || '; end;'
      using out v_string;
    

    v_string 然后将包含“TEST147”。

    【讨论】:

    • 感谢您的帮助。它正在生成值 'TEST147' 但它在 dbms_output.put_line('Result: ' || v_string); 上返回错误错误:PLS-00201:必须声明标识符“TEST147”。
    • 我不明白。如果将 dbms_output.put_line(filename) 放在立即执行之前,会得到什么?
    • 遇到立即执行语句时抛出错误。 APC提供的另一种方法有效。感谢您的宝贵时间。
    【解决方案2】:

    动态执行字符串很容易......

    create or replace function fmt_fname (p_dyn_string in varchar2)
        return varchar2
    is
        return_value varchar2(128);
    begin
        execute immediate 'select '||p_dyn_string||' from dual'
            into return_value;
        return  return_value;
    end fmt_fname;
    /
    

    问题出现在你的字符串包含文字的地方,带有可怕的引号......

    SQL> select fmt_fname('TEST||to_char(sysdate, 'DDD')') from dual
      2  /
    select fmt_fname('TEST||to_char(sysdate, 'DDD')') from dual
                                              *
    ERROR at line 1:
    ORA-00907: missing right parenthesis
    
    
    SQL>
    

    所以我们必须转义撇号,所有撇号,包括您​​未包含在已发布字符串中的撇号:

    SQL> select * from t34
      2  /
    
            ID FILENAME
    ---------- ------------------------------
             1 APC001
             2 XYZ213
             3 TEST147
    
    
    SQL> select * from t34
      2  where filename = fmt_fname('''TEST''||to_char(sysdate, ''DDD'')')
      3  /
    
            ID FILENAME
    ---------- ------------------------------
             3 TEST147
    
    SQL>
    

    编辑

    为了公平起见,我觉得我应该指出托尼的解决方案同样有效:

    SQL> create or replace function fmt_fname (p_dyn_string in varchar2)
      2      return varchar2
      3  is
      4      return_value varchar2(128);
      5  begin
      6      execute immediate 'begin :result := ' || p_dyn_string || '; end;'
      7          using out return_value;
      8      return  return_value;
      9  end;
     10  /
    
    Function created.
    
    SQL> select fmt_fname('''TEST''||to_char(sysdate, ''DDD'')') from dual
      2  /
    
    FMT_FNAME('''TEST''||TO_CHAR(SYSDATE,''DDD'')')
    --------------------------------------------------------------------------------
    TEST147
    
    SQL>
    

    事实上,避免 DUAL 上的 SELECT 可能会更好。

    【讨论】:

    • 通过 SQL 执行未经验证的用户输入会导致 SQL 注入攻击。使用 SELECT 至少提供了一些保护,因为它限制了函数可以做什么。允许 PL/SQL 注入会导致各种麻烦。
    猜你喜欢
    • 2019-12-26
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 2011-06-12
    • 1970-01-01
    • 2019-04-07
    • 2013-10-26
    相关资源
    最近更新 更多