我目前正在 Oracle SQL Developer 中处理 PL SQL 脚本,我在其中还添加了一些 dbms_output 命令用于日志记录。下面的代码工作得很好,我唯一的问题是在两行(format_error_stack 和 format_error_backtrace)之后插入了一个换行符,我想阻止它。下面的程序只是一个测试程序,不应产生任何有价值的输出。
procedure test(
i_key in number
)
is
l_test number := 0;
begin
dbms_output.put_line('TEST - START PROCEDURE');
l_test := i_key;
dbms_output.put_line('TEST - Value: ' ||i_key|| '.');
raise no_data_found;
exception
when no_data_found then
dbms_output.put_line('Exception: ' ||SUBSTR(DBMS_UTILITY.format_error_stack,1,4000));
dbms_output.put_line('Backtrace: ' ||SUBSTR(DBMS_UTILITY.format_error_backtrace,1,4000));
dbms_output.put_line('Test');
end;
上面的程序有以下输出:
TEST - START PROCEDURE
TEST - Value: 1.
Exception: ORA-01403: no data found
Backtrace: ORA-06512: at "EXAMPLE.TEST_PROC", line 19
Test
PL/SQL procedure successfully completed.
我已经用谷歌搜索了这个问题以及 DBMS_UTILITY 函数,但找不到任何合理的解释为什么在两个 DBMS_UTILITY 函数之后有换行符。
看起来是关于线的长度(不过,那是相当短的线)。
见第 16 行,它提取长度为 25 个字符的子字符串并导致“换行”:
SQL> create or replace
2 procedure test(
3 i_key in number
4 )
5 is
6 l_test number := 0;
7 begin
8
9 dbms_output.put_line('TEST - START PROCEDURE');
10 l_test := i_key;
11 dbms_output.put_line('TEST - Value: ' ||i_key|| '.');
12 raise no_data_found;
13
14 exception
15 when no_data_found then
16 dbms_output.put_line('Exception: ' ||SUBSTR(DBMS_UTILITY.format_error_stack,1,25)); --> here
17 dbms_output.put_line('Backtrace: ' ||SUBSTR(DBMS_UTILITY.format_error_backtrace,1,4000));
18 dbms_output.put_line('Test');
19 end;
20 /
Procedure created.
SQL> set serveroutput on
SQL> exec test (1);
TEST - START PROCEDURE
TEST - Value: 1.
Exception: ORA-01403: no data found
--> here
Backtrace: ORA-06512: at "SCOTT.TEST", line 11
Test
PL/SQL procedure successfully completed.
但是,如果将其缩短为 24 个字符,则不再有换行符:
SQL> create or replace
2 procedure test(
3 i_key in number
4 )
5 is
6 l_test number := 0;
7 begin
8
9 dbms_output.put_line('TEST - START PROCEDURE');
10 l_test := i_key;
11 dbms_output.put_line('TEST - Value: ' ||i_key|| '.');
12 raise no_data_found;
13
14 exception
15 when no_data_found then
16 dbms_output.put_line('Exception: ' ||SUBSTR(DBMS_UTILITY.format_error_stack,1,24)); --> here
17 dbms_output.put_line('Backtrace: ' ||SUBSTR(DBMS_UTILITY.format_error_backtrace,1,4000));
18 dbms_output.put_line('Test');
19 end;
20 /
Procedure created.
SQL> exec test (1);
TEST - START PROCEDURE
TEST - Value: 1.
Exception: ORA-01403: no data found --> here
Backtrace: ORA-06512: at "SCOTT.TEST", line 11
Test
PL/SQL procedure successfully completed.
SQL>
例如
SET LINESIZE 500
(在 SQL*Plus 中)有帮助吗?不。
为什么会这样?不知道。
格式化的堆栈和回溯都以换行符结尾。
LENGTH(SUBSTR(DBMS_UTILITY.format_error_stack,1,4000)))
返回 25.
ASCII(SUBSTR(DBMS_UTILITY.format_error_stack,25,1)))
返回 10 - 这是换行符的字符代码。
然后你做
dbms_output.put_line(...)
也添加换行符:
当您调用 PUT_LINE 时,您指定的项目后面会自动跟上一个行尾标记。如果调用 PUT 来构建一行,则必须通过调用 NEW_LINE 添加自己的行尾标记。 GET_LINE 和 GET_LINES 不返回未以换行符终止的行。
您可以通过使用
put
来避免这种情况,并且依赖消息总是以换行符结尾。但是当您将原始值截断为 4000 个字符时,您可能会有更长的回溯并且如果关闭则切断 - 然后不要以换行符结尾,因为它可能(或可能)在中间一条消息,而不是结束。您可以倒数到最后一个换行符,但这有点混乱。
有趣的是 backtrace 的文档包括一次打印一行的示例代码,它在换行符处拆分源文本,然后使用
put_line
添加一个。这将允许处理特别大的字符串,尝试直接传递到 put_line
可能会出错,因为它超过了可以处理的 limits - 即如果回溯超过 32k.
所以你可能想采用这种方法而不是只捕获前 4000 个字符。