Firebird SQL过程能知道调用它的父过程/触发器吗



我有一个SQL过程,如果从一个特定过程调用它,它应该会返回一个不同的结果。SQL过程是否可以检测到它是从一个特定的其他SQL过程调用的?

也许监控mon$。。。表格数据能给出答案吗?

问题适用于Firebird 2.1

例如,有mon$call_stack表,但对于大部分mon$。。。Firebird 2.1的表格是空的,而Firebird的后续版本则是空的。

隐藏的数据依赖关系是个坏主意。程序员之所以看到";纯函数";作为一件值得追求的好事。也许不是在所有情况下,也不是不惜一切代价,但当其他因素不受影响时,最好是这样

https://en.wikipedia.org/wiki/Pure_function

因此,Mark正确地认为,如果有什么东西影响了您的过程逻辑,那么最好通过成为显式函数参数来显式地记录它除非你明确的目标是创建一个隐藏的后门

然而,这意味着所有的";客户端";在该过程中,所有可以调用它的地方也应该更改,并且这应该在客户端部署站点的开发和升级过程中协同完成。这可能很复杂。

因此,我宁愿建议创建一个新的程序,并将所有实际的逻辑转移到其中

https://en.wikipedia.org/wiki/Adapter_pattern

假设你有一些

create procedure old_proc(param1 type1, param2 type2, param3 type3) as 
begin
....some real work and logic here....
end;

将其转换为类似的东西

create procedure new_proc(param1 type1, param2 type2, param3 type3, 
new_param smallint not null = 0) as 
begin
....some real work and logic here....
....using new parameter for behavior fine-tuning...
end;
create procedure old_proc(param1 type1, param2 type2, param3 type3) as 
begin
execute procedure new_proc(param1, param2, param3)
end;

然后你明确地做出";一个特定程序";调用CCD_ 1。然后,逐渐地,一个地方接一个地方,您将所有程序从调用old_proc移动到调用new_proc,最终当所有依赖关系移动到新的API时,您将退出old_proc

  • https://www.firebirdsql.org/rlsnotesh/rnfbtwo-psql.html#psql-默认参数

还有一个选项要通过";隐藏后门参数"-这是上下文变量,在Firebird 2.0 中引入

https://www.firebirdsql.org/rlsnotesh/rlsnotes20.html#dml-dsql上下文

然后你的被叫会像一样检查

.....normal execution
if ( rdb$get_context('USER_TRANSACTION','my_caller') is not null) THEN BEGIN
....new behavior...
end;

然而,你必须做出";一个特定程序";在调用之前正确地设置这个变量(这很乏味,但并不难(,并在调用之后正确地删除它(即使在出现任何错误/异常的情况下,也应该正确地设置它,这也很乏味,也不容易(。

我不知道有任何这样的选项。如果您的过程在从特定过程调用时表现出特殊行为,我建议您通过添加一个指定行为类型的额外参数或将其分为两个不同的过程来明确它。

这样,您也可以直接测试行为。

虽然我同意最好的方法可能是在过程中添加一个参数,以帮助确定从哪里调用它,但有时我们没有这种奢侈。考虑这样一种情况,即过程签名不能更改,因为它在遗留系统中并且在许多地方被调用。在这种情况下,我将考虑以下示例;

在本例中,需要知道是谁调用它的存储过程将被称为SPROC_A。

首先,我们创建一个全局温度表

CREATE GLOBAL TEMPORARY TABLE GTT_CALLING_PROC
( PKEY INTEGER primary key,
CALLING_PROC VARCHAR(31))
ON COMMIT DELETE ROWS;

接下来,我们创建另一个名为SPROC_A_WRAPPER的存储过程,它将封装对SPROC_A的调用

CREATE OR ALTER PROCEDURE SPROC_A_WRAPPER
AS
DECLARE CALLING_SPROC VARCHAR(31);
BEGIN
DELETE FROM GTT_CALLING_PROC
WHERE GTT_CALLING_PROC.PKEY = 1;
INSERT INTO GTT_CALLING_PROC (
PKEY,
CALLING_PROC)
VALUES (
1,
'SPROC_A_WRAPPPER');
EXECUTE PROCEDURE SPROC_A;
DELETE FROM GTT_CALLING_PROC
WHERE GTT_CALLING_PROC.PKEY = 1;
END

最后我们有了SPROC_A

CREATE OR ALTER PROCEDURE SPROC_A
AS
DECLARE CALLING_SPROC VARCHAR(31);
BEGIN
SELECT FIRST 1 CALLING_PROC
FROM GTT_CALLING_PROC
WHERE GTT_CALLING_PROC.PKEY = 1
INTO :CALLING_SPROC;
IF (:CALLING_SPROC = 'SPROC_A_WRAPPER') THEN
BEGIN
/*  Do Something  */
END
ELSE
BEGIN
/*  Do Something Else */
END
END

SPROC_A_WRAPPER将填充Temp表,调用该SPROC_A,然后从Temp表中删除该行,以防从同一事务中的其他地方调用SPROC_A,它不会认为SPROC_A-WRAPPER调用了它。

虽然有点粗糙,但我相信这会满足你的需要。

最新更新