我有一些执行静态 DML 语句并使用一些 pl\sql 变量的 PL\SQL 过程 在 where 子句中。 例如:
procedure execute_insert is
l_parameter varchar2(100);
begin
l_parameter := '5';
Insert into Destination_Table(id)
select id
from Source_Table st
where 1=1
and st.id = l_parameter;
exception
when others then
(error logging)
end execute_insert;
我希望能够编写此 sql 语句,以防它在日志表中产生错误。 我发现了这个https://tonyhasler.wordpress.com/2010/01/17/identifying-the-sql_id-of-static-sql-in-plsql-blocks/?unapproved=8391&moderation-hash=1cfb98260e508b941a539d746d98144f#respond
实际使用这个包:
CREATE OR REPLACE PACKAGE SQL_UTIL as
FUNCTION GET_LAST_SQLTEXT RETURN CLOB;
end SQL_UTIL;
/
CREATE OR REPLACE PACKAGE BODY SQL_UTIL
AS
FUNCTION GET_LAST_SQLTEXT
RETURN CLOB
IS
l_sql_text CLOB;
BEGIN
SELECT sql_fulltext
INTO l_sql_text
FROM v$sql sq
JOIN
v$session se
ON sq.sql_id = se.prev_sql_id
AND se.prev_child_number = sq.child_number
AND sid = SYS_CONTEXT('USERENV', 'SID');
RETURN l_sql_text;
END;
END SQL_UTIL;
/
并像这样使用它:
DECLARE
x NUMBER;
BEGIN
select 1 INTO x FROM dual;
DBMS_OUTPUT.put_line(sql_util.get_last_sqltext);
END;
但是这个解决方案不适用于我的情况,因为它不会打印 pl\sql 变量的值 - 例如在下面的 PL\SQL 块中:
DECLARE
x VARCHAR2(10);
y VARCHAR2(50) := '5';
BEGIN
select y INTO x FROM dual;
DBMS_OUTPUT.put_line(sql_util.get_last_sqltext);
END;
它将打印:
SELECT :B1 FROM DUAL
我想得到:
SELECT 5 FROM DUAL
有没有其他方法可以在不使用动态sql的情况下实现这一点? 而且我也不想在声明中添加注释来追踪它。
提前谢谢您。
您将无法获得
SELECT 5 FROM DUAL
,因为那不是 SQL 游标的文本。在 PL/SQL 中,y
是局部变量。当在 SQL 语句中使用时,它充当绑定变量。实际的 SQL 游标是用占位符解析的:SELECT :B1 FROM DUAL
。如果不是这种情况,则必须重新解析并为 y
的每个值创建一个新游标,这违背了绑定变量的全部意义。
仅仅为了日志记录机制的目的,绝对不值得使用动态 SQL 强制这些值的字面化。您将产生性能问题(每次执行时都会进行硬解析),并且还会乱扔共享池,最终导致数据库出现内存问题。大多数 DBA 都会强烈反对这种方法(这是正确的)。 大多数 PL/SQL 程序员依赖于异常处理程序内捕获的错误堆栈和调用堆栈。它们被发送到日志记录过程,该过程将它们(在匿名事务内)插入到日志记录表中,
没有SQL 本身。但是行号可以轻松地用于在过程/包中定位 SQL,因此您实际上不会因不捕获 SQL 而丢失任何内容。 最后,使用
prev_sql_id
的方法不太可靠。在错误处理或日志记录机制中的某个位置发出额外的 SQL 语句将有问题的 SQL 推出
prev_sql_id
槽太容易了。如果您没有任何异常处理程序并且异常正在向客户端引发,则可以使用 after servererror on database
系统触发器,它提供了一些允许捕获违规 SQL 的伪变量,但此类触发器仅在异常发生时才会触发扔给客户端。在 PL/SQL 编程中,您通常会在代码中处理异常,以便触发器永远不会触发。我建议使用普通的异常处理程序,并在其中使用从错误处理函数(如 dbms_utility.format_error_stack
/
.format_error_backtrace
/ .format_call_stack
)获取的参数调用日志记录过程(您自己编写)。使用它在代码中查找 SQL,而无需尝试在运行时捕获和存储 SQL。