1

PostgreSQL サーバー バージョン 9 から8.4に移行した後、非常に奇妙なエラーが発生しました。

簡単な説明:挿入または更新の前に
各行の特定のテーブルにトリガーがあり、条件ステートメント (if-else) で TG_OP 値チェックとOLDオブジェクトを使用する場合、 INSERTを実行すると次のエラーが発生します。

ERROR:  record "old" is not assigned yet
DETAIL:  The tuple structure of a not-yet-assigned record is indeterminate.

詳細な説明:
次の DB 構造があります。

CREATE TABLE table1
(
  id serial NOT NULL,
  name character varying(256),
  CONSTRAINT table1_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);

CREATE OR REPLACE FUNCTION exemplary_function()
RETURNS trigger AS
$BODY$    BEGIN
IF TG_OP = 'INSERT' OR OLD.name <> NEW.name THEN
    NEW.name = 'someName';
    END IF;

RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;

CREATE TRIGGER trigger1
  BEFORE INSERT OR UPDATE
  ON table1
FOR EACH ROW EXECUTE PROCEDURE exemplary_function();

エラーをトリガーする次のSQLクエリ:

INSERT INTO table1 (name) VALUES ('other name')

パーサーが条件付きで停止していないように見えTG_OP = 'INSERT'ますが (それは true であるため停止する必要があります)、別のパーサーをチェックするとエラーが発生します。興味深いことに、バージョン 8.4 でしか再現できませんでした。

4

1 に答える 1

1

Postgres は正式にはブール文のショートカットを行いません (たとえば C とは異なります)。

ショートカットを決定できる場合があるとは言っていますが(docsを参照)、最初の式ではなく2番目の式を簡単にショートカットすることを決定する場合があります。

評価順を決める前に、基本的に各辺の式がどれだけ複雑かを見ていきます。それが TRUE の場合、反対側に迷惑をかけないことを決定できます。

OLDこの場合、式を評価するための最良の順序を決定しようとしている間に、解釈しようとしているように見えます。

CASE を使用して式を分割することで、これを回避できるはずです。

IF (CASE WHEN TG_OP = 'INSERT' THEN TRUE ELSE OLD.name <> NEW.name END) THEN
于 2013-05-08T16:39:43.380 に答える