すべてのプロダクト
Search
ドキュメントセンター

PolarDB:エラーとメッセージ

最終更新日:May 30, 2024

このトピックでは、PL/SQLのエラーとメッセージについて説明します。

レポートエラーとメッセージ

RAISEステートメントを使用して、メッセージを報告し、エラーを発生させることができます。

RAISE [レベル] 'format' [, 式 [, ... ]] [USING option = expression [, ... ] ];
    RAISE [レベル] condition_name [ USINGオプション=式 [, ... ] ];
    RAISE [レベル] SQLSTATE 'sqlstate' [ USING option = expression [, ... ] ] ];
    RAISE [レベル] USINGオプション=式 [, ... ];
    昇る; 

levelオプションは、エラーの重大度を指定します。 有効な値: DEBUGLOGINFONOTICEWARNINGEXCEPTION。 デフォルト値: EXCEPTIONEXCEPTIONレベルでは、エラーが発生し、通常、現在のトランザクションは中止されます。 他のレベルについては、異なる優先度のメッセージのみが生成される。 特定の優先度のメッセージがクライアントに報告されるか、サーバーログに書き込まれるか、またはその両方が、log_min_messagesおよびclient_min_messagesによって制御されます。

levelオプションの後にformat文字列を指定できます。 形式文字列は単純な文字列リテラルである必要があり、式にすることはできません。 フォーマット文字列は、報告されるエラーメッセージテキストを指定する。 フォーマット文字列の後には、メッセージに挿入されるオプションのパラメータ式が続く。 フォーマット文字列では、パーセント記号 (%) が次のオプションパラメーターの値に置き換えられます。 % % はリテラル % を表します。 パラメーターの数は、フォーマット文字列の % プレースホルダーの数と一致する必要があります。 それ以外の場合、関数のコンパイル中にエラーが発生します。

次の例では、文字列の %v_job_idパラメーターの値に置き換えられます。

RAISE NOTICE 'Calling cs_create_job(%)'、v_job_id;

1つ以上のoption=expression項目を含むUSING句を指定することで、エラーレポートに追加情報を添付できます。 は、任意の文字列値を生成する式です。 optionキーの有効値:

MESSAGE: エラーメッセージのテキストを設定します。 このオプションは、USING句の前に書式文字列を含むRAISEステートメントの形式では使用できません。

DETAIL: エラーの詳細を含むメッセージを提供します。

ヒント: ヒントを提供します。

ERRCODE: 報告するSQLSTATEエラーコードを指定します。

COLUMNCONSTRAINTDATATYPETABLE、またはSCHEMA: 関連するオブジェクトの名前を提供します。

次の例は、指定したエラーメッセージとヒントを使用してトランザクションを中止する方法を示しています。

RACEPTION「存在しないID-> % 」、user_id
          使用ヒント='ユーザーIDを確認してください'; 

次の例は、SQLSTATEコードを設定する2つの同等の方法を示しています。

RAISE 'Duplicate user ID: % '、user_id USING ERRCODE = 'unique_violation';
    RAISE '重複ユーザーID: %' 、user_id USING ERRCODE = '23505'; 

次の例は、RAISEステートメントの別の構文を示しています。 この構文では、メインパラメーターは条件名または報告するSQLSTATEコードです。

RAISE division_by_zero;
    RAISE SQLSTATE '22012'; 

この構文では、USING句を使用して、カスタムエラーメッセージ、詳細、またはヒントを提供できます。 前の例は、次の方法で書くこともできます。

RAISE unique_violation USUSING MESSAGE = 'Duplicate user ID: '| | user_id;

RAISE USINGまたはRAISE ''level' USINGバリアントを使用して、他のすべてをUSING句のリストに入れることもできます。

RAISEステートメントの最後のバリアントにはパラメーターがありません。 このバリアントは、BEGINブロックのEXCEPTION句内でのみ使用して、処理中のエラーを再度発生させることができます。

説明

以前のバージョンでは、パラメーターのないRAISEステートメントは、アクティブな例外ハンドラーを含むブロックからのエラーが再び発生することを示しています。 したがって、ハンドラー内にネストされたEXCEPTION句は、ネストされたEXCEPTION句のブロック内にRAISEステートメントがある場合でも、エラーをキャッチできません。 この動作は驚くべきことであり、OracleのPL/SQLと互換性がありません。

