【完全ガイド】PLS-00201: identifier must be declared の原因と解決方法|ロール経由権限の罠・DBMS_LOCK・シノニム 徹底解説

【完全ガイド】PLS-00201: identifier must be declared の原因と解決方法|ロール経由権限の罠・DBMS_LOCK・シノニム 徹底解説

Oracle PL/SQL 開発者・DBA が必ず一度は遭遇するコンパイルエラー:

Warning: Procedure created with compilation errors.

SQL> SHOW ERRORS
Errors for PROCEDURE MY_PROC:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/3      PL/SQL: Statement ignored
5/3      PLS-00201: identifier 'DBMS_LOCK.SLEEP' must be declared

「識別子が宣言されていない」というシンプルなメッセージ。しかし、実際には極めて多岐にわたる原因があり、特に**「権限はあるはずなのに失敗する」というロール経由権限の罠**が Oracle 特有の悪名高い問題として知られています:

  • 未宣言の変数(初学者頻出)
  • 変数名のスペルミス
  • スコープ外の参照
  • GRANT EXECUTE 権限不足
  • シノニム不足DBMS_LOCK, DBMS_SYSTEM 等)
  • ロール経由の権限(コンパイル時無効)← 最も難解な罠
  • 予約語との衝突
  • 引用符付き識別子(case-sensitive)
  • パッケージ本体で外部参照
  • INVALID オブジェクトへの参照

このエラーはPL/SQL コンパイル時に発生するため、SQL 実行時の ORA-00904 (invalid identifier) とは根本的に異なります:

PLS-00201: PL/SQL コンパイル時(オブジェクト作成/変更時)
ORA-00904: SQL 実行時(クエリ実行時)
ORA-06550: PL/SQL 実行時(無名ブロック等)

現場では、特にエンタープライズシステムで**「昨日まで動いていたのに」**と嘆く典型的エラーです:

シナリオ: E-Business Suite でパッケージ再コンパイル
Warning: Package Body altered with compilation errors.
PLS-00201: identifier 'SYS.DBMS_SYS_SQL' must be declared

多くの日本語記事が「変数を宣言せよ」で終わりますが、実務では:

  • GRANT EXECUTE が必要な場合
  • ロール経由の権限は無効というOracle の重要な原則
  • DEFINER'S RIGHTS vs INVOKER'S RIGHTS(AUTHID)
  • シノニム作成DBMS_LOCK, DBMS_SYSTEM, DBMS_SYS_SQL
  • ALTER USER ... GRANT CONNECT THROUGH の活用
  • ORA-06550 との併発の解釈
  • Rails / Java アプリでの発生
  • CI/CD パイプラインでの事前検出

さらに、Oracle の “ロール経由権限がコンパイル時に効かない” ルールは、多くの開発者を深い混乱に陥れます:

-- APPL ユーザーで実行
-- ロール DEV_ROLE 経由で EXECUTE 権限がある
GRANT EXECUTE ON COMN.PRC_EOD TO DEV_ROLE;
GRANT DEV_ROLE TO APPL;

-- SQL 実行時は動く
BEGIN COMN.PRC_EOD; END;  -- OK

-- でも PL/SQL 内で使うと失敗
CREATE PROCEDURE MY_PROC IS
BEGIN
  COMN.PRC_EOD;   -- PLS-00201
END;
/

「なぜ?」の答え: Oracle の PL/SQL コンパイルは、ロール経由の権限を無効化するため。直接権限が必須です。

本記事では、PLS-00201: identifier must be declared完全な原因と解決方法を、リファレンスとして実用的に整理します。10大発生パターン、ORA-00904/ORA-06550 との違い、5つの解決策、DEFINER’S RIGHTS vs INVOKER’S RIGHTS、Rails/Java/Python 対応、実践シナリオ、FAQまで完全網羅。この1本で PLS-00201 を根本から解決できるようになります。


目次

結論:宣言 or 権限 が必要

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

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

PLS-00201: identifier 'X' must be declared
                       ↑
                識別子 X が宣言されていない
                = 未宣言 or 見えない

識別子の意味:

  • 変数 / 定数
  • プロシージャ / ファンクション / パッケージ
  • テーブル / ビュー
  • タイプ

最速の診断

-- ① オブジェクト存在確認
SELECT owner, object_name, object_type, status
FROM all_objects
WHERE object_name = UPPER('X');

