一般に、引用符は2倍にすることでエスケープされます。
変数をSQL文字列に連結するには、quote_literal()
を使用する必要があります -その関数は、一重引用符を適切にエスケープします(例:
quote_literal(temp_row.row_data)
そうは言っても、より良い(そしてより安全な)解決策は、format()
と組み合わせたパラメーターを使用することです。 :
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', tg_table_name)
using temp_row.action_tstamp_tx, temp_row.action, temp_row.row_data;
%I
プレースホルダーは通常、識別子を適切にエスケープしますが、この場合は機能しません。非標準のテーブル名でも正しく機能することを100%確認したい場合は、最初にターゲットテーブル名を変数に入れ、それをformat()
に使用する必要があります。 機能:
l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
この部分:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
最初の行の後も失敗します。 execute .. into ...
クエリがシングルを返すことを期待します 。使用しているステートメントはすべてを返します 履歴テーブルの行。
そもそもなぜそうするのかもわかりません。
履歴テーブルから選択する必要はまったくありません。
このようなもので十分です(未テスト! ):
IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN
temp_row := OLD;
ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN
temp_row := OLD;
ELSIF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN
temp_row := NEW;
ELSE
RAISE EXCEPTION '[audit.if_modified] - Trigger func added as trigger for unhandled case: %, %',TG_OP, TG_LEVEL;
RETURN NULL;
END IF;
execute format ('insert ... values ($1, $2, $3')
using now(), SUBSTRING(TG_OP,1,1), temp_row;
最後に、監査トリガーは以前に作成されており、これに対する既成のソリューションがたくさんあります: