我很困惑。我有一个用户可以在SQL Developer中运行下面的程序,它运行正常。
begin
FOR C IN (SELECT TABLE_NAME FROM ALL_TABLES
WHERE TABLE_NAME LIKE 'TEMP_%'
AND OWNER = '<user name in caps>')
LOOP
EXECUTE IMMEDIATE('DROP TABLE <user name in caps>.' || C.table_name || ' PURGE');
END LOOP;
end;
但是 - 如果我将函数包装在存储过程中并运行它,而没有抛出异常,则以“temp”开头的表不会删除。我实际上是从三种不同的模式中删除 - 因此重复。
CREATE OR REPLACE PROCEDURE DELETETEMPTABLES AS
BEGIN
--DROP ANY TABLES THAT START WITH "TEMP_"
FOR C IN (SELECT TABLE_NAME FROM ALL_TABLES
WHERE TABLE_NAME LIKE 'TEMP_%'
AND OWNER = '<user name in caps>')
LOOP
EXECUTE IMMEDIATE('DROP TABLE <user name in caps>.' || C.table_name || ' PURGE');
END LOOP;
FOR C IN (SELECT TABLE_NAME FROM ALL_TABLES
WHERE TABLE_NAME LIKE 'TEMP_%'
AND OWNER = '<user name in caps>')
LOOP
EXECUTE IMMEDIATE('DROP TABLE <user name in caps>.' || C.table_name || ' PURGE');
END LOOP;
FOR C IN (SELECT TABLE_NAME FROM ALL_TABLES
WHERE TABLE_NAME LIKE 'TEMP_%'
AND OWNER = '<user name in caps>')
LOOP
EXECUTE IMMEDIATE('DROP TABLE <user name in caps>.' || C.table_name || ' PURGE');
END LOOP;
exception
WHEN OTHERS THEN
log_errors (p_error_message => 'Nightly Processing->DeleteTempTables-> ' ||SQLERRM);
END DELETETEMPTABLES;
答案 0 :(得分:1)
最有可能的是,这是一个特权问题。
ALL_TABLES
列出您拥有权限的所有表。以交互方式运行时,包括您通过角色拥有的所有表。但是,当您尝试创建存储过程时,将排除通过角色授予的权限,并且您只能看到直接授予的那些表。如果希望代码有效,则对象(或DBA)的所有者需要将对象的权限直接授予过程所有者,而不是通过角色。实际上,该过程的所有者还需要直接授予它的DROP ANY TABLE
权限(而不是通过像DBA
这样的角色)才能使DROP TABLE
语句成功。
答案 1 :(得分:1)
贾斯汀是对的。但是你经常可以使用AUTHID来克服私有问题。尝试:
CREATE OR REPLACE PROCEDURE DELETETEMPTABLES
AUTHID CURRENT_USER
AS
这在Oracle中称为“调用者权限”。默认值为definers权限(authid definer)。有关详情,请参阅here和here。
在子程序中使用角色取决于它是否执行 定义者的权利或赋权者的权利。在定义者的权利范围内 子程序,所有角色都被禁用。角色不用于特权 检查,你不能设置角色。
在调用者权利子程序中,角色已启用(除非 子程序由定义者权利直接或间接调用 子程序)。角色用于权限检查,您可以使用 本机动态SQL,用于设置会话的角色。但是,你做不到 使用角色为模板对象授予权限,因为角色适用 在运行时,而不是在编译时。