【Oracle】ORA-06530の原因と解決方法|Reference to uninitialized composite の直し方

ORA-06530: Reference to uninitialized composite は、Oracle PL/SQLで初期化していないオブジェクト型や複合型を参照した時に発生するエラーです。特に、オブジェクト型の変数を宣言しただけで、コンストラクタを呼ばずに属性へ代入しようとした場合に起きやすいです。

Oracle公式のORA-06530説明では、object、LOB、その他のcompositeを初期化せずに左辺として参照したことが原因で、適切なコンストラクタまたはwhole-object assignmentで初期化することが対処として示されています。

先に結論
ORA-06530が出たら、対象のオブジェクト変数を type_name(...) のコンストラクタで初期化してから属性へ代入します。コレクション未初期化なら ORA-06531、発生行の追跡は ORA-06512 を確認します。
スポンサーリンク

ORA-06530とは

ORA-06530は、複合型の変数そのものがNULL状態のまま、属性や要素を更新しようとした時に出ます。単純な数値や文字列ではなく、オブジェクト型、LOB、複合型の初期化漏れを疑います。

対象 未初期化の例 起きやすいエラー
オブジェクト型 l_order t_order_obj; のまま l_order.id := 1 ORA-06530
コレクション l_ids t_num_list; のまま l_ids.EXTEND ORA-06531
添字問題 初期化済みだが範囲外の添字を使う ORA-06532 / ORA-06533
値や型の問題 属性へ長すぎる文字列や不正な数値を代入 ORA-06502

発生する典型例

次の例では、オブジェクト型の変数 l_order を宣言しただけで、コンストラクタを呼んでいません。この状態で属性 order_id に代入しようとするとORA-06530になります。

ora06530-uninitialized-object.sql
CREATE OR REPLACE TYPE t_order_obj AS OBJECT (
  order_id NUMBER,
  status   VARCHAR2(20)
);
/

DECLARE
  l_order t_order_obj;
BEGIN
  l_order.order_id := 1001;
END;
/

-- ORA-06530: Reference to uninitialized composite
-- ORA-06512: at line 4

ここでの問題は、order_id という属性ではなく、親である l_order そのものがNULL状態であることです。

基本の直し方

オブジェクト型は、型名と同じコンストラクタでインスタンスを作ってから属性を更新します。属性に初期値を入れたい場合も、まずオブジェクト全体を生成します。

initialize-object-constructor.sql
DECLARE
  l_order t_order_obj := t_order_obj(NULL, NULL);
BEGIN
  l_order.order_id := 1001;
  l_order.status := 'NEW';

  DBMS_OUTPUT.PUT_LINE(l_order.order_id || ':' || l_order.status);
END;
/
やりたいこと 書き方 注意点
空に近い状態で作る t_order_obj(NULL, NULL) オブジェクト自体は初期化済みになる
初期値付きで作る t_order_obj(1001, 'NEW') 属性の順番と型を合わせる
あとから属性を更新する コンストラクタ後に l_order.status := ... 親オブジェクトがNULLでないこと
全体を差し替える l_order := t_order_obj(...) whole-object assignmentとして扱える

症状別の最短修正

ORA-06530は、どの複合型がNULLのままなのかを見つけると早く直せます。発生行の左辺や戻り値を見て、次のように切り分けます。

症状 原因になりやすい箇所 最短修正
l_obj.attr := ...で失敗 親オブジェクトl_objがNULL l_obj := t_obj(...)で初期化
関数戻り値の属性参照で失敗 関数がNULLオブジェクトを返している NULL判定するか初期化済みオブジェクトを返す
OUT引数を呼び出し元で使うと失敗 プロシージャ内でOUTオブジェクトを初期化していない OUT引数にコンストラクタ結果を代入
親は初期化済みなのに子で失敗 属性内のオブジェクトやコレクションがNULL 子属性もコンストラクタで初期化
初期化後に別エラーになる 属性値の型や長さが合っていない ORA-06502として確認

whole-object assignmentで直す

