現象:在存儲過程中使用 `EXECUTE IMMEDIATE 'CREATE TABLE ...'` 報 `ORA-01031: insufficient privileges`。原因:PL/SQL 定義者權限執行時,**角色權限不生效**,使用者必須被**直接授予**系統權限 `CREATE ANY TABLE` (或 `CREATE TABLE` 配合 `ALTER SESSION SET CURRENT_SCHEMA`)。本文提供最小權限解決方案與替代設計模式。
-- 當前使用者 SUK (假設有 RESOURCE 角色,含 CREATE TABLE)
CREATE OR REPLACE PROCEDURE p_create_table AS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE create_table (id INT)';
END;
/
-- 執行
EXEC p_create_table;
-- 報錯:
-- ORA-01031: insufficient privileges
-- ORA-06512: at "SUK.P_CREATE_TABLE", line 3
| 權限來源 | 定義者權限程式單元中是否生效 | 說明 |
|---|---|---|
| 直接授予系統權限 (GRANT CREATE TABLE TO user) | ✅ 生效 | 編譯時檢查通過,執行時驗證通過 |
| 角色授予系統權限 (GRANT RESOURCE TO user → 含 CREATE TABLE) | ❌ 不生效 | 角色在 Definer's Rights 中停用 |
| 直接授予 CREATE ANY TABLE | ✅ 生效 | 可在任何 Schema 建表 (高權限,慎用) |
-- 以 DBA 或擁有 ADMIN OPTION 的使用者執行
GRANT CREATE TABLE TO suk;
GRANT CREATE ANY TABLE TO suk;
CREATE OR REPLACE PROCEDURE p_create_table
AUTHID CURRENT_USER AS -- 或 12c+ DEFAULT AUTHID CURRENT_USER
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE create_table (id INT)';
END;
/
-- DBA 建立通用建表程序,應用僅傳參數
CREATE OR REPLACE PROCEDURE admin_create_table (
p_owner IN VARCHAR2,
p_table_name IN VARCHAR2,
p_ddl IN CLOB
) AUTHID DEFINER AS
PRAGMA AUTONOMOUS_TRANSACTION; -- 獨立交易
BEGIN
-- 這裡可加入命名規範檢查、審計日誌、配額驗證
EXECUTE IMMEDIATE p_ddl;
COMMIT;
END;
/
-- 授予應用使用者 EXECUTE 權限
GRANT EXECUTE ON admin_create_table TO app_user;
-- 授權後重新編譯存儲過程 (可選)
ALTER PROCEDURE p_create_table COMPILE;
-- 再次執行
EXEC p_create_table;
-- 應成功
-- 查詢建立的表
SELECT * FROM user_tables WHERE table_name = 'CREATE_TABLE';
理解「角色在定義者權限中失效」是解決 `ORA-01031` 的關鍵。直接授予系統權限或改用呼叫者權限/管理程序代建,即可安全解決存儲過程建表權限問題。