既定では、RAISE EXCEPTIONステートメントで条件名またはSQLSTATEコードを指定しない場合、ERRCODE_RAISE_EXCEPTIONまたはP0001が使用されます。 メッセージテキストを指定しない場合は、条件名またはSQLSTATEコードが使用されます。

SQLSTATEコードを指定する場合、定義済みのエラーコードに限定されません。 5桁または大文字のASCII文字で構成される任意のエラーコードを使用できます。 SQLSTATEコードを00000に設定することはできません。 3つのゼロで終わるエラーコードは使用しないことをお勧めします。 3つのゼロで終わるコードはカテゴリコードであり、カテゴリ全体をトラップすることによってのみトラップできます。

Checkアサーション

ASSERTステートメントを使用して、デバッグチェックをPL/SQL関数に簡単に挿入できます。

ASSERT condition [ , message ];

条件は、常にtrueに評価されると予想されるブール式です。 もしそうであれば、ASSERTステートメントはそれ以上何もしない。 結果がfalseまたはNULLの場合、ASSERT_FAILURE例外が発生します。 条件の評価中にエラーが発生した場合、一般的なエラーが報告されます。

オプションのメッセージが提供され、条件が失敗した場合、そのメッセージはエラーメッセージのデフォルトテキスト「アサーション失敗」を置き換える式として使用されます。 この場合、式の結果はNULLにすることはできません。 アサーションが成功する通常のケースでは、message式は評価されません。

plpgsql.check_assersパラメーターを設定することで、アサーションのテストを有効または無効にできます。 このパラメーターはブール値を取り、デフォルト値はonです。 このパラメーターがoffに設定されている場合、ASSERTステートメントは何もしません。

説明

ASSERT文は、プログラムのバグを検出するために使用されます。 一般的なエラーの報告には使用されません。 一般的なエラーを報告するには、RAISEステートメントを使用します。

例外

概要

例外はPL/SQLランタイムエラーです。 これらは、設計障害、コーディングミス、ハードウェア障害など、多くの理由で発生する可能性があります。 すべての潜在的な例外が予想されるわけではありませんが、例外が発生したときにプログラムを実行できるようにする例外ハンドラーを作成できます。 任意のPL/SQLブロックは、1つ以上の例外ハンドラからなる例外処理セクションを有することができる。 たとえば、次の構文を使用して例外処理セクションを指定できます。 ex_name_1フィールドは例外の名前を指定し、statements_nフィールドは1つ以上のステートメントを指定します。

DECLARE
  ...
BEGIN
  ...
EXCEPTION
  ex_name_1がstatements_1である場合
  ex_name_2またはex_name_3がstatements_2の場合
  他の人がstatements_3を超えたとき
エンド; 

BEGINブロックであるPL/SQLブロックの実行可能部分で例外が発生すると、実行可能部分は停止し、例外処理セクションが制御を引き継ぎます。 内部的には、PolarDBは例外コードに基づいて例外条件のトリガーを制御します。 各ex_name_nは、一意の例外コードをマッピングします。 ex_name_1が発生すると、statements_1が実行されます。 ex_name_2またはex_name_3が発生すると、statements_2が実行されます。 他の例外が発生した場合、statements_3が実行されます。 OTHERSキーワードは、他のすべての例外を示します。 OTHERSを指定せず、ex_name_nフィールドでトラップされない例外が発生した場合、例外はPL/SQLブロックの呼び出し元の例外処理セクションで発生し、処理されます。 PL/SQLブロックが例外を処理できない場合、例外は最終的に呼び出し元にスローされます。

例外ハンドラーは、よりわかりやすいプログラムを簡単に作成し、未処理の例外の発生を減らすのに役立ちます。 例外ハンドラーを使用しない場合は、例外が発生する可能性のあるすべての位置を確認し、例外を処理する必要があります。 潜在的な例外および例外が発生する可能性のある位置は、特に例外をすぐに検出できない場合に見落とされやすい。 たとえば、計算でデータを使用しない限り、不良データを検出することはできません。

例外ハンドラーを使用する場合、すべての例外と例外が発生する可能性のある位置を知る必要はありません。 例外処理セクションは、例外が発生する可能性のあるすべてのブロックでのみ構成する必要があります。 例外処理セクションには、特定の例外と未知の例外の両方の例外ハンドラが含まれます。 ブロックまたはそのサブブロックで例外が発生した場合、例外ハンドラが例外を処理します。 例外ハンドラのコードは、ブロックの例外処理セクションで分離されます。

