Ошибка pg_restore: функция raise_err (неизвестно) не существует

Я запускаю ежедневное резервное копирование своей базы данных с помощью pg_dump и pg_restore, которые недавно перестали работать после того, как я отправил обновление.

У меня есть функция validate_id, которая является оператором Case/When, просто для быстрой проверки некоторых данных, имеющих проблемы с целостностью. Выглядит примерно так:

CREATE OR REPLACE FUNCTION validate_id(
    _string text,
    _type type
) RETURNS boolean AS
$$
SELECT
    CASE WHEN (stuff) THEN TRUE
    WHEN (other stuff) THEN TRUE
    When (more stuff) THEN raise_err('Not an accepted type, the accepted types are: x y z')
ELSE FALSE
$$
LANGUAGE SQL;

Поскольку я добавил эту функцию, когда я делаю дамп с помощью этой команды:

pg_dump -U postgres -h ipaddress -p 5432 -w -F t databaseName > backupsfolder/databaseName.tar

Когда я использую эту команду:

pg_restore -U postgres -h localhost -p 5432 -d postgres -C "backupsfolder/databaseName.tar"

По состоянию на два дня назад это теперь вызывает ошибку:

pg_restore: error: could not execute query: ERROR: function raise_err(unknown) does not exist

Я совсем запутался, что делать. Я думаю, что может происходить то, что он пытается восстановить эту функцию до того, как восстановит функцию raise_err. Который, как я думал, был встроен в postgres (я могу SELECT raise_err('Hello, World');). Это возможно? Это мой оператор CASE, потому что мне нужно возвращать только логические значения? Все разрешения кажутся правильными, и восстановление с использованием предыдущих резервных копий работает нормально.


person HelpMeExitVim    schedule 20.08.2020    source источник
comment
Войдите в исходную базу данных с помощью psql и выполните \df+ raise_err. Насколько я знаю, это не стандартная функция. Вам не нужна другая функция, чтобы вызвать ошибку, так как вы можете просто сделать raise error   -  person Mike Organek    schedule 21.08.2020
comment
Это работает в функции, написанной на sql, или это должно быть plpgsql?   -  person HelpMeExitVim    schedule 21.08.2020
comment
\df+ raise_err действительно... возвращает функцию. Это не то, что я когда-либо помню, чтобы явно создавать, но я имею в виду, что всякое случается.   -  person HelpMeExitVim    schedule 21.08.2020
comment
Извините, я не подумал об этом. language sql не будет его поддерживать, и это, вероятно, объясняет, почему вы написали его как функцию. Кроме того, это raise exception, а не raise error, как я ошибочно сказал в своем предыдущем комментарии. Похоже, что иногда это происходит: stackoverflow.com/q/30707533/13808319   -  person Mike Organek    schedule 21.08.2020
comment
Потрясающий! Вот и все, я чувствую себя очень глупо. Спасибо за помощь!   -  person HelpMeExitVim    schedule 21.08.2020
comment
Вы используете это как функцию CHECK? Если да, то нет-нет createtable: в настоящее время выражения CHECK не может содержать подзапросы и ссылаться на переменные, отличные от столбцов текущей строки (см. Раздел 5.4.1). Можно ссылаться на таблоид системного столбца, но не на какой-либо другой системный столбец.   -  person Adrian Klaver    schedule 21.08.2020
comment
Не чувствуйте себя глупо, создание этой функции имеет смысл, IMO. Я подозреваю, что тот факт, что это функция language sql, сбил с толку алгоритм, пытающийся найти зависимости во время pg_backup.   -  person Mike Organek    schedule 21.08.2020


Ответы (2)


Проблема в том, что raise_err не соответствует схеме в коде вашей функции.

Это потенциально опасно: злоумышленник может создать собственную функцию raise_err и настроить search_path так, чтобы вызывалась не та функция.

Поскольку pg_restore обычно запускается суперпользователем, это может быть проблемой безопасности. Представьте, что такая функция используется в определении индекса!

По этим причинам pg_dump и pg_restore задают пустой search_path в текущих версиях PostgreSQL.

Решение вашей проблемы состоит в том, чтобы явно использовать схему функции в вашем операторе SQL.

person Laurenz Albe    schedule 21.08.2020

В итоге я решил эту проблему, явно установив пути поиска для обеих функций, raise_err() и validate_id() в public:

ALTER FUNCTION validate_id(text,text) SET search_path=public;
ALTER FUNCTION raise_err(text,text) SET search_path=public;
person HelpMeExitVim    schedule 25.08.2020