-- ② 権限確認(直接権限のみ)
SELECT * FROM user_tab_privs 
WHERE table_name = UPPER('X');

-- ③ シノニム確認
SELECT * FROM all_synonyms
WHERE synonym_name = UPPER('X');

5つの解決策

#手法使う場面
変数宣言未宣言変数
GRANT EXECUTE権限不足
シノニム作成スキーマ違い
ロール → 直接権限ロール経由の罠
スキーマプレフィックス明示的参照

3つの姉妹エラー

エラータイミング意味
PLS-00201PL/SQL コンパイル識別子未宣言
ORA-00904SQL 実行時列名等の識別子無効
ORA-06550PL/SQL 実行時ライン/カラム位置

PLS-00201 は必ず ORA-06550 と併発(コンパイル時)。

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


PL/SQL コンパイル vs SQL 実行の違い

PLS-00201 発生タイミング

オブジェクト作成/変更時:

CREATE OR REPLACE PROCEDURE my_proc IS
BEGIN
  DBMS_LOCK.SLEEP(1);  -- ← PLS-00201 の可能性
END;
/
-- Warning: Procedure created with compilation errors.

無名ブロック実行時:

BEGIN
  DBMS_LOCK.SLEEP(1);   -- ← ORA-06550 + PLS-00201
END;
/

通常の SQL:

-- SQL 実行時は権限があれば動く
BEGIN COMN.PRC_EOD; END;   -- OK(ロール経由でも)

決定的違い

SQL 実行時: ロール経由の権限で動く
PL/SQL コンパイル時: ロール経由の権限は無効

理由: PL/SQL は「事前コンパイル」される
     ロールは動的、コンパイル時に決まらない

この違いが混乱の元


【原因①】未宣言の変数(初学者頻出)

症状

DECLARE
  v_id NUMBER;
BEGIN
  SELECT id INTO v_id FROM t;
  DBMS_OUTPUT.PUT_LINE(v_name);  -- ← 未宣言
END;
/
-- PLS-00201: identifier 'V_NAME' must be declared

解決

DECLARE
  v_id NUMBER;
  v_name VARCHAR2(100);  -- 宣言
BEGIN
  SELECT id, name INTO v_id, v_name FROM t;
  DBMS_OUTPUT.PUT_LINE(v_name);
END;
/

【原因②】変数名のスペルミス

症状

DECLARE
  v_customer_name VARCHAR2(100);
BEGIN
  v_costomer_name := 'John';  -- ← タイポ
END;
/
-- PLS-00201: identifier 'V_COSTOMER_NAME' must be declared

解決

タイポ修正、IDE のオートコンプリート活用。


【原因③】スコープ外の参照

症状

DECLARE
  v_outer NUMBER;
BEGIN
  DECLARE
    v_inner NUMBER;
  BEGIN
    v_inner := 1;
  END;
  
  v_inner := 2;  -- ← スコープ外
END;
/
-- PLS-00201

解決

スコープを意識:

DECLARE
  v_outer NUMBER;
  v_inner NUMBER;   -- 外側で宣言
BEGIN
  v_inner := 1;
  v_inner := 2;   -- OK
END;
/

【原因④】ロール経由の権限(超危険な罠)

シナリオ

-- SYS 側で権限付与
GRANT EXECUTE ON dbms_lock TO dev_role;
GRANT dev_role TO app_user;

-- app_user で確認
SELECT * FROM session_roles;
-- DEV_ROLE が有効

-- SQL 実行は OK
BEGIN dbms_lock.sleep(1); END;
/
-- 正常終了

-- PL/SQL コンパイルは失敗
CREATE OR REPLACE PROCEDURE my_proc IS
BEGIN
  dbms_lock.sleep(1);
END;
/
-- PLS-00201: identifier 'DBMS_LOCK.SLEEP' must be declared

原因

Oracle の重要ルール:

PL/SQL コンパイル時は、ロール経由の権限が無効化される。直接権限のみ有効。

解決

直接権限を付与:

-- ロール経由でなく、ユーザーに直接
GRANT EXECUTE ON dbms_lock TO app_user;
-- これで PL/SQL コンパイルも動く

診断クエリ

-- 直接権限のみ
SELECT * FROM user_tab_privs 
WHERE table_name = 'DBMS_LOCK';

