Как обновить ту же строку, что и insert / update в plpgsql, не достигая max_stack_depth - PullRequest
1 голос
/ 09 апреля 2019

Моя проблема в том, что я достиг предела стека. И в сообщении об ошибке говорится: «Вы должны увеличить max_stack_depth & rdquo; и показывает строку, которую я использую для обновления другого столбца.

Я сталкиваюсь с этой ошибкой после запроса на обновление (код ниже).

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

То, что я хочу сделать, просто, и я делал это много раз, но здесь я что-то упускаю.

Хочу: если на столе есть обновление support_fh нажать триггер. Я ожидаю, что этот триггер сделает:

если новыми значениями запроса на обновление являются section = 'DISTRIBUTION' и modulo = '6' и fabricant = 'NEXANS' и capacite = 12, тогда установите diametre = '12.5' (код ниже).

Конечно, это строка diametre из той же строки, что и запрос на обновление.

Кроме того, я знаю, что должен использовать тип character varying вместо типа integer, но меня спросили, вот так.

Моя триггерная функция:

create or replace function maj_diam() returns trigger
as
$$
Declare fab_loc character varying;
Declare section_loc character varying;
Declare capa_loc character varying;
Declare modulo_loc character varying;

BEGIN
    Select fabricant into fab_loc from support_fh where id = new.id;
    Select section into section_loc from support_fh where id = new.id;
    Select capcite into capa_loc from support_fh where id = new.id;
    Select modulo into modulo_loc from support_fh where id = new.id;

    if fab_loc = 'NEXANS' and section_loc = 'DISTRIBUTION'
       and capa_loc = '12' and modulo_loc = '6' then
        update support_fh set diametre = '12.2' where id = new.id;
    endif;

    return new;
end;
$$;

Мой триггер:

create trigger maj_diam
After update on support_fh
for each row
execute procedure maj_diam();

Мой запрос на обновление для проверки моего триггера:

update support_fh set fabricant = 'NEXANS', section = 'DISTRIBUTION', capacite = '12', modulo = '6' 
where id = 11827;

Я хочу извлечь уроки из этого, поэтому, если возможно, объясните мне, что я делаю здесь неправильно, или, если в моем подходе не хватает понимания.

Ответы [ 2 ]

2 голосов
/ 09 апреля 2019

Вы получаете эту проблему, потому что обновление в триггере снова запустит триггер, вызывая бесконечный цикл.Никакое значение max_stack_depth не достаточно велико для этого (и слишком большое увеличение этого значения в любом случае опасно).

Вместо того, что вы делаете, вы должны создать триггер BEFORE и изменить NEWзначение, которое должно быть вставлено:

IF NEW.fab_loc = 'NEXANS' AND NEW.section_loc = 'DISTRIBUTION'
   AND NEW.capa_loc = '12' AND NEW.modulo_loc = '6'
THEN
   NEW.diametre := '12.2';
END IF;
1 голос
/ 09 апреля 2019

Если вы хотите изменить столбцы в строке, которая обновлена ​​(или вставлена), не используйте UPDATE в функции триггера. Объявите триггер как BEFORE UPDATE, а затем просто присвойте новые значения.

Вам также не нужны четыре оператора select для чтения четырех столбцов из одной таблицы.

Но поскольку вы обращаетесь только к столбцам из той же строки, которая была обновлена, вам даже не нужен SELECT.

Таким образом, ваша функция триггера может быть упрощена до:

create or replace function maj_diam() returns trigger
as
$$
BEGIN
   if new.fabricant = 'NEXANS' 
      and new.section = 'DISTRIBUTION' 
      and new.capcite = '12' 
      and new.modulo = '6' 
   then
     new.diametre := '12.2';
   end if;
   return new;
end;
$$;

Предполагая, что capcite, modulo и diametre на самом деле являются числами, вы не должны сравнивать их со значениями varchar. Таким образом, приведенный выше код, вероятно, должен быть: new.diametre := 12.2; или new.capcite = 12.

И определение триггера необходимо изменить на:

create trigger maj_diam
BEFORE update on support_fh
for each row
execute procedure maj_diam();
...