例えば、学生の平均点を計算する関数を書いてるとしよう。もし点数がなかったら(つまりゼロで割ろうとしたら)どうなる?そんなコードを本番に出したら、思わぬエラーがすぐにやってくるよね。PL/pgSQLには、こういうエラーをしっかり処理できる強力なツールがあるから、コードが頑丈で安全、しかも扱いやすくなるんだ。
PL/pgSQLのエラー処理でできること:
- 何がダメだったのか説明するメッセージを出せる。
- 致命的なエラーのときはコードの実行を止められる。
- 問題をログに残して、あとで分析できる。
PL/pgSQLの主なメッセージレベル
PL/pgSQLにはいくつかのメッセージレベルがあって、開発者が問題を効率よく見つけて直せるようになってる。こんな感じ:
- NOTICE: 情報メッセージを出す。デバッグ用に使うよ。
- WARNING: プログラムの実行は止まらないけど、何か問題がありそうなときの通知。
- EXCEPTION: プログラムの実行を止める致命的なエラー(呼び出し元に制御が戻る)。
PL/pgSQLのメッセージレベル一覧
| メッセージレベル | 説明 |
|---|---|
NOTICE |
情報やデバッグ用メッセージ。実行には影響しない |
WARNING |
問題がありそうなときの警告。ヒントとして使う |
EXCEPTION |
プログラムの実行を止める重大なエラー |
RAISEコマンドの構文
メッセージを出したりエラーを処理したりするにはRAISE文を使うよ。基本の構文はこれ:
RAISE <メッセージレベル> 'メッセージテキスト' [, 変数...];
<メッセージレベル>—NOTICE,WARNING,EXCEPTIONのどれか。'メッセージテキスト'— 問題の説明。[変数...]— メッセージテキストに埋め込む追加の値。
例1: RAISE NOTICEの使い方
関数の中で何が起きてるか知りたいときってあるよね。例えばループのデバッグ:
DO $$
BEGIN
FOR i IN 1..5 LOOP
RAISE NOTICE '今のiの値: %', i;
END LOOP;
END
$$;
結果: コンソールに今のiの値: 1、今のiの値: 2…5まで出力されるよ。
例2: RAISE EXCEPTIONの使い方
今度は、特定の条件でエラーを出して関数を終了させたい場合:
DO $$
BEGIN
IF 1 = 1 THEN
RAISE EXCEPTION '何かおかしいぞ!';
END IF;
END
$$;
結果: 実行が止まって、エラーメッセージがコンソールに出る。
RAISEでパラメータを使う
パラメータを使えば、メッセージテキストをカスタマイズできる。%のプレースホルダーを使うよ:
例3: RAISEに変数を埋め込む
DO $$
DECLARE
student_name TEXT := 'イワン';
average_score NUMERIC := NULL;
BEGIN
IF average_score IS NULL THEN
RAISE EXCEPTION '学生 % の平均点がないよ!', student_name;
END IF;
END
$$;
結果: 学生 イワン の平均点がないよ!というメッセージ。
こんな感じで、%がstudent_nameの値に置き換わるから、メッセージが分かりやすくなるね。
カスタムエラーの生成
エラーって、トラブルだけじゃなくて、わざと作ってコードを守るためにも使うんだ。
例4: 入力値のチェック
数値の入力値をチェックして、マイナスだったらエラーを出す関数を書いてみよう:
CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
IF value < 0 THEN
RAISE EXCEPTION '数値 % はマイナスだよ!', value;
END IF;
RETURN '数値はOK。';
END;
$$ LANGUAGE plpgsql;
この関数をテストしてみる:
SELECT check_positive(-5);
結果: 数値 -5 はマイナスだよ!というエラー。
もしプラスの値を渡したら:
SELECT check_positive(10);
結果: 数値はOK。
コンテキストでのエラー処理
エラーを発生させるだけじゃなくて、状況に応じて処理できたらもっといいよね。そのためにBEGIN ... EXCEPTIONブロックを使うんだ。
エラー処理の構造
BEGIN
-- メインのコード
EXCEPTION
WHEN エラータイプ THEN
-- エラーのときの処理
WHEN 別のエラー THEN
-- 別のエラーのときの処理
WHEN OTHERS THEN
-- その他すべてのエラーの処理
END;
各パーツの意味:
EXCEPTION— エラー処理ブロックの始まりを示すキーワード。WHEN— 例えばunique_violationやdivision_by_zeroみたいに、特定のエラータイプを指定できる。OTHERS—WHENで指定してないすべてのエラーを処理するのに使う。
例5: ゼロ除算のエラー処理
簡単な割り算関数でエラー処理を見てみよう:
CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
-- 割り算を試す
RETURN a / b;
EXCEPTION
WHEN division_by_zero THEN
RAISE WARNING 'ゼロで割ろうとしたよ。NULLを返すね。';
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
この関数をテスト:
SELECT safe_divide(10, 2); -- 期待される結果: 5
SELECT safe_divide(10, 0); -- 期待される結果: NULLとコンソールに警告
RAISEを使うときのよくあるミス
メッセージレベルの指定忘れ。 レベルを指定しないと、PostgreSQLがエラーを出すよ。
ダメな例:
RAISE 'レベルなしのメッセージ';
正しい例:
RAISE NOTICE 'NOTICEレベルのメッセージ';
パラメータの数が合ってない。 %を使うなら、ちゃんと必要な数だけ変数を渡そう。
ダメな例:
RAISE NOTICE 'パラメータ付きの例 %';
正しい例:
RAISE NOTICE 'パラメータ付きの例 %', '値';
やりすぎ。 RAISE EXCEPTIONを多用しすぎると、大事な処理まで止まっちゃう。使いどころは考えてね。
お役立ちヒント
WHEN OTHERSブロックには注意。 できるだけ具体的なエラーを指定して、他のエラーを間違ってキャッチしないようにしよう。RAISEはデバッグにも使える。 エラーは絶対に放置しないでね。- パフォーマンスも忘れずに。 エラー処理は特に大きなプロシージャだとコストがかかることもあるよ。
ここまでちゃんとできれば、君のプロシージャはどんな予期せぬトラブルにも耐えられるはず。PMもきっと君を誇りに思うよ!
GO TO FULL VERSION