While I was testing something on a 12.1 test database got this below error whenever I’m trying to execute specific admin commands:
SQL> drop user xx;
drop user xx
*
ERROR at line 1:
ORA-04088: error during execution of trigger ‘SYS.XDB_PI_TRIG’
ORA-00604: error occurred at recursive SQL level 1
ORA-06550: line 3, column 13:
PLS-00302: component ‘IS_VPD_ENABLED’ must be declared
ORA-06550: line 3, column 5:
PL/SQL: Statement ignored
SQL> alter table bb move online compress;
alter table bb move online compress
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-04088: error during execution of trigger ‘SYS.XDB_PI_TRIG’
ORA-00604: error occurred at recursive SQL level 2
ORA-06550: line 3, column 13:
PLS-00302: component ‘IS_VPD_ENABLED’ must be declared
ORA-06550: line 3, column 5:
PL/SQL: Statement ignored
The above was just a sample but the error with showing up with lots of admin commands!
I checked the trigger SYS.XDB_PI_TRIG which causing this error and it was already valid, so I decided to DISABLE it, and then admin commands ran as usual:
SQL> alter trigger SYS.XDB_PI_TRIG disable;
Trigger altered.
Above failing admin commands have run smoothly:
SQL> alter table bb move online compress;
Table altered.
Frankly speaking, I tried to google that error without any success, I didn’t dig deeper, so I took the shortest/laziest way and disabled the root cause trigger as a dirty fix, the database where I disabled that trigger was a test DB, most probably one of my fancy test scenarios caused this issue to happen.
In case you have the same error on a Production Database I strongly recommend you to contact Oracle Support before disabling the above-mentioned trigger.
Update: I’ve dug more and found that the root cause was that someone created a table with the name «sys» under SYS user. Bug 17431402 yes it’s a bug because the engine should throw an error if someone tries to create an object with a «reserved word».
I’ve dropped that object «sys.sys» and the error disappeared:
SQL> alter trigger SYS.XDB_PI_TRIG disable;
Trigger altered.
SQL> drop table sys.sys;
Table dropped.
SQL> alter trigger SYS.XDB_PI_TRIG enable;
Trigger altered.
SQL> alter table bb move online compress;
Table altered.
phew!
May 1, 2021
I got ” ORA-04088: error during execution of trigger ‘string.string’” error in Oracle database.
ORA-04088: error during execution of trigger ‘string.string’
Details of error are as follows.
ORA-04088 error during execution of trigger 'string.string' Cause: A runtime error occurred during execution of a trigger. Action: Check the triggers which were involved in the operation.
error during execution of trigger ‘string.string’
This ORA-04088 errors are related with the runtime error occurred during execution of a trigger.
when I check related table triggers and constraints, problem is occured because of trigger.
I have disabled triggers with following command.
alter trigger TRIGGER_NAME disable;
Or Check and fix the triggers which were involved in the operation.
Do you want to learn Oracle Database for Beginners, then read the following articles.
Oracle Tutorial | Oracle Database Tutorials for Beginners ( Junior Oracle DBA )
1,214 views last month, 1 views today
About Mehmet Salih Deveci
![]()
I am Founder of SysDBASoft IT and IT Tutorial and Certified Expert about Oracle & SQL Server database, Goldengate, Exadata Machine, Oracle Database Appliance administrator with 10+years experience.I have OCA, OCP, OCE RAC Expert Certificates I have worked 100+ Banking, Insurance, Finance, Telco and etc. clients as a Consultant, Insource or Outsource.I have done 200+ Operations in this clients such as Exadata Installation & PoC & Migration & Upgrade, Oracle & SQL Server Database Upgrade, Oracle RAC Installation, SQL Server AlwaysOn Installation, Database Migration, Disaster Recovery, Backup Restore, Performance Tuning, Periodic Healthchecks.I have done 2000+ Table replication with Goldengate or SQL Server Replication tool for DWH Databases in many clients.If you need Oracle DBA, SQL Server DBA, APPS DBA, Exadata, Goldengate, EBS Consultancy and Training you can send my email adress [email protected].- -Oracle DBA, SQL Server DBA, APPS DBA, Exadata, Goldengate, EBS ve linux Danışmanlık ve Eğitim için [email protected] a mail atabilirsiniz.
Hello, we used exceltable package a few week ago and everything was fine. During this period, our oracle admins applied some patch or etc. and now we get an oracle error ORA-04088 which is connected with trigger checking grants to PUBLIC. I don’t know why something should grant privileges to PUBLIC, but it seems that error emerges on this row — «open l_rc for l_query using p_file, p_method, p_password;» in first getCursor function in EXCELTABLE package. We use ORACLE DB 12.2. Do you have any idea where is granting privileges used and why emerges this error? Thank you in advance.
- This is part of our SQL code:
declare
piv_excel_name ext_ds_upt_kalendar_pro_kl.nazev_souboru%TYPE := ‘Kalendar.xlsx’;
piv_nazev_listu ext_ds_upt_kalendar_pro_kl.nazev_listu%TYPE := ‘Plan’;
cv_db_adresar CONSTANT VARCHAR2(16) := ‘DB_DIR’;
lvr_data SYS_REFCURSOR;
begin
lvr_data :=
ExcelTable.getCursor(
p_file => ExcelTable.getFile(cv_db_adresar, piv_excel_name)
, p_sheet => piv_nazev_listu
, p_cols => ‘»A2″ VARCHAR2(100) column »A»’
, p_range => ‘A2:A2’
);
end;
- This is whole error message:
Error report —
ORA-04088: error during execution of trigger ‘APPLDBA_P.BEFORE_GRANT_PUBLIC’
ORA-00604: error occurred at recursive SQL level 3
ORA-20997: Public grants on data schema objects not allowed
ORA-06512: on line 23
ORA-06512: on «EXT_STAGE.EXCELTABLE», line 4087
ORA-06512: on line 11
- 00000 — «error during execution of trigger ‘%s.%s'»
*Cause: A runtime error occurred during execution of a trigger.
*Action: Check the triggers which were involved in the operation.
- This is the trigger mentioned above:
create or replace TRIGGER appldba_p.before_grant_public BEFORE GRANT ON DATABASE
declare
vLst ora_name_list_t;
vCnt int;
function is_authorized(p_owner varchar2,p_grantor varchar2) return varchar2 is
vRet varchar2(1);
begin
select decode(max(profile),’DAT_USER_PROFILE’,’F’,’T’) into vRet from dba_users where username=p_owner;
if vRet=’F’ then
select decode(count(*),0,’F’,’T’) into vRet from dba_role_privs where granted_role=’DBA’ and grantee=p_grantor;
end if;
return vRet;
end;
begin
if ora_dict_obj_name is null then
return;
end if;
vCnt:=ora_grantee(vLst);
for i in 1..nvl(vCnt,0) loop
if vLst(i)=’PUBLIC’ and is_authorized(ora_dict_obj_owner,ora_login_user)=’F’ then
raise_application_error(-20997,’Public grants on data schema objects not allowed’);
end if;
end loop;
end;
СУБД Oracle внутри себя достаточно давно поддерживает автономные транзакции. Мы видим их в форме рекурсивного SQL. Например, рекурсивная транзакция может выполняться при выборе значения из последовательности, чтобы немедленно увеличить значение счетчика последовательности в таблице SYS.SEQ$. Обновление таблицы SYS.SEQ$ для поддержки вашей последовательности немедленно фиксируется и становится видимым другим транзакциям, хотя ваша транзакция еще и не зафиксирована. Вдобавок, если вы откатите свою транзакцию, то увеличение значения счетчика последовательности останется в силе; оно не будет откачено вместе с вашей транзакцией, поскольку уже было зафиксировано. Управление пространством, аудит и другие внутренние операции выполняются в аналогичной рекурсивной манере.
Теперь это средство открыто для применения всем. Однако я обнаружил, что оправданное применение автономных транзакций в реальном мире очень ограничено. Временами я встречаю их в качестве обходного пути для решения таких проблем, как ограничения мутирующей таблицы в триггере. Однако это почти всегда ведет к проблемам с целостностью данных, поскольку причиной мутирующей
таблицы является попытка читать таблицу в то время, когда инициирован ее триггер. Используя автономную транзакцию, вы можете запросить таблицу, но при этом не сможете увидеть изменения (для чего в первую очередь и предназначено ограничение мутирующей таблицы; таблица находится в процессе модификации, поэтому результаты запроса должны быть несогласованными). Любые решения, принятые на основе запроса из триггера, сомнительны — в этот момент времени вы читаете “старые” данные.
Потенциально корректное применение автономной транзакции — в специализированном аудите, но я подчеркиваю слова “потенциально корректное”. Существуют более эффективные пути аудита информации базы данных, нежели посредством написания специального триггера. Например, вы можете использовать пакет DBMS_FGA или саму команду AUDIT.
Часто задаваемый разработчиками приложений вопрос звучит так: “Как я могу выполнять аудит каждой попытки модификации секретной информации и записывать значения, которые они пытаются модифицировать?” Они хотят не только предотвращать попытки модификации, но также сохранять записи о таких попытках. До появления автономных транзакций многие разработчики пытались (и безуспешно) делать это с помощью стандартных триггеров без автономных транзакций. Триггер должен обнаруживать UPDATE, и, увидев, что пользователь модифицирует данные, которых он модифицировать не должен, создавать запись аудита и отказывать UPDATE. К сожалению, когда триггер отвергает UPDATE, он также выполняет откат записи аудита — это типичная ситуация “все или ничего”. С автономными транзакциями стало возможным безопасно выполнять аудит попыток выполнения запретных операций, одновременно откатывая эти операции. В процессе мы можем информировать конечного пользователя о том, что он пытается модифицировать данные, которые не имеет права модифицировать, а также о том, что его попытка зафиксирована в записи аудита.
Интересно отметить, что родная команда Oracle AUDIT уже в течение многих лет предоставляет возможность фиксации безуспешных попыток модификации информации, используя автономные транзакции. Предоставление этого средства в распоряжение разработчиков Oracle позволяет нам выполнять собственный, более гибкий специализированный аудит.
Рассмотрим небольшой пример. Давайте добавим триггер автономной транзакции к таблице, которая фиксирует след аудита, детализируя, кто пытался обновить таблицу, и когда это произошло, наряду с информативным сообщением о том, какие именно данные этот пользователь пытался модифицировать. Логика такого триггера должна предотвращать любые попытки обновления записи сотрудника, который (прямо или опосредованно) не подчиняется вам.
Во-первых, создадим копию таблицы EMP из схемы SCOTT, чтобы использовать в качестве таблицы примеров:
ops$tkyte@ORA10G> create table emp
2 as
3 select * from scott.emp;
Table created.
Таблица создана.
ops$tkyte@ORA10G> grant all on emp to scott;Grant succeeded.
Полномочия унаследованы.
Мы также создадим таблицу AUDIT_TAB, в которой будем размещать информацию аудита. Обратите внимание, что мы используем атрибут DEFAULT в столбцах, которые должны хранить имя текущего зарегистрированного пользователя и текущее значение даты/времени в наш “след” аудита.
ops$tkyte@ORA10G> create table audit_tab2 ( username varchar2(30) default user,3 timestamp date default sysdate,4 msg varchar2(4000)5 )6 /
Table created.
Таблица создана.
Далее создадим триггер EMP_AUDIT для выполнения аудита действия UPDATE над таблицей EMP:
ops$tkyte@ORA10G> create or replace trigger EMP_AUDIT2 before update on emp3 for each row 4 declare
5 pragma autonomous_transaction;
6 l_cnt number;7 begin
26 end;
27 /Trigger created.Триггер создан.
Обратите внимание на применение запроса с CONNECT BY. Это позволяет нам развернуть всю иерархию, начиная с текущего пользователя, чтобы проверить, что запись, попытка обновления которой предпринимается, относится к кому-то, кто подчиняется нам на некотором уровне.
Ниже перечислены главные моменты, которые нужно отметить относительно этого триггера.
PRAGMA AUTONOMOUS_TRANSACTION применяется к определению триггера. Весь триггер представляет собой “автономную транзакцию”, и потому независим от родительской транзакции, пытающейся выполнить обновление.
Триггер пытается выполнять чтение таблицы, которую он защищает, а именно — таблицу EMP. Само по себе это может привести к ошибке “мутирующей” таблицы во время выполнения, но это не касается автономной транзакции. Автономная транзакция обходит эту проблему — она позволяет читать таблицу, но с условием, что мы не увидим тех изменений, которые проводятся в таблице вышестоящей транзакцией. В таком случае следует проявлять исключительную осторожность. Подобная логика должна быть тщательно продумана. Что если текущая транзакция пытается обновить саму иерархию сотрудников? Мы не увидим этих изменений в триггере, и это следует принимать во внимание, проверяя корректность кода триггера.
Этот триггер выполняет фиксацию. Раньше такое было невозможно — триггеры никогда не фиксировали работу. Данный триггер не фиксирует ту работу, которая была причиной его вызова; вместо этого он фиксирует только ту работу, которую выполняет он сам (запись аудита).
Итак, мы настроили таблицу EMP, имеющую замечательную иерархическую структуру (рекурсивное отношение EMPNO — MGR). Также у нас есть таблица AUDIT_TABLE, в которую мы хотим вносить записи о безуспешных попытках модифицировать информацию. У нас имеется триггер, обеспечивающий выполнение нашего правила — что только наш руководитель или руководитель нашего руководителя (и так далее) может модифицировать нашу запись.
Давайте посмотрим, как это работает, попытавшись обновить запись в таблице EMP:
ops$tkyte@ORA10G> update emp set sal = sal*10;
update emp set sal = sal*10
*
ERROR at line 1:
ORA-20001: Access Denied
ORA-06512: at «OPS$TKYTE.EMP_AUDIT», line 21
ORA-04088: error during execution of trigger ‘OPS$TKYTE.EMP_AUDIT’
ОШИБКА в строке 1:
ORA-20001: Доступ запрещен
ORA-06512: в «OPS$TKYTE.EMP_AUDIT», строка 21
ORA-04088: ошибка во время выполнения триггера ‘OPS$TKYTE.EMP_AUDIT’
ops$tkyte@ORA10G> select * from audit_tab;
USERNAME TIMESTAMP MSG
OPS$TKYTE 27-APR-05 Attempt to update 7369
Вызов триггера предотвращает операцию UPDATE, в то же время создавая постоянную запись о такой попытке (обратите внимание, как используется ключевое слово DEFAULT в операторе CREATE TABLE таблицы AUDIT_TAB, чтобы автоматически вносить значения USER и SYSDATE). Далее давайте зарегистрируемся как пользователь, который может выполнить UPDATE, и попытаемся сделать кое-что:
ops$tkyte@ORA10G> connect scott/tiger
Connected.
Подключено.
scott@ORA10G> set echo on
scott@ORA10G> update ops$tkyte.emp set sal = sal*1.05 where ename = ‘ADAMS’;
1 row updated.
1 строка обновлена.
scott@ORA10G> update ops$tkyte.emp set sal = sal*1.05 where ename = ‘SCOTT’;
update ops$tkyte.emp set sal = sal*1.05 where ename = ‘SCOTT’
*
ERROR at line 1:
ORA-20001: Access Denied
ORA-06512: at «OPS$TKYTE.EMP_AUDIT», line 21
ORA-04088: error during execution of trigger ‘OPS$TKYTE.EMP_AUDIT’
ОШИБКА в строке 1:
ORA-20001: Доступ запрещен
ORA-06512: в «OPS$TKYTE.EMP_AUDIT», строка 21
ORA-04088: ошибка во время выполнения триггера ‘OPS$TKYTE.EMP_AUDIT’
В инсталляции по умолчанию демонстрационной таблицы EMP сотрудник ADAMS подчиняется SCOTT, поэтому первый оператор UPDATE выполнился успешно. Второй UPDATE, где SCOTT пытается дать самому себе прибавку, терпит провал, поскольку SCOTT не подчиняется SCOTT. Зарегистрируемся в схеме, содержащей таблицу AUDIT_TAB, и увидим следующее:
scott@ORA10G> connect /
Connected.
Подключено.
ops$tkyte@ORA10G> set echo on
ops$tkyte@ORA10G> select * from audit_tab;
USERNAME TIMESTAMP MSG
OPS$TKYTE 27-APR-05 Attempt to update 7369
SCOTT 27-APR-05 Attempt to update 7788
Как видим, попытка SCOTT выполнить оператор UPDATE была зафиксирована.
| < Предыдущая | Следующая > |
|---|
Problem Description-------------------------------You are creating a trigger that includes an exception handling block. You wish to raise a user defined error when a certain condition is met within the trigger body using keyword RAISE.Inside your error handling block you also include a call to RAISE_APPLICATION_ERROR.Consider this code example --create table tmp (col1 char(40));create table violations (col1 varchar2(30));CREATE OR REPLACE TRIGGER DEMO_RULE_001BEFORE INSERT OR UPDATE ON TMPFOR EACH ROWDECLARERULE_001 EXCEPTION;BEGINIF :NEW.col1 = 'mike' THENdbms_output.put_line(:new.col1);INSERT INTO VIOLATIONS values ('violation logged');-- Raise ruleRAISE RULE_001;END IF;EXCEPTIONWHEN RULE_001 THENRAISE_APPLICATION_ERROR (-20001,'Guideline Violation, Rule-001.');END;When this trigger is executed, you receive the ora-4088 and ora-6512 errors.ORA-04088: error during execution of trigger 'SCOTT.DEMO_RULE_001'Solution Description-------------------------------You cannot use both RAISE, within the execution block of a trigger, and RAISE_APPLICATION_ERROR, within the exception block.Explanation------------------------RAISE forces execution to move into the exception block.RAISE_APPLICATION_ERROR, within the exception block, terminates the program.If the trigger body does not complete, the triggering SQL statement and anySQL statements within the trigger body are rolled back. Thus, execution completes unsuccessfully with a runtime error and it appears as if none of the code within the trigger body gets executed.Consider this corrected code --CREATE OR REPLACE TRIGGER DEMO_RULE_001BEFORE INSERT OR UPDATE ON TMPFOR EACH ROWDECLARERULE_001 EXCEPTION;BEGINIF :NEW.col1 = 'mike' THENdbms_output.put_line(:new.col1);INSERT INTO VIOLATIONS values ('violation logged');-- Raise ruleRAISE RULE_001;END IF;EXCEPTIONWHEN RULE_001 THEN--raise_application_error(-20001, 'Guideline Violation, Rule-001.');dbms_output.put_line('Guideline Violation, Rule-001.');END;Oracle Support Doc ID 103293.1
Hi I have this trigger
create or replace TRIGGER trg_cust
after insert or update on nbty_customer
referencing old as old new as new
for each row
declare
pragma autonomous_transaction;
V_REQ VARCHAR2(10);
begin
IF(:NEW.cust_sal<1000)
THEN
select :NEW.cust_sal+:OLD.cust_sal INTO V_REQ FROM nbty_customer
where cust_id=:old.cust_id;
ELSE
SELECT :NEW.cust_sal-:OLD.cust_sal INTO V_REQ FROM nbty_customer where cust_id=:old.cust_id;
end if;
merge into nbty_cache_cust
using
(select distinct :new.cust_id cust_id, :new.cust_name cust_name,V_REQ V_REQ
from nbty_customer) b
on (cust_nbty_id = b.cust_id)
when matched then
update set cust_nbty_name = b.cust_name, cust_nbty_sal = b.V_REQ
when not matched then
insert (cust_nbty_id, cust_nbty_name, cust_nbty_sal)
values (b.cust_id, b.cust_name, b.V_REQ);
commit;
end;
Which compiles properly but when an insertion is done on the table nbty_customer like for example
insert into nbty_customer values('2','abc','200')
It throws ora-01403 no data found error,ora-04088 error during execution of trigger
Kindly help, I am not able to figure out what the issue is?
![]()
asked Apr 30, 2014 at 14:21
![]()
1
The problem was due to a select into clause which returned a ‘no data found’ so I removed the select into and directly used a bind variable instead:
IF(:new.cust_sal<1000)
then
v_req:=nvl(:new.cust_sal,0)+nvl(:old.cust_sal,0);
else
v_req:=nvl(:new.cust_sal,0)-nvl(:old.cust_sal,0);
end if;
This solved the problem.
![]()
answered May 2, 2014 at 9:21
![]()
I just commented, and then I noticed this:
select :NEW.cust_sal+:OLD.cust_sal INTO V_REQ FROM nbty_customer
where cust_id=:old.cust_id;
On insert, this select will fail since there is no :old.cust_id. Use :new.cust_id instead. (also, :old.cust_sal will be null too)
answered Apr 30, 2014 at 14:30
![]()
Patrick HofmanPatrick Hofman
152k21 gold badges246 silver badges316 bronze badges
9
In your trigger body, you’re trying to select the data of your new row:
SELECT :NEW.cust_sal-:OLD.cust_sal INTO V_REQ FROM nbty_customer where cust_id=:old.cust_id;
But you declared your trigger body as PRAGMA AUTONOMOUS_TRANSACTION. Therefore, your trigger does not see the changes that triggered the trigger execution in the first place.
Using AUTONOMOUS_TRANSACTION in triggers is never a good idea; see Tom Kyte on Triggers for a detailed explanation on why you want to avoid this.
If you need to cache your data for performance reasons, I’d recommend using a Materialized View instead. You can set it to REFRESH ON COMMIT if needed:
create materialized view mv_cache
refresh on commit
as
select distinct cust_id cust_id, cust_name cust_name, V_REQ
from nbty_customer
answered Apr 30, 2014 at 14:36
![]()
Frank SchmittFrank Schmitt
29.6k11 gold badges71 silver badges107 bronze badges
Hi I have this trigger
create or replace TRIGGER trg_cust
after insert or update on nbty_customer
referencing old as old new as new
for each row
declare
pragma autonomous_transaction;
V_REQ VARCHAR2(10);
begin
IF(:NEW.cust_sal<1000)
THEN
select :NEW.cust_sal+:OLD.cust_sal INTO V_REQ FROM nbty_customer
where cust_id=:old.cust_id;
ELSE
SELECT :NEW.cust_sal-:OLD.cust_sal INTO V_REQ FROM nbty_customer where cust_id=:old.cust_id;
end if;
merge into nbty_cache_cust
using
(select distinct :new.cust_id cust_id, :new.cust_name cust_name,V_REQ V_REQ
from nbty_customer) b
on (cust_nbty_id = b.cust_id)
when matched then
update set cust_nbty_name = b.cust_name, cust_nbty_sal = b.V_REQ
when not matched then
insert (cust_nbty_id, cust_nbty_name, cust_nbty_sal)
values (b.cust_id, b.cust_name, b.V_REQ);
commit;
end;
Which compiles properly but when an insertion is done on the table nbty_customer like for example
insert into nbty_customer values('2','abc','200')
It throws ora-01403 no data found error,ora-04088 error during execution of trigger
Kindly help, I am not able to figure out what the issue is?
![]()
asked Apr 30, 2014 at 14:21
![]()
1
The problem was due to a select into clause which returned a ‘no data found’ so I removed the select into and directly used a bind variable instead:
IF(:new.cust_sal<1000)
then
v_req:=nvl(:new.cust_sal,0)+nvl(:old.cust_sal,0);
else
v_req:=nvl(:new.cust_sal,0)-nvl(:old.cust_sal,0);
end if;
This solved the problem.
![]()
answered May 2, 2014 at 9:21
![]()
I just commented, and then I noticed this:
select :NEW.cust_sal+:OLD.cust_sal INTO V_REQ FROM nbty_customer
where cust_id=:old.cust_id;
On insert, this select will fail since there is no :old.cust_id. Use :new.cust_id instead. (also, :old.cust_sal will be null too)
answered Apr 30, 2014 at 14:30
![]()
Patrick HofmanPatrick Hofman
152k21 gold badges246 silver badges316 bronze badges
9
In your trigger body, you’re trying to select the data of your new row:
SELECT :NEW.cust_sal-:OLD.cust_sal INTO V_REQ FROM nbty_customer where cust_id=:old.cust_id;
But you declared your trigger body as PRAGMA AUTONOMOUS_TRANSACTION. Therefore, your trigger does not see the changes that triggered the trigger execution in the first place.
Using AUTONOMOUS_TRANSACTION in triggers is never a good idea; see Tom Kyte on Triggers for a detailed explanation on why you want to avoid this.
If you need to cache your data for performance reasons, I’d recommend using a Materialized View instead. You can set it to REFRESH ON COMMIT if needed:
create materialized view mv_cache
refresh on commit
as
select distinct cust_id cust_id, cust_name cust_name, V_REQ
from nbty_customer
answered Apr 30, 2014 at 14:36
![]()
Frank SchmittFrank Schmitt
29.6k11 gold badges71 silver badges107 bronze badges