属性を1つずつ代入する前に、オブジェクト全体を代入して初期化する方法もあります。Oracle公式の対処にもあるように、コンストラクタまたはwhole-object assignmentで複合型全体を初期化するのが基本です。

whole-object-assignment.sql
DECLARE
  l_order t_order_obj;
BEGIN
  l_order := t_order_obj(1001, 'NEW');

  l_order.status := 'CONFIRMED';
END;
/

オブジェクト型の属性にコレクションがある場合

親オブジェクトを初期化していても、属性として持っているコレクションがNULLだと、別の未初期化エラーにつながります。親と子の両方を初期化する意識が必要です。

object-with-collection-bad.sql
CREATE OR REPLACE TYPE t_num_list AS TABLE OF NUMBER;
/
CREATE OR REPLACE TYPE t_order_detail AS OBJECT (
  order_id NUMBER,
  item_ids t_num_list
);
/

DECLARE
  l_order t_order_detail := t_order_detail(1001, NULL);
BEGIN
  l_order.item_ids.EXTEND;
END;
/

-- 親は初期化済みだが item_ids がNULL
object-with-collection-good.sql
DECLARE
  l_order t_order_detail := t_order_detail(1001, t_num_list());
BEGIN
  l_order.item_ids.EXTEND;
  l_order.item_ids(1) := 501;
END;
/

コレクション属性が未初期化の場合は、ORA-06531の原因と解決方法 の考え方がそのまま使えます。

ネストしたオブジェクト属性で起きる場合

親オブジェクトだけでなく、属性として持っている子オブジェクトも初期化が必要です。親を生成していても、子属性にNULLを渡していれば、子属性のさらに内側を更新する時にORA-06530になります。

nested-object-attribute-bad.sql
CREATE OR REPLACE TYPE t_customer_obj AS OBJECT (
  customer_id NUMBER,
  name        VARCHAR2(100)
);
/
CREATE OR REPLACE TYPE t_order_with_customer AS OBJECT (
  order_id NUMBER,
  customer t_customer_obj
);
/

DECLARE
  l_order t_order_with_customer := t_order_with_customer(1001, NULL);
BEGIN
  l_order.customer.name := 'SATO';
END;
/

-- customer がNULLなので ORA-06530
nested-object-attribute-good.sql
DECLARE
  l_order t_order_with_customer :=
    t_order_with_customer(1001, t_customer_obj(NULL, NULL));
BEGIN
  l_order.customer.customer_id := 501;
  l_order.customer.name := 'SATO';
END;
/

レコード型との違い

PL/SQLの RECORD 変数は、オブジェクト型とは扱いが少し違います。通常のレコード変数は宣言すればフィールドに代入できますが、オブジェクト型はコンストラクタで生成する必要があります。この違いを混同するとORA-06530に気づきにくくなります。

record-variable-example.sql
DECLARE
  TYPE t_order_rec IS RECORD (
    order_id NUMBER,
    status   VARCHAR2(20)
  );
  l_order t_order_rec;
BEGIN
  l_order.order_id := 1001;
  l_order.status := 'NEW';
END;
/

-- RECORDはこの形で使える

PL/SQLの基本構文やブロックの考え方は PL/SQL基本構文完全ガイド も参考になります。

ORA-06531との違い

ORA-06530とORA-06531は、どちらも未初期化が原因ですが、対象が違います。何がNULL状態なのかを見ると切り分けやすいです。

エラー 対象 対処
ORA-06530 オブジェクト型、LOB、その他composite l_obj.attr := ... コンストラクタまたは全体代入
ORA-06531 コレクション l_list.EXTEND コレクションコンストラクタで初期化
ORA-06532 添字の許容範囲外 l_list(0)、VARRAY上限超え 添字値とLIMIT確認
ORA-06533 要素数超え COUNT=0l_list(1) EXTENDCOUNT確認

関数戻り値やOUT引数で起きる場合

関数やプロシージャからオブジェクト型を返す時に、NULLのまま返すと呼び出し元でORA-06530になることがあります。0件や該当なしを表したい場合でも、呼び出し元が属性を参照するなら、NULLではなく初期化済みオブジェクトを返す設計にします。

