You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让自定义Postgres now()函数优先级高于pg_catalog中的同名函数?

如何让自定义now()函数优先级高于Postgres内置函数?

在测试数据库中,我尝试通过创建自定义函数覆盖Postgres的now()以实现时间调整,代码如下:

CREATE SCHEMA if not exists override;
CREATE OR REPLACE FUNCTION override.now()
RETURNS timestamp with time zone
AS
$$
BEGIN
RETURN pg_catalog.now() + COALESCE(
  NULLIF(current_setting('timecop.offset_in_seconds', true), '')::integer, 0
) * interval '1 second';
END;
$$
LANGUAGE plpgsql STABLE PARALLEL SAFE STRICT;
SET search_path TO DEFAULT;
SELECT set_config('search_path', 'override,' || current_setting('search_path'), false);

通过SET timecop.offset_in_seconds = 3600启用时间偏移后,调用now()却未生效,查询函数列表发现pg_catalog中的now()优先级更高:

app_test=# \df+ now
                                                                                        List of functions
   Schema   | Name |     Result data type     | Argument data types | Type | Volatility | Parallel |  Owner   | Security | Access privileges | Language | Source code |       Description
------------+------+--------------------------+---------------------+------+------------+----------+----------+----------+-------------------+----------+-------------+--------------------------
 pg_catalog | now  | timestamp with time zone |                     | func | stable     | safe     | postgres | invoker  |                   | internal | now         | current transaction time

问题原因

Postgres默认会搜索pg_catalog中的内置函数,但如果自定义schema位于search_path的最前端,同签名的自定义函数会被优先调用。你的情况大概率是search_path设置未正确生效,导致Postgres仍优先使用系统内置函数。

解决方法

1. 确认自定义函数与schema存在

先执行以下SQL确认override.now()已正确创建:

SELECT proname, nspname 
FROM pg_proc 
JOIN pg_namespace ON pg_proc.pronamespace = pg_namespace.oid 
WHERE proname = 'now';

正常应返回两条记录:(now, override)和(now, pg_catalog)。

2. 确保search_path将override置于最前端

Postgres会按search_path的顺序查找函数,将自定义schema放在最前面即可优先匹配:

  • 临时生效(当前会话):
    SET search_path = override, "$user", public;
    
    设置后直接测试SELECT now();即可生效。
  • 永久生效(针对数据库):
    ALTER DATABASE app_test SET search_path = override, "$user", public;
    
    执行后需要重新连接会话才会生效。
  • 永久生效(针对特定用户):
    ALTER ROLE your_test_user SET search_path = override, "$user", public;
    
    同样需要重新连接会话。

3. 极端方案(测试环境慎用)

如果上述方法无效,且你拥有超级用户权限,可以直接替换pg_catalog中的now()函数(仅推荐测试环境临时使用):

CREATE OR REPLACE FUNCTION pg_catalog.now()
RETURNS timestamp with time zone
AS
$$
BEGIN
RETURN pg_catalog.current_timestamp + COALESCE(
  NULLIF(current_setting('timecop.offset_in_seconds', true), '')::integer, 0
) * interval '1 second';
END;
$$
LANGUAGE plpgsql STABLE PARALLEL SAFE STRICT;

测试完成后记得恢复系统函数:

CREATE OR REPLACE FUNCTION pg_catalog.now()
RETURNS timestamp with time zone
AS 'SELECT current_timestamp'
LANGUAGE sql STABLE PARALLEL SAFE STRICT;

内容的提问来源于stack exchange,提问作者23tux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:55:12