事前定義の例外

事前定義の例外は、事前定義の名前を持つ内部的に定義された例外で、PL/SQLによりパッケージSTANDARDの中でグローバルに宣言されています。事前定義の例外はランタイム・システムによって暗黙的(自動的)に呼び出されます。事前定義の例外には名前が付いているため、それ専用の例外ハンドラを記述できます。

表12-3に、事前定義の例外の名前とエラー・コードを示します。

表12-3 PL/SQLの事前定義の例外

例外名 Oracleエラー エラー・コード

ACCESS_INTO_NULL

ORA-06530

-6530

CASE_NOT_FOUND

ORA-06592

-6592

COLLECTION_IS_NULL

ORA-06531

-6531

CURSOR_ALREADY_OPEN

ORA-06511

-6511

DUP_VAL_ON_INDEX

ORA-00001

-1

INVALID_CURSOR

ORA-01001

-1001

INVALID_NUMBER

ORA-01722

-1722

LOGIN_DENIED

ORA-01017

-1017

NO_DATA_FOUND

ORA-01403

+100

NO_DATA_NEEDED

ORA-06548

-6548

NOT_LOGGED_ON

ORA-01012

-1012

PROGRAM_ERROR

ORA-06501

-6501

ROWTYPE_MISMATCH

ORA-06504

-6504

SELF_IS_NULL

ORA-30625

-30625

STORAGE_ERROR

ORA-06500

-6500

SUBSCRIPT_BEYOND_COUNT

ORA-06533

-6533

SUBSCRIPT_OUTSIDE_LIMIT

ORA-06532

-6532

SYS_INVALID_ROWID

ORA-01410

-1410

TIMEOUT_ON_RESOURCE

ORA-00051

-51

TOO_MANY_ROWS

ORA-01422

-1422

VALUE_ERROR

ORA-06502

-6502

ZERO_DIVIDE

ORA-01476

-1476

例12-6では、企業の株価収益率を計算しています。企業の収益が0(ゼロ)の場合に除算演算を実行すると、事前定義の例外ZERO_DIVIDEが呼び出され、ブロックの実行部から例外処理部に制御が移ります。

例12-7では、例12-6で処理されている例外を、エラー・チェック・コードを使用して回避しています。

例12-8では、プロシージャは、パラメータdiscrimの値に応じてEMPLOYEES表またはDEPARTMENTS表のカーソル変数をオープンします。無名ブロックは、プロシージャを起動してEMPLOYEES表のカーソル変数をオープンしますが、DEPARTMENTS表からフェッチするため、事前定義の例外ROWTYPE_MISMATCHが発生します。

関連項目:

例12-6 ZERO_DIVIDEを処理する無名ブロック

DECLARE
  stock_price   NUMBER := 9.73;
  net_earnings  NUMBER := 0;
  pe_ratio      NUMBER;
BEGIN
  pe_ratio := stock_price / net_earnings;  -- raises ZERO_DIVIDE exception
  DBMS_OUTPUT.PUT_LINE('Price/earnings ratio = ' || pe_ratio);
EXCEPTION
  WHEN ZERO_DIVIDE THEN
    DBMS_OUTPUT.PUT_LINE('Company had zero earnings.');
    pe_ratio := NULL;
END;
/

結果:

Company had zero earnings.

例12-7 ZERO_DIVIDEを回避する無名ブロック

DECLARE
  stock_price   NUMBER := 9.73;
  net_earnings  NUMBER := 0;
  pe_ratio      NUMBER;
BEGIN
  pe_ratio :=
    CASE net_earnings
      WHEN 0 THEN NULL
      ELSE stock_price / net_earnings
    END;
END;
/

例12-8 ROWTYPE_MISMATCHを処理する無名ブロック

CREATE OR REPLACE PACKAGE emp_dept_data AUTHID DEFINER AS
  TYPE cv_type IS REF CURSOR;
  
  PROCEDURE open_cv (
    cv       IN OUT cv_type,
    discrim  IN     POSITIVE
  );
  END emp_dept_data;
/
 
CREATE OR REPLACE PACKAGE BODY emp_dept_data AS
  PROCEDURE open_cv (
    cv      IN OUT cv_type,
    discrim IN     POSITIVE) IS
  BEGIN
    IF discrim = 1 THEN
    OPEN cv FOR
      SELECT * FROM EMPLOYEES ORDER BY employee_id;
    ELSIF discrim = 2 THEN
      OPEN cv FOR
        SELECT * FROM DEPARTMENTS ORDER BY department_id;
    END IF;
  END open_cv;
END emp_dept_data;
/

無名ブロックからプロシージャopen_cvを起動します。

DECLARE
  emp_rec   EMPLOYEES%ROWTYPE;
  dept_rec  DEPARTMENTS%ROWTYPE;
  cv        Emp_dept_data.CV_TYPE;
BEGIN
  emp_dept_data.open_cv(cv, 1);  -- Open cv for EMPLOYEES fetch.
  FETCH cv INTO dept_rec;        -- Fetch from DEPARTMENTS.
  DBMS_OUTPUT.PUT(dept_rec.DEPARTMENT_ID);
  DBMS_OUTPUT.PUT_LINE('  ' || dept_rec.LOCATION_ID);
EXCEPTION
  WHEN ROWTYPE_MISMATCH THEN
     BEGIN
       DBMS_OUTPUT.PUT_LINE
         ('Row type mismatch, fetching EMPLOYEES data ...');
       FETCH cv INTO emp_rec;
       DBMS_OUTPUT.PUT(emp_rec.DEPARTMENT_ID);
       DBMS_OUTPUT.PUT_LINE('  ' || emp_rec.LAST_NAME);
     END;
END;
/

結果:

Row type mismatch, fetching EMPLOYEES data ...
90  King