bad-return-null-object.sql
CREATE OR REPLACE FUNCTION get_order RETURN t_order_obj IS
  l_order t_order_obj;
BEGIN
  RETURN l_order;
END;
/

-- 呼び出し元で result.status := ... のように使うとORA-06530になり得る
good-return-initialized-object.sql
CREATE OR REPLACE FUNCTION get_order RETURN t_order_obj IS
BEGIN
  RETURN t_order_obj(NULL, NULL);
END;
/

調査手順

実際にORA-06530が出たら、直後の ORA-06512 で発生行を確認し、USER_SOURCE で該当箇所を見ます。その行で属性代入しているオブジェクト変数が、直前でコンストラクタまたはwhole-object assignmentにより初期化されているかを見ます。

check-user-source-ora06530.sql
SELECT line,
       text
FROM user_source
WHERE name = 'PKG_ORDER'
  AND type = 'PACKAGE BODY'
  AND line BETWEEN 80 AND 105
ORDER BY line;

発生行の読み方は ORA-06512の原因と読み方、バックトレースのログ設計は DBMS_UTILITY完全ガイド が参考になります。

順番 見る場所 確認内容
1 ORA-06512の最初のオブジェクト付き行 どの行で属性代入しているか
2 属性の左側 l_obj.attrl_obj がNULLでないか
3 直前の初期化 コンストラクタまたは全体代入があるか
4 戻り値・OUT引数 NULLオブジェクトを受け取っていないか
5 属性の型 属性がコレクションなら子も初期化しているか

よくある原因と対処一覧

原因 症状 対処
オブジェクト型を宣言しただけ l_obj.attr := ...でORA-06530 先にtype_name(...)で初期化
関数がNULLオブジェクトを返す 呼び出し元で属性参照時に失敗 初期化済みオブジェクトを返すかNULL判定する
OUT引数にNULLを返す 呼び出し元で代入・参照時に失敗 呼び出し先でコンストラクタを代入
親だけ初期化して子属性がNULL コレクション属性で失敗 子コレクションも初期化
値の代入先が合わない 初期化後にORA-06502 ORA-06502として型や桁を確認

チェックリスト

項目 OKの状態
オブジェクト変数を初期化した type_name(...) を代入している
属性代入前にNULLでない 親オブジェクトが生成済み
関数戻り値を確認した NULLオブジェクトを返していない
OUT引数を確認した 呼び出し元で使う前に初期化済み
子コレクションも初期化した 親だけでなく属性内の複合型も生成済み
ORA-06512の行を確認した 発生行と呼び出し元を分けて読んでいる

よくある質問

オブジェクト型を宣言しただけでは使えませんか?

属性参照や属性代入をするには、コンストラクタでオブジェクトを初期化する必要があります。

RECORD型でもORA-06530になりますか?

通常のPL/SQL RECORDは宣言後にフィールド代入できます。ORA-06530で多いのはオブジェクト型やその他の複合型の未初期化です。

ORA-06531とは何が違いますか?

ORA-06530はオブジェクト型などのcomposite、ORA-06531はコレクションの未初期化です。親オブジェクトかコレクションかを見ます。

NULLを返したい場合はどうすればよいですか?

呼び出し元でNULL判定してから属性参照します。呼び出し元が必ず属性を使う設計なら、NULLではなく初期化済みオブジェクトを返す方が安全です。

まとめ

ORA-06530は、初期化していないオブジェクト型や複合型を参照した時に発生します。属性へ代入する前に、type_name(...) のコンストラクタ、またはwhole-object assignmentでオブジェクト全体を初期化します。

コレクション未初期化のORA-06531とは対象が違いますが、どちらも「親となる変数がNULL状態のまま使われている」点は似ています。ORA-06512で発生行を確認し、左辺の親オブジェクトが初期化済みかを確認するのが最短です。

参考

ORA-06530 – Oracle Database Error Help

Object Methods – Oracle Database Object-Relational Developer's Guide

Using PL/SQL With Object Types – Oracle Database Object-Relational Developer's Guide