Почему внутри триггера не выполняется код перед поднятым_подключением? - PullRequest
0 голосов
/ 26 апреля 2018

Если я создаю этот триггер, то возникает ошибка, когда в таблицах используется удаление или усечение, но в logTable ничего не вставляется, но если я удаляю RAISE_APPLICATION_ERROR ... тогда значения вставляются в logTable, но удаление / усечение тоже выполняются. Зачем? Как я могу избежать сброса / усечения в схеме (если я использую вместо триггера, он запускается, только если владелец схемы что-то отбрасывает / усекает).

CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
  IF ora_dict_obj_owner = 'MySchema' THEN
    select user INTO username from dual; 
    INSERT INTO logTable VALUES(username , SYSDATE);
    RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
  END IF;
END;

1 Ответ

0 голосов
/ 27 апреля 2018

Согласно документации :

атомарность на уровне заявления

База данных Oracle поддерживает атомарность на уровне операторов, что означает, что оператор SQL является атомарной единицей работы и либо полностью успешен, либо полностью провален.

Успешное утверждение отличается от совершенной транзакции. один оператор SQL выполняется успешно, если база данных анализирует и запускает его без ошибок как атомарный блок, как при изменении всех строк в многорядном обновлении.

Если инструкция SQL вызывает ошибку во время выполнения, то это не успешно, и поэтому все эффекты утверждения откатились. это операция - это откат на уровне оператора .

Процедура является оператором PL / SQL, она атомарная, если вы вызываете ошибку в процедуре, то вся процедура завершается неудачей, и Oracle выполняет откат всех изменений, выполненных этой процедурой.


Но вы можете создать процедуру с AUTONOMOUS_TRANSACTION Pragma , чтобы обойти это поведение следующим образом:

CREATE TABLE logtable(
   username varchar2(200),
   log_date date
);

CREATE OR REPLACE PROCEDURE log_message( username varchar2 ) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  INSERT INTO logtable( username, log_date ) VALUES ( username, sysdate );
  COMMIT;
END;
/


CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
  IF ora_dict_obj_owner = 'TEST' THEN
    log_message( user );
    RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
  END IF;
END;

А теперь:

drop table table1;

ORA-00604: error occurred at recursive SQL level 1
ORA-20001: ERROR, YOU CAN NOT DELETE THIS!!
ORA-06512: at line 6
00604. 00000 -  "error occurred at recursive SQL level %s"
*Cause:    An error occurred while processing a recursive SQL statement
           (a statement applying to internal dictionary tables).
*Action:   If the situation described in the next error on the stack
           can be corrected, do so; otherwise contact Oracle Support.

select * from logtable;

USERNAME  LOG_DATE
--------  -------------------
TEST      2018-04-27 00:16:34
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...