如何在注销触发期间删除序列和程序?

How to delete sequences and procedures during logoff trigger?

在我所处的特殊情况下,您能否帮助我。在注销触发器期间删除序列和过程时,我收到“ORA-30511:系统触发器中无效的 DDL 操作”。

我需要在注销事件发生之前删除用户的 tables、序列和过程。我正在使用单独的触发器在 DB_OBJECTS table 中编写 table 详细信息。下面是我的注销触发器 - 你能帮我看看我做错了什么吗?删除 tables 在下面的代码中工作正常。仅删除序列和过程会出现“ORA-30511:系统触发器中无效的 DDL 操作”错误。

CREATE OR REPLACE TRIGGER DELETE_BEFORE_LOGOFF
  BEFORE LOGOFF ON DATABASE
DECLARE
  USER_ID NUMBER := SYS_CONTEXT('USERENV', 'SESSIONID');
BEGIN
  FOR O IN (SELECT USER, OBJECT_NAME, OBJECT_TYPE
                FROM DB_OBJECTS WHERE SID = USER_ID
                AND USERNAME = USER AND SYSDATE > CREATED_DTTM) LOOP
          IF O.OBJECT_TYPE = 'TABLE' THEN
              EXECUTE IMMEDIATE 'DROP TABLE ' || O.USER || '.' || O.OBJECT_NAME || ' CASCADE CONSTRAINTS';
          ELSIF O.OBJECT_TYPE = 'SEQUENCE' THEN
              EXECUTE IMMEDIATE 'DROP SEQUENCE ' || O.USER || '.' || O.OBJECT_NAME;
          ELSIF O.OBJECT_TYPE = 'PROCEDURE' THEN
              EXECUTE IMMEDIATE 'DROP PROCEDURE ' || O.USER || '.' || O.OBJECT_NAME;
          END IF;
  END LOOP;
  EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;
/

这很简单。

  • 错误代码:ORA-30511
  • 问题描述:系统触发器中无效的 DDL 操作
  • 原因:试图在系统触发器中执行无效的 DDL 操作。系统触发器目前不支持大多数 DDL 操作。当前唯一支持的 DDL 操作是 table 操作 和 ALTER/COMPILE 操作。
  • 操作:删除系统触发器中的无效 DDL 操作。

这就是为什么只有

Dropping tables is working fine

成功。

因此,您不能使用触发器来做到这一点。


然后你问(在评论中)如何删除这些对象。据我所知,手动。不过,这很不寻常 - 如果有人不小心注销怎么办?你会放弃他们创造的一切。如果您将该模式用于教育目的(例如,每个学生都有自己的模式),那么您可以创建一个“清理”脚本,一旦 class 结束,您就会 运行 。像这样:

SET SERVEROUTPUT ON;

DECLARE
   l_user  VARCHAR2 (30) := 'SCOTT';
   l_str   VARCHAR2 (200);
BEGIN
   IF USER = l_user
   THEN
      FOR cur_r IN (SELECT object_name, object_type
                      FROM user_objects
                     WHERE object_name NOT IN ('EMP',
                                               'DEPT',
                                               'BONUS',
                                               'SALGRADE'))
      LOOP
         BEGIN
            l_str :=
                  'drop '
               || cur_r.object_type
               || ' "'
               || cur_r.object_name
               || '"';
            DBMS_OUTPUT.put_line (l_str);

            EXECUTE IMMEDIATE l_str;
         EXCEPTION
            WHEN OTHERS
            THEN
               NULL;
         END;
      END LOOP;
   END IF;
END;
/

PURGE RECYCLEBIN;

它远非完美;我用它来清理我用来在各种网站上回答问题的 Scott 模式,所以 - 一旦它变得一团糟,我 运行 那个 PL/SQL 代码多次(因为可能的外键约束)。

其他选项是保留 create user 脚本(以及所有 grant 语句)并且 - 一旦 class 结束 - 删除现有用户并简单地重新创建它。

或者,如果该用户包含一些预建的 tables,保留导出文件(我的意思是数据泵导出的结果)并在删除用户后导入它。

有多种选择 - 我不知道我是否猜对了,但现在你有 一些东西 可以考虑了。