【Oracle】ORA-06503の原因と解決方法|function returned without value の直し方

【Oracle】ORA-06503の原因と解決方法|function returned without value の直し方 Oracle

ORA-06503: PL/SQL: Function returned without value は、OracleのPL/SQL関数が RETURN を実行しないまま終了した時に発生するエラーです。検索結果やログでは function returned without value と小文字で見ることもあります。関数は戻り値を返すことが契約なので、正常終了するすべての経路で値を返す必要があります。

よくある原因は、IFCASE の一部の分岐だけ RETURN がない、EXCEPTION で例外を握りつぶして何も返していない、テストデータでは通っていた条件が本番データでは外れて最後まで到達してしまう、というパターンです。

先に結論
ORA-06503が出たら、まず関数内のすべての終了経路に RETURN があるか確認します。次に、WHEN OTHERS THEN NULL のように例外を握りつぶしていないか、呼び出し元の ORA-06512 の行番号から実際に落ちた関数を確認します。コンパイルエラーではなく実行時エラーなので、ORA-06550 とは切り分けて考えます。
スポンサーリンク

ORA-06503とは

ORA-06503は、関数が戻り値なしで終了したことを示します。プロシージャは戻り値を返さなくても問題ありませんが、関数は宣言した戻り型に合う値を返す必要があります。

対象 戻り値 RETURNなしで終了した場合
プロシージャ なし 正常終了できる
関数 あり ORA-06503 になる
関数の一部分岐 条件によってあり/なし RETURNがない経路で ORA-06503
例外処理内 明示的に返す必要あり 何も返さないと ORA-06503

Oracle公式のORA-06503説明でも、関数が値を返さずに終了したことが原因として示されています。そのため、対処は「どの経路でRETURNを通らなかったか」を見つけることです。

RETURN漏れの基本例

もっとも単純なのは、条件に一致した時だけ RETURN し、条件に一致しなかった時に関数の末尾まで到達してしまうパターンです。

ora06503-missing-return.sql
CREATE OR REPLACE FUNCTION get_rank_name(p_score NUMBER)
RETURN VARCHAR2
IS
BEGIN
  IF p_score >= 90 THEN
    RETURN 'A';
  ELSIF p_score >= 80 THEN
    RETURN 'B';
  END IF;

  -- p_score が80未満の場合、RETURNされずに終了する
END;
/

SELECT get_rank_name(70) FROM dual;
-- ORA-06503: PL/SQL: Function returned without value

この関数はコンパイルできる場合がありますが、p_score が80未満になると戻り値がありません。ORA-06503は、このように「文法としては成立しているが、実行経路によって戻り値がない」時に表面化します。

基本の直し方

一番安全なのは、関数の最後にデフォルトの RETURN を置くか、すべての分岐で明示的に戻り値を返すことです。

ora06503-return-default.sql
CREATE OR REPLACE FUNCTION get_rank_name(p_score NUMBER)
RETURN VARCHAR2
IS
BEGIN
  IF p_score >= 90 THEN
    RETURN 'A';
  ELSIF p_score >= 80 THEN
    RETURN 'B';
  ELSE
    RETURN 'C';
  END IF;
END;
/

業務上「該当なし」を戻したいなら NULL を返す設計もあります。ただし、呼び出し元が NULL を想定していない場合は別の不具合になるため、戻り値の意味を決めてから実装します。

IF分岐で起きるパターン

IF分岐では、条件を追加した時にRETURN漏れが入りやすくなります。特に、初期値では問題なくても、未知のステータスやNULLが入った時に最後まで抜けるケースがあります。

