【完全ガイド】ORA-06512: at “…” line X の原因と解決方法|PL/SQL スタックトレース・DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 徹底解説

【完全ガイド】ORA-06512: at “…” line X の原因と解決方法|PL/SQL スタックトレース・DBMS_UTILITY.FORMAT_ERROR_BACKTRACE 徹底解説

Oracle PL/SQL 開発者が実行時に必ず遭遇するエラー出力:

BEGIN my_proc; END;
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "SCOTT.MY_PROC", line 42
ORA-06512: at line 1

「line X で発生」というシンプルなメッセージ。実は極めて重要な特性があります:

  • ORA-06512PL/SQL 実行時のスタックトレース(呼び出し履歴の位置情報)
  • ORA-06512 単独では原因不明、併記される ORA-06502, ORA-01403, ORA-01422 等が実際の原因
  • エラースタックの最初の実質エラー根本原因
  • 後続の ORA-06512呼び出し履歴を辿る位置情報

姉妹エラー ORA-06550 との決定的違い:

ORA-06550: PL/SQL コンパイル時の位置情報(PLS-xxx と組み合わせ)
ORA-06512: PL/SQL 実行時のスタックトレース(ORA-xxxx と組み合わせ)

現場で最も典型的なのは、ORA-06502 との組み合わせ:

ORA-06502: PL/SQL: numeric or value error   ← 根本原因
ORA-06512: at "SCOTT.MY_PKG", line 42        ← パッケージの line 42 で発生
ORA-06512: at "SCOTT.WRAPPER", line 15       ← WRAPPER の line 15 から呼ばれた
ORA-06512: at line 1                          ← 匿名ブロックの line 1 から呼ばれた

スタックトレースを下から上に読むことで、呼び出し経路が判明します:

line 1(匿名ブロック)
  → line 15(WRAPPER プロシージャ)
    → line 42(MY_PKG パッケージ)← ここでエラー発生

多くの日本語記事が「line 42 を見よ」で終わりますが、実務では:

  • ORA-06512 は実際のエラーではないという原理
  • スタックトレースの正しい読み方(下から上)
  • DBMS_UTILITY.FORMAT_ERROR_BACKTRACE の活用
  • DBMS_UTILITY.FORMAT_ERROR_STACK vs SQLERRM
  • UTL_CALL_STACK (12c+) の高度な使用
  • EXCEPTION ブロックの適切な設計
  • RAISE_APPLICATION_ERROR によるカスタム例外
  • ネストブロックでの例外伝播
  • トリガー内でのエラー処理
  • Rails / Java / Python からの受信メッセージ解析

さらに、Oracle 10g で追加された DBMS_UTILITY.FORMAT_ERROR_BACKTRACE は、**「ORA-06512 の悩みを根本解決」**する画期的機能:

EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Error Stack: ' || DBMS_UTILITY.FORMAT_ERROR_STACK);
    DBMS_OUTPUT.PUT_LINE('Backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    RAISE;
END;

これにより、例外発生元の完全な追跡が可能になります。

本記事では、ORA-06512: at "..." line X完全な原因と解決方法を、リファレンスとして実用的に整理します。スタックトレースの読み方、10大発生パターン、DBMS_UTILITY の活用、5つの解決策、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で ORA-06512 に冷静に対処できるようになります。


目次

結論:スタックトレースの最初の実質エラーを見る

時間がない方向けに、最速の対処を先に示します。

エラーメッセージの構造

ORA-XXXX: <実際のエラー内容>              ← 根本原因(これを見る)
ORA-06512: at "SCHEMA.OBJECT", line X    ← 発生位置
ORA-06512: at "SCHEMA.CALLER", line Y    ← 呼び出し元
ORA-06512: at line 1                     ← 匿名ブロック

ORA-06512 は位置情報のみその直前の ORA-XXXX が実際のエラー

スタックトレースの読み方

1. 最初の非-06512 エラー = 根本原因
2. 最初の ORA-06512 = エラー発生位置
3. 後続の ORA-06512 = 呼び出し履歴(下から上へ辿る)

姉妹エラー

エラータイミング
ORA-06512PL/SQL 実行時(ランタイムスタック)
ORA-06550PL/SQL コンパイル時(位置情報)

最速の診断

-- EXCEPTION で詳細情報取得
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
    DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
    DBMS_OUTPUT.PUT_LINE('Error Stack: ' || DBMS_UTILITY.FORMAT_ERROR_STACK);
    DBMS_OUTPUT.PUT_LINE('Backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    RAISE;
END;

5つの解決策

#手法使う場面
最初の実質エラーを解決基本
DBMS_UTILITY で詳細取得ログ強化
EXCEPTION ハンドリング例外制御
RAISE_APPLICATION_ERRORカスタム例外
UTL_CALL_STACK 使用12c+ 高度診断

詳細は以下で解説します。


ORA-06512 の本質:ランタイムスタックトレース

位置情報のみ

ORA-06512 自体には固有の意味なし:

ORA-06512: at "SCHEMA.OBJECT", line X
                                     ↑
                              PL/SQL ソース内の位置

実際のエラーは併記される

ORA-XXXX: <実際のエラーメッセージ>    ← これが原因
ORA-06512: at ...                      ← 位置

*多くの ORA- エラー**と組み合わせ:

  • ORA-06502: 数値/値エラー
  • ORA-01403: NO_DATA_FOUND
  • ORA-01422: TOO_MANY_ROWS
  • ORA-00001: UNIQUE 制約違反
  • ORA-04068: パッケージ状態破棄
  • ORA-20xxx: ユーザー定義例外

スタックの深さ

ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SCOTT.PKG_A", line 100    ← 最深部(エラー発生元)
ORA-06512: at "SCOTT.PKG_B", line 50     ← PKG_B から PKG_A 呼び出し
ORA-06512: at "SCOTT.PKG_C", line 20     ← PKG_C から PKG_B 呼び出し
ORA-06512: at line 1                      ← 匿名ブロック(最上位)

下から上へ辿ることで呼び出し経路判明。


【原因①】ORA-06502 との組み合わせ(最頻出)

症状

DECLARE
  v_name VARCHAR2(3);
BEGIN
  v_name := 'John Doe';   -- 8 文字を 3 に代入
END;
/
-- ORA-06502: PL/SQL: numeric or value error: character string buffer too small
-- ORA-06512: at line 4

診断

ORA-06502 が根本原因line 4 が発生位置。

解決

DECLARE
  v_name VARCHAR2(100);   -- 十分なサイズ
BEGIN
  v_name := 'John Doe';
END;
/

ORA-06502 の詳細は ORA-06502: PL/SQL numeric or value error の記事も参照してください。


【原因②】ORA-01403 NO_DATA_FOUND

症状

DECLARE
  v_name VARCHAR2(100);
BEGIN
  SELECT name INTO v_name FROM emp WHERE id = 99999;
  -- id=99999 が存在しない
END;
/
-- ORA-01403: no data found
-- ORA-06512: at line 4

解決A: EXCEPTION ハンドラ

DECLARE
  v_name VARCHAR2(100);
BEGIN
  SELECT name INTO v_name FROM emp WHERE id = 99999;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    v_name := 'N/A';
END;
/

解決B: 事前チェック

DECLARE
  v_count NUMBER;
  v_name VARCHAR2(100);
BEGIN
  SELECT COUNT(*) INTO v_count FROM emp WHERE id = 99999;
  IF v_count > 0 THEN
    SELECT name INTO v_name FROM emp WHERE id = 99999;
  END IF;
END;
/

【原因③】ORA-01422 TOO_MANY_ROWS

症状

DECLARE
  v_name VARCHAR2(100);
BEGIN
  SELECT name INTO v_name FROM emp WHERE dept_id = 10;
  -- dept_id=10 に複数行
END;
/
-- ORA-01422: exact fetch returns more than requested number of rows
-- ORA-06512: at line 4

解決

A. ROWNUM で 1 件に:

SELECT name INTO v_name FROM emp 
WHERE dept_id = 10 AND ROWNUM = 1;

B. カーソル使用:

FOR r IN (SELECT name FROM emp WHERE dept_id = 10) LOOP
  -- 各行を処理
END LOOP;

C. EXCEPTION:

EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    -- 複数行対応
END;

【原因④】ORA-04068 パッケージ状態破棄

症状

BEGIN
  my_pkg.some_proc;
END;
/
-- ORA-04068: existing state of packages has been discarded
-- ORA-06512: at "SCOTT.MY_PKG", line 20
-- ORA-06512: at line 2

解決

再度実行(自動的にパッケージ再初期化):

-- 再実行で解消
BEGIN
  my_pkg.some_proc;
END;
/

ORA-04068 の詳細は ORA-04068: existing state of packages の記事も参照してください。


【原因⑤】ORA-00001 UNIQUE 制約違反

症状

BEGIN
  INSERT INTO users (id, email) VALUES (100, 'existing@example.com');
  -- email が UNIQUE 制約に違反
END;
/
-- ORA-00001: unique constraint (SCOTT.UK_USERS_EMAIL) violated
-- ORA-06512: at line 2

解決

EXCEPTION ハンドラ:

BEGIN
  INSERT INTO users (id, email) VALUES (100, 'existing@example.com');
EXCEPTION
  WHEN DUP_VAL_ON_INDEX THEN
    -- 既存の場合の処理
    UPDATE users SET email_verified = 1 WHERE email = 'existing@example.com';
END;
/

UNIQUE 制約は ORA-00001: unique constraint violated の記事も参照してください。


【原因⑥】ORA-20xxx カスタム例外

症状

CREATE OR REPLACE PROCEDURE validate_age(p_age NUMBER) IS
BEGIN
  IF p_age < 0 OR p_age > 150 THEN
    RAISE_APPLICATION_ERROR(-20001, '年齢が無効: ' || p_age);
  END IF;
END;
/

BEGIN
  validate_age(-5);
END;
/
-- ORA-20001: 年齢が無効: -5
-- ORA-06512: at "SCOTT.VALIDATE_AGE", line 4
-- ORA-06512: at line 2

解決

呼び出し元で EXCEPTION:

BEGIN
  validate_age(-5);
EXCEPTION
  WHEN OTHERS THEN
    IF SQLCODE = -20001 THEN
      DBMS_OUTPUT.PUT_LINE('年齢エラー: ' || SQLERRM);
    END IF;
END;

【原因⑦】ZERO_DIVIDE

症状

DECLARE
  v_result NUMBER;
BEGIN
  v_result := 100 / 0;
END;
/
-- ORA-01476: divisor is equal to zero
-- ORA-06512: at line 4

解決

DECLARE
  v_result NUMBER;
  v_divisor NUMBER := 0;
BEGIN
  IF v_divisor != 0 THEN
    v_result := 100 / v_divisor;
  ELSE
    v_result := 0;
  END IF;
END;
/

ZERO_DIVIDE は ORA-01476: divisor is zero の記事も参照してください。


【原因⑧】VALUE_ERROR

症状

DECLARE
  v_num NUMBER(3);   -- 3 桁
BEGIN
  v_num := 9999;   -- 4 桁
END;
/
-- ORA-06502: PL/SQL: numeric or value error
-- ORA-06512: at line 4

解決

DECLARE
  v_num NUMBER(4);   -- 4 桁に拡張
BEGIN
  v_num := 9999;
END;
/

【原因⑨】トリガー内のエラー

症状

CREATE TRIGGER trg_before_insert
BEFORE INSERT ON orders
FOR EACH ROW
DECLARE
  v_customer_name VARCHAR2(100);
BEGIN
  SELECT name INTO v_customer_name 
  FROM customers WHERE id = :NEW.customer_id;
  -- 存在しない場合 NO_DATA_FOUND
END;
/

INSERT INTO orders (id, customer_id) VALUES (1, 99999);
-- ORA-01403: no data found
-- ORA-06512: at "SCOTT.TRG_BEFORE_INSERT", line 5
-- ORA-04088: error during execution of trigger 'SCOTT.TRG_BEFORE_INSERT'

解決

トリガー内で EXCEPTION:

CREATE OR REPLACE TRIGGER trg_before_insert
BEFORE INSERT ON orders
FOR EACH ROW
DECLARE
  v_customer_name VARCHAR2(100);
BEGIN
  BEGIN
    SELECT name INTO v_customer_name 
    FROM customers WHERE id = :NEW.customer_id;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      RAISE_APPLICATION_ERROR(-20001, 
        '顧客不在: ' || :NEW.customer_id);
  END;
END;
/

トリガー系は ORA-04091: mutating table の記事も参照してください。


【原因⑩】ネストブロックでの例外伝播

症状

BEGIN
  BEGIN
    SELECT name INTO v_name FROM emp WHERE id = 999;
  END;
  -- 内側の例外がキャッチされず、外側に伝播
END;
/
-- ORA-01403: no data found
-- ORA-06512: at line 3
-- ORA-06512: at line 5

解決

適切なレベルで EXCEPTION:

BEGIN
  BEGIN
    SELECT name INTO v_name FROM emp WHERE id = 999;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      v_name := 'Unknown';
  END;
  -- 外側は正常続行
END;
/

スタックトレースの正しい読み方

基本原則

1. 最初の非-06512 エラー = 根本原因
2. 最初の ORA-06512 = エラー発生位置(最深部)
3. 続く ORA-06512 = 呼び出し履歴(下から上)

実例

ORA-06502: PL/SQL: numeric or value error       ← 根本原因
ORA-06512: at "SCOTT.PKG_INNER", line 25         ← ここで発生(最深部)
ORA-06512: at "SCOTT.PKG_MIDDLE", line 15        ← ここから呼ばれた
ORA-06512: at "SCOTT.PKG_OUTER", line 5          ← ここから呼ばれた
ORA-06512: at line 1                              ← 匿名ブロックから呼ばれた

呼び出し経路:

匿名ブロック line 1
  → PKG_OUTER.something line 5
    → PKG_MIDDLE.something line 15
      → PKG_INNER.something line 25 ← ここで ORA-06502 発生

診断ツール完全リファレンス

SQLERRM / SQLCODE

EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
    -- -6502, -1403 等の数値

    DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
    -- ORA-06502: PL/SQL: numeric...
END;

DBMS_UTILITY.FORMAT_ERROR_STACK

EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(
      'Error Stack: ' || CHR(10) || 
      DBMS_UTILITY.FORMAT_ERROR_STACK
    );
END;

出力例:

Error Stack: 
ORA-06502: PL/SQL: numeric or value error

DBMS_UTILITY.FORMAT_ERROR_BACKTRACE

EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(
      'Backtrace: ' || CHR(10) || 
      DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
    );
END;

出力例:

Backtrace: 
ORA-06512: at "SCOTT.PKG_INNER", line 25
ORA-06512: at "SCOTT.PKG_MIDDLE", line 15

Oracle 10g+ で追加。呼び出しスタック完全表示

UTL_CALL_STACK (12c+)

DECLARE
  v_depth PLS_INTEGER;
BEGIN
  -- ... エラー発生 ...
EXCEPTION
  WHEN OTHERS THEN
    v_depth := UTL_CALL_STACK.error_depth;
    FOR i IN 1..v_depth LOOP
      DBMS_OUTPUT.PUT_LINE(
        'Error ' || i || ': ' || 
        UTL_CALL_STACK.error_number(i) || ' - ' ||
        UTL_CALL_STACK.error_msg(i)
      );
    END LOOP;
END;

12c+ の高度な API、構造化されたスタック情報。


5つの解決策 完全リファレンス

解決策① 最初の実質エラーを解決

ORA-06512 は無視して、その前の ORA-XXXX を見る
根本原因を解決 → ORA-06512 も自動的に消える

解決策② DBMS_UTILITY で詳細取得

CREATE OR REPLACE PROCEDURE log_error IS
BEGIN
  -- 業務ロジック
EXCEPTION
  WHEN OTHERS THEN
    -- 詳細ログ
    INSERT INTO error_log (
      error_time, error_code, error_message, backtrace
    ) VALUES (
      SYSTIMESTAMP,
      SQLCODE,
      DBMS_UTILITY.FORMAT_ERROR_STACK,
      DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
    );
    COMMIT;
    RAISE;   -- 上位に伝播
END;
/

解決策③ EXCEPTION ハンドリング

BEGIN
  -- 処理
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- データなし対応
  WHEN TOO_MANY_ROWS THEN
    -- 複数行対応
  WHEN VALUE_ERROR THEN
    -- 値エラー対応
  WHEN OTHERS THEN
    -- その他
    RAISE;
END;

解決策④ RAISE_APPLICATION_ERROR

IF invalid_condition THEN
  RAISE_APPLICATION_ERROR(
    -20001, 
    '意味のあるエラーメッセージ'
  );
END IF;

アプリ層で捕捉しやすいカスタム例外。

解決策⑤ UTL_CALL_STACK (12c+)

FOR i IN 1..UTL_CALL_STACK.error_depth LOOP
  DBMS_OUTPUT.PUT_LINE(
    UTL_CALL_STACK.error_number(i) || ' - ' ||
    UTL_CALL_STACK.error_msg(i)
  );
END LOOP;

Rails / Java / Python 対応

Rails ActiveRecord

エラースタック解析:

begin
  ActiveRecord::Base.connection.execute("BEGIN my_proc; END;")
rescue ActiveRecord::StatementInvalid => e
  # エラースタック全体
  Rails.logger.error e.message
  
  # 根本原因(06512 以外の最初)を抽出
  lines = e.message.split("\n")
  root_cause = lines.find { |l| l.match(/ORA-/) && !l.match(/ORA-06512/) }
  Rails.logger.error "根本原因: #{root_cause}"
  
  # ORA-06512 で位置情報
  positions = lines.select { |l| l.match(/ORA-06512/) }
  positions.each { |p| Rails.logger.error "位置: #{p}" }
end

Rails 8 系の詳細は Rails 8 アップグレードガイドの記事、find/find_by/where の記事も参照してください。

Java (JDBC)

try {
    stmt.execute("BEGIN my_proc; END;");
} catch (SQLException e) {
    logger.error("Error: " + e.getMessage());
    
    // スタック解析
    String[] lines = e.getMessage().split("\n");
    
    // 根本原因
    for (String line : lines) {
        if (line.matches(".*ORA-\\d+.*") && !line.contains("ORA-06512")) {
            logger.error("根本原因: " + line);
            break;
        }
    }
    
    // 位置情報
    for (String line : lines) {
        if (line.contains("ORA-06512")) {
            logger.error("位置: " + line);
        }
    }
}

Python (oracledb)

import oracledb
import re

def parse_plsql_error(message):
    lines = message.split('\n')
    root_cause = None
    positions = []
    
    for line in lines:
        if 'ORA-06512' in line:
            positions.append(line.strip())
        elif re.search(r'ORA-\d+', line) and not root_cause:
            root_cause = line.strip()
    
    return root_cause, positions

try:
    cursor.execute("BEGIN my_proc; END;")
except oracledb.DatabaseError as e:
    error_obj, = e.args
    root, positions = parse_plsql_error(error_obj.message)
    print(f"根本原因: {root}")
    for pos in positions:
        print(f"位置: {pos}")

実践シナリオ

シナリオ1:本番エラーの緊急診断

-- 1. エラーログテーブル作成
CREATE TABLE error_log (
  error_time TIMESTAMP DEFAULT SYSTIMESTAMP,
  error_code NUMBER,
  error_msg VARCHAR2(4000),
  backtrace VARCHAR2(4000),
  call_stack VARCHAR2(4000)
);

-- 2. 全プロシージャで統一エラーハンドリング
CREATE OR REPLACE PROCEDURE log_error IS
BEGIN
  -- 実装
EXCEPTION
  WHEN OTHERS THEN
    INSERT INTO error_log VALUES (
      SYSTIMESTAMP, SQLCODE, SQLERRM,
      DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,
      DBMS_UTILITY.FORMAT_CALL_STACK
    );
    COMMIT;
    RAISE;
END;

シナリオ2:スタックトレース解析

本番エラー:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "APP.PKG_INVOICE", line 145
ORA-06512: at "APP.PKG_ORDER", line 67
ORA-06512: at "APP.WEB_HANDLER", line 25
ORA-06512: at line 1

解析:
1. 根本原因: ORA-06502(文字列バッファ)
2. 発生位置: APP.PKG_INVOICE line 145
3. 呼び出し履歴:
   line 1 (匿名) → WEB_HANDLER:25 → PKG_ORDER:67 → PKG_INVOICE:145

シナリオ3:DBMS_UTILITY で詳細ログ

CREATE OR REPLACE PROCEDURE process_order(p_id NUMBER) IS
BEGIN
  -- 業務ロジック
  UPDATE orders SET status = 'processed' WHERE id = p_id;
EXCEPTION
  WHEN OTHERS THEN
    INSERT INTO error_log VALUES (
      SYSTIMESTAMP,
      SQLCODE,
      DBMS_UTILITY.FORMAT_ERROR_STACK,
      DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
    );
    COMMIT;
    RAISE;
END;
/

シナリオ4:Rails ログでの詳細化

class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::StatementInvalid do |e|
    if e.message.include?("ORA-06512")
      # 詳細ログ
      Rails.logger.error("PL/SQL Error:")
      e.message.split("\n").each do |line|
        Rails.logger.error("  #{line}")
      end
      
      # ユーザー向けエラー
      render json: { error: "システムエラーが発生しました" }, status: 500
    else
      raise
    end
  end
end

シナリオ5:Java Spring Boot での統一

@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    @ExceptionHandler(SQLException.class)
    public ResponseEntity<?> handleSQLException(SQLException e) {
        if (e.getMessage().contains("ORA-06512")) {
            log.error("PL/SQL Runtime Error:");
            for (String line : e.getMessage().split("\n")) {
                log.error("  {}", line);
            }
        }
        return ResponseEntity.status(500).body("Internal Error");
    }
}

シナリオ6:Python での詳細ログ

import oracledb
import logging

logger = logging.getLogger(__name__)

def call_stored_proc(cursor, proc_name):
    try:
        cursor.callproc(proc_name)
    except oracledb.DatabaseError as e:
        error_obj, = e.args
        logger.error(f"PL/SQL Runtime Error in {proc_name}:")
        for line in error_obj.message.split('\n'):
            logger.error(f"  {line}")
        raise

シナリオ7:UTL_CALL_STACK (12c+)

CREATE OR REPLACE PROCEDURE detailed_error_log IS
  v_depth PLS_INTEGER;
BEGIN
  -- 業務処理
EXCEPTION
  WHEN OTHERS THEN
    v_depth := UTL_CALL_STACK.error_depth;
    FOR i IN 1..v_depth LOOP
      DBMS_OUTPUT.PUT_LINE(
        'Error ' || i || ': [' ||
        UTL_CALL_STACK.error_number(i) || '] ' ||
        UTL_CALL_STACK.error_msg(i)
      );
    END LOOP;
    RAISE;
END;
/

シナリオ8:Docker Oracle テスト

docker exec -it oracle-xe sqlplus scott/tiger <<EOF
CREATE PROCEDURE test_proc IS
  v_x NUMBER;
BEGIN
  SELECT id INTO v_x FROM emp WHERE id = 99999;
END;
/

BEGIN test_proc; END;
/
-- ORA-01403: no data found
-- ORA-06512: at "SCOTT.TEST_PROC", line 4
-- ORA-06512: at line 1
EOF

Docker 関連は docker daemon 接続エラーの記事、Docker no space left on device の記事も参照してください。

シナリオ9:CI/CD パイプラインでの例外検出

- name: Run PL/SQL tests
  run: |
    sqlplus -s $DB_USER/$DB_PW <<EOF
    SET SERVEROUTPUT ON
    BEGIN
      run_tests;
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('TEST FAILED');
        DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
        RAISE;
    END;
    /
    EOF

Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事を参照してください。

シナリオ10:Autonomous DB

-- Autonomous DB でも同じ動作
-- SQL Developer Web でスタックトレース確認
-- APEX でエラーログ管理

トラブルシューティング

ORA-06512 だけ見て解決できない

そもそも ORA-06512 は位置情報のみその前の ORA-XXXX を確認。

スタックが長すぎる

根本原因(最初の非-06512) を優先、他は無視可能。

line 番号がずれる

パッケージ本体のみ再コンパイル、またはソースコードとの照合

RAISE の使い所

EXCEPTION
  WHEN OTHERS THEN
    -- ログ記録
    RAISE;   -- 上位に伝播(推奨)
END;

ログだけで無視は問題を隠蔽、RAISE で伝播が原則。

アプリからのエラー受信

JDBC / oracledb は全スタックを含む。改行で分割して解析

PostgreSQL からの移行

PG の RAISE EXCEPTION は Oracle の RAISE_APPLICATION_ERROR に対応。


よくある質問(FAQ)

Q1. ORA-06512 と ORA-06550 の違い

  • 06512: 実行時スタックトレース
  • 06550: コンパイル時の位置情報

Q2. line X はソースの何行目?

PL/SQL ソースの行番号CREATE OR REPLACE 部分から数える。

Q3. スタックトレースの読み方

下から上(呼び出し順)、最上部が最深部(エラー発生元)。

Q4. DBMS_UTILITY.FORMAT_ERROR_STACK vs FORMAT_ERROR_BACKTRACE

  • ERROR_STACK: エラーメッセージ全体
  • ERROR_BACKTRACE: ORA-06512 の履歴のみ

Q5. UTL_CALL_STACK 使うべき?

12c+ で複雑な例外解析に有用、単純なら FORMAT_ERROR_BACKTRACE で十分。

Q6. Rails での対応

エラーメッセージ改行分割 + 06512 除外で根本原因抽出。

Q7. Java での対応

SQLException.getMessage() を改行で split、正規表現で解析。

Q8. Python での対応

oracledb.DatabaseErrormessage を解析。

Q9. RAISE すべきか

推奨、例外を無視すると問題隠蔽。

Q10. RAISE_APPLICATION_ERROR の範囲

-20000 〜 -20999 のカスタム例外。

Q11. パッケージ状態エラーとの併発

ORA-04068 + ORA-06512 の組み合わせ、再実行で解消することが多い。

Q12. Autonomous DB での違い

同じ動作、SQL Developer Web / APEX で管理。


参考リンク

Oracle 公式


まとめ

ORA-06512: at "..." line X の要点を再整理します。

エラーの本質

PL/SQL 実行時のスタックトレース(位置情報)
→ それ単独では意味なし
→ 併記される ORA-XXXX が実際の原因

エラーメッセージの構造

ORA-XXXX: <実際のエラー>              ← 根本原因
ORA-06512: at "SCHEMA.OBJECT", line X ← 発生位置(最深部)
ORA-06512: at "SCHEMA.CALLER", line Y ← 呼び出し元
ORA-06512: at line 1                  ← 匿名ブロック

スタックトレースの読み方

1. 最初の非-06512 エラー = 根本原因
2. 最初の ORA-06512 = エラー発生位置
3. 続く ORA-06512 = 呼び出し履歴(下から上)

姉妹エラー

エラータイミング
ORA-06512PL/SQL 実行時
ORA-06550PL/SQL コンパイル時

10大原因

#併発エラー対処
ORA-06502 (数値/値)型・サイズ確認
ORA-01403 (NO_DATA_FOUND)EXCEPTION or 事前チェック
ORA-01422 (TOO_MANY_ROWS)ROWNUM=1 or カーソル
ORA-04068 (パッケージ状態)再実行
ORA-00001 (UNIQUE)DUP_VAL_ON_INDEX ハンドラ
ORA-20xxx (カスタム)呼び出し元で捕捉
ORA-01476 (ZERO_DIVIDE)事前チェック
VALUE_ERROR型・サイズ調整
トリガー内内部 EXCEPTION
ネストブロック伝播適切なレベルで捕捉

診断ツール

-- エラースタック(メッセージ)
DBMS_UTILITY.FORMAT_ERROR_STACK

-- バックトレース(06512 履歴)
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE

-- 12c+ 構造化 API
UTL_CALL_STACK.error_number(i)
UTL_CALL_STACK.error_msg(i)

-- 従来
SQLCODE
SQLERRM

5つの解決策

-- ① 最初の実質エラー解決

-- ② DBMS_UTILITY で詳細取得
EXCEPTION
  WHEN OTHERS THEN
    INSERT INTO error_log VALUES (
      SYSTIMESTAMP, SQLCODE,
      DBMS_UTILITY.FORMAT_ERROR_STACK,
      DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
    );
    RAISE;

-- ③ EXCEPTION ハンドリング
EXCEPTION
  WHEN NO_DATA_FOUND THEN ...
  WHEN TOO_MANY_ROWS THEN ...

-- ④ RAISE_APPLICATION_ERROR
RAISE_APPLICATION_ERROR(-20001, 'エラー');

-- ⑤ UTL_CALL_STACK (12c+)
FOR i IN 1..UTL_CALL_STACK.error_depth LOOP
  DBMS_OUTPUT.PUT_LINE(UTL_CALL_STACK.error_msg(i));
END LOOP;

各言語での対応

Rails:  e.message.split('\n') で解析
Java:   SQLException.getMessage() 分割
Python: oracledb.DatabaseError.message 分割
共通:   ORA-06512 除外して根本原因抽出

予防のポイント

1. 全プロシージャで EXCEPTION ハンドラ
2. DBMS_UTILITY.FORMAT_ERROR_BACKTRACE でログ
3. RAISE で上位に例外伝播
4. RAISE_APPLICATION_ERROR で意味のあるエラー
5. アプリ側で解析ロジック実装
6. 統一されたエラーログテーブル
7. CI/CD でエラー検証
8. UTL_CALL_STACK (12c+) 活用
9. スタックトレースを下から読む
10. 根本原因を修正、隠蔽しない

これらの知識は、Oracle での PL/SQL 開発・デバッグ・DBA 業務・E-Business Suite 運用・Rails / Java / Python アプリ運用・エラーログ設計・監視体制構築・本番デプロイなど、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-06512 に出会っても冷静に的確に対処できるようになります。


本記事は2026年6月時点の情報をもとに、Oracle Database 19c〜23ai での動作確認・公式ドキュメントに基づき作成しています。Oracle のバージョンにより挙動が異なる場合があるため、最新の情報は Oracle 公式ドキュメント(docs.oracle.com)もあわせてご確認ください。