-- ロール経由の権限
SELECT * FROM role_tab_privs
WHERE table_name = 'DBMS_LOCK';
-- こちらはあっても PL/SQL では無効

【原因⑤】シノニム不足(DBMS_LOCK, DBMS_SYSTEM)

症状

CREATE OR REPLACE PROCEDURE trace_enable IS
BEGIN
  dbms_system.set_ev(...);   -- ← PLS-00201
END;
/

原因

DBMS_SYSTEM は SYS スキーマ限定、パブリックシノニム未作成。

解決

-- SYS で実行
CREATE PUBLIC SYNONYM dbms_system FOR sys.dbms_system;
GRANT EXECUTE ON dbms_system TO app_user;
-- または PUBLIC 全体に
GRANT EXECUTE ON dbms_system TO PUBLIC;

同様のケース

DBMS_LOCK      → シノニム + GRANT
DBMS_SYS_SQL   → シノニム + GRANT
DBMS_SYSTEM    → シノニム + GRANT
UTL_RAW        → 通常はデフォルト有効

権限系は ORA-01031: insufficient privileges の記事も参照してください。


【原因⑥】スキーマ違い

症状

APPL ユーザーから COMN スキーマのプロシージャ:

-- APPL ユーザー
CREATE OR REPLACE PROCEDURE my_proc IS
BEGIN
  prc_eod_processing;   -- ← COMN.PRC_EOD_PROCESSING
END;
/
-- PLS-00201

解決A: スキーマプレフィックス

COMN.prc_eod_processing;

解決B: シノニム作成

-- APPL 側で
CREATE SYNONYM prc_eod_processing FOR comn.prc_eod_processing;

-- または PUBLIC
CREATE PUBLIC SYNONYM prc_eod_processing FOR comn.prc_eod_processing;

解決C: EXECUTE 権限

-- COMN 側で
GRANT EXECUTE ON prc_eod_processing TO appl;

【原因⑦】INVALID オブジェクト

症状

SELECT status FROM user_objects 
WHERE object_name = 'MY_PKG';
-- INVALID

-- 使うと
BEGIN my_pkg.some_proc; END;
/
-- PLS-00201(見えない状態)

解決

再コンパイル:

ALTER PACKAGE my_pkg COMPILE;
ALTER PACKAGE my_pkg COMPILE BODY;

-- 一括
BEGIN
  DBMS_UTILITY.COMPILE_SCHEMA('APPL');
END;
/

-- または
EXEC UTL_RECOMP.recomp_serial('APPL');

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


【原因⑧】DEFINER’S vs INVOKER’S RIGHTS

概念

DEFINER’S RIGHTS(デフォルト):

  • パッケージ所有者の権限で実行
  • 所有者に直接権限必要

INVOKER’S RIGHTS (AUTHID CURRENT_USER):

  • 呼び出し元の権限で実行
  • 動的な権限判定

-- DEFINER'S RIGHTS(デフォルト)
CREATE OR REPLACE PROCEDURE p1 IS
BEGIN
  ...
END;
/

-- INVOKER'S RIGHTS
CREATE OR REPLACE PROCEDURE p2 AUTHID CURRENT_USER IS
BEGIN
  ...
END;
/

使い分け

DEFINER'S:
  ✓ 通常のビジネスロジック
  ✓ 権限はパッケージ所有者に集中
  
INVOKER'S:
  ✓ 汎用ユーティリティ
  ✓ 複数スキーマから呼ばれる
  ✗ ロール経由でも動く(12c+)

【原因⑨】予約語との衝突

症状

DECLARE
  level NUMBER := 1;   -- ← LEVEL は疑似列
BEGIN
  DBMS_OUTPUT.PUT_LINE(level);
END;
/
-- 意図と異なる、または PLS-00201

解決

変数名を変更:

DECLARE
  v_level NUMBER := 1;
BEGIN
  DBMS_OUTPUT.PUT_LINE(v_level);
END;
/

予約語関連は ORA-00904: invalid identifier の記事も参照してください。


【原因⑩】引用符付き識別子

症状

Rails マイグレーションで作成されたテーブル:

CREATE TABLE users ("createdAt" TIMESTAMP);
-- 引用符付き = case-sensitive

CREATE OR REPLACE PROCEDURE p IS
  v_at users.createdAt%TYPE;
  -- Oracle は CREATEDAT に大文字化して検索
  -- しかし実列名は "createdAt"
