Oracle で SQL を実行したとき、ORA-01031: insufficient privileges(権限が不十分です)が発生することがあります。このエラーは「操作に必要な権限がユーザーに付与されていない」ことを示しますが、原因は単純な権限未付与だけでなく、ロール経由の権限が PL/SQL 内で有効にならないという Oracle 特有の仕様が絡む場合があります。
この記事でわかること
- ORA-01031 が発生する主な原因パターン
- 現在の権限を USER_SYS_PRIVS / USER_TAB_PRIVS / SESSION_PRIVS で確認する方法
- ロール経由の権限が DEFINER RIGHTS の PL/SQL で無効になる理由と対処法
- GRANT 文でシステム権限・オブジェクト権限を付与する手順
- EXECUTE IMMEDIATE・動的 SQL での ORA-01031 のパターン
ORA-01031 が発生する主なパターン
| パターン | 典型的なケース | 対処法 |
|---|---|---|
| オブジェクト権限の未付与 | 他スキーマのテーブルへの SELECT・INSERT・UPDATE・DELETE・EXECUTE | GRANT SELECT ON owner.table_name TO user |
| システム権限の未付与 | CREATE TABLE・CREATE VIEW・ALTER SYSTEM など | GRANT CREATE TABLE TO user |
| PL/SQL でのロール権限無効 | ロール経由で付与された権限が DEFINER RIGHTS の PL/SQL 内で使えない | 権限を直接 GRANT する |
| ビュー・シノニムの参照エラー | ビューの基底テーブルや参照先スキーマへの権限がない | 基底テーブルへの権限を付与する |
| DDL の実行権限不足 | ALTER TABLE / DROP TABLE / TRUNCATE TABLE など | DBA または対象オブジェクトの所有者に依頼する |
現在の権限を確認する
現在のユーザーの権限を確認する
-- 現在ログイン中のユーザーを確認する SELECT USER FROM DUAL; -- システム権限(CREATE TABLE・CONNECT など)を確認する SELECT privilege, admin_option FROM USER_SYS_PRIVS ORDER BY privilege; -- オブジェクト権限(特定テーブルへの SELECT・INSERT など)を確認する SELECT owner, table_name, privilege, grantable FROM USER_TAB_PRIVS WHERE grantee = USER ORDER BY owner, table_name, privilege; -- 現在のセッションで有効な権限(ロール経由を含む)を確認する -- SESSION_PRIVS: ロール経由の権限も含めて現在セッションで有効な権限 SELECT privilege FROM SESSION_PRIVS ORDER BY privilege; -- 付与されているロールを確認する SELECT granted_role, default_role FROM USER_ROLE_PRIVS ORDER BY granted_role; -- ロール経由で付与されているオブジェクト権限を確認する(DBA 権限が必要) SELECT r.granted_role, tp.owner, tp.table_name, tp.privilege FROM USER_ROLE_PRIVS r JOIN ROLE_TAB_PRIVS tp ON r.granted_role = tp.role ORDER BY r.granted_role, tp.owner, tp.table_name;
最重要: ロール経由の権限が PL/SQL 内で有効にならない
Oracle の PL/SQL はデフォルトで DEFINER RIGHTS(定義者権限)で動作します。この場合、プロシージャ内ではロール経由で付与された権限が無効になり、直接 GRANT された権限のみが有効です。
具体的には: ユーザー A に DBA ロールが付与されていても、ユーザー A が所有するプロシージャ内で SELECT * FROM dba_objects などを実行するとORA-01031 が発生します。DBA ロールではなく、直接 SELECT ANY TABLE などが必要です。
ロール権限が PL/SQL で無効になるパターンと対処法
-- ユーザー APP_USER に CONNECT・RESOURCE ロールが付与されている
-- RESOURCE ロールには CREATE TABLE などの権限が含まれる
-- NG: ロール経由の権限でプロシージャ内の DDL は実行できない
CREATE OR REPLACE PROCEDURE create_temp_table AS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE work_temp (id NUMBER)';
-- ORA-01031 が発生する(RESOURCE ロール経由の CREATE TABLE は無効)
END;
/
-- 対処: CREATE TABLE 権限を直接 GRANT する
-- ※DBA がコマンドを実行する
GRANT CREATE TABLE TO app_user; -- ロール経由ではなく直接付与する
-- 確認: USER_SYS_PRIVS に CREATE TABLE が直接付与されているかどうか確認
SELECT privilege FROM USER_SYS_PRIVS WHERE privilege = 'CREATE TABLE';
-- 別テーブルを参照する場合もロール権限は無効
CREATE OR REPLACE PROCEDURE read_other_schema AS
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM other_schema.some_table;
-- ORA-01031 が発生する(ロール経由の SELECT 権限は DEFINER RIGHTS では無効)
END;
/
-- 対処: 直接権限を付与する(DBA または所有者が実行)
GRANT SELECT ON other_schema.some_table TO app_user;
-- AUTHID CURRENT_USER (INVOKER RIGHTS) にすれば呼び出し元の権限で動く
CREATE OR REPLACE PROCEDURE read_other_schema
AUTHID CURRENT_USER -- ← 呼び出しユーザーの権限(ロール含む)で実行される
AS
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM other_schema.some_table;
-- 呼び出しユーザーが other_schema.some_table の SELECT 権限を持っていれば成功する
END;
/
GRANT 文で権限を付与する
オブジェクト権限とシステム権限の GRANT
-- オブジェクト権限の付与(DBA または所有者が実行)
GRANT SELECT ON hr.employees TO app_user; -- 1テーブルへの SELECT
GRANT SELECT, INSERT, UPDATE ON hr.orders TO app_user; -- 複数権限の一括付与
GRANT SELECT ON hr.employees TO app_user WITH GRANT OPTION; -- 再付与権限付き
GRANT SELECT ANY TABLE TO app_user; -- 任意テーブルの SELECT(強力)
GRANT EXECUTE ON hr.process_pkg TO app_user; -- パッケージの実行権限
-- スキーマ内の全テーブルへの SELECT を一括付与する(PL/SQL ループ)
BEGIN
FOR t IN (SELECT table_name FROM dba_tables WHERE owner = 'HR') LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON HR.' || t.table_name || ' TO APP_USER';
END LOOP;
END;
/
-- システム権限の付与
GRANT CREATE SESSION TO app_user; -- ログイン権限
GRANT CREATE TABLE TO app_user; -- テーブル作成
GRANT CREATE VIEW TO app_user; -- ビュー作成
GRANT CREATE PROCEDURE TO app_user; -- プロシージャ・関数・パッケージ作成
GRANT CREATE SEQUENCE TO app_user; -- シーケンス作成
GRANT CREATE TRIGGER TO app_user; -- トリガー作成
-- 権限の剥奪
REVOKE SELECT ON hr.employees FROM app_user;
REVOKE CREATE TABLE FROM app_user;
-- 付与した権限を確認する(DBA 権限が必要)
SELECT grantee, owner, table_name, privilege, grantable
FROM DBA_TAB_PRIVS
WHERE owner = 'HR'
ORDER BY grantee, table_name;
まとめ
- ORA-01031 の主な原因:オブジェクト権限(SELECT・EXECUTE など)またはシステム権限(CREATE TABLE など)が未付与。または PL/SQL でのロール権限の制限
- 権限確認:USER_SYS_PRIVS(直接付与のシステム権限)・USER_TAB_PRIVS(オブジェクト権限)・SESSION_PRIVS(ロール経由も含む有効な権限)で確認する
- DEFINER RIGHTS(デフォルト):PL/SQL はロール経由の権限が無効。直接 GRANT が必要。ロールを使いたい場合は AUTHID CURRENT_USER(INVOKER RIGHTS)に変更する
- GRANT の対象:特定テーブルへの権限は所有者または DBA が GRANT する。SELECT ANY TABLE などのシステム権限は DBA のみが付与できる
- ビュー・シノニム:アクセス先がビューやシノニムの場合、基底テーブルへの権限も必要な場合がある
権限管理全般については Oracle VPD(Virtual Private Database)完全ガイドも参照してください。PL/SQL の AUTHID(定義者権限と呼び出し者権限)の詳細は Oracle パッケージ完全ガイドも参照してください。