内部例外

内部例外は、システムの実行中に発生する可能性がある内部で定義された例外です。 PolarDBは、一意の5文字コードを使用して各内部例外を表します。 内部例外にも一意の例外名があります。

たとえば、22012はdivision_by_zero例外を示し、2202Eはarray_subscript_error例外を示します。 次の例に示すように、ex_name_nフィールドを例外コードまたは例外名に設定することで、内部例外を指定できます。

例外
  sqlstate「22012」が終了したとき
    ...
  array_subscript_errorがあったとき
    ...

RAISEステートメントを使用して、内部例外を明示的に発生させることができます。

DECLARE
開始
  RAISE division_by_zero; -- divide_by_zero例外を明示的に発生させます。
EXCEPTION
  division_by_zeroがあったとき
    通知を上げる「例外をキャッチ! 」;
    RAISE; -例外を再度発生させます。 
エンド; 
説明

EXCEPTIONブロックを使用すると、パラメーターなしでRAISEステートメントを使用して、現在発生している例外を直接発生させることができます。 この特殊な構文は、EXCEPTIONブロックでのみ使用できます。

事前定義済み例外

PolarDBでは、各内部例外に例外名があります。 したがって、例外名を使用して内部例外をキャッチできます。 さらに、PolarDBは一部のOracle定義の例外と互換性があります。 次の表に、Oracle例外名とPolarDB例外名の間のマッピングを示します。

Oracle例外コード

Oracle例外名

PolarDB例外コード

PolarDB例外名

-6592

case_not_found

20000

case_not_found

-6531

collection_is_null

2203G

collection_is_null

-6511

cursor_already_open

42P03

duplicate_cursor

-1

dup_val_on_index

23505

unique_violation

-6533

subscript_beyond_count

2203H

subscript_beyond_count

-6532

subscript_outside_limit

2202E

array_subscript_error

-1422

too_many_rows

P0003

too_many_rows

-1476

zero_divide

22012

division_by_zero

説明

Oracleの例外名を使用して例外を処理できます。

ユーザー定義の例外

次の構文を使用して、カスタム例外を宣言できます。 次に、カスタム例外を発生させてキャッチできます。

<bx id="1" type="code" text="code id=" xd7sdq "title=" "uuid=" ljwbzhgth3ikb6m84na "code=" DECLARE
exception_name例外;
開始
RAISE exception_name;
例外
exception_nameがあったとき
RAISE NOTICE 'ユーザー定義の例外をキャッチ!';
上げる通知 '% : %' 、SQLCODE、SQLERRM;
END;"data-tag=" codeblock "outputclass=" language-plsql ""/>DECLARE
  exception_name例外;
開始
  RAISE exception_name;
例外
  exception_nameがあったとき
    RAISE NOTICE 'ユーザー定義の例外をキャッチ!';
    上げる通知 '% : %' 、SQLCODE、SQLERRM;
エンド; 

ユーザー定義の例外が例外コードにバインドされていない場合、例外は内部例外コードにバインドされます。 SQLCODEを使用して取得する例外コードは1で、SQLERRMを使用して取得する例外メッセージは ''User-Defined Exception' です。

特定の例外コードをユーザー定義の例外にバインドし、ユーザー定義の例外が発生したときに特定の例外メッセージをユーザー定義の例外に関連付ける場合は、次の構文を使用できます。

<bx id="1" type="code" text="code id=" ngywmg "title=" "uuid=" ljwc678lk6lumm0hdcq "code=" DECLARE
my_exception例外;
PRAGMA EXCEPTION_INIT (my_exception, -20001)
開始
RAISE_APPLICATION_ERROR(-20001, 'raise a special division by zero exception!')
例外
WHEN my_exception THEN -- WHEN zero_divide/division_by_zero THEN
上げる通知 '% : %' 、SQLCODE、SQLERRM;
END;"data-tag=" codeblock "outputclass=" language-plsql ""/>DECLARE
  my_exception例外;
  PRAGMA EXCEPTION_INIT (my_exception, -20001); -- 例外を例外コードにバインドします。