BEGIN
  ...
END;
/
-- PLS-00201

解決

A. 引用符付きで参照:

v_at users."createdAt"%TYPE;

B. 列名を標準化(推奨):

ALTER TABLE users RENAME COLUMN "createdAt" TO created_at;

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

解決策① 変数宣言

DECLARE
  v_name VARCHAR2(100);   -- 明示的宣言
BEGIN
  v_name := 'John';
END;
/

解決策② GRANT EXECUTE

-- 直接権限(PL/SQL では必須)
GRANT EXECUTE ON dbms_lock TO app_user;
GRANT EXECUTE ON comn.prc_eod TO appl;

解決策③ シノニム作成

-- パブリック
CREATE PUBLIC SYNONYM dbms_lock FOR sys.dbms_lock;

-- プライベート
CREATE SYNONYM my_pkg FOR other_schema.my_pkg;

解決策④ ロール → 直接権限

-- ❌ ロール経由(PL/SQL 無効)
GRANT dev_role TO app_user;
GRANT EXECUTE ON dbms_lock TO dev_role;

-- ✅ 直接権限
GRANT EXECUTE ON dbms_lock TO app_user;

解決策⑤ スキーマプレフィックス

-- 明示的にスキーマ指定
comn.prc_eod_processing;
sys.dbms_lock.sleep(1);

Rails / Java / Python 対応

Rails ActiveRecord

ストアド呼び出し時のエラー:

begin
  ActiveRecord::Base.connection.execute("BEGIN dbms_lock.sleep(1); END;")
rescue ActiveRecord::StatementInvalid => e
  if e.message.include?("PLS-00201")
    Rails.logger.error "権限またはシノニム不足: #{e.message}"
    # 対処: DBA に GRANT EXECUTE 依頼
  end
end

マイグレーションでの権限付与:

class GrantExecuteToApp < ActiveRecord::Migration[8.0]
  def up
    execute "GRANT EXECUTE ON dbms_lock TO app_user"
  end
end

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

Java (JDBC)

try {
    stmt.execute("BEGIN dbms_lock.sleep(1); END;");
} catch (SQLException e) {
    if (e.getMessage().contains("PLS-00201")) {
        logger.error("権限不足: " + e.getMessage());
    }
}

Python (oracledb)

import oracledb

try:
    cursor.execute("BEGIN dbms_lock.sleep(1); END;")
except oracledb.DatabaseError as e:
    error_obj, = e.args
    if "PLS-00201" in error_obj.message:
        print(f"権限不足: {error_obj.message}")

実践シナリオ

シナリオ1:本番デプロイ時の PLS-00201 対策

-- 事前チェックスクリプト
SELECT o.owner, o.object_name, o.object_type, o.status
FROM user_objects o
WHERE o.status = 'INVALID';

-- INVALID があれば再コンパイル
BEGIN
  DBMS_UTILITY.COMPILE_SCHEMA('APP_USER');
END;
/

-- 権限確認
SELECT * FROM user_tab_privs
WHERE grantee = 'APP_USER'
  AND privilege = 'EXECUTE';

シナリオ2:ロール経由権限のトラブルシューティング

-- 1. ロール経由の権限確認
SELECT * FROM role_tab_privs 
WHERE table_name = 'DBMS_LOCK';

-- 2. 直接権限確認
SELECT * FROM user_tab_privs 
WHERE table_name = 'DBMS_LOCK';

-- 3. 直接権限がなければ付与
GRANT EXECUTE ON dbms_lock TO app_user;

-- 4. 再コンパイル
ALTER PROCEDURE my_proc COMPILE;

シナリオ3:E-Business Suite での対処

-- APPS ユーザーで DBMS_SYSTEM 使う場合
SQL> CONN sys/pw AS SYSDBA
SQL> CREATE PUBLIC SYNONYM dbms_system FOR dbms_system;
SQL> GRANT EXECUTE ON dbms_system TO apps;

SQL> ALTER PACKAGE apps.fnd_trace COMPILE BODY;
-- コンパイル成功

シナリオ4:CI/CD パイプラインでの事前チェック

# .github/workflows/db-deploy.yml
- name: Compile check
  run: |
    sqlplus $DB_USER/$DB_PW <<EOF
    ALTER PACKAGE my_pkg COMPILE BODY;
    SHOW ERRORS
    EOF

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

シナリオ5:新スキーマ設定時のチェックリスト

-- スキーマ間の依存を全て EXECUTE 権限付与
BEGIN
  FOR r IN (
    SELECT owner, object_name, object_type
    FROM all_objects
    WHERE object_type IN ('PACKAGE', 'PROCEDURE', 'FUNCTION')
      AND owner = 'COMN'
  ) LOOP
    EXECUTE IMMEDIATE 
      'GRANT EXECUTE ON ' || r.owner || '.' || r.object_name || 
      ' TO appl';
  END LOOP;
END;
/

シナリオ6:Rails マイグレーションで権限管理

class SetupPermissions < ActiveRecord::Migration[8.0]
  def up
    execute "GRANT EXECUTE ON dbms_lock TO app_user"
    execute "GRANT EXECUTE ON dbms_utility TO app_user"
    execute "GRANT EXECUTE ON dbms_stats TO app_user"
  end
  
  def down
    execute "REVOKE EXECUTE ON dbms_lock FROM app_user"
    # ...
  end
end

シナリオ7:Docker Oracle での再現

docker exec -it oracle-xe sqlplus scott/tiger <<EOF
CREATE OR REPLACE PROCEDURE p IS
BEGIN
  dbms_lock.sleep(1);
END;
/
SHOW ERRORS
EOF

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

シナリオ8:Java Spring での対処

@Configuration
public class OraclePermissionInit {
    @Bean
    public CommandLineRunner init(JdbcTemplate jdbc) {
        return args -> {
            try {
                jdbc.execute("BEGIN dbms_lock.sleep(0); END;");
            } catch (Exception e) {
                if (e.getMessage().contains("PLS-00201")) {
                    logger.error("DBA に GRANT EXECUTE ON DBMS_LOCK 依頼");
                }
            }
        };
    }
}

シナリオ9:Autonomous DB での挙動

-- Autonomous DB では権限管理が制限的
-- 一部の SYS パッケージは admin ユーザーでも使えない
-- ADB 固有の代替方法を使う(DBMS_CLOUD 等)

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

-- INVALID オブジェクトの一括再コンパイル
BEGIN
  UTL_RECOMP.recomp_parallel(4, 'APP_SCHEMA');
END;
/

-- 権限の一括付与スクリプト
SELECT 'GRANT EXECUTE ON ' || object_name || ' TO app_user;' AS sql
FROM dba_objects
WHERE owner = 'SYS'
  AND object_name IN ('DBMS_LOCK', 'DBMS_SYSTEM', 'DBMS_UTILITY')
  AND object_type = 'PACKAGE';

トラブルシューティング

エラーが特定できない

SHOW ERRORS PACKAGE BODY my_pkg;
-- 行番号・列番号と共に表示

コンパイルは通るが実行時失敗

AUTHID CURRENT_USER の場合、呼び出し元の権限次第。

ロール経由権限の詳細確認

-- 現セッションのロール
SELECT * FROM session_roles;

-- 有効な権限
SELECT * FROM session_privs;

大文字小文字の混乱

-- 引用符付き列の検出
SELECT * FROM user_tab_columns 
WHERE table_name = 'YOUR_TABLE'
  AND column_name != UPPER(column_name);

動的 SQL での対処

動的 SQL は実行時判定、権限がロール経由でも OK:

EXECUTE IMMEDIATE 'BEGIN dbms_lock.sleep(1); END;';
-- ロール経由でも動く

PL/SQL 内で使いたければ動的 SQL も選択肢。

E-Business Suite での対応

Oracle 純正シノニム設定スクリプトを実行:

@?/rdbms/admin/utlrp.sql

よくある質問(FAQ)

Q1. PLS-00201 と ORA-00904 の違い

  • PLS-00201: PL/SQL コンパイル時
  • ORA-00904: SQL 実行時

Q2. なぜロール経由権限が効かない

PL/SQL は事前コンパイル、ロールは動的。コンパイル時に権限判定できない。

Q3. AUTHID CURRENT_USER で解決?

部分的に解決。ただし呼び出し元の権限次第。

Q4. DBMS_LOCK が使えない

SYSDBA でシノニム作成 + GRANT EXECUTEが必要。

Q5. Rails / Java での対応

DBA に権限依頼、または動的 SQL 活用。

Q6. 動的 SQL の使い所

ロール経由権限でも動く。パフォーマンスとの相談。

Q7. INVALID オブジェクトの一括再コンパイル

EXEC DBMS_UTILITY.COMPILE_SCHEMA('SCHEMA');

Q8. E-Business Suite での典型パターン

DBMS_SYSTEM, DBMS_SYS_SQL のシノニム/権限不足。

Q9. 予防策

  • 直接権限付与
  • 定期的な INVALID チェック
  • CI/CD で事前検証

Q10. Autonomous DB での制約

一部の SYS パッケージ使用不可、DBMS_CLOUD 等の代替を使う。

Q11. パフォーマンスへの影響

コンパイルエラーは実行不能、パフォーマンス以前の問題。

Q12. パブリックシノニムの権限

創らないと駄目GRANT EXECUTE だけでは不十分な場合あり。


参考リンク

Oracle 公式


まとめ

PLS-00201: identifier must be declared の要点を再整理します。

エラーの本質

PL/SQL コンパイル時に識別子が見つからない
→ 未宣言 or 見えない
→ 変数不足 or 権限不足 or スキーマ違い

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

PLS-00201: identifier 'X' must be declared
                       ↑
                識別子 X を宣言 or 権限付与

姉妹エラー

エラータイミング
PLS-00201PL/SQL コンパイル
ORA-00904SQL 実行時
ORA-06550PL/SQL 実行位置情報

10大原因

#原因対処
未宣言変数宣言
スペルミス修正
スコープ外外側で宣言
ロール経由権限直接権限
シノニム不足CREATE SYNONYM
スキーマ違いプレフィックス or シノニム
INVALID オブジェクト再コンパイル
DEFINER’S RIGHTSAUTHID CURRENT_USER
予約語変数名変更
引用符付き識別子引用符 or リネーム

5つの解決策

-- ① 変数宣言
DECLARE v_x NUMBER;

-- ② GRANT EXECUTE(直接権限)
GRANT EXECUTE ON pkg TO user;

-- ③ シノニム作成
CREATE PUBLIC SYNONYM pkg FOR schema.pkg;

-- ④ ロール → 直接
-- ❌ GRANT role_x TO user;
-- ✅ GRANT EXECUTE ON pkg TO user;

-- ⑤ スキーマプレフィックス
schema.pkg.proc;

ロール経由権限の重要ルール

SQL 実行時: ロール経由 OK
PL/SQL コンパイル時: 直接権限のみ

→ PL/SQL でパッケージ使うなら直接権限必須

DEFINER’S vs INVOKER’S RIGHTS

-- DEFINER'S(デフォルト)
CREATE PROCEDURE p IS BEGIN ... END;

-- INVOKER'S
CREATE PROCEDURE p AUTHID CURRENT_USER IS BEGIN ... END;

INVOKER’S はロール経由権限で動く(12c+)。

診断クエリ

-- ① 存在確認
SELECT * FROM all_objects WHERE object_name = 'X';

-- ② 直接権限
SELECT * FROM user_tab_privs WHERE table_name = 'X';

-- ③ ロール経由権限
SELECT * FROM role_tab_privs WHERE table_name = 'X';

-- ④ INVALID
SELECT * FROM user_objects WHERE status = 'INVALID';

-- ⑤ シノニム
SELECT * FROM all_synonyms WHERE synonym_name = 'X';

DBMS_LOCK 使用の設定

-- SYS で
CREATE PUBLIC SYNONYM dbms_lock FOR sys.dbms_lock;
GRANT EXECUTE ON dbms_lock TO app_user;
-- または PUBLIC

予防のポイント

1. 直接権限付与を徹底
2. 定期的な INVALID チェック
3. CI/CD で事前コンパイル検証
4. 引用符付き識別子を避ける
5. IDE のオートコンプリート
6. スキーマ設計時に権限設計
7. AUTHID の意識的な使い分け
8. Rails マイグレーションで権限管理
9. 動的 SQL の選択肢
10. スキーマ間の依存最小化

これらの知識は、Oracle での PL/SQL 開発・DBA 業務・権限管理・E-Business Suite 運用・Rails / Java / Python アプリ運用・CI/CD パイプライン・本番デプロイなど、あらゆる場面で活用できます。本記事をブックマークしておけば、PLS-00201 に出会っても冷静に的確に対処できるようになります。


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