権限まわりのエラーは、データベースの構築や運用で繰り返し出会うものです。
その代表が ORA-01031「権限が不足しています」で、システム権限(CREATE TABLE のような操作を行う権利)が足りないときに出ます。
足りない権限を GRANT すれば解消する、それだけのエラーに見えます。
ただ、実際の切り分けは、それほど単純ではありません。
同じ「権限が足りない」ように見える失敗でも、原因によって番号は3つに分かれます。
さらに、ORA-01031 でつまずきやすいのが、次のようなケースです。
「必要な権限は GRANT してもらったはずなのに、ストアドプロシージャを実行すると ORA-01031 で失敗する」。
同じ SQL を SQL*Plus で直接打つと、成功する。
しかし、プロシージャの中では確かに「権限が不足しています」になる…。
ORA-01031 には、権限の付与のされ方によって、同じユーザーの同じ SQL が成功したり失敗したりする条件があります。
今回は、Oracle Database 19c の実機でこれらを1つずつ再現し、切り分けの型を整理します。
具体的には、次の3点を実機ログで確認します。
- 「権限が足りない」失敗が、ORA-01031・ORA-00942・ORA-01950 の3つの番号に分かれること
- 対話では成功する SQL が、ストアドプロシージャの中でだけ ORA-01031 になる条件(ロール経由の権限)
- 権限の有無と出どころ(直接付与かロール経由か)を調べるビューの使い方
1. 症状
CREATE TABLE などの SQL を実行すると、次のエラーで失敗します。
CREATE TABLE t_direct (c1 NUMBER)
*
行1でエラーが発生しました。:
ORA-01031: 権限が不足していますメッセージは「権限が不足しています」とだけ示し、どの権限が足りないのかは表示されません。
また、権限まわりの失敗がすべてこの番号になるわけではない、という点が調査を混乱させます。
※先頭のゼロを省いて ORA-1031 と表記されることもありますが、同じエラーを指します。
2. 原因の仕組み
ORA-01031 は、システム権限の不足を示すエラーです。
システム権限とは、CREATE TABLE・CREATE VIEW・ALTER SYSTEM のように、「その種類の操作を行ってよいか」を決める権限です。
このエラーが出ている時点で、ログイン(認証)はすでに成功しています。
ユーザー名やパスワードの段階で失敗する ORA-01017 とは層が異なり、「あなたが誰かは確認できた。しかし、その操作をする権利がない」という状態です。
ただし、「権限が足りない」ように見える失敗が、すべてこの番号になるわけではありません。
足りないものの種類によって、エラー番号は次の3つに分かれます。
| 番号 | メッセージ(19c 実機) | 足りないもの | 典型的な状況 |
|---|---|---|---|
| ORA-01031 | 権限が不足しています | システム権限(操作の権利) | CREATE TABLE などの DDL が拒否される |
| ORA-00942 | 表またはビューが存在しません。 | オブジェクト権限(他人の表へのアクセス) | 実在する他人の表が見えない |
| ORA-01950 | 表領域’XX’に対する権限がありません | 表領域の割当(QUOTA) | 表は作れたのに INSERT できない |
※メッセージ中の XX の部分には、実際の表領域名が入ります。
番号が分かれている以上、番号を確認すれば「何が足りないのか」の種類まで絞れます。
このため、権限まわりの調査は「GRANT が足りないのでは」と当てずに進めるのではなく、まず番号で「足りないものの種類」を確定するところから始めます。
メッセージから読み取れる情報の量も、番号ごとに異なります。
最も少ない ORA-00942 は、権限がないことすら示さず、オブジェクトの存在ごと隠します(実在を隠す点は、ユーザーの存在を示さない ORA-01017 と共通です)。
ORA-01031 は「権限が足りない」とだけ示します。
最も多い ORA-01950 は、「表領域’XX’に対する」と対象を名指しで示します。
どこまで示されるかが異なるため、番号ごとに調査の入り口も変わります。
次の章から、この3つを実機で再現します。
その後、「持っているはずの権限が、プロシージャの中でだけ効かない」条件に進みます。
3. 「権限が足りない」の3つの番号を実機で再現する
3-1. 検証環境
検証は次の環境で行いました。
- Oracle Database 19c Enterprise Edition・非CDB構成(バージョンは 19.28。四半期ごとの更新パッチ=RU の適用後番号です)
- Oracle Linux 8・SQL*Plus 19c(エラーメッセージは日本語表示の設定)
検証用のユーザーは2つ作成します。
1つ目の TS01031 には、接続に必要な CREATE SESSION 権限だけを付与します。
デフォルト表領域(表領域を指定せずにオブジェクトを作ったときの格納先)には、標準的な構成のデータベースに最初から用意されている USERS を指定します。
USERS への割当(QUOTA)は、あえて付けません(あとで ORA-01950 を再現するためです)。
もう1つの TS01031X は「他人の表の持ち主」役で、マーカー行を1行だけ入れた表 secret_data を持たせておきます。
SQL> CREATE USER ts01031 IDENTIFIED BY "Ts01031#Lab" DEFAULT TABLESPACE users;
ユーザーが作成されました。
SQL> GRANT CREATE SESSION TO ts01031;
権限付与が成功しました。3-2. 権限なしの CREATE TABLE → ORA-01031
作成した TS01031 で接続し、まず自分が持っている権限を確認します。
SESSION_PRIVS ビュー(自分のセッションで有効なシステム権限の一覧。特別な権限なしで参照できます)を使います。
SQL> CONNECT ts01031/"Ts01031#Lab"
接続されました。
SQL> SELECT * FROM session_privs;
PRIVILEGE
----------------------------------------
CREATE SESSIONCREATE SESSION の1行だけ、つまり「接続はできるが、それ以外の操作の権利はない」状態です。
この状態で表を作ってみます。
SQL> CREATE TABLE t_direct (c1 NUMBER);
CREATE TABLE t_direct (c1 NUMBER)
*
行1でエラーが発生しました。:
ORA-01031: 権限が不足していますCREATE TABLE というシステム権限を持っていないため、ORA-01031 で拒否されました。
3-3. GRANT すると、同じコマンドが成功する
SYSDBA で CREATE TABLE 権限を付与し、同じコマンドを再実行します。
SQL> CONNECT / AS SYSDBA
接続されました。
SQL> GRANT CREATE TABLE TO ts01031;
権限付与が成功しました。TS01031 で接続し直して、権限の変化を確認してから同じ CREATE TABLE を実行します。
SQL> CONNECT ts01031/"Ts01031#Lab"
接続されました。
SQL> SELECT * FROM session_privs;
PRIVILEGE
----------------------------------------
CREATE SESSION
CREATE TABLESQL> CREATE TABLE t_direct (c1 NUMBER);
表が作成されました。SESSION_PRIVS に CREATE TABLE が増え、先ほどと同じコマンドが成功しました。
権限がない→付与する→同じ操作が通る、という ORA-01031 の基本形です。
3-4. 表は作れたのに INSERT できない → ORA-01950
続けて、作った表にデータを入れてみます。
SQL> INSERT INTO t_direct VALUES (1);
INSERT INTO t_direct VALUES (1)
*
行1でエラーが発生しました。:
ORA-01950: 表領域'USERS'に対する権限がありません今度は ORA-01031 ではなく、ORA-01950 が返りました。
t_direct は表領域を指定せずに作成したので、格納先は TS01031 のデフォルト表領域である USERS です。
CREATE TABLE の権限(操作の権利)と、表領域の割当(QUOTA=その表領域に何バイトまで使ってよいか)は別管理で、このユーザーには USERS の割当を付けていないためです。
注意したいのは、割当がないのに CREATE TABLE 自体は成功していた点です。
今回の環境では、CREATE TABLE を実行した時点では表の定義(表の名前や列の構成)が登録されるだけで、データを入れるための実体の領域(セグメント)は、まだ表領域に確保されません。
実体の領域が確保されるのは、最初のデータ挿入のときです。
この「実体の確保をデータ挿入まで遅らせる」動作は遅延セグメント作成と呼ばれ、19c ではデフォルトで有効です。
QUOTA のチェックが働くのは実体の領域を確保する瞬間のため、この不足は表を作った時点では気づけず、最初の INSERT で発覚します。
なお、遅延セグメント作成は Enterprise Edition の機能です(『Oracle Databaseライセンス情報ユーザー・マニュアル』に記載)。
Standard Edition 2 では利用できないため、この「作成の時点では気づけない」流れは Enterprise Edition を前提とした動作です。
割当を付与すると、同じ INSERT が成功します。
SQL> CONNECT / AS SYSDBA
接続されました。
SQL> ALTER USER ts01031 QUOTA 10M ON users;
ユーザーが変更されました。
SQL> CONNECT ts01031/"Ts01031#Lab"
接続されました。
SQL> INSERT INTO t_direct VALUES (1);
1行が作成されました。3-5. 他人の表が見えない → ORA-00942
次に、TS01031 のまま、別ユーザー TS01031X が持つ表を読んでみます。
この表は検証の準備で実際に作成してあり、マーカー行が1行入っています。
SQL> SELECT * FROM ts01031x.secret_data;
SELECT * FROM ts01031x.secret_data
*
行1でエラーが発生しました。:
ORA-00942: 表またはビューが存在しません。実在する表なのに、「存在しません」と返りました。
ORA-01031 は出ません。
他人のオブジェクトへのアクセスに必要なのはオブジェクト権限(その表への SELECT など)で、これがない場合、そのオブジェクトは存在ごと見えない扱いになります。
この「実在しても隠す」応答の背景にある考え方は、認証の失敗理由を明かさない ORA-01017 の記事で取り上げています。
この表への SELECT 権限(オブジェクト権限)を付与すると、同じ SELECT が通ります。
SQL> CONNECT / AS SYSDBA
接続されました。
SQL> GRANT SELECT ON ts01031x.secret_data TO ts01031;
権限付与が成功しました。
SQL> CONNECT ts01031/"Ts01031#Lab"
接続されました。
SQL> SELECT * FROM ts01031x.secret_data;
MEMO
------------------------------
marker_x_row3-6. 切り分け表
ここまでの結果を一覧にまとめます。
ログオン時の隣接エラーも1行加えています。
| エラー番号 | メッセージ(19c 実機) | 足りないもの | 対処 |
|---|---|---|---|
| ORA-01031 | 権限が不足しています | システム権限 | GRANT(付与の方法に注意=次章) |
| ORA-00942 | 表またはビューが存在しません。 | オブジェクト権限 | 対象への GRANT SELECT 等 |
| ORA-01950 | 表領域’XX’に対する権限がありません | 表領域の割当(QUOTA) | ALTER USER ~ QUOTA |
| ORA-01045 | ユーザーXXにはCREATE SESSION権限がありません。ログオンが拒否されました。 | ログオン時の CREATE SESSION | GRANT CREATE SESSION(ORA-01017 の記事で実機再現) |
※メッセージ中の XX の部分には、実際の表領域名・ユーザー名が入ります。
4. 対話では成功するのに、プロシージャの中では ORA-01031
ここからは、冒頭で挙げた「GRANT してもらったはずなのに、プロシージャの中でだけ ORA-01031」のケースです。
見出しの「対話」とは、SQL*Plus などで SQL を直接打って実行することを指します(プロシージャの中からの実行との対比で、この記事ではこう呼びます)。
権限を「持っているかどうか」だけでなく、「どの方法で付与されたか」で結果が変わることを再現します。
権限の付与には2つの方法があります。
ユーザーへ直接 GRANT する直接付与と、権限をまとめたロール(権限の入れ物。ロールをユーザーに付与すると、中の権限がまとめて使えるようになります)を経由する付与です。
ユーザーごとに権限を1つずつ GRANT するより、役割ごとに束ねたロールを付け外しするほうが管理しやすいため、運用ではロールで権限を管理する設計が一般的です。
ところが、この2つの方法は PL/SQL の中で挙動が分かれます。
4-1. 準備: 権限源をロールだけにする
まず、前の章で直接付与した CREATE TABLE をいったん取り消し、代わりに CREATE TABLE だけを持つロールを作って付与します。
これで、TS01031 の CREATE TABLE の権限源はロール経由だけになります。
あわせて、プロシージャの作成に必要な CREATE PROCEDURE は直接付与しておきます(検証の焦点を CREATE TABLE に絞るためです)。
SQL> CONNECT / AS SYSDBA
接続されました。
SQL> REVOKE CREATE TABLE FROM ts01031;
取消しが成功しました。
SQL> CREATE ROLE r_ts01031_ct;
ロールが作成されました。
SQL> GRANT CREATE TABLE TO r_ts01031_ct;
権限付与が成功しました。
SQL> GRANT r_ts01031_ct TO ts01031;
権限付与が成功しました。
SQL> GRANT CREATE PROCEDURE TO ts01031;
権限付与が成功しました。4-2. 対話ではロール経由の権限で成功する
TS01031 で接続し直し、権限の見え方と、対話での CREATE TABLE を確認します。
SQL> CONNECT ts01031/"Ts01031#Lab"
接続されました。
SQL> SELECT * FROM session_privs;
PRIVILEGE
----------------------------------------
CREATE SESSION
CREATE TABLE
CREATE PROCEDURESQL> CREATE TABLE t_interactive (c1 NUMBER);
表が作成されました。対話なら、ロール経由の CREATE TABLE で表を作れます。
そして注目したいのは SESSION_PRIVS の見え方です。
ロール経由の CREATE TABLE も、直接付与と区別されずに一覧に載ります。
つまり、SESSION_PRIVS に権限が見えていることは、この後のプロシージャでも使えることを意味しません。
4-3. 定義者権限プロシージャの中では ORA-01031 になる
同じユーザーで、CREATE TABLE を実行するだけのプロシージャを作って実行します。
AUTHID 句を書いていないため、このプロシージャはデフォルトの定義者権限(作成者の権限で動く方式)です。
CREATE OR REPLACE PROCEDURE proc_ct_by_role IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE t_from_proc (c1 NUMBER)';
END;
/作成は成功します(権限のチェックは実行時に行われるためです)。
実行すると、次のようになります。
SQL> EXEC proc_ct_by_role
BEGIN proc_ct_by_role; END;
*
行1でエラーが発生しました。:
ORA-01031: 権限が不足しています ORA-06512:
"TS01031.PROC_CT_BY_ROLE", 行3
ORA-06512: 行1※出力は端末の折り返しをそのまま載せています。
対話では成功した同じユーザーの同じ CREATE TABLE が、プロシージャの中では ORA-01031 で失敗しました。
これは不具合ではなく、文書化された動作です。
『Oracle Databaseセキュリティ・ガイド』の「定義者権限を持つ名前付きブロックで使用されるロール」の節に、「定義者権限で実行される名前付きPL/SQLブロックでは、すべてのロールは使用禁止になっています」と明記されています。
つまり、定義者権限のプロシージャ・ファンクション・トリガーの中では、ロール経由の権限は権限チェックに使われません。
なお、エラーに付いている ORA-06512 は発生位置を示す行です。
「行3」をデータディクショナリの USER_SOURCE と突き合わせると、EXECUTE IMMEDIATE の行が発生点だと確認できます(スタックの読み方は ORA-06512 の記事で整理しています)。
SQL> col TEXT for a100
SQL> select line,text from user_source where NAME in ('PROC_CT_BY_ROLE') order by LINE;
LINE TEXT
---------- ----------------------------------------------------------------------------------------------------
1 PROCEDURE proc_ct_by_role IS
2 BEGIN
3 EXECUTE IMMEDIATE 'CREATE TABLE t_from_proc (c1 NUMBER)';
4 END;また、効かなくなるのは、CREATE TABLE のようなシステム権限に限りません。
ロール経由で持っているオブジェクト権限(他人の表への SELECT など)も、定義者権限の PL/SQL の中では同様に使われません(ガイドの文言どおり「すべてのロール」が対象です)。
このパターンも実機で確認しています。
他人の表への SELECT 権限をロール経由だけにすると、対話では読めた同じ表が、定義者権限プロシージャの中では ORA-00942 になりました。
足りなくなるのがオブジェクト権限なので、番号は ORA-01031 ではなく、「存在ごと隠される」ORA-00942 側に合流します。
この場合も、SELECT 権限を直接 GRANT に変えれば、同じプロシージャが正常に完了します。
4-4. 直接付与に戻すと、同じプロシージャが成功する
プロシージャには一切手を加えず、権限の付与方法だけを直接付与に戻します。
SQL> CONNECT / AS SYSDBA
接続されました。
SQL> GRANT CREATE TABLE TO ts01031;
権限付与が成功しました。
SQL> CONNECT ts01031/"Ts01031#Lab"
接続されました。
SQL> EXEC proc_ct_by_role
PL/SQLプロシージャが正常に完了しました。プロシージャを1文字も変えず、付与の方法をロール経由から直接付与に変えただけで、成否が入れ替わりました。
表の一覧でも、プロシージャ内で作られた表が確認できます。
SQL> SELECT table_name FROM user_tables ORDER BY table_name;
TABLE_NAME
--------------------------------------------------------------------------------
T_DIRECT
T_FROM_PROC
T_INTERACTIVE「GRANT してもらったはずなのに、プロシージャの中でだけ ORA-01031」の正体はこれです。
GRANT 自体はされていて、対話では効いている。
しかし、その GRANT がロール経由だと、定義者権限の PL/SQL の中では効きません。
対処は、プロシージャが必要とするシステム権限を、実行するスキーマのユーザーへ直接 GRANT することです。
5. AS SYSDBA の失敗は ORA-01031 とは限らない
もう1つ、ORA-01031 が出るとよく言われる場面を確かめます。
SYSDBA 権限のない一般ユーザーが AS SYSDBA を付けて接続すると ORA-01031 になる、という定説です。
データベースサーバー上の oracle ユーザー(Oracle をインストールした OS ユーザー)で起動した SQL*Plus から、一般ユーザー TS01031 の正しい資格情報に AS SYSDBA を付けて接続してみます。
SQL> CONNECT ts01031/"Ts01031#Lab" AS SYSDBA
接続されました。
SQL> SHOW USER
ユーザーは"SYS"です。ORA-01031 どころか、接続に成功しました。
しかも、接続されたのは TS01031 ではなく SYS です。
さらに、存在しないユーザー名とデタラメなパスワードでも試します。
SQL> CONNECT nouser/"nopassword" AS SYSDBA
接続されました。これも成功します。
サーバー上で OSDBA グループ(一般に dba という名前の OS グループ)に属する OS ユーザーが AS SYSDBA を付けると、OS 認証が使われ、CONNECT に書いたユーザー名とパスワードは一切参照されないためです。
今回の接続元である oracle ユーザーは、このグループに属しています。
dba グループの OS ユーザーであれば、誰でもパスワードなしで SYS になれるということでもあり、OS アカウントの管理がデータベースのセキュリティの土台になっていることが分かります。
一方、OSDBA グループに属さない OS ユーザー(検証では root)で / as sysdba を実行すると、次のようになります。
ERROR:
ORA-01017: ユーザー名/パスワードが無効です。ログオンは拒否されました。返ってきたのは ORA-01031 ではなく ORA-01017 でした(19.28 実機)。
つまり、この環境では「AS SYSDBA の失敗=ORA-01031」という定説は成立せず、OS 認証の失敗は ORA-01017 に合流します。
/ as sysdba が拒否されたときの初動は、パスワードの見直しでも GRANT の確認でもなく、id コマンドで OS ユーザーの所属グループを確認することです。
なお、OS ユーザーを dba グループに追加するには、root で usermod -aG dba ユーザー名 を実行します。
この手順も、dba グループに属さない新規 OS ユーザー ts01031os を作って、実機で確かめました。
追加前と追加後のそれぞれで、id と sqlplus / as sysdba の結果を並べます。
追加前(dba グループに属さない状態):接続は ORA-01017 で拒否されます。
# id ts01031os
uid=54322(ts01031os) gid=54331(ts01031os) groups=54331(ts01031os)$ sqlplus / as sysdba
ERROR:
ORA-01017: ユーザー名/パスワードが無効です。ログオンは拒否されました。追加後(usermod で dba グループに追加し、ログインし直した状態):同じコマンドが、パスワードなしの SYS 接続に変わります。
# usermod -aG dba ts01031os
# id ts01031os
uid=54322(ts01031os) gid=54331(ts01031os) groups=54331(ts01031os),54322(dba)$ sqlplus / as sysdba
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.28.0.0.0
に接続されました。
SQL> SHOW USER
ユーザーは"SYS"です。※SQL*Plus 起動時のバナー表示(バージョンと日時の行)と、失敗時の再試行の繰り返し部分は省略しています。
※グループ追加の反映には、ログインし直しが必要です。
ただし、この検証で見たとおり、dba グループへの追加は「パスワードなしで SYS として接続できる権限」を渡すことと同じです。
追加する相手は管理用のアカウントに限定します。
6. 権限の出どころを調べる(初動コマンド)
前の章までの切り分けには、権限を「持っているか」だけでなく「どの方法で付与されたか」の確認が必要でした。
それぞれを調べるビューを整理します。
まず、自分のセッションで有効なシステム権限は SESSION_PRIVS で確認できます(特別な権限は不要です)。
SELECT * FROM session_privs;ただし、この一覧には直接付与とロール経由が区別されずに並びます。
定義者権限の PL/SQL で使えるかどうかを判断するには、出どころを分けて見る必要があります。
DBA 権限で、次の2本を見比べます。
SELECT grantee, privilege FROM dba_sys_privs WHERE grantee = 'ユーザー名';
SELECT grantee, granted_role FROM dba_role_privs WHERE grantee = 'ユーザー名';検証ユーザーの実物では、次のように見えます。
SQL> SELECT grantee, privilege FROM dba_sys_privs WHERE grantee = 'TS01031' ORDER BY privilege;
GRANTEE PRIVILEGE
------------ --------------------
TS01031 CREATE PROCEDURE
TS01031 CREATE SESSION
TS01031 CREATE TABLE
SQL> SELECT grantee, granted_role FROM dba_role_privs WHERE grantee = 'TS01031';
GRANTEE GRANTED_ROLE
------------ ---------------
TS01031 R_TS01031_CTDBA_SYS_PRIVS に出る行が直接付与、DBA_ROLE_PRIVS に出る行がロール経由です。
ロールの中身は ROLE_SYS_PRIVS で確認できます。
SQL> SELECT role, privilege FROM role_sys_privs WHERE role = 'R_TS01031_CT';
ROLE PRIVILEGE
--------------- --------------------
R_TS01031_CT CREATE TABLEオブジェクト権限(他人の表への SELECT など)は DBA_TAB_PRIVS です。
SQL> SELECT grantee, owner, table_name, privilege FROM dba_tab_privs WHERE grantee = 'TS01031';
GRANTEE OWNER TABLE_NAME PRIVILEGE
------------ ---------- ------------ --------------------
TS01031 TS01031X SECRET_DATA SELECT「プロシージャの中でだけ ORA-01031」の調査であれば、必要な権限が DBA_SYS_PRIVS(直接付与)にあるかを見ます。
DBA_ROLE_PRIVS(ロール経由)にしかなければ、それが原因です。
7. よくある Q&A
Q1. GRANT してもらったはずなのに、プロシージャの中でだけ ORA-01031 が出ます。なぜですか?
その GRANT がロール経由になっている可能性が高いです。
定義者権限の PL/SQL の中では、ロール経由の権限は使われません(『Oracle Databaseセキュリティ・ガイド』に明文がある、文書化された動作です)。
「権限の出どころを調べる」の章のとおり、必要な権限が DBA_SYS_PRIVS(直接付与)にあるか、DBA_ROLE_PRIVS(ロール経由)にしかないかを確認します。
DBA_ROLE_PRIVS にしかなければ、そのユーザーへ権限を直接 GRANT すると、プロシージャを変更せずに解消できます。
Q2. SESSION_PRIVS に権限が見えているのに、実行すると ORA-01031 になります。ビューの表示は当てにならないのですか?
対話の SQL に対しては当てになりますが、プロシージャに対しては判断材料が足りません。
SESSION_PRIVS は直接付与とロール経由を区別せずに表示するため、「一覧に載っている=定義者権限の PL/SQL でも使える」とは限らないからです。
プロシージャで使えるかを判断したい場合は、DBA_SYS_PRIVS で直接付与を確認します。
Q3. 表は作れたのに、INSERT すると「表領域に対する権限がありません」と言われます。CREATE TABLE 権限があるのになぜですか?
CREATE TABLE 権限(操作の権利)と、表領域の割当(QUOTA)は別管理のためです。
19c の Enterprise Edition ではデフォルトで遅延セグメント作成(表の実体の領域確保を最初のデータ挿入まで遅らせる動作)が有効なため、割当がなくても表の作成までは成功し、最初のデータ挿入で ORA-01950 が発覚します。
対処は ALTER USER ユーザー名 QUOTA 10M ON 表領域名; のような割当の付与です。
Q4. sqlplus / as sysdba が失敗しました。ORA-01031 だと思っていたら ORA-01017 でした。どちらが正しいのですか?
サーバー上のローカル接続では、この記事の検証のとおり ORA-01017 になります(19c 実機)。
/ as sysdba は OS 認証で接続するため、失敗の原因は SYSDBA 権限の有無ではなく、実行した OS ユーザーが OSDBA グループ(dba グループ)に属していないことだからです。
初動は id コマンドでの所属グループ確認です。
詳しくは ORA-01017 の記事で取り上げています。
Q5. プロシージャを実行者権限(AUTHID CURRENT_USER)にすれば、ロール経由の権限でも動きますか?
動きます。
「対話では成功するのに、プロシージャの中では ORA-01031」の章と同じ「CREATE TABLE の権限源はロール経由だけ」の状態で、AUTHID CURRENT_USER を付けた同型のプロシージャを作って実行すると、次のとおり正常に完了します(19c 実機)。
CREATE OR REPLACE PROCEDURE proc_ct_invoker AUTHID CURRENT_USER IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE t_from_invoker (c1 NUMBER)';
END;
/SQL> EXEC proc_ct_invoker
PL/SQLプロシージャが正常に完了しました。定義者権限(proc_ct_by_role)では ORA-01031 だった同じ CREATE TABLE が、実行者権限では成功します。
『Oracle Databaseセキュリティ・ガイド』にも、実行者権限の PL/SQL ではロールが権限チェックに使用されると記載されています。
ただし、定義者権限と実行者権限の選択は「そのプロシージャを誰の権限・誰のスキーマで動かすか」というセキュリティ設計そのものです。
ロールを効かせる目的だけで実行者権限に変えると、実行者ごとに動作が変わるプロシージャになります。
プロシージャの設計を変えずに解消するなら、必要な権限の直接 GRANT が確実です。
Q6. 何回か ORA-01031 を出すと、アカウントがロックされたりしますか?
されません。
アカウントのロックにつながるのは、ログイン(認証)の失敗です。
ロックまでの回数を決めるプロファイルのパラメータ FAILED_LOGIN_ATTEMPTS が数えるのは「ログインに連続して失敗できる回数」(『Oracle Database SQL言語リファレンス』CREATE PROFILE の項)で、ORA-01031 はログイン後の操作に対するエラーのため、この回数には含まれません。
Q7. DBA ロールを付与したユーザーでは、QUOTA を意識したことがありません。なぜ ORA-01950 が出ないのですか?
UNLIMITED TABLESPACE というシステム権限(すべての表領域を、割当の制限なしで使える権限)が、DBA ロールの付与と同時にユーザーへ直接付与されているためです。
この権限を持つユーザーには QUOTA の制限が適用されず、ORA-01950 は発生しません。
『Oracle Database SQL言語リファレンス』の GRANT の項によると、UNLIMITED TABLESPACE はロールに付与できないシステム権限です。
このため DBA ロールの中身には含まれておらず、SYS などの管理ユーザーが DBA ロールを GRANT すると、同じ付与の一部としてユーザー本体へ直接付与される、という動きをします。
この記事で見てきた「ロール経由と直接付与」の区別が、ここにも現れています。
8. まとめ
ORA-01031 の切り分けの型を整理します。
- まず番号で「足りないもの」の種類を確定する。 システム権限=ORA-01031/オブジェクト権限=ORA-00942(存在ごと隠される)/表領域の割当=ORA-01950
- 「プロシージャの中でだけ ORA-01031」はロール経由の権限を疑う。 定義者権限の PL/SQL ではロールは使用禁止(マニュアルに明文)。対話で成功しても、SESSION_PRIVS に見えていても、判断材料にならない。オブジェクト権限がロール経由の場合は、同じ罠が ORA-00942 の形で出る
- 出どころは2本のビューで見比べる。 DBA_SYS_PRIVS=直接付与/DBA_ROLE_PRIVS=ロール経由。定義者権限の PL/SQL で効くのは直接付与だけ
- ORA-01950 は最初の INSERT まで気づけない。 遅延セグメント作成(Enterprise Edition)により、割当ゼロでも表の作成は成功してしまう
- AS SYSDBA の失敗は ORA-01031 とは限らない。 サーバー上のローカル接続では OS 認証が使われ、失敗は ORA-01017 に合流する(19c 実機)。初動は id コマンド
調査の流れをフローにすると次のとおりです。
「権限が足りない」失敗が起きたら、まずエラー番号を確認
│
├─ ORA-00942 → オブジェクト権限がない(存在ごと隠される)
│ → 対象への GRANT SELECT 等
│ ※プロシージャ内だけで出るなら、ロール経由を疑う(ORA-01031 と同じ型)
├─ ORA-01950 → 表領域の割当(QUOTA)がない
│ → ALTER USER ~ QUOTA
│
└─ ORA-01031 → システム権限がない
├─ そもそも持っていない → SESSION_PRIVS で確認 → GRANT
├─ 対話では成功・プロシージャ内だけ失敗
│ → ロール経由を疑う(DBA_SYS_PRIVS と DBA_ROLE_PRIVS を見比べる)
│ → 直接 GRANT で解消
└─ / as sysdba の失敗 → 実は ORA-01017(OS 認証)
→ id コマンドで OS グループを確認「権限が足りない」という同じ体感でも、番号と権限の出どころを読めば、GRANT を試しては失敗を繰り返す前に原因へたどり着けます。








