web-dev-qa-db-ja.com

postgresqlのmax_stack_depthエラー

私はPostgreSQLを初めて使用するので、ヘルプや推奨事項をいただければ幸いです。

次の関数を実行してテーブルを更新しています:

$BODY$
  DECLARE
    commercial_period date := (SELECT periods.period FROM common.periods WHERE periods.type = 'commercial');
   --period text := concat('_',right((date_part('year',residential_period))::text,2),'_',right((date_part('year',residential_period))::text,2)::integer+1);
  BEGIN
-------------------------------------------------------------------------------------------------------------
    --copies alternative data from temporal table to common.status
    UPDATE
      common.status
    SET
      implementation_status = A.implementation_status,
      latest_version = A.latest_version
    FROM
      monitoring_commercial_temporal.possible_alternatives AS A
    WHERE
      status.reference = A.reference
      AND (status.update_period = A.update_period
      OR status.update_period IS NULL);
-------------------------------------------------------------------------------------------------------------
    --sets as lastest version any site, not in the temporal list of alternatives
    UPDATE
      common.status
    SET
      latest_version = 'yes'
    WHERE
      (reference, update_period) NOT IN (SELECT reference, update_period FROM monitoring_commercial_temporal.possible_alternatives)
      AND update_period = commercial_period + interval '1 year'
      AND implementation_status <> 'non-preferred alternative'
      AND latest_version IS NULL;
-------------------------------------------------------------------------------------------------------------
   END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION public.monitoring_update_alternatives_commercial()
  OWNER TO postgres;

しかし、私は次のエラーを受け取ります:

エラー:スタックの深さの制限を超えていますヒント:プラットフォームのスタックの深さの制限が適切であることを確認した後、構成パラメーター "max_stack_depth"(現在は2048kB)を増やしてください。

> CONTEXT:  SQL function "st_intersects" during inlining SQL statement
> "SELECT (SELECT 
>                                     array_agg(status.reference) 
>                                   FROM 
>                                     common.geometries AS A, 
>                                     common.geometries AS B, 
>                                     common.status,
>                                     common.permission_details 
>                                   WHERE 
>                                     NEW.reference = A.reference 
>                                     AND status.reference = B.reference 
>                                     AND status.reference = permission_details.app
>                                     AND NEW.reference <> status.reference
>                                     AND ST_Intersects(B.geom, A.geom)
>                                     AND (NEW.update_period = residential_period + INTERVAL '1 YEAR' OR NEW.update_period IS NULL)
>                                     AND status.update_period = residential_period + INTERVAL '1 YEAR'
>                                     AND permission_details.monitoring_type <> 'commercial'
>                                     AND (((ST_Area(ST_Intersection(B.geom, A.geom))+0.01) /
> (ST_Area(B.geom)+0.01) >= 0.2)
>                                     OR ((ST_Area(ST_Intersection(B.geom, A.geom))+0.01) /
> (ST_Area(A.geom)+0.01) >= 0.2)))" PL/pgSQL function
> monitoring_update_status_before() line 72 at assignment SQL statement
> "UPDATE 
>     common.status AS A   SET
>     trigger = TRUE   WHERE
>     A.latest_version = NEW.reference
>     AND A.update_period = NEW.update_period" PL/pgSQL function monitoring_update_status_after() line 5 at SQL statement

次に、UPDATEの最後の6行を繰り返します

1
Shohreh

おそらく、UPDATEでトリガーがトリガーされると、同じテーブルでUPDATEが実行され、それ自体がトリガーを起動します。スタックがいっぱいになり、スタックの深さの制限を超えたエラーが発生するまで、再帰的に繰り返されます。

これは問題を示す最小限の例です:

create table tst(id int primary key, col int, trigger boolean);

create function trg() returns trigger  as $$
 begin update tst set trigger=true where tst.id=NEW.id; return NEW; END
$$ language plpgsql;

create trigger t before update on tst for each row execute procedure trg();

insert into tst(id) values(1),(2);

update tst set col=1 where id=1;
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.
CONTEXT:  SQL statement "update tst set trigger=false where tst.id=NEW.id"
PL/pgSQL function trg() line 1 at SQL statement
SQL statement "update tst set trigger=false where tst.id=NEW.id"

上記のケースでの間違いは、トリガー内で既に更新されているテーブルのUPDATEを発行することです。正しい方法は、直接割り当てることですNEW.trigger、次のように:

create function trg() returns trigger  as
$$
 begin NEW.trigger=true; return NEW; END
$$ language plpgsql;
1
Daniel Vérité