Когда / как функции выражения по умолчанию связаны с search_path?

Для целей тестирования я предоставляю свою собственную реализацию now() функция, которая public.now(), С помощью search_path переопределить значение по умолчанию pg_catalog.now() с моей собственной версией в основном работает, но у меня есть таблица с таблицей с выражением по умолчанию now(), Отображение таблицы производит нечто похожее на следующее:

 start_date   | date    | not null default now()

Однако после сохранения и восстановления схемы (в тестируемой БД) та же таблица показа выдает

 start_date   | date    | not null default pg_catalog.now()

Исходя из этого, я предполагаю, что изначально функция в выражении по умолчанию не связана ни с одной схемой, и путь поиска будет использоваться для поиска правильной. Однако операция дампа или восстановления "привязывает" функцию к текущей.

Верно ли мое понимание "состояния привязки" функции? Есть ли способ сохранить несвязанность функции через границы дампа / восстановления?

3 ответа

Решение

Значения по умолчанию анализируются во время создания (раннее связывание!). То, что вы видите в psql, pgAdmin или других клиентах, является текстовым представлением, но, на самом деле, OID функции now() на момент создания столбец по умолчанию хранится в системном каталоге pg_attrdef, Я цитирую:

adbin   pg_node_tree  The internal representation of the column default value
adsrc   text          A human-readable representation of the default value

Когда вы меняете search_path, что заставляет Postgres отображать имя функции, дополненной схемой, поскольку оно не будет корректно разрешаться с текущей search_path,

Дамп и восстановление не связаны с вашим кастомом search_path установка. Они устанавливают это явно. То, что вы видите, не связано с циклом дамп / восстановление.

Переопределить встроенные функции

размещение public до pg_catalog в search_path это игра в азартные игры. Неимущим пользователям (включая себя) часто разрешается писать там и создавать функции, которые могут непреднамеренно перекрывать системные функции - с произвольным (или злонамеренным) результатом.

Вам нужна выделенная схема с ограниченным доступом для переопределения встроенных функций. Вместо этого используйте что-то вроде этого:

SET search_path = override, pg_catalog, public;

Подробности в этом связанном ответе на dba.SE.

Функция по умолчанию является "связанной" во время создания ограничения по умолчанию. Представление, показывающее неквалифицированное имя, просто сокращает его.

Это можно продемонстрировать, вставив строки до и после затенения функции:

Set search_path to public,pg_catalog;

Create Temp Table foo (
    test date not null default now()
);

Insert Into foo default values;

Create Function public.now() Returns timestamp with time zone Language SQL As $$ 
     -- No idea why I chose this date.
     Select '1942-05-09'::timestamp with time zone;
$$;

Insert Into foo default values;

Select * from foo;

Обратите внимание, что обе строки (вставленные до и после создания функции) содержат сегодняшнюю дату, а не фиктивную дату.

Кроме того, создание таблицы с указанной выше функцией уже в области видимости, а затем попытка удалить функцию приводит к ошибке зависимости:

Set search_path to public,pg_catalog;

Create Function public.now() Returns timestamp with time zone Language SQL As $$ 
    Select '1942-05-09'::timestamp with time zone;
$$;

Create Temp Table bar (
    test date not null default now()
);

Insert Into bar default values;

Select * from bar;
-- Single row containing the dummy date rather than today

Drop Function public.now();
-- ERROR:  cannot drop function now() because other objects depend on it

Если бы привязка произошла только при вставке, такой зависимости не было бы.

Не беспокойся обо всем этом. Postgres иногда пишет устаревшие вещи после компиляции. Особенно представления часто меняются за счет признания.

И: now() и pg_catalog.now() обычно одинаковы. Увидеть:

CREATE OR REPLACE FUNCTION now()
    RETURNS timestamp with time zone AS
'now'
    LANGUAGE internal STABLE STRICT
 COST 1;
 ALTER FUNCTION now()
    OWNER TO postgres;
 COMMENT ON FUNCTION now() IS 'current transaction time';

Не беспокойся

Другие вопросы по тегам