【问题标题】:Oracle: Find the position of an error in dynamic SQL using SQL or PL/SQLOracle:使用 SQL 或 PL/SQL 查找动态 SQL 中的错误位置
【发布时间】:2013-04-24 04:17:25
【问题描述】:

如何在 PL/SQL 或 SQL 的动态 SQL 语句中找到错误的位置?

从 SQL*Plus 我看到错误的位置,例如,无效的 SQL DML 语句:

SYS@orcl> SELECT
       2    X
       3  FROM
       4    TABLEX
       5  /
  TABLEX
  *
ERROR at line 4:
ORA-00942: table or view does not exist

SQL*Plus 用行号显示错误,并在发现错误的地方打印并用星号标记该行。

转换为动态SQL,我可以得到错误代码(SQLCODE)和错误信息(SQLERRM):

SYS@orcl> SET SERVEROUTPUT ON
SYS@orcl> BEGIN
       2    EXECUTE IMMEDIATE 'SELECT X FROM TABLEX';
       3  EXCEPTION
       4    WHEN OTHERS THEN
       5      DBMS_OUTPUT.PUT_LINE('SQLCODE:' || SQLCODE);
       6      DBMS_OUTPUT.PUT_LINE('SQLERRM:' || SQLERRM);
       7  END;
       8  /
SQLCODE:-942
SQLERRM:ORA-00942: table or view does not exist

但是如何获取错误在动态 SQL 字符串中的位置呢?

我看到 Oracle 提供了一个 SQL 通信区 (SQLCA),其中包含有关错误的有趣信息。特别是:

  • SQLCODE 和 SQLERRM 字段(可能是使用相应 PL/SQL 函数检索的数据的来源),
  • SQLERRD 字段,其中提供“解析错误偏移量”的 SQLERRD(5) 元素。

是否可以从 PL/SQL 或 SQL 访问 SQLERRD?如果是这样,怎么做?如果不是,还有什么其他技术可以从 PL/SQL 或 SQL 中给出错误的位置?

(此处http://docs.oracle.com/cd/B28359_01/appdev.111/b31231/chapter8.htm#BABIGBFF SQLCA 已记录并使用 Pro*C 访问。)

(这里的答案how to declare SQLCA.SQLERRD? 似乎表明 SQLERRD 没有在 PL/SQL 中定义,因此无法访问。)

Why doesn't Oracle tell you WHICH table or view does not exist? 此处的讨论给出了一些建议,以使用跟踪文件显示错误的 SQL,并在某些开发工具中显示错误的位置。)

【问题讨论】:

    标签: sql oracle plsql


    【解决方案1】:

    你有一个用于提取dbms_utility中的错误消息的包

    begin 
        .. generate error
    exception when others then 
        dbms_output.put_line(
            dbms_utility.format_call_stack()      || chr(10) || 
            dbms_utility.format_error_backtrace() || chr(10) || 
            dbms_utility.format_error_stack())
    end;
    

    【讨论】:

    • DBMS_UTILITY 本身不足以在动态 SQL 语句 inside 中查找行号。 @ThinkJet 的第二个块将起作用,尽管将 SQL 包装在动态 SQL 块中仍然存在困难。 (第一个块并不总是有效 - 它不会为解析错误获得正确的行号,例如如果表名错误。)
    【解决方案2】:

    通过动态 PL/SQL 运行语句会将相关的行号存储在错误堆栈中。

    比如这个语句第4行有错误:

    declare
        v_count number;
        v_bad_sql varchar2(32767) := 
            'SELECT
                X
              FROM
                TABLEX';
    begin
        execute immediate v_bad_sql into v_count;
    exception when others then
        begin
            execute immediate
                'begin for i in ( '||v_bad_sql||') loop null; end loop; end;';
        exception when others then
            dbms_output.put_line(sqlerrm);
        end;
    end;
    /
    
    ORA-06550: line 4, column 4:
    PL/SQL: ORA-00942: table or view does not exist
    ORA-00942: table or view does not exist
    ORA-06550: line 1, column 18:
    PL/SQL: SQL Statement ignored
    ORA-00942: table or view does not exist
    

    这种方法有一些缺点:

    1. 它需要一些额外的、丑陋的代码来捕获异常并重试 SQL。
    2. 该示例仅适用于选择。您需要针对插入、更新、删除、合并、动态 PL/SQL 等进行调整。通常您应该知道它是哪种 SQL 语句。如果运气不好,则需要解析语句,这可能非常困难。
    3. 如果整个 PL/SQL 语句在一行上,则列号错误。

    【讨论】:

    • 我试图通过打印有问题的行和另一行用星号标记问题的开始来模仿 SQL*Plus 的行为。我可以通过解析错误堆栈来获取所需的行数和列数,但是有没有更简单的方法?
    • 据我所知没有更简单的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多