是否可以将EXTERNAL FUNCTION设为常量或不可变,以便Firebird在一个SQL语句的过程中知道不重新计算它?
在下面的示例中(Firebird 2.1),我希望GETTIMEOFDAY()的行为类似于CURRENT_TIMESTAMP,但它会被评估两次:
SQL> DECLARE EXTERNAL FUNCTION gettimeofday -- gettimeofday(2) wrapper
CON> RETURNS DOUBLE PRECISION BY VALUE
CON> ENTRY_POINT 'UDF_gettimeofday' MODULE_NAME 'udf_gettimeofday';
SQL> SELECT CURRENT_TIMESTAMP AS ts,
CON> CAST(GETTIMEOFDAY() AS INTEGER) AS time_t,
CON> FB_SLEEP(2) AS zzz
CON> FROM rdb$database
CON> CROSS JOIN (SELECT 1 AS foo
CON> FROM rdb$database
CON> UNION ALL
CON> SELECT 2
CON> FROM rdb$database) d;
TS TIME_T ZZZ
========================= ============ ============
2011-03-15 20:57:46.0390 1300244268 0
2011-03-15 20:57:46.0390 1300244270 0
正如您所看到的,“TS”的值保持不变,但我的“TIME_T”在FB_SLEEP()调用中前进。 (FB_SLEEP是暂停指定秒数的便捷功能。)
我想要的是什么?我知道PostgreSQL正是以STABLE FUNCTIONS。
的概念准确地允许这一点答案 0 :(得分:2)
AFAIK,你不能将一个UDF标记为Firebird中的常量或不可变,但作为一种解决方法,你可以依靠内联视图(也就是派生表)来实现你想要的:只选择一次值并使用它作为结果中的常量。我手头没有任何UDF进行测试,所以可能有一些语法错误,但我希望你能抓住这个背后的想法:
SELECT CURRENT_TIMESTAMP AS ts,
q1.time_t,
FB_SLEEP(2) AS zzz
FROM rdb$database
CROSS JOIN (select CAST(GETTIMEOFDAY() AS INTEGER) AS time_t from rdb$database)
CROSS JOIN (SELECT 1 AS foo
FROM rdb$database
UNION ALL
SELECT 2
FROM rdb$database) d;
您还可以依赖可选择的存储过程来运行udf一次并将列添加到给定查询的结果中
编辑根据要求,我包含了存储过程:
SET TERM ^ ;
CREATE PROCEDURE ExampleSP
RETURNS
(
ts timestamp
, time_t integer
, zzz integer
)
as
BEGIN
SELECT CAST(GetTimeOfDay() AS Integer)
FROM rdb$database
INTO :time_t;
for SELECT Current_Timestamp AS ts,
FB_SLEEP(2) AS zzz
FROM rdb$database
CROSS JOIN (SELECT 1 AS foo
FROM rdb$database
UNION ALL
SELECT 2
FROM rdb$database) d
INTO :ts, :zzz do
SUSPEND;
END
^
SET TERM ; ^
SELECT * FROM ExampleSP;
答案 1 :(得分:1)
简介
简短的回答是“不”,随附的指导是“始终以UTC格式运行您的服务器。”
<强>变通方法强>
最简单的情况:稳定的UTC时间戳
(这是我最初的目标。)如果CURRENT_TIMESTAMP足够精确,只需以UTC格式运行服务器即可。不需要UDF。
明确预先计算UDF
没有直接支持的方法来“稳定”UDF。因此,大多数客户最好只是预先计算UDF的返回值,在GTT等中将该文字值作为客户端提供的参数提供。
<强>未完善强>
CURRENT_TRANSACTION和CURRENT_TIMESTAMP一起有效地识别单个查询,至少达到CURRENT_TIMESTAMP的精度。 (再次假设时钟是UTC,以免在夏令时发生变化时自行重复。)
考虑到这一点,可选择的存储过程可以使用RDB $ SET_CONTEXT和RDB $ GET_CONTEXT将UDF的返回值缓存为字符串,存储在USER_TRANSACTION上下文中并键入CURRENT_TIMESTAMP。添加一些额外的逻辑来修剪USER_TRANSACTION下存储的条目数。呸。