コードの変更を避け、関数がエラー時に返されるようにしたい場合は、ブロックをNULL
使用してエラーをトラップするPL/PgSQL関数でそれらをラップすることでこれを行うことができます。BEGIN ... EXCEPTION
これを行うには、最初にエラーのSQLSTATEを取得します。
regress=# \set VERBOSITY verbose
regress=# SELECT pgp_sym_decrypt('fred','key');
ERROR: 39000: Wrong key or corrupt data
LOCATION: decrypt_internal, pgp-pgsql.c:607
これはエラーハンドラーで直接使用できますが、シンボリック名を使用することを好むため、付録A-エラーコードで39000に関連付けられているエラー名を調べて、それが総称関数呼び出しエラーであることを確認しますexternal_routine_invocation_exception
。私たちが望んでいたほど具体的ではありませんが、それは可能です。
ここで、ラッパー関数が必要です。このようなものを定義する必要があります。サポートするオーバーロードされた署名ごとに1つの関数を使用pgp_sym_decrypt
します。(bytea,text)
を返すフォームの場合、たとえば、次のようになりますtext
。
CREATE OR REPLACE FUNCTION pgp_sym_decrypt_null_on_err(data bytea, psw text) RETURNS text AS $$
BEGIN
RETURN pgp_sym_decrypt(data, psw);
EXCEPTION
WHEN external_routine_invocation_exception THEN
RAISE DEBUG USING
MESSAGE = format('Decryption failed: SQLSTATE %s, Msg: %s',
SQLSTATE,SQLERRM),
HINT = 'pgp_sym_encrypt(...) failed; check your key',
ERRCODE = 'external_routine_invocation_exception';
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
DEBUG
レベルメッセージで元のエラーを保存することを選択しました。これは、元のラッパーとラッパーの比較であり、完全なメッセージの詳細度とデバッグレベルの出力が含まれています。
デバッグ出力を有効にして、を表示しRAISE
ます。pgp_decrypt_sym
パラメータを含む、呼び出しの*元のクエリテキストも表示されることに注意してください。
regress=# SET client_min_messages = DEBUG;
詳細なロギングが有効になっている場合でも、新しいラップされた関数はエラーを報告しますが、以下を返しますNULL
。
regress=# SELECT pgp_sym_decrypt_null_on_err('redsdfsfdsfd','bobsdf');
LOG: 00000: statement: SELECT pgp_sym_decrypt_null_on_err('redsdfsfdsfd','bobsdf');
LOCATION: exec_simple_query, postgres.c:860
DEBUG: 39000: Decryption failed: SQLSTATE 39000, Msg: Wrong key or corrupt data
HINT: pgp_sym_encrypt(...) failed; check your key
LOCATION: exec_stmt_raise, pl_exec.c:2806
pgp_sym_decrypt_null_on_err
-----------------------------
(1 row)
失敗するオリジナルと比較して:
regress=# SELECT pgp_sym_decrypt('redsdfsfdsfd','bobsdf');
LOG: 00000: statement: SELECT pgp_sym_decrypt('redsdfsfdsfd','bobsdf');
LOCATION: exec_simple_query, postgres.c:860
ERROR: 39000: Wrong key or corrupt data
LOCATION: decrypt_internal, pgp-pgsql.c:607
どちらの形式も、関数が失敗したときに呼び出されたパラメーターを示していることに注意してください。バインドパラメータ(「プリペアドステートメント」)を使用した場合、パラメータは表示されませんが、データベース内暗号化を使用している場合は、ログがセキュリティ上重要であると見なす必要があります。
個人的には、アプリで暗号化を行う方が良いと思います。そのため、DBはキーにアクセスできません。