Меню

Ошибка превышен предел глубины стека postgres

Ваш триггер срабатывает на событие BEFORE UPDATE, а внутри него происходит еще один update, который снова вызывает этот триггер, что приводит к бесконечной рекурсии.

Также немного странным выглядит само обновление:

UPDATE trips set all_sum_column = summ;

Вы действительно хотите обновить all_sum_column всех записей таблицы на одно и тоже значение при обновлении одной из них?

Я полагаю, что это просто ошибка в коде (потому что при подсчете суммы вы учитываеете только текущую запись trips.id_route = routes.id_route), и вы хотите обновить только текущую запись из tips. В таком случае необходимо обновлять не через update, а используя специальное ключевое слово, доступное внутри триггера — NEW (оно представляет собой новую версию обновляемой строки, также есть OLD — предыдущая версия соответственно):

NEW.all_sum_column = summ;

Это не вызовет последующего выполнения триггера еще раз.

Триггер будет выглядеть так:

create or replace function month_sum_update1() returns trigger as
$BODY$
DECLARE
    summ int;
BEGIN
    select sum(quantity*price) into summ from trips, routes
    WHERE routes.id_route = NEW.id_route
      AND (date_travel<=now() AND date_travel>=now()-interval '1 month');
    NEW.all_sum_column = summ;
    return NEW;
END;
$BODY$
    language plpgsql;

Больше о триггерах в официальной документации.

Я пытаюсь создать триггер, когда после вставки рисунка я хочу вставить его в таблицу In_Gallery или On_Loan, но не в обе. Когда я пытался создать функцию триггера, я продолжал получать сообщение об ошибке:

ERROR: stack depth limit exceeded
HINT:  Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.

Я не уверен, что с этим не так:

    CREATE OR REPLACE FUNCTION checkOnLoan()    
    RETURNS trigger AS
$$
    DECLARE    
       countGal numeric;
    BEGIN
            SELECT COUNT(*) INTO countGal FROM IN_GALLERY WHERE P_id = new.P_id;
            IF countGal = 0 THEN    
                INSERT INTO ON_LOAN VALUES (new.Certid, new.P_id, new.Insurer);
            ELSE
                RAISE EXCEPTION 'ALREADY IN GALLERY';
            END IF;
    RETURN new;
    END;
$$

LANGUAGE 'plpgsql';

CREATE TRIGGER OnLoan
    AFTER INSERT ON ON_LOAN
    FOR EACH ROW
    EXECUTE PROCEDURE checkOnLoan();

2 ответа

Непосредственной причиной вашей ошибки является бесконечный цикл, подобный объясненному в настоящее время принятому ответу. Но вы должны, вероятно, исправить больше, чем просто это. Триггер BEFORE улучшит ситуацию …

Функция запуска:

CREATE OR REPLACE FUNCTION check_onloan()
  RETURNS trigger AS
$$
BEGIN
   IF EXISTS (SELECT FROM in_gallery WHERE p_id = NEW.p_id) THEN
      RAISE EXCEPTION 'p_id % already in gallery!', NEW.p_id;
   END IF;
   RETURN NEW;  -- for BEFORE trigger
END
$$  LANGUAGE plpgsql;

Курок:

CREATE TRIGGER insert_after_on_loan
BEFORE INSERT ON on_loan             -- !!!
FOR EACH ROW EXECUTE PROCEDURE check_onloan();

RETURN NEW не имеет никакого смысла вообще для триггера AFTER. Руководство:

Возвращаемое значение игнорируется для триггеров уровня строки, запускаемых после операции, и поэтому они могут возвращать NULL.

Мое обоснованное предположение: вам нужен триггер BEFORE. Осталось только сделать исключение. Дешевле проверить перед выполнением работы, чем откатить ее позже. Для этой цели обычно эффективнее проверять существование с помощью IF EXISTS ..., а не подсчитывать. Тогда вам не нужно определять какие-либо переменные и нет DECLARE раздела.

Связанный:

  • PL / pgSQL проверяет, существует ли строка

  • Откат транзакции при ошибке запуска

Очевидно, вам нужен еще один зеркальный триггер для таблицы in_gallery в этом дизайне — который, вероятно, не идеален для начала.

Как бы вы это ни делали, будет оставшееся состояние гонки . При одновременной загрузке записи несколько транзакций могут попытаться ввести один и тот же p_id в обе таблицы практически в одно и то же время, но пока не увидеть p_id в таблице other , и введите его в обе таблицы. Это помогает держать транзакции короткими, чтобы минимизировать временные рамки, но проблема остается в принципе.

Одним чистым решением будет одна таблица painting с флагом boolean, указывающей ее статус. Это может иметь только одно состояние за раз. Детали зависят от вашей полной ситуации …

В стороне: пересмотреть регистр написания идентификаторов в CaMeL в Postgres.

  • Имена столбцов PostgreSQL чувствительны к регистру?


1

Erwin Brandstetter
2 Дек 2019 в 02:04

Вы снова INSERT в триггере AFTER INSERT, вызывая повторный запуск триггера в течение этой секунды INSERT, который снова INSERT запускает и запускает триггер заново, и так далее, и так далее , В какой-то момент стек исчерпан всеми вызовами этой функции, и вы получите ошибку.

Удалите INSERT из функций триггера и просто RETURN new. Возвращение new приведет к завершению оригинала INSERT. Для триггеров AFTER INSERT нет необходимости вручную INSERT в функции триггера.

Как:

CREATE OR REPLACE FUNCTION checkOnLoan()    
RETURNS trigger AS
$$
DECLARE    
    countGal numeric;
BEGIN
    SELECT COUNT(*) INTO countGal FROM IN_GALLERY WHERE P_id = new.P_id;
    IF countGal = 0 THEN    
        RETURN new;
    ELSE
        RAISE EXCEPTION 'ALREADY IN GALLERY';
    END IF;
END;
$$
LANGUAGE plpgsql;

И аналог для другой триггерной функции.


3

sticky bit
30 Ноя 2019 в 00:49

Хорошо, если вы действительно хотите, чтобы триггер обновлялся, что вы могли бы сделать, чтобы установить этот триггер как специфичный для столбца, чтобы он не запускался при обновлении до all_books, что вызывает вашу рекурсию. Что-то вроде этого —

create trigger total2
after update of copy_id
on totalbooks
for each row
execute procedure total1();

Конечно, вы можете изменить, какие столбцы запускают функцию, я просто выбрал copy_id потому что это то, что вы считаете.

ОДНАКО

Если вы обновляете с помощью count() результат, вы можете просто включить триггер INSERT и DELETE действия. Таким образом, триггер будет срабатывать при изменении счетчика, но сам не будет срабатывать при обновлении. // РЕДАКТИРОВАТЬ: так как ваш sum это всего лишь подсчет всех записей в copies, он изменится только при вставке или обновлении записи, поэтому запуск этого триггера при обновлении в любом случае не имеет смысла.

РЕДАКТИРОВАТЬ: я подумал, что было бы полезно добавить ссылку на СОЗДАТЬ ТРИГГЕР Документация. См. раздел с пометкой «событие», потому что в нем подробно описано, как указывать столбцы в событии.

РЕДАКТИРОВАТЬ ДЛЯ НОВОЙ ИНФОРМАЦИИ:

Учитывая то, что вам нужно выполнить, я думаю, вам нужно переосмыслить свой дизайн данных, я предлагаю вам использовать отношения родитель-потомок (каждый раз, когда вы кэшируете общие данные во многих строках в таблице, потому что они имеют что-то общее, что является признаком того, что вам может понадобиться родительская таблица).

Иметь books таблица, где каждая строка содержит информацию об одной книге (название, автор и т. д.), а затем copies таблица, в которой каждая строка содержит информацию об одной копии книги (серийный номер, дата последнего извлечения и т. д.).

Таким образом, получить количество копий так же просто, как SELECT COUNT(*) FROM copies WHERE book_id=[some book id].

Если вы действительно хотите где-то кэшировать счетчик, сделайте это на books таблице.

Создать INSERT OR UPDATE запускать copies это делает UPDATE books SET copy_count=(SELECT COUNT(*) FROM copies WHERE book_id=NEW.book_id) WHERE id=NEW.book_id.

Затем создайте DELETE триггер на копиях, которые делают UPDATE books SET copy_count=(SELECT COUNT(*) FROM copies WHERE book_id=OLD.book_id) WHERE id=OLD.book_id

Причина двух триггеров заключается в том, что NEW переменная доступна только в INSERT or UPDATE триггеры и OLD доступно только в DELETE триггеры. Вы могли бы сделать все это как один триггер, но для этого потребуется больше кода, чем я хотел бы разместить здесь.

Убедитесь, что все ваши триггеры AFTER триггеры, иначе новая вставленная/удаленная строка не будет учитываться при подсчете.

