Oracle:使用 SQL 或 PL/SQL 查找动态 SQL 中的错误位置
Posted
技术标签:
【中文标题】Oracle:使用 SQL 或 PL/SQL 查找动态 SQL 中的错误位置【英文标题】:Oracle: Find the position of an error in dynamic SQL using SQL or PL/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,并在某些开发工具中显示错误的位置。)
【问题讨论】:
【参考方案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
这种方法有一些缺点:
-
它需要一些额外的、丑陋的代码来捕获异常并重试 SQL。
该示例仅适用于选择。您需要针对插入、更新、删除、合并、动态 PL/SQL 等进行调整。通常您应该知道它是哪种 SQL 语句。如果运气不好,则需要解析语句,这可能非常困难。
如果整个 PL/SQL 语句在一行上,则列号错误。
【讨论】:
我试图通过打印有问题的行和另一行用星号标记问题的开始来模仿 SQL*Plus 的行为。我可以通过解析错误堆栈来获取所需的行数和列数,但是有没有更简单的方法? 据我所知没有更简单的方法。以上是关于Oracle:使用 SQL 或 PL/SQL 查找动态 SQL 中的错误位置的主要内容,如果未能解决你的问题,请参考以下文章
如何在 pl/sql (oracle 9i) 中查找数据类型的大小?
如何从 Oracle 10G PL/SQL 函数和过程中查找所有表引用? [复制]
Oracle:使用 SQL 或 PL/SQL 提取文件扩展名的最快方法