При вызове функции SQL, выполняющей вставку, из функции PGPLSQL с блоком EXCEPTION WHEN OTHERS исключение возникает, а не перехватывается, если нарушенное ограничение внешнего ключа откладывается.
Я использую Amazon Aurora PostgreSQL совместимый (v 10.4). Я обнаружил, что мой обработчик исключений не всегда перехватывал исключения, которые вместо этого вызывались в приложении (в моем случае это функция Python AWS Lambda, использующая Pyscopg2).
Потребовалось много усилий для устранения неполадок, чтобы сузить их до отложенного ограничения, поэтому я создал тестовую функцию, которая довольно надежно воспроизводит проблему.
Я также воспроизвел такое же поведение на экземпляре RDS (не Aurora), работающем под управлением версии 10.5, а также на экземпляре RDS 9.6.6, так что это не Aurora и не относится к версии 10.4.
Это ошибка? Или я упускаю что-то, что задокументировано с отложенными ограничениями?
Вот две таблицы и две функции.
CREATE TABLE public.load (
load_id BIGINT NOT NULL,
created_timestamp TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
ds_code TEXT NOT NULL,
route TEXT,
file_name TEXT,
user_name TEXT,
staged BOOLEAN,
staging_duration INTERVAL,
CONSTRAINT load_pkey
PRIMARY KEY (load_id));
CREATE TABLE load_content (
load_id BIGINT NOT NULL,
load_content TEXT,
CONSTRAINT data_load_pk
PRIMARY KEY (load_id),
CONSTRAINT data_load_load_load_id_fk
FOREIGN KEY (load_id) REFERENCES public.load
)
;
CREATE FUNCTION insert_something() RETURNS void
LANGUAGE SQL
AS
$$
INSERT INTO public.load_content values (1);
$$
;
CREATE FUNCTION test_load() RETURNS TEXT
LANGUAGE plpgsql
AS
$$
BEGIN
PERFORM public.insert_something();
RETURN 'success';
EXCEPTION
WHEN OTHERS THEN
RETURN 'failure';
END
;
$$
;
Выполнение public.test_load () возвращает одну строку «fail».
Если вы затем сделаете это:
alter table public.load_content
drop constraint data_load_load_load_id_fk;
ALTER TABLE public.load_content
ADD CONSTRAINT data_load_load_load_id_fk
FOREIGN KEY (load_id) REFERENCES public.load
DEFERRABLE INITIALLY DEFERRED
;
Затем выполните public.test_load (), исключение просто происходит:
[2019-01-14 16:36:32] [23503] ERROR: insert or update on table "load_content" violates foreign key constraint "data_load_load_load_id_fk"
[2019-01-14 16:36:32] Detail: Key (load_id)=(1) is not present in table "load".
Очевидно, я значительно упростил это для целей тестирования - то, что на самом деле происходит в моей системе, это триггер в таблице «загрузки», который срабатывает для нормализации необработанных данных (обычно JSON) в промежуточную модель данных.