Я stack depth limit exceeded при попытке сохранить строку из R в PostgreSQL. Чтобы решить проблему с массовыми upserts, я использовал такой запрос:

sql_query_data <- sprintf("BEGIN;
CREATE TEMPORARY TABLE
ts_updates(ts_key varchar, ts_data hstore, ts_frequency integer) ON COMMIT DROP;
INSERT INTO ts_updates(ts_key, ts_data) VALUES %s;
LOCK TABLE %s.timeseries_main IN EXCLUSIVE MODE;

UPDATE %s.timeseries_main
SET ts_data = ts_updates.ts_data,
ts_frequency = ts_updates.ts_frequency
FROM ts_updates
WHERE ts_updates.ts_key = %s.timeseries_main.ts_key;

INSERT INTO %s.timeseries_main
SELECT ts_updates.ts_key, ts_updates.ts_data, ts_updates.ts_frequency
FROM ts_updates
LEFT OUTER JOIN %s.timeseries_main ON (%s.timeseries_main.ts_key = ts_updates.ts_key)
WHERE %s.timeseries_main.ts_key IS NULL;
COMMIT;",
values, schema, schema, schema, schema, schema, schema, schema)

}

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

Однако сейчас эта стратегия сталкивается с некоторыми проблемами. У меня больше нет записей, но несколько, в которых hstore немного больше. Но это действительно не «большой». Я читаю предложения @Craig Ringer, который советует не приближаться к пределу 1 ГБ. Поэтому я предполагаю, что размер самого hstore не является проблемой, но я получаю это сообщение:

Error in postgresqlExecStatement(conn, statement,...): RS-DBI driver: (could not Retrieve the result: ERROR: stack depth limit exceeded HINT: Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform stack depth limit is adequate. )

EDIT: я увеличил лимит до 7 МБ и столкнулся с той же ошибкой, что и 7 МБ. Это действительно странно для меня, потому что я сам запрос составляет всего 1,7 МБ (проверял его, вставляя его в текстовый файл). Может ли кто-нибудь пролить свет на это?

38 / 33 / 12

Регистрация: 31.05.2012

Сообщений: 586

1

02.08.2017, 16:09. Показов 4110. Ответов 5


всем привет! Создал тригер для инсерта и в результате вставки выдает ошибку

[54001] ERROR: stack depth limit exceeded Подсказка: Increase the configuration parameter «max_stack_depth» (currently 2048kB), after ensuring the platform’s stack depth limit is adequate. Где: SQL statement «SELECT 1 FROM ONLY «public».»posts» x WHERE «id» OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x» SQL statement «INSERT INTO public.post_content (htmlcode, type, post_id) VALUES (NEW.htmlcode, NEW.type, 37)» PL/pgSQL function increment_type_of_post_content() line 4 at SQL statem …
Details

Может кто подсказать чего он хочет?

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



4719 / 3927 / 994

Регистрация: 29.08.2013

Сообщений: 25,181

Записей в блоге: 3

02.08.2017, 16:55

2

СУБД нужно угадать?



0



38 / 33 / 12

Регистрация: 31.05.2012

Сообщений: 586

02.08.2017, 18:24

 [ТС]

3

Цитата
Сообщение от qwertehok
Посмотреть сообщение

СУБД нужно угадать?

postgres



0



4719 / 3927 / 994

Регистрация: 29.08.2013

Сообщений: 25,181

Записей в блоге: 3

02.08.2017, 18:48

4

Цитата
Сообщение от Левиафам
Посмотреть сообщение

Подсказка: Increase the configuration parameter «max_stack_depth» (currently 2048kB), after ensuring the platform’s stack depth limit is adequate

читали?



0



38 / 33 / 12

Регистрация: 31.05.2012

Сообщений: 586

02.08.2017, 23:49

 [ТС]

5

Цитата
Сообщение от qwertehok
Посмотреть сообщение

читали?

ну это как-то странно что превышает 2 метра, может я что-то не так делаю….



0



1184 / 914 / 367

Регистрация: 02.09.2012

Сообщений: 2,785

03.08.2017, 04:54

6

Цитата
Сообщение от Левиафам
Посмотреть сообщение

может я что-то не так делаю…

Покажите тогда хотя бы код триггера, триггерной функции, ну и самого SQL-выражения, которое приводит к срабатыванию триггера.



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

03.08.2017, 04:54

6

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Ошибка при xslt преобразовании ошибка преобразования xslt
  • Ошибка построения диалога подписания jinn client