パターン 起きる理由 修正方針
IFELSE がない どの条件にも一致しない経路がある ELSE RETURN ... を追加する
条件がNULLになる 比較結果がTRUEにならない NULL時の戻り値を決める
ステータス追加に未対応 新しい値が既存分岐に入らない 未知値の扱いを明示する
途中で例外が起きる 例外部でRETURNしない 返すか再送出するか決める
ora06503-if-null-safe.sql
CREATE OR REPLACE FUNCTION status_label(p_status VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
  IF p_status = 'A' THEN
    RETURN '有効';
  ELSIF p_status = 'I' THEN
    RETURN '無効';
  ELSIF p_status IS NULL THEN
    RETURN '未設定';
  ELSE
    RETURN '不明';
  END IF;
END;
/

CASE文で起きるパターン

CASE文でも、すべての値を網羅できていないとRETURN漏れになります。式としての CASE を使って戻り値を作ると、経路が見えやすくなります。

ora06503-case-return.sql
CREATE OR REPLACE FUNCTION priority_label(p_priority NUMBER)
RETURN VARCHAR2
IS
BEGIN
  RETURN CASE p_priority
           WHEN 1 THEN '高'
           WHEN 2 THEN '中'
           WHEN 3 THEN '低'
           ELSE '未分類'
         END;
END;
/

条件分岐の書き方は OracleのCASE式ガイド も参考になります。関数では「どの条件でも最終的に値が返るか」を優先して読みやすくします。

EXCEPTIONで握りつぶすと起きる

実務で危険なのが、例外を握りつぶして関数を終わらせるパターンです。WHEN OTHERS THEN NULL は一見安全そうに見えますが、関数では戻り値がなくなるためORA-06503につながります。

ora06503-when-others-null.sql
CREATE OR REPLACE FUNCTION get_customer_name(p_customer_id NUMBER)
RETURN VARCHAR2
IS
  l_name customers.customer_name%TYPE;
BEGIN
  SELECT customer_name
  INTO l_name
  FROM customers
  WHERE customer_id = p_customer_id;

  RETURN l_name;
EXCEPTION
  WHEN OTHERS THEN
    NULL;
    -- ここで終了すると戻り値がない
END;
/

例外時も値を返す設計なら、何を返すかを明示します。エラーとして扱うべきなら、RAISE で呼び出し元へ再送出します。例外処理全体の設計は PL/SQL例外処理ガイド が参考になります。

ora06503-exception-fixed.sql
CREATE OR REPLACE FUNCTION get_customer_name(p_customer_id NUMBER)
RETURN VARCHAR2
IS
  l_name customers.customer_name%TYPE;
BEGIN
  SELECT customer_name
  INTO l_name
  FROM customers
  WHERE customer_id = p_customer_id;

  RETURN l_name;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN NULL;
  WHEN OTHERS THEN
    RAISE;
END;
/

ORA-06512の行番号から原因を追う

ORA-06503は、単独ではどの分岐でRETURN漏れになったか分かりにくいことがあります。エラースタックに ORA-06512 が出ている場合は、行番号から関数内の該当箇所を確認します。ソース確認には USER_SOURCE を使います。

ora06503-error-stack.txt
ORA-06503: PL/SQL: Function returned without value
ORA-06512: at "APP.GET_RANK_NAME", line 10
ORA-06512: at line 1
check-user-source-ora06503.sql
SELECT line,
       text
FROM user_source
WHERE name = 'GET_RANK_NAME'
  AND type = 'FUNCTION'
ORDER BY line;

ORA-06512の読み方 を使うと、呼び出し元ではなく、実際に戻り値なしで終了した関数の行を追いやすくなります。

PLW-05005で事前に検知する

ORA-06503は実行時に出るエラーですが、PL/SQLコンパイラの警告を有効にしていると、戻り値なしで終了する可能性がある関数を PLW-05005 として検知できることがあります。本番で初めて落とさないために、開発時やCIでは PLSQL_WARNINGS を有効にしておくと安全です。

enable-plsql-warnings.sql
ALTER SESSION SET PLSQL_WARNINGS = 'ENABLE:ALL';

CREATE OR REPLACE FUNCTION get_rank_name(p_score NUMBER)
RETURN VARCHAR2
IS
BEGIN
  IF p_score >= 90 THEN
    RETURN 'A';
  END IF;
END;
/

SHOW ERRORS FUNCTION get_rank_name;
-- PLW-05005: subprogram GET_RANK_NAME returns without value

警告をエラー扱いにしたい場合は、環境に合わせて ERROR:ALL や特定番号の警告だけをエラー化します。チームでPL/SQLを管理しているなら、PL/SQLコンパイル時エラーと警告ガイド と合わせて、警告を放置しない運用にすると再発を減らせます。

設定 意味 使いどころ
ENABLE:ALL 警告を表示する 開発時、レビュー前
ERROR:ALL 警告をエラーとして扱う CIや品質ゲート
DISABLE:ALL 警告を表示しない 原則おすすめしない
PLW-05005 戻り値なしで終了する可能性 ORA-06503の事前検知

コンパイルエラーではなく実行時エラー

ORA-06503は、関数の作成時ではなく実行時に出ることが多いエラーです。ただし PLSQL_WARNINGS を有効にしている場合は、SHOW ERRORSUSER_ERRORSPLW-05005 が出ることがあります。

エラー タイミング 見る場所 関連記事
ORA-06503 関数実行時 実行経路、RETURN、例外処理 この記事
ORA-06512 例外スタック表示時 行番号、呼び出し順 ORA-06512
ORA-06550 PL/SQLコンパイル/実行呼び出し時 構文、宣言、コンパイルエラー ORA-06550
PLS-00201 コンパイル時 未宣言の識別子 PLS-00201

ストアドプロシージャとファンクションの基本的な作り方は、ストアドプロシージャ・ファンクション作成ガイド にまとめています。

SQLから呼び出す関数でも起きる

PL/SQLブロック内だけでなく、SQLから関数を呼び出した場合にもORA-06503は発生します。画面の一覧取得やレポートSQLで関数を呼んでいると、特定の行だけで落ちることがあります。

ora06503-sql-call.sql
SELECT employee_id,
       get_rank_name(score) AS rank_name
FROM employee_scores;

-- score が想定外の行に当たると ORA-06503 になる

この場合は、どの入力値でRETURN漏れになるかを絞ります。関数単体で代表値、境界値、NULL、想定外値をテストすると原因を見つけやすくなります。

テスト観点

テスト値 確認すること
通常値 想定した戻り値になる 90'A'
境界値 条件境界でRETURN漏れがない 79808990
NULL NULL時の扱いが決まっている p_status IS NULL
想定外値 未知コードでも戻るか、明示的に例外にする 'X'-1
例外発生時 返すか再送出するかが明確 NO_DATA_FOUNDTOO_MANY_ROWS

「とりあえずNULLを返す」だけで済ませると、呼び出し元で別の不具合になることがあります。業務上の戻り値としてNULLが妥当か、エラーにすべきかを分けて考えます。

修正方針の選び方

状況 おすすめの修正 理由
該当なしが正常系 RETURN NULL または既定値を返す 呼び出し元が扱える戻り値にする
想定外値はデータ不備 RAISE_APPLICATION_ERROR で明示する 不正データを隠さない
例外を上位で処理したい RAISE で再送出する 原因のスタックを保てる
分岐が増え続ける 最後にデフォルトRETURNを置く 新しい値でも戻り値なしを避ける
戻り値の種類が多い CASE式やテーブル参照に寄せる 分岐漏れを減らせる
ora06503-raise-application-error.sql
CREATE OR REPLACE FUNCTION status_label(p_status VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
  CASE p_status
    WHEN 'A' THEN RETURN '有効';
    WHEN 'I' THEN RETURN '無効';
    ELSE
      RAISE_APPLICATION_ERROR(-20001, '未知のステータスです: ' || p_status);
  END CASE;
END;
/

チェックリスト

項目 OKの状態
関数の末尾まで到達しても戻り値がある 最後に RETURN または明示的な例外がある
IF/CASEの全分岐が網羅されている ELSE やデフォルト値がある
NULL入力の扱いが決まっている NULL用の分岐または戻り値がある
例外処理で握りつぶしていない RETURN するか RAISE する
ORA-06512の行番号を確認した 落ちた関数と行が特定できている
呼び出し元が戻り値を扱える NULLや既定値の意味が共有されている

よくある質問

RETURN NULLでもよいですか?

業務上「該当なし」や「未設定」をNULLで表す設計なら問題ありません。ただし、NULLがエラーを隠すだけなら、RAISERAISE_APPLICATION_ERROR を使う方が安全です。

プロシージャでもORA-06503になりますか?

ORA-06503は関数が戻り値なしで終了した時のエラーです。プロシージャ自体には戻り値がないため、通常このエラーの対象は関数です。

コンパイルは成功しているのに実行時に落ちます

すべての入力でRETURNが通るとは限らないためです。境界値、NULL、想定外コード、例外発生時の経路を確認してください。

WHEN OTHERS THEN NULL は避けるべきですか?

原則として避けます。関数では戻り値なしの終了につながりやすく、原因も見えにくくなります。返す値を明示するか、例外を再送出します。

まとめ

ORA-06503は、PL/SQL関数が値を返さずに終了した時に発生します。原因は、RETURN 漏れ、IF/CASEの分岐漏れ、NULLや想定外値、例外処理での握りつぶしが中心です。

対処では、すべての終了経路で RETURN する、例外時は返すか再送出する、ORA-06512 の行番号から実際に落ちた関数を追う、という順で確認します。関数は「必ず戻り値を返す」という前提で設計すると、同じエラーを防ぎやすくなります。

参考

ORA-06503 – Oracle Database Error Help

PLW-05005 – Oracle Database Error Help

PL/SQL Subprograms – Oracle Database PL/SQL Language Reference

RETURN Statement – Oracle Database PL/SQL Language Reference