Home > Mobile >  Overwrite Postgres now() function
Overwrite Postgres now() function

Time:12-05

In my test database, I want to override now() in Postgres, so I can travel to a certain point in time. I'd like to override it like this:

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);

To enable it, I call

SET timecop.offset_in_seconds = 3600 -- 1 hour ahead

To disable it, I call

RESET timecop.offset_in_seconds

The problem is, that Postgres somehow doesn't use the function:

app_test=# select now();
              now
-------------------------------
 2022-12-04 10:22:26.824469 00
(1 row)

app_test=# SET timecop.offset_in_seconds = 3600;
SET
app_test=# select now();
              now
-------------------------------
 2022-12-04 10:22:34.481502 00
(1 row)

Looking at the now() method itself, I seems like the search path searches in pg_catalog before the override schema:

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

So, how could I move my overwritten now() BEFORE the pg_catalog?

CodePudding user response:

pg_catalog is always on the search path, but you can opt not to have it in the beginning:

SET search_path = override, pg_catalog;
  • Related