【问题标题】:Why do I get "ORA-00933: SQL command not properly ended" error ( execute immediate )?为什么会出现“ORA-00933:SQL 命令未正确结束”错误(立即执行)?
【发布时间】:2021-11-30 16:02:09
【问题描述】:

我创建了一个函数,它使用动态 sql:

create function check_ref_value
(
    table_name varchar2,
    code_value number,
    code_name  varchar2
) return number is
    l_query varchar2(32000 char);
    l_res   number;
begin
    l_query := '
        select sign(count(1))
        into :l_res
        from '|| table_name ||'
        where '|| code_name ||' = :code_value
    ';

    execute immediate l_query
    using in code_value, out l_res;

    return l_res;
end;

但是当我尝试使用它时,我得到一个异常“ORA-00933:SQL 命令未正确结束” 这段代码有什么问题?

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    您可以使用EXECUTE IMMEDIATE ... INTO ... USING ... 获取返回值,使用DBMS_ASSERT 在SQL 注入尝试的情况下引发错误:

    create function check_ref_value
    (
        table_name varchar2,
        code_value number,
        code_name  varchar2
    ) return number is
        l_query varchar2(32000 char);
        l_res   number;
    begin
        l_query := 'select sign(count(1))'
                || ' from  ' || DBMS_ASSERT.SIMPLE_SQL_NAME(table_name)
                || ' where ' || DBMS_ASSERT.SIMPLE_SQL_NAME(code_name)
                || ' = :code_value';
        execute immediate l_query INTO l_res USING code_value;
    
        return l_res;
    end;
    /
    

    其中,对于样本数据:

    CREATE TABLE abc (a, b, c) AS
    SELECT 1, 42, 3.14159 FROM DUAL;
    

    然后:

    SELECT CHECK_REF_VALUE('abc', 42, 'b') AS chk FROM DUAL;
    

    输出:

    CHK
    1

    还有:

    SELECT CHECK_REF_VALUE('abc', 42, '1 = 1 OR b') AS chk FROM DUAL;
    

    引发异常:

    ORA-44003: invalid SQL name
    ORA-06512: at "SYS.DBMS_ASSERT", line 160
    ORA-06512: at "FIDDLE_UVOFONEFDEHGDQJELQJL.CHECK_REF_VALUE", line 10
    

    至于你的问题:

    这段代码有什么问题?

    使用SELECT ... INTO 仅在PL/SQL 块中的SQL 语句中有效,并且当您通过EXECUTE IMMEDIATE 运行该语句时,它在SQL 范围内而不是PL/SQL 范围内执行。

    您可以通过将动态代码包装在 BEGIN .. END PL/SQL 匿名块中来修复它(并颠倒 USING 子句中绑定参数的顺序):

    create function check_ref_value
    (
        table_name varchar2,
        code_value number,
        code_name  varchar2
    ) return number is
        l_query varchar2(32000 char);
        l_res   number;
    begin
        l_query := '
          BEGIN
            select sign(count(1))
            into :l_res
            from '|| DBMS_ASSERT.SIMPLE_SQL_NAME(table_name) ||'
            where '|| DBMS_ASSERT.SIMPLE_SQL_NAME(code_name) ||' = :code_value;
          END;
        ';
    
        execute immediate l_query
        using out l_res, in code_value;
    
        return l_res;
    end;
    /
    

    (但是,这比使用EXECUTE IMMEDIATE ... INTO ... USING ... 更复杂一些。)

    db小提琴here

    【讨论】:

      猜你喜欢
      • 2019-02-12
      • 1970-01-01
      • 2013-07-15
      • 2014-10-07
      • 1970-01-01
      • 2012-02-14
      • 1970-01-01
      • 2019-08-22
      • 1970-01-01
      相关资源
      最近更新 更多