【完全ガイド】ORA-04065: not executed, altered or dropped package の原因と解決方法|3兄弟完全比較・Shared Pool・EBR 徹底解説

【完全ガイド】ORA-04065: not executed, altered or dropped package の原因と解決方法|3兄弟完全比較・Shared Pool・EBR 徹底解説

Oracle 開発者・DBA がパッケージ更新運用で頻繁に遭遇するエラー:

ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package "SCOTT.MY_PKG" has been invalidated
ORA-04065: not executed, altered or dropped package "SCOTT.MY_PKG"
ORA-06508: PL/SQL: could not find program unit being called
ORA-06512: at line 1

**「変更/削除されたため実行不可」**というシンプルなメッセージ。Oracle のパッケージ状態管理の3兄弟エラーの1つです:

  • ORA-04068(DISCARDED、破棄)
  • ORA-04061(INVALIDATED、無効化)
  • ORA-04065(altered/dropped、変更/削除で実行不可) ← 本記事
  • ORA-06508(program unit not found、併発)

このエラーの本質は、Oracle がパッケージの変更/削除を検出:

1. セッション A がパッケージ P を実行中
2. 別セッション B(DBA / デプロイ)が P を変更/削除
3. セッション A が P を再度呼び出し
4. → Oracle が P の変更を検出
5. → ORA-04065 発生(呼び出し不可)
目次

パッケージ状態エラー3兄弟の位置づけ

3つのエラーは通常セットで発生、それぞれの意味:

ORA-04068: 「状態が破棄された」(実行時、セッションレベル)
    → セッション A の P の状態がクリアされた
    
ORA-04061: 「状態が無効化された」(コンパイル時検出)
    → セッション A の状態と新しい P が不整合

ORA-04065: 「変更/削除されたため実行不可」(実行拒否)
    → Oracle が呼び出し自体を拒否

ORA-06508: 「プログラムユニット発見不可」
    → 実際の呼び出し失敗

現場で最も典型的なパターン:

  • パッケージ本体 (BODY) の再コンパイル
  • Oracle E-Business Suite Workflow(PO 承認 / Absence 承認等)
  • IFS ERP のカスタム view / SSIS パッケージ
  • Oracle Database Proactive Patch(datapatch)
  • Spring Boot Java Callable Statement
  • Oracle Integration Cloud (OIC) Database Adapter
  • CI/CD デプロイパイプライン
  • Rails マイグレーション
  • 共通ライブラリパッケージの更新
  • DROP TYPE による依存パッケージ無効化

さらに、Oracle 公式ドキュメントが示す推奨対処:

Cause: Attempt to execute a stored procedure that has been altered 
       or dropped thus making it not callable from the calling procedure.
Action: Recompile its dependents.

多くの日本語記事が「再コンパイルせよ」で終わりますが、実務では:

  • 3兄弟エラーの厳密な違いの理解
  • ALTER SYSTEM FLUSH SHARED_POOL の使い所とリスク
  • DBMS_SHARED_POOL.PURGE による特定カーソルのパージ
  • V$SQL から依存カーソルの特定
  • Edition-Based Redefinition (EBR) による回避
  • PRAGMA SERIALLY_REUSABLE の効果
  • Oracle EBS adadmin での対処
  • Rails ActiveRecord 接続プールのリセット
  • Oracle 26ai SESSION_EXIT_ON_PACKAGE_STATE_ERROR 新機能
  • datapatch -verbose の再実行推奨

さらに、Oracle E-Business Suite (EBS)IFS ERP などのエンタープライズアプリでは、特定のパターンが知られています:

IFS ERP カスタム view + SSIS:
ORA-04065 が occasionally 発生 → SSIS リトライで自己回復

Oracle EBS PO Workflow:
Notification Mailer 停止 → SHARED_POOL フラッシュ → 再起動

Oracle datapatch 12.1.0.2.190716:
再実行(rerun)で解消

