火鸟常数UDF
是否可以将 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 正是通过其稳定函数的概念允许这样做。
Is it possible to make an EXTERNAL FUNCTION as constant or immutable, so that Firebird knows not to recompute it during the course of one SQL statement?
In the example below (Firebird 2.1), I'd like GETTIMEOFDAY() to behave like CURRENT_TIMESTAMP, but it is instead evaluated twice:
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
As you can see, the value of "TS" remains constant, but my "TIME_T" advances across the FB_SLEEP() calls. (FB_SLEEP is a convenience function to pause for the given number of seconds.)
Is what I want possible? I know PostgreSQL permits precisely this with its concept of STABLE FUNCTIONS.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
AFAIK,您不能在 Firebird 中将 UDF 标记为常量或不可变,但作为一种解决方法,您可以依靠内联视图(又名派生表)来实现您想要的:仅选择一次值并将其用作常量在你的结果中。我手头没有任何 UDF 来进行测试,所以可能会出现一些语法错误,但我希望您能理解这背后的想法:
您还可以依赖一个可选择的存储过程来运行 udf 一次并将列添加到结果中给定查询的
编辑 根据要求,我包括存储过程:
AFAIK, you cannot mark a UDF as constant or inmutable in Firebird, but as a workaround you can rely on a in-line view (aka derived table) to achieve what you want: select the value just one time and use it as a constant in your results. I do not have any UDF at hand to make a test, so maybe some syntax error, but I hope you catch the idea behind this:
You can also rely on a selectable stored procedure to run the udf once and add the column to the results of a given query
Edit As requested, I'm including the Stored procedure:
简述
简短的回答是“否”,随附的指导是“始终在 UTC 中运行服务器”。
解决方法
最简单的情况:稳定的 UTC 时间戳
(这是我最初的目标。)如果 CURRENT_TIMESTAMP 足够精确,只需以 UTC 运行服务器即可。不需要UDF。
显式预计算 UDF
没有直接支持的方法来“稳定”UDF。因此,大多数客户端最好简单地预先计算 UDF 的返回值,使该文字值可用作 GTT 等中客户端提供的参数。
Kludge
CURRENT_TRANSACTION 和 CURRENT_TIMESTAMP 一起有效地标识单个查询,至少达到 CURRENT_TIMESTAMP 的精度。 (再次假设时钟采用 UTC 格式,以免时间在夏令时更改期间重复出现。)
考虑到这一点,可选择的存储过程可以使用 RDB$SET_CONTEXT 将 UDF 的返回值缓存为字符串,并且RDB$GET_CONTEXT,存储在 USER_TRANSACTION 上下文中并关闭 CURRENT_TIMESTAMP。添加一些额外的逻辑来修剪存储在 USER_TRANSACTION 下的条目数量。恶心。
In Brief
The short answer is "no," and the accompanying guidance is "always run your server in UTC."
Workarounds
Simplest case: stable UTC timestamps
(This was my original aim.) If CURRENT_TIMESTAMP is precise enough, simply run your server in UTC. No UDF required.
Explicitly precompute UDF
There's no directly supported way to "stabilize" a UDF. So, most clients are better off simply pre-computing the UDF's return value, making that literal value available as a client-supplied parameter, in a GTT, etc.
Kludge
CURRENT_TRANSACTION and CURRENT_TIMESTAMP taken together effectively identify an individual query, at least to the precision of CURRENT_TIMESTAMP. (Again presuming that the clock is in UTC, lest time repeat itself during a daylight savings change.)
That in mind, a selectable stored procedure could cache the UDF's return value as a string using RDB$SET_CONTEXT and RDB$GET_CONTEXT, storing in the USER_TRANSACTION context and keying off of CURRENT_TIMESTAMP. Add in a little extra logic to prune the number of entries stored under USER_TRANSACTION, too. Yuck.