BEGIN
  RAISE_APPLICATION_ERROR(-20001、'ゼロで特別な除算を行う例外! '); -- 例外コードに基づいて例外を発生させ、例外メッセージを例外に関連付けます。
EXCEPTION
  WHEN my_exception THEN -- WHEN zero_divide/division_by_zero THEN
    上げる通知 '% : %' 、SQLCODE、SQLERRM;
エンド; 

実行結果:

注意: -20001: ゼロ例外による特別な除算を上げます!

次の構文を使用して、例外コードをユーザー定義の例外にバインドできます。 例外コードは、Oracleスタイルの負数である必要があります。

PRAGMA EXCEPTION_INIT (exception_name, error_code);

次に、RAISE_APPLICATION_ERRORプロシージャを使用して、例外コードに基づいて例外を発生させ、例外メッセージを例外に関連付けることができます。 例外コードの有効値:-20999への20000。

RAISE_APPLICATION_ERROR(error_code, 'raise a special exception! ');

定義済みの例外と同じ名前のユーザー定義の例外を作成した場合、定義した例外は定義済みの例外を上書きします。 PolarDBで定義済みの例外をオーバーライドしないことを推奨します。

<bx id="1" type="code" text="code id=" qg96ra "title=" "uuid=" lk0xynbxq7ty1g89qmj "code=" DECLARE
zero_divide例外;
開始
RAISE zero_divide;
例外
zero_divideがあったとき
昇格通知 '% %' 、sqlcode、sqlerrm;
END;"data-tag=" codeblock "outputclass=" language-plsql ""/>DECLARE
  zero_divide例外;
開始
  RAISE zero_divide;
例外 
  zero_divideがあったとき
    昇格通知 '% %' 、sqlcode、sqlerrm;
エンド; 

実行結果:

注意: 1ユーザー定義の例外

明示的に例外を発生させる

システムエラーが発生すると、システムは自動的に内部例外を発生します。 自動例外発生に加えて、次のサンプルコードに示すメソッドを使用して、例外を明示的に発生させることができます。

<bx id="1" type="code" text="code code=" DECLARE
my_exception例外;
開始
-
DECLARE
開始
RAISE my_exception; -- 1. 指定異状
例外
my_exceptionがあったとき
通知を上げる '内部の例外をキャッチ!';
レイズ;-2.
エンド;

例外
my_exceptionがあったとき
RAISE_APPLICATION_ERROR(-20000, 'raise a special exception!'); -- 3.
END;"id=" 0at0gl "title=" "uuid=" lk0yaz0b1slp1ur0osi "data-tag=" codeblock "outputclass=" language-plsql ""/>DECLARE
  my_exception例外;
開始
  -ネストされたブロック。
  DECLARE
  BEGIN
    RAISE my_exception; -- 1。 特定の例外を発生させます。
  EXCEPTION
    my_exceptionがあったとき
      通知を上げる '内部の例外をキャッチ!';
      昇格;-2。 現在の例外を上げます。
  エンド;

例外
  my_exceptionがあったとき
    RAISE_APPLICATION_ERROR (− 20000、'特別な例外を発生させる!'); − 3. RAISE_APPLICATION_ERRORプロシージャを使用して、指定された例外コードと例外メッセージで例外を発生させます。
エンド; 

実行結果:

<bx id="1" type="code" text="code id=" hiesfi "title=" "uuid=" lk0yek3pj94cj7q53y "code=" NOTICE: 内部例外をキャッチ!
エラー: 特別な例外を提起! data-tag="codeblock" outputclass="language-plsql" "/> 注意: 内部例外をキャッチ!
エラー: 特別な例外を提起! 

例外伝播

例外ハンドラーを含まないブロックで例外が発生した場合、ブロックが例外を処理するまで、例外は外部ブロックに伝播します。 例外を処理するブロックがない場合、PL/SQLは未処理の例外を呼び出し元またはホスト環境に返します。 例外がブロックによって処理される場合、外側ブロックの次のステートメントが実行されます。 外部ブロックが存在しない場合、システムは呼び出し元またはホスト環境に戻ります。

例外コードと例外メッセージの取得

例外がキャッチされない場合、コンソールまたは他の呼び出し元で例外メッセージを取得できますが、例外コードを取得することはできません。 例外がキャッチされた後、SQLCODEを使用して例外コードを取得し、SQLERRMを使用して例外メッセージを取得できます。例:

<bx id="1" type="code" text="code id=" 47yfmf "title=" "uuid=" lk0yqpsakx8c6ulci5 "code=" DECLARE
...
開始
...
例外
他の人がそこにいるとき
昇格通知 '% %' 、sqlcode、sqlerrm;
END;"data-tag=" codeblock "outputclass=" language-plsql ""/>DECLARE
  ...
BEGIN
  ...
EXCEPTION 
  WHEN OTHERS THEN
    昇格通知 '% %' 、sqlcode、sqlerrm;
エンド; 

トランザクションの動作

PL/SQLプログラムは常にトランザクションで実行されます。 EXCEPTIONブロックが存在する場合、PolarDBはBEGINブロック内のステートメントを実行するためのサブトランザクションを暗黙的に作成します。 BEGINブロックで例外が発生した場合、サブトランザクションはロールバックされ、exceptionブロックのステートメントを実行するために新しいサブトランザクションが作成されます。 EXCEPTIONブロック内のステートメントが正常に実行されると、サブトランザクションをコミットできます。 例:

<bx id="1" type="code" text="code id=" y1pphg "title=" "uuid=" lk0z1vtft0b7h2jht5 "code="-準備完了表
CREATE TABLEテスト (id INT);

-- BEGIN出異株、例外正常行
DECLARE
my_exception例外;
開始
テスト値に挿入 (1);
昇格my_exception;
例外
my_exceptionがあったとき
通知を上げる 'キャッチ!';
テスト値に挿入する (2) 。エンド;

-- 表
SELECT id FROM test;"data-tag=" codeblock "outputclass=" language-plsql ""/>-- テストテーブルを準備します。
CREATE TABLEテスト (id INT);

-- BEGINブロックで例外を発生させます。 EXCEPTIONブロック内のステートメントを実行できます。
DECLARE
  my_exception例外;
開始
  テスト値に挿入 (1);
  昇格my_exception;
例外
  my_exceptionがあったとき
    通知を上げる 'キャッチ!';
    テスト値に挿入する (2) 。エンド;

-- テーブルからデータを照会します。
SELECT idからテスト; 

実行結果:

<bx id="1" type="code" text="code id=" 2zi0yr "title=" "uuid=" lk0z5c840or11gk56iz "code=" NOTICE: catch!
やる
postgres=# select * from t;
id
----
2
(1行) "data-tag=" codeblock "outputclass=" language-plsql ""/>NOTICE: catch!
やる
postgres=# select * from t;
 id
----
  2
(1行) 

例外が発生する前にBEGINブロックで生成された結果を保持する場合は、トランザクションを明示的にコミットするか、ステートメントレベルのトランザクションを有効にします。 明示的なコミットを実行すると、サブトランザクションとその親トランザクションの両方が送信されます。 後続のステートメントを実行するために、新しいトランザクションとサブトランザクションが生成されます。

説明

PL/SQLのトランザクション制御ステートメントは、最上位プロシージャのPL/SQLブロックと匿名ブロックでのみ許可されます。

<bx id="1" type="code" text="code id=" cqkdbz "title=" "uuid=" lk0z7wn363cfsaksqim "code="
テストから削除します。DECLARE
my_exception例外;
開始
テスト値に挿入 (1);
COMMIT; -保証
昇格my_exception;
例外
my_exceptionがあったとき
通知を上げる 'キャッチ!';
テスト値に挿入する (2) 。エンド;

-- 表
SELECT id FROM test;"data-tag=" codeblock "outputclass=" language-plsql ""/>-- テストテーブルをクリアします。
テストから削除します。DECLARE
  my_exception例外;
開始
  テスト値に挿入 (1);
  COMMIT; -トランザクションをコミットします。
  昇格my_exception;
例外
  my_exceptionがあったとき
    通知を上げる 'キャッチ!';
    テスト値に挿入する (2) 。エンド;

-- テーブルからデータを照会します。
SELECT idからテスト; 

実行結果:

<bx id="1" type="code" text="code id=" 1264br "title=" "uuid=" lk0zavv0q46caybjbo "code=" NOTICE: catch!
やる
postgres=# select * from t;
id
----
1
2
(2行) "data-tag=" codeblock "outputclass=" language-plsql ""/>NOTICE: catch!
やる
postgres=# select * from t;
 id
----
  1
  2
(2行)