本記事では、ORA-04065: not executed, altered or dropped完全な原因と解決方法を、リファレンスとして実用的に整理します。3兄弟の完全比較、10大発生パターン、6つの解決策、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で ORA-04065 に冷静に対処できるようになります。


結論:再実行 or Shared Pool フラッシュ

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

エラーメッセージの読み方

ORA-04065: not executed, altered or dropped package "SCHEMA.PACKAGE"
                                                     ↑
                                        変更/削除されたパッケージ

= 呼び出そうとしたパッケージが altered/dropped されている

最速の対処

即時対処: 再実行(同じ呼び出しをリトライ)
  → Oracle が自動的にパッケージ状態を再初期化
  → 通常成功

失敗する場合:
1. Shared Pool フラッシュ
2. 依存カーソルパージ
3. パッケージ再コンパイル

パッケージ状態エラー3兄弟

エラー意味タイミング
ORA-04068状態が DISCARDED(破棄)実行時
ORA-04061状態が INVALIDATED(無効化)コンパイル時検出
ORA-04065altered/dropped で実行不可実行拒否
ORA-06508プログラムユニット発見不可併発

通常セットで発生、原因は同じ(パッケージ変更/削除)。

6つの解決策

#手法使う場面
再実行自動回復(多くの場合)
Shared Pool フラッシュ緊急対応
依存カーソルパージ特定対処
パッケージ再コンパイルINVALID 対処
Edition-Based Redefinition24時間運用
SESSION_EXIT_ON_PACKAGE_STATE_ERROR (26ai)最新環境

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


Oracle パッケージ変更の仕組み

パッケージ変更のライフサイクル

1. パッケージ P 作成 → 全セッションで使用可能
2. セッション A が P を実行
   → セッションのパッケージ状態が確立
3. 別セッションで P を CREATE OR REPLACE
   → Shared Pool 内の P コピーが INVALID に
4. セッション A が P を再度呼び出し
   → 3兄弟エラー発生
5. セッション A が同じ呼び出しをリトライ
   → 状態が再初期化されて成功(多くの場合)

3 兄弟の発生順序

実際のエラー出力:
ORA-04068: existing state of packages has been discarded  ← 最初
ORA-04061: existing state of package ... invalidated       ← カスケード
ORA-04065: not executed, altered or dropped                ← 実行拒否
ORA-06508: PL/SQL: could not find program unit being called ← 実行失敗
ORA-06512: at line 1                                        ← 位置

読み方:

  1. 04068: セッション状態が破棄された
  2. 04061: 検出された不整合
  3. 04065: そのため実行できない
  4. 06508: プログラムユニットが見つからない

自動回復の仕組み

Oracle は次回呼び出しで自動的に状態再初期化:

BEGIN my_pkg.proc_a; END;   -- 1 回目: ORA-04065
BEGIN my_pkg.proc_a; END;   -- 2 回目: 通常成功

多くのアプリで自動リトライで解決


【原因①】パッケージ再コンパイル中(最頻出)

シナリオ

セッション A: my_pkg 実行中
セッション B (DBA): 
  CREATE OR REPLACE PACKAGE my_pkg AS ... END;
セッション A: my_pkg 再度呼び出し
→ ORA-04065

診断

-- パッケージの最終更新時刻
SELECT owner, object_name, object_type, status, last_ddl_time
FROM dba_objects
WHERE object_name = 'MY_PKG'
ORDER BY last_ddl_time DESC;

対処

A. 再実行:

BEGIN
  my_pkg.proc_a;   -- 初回: ORA-04065
END;
/

BEGIN
  my_pkg.proc_a;   -- 2 回目: 通常成功
END;
/

B. アプリで自動リトライ:

def call_proc
  ActiveRecord::Base.connection.execute("BEGIN my_pkg.proc_a; END;")
rescue ActiveRecord::StatementInvalid => e
  if e.message.include?("ORA-04065") && (retries ||= 0) < 3
    retries += 1
    retry
  end
  raise
end

パッケージ状態関連は ORA-04068: existing state of packages の記事、ORA-04061: existing state has been invalidated の記事も参照してください。


【原因②】Oracle E-Business Suite Workflow

症状(現場頻発)

ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "APPS.PO_REQAPPROVAL_INIT1" 
           has been invalidated
ORA-04065: not executed, altered or dropped package body 
           "APPS.PO_REQAPPROVAL_INIT1"
ORA-06508: PL/SQL: could not find program unit being called

PO Requisition Approval, Workflow Notification 失敗。

対処(Oracle 公式手順)

STEP 1: Shared Pool フラッシュ:

SQL> CONN / AS SYSDBA
SQL> ALTER SYSTEM FLUSH SHARED_POOL;

STEP 2: Concurrent Manager 停止 → adadmin で再コンパイル:

$COMMON_TOP/admin/scripts/$SID/adstpall.sh apps/apps

adadmin
# Recompile APPS Schema オプション

$COMMON_TOP/admin/scripts/$SID/adstrtal.sh apps/apps

STEP 3: 定期的な INVALID 再コンパイル:

BEGIN
  UTL_RECOMP.recomp_parallel(4, 'APPS');
END;
/

【原因③】IFS ERP カスタム view

シナリオ(実例)

IFS ERP カスタム view + SSIS パッケージ:
「Most of the time works, occasionally errors with 4068/4061/4065」

ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package "IFSAPP.SHIPMENT_CFP" 
           has been invalidated
ORA-04065: not executed, altered or dropped package "IFSAPP.SHIPMENT_CFP"

対処

A. SSIS リトライロジック:

try {
    ExecuteSSISPackage();
} catch (SqlException ex) {
    if (ex.Number == 4065 || ex.Number == 4068) {
        Thread.Sleep(1000);
        ExecuteSSISPackage();   // リトライ
    }
}

B. IFS パッケージ再コンパイル(メンテナンス時)。


【原因④】Oracle datapatch 中

症状(12.1.0.2.190716 パッチ適用中)

Patch 29496791 apply (pdb PDB$SEED): WITH ERRORS
Error at line 26523: ORA-04068: existing state of packages has been discarded
Error at line 26524: ORA-04061: existing state of package body 
                     "SYS.DBMS_REGISTRY_SYS" has been invalidated
Error at line 26526: ORA-04065: not executed, altered or dropped package body
Error at line 26528: ORA-06508: PL/SQL: could not find program unit being called

内部スクリプト実行順序の問題。

対処(Oracle 公式推奨)

A. datapatch を再実行:

$ORACLE_HOME/OPatch/datapatch -verbose
# 2 回目実行で解消

B. 事前対処(datapatch 前):

-- 隠しパラメータ設定(一部の問題)
ALTER SYSTEM SET "_srvntfn_job_deq_timeout" = 0 SCOPE=SPFILE;
SHUTDOWN IMMEDIATE
STARTUP

【原因⑤】Spring Boot Java Callable

症状

Caused by: org.springframework.jdbc.UncategorizedSQLException: 
CallableStatementCallback; uncategorized SQLException for SQL 
[{call TEST1_PKG.matchUpdatedInventory(?, ?, ?, ?, ?)}]; 
SQL state [72000]; ERROR code [4068]; 
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package "TEST1.TEST1_PKG" has been invalidated
ORA-04065: not executed, altered or dropped package "TEST1.TEST1_PKG"

対処

A. Spring での自動リトライ:

@Retryable(
    value = SQLException.class,
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000)
)
public void callInventoryUpdate() {
    jdbcTemplate.execute("{call TEST1_PKG.matchUpdatedInventory(?, ?, ?, ?, ?)}");
}

B. 接続プールリセット:

if (e.getErrorCode() == 4065 || e.getErrorCode() == 4068) {
    dataSource.evictConnections();
}

【原因⑥】Oracle Integration Cloud (OIC)

症状

Oracle 公式が troubleshooting ページで明示:

Resolve Error ORA-04068: existing state of packages has been discarded

Database Adapter 経由でストアド呼び出し。

対処

A. OIC 側リトライ設定B. ストアド設計見直し(グローバル状態除去)。


【原因⑦】CI/CD デプロイ中

シナリオ

- name: Deploy PL/SQL
  run: |
    sqlplus $DB_USER/$DB_PW <<EOF
    @deploy_packages.sql
    EOF

# アプリ継続稼働中 → ORA-04065 頻発

解決

A. デプロイ順序(推奨):

# 1. アプリ一時停止
kamal app stop

# 2. パッケージデプロイ
sqlplus $DB_USER/$DB_PW @deploy_packages.sql

# 3. アプリ再起動
kamal app start

B. アプリでリトライ

Kamal 2 デプロイの詳細は Kamal 2 デプロイの記事、rails db:migrate 使い方の記事も参照してください。


【原因⑧】Rails マイグレーション

シナリオ

class UpdatePackages < ActiveRecord::Migration[8.0]
  def up
    execute "CREATE OR REPLACE PACKAGE my_pkg AS ... END;"
  end
end

# Web アプリが my_pkg 使用中
# → ORA-04065

解決

class UpdatePackages < ActiveRecord::Migration[8.0]
  def up
    execute "CREATE OR REPLACE PACKAGE my_pkg AS ... END;"
    execute "CREATE OR REPLACE PACKAGE BODY my_pkg AS ... END;"
    
    # 接続プールリセット
    ActiveRecord::Base.connection_pool.disconnect!
  end
end

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


【原因⑨】共通ライブラリパッケージ更新

シナリオ

-- 共通ライブラリ COMMON_UTIL 更新
CREATE OR REPLACE PACKAGE common_util AS
  FUNCTION format_date(d DATE) RETURN VARCHAR2;
END;
/

-- 依存する多数のパッケージが INVALID に
-- 業務中に大量 ORA-04065 発生

解決

A. 依存関係一括再コンパイル:

BEGIN
  UTL_RECOMP.recomp_parallel(4);
END;
/

B. デプロイ時にアプリ停止(推奨)。


【原因⑩】TYPE / OBJECT 削除

シナリオ

-- TYPE 定義
CREATE TYPE addr_t AS OBJECT (...);

-- 依存パッケージ
CREATE PACKAGE addr_pkg AS
  PROCEDURE proc(a addr_t);
END;
/

-- TYPE 削除
DROP TYPE addr_t;
-- addr_pkg 呼び出し → ORA-04065

解決

A. TYPE 再作成 + パッケージ再コンパイル:

CREATE OR REPLACE TYPE addr_t AS OBJECT (...);
ALTER PACKAGE addr_pkg COMPILE;

B. 事前依存関係確認:

SELECT * FROM user_dependencies
WHERE referenced_name = 'ADDR_T';

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

エラーコード確認

EXCEPTION
  WHEN OTHERS THEN
    IF SQLCODE = -4065 THEN
      DBMS_OUTPUT.PUT_LINE('Package altered/dropped');
    ELSIF SQLCODE = -4061 THEN
      DBMS_OUTPUT.PUT_LINE('Package state invalidated');
    ELSIF SQLCODE = -4068 THEN
      DBMS_OUTPUT.PUT_LINE('Package state discarded');
    END IF;
END;

V$SQL で依存カーソル

SELECT sql_id, hash_value, address, sql_text
FROM v$sql
WHERE sql_text LIKE '%MY_PKG%'
  OR sql_fulltext LIKE '%MY_PKG%';

INVALID オブジェクト

SELECT owner, object_name, object_type, last_ddl_time
FROM dba_objects
WHERE status = 'INVALID'
ORDER BY last_ddl_time DESC;

V$SESSION

SELECT sid, serial#, username, module, status
FROM v$session
WHERE prev_sql_id IN (
  SELECT sql_id FROM v$sql WHERE sql_text LIKE '%MY_PKG%'
);

DBA_DDL_LOG

-- パッケージ変更履歴
SELECT * FROM dba_ddl_log
WHERE object_name = 'MY_PKG'
ORDER BY occurred DESC;

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

解決策① 再実行(自動回復)

-- Oracle は次回呼び出しで自動的に状態再初期化
BEGIN my_pkg.proc_a; END;   -- 1 回目: ORA-04065
BEGIN my_pkg.proc_a; END;   -- 2 回目: 通常成功

多くの場合これで解決

解決策② Shared Pool フラッシュ

-- 全 Shared Pool クリア(緊急対応、パフォーマンス影響大)
SQL> CONN / AS SYSDBA
SQL> ALTER SYSTEM FLUSH SHARED_POOL;

-- Result Cache もクリア
SQL> ALTER SYSTEM FLUSH BUFFER_CACHE;

-- ⚠️ 業務中は慎重に

解決策③ 依存カーソルパージ

-- 特定 SQL のカーソルパージ(12c+)
DECLARE
  v_addr VARCHAR2(50);
  v_hash NUMBER;
BEGIN
  FOR r IN (
    SELECT address, hash_value 
    FROM v$sql 
    WHERE sql_text LIKE '%MY_PKG%'
  ) LOOP
    DBMS_SHARED_POOL.PURGE(
      r.address || ',' || r.hash_value, 
      'C'
    );
  END LOOP;
END;
/

Shared Pool 全体フラッシュより影響小

解決策④ パッケージ再コンパイル

-- 個別
ALTER PACKAGE my_pkg COMPILE;
ALTER PACKAGE my_pkg COMPILE BODY;

-- スキーマ一括
BEGIN
  DBMS_UTILITY.COMPILE_SCHEMA('APP_USER');
END;
/

-- 並列(推奨)
BEGIN
  UTL_RECOMP.recomp_parallel(4, 'APP_USER');
END;
/

INVALID 関連は PLS-00905: object is invalid の記事も参照してください。

解決策⑤ Edition-Based Redefinition (EBR)

Oracle 11g R2+ の高度な機能、無停止デプロイ:

-- 新エディション作成
CREATE EDITION new_edition;

-- 新エディションでパッケージ変更
ALTER SESSION SET EDITION = new_edition;
CREATE OR REPLACE PACKAGE my_pkg AS ... END;

-- 既存セッションは旧エディションで動作継続
-- 新セッションのみ新エディション
-- → ORA-04065 回避

-- 全セッション移行後
ALTER DATABASE DEFAULT EDITION = new_edition;

解決策⑥ SESSION_EXIT_ON_PACKAGE_STATE_ERROR (26ai)

Oracle 26ai 新機能:

ALTER SYSTEM SET session_exit_on_package_state_error = TRUE;

効果:

  • ORA-04065/04068 発生時、セッション自動切断
  • アプリの接続再取得ロジックで自動回復
  • silent data corruption 防止

Rails / Java / Python 対応

Rails ActiveRecord

自動リトライ + 接続リセット:

module OraclePackageRetry
  def call_with_retry(sql, max_retries: 3)
    retries = 0
    begin
      ActiveRecord::Base.connection.execute(sql)
    rescue ActiveRecord::StatementInvalid => e
      if package_state_error?(e) && retries < max_retries
        retries += 1
        Rails.logger.warn "Package state error, retry #{retries}"
        ActiveRecord::Base.connection.reconnect!
        retry
      end
      raise
    end
  end
  
  private
  
  def package_state_error?(e)
    e.message.include?("ORA-04065") || 
      e.message.include?("ORA-04068") ||
      e.message.include?("ORA-04061")
  end
end

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

Java (JDBC / Spring)

Spring Retry:

@Service
public class PackageCaller {
    @Retryable(
        value = SQLException.class,
        maxAttempts = 3,
        backoff = @Backoff(delay = 1000, multiplier = 2)
    )
    public void callWithRetry(String sql) {
        try (Connection conn = ds.getConnection();
             Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
        } catch (SQLException e) {
            if (isPackageStateError(e)) {
                throw e;   // リトライ対象
            }
            throw new RuntimeException(e);
        }
    }
    
    private boolean isPackageStateError(SQLException e) {
        int code = e.getErrorCode();
        return code == 4065 || code == 4068 || code == 4061;
    }
}

Python (oracledb)

import oracledb
import time

def call_with_retry(dsn, user, pw, sql, max_retries=3):
    package_state_errors = {4065, 4068, 4061}
    
    for attempt in range(max_retries):
        try:
            with oracledb.connect(user=user, password=pw, dsn=dsn) as conn:
                cursor = conn.cursor()
                cursor.execute(sql)
                return
        except oracledb.DatabaseError as e:
            error_obj, = e.args
            if error_obj.code in package_state_errors and attempt < max_retries - 1:
                print(f"Package state error, retry {attempt + 1}")
                time.sleep(2 ** attempt)
                continue
            raise

実践シナリオ

シナリオ1:本番緊急対応

-- 1. 発生確認
SELECT sid, serial#, username, program, status
FROM v$session
WHERE status = 'ACTIVE';

-- 2. Shared Pool フラッシュ
SQL> CONN / AS SYSDBA
SQL> ALTER SYSTEM FLUSH SHARED_POOL;

-- 3. パッケージ再コンパイル
ALTER PACKAGE app.my_pkg COMPILE BODY;

-- 4. INVALID 一括修復
BEGIN
  UTL_RECOMP.recomp_parallel(4, 'APP');
END;
/

-- 5. アプリ側リトライで自動回復確認

シナリオ2:Oracle EBS Workflow 対応

-- 1. 影響オブジェクト特定
SELECT owner, object_name, status
FROM dba_objects
WHERE status = 'INVALID' AND owner = 'APPS';

-- 2. Concurrent Manager 停止
-- $ $COMMON_TOP/admin/scripts/$SID/adstpall.sh apps/apps

-- 3. Shared Pool フラッシュ
SQL> CONN / AS SYSDBA
SQL> ALTER SYSTEM FLUSH SHARED_POOL;

-- 4. APPS 再コンパイル
BEGIN
  UTL_RECOMP.recomp_parallel(4, 'APPS');
END;
/

-- 5. Notification Mailer 再起動

シナリオ3:Spring Boot での耐障害設計

@Configuration
@EnableRetry
public class RetryConfig {
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate template = new RetryTemplate();
        
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(1000);
        template.setBackOffPolicy(backOffPolicy);
        
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(3);
        template.setRetryPolicy(retryPolicy);
        
        return template;
    }
}

@Service
public class PackageService {
    @Autowired
    private RetryTemplate retryTemplate;
    
    public void callPackage() {
        retryTemplate.execute(context -> {
            jdbcTemplate.execute("{call my_pkg.proc_a}");
            return null;
        });
    }
}

シナリオ4:Rails 接続プール管理

# config/initializers/oracle_retry.rb
class OracleRetryMiddleware
  def initialize(app)
    @app = app
  end
  
  def call(env)
    @app.call(env)
  rescue ActiveRecord::StatementInvalid => e
    if package_state_error?(e)
      # 接続プール全リセット
      ActiveRecord::Base.connection_pool.disconnect!
      # リトライ
      @app.call(env)
    else
      raise
    end
  end
  
  private
  
  def package_state_error?(e)
    [4065, 4068, 4061].any? { |code| e.message.include?("ORA-#{code.to_s.rjust(5, '0')}") }
  end
end

シナリオ5:Oracle datapatch 対処

# 1. パッチ適用試行
$ORACLE_HOME/OPatch/datapatch -verbose

# 2. エラー確認(4068/4061/4065 出た場合)
tail -100 /u01/app/oracle/cfgtoollogs/sqlpatch/*.log

# 3. datapatch 再実行(Oracle 公式推奨)
$ORACLE_HOME/OPatch/datapatch -verbose

# 4. 通常 2 回目で成功

シナリオ6:CI/CD パイプライン統合

- name: Deploy PL/SQL (safe)
  run: |
    # 1. アプリ停止
    kubectl scale deployment app --replicas=0
    sleep 30  # 接続クローズ待機
    
    # 2. パッケージデプロイ
    sqlplus $DB_USER/$DB_PW <<EOF
    @deploy_packages.sql
    EOF
    
    # 3. INVALID 確認 & 修復
    sqlplus / as sysdba <<EOF
    BEGIN
      UTL_RECOMP.recomp_parallel(4);
    END;
    /
    SELECT COUNT(*) FROM dba_objects WHERE status = 'INVALID';
    EOF
    
    # 4. アプリ再起動
    kubectl scale deployment app --replicas=3

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

シナリオ7:Docker Oracle でのテスト

docker exec -it oracle-xe sqlplus scott/tiger <<EOF
CREATE OR REPLACE PACKAGE test_pkg AS
  PROCEDURE proc_a;
END;
/
CREATE OR REPLACE PACKAGE BODY test_pkg AS
  PROCEDURE proc_a IS
  BEGIN
    DBMS_OUTPUT.PUT_LINE('OK');
  END;
END;
/

BEGIN test_pkg.proc_a; END;
/
-- OK

-- 別セッションで再作成
-- CREATE OR REPLACE PACKAGE test_pkg AS ... END;

BEGIN test_pkg.proc_a; END;
/
-- ORA-04068 + 04061 + 04065

BEGIN test_pkg.proc_a; END;
/
-- 再実行で成功
EOF

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

シナリオ8:定期監視スクリプト

#!/bin/bash
# monitor_package_state.sh

# INVALID オブジェクト監視
invalid=$(sqlplus -s / as sysdba <<EOF
SET HEADING OFF FEEDBACK OFF
SELECT COUNT(*) FROM dba_objects WHERE status = 'INVALID';
EXIT;
EOF
)

if [ "$invalid" -gt "0" ]; then
  # 自動再コンパイル
  sqlplus / as sysdba <<EOF
  BEGIN
    UTL_RECOMP.recomp_parallel(4);
  END;
  /
EOF
fi

crontab の詳細は crontab 使い方の記事も参照してください。

シナリオ9:Python での実装

import oracledb
import logging
from functools import wraps

logger = logging.getLogger(__name__)

def retry_on_package_error(max_retries=3):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except oracledb.DatabaseError as e:
                    error_obj, = e.args
                    if error_obj.code in (4065, 4068, 4061):
                        logger.warning(f"Package state error, retry {attempt + 1}")
                        continue
                    raise
            raise Exception("Max retries exceeded")
        return wrapper
    return decorator

@retry_on_package_error(max_retries=3)
def call_stored_proc(cursor, proc_name):
    cursor.callproc(proc_name)

シナリオ10:Autonomous DB での対応

-- Autonomous DB でも同じ動作
-- 26ai 環境では新機能活用推奨

ALTER SYSTEM SET session_exit_on_package_state_error = TRUE;
-- パッケージ状態エラー時にセッション自動切断

トラブルシューティング

再実行しても直らない

Shared Pool フラッシュ or 依存カーソルパージ:

ALTER SYSTEM FLUSH SHARED_POOL;

頻発する場合

根本原因: グローバル状態を持つパッケージ、または業務中のデプロイ。設計見直し。

Shared Pool フラッシュの影響

キャッシュクリアでパフォーマンス低下、業務時間外推奨。

特定カーソルだけパージしたい

BEGIN
  DBMS_SHARED_POOL.PURGE('<address>,<hash>', 'C');
END;
/

EBR の導入コスト

設計変更大、慎重に計画。24時間運用では効果大。

PostgreSQL からの移行

PG は関数ベースでこの問題なし。移行時は状態管理見直し。


よくある質問(FAQ)

Q1. ORA-04065 と ORA-04061 の違い

  • 04065: altered/dropped で実行不可
  • 04061: 状態が invalidated

Q2. ORA-04068 との違い

  • 04068: 状態が discarded(実行時)
  • 04065: altered/dropped(実行拒否)

Q3. なぜ 3 兄弟でセット発生

パッケージ変更1 つのイベント3 種類のエラーとして表現される。

Q4. 再実行で解決するか

多くの場合 YES。Oracle が自動再初期化。

Q5. Shared Pool フラッシュのリスク

全キャッシュクリア、パフォーマンス影響大。

Q6. Rails での対応

リトライ + 接続プールリセット

Q7. Java での対応

Spring Retry or 手動リトライ

Q8. Oracle EBS での対処

Notification Mailer 停止 + Shared Pool フラッシュ + 再コンパイル

Q9. Oracle datapatch エラー

datapatch を再実行(Oracle 公式推奨)。

Q10. EBR の推奨環境

24時間運用無停止デプロイ必須。

Q11. Oracle 26ai 新機能

SESSION_EXIT_ON_PACKAGE_STATE_ERROR で自動切断。

Q12. 予防策

  • グローバル状態最小化
  • デプロイ順序管理
  • リトライロジック実装
  • EBR 検討

参考リンク

Oracle 公式


まとめ

ORA-04065: not executed, altered or dropped package の要点を再整理します。

エラーの本質

呼び出そうとしたパッケージが altered/dropped されている
→ Oracle が呼び出しを拒否
→ 通常 ORA-04068 + ORA-04061 とセットで発生
→ ORA-06508 も併発

エラーメッセージの読み方

ORA-04065: not executed, altered or dropped package "SCHEMA.PACKAGE"
                                                     ↑
                                        変更/削除されたパッケージ

パッケージ状態エラー3兄弟

エラー意味タイミング
ORA-04068DISCARDED(破棄)実行時
ORA-04061INVALIDATED(無効化)コンパイル時検出
ORA-04065altered/dropped実行拒否
ORA-06508プログラムユニット発見不可併発

10大原因

#原因対処
パッケージ再コンパイル中再実行
Oracle EBS Workflowadadmin
IFS ERP + SSISリトライ
Oracle datapatch再実行
Spring Boot JavaSpring Retry
OIC Database Adapterリトライ設定
CI/CD デプロイアプリ停止
Rails migration接続プールリセット
共通ライブラリ更新一括再コンパイル
TYPE / OBJECT 削除再作成 + COMPILE

6つの解決策

-- ① 再実行(Oracle 自動回復)
BEGIN my_pkg.proc_a; END;

-- ② Shared Pool フラッシュ(緊急)
ALTER SYSTEM FLUSH SHARED_POOL;

-- ③ 依存カーソルパージ
DBMS_SHARED_POOL.PURGE('<addr>,<hash>', 'C');

-- ④ パッケージ再コンパイル
ALTER PACKAGE my_pkg COMPILE;
UTL_RECOMP.recomp_parallel(4);

-- ⑤ Edition-Based Redefinition
CREATE EDITION new_edition;
ALTER SESSION SET EDITION = new_edition;

-- ⑥ 26ai 新機能
ALTER SYSTEM SET session_exit_on_package_state_error = TRUE;

各言語での対応

Rails:   リトライ + connection_pool.disconnect!
Java:    Spring Retry + errorCode 判定
Python:  DatabaseError.code チェック + リトライ
共通:    接続再取得ロジック実装

予防のポイント

1. グローバル状態を最小化
2. PRAGMA SERIALLY_REUSABLE 活用
3. リトライロジック実装
4. デプロイ順序管理(アプリ停止)
5. Rails 接続プールリセット
6. EBR 検討(24時間運用)
7. 26ai の新機能活用
8. 定期的な INVALID オブジェクト監視
9. Oracle EBS は Vendor 手順遵守
10. Oracle datapatch は 2 回実行前提

これらの知識は、Oracle での PL/SQL 開発・パッケージ設計・DBA 運用・Oracle EBS 管理・IFS ERP 運用・Rails / Java / Python アプリ運用・CI/CD パイプライン・24時間運用・データベースアップグレードなど、あらゆる場面で活用できます。本記事をブックマークしておけば、ORA-04065 に出会っても冷静に的確に対処できるようになります。


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