1

I want to create a backup table with ddl trigger (before drop) and encountered the following problem.

It is okay while the first drop happens: the a_backup table contains the data of dropped table. But why I cannot drop another table after this?

ORA-01031: insufficient privileges



create table b (x number);

-- Table B created.

create table a (x number);

-- Table A created.

create table a_backup as select * from a where 1 = 0;

-- Table A_BACKUP created.

create or replace trigger a_backup_tr
    before drop
    on database
begin
    IF ora_dict_obj_name <> 'A' then
    null;
    ELSIF ora_dict_obj_name = 'A'
    and ora_dict_obj_owner = 'TRANEE' then
    insert into a_backup
    select * from a;
    ELSE null;
    end if;
end;
/

-- Trigger A_BACKUP_TR compiled


-- 1

drop table a;

-- Table A dropped.


-- 2

drop table b;

-- ORA-04045: errors during recompilation/revalidation of TRANEE.A_BACKUP_TR

-- ORA-01031: insufficient privileges

And you cannot drop any table after the drop except you runs the create or replace trigger script again. Is there a problem with the IF-THEN part? When the table A doesn't exist, the IF-statement has to go into NULL?

Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
diaphol
  • 117
  • 1
  • 9
  • Just noticed that the functionality you are developing in your question is very similar to Oracle's [recyclebin](https://docs.oracle.com/cd/B28359_01/server.111/b28310/tables011.htm#ADMIN01511) feature. – wolφi Jul 06 '18 at 18:28

1 Answers1

5

But why I cannot drop another table after this?

insert into a_backup select * from a; 

In trigger you explicitly refer to table A and it does not exist at that moment.

You could use dynamic SQL:

create or replace trigger a_backup_tr
    before drop
    on database
begin
    IF ora_dict_obj_name <> 'A' then
        null;
    ELSIF ora_dict_obj_name = 'A' and ora_dict_obj_owner = 'TRANEE' then
        EXECUTE IMMEDIATE 'insert into tranee.a_backup select * from tranee.a';
    ELSE null;
    end if;
end;
/

Personally I don't like the idea of using trigger for such mechanism. Also blind insert and SELECT * may fail if schema drifts in the future. Perhaps better approach is Flashback Drop (Recycle Bin)


EDIT:

As mentioned by @wolφi to mitigate blind insert you could create table inside trigger:

create or replace trigger a_backup_tr
    before drop
    on database
begin
    IF ora_dict_obj_name <> 'A' then
      null;
    ELSIF ora_dict_obj_name = 'A' and ora_dict_obj_owner = 'TRANEE' then
      --TODO: additional check if table already exists
      EXECUTE IMMEDIATE 'CREATE TABLE tranee.a_backup AS SELECT * FROM tranee.a';
    ELSE null;
    end if;
end;
/
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
  • Do you need to qualify the schema of `a_backup` in the ON DATABASE trigger? – wolφi Jul 06 '18 at 16:43
  • @wolφi It will work as is. But it is a good idea to explicitly qualify name. – Lukasz Szozda Jul 06 '18 at 17:33
  • 1
    Ok, thanks! @diaphol: I agree with Lukasz that it is probably not a good idea to backup in a trigger. If at all, I'd use in the trigger body `CREATE TABLE tranee.a_backup AS SELECT * FROM tranee.a`, instead of `INSERT`. It's faster (no undo), safer (no problem with columns) and cleaner (code in one place). – wolφi Jul 06 '18 at 17:43
  • Thanks for the edit, very kind! Would a 'RENAME' also work or would it mess up the `DROP` statement? And, come to think of it, this is exactly what the `RECYCLEBIN` does, isn't it? – wolφi Jul 06 '18 at 18:26
  • 1
    @wolφi Yes, the techonology is called [Flashback Drop (Recycle Bin)](https://oracle-base.com/articles/10g/flashback-10g#flashback_drop). And as for rename does not fire trigger for drop. – Lukasz Szozda Jul 06 '18 at 19:15
  • thanks for the help; it’s not a business issue just a part of trigger exercise and escpecially not a backup solution @wolφi – here, the “a_backup” table contains more columns (username, action, systimestamp etc) and the main aim was that how can save the data from the “data erasing” steps – so there’s another trigger for dml (delete or update) and this ddl trigger contains the truncate as well; so the backup table is filling continuously; that was the reason why I used insert into instead of create – diaphol Jul 06 '18 at 21:51