行を削除して、効果をロールバックすることができます。例外が発生すると、データベースへの永続化されたすべての変更がキャンセルされるため、トリガー関数でこれを行うことは望ましくありません。マニュアル:
エラーが句によってキャッチされるEXCEPTION
と、PL/pgSQL 関数のローカル変数はエラーが発生したときのままになりますが、ブロック内の永続的なデータベース状態へのすべての変更はロールバックされます。
大胆強調鉱山。
ただし、これを別のブロックまたは別のplpgsql 関数にラップし、そこで例外をキャッチして、メイン (トリガー) 関数への影響を防ぐことができます。
CREATE OR REPLACE FUNCTION f_can_del(_id int)
RETURNS boolean AS
$func$
BEGIN
DELETE FROM master WHERE master_id = _id; -- DELETE is always rolled back
IF NOT FOUND THEN
RETURN NULL; -- ID not found, return NULL
END IF;
RAISE SQLSTATE 'MYERR'; -- If DELETE, raise custom exception
EXCEPTION
WHEN FOREIGN_KEY_VIOLATION THEN
RETURN FALSE;
WHEN SQLSTATE 'MYERR' THEN
RETURN TRUE;
-- other exceptions are propagated as usual
END
$func$ LANGUAGE plpgsql;
これはTRUE
/ FALSE
/NULL
行が削除できる / 削除できない / 存在しないことを示します。
ここでdb<>fiddle
古いsqlfiddle
この関数を動的にして、テーブル/列/値を簡単にテストできます。
PostgreSQL 9.2以降では、どのテーブルがブロックされていたかを報告することもできます。
PostgreSQL 9.3以降では、さらに詳細な情報が提供されます。
任意のテーブル、列、および型のジェネリック関数
コメントに投稿した動的関数の試行が失敗したのはなぜですか? マニュアルからのこの引用は手がかりを与えるはずです:
EXECUTE
特に、 の出力は変更されますがGET DIAGNOSTICS
、 は変更されないことに注意してくださいFOUND
。
それはで動作しGET DIAGNOSTICS
ます:
CREATE OR REPLACE FUNCTION f_can_del(_tbl regclass, _col text, _id int)
RETURNS boolean AS
$func$
DECLARE
_ct int; -- to receive count of deleted rows
BEGIN
EXECUTE format('DELETE FROM %s WHERE %I = $1', _tbl, _col)
USING _id; -- exception if other rows depend
GET DIAGNOSTICS _ct = ROW_COUNT;
IF _ct > 0 THEN
RAISE SQLSTATE 'MYERR'; -- If DELETE, raise custom exception
ELSE
RETURN NULL; -- ID not found, return NULL
END IF;
EXCEPTION
WHEN FOREIGN_KEY_VIOLATION THEN
RETURN FALSE;
WHEN SQLSTATE 'MYERR' THEN
RETURN TRUE;
-- other exceptions are propagated as usual
END
$func$ LANGUAGE plpgsql;
ここでdb<>fiddle
古いsqlfiddle
その間、列のデータ型を含めて完全に動的にしました(もちろん、指定された列と一致する必要があります)。そのためにポリモーフィック型anyelement
を使用しています。見る:
SQLi から保護するためformat()
に、型のパラメーターも使用します。regclass
見る: