A trigger törzse

A trigger törzse állhat egyetlen CALL utasításból, amely egy tárolt eljárást hív meg. Ez az eljárás lehet PL/SQL eljárás, de lehet egy C vagy Java nyelven megírt eljárás is.

Másik lehetőség, hogy a trigger törzse egy PL/SQL blokk. Minden, amit a blokkról írtunk, itt is igaz, de van néhány korlátozás. A trigger törzsét alkotó blokkban nem lehetnek tranzakcióvezérlő utasítások (COMMIT, ROLLBACK, SAVEPOINT, SET TRANSACTION). Természetesen a törzsből hívott alprogramok sem tartalmazhatják ezeket az utasításokat. A PL/SQL fordító megengedi ezeket, hibát csak a trigger futása közben okoznak.

Olyan triggerben, amelynek törzse autonóm tranzakciót tartalmaz, használhatók a tranzakcióvezérlő utasítások.

Autonóm tranzakciót tartalmazó kölcsönösen rekurzív triggerek használata az erőforrások zárolása miatt holtpontot eredményezhet.

1. példa

/* Holtpont az AUTONOMOUS_TRANSACTION miatt rekurzív triggerekben. */

CREATE TABLE tab_1 (a NUMBER);

INSERT INTO tab_1 VALUES(1);

CREATE TABLE tab_2 (a NUMBER);

INSERT INTO tab_2 VALUES(1);

CREATE OR REPLACE TRIGGER tr_tab1
  AFTER DELETE ON tab_1
  FOR EACH ROW
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  DELETE FROM tab_2;
END tr_tab1;
/

CREATE OR REPLACE TRIGGER tr_tab2
  AFTER DELETE ON tab_2
  FOR EACH ROW
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  DELETE FROM tab_1;
END tr_tab2;
/

DELETE FROM tab_1;

/* Eredmény:
Hiba a(z) 1. sorban:
DELETE FROM tab_1
  *
ORA-00060: erőforrásra várakozás közben holtpont jött létre
ORA-06512: a(z) "PLSQL.TR_TAB2", helyen a(z) 4. sornál
ORA-04088: hiba a(z) 'PLSQL.TR_TAB2' trigger futása közben
ORA-06512: a(z) "PLSQL.TR_TAB1", helyen a(z) 4. sornál
ORA-04088: hiba a(z) 'PLSQL.TR_TAB1' trigger futása közben
*/

A DML triggerek törzsében használható három paraméter nélküli logikai függvény, amelyek a triggert aktivizáló utasításról adnak információt (miután egy triggert több DML utasítás is aktivizálhat). Ezek a függvények az INSERTING, DELETING, UPDATING függvények, amelyek rendre akkor térnek vissza igaz értékkel, ha az aktivizáló utasítás az INSERT, DELETE, UPDATE volt.

2. példa

/* A szükséges táblák és az eljárás az előző példában voltak definiálva. */
CREATE OR REPLACE TRIGGER tr_utasitas_before
  BEFORE INSERT OR UPDATE OR DELETE ON tabla
BEGIN
  tabla_insert('UTASITAS BEFORE ' || CASE
                                       WHEN INSERTING THEN 'INSERT'
                                       WHEN UPDATING THEN 'UPDATE'
                                       WHEN DELETING THEN 'DELETE'
  END);
END tr_utasitas_before;
/

CREATE OR REPLACE TRIGGER tr_utasitas_after
  AFTER INSERT OR UPDATE OR DELETE ON tabla
BEGIN
  tabla_insert('UTASITAS AFTER ' || CASE
                                        WHEN INSERTING THEN 'INSERT'
                                        WHEN UPDATING THEN 'UPDATE'
                                        WHEN DELETING THEN 'DELETE'
  END);
END tr_utasitas_after;
/
show errors;

CREATE OR REPLACE TRIGGER tr_sor_before
  BEFORE INSERT OR UPDATE OR DELETE ON tabla
  FOR EACH ROW
BEGIN
  tabla_insert('sor before ' || :OLD.a || ', ' || :NEW.a
    || ' ' || CASE
                WHEN INSERTING THEN 'insert'
                WHEN UPDATING THEN 'update'
                WHEN DELETING THEN 'delete'
  END);
END tr_sor_before;
/
show errors;

CREATE OR REPLACE TRIGGER tr_sor_after
  AFTER INSERT OR UPDATE OR DELETE ON tabla
  FOR EACH ROW
BEGIN
  tabla_insert('sor after ' || :OLD.a || ', ' || :NEW.a
    || ' ' || CASE
                WHEN INSERTING THEN 'insert'
                WHEN UPDATING THEN 'update'
                WHEN DELETING THEN 'delete'
  END);
END tr_sor_after;
/

DELETE FROM tabla;

DELETE FROM tabla_log;

-- Biztosan létezik 2 tábla a sémában. */
INSERT INTO tabla
  (SELECT ROWNUM FROM tab WHERE ROWNUM <= 2);

UPDATE tabla SET a = a+10;

DELETE FROM tabla;

SELECT * FROM tabla_log;

/*
S
------------------------------
UTASITAS BEFORE INSERT
sor before , 1 insert
sor after , 1 insert
sor before , 2 insert
sor after , 2 insert
UTASITAS AFTER INSERT
UTASITAS BEFORE UPDATE
sor before 1, 11 update
sor after 1, 11 update
sor before 2, 12 update
sor after 2, 12 update
UTASITAS AFTER UPDATE
UTASITAS BEFORE DELETE
sor before 11, delete
sor after 11, delete
sor before 12, delete
sor after 12, delete
UTASITAS AFTER DELETE
*/

Rendszertrigger létrhozásához ADMINISTER DATABASE TRIGGER rendszerjogosultság szükséges.

A rendszertriggerek törzsében az ún. eseményattribútum függvények használhatók, melyek a bekövetkezett rendszer- és felhasználói események jellemzőit adják meg. Ezek a függvények ugyan bármely PL/SQL blokkból meghívhatók, de valós eredményt csak egy trigger törzsében szolgáltatnak. Ezek a függvények a SYS tulajdonában lévő függvények, nyilvános szinonimáik ora_ prefixszel kezdődnek. A szinonimák ismertetését a 13.1. táblázat tartalmazza.

13.1. táblázat - Eseményattribútum függvények

Szinonima

Típus

Leírás

Példa

ora_client_ip_address

VARCHAR2

TCP/IP protokoll esetén megadja a kliens IP-címét LOGON esemény bekövetkeztekor.

IF ora_sysevent = 'LOGON' THEN

cim := ora_client_ip_address;

END IF;

ora_database_name

VARCHAR2(50)

Az adatbázis nevét adja meg.

DECLARE

db_nev VARCHAR2(50);

BEGIN

db_nev := ora_database_name;

END;

ora_des_encrypted_password

VARCHAR2

Az éppen létrehozás vagy módosítás alatt álló felhasználó jelszava DES titkosítással.

IF ora_dict_obj_type = 'USER'

THEN

INSERT INTO esemenyek VALUES

(ora_des_encrypted_password);

END IF;

ora_dict_obj_name

VARCHAR2(30)

Azon adatszótárbeli objektum neve, amelyen a DDL művelet végrehajtódik.

INSERT INTO esemenyek VALUES

('Változtatott objektum: ' ||

ora_dict_obj_name);

ora_dict_obj_name_list

(nev_lista OUT

ora_name_list_t)

BINARY_INTEGER

Az éppen módosítás alatt álló objektumok számát és neveinek listáját határozza meg.

IF ora_sysevent = 'ASSOCIATE

STATISTICS' THEN

valt_obj_szama :=

ora_dict_obj_name_list

(nev_lista);

END IF;

ora_dict_obj_owner

VARCHAR2(30)

Azon adatszótárbeli objektum tulajdonosa, amelyen a DDL művelet végrehajtódik.

INSERT INTO esemenyek VALUES

('Objektum tulajdonosa: ' ||

ora_dict_obj_owner);

ora_dict_obj_owner_list

(tulaj_lista OUT

ora_name_list_t)

BINARY_INTEGER

Az éppen módosítás alatt álló objektumok számát és tulajdonosaik nevének listáját határozza meg.

IF ora_sysevent = 'ASSOCIATE

STATISTICS' THEN

valt_obj_szama :=

ora_dict_obj_owner_list(

tulaj_lista);

END IF;

ora_dict_obj_type

VARCHAR(20)

Azon adatszótárbeli objektum típusa, amelyen a DDL művelet végrehajtódik.

INSERT INTO esemenyek VALUES

('Objektum típusa: ' ||

ora_dict_obj_type);

ora_grantee(

felh_lista OUT

ora_name_list_t)

BINARY_INTEGER

A feljogosítottak számát és listáját határozza meg.

IF ora_sysevent = 'GRANT' THEN

felh_szama :=

ora_grantee(felh_lista); END

IF;

ora_instance_num

NUMBER

Az adatbázispéldány számát adja meg.

IF ora_instance_num = 1 THEN

INSERT INTO esemenyek VALUES

('1');

END IF;

ora_is_alter_column(

oszlop_nev

IN VARCHAR2)

BOOLEAN

Igazzal tér vissza, ha a megadott oszlop megváltozott.

IF ora_sysevent = 'ALTER' AND

ora_dict_obj_type = 'TABLE'

THEN oszlop_valtozott :=

ora_is_alter_column('FOO');

END IF;

ora_is_creating_nested_table

BOOLEAN

Igazzal tér vissza, ha beágyazott tábla jött létre.

IF ora_sysevent = 'CREATE'

AND ora_dict_obj_type =

'TABLE' AND

ora_is_creating_nested_table

THEN INSERT INTO

esemenyek VALUES

('Egy beágyazott tábla jött

létre.');

END IF;

ora_is_drop_column(

oszlop_nev IN

VARCHAR2)

BOOLEAN

Igazzal tér vissza, ha a megadott oszlop törlődött.

IF ora_sysevent = 'ALTER'

AND ora_dict_obj_type =

'TABLE'

THEN

drop_column :=

ora_is_drop_column('FOO');

END IF;

ora_is_servererror(

hiba_szam IN

NUMBER)

BOOLEAN

Igazzal tér vissza, ha a megadott hiba a hibaveremben van.

IF

ora_is_servererror(hiba_szam)

THEN INSERT INTO esemenyek

VALUES

('Szerverhiba!!');

END IF;

ora_login_user

VARCHAR2(30)

A bejelentkezett felhasználó nevét adja meg.

SELECT ora_login_user FROM dual;

ora_partition_pos

BINARY_INTEGER

Egy CREATE TABLE-re vonatkozó INSTEAD OF triggerben megadja, hogy a táblát létrehozó utasítás mely pozícióján lehet PARTITION utasításrészt elhelyezni.

-- Már elmentettük az

-- ora_sql_txt értékét az

-- sql_text változóba.

n := ora_partition_pos;

uj_utasitas :=

substr(sql_text, 1, n-1)

|| ' ' ||

sajat_part_resz || ' '

|| substr(sql_text, n));

ora_privileges(

privilegium_lista

OUT

ora_name_list_t)

BINARY_INTEGER

Az éppen kapott vagy visszavont jogosultságok számát és listáját határozza meg.

IF ora_sysevent = 'GRANT'

OR ora_sysevent = 'REVOKE'

THEN

priv_szama :=

ora_privileges(priv_lista);

END IF;

ora_revokee(felh_list

OUT

ora_name_list_t)

BINARY_INTEGER

Azon felhasználók számát és neveinek listáját határozza meg, akiktől jogosultságokat vontak vissza.

IF (ora_sysevent =

'REVOKE') THEN felh_szama

:= ora_revokee(felh_list);

END IF;

ora_server_error(

pozicio IN NUMBER)

NUMBER

A hibaverem megadott pozícióján elhelyezett hibaszámot adja vissza. A verem tetejének pozíciója 1.

INSERT INTO esemenyek VALUES

('A legutolsó hiba száma: '

|| ora_server_error(1));

ora_server_error_depth

BINARY_INTEGER

A hibaveremben levő összes hiba darabszámát adja vissza.

n := ora_server_error_depth;

ora_server_error_msg(

pozicio IN

BINARY_INTEGER)

VARCHAR2

A hibaverem megadott pozícióján elhelyezett hibához tartozó üzenetet adja vissza. A verem tetejének pozíciója 1.

INSERT INTO esemenyek

VALUES ('A legutolsó hiba: '

|| ora_server_error_msg(1));

ora_server_error_num_

params( pozicio IN

BINARY_INTEGER)

BINARY_INTEGER

A hibaverem megadott pozícióján elhelyezett hibához tartozó üzenetben lecserélt "%s" formájú hibaparaméterek számát adja meg.

n :=

ora_server_error_num_params

(1);

ora_server_error_param(

pozicio IN

BINARY_INTEGER,

param IN

BINARY_INTEGER)

VARCHAR2

A hibaverem megadott pozícióján elhelyezett hibához tartozó üzenetben lecserélt "%s", "%d" formájú hibaparaméterek számát adja meg.

param :=

ora_server_error_param(1,

2);

ora_sql_txt(sql_text

OUT ora_name_list_t)

BINARY_INTEGER

Meghatározza a triggert aktivizáló utasítás szövegét. Ha az utasítás túl hosszú, akkor több táblasorra tördelődik. A visszatérési érték a tábla sorainak száma.

DECLARE

sql_text

ora_name_list_t;

stmt VARCHAR2(2000);

...

n := ora_sql_txt(sql_text);

FOR i IN 1..n LOOP

stmt := stmt ||

sql_text(i);

END LOOP;

INSERT INTO esemenyek

VALUES ('Az aktiváló

utasítás: ' || stmt);

...

ora_sysevent

VARCHAR2(20)

A triggert aktivizáló redszeresemény.

INSERT INTO esemenyek

VALUES (ora_sysevent);

ora_with_grant_option

BOOLEAN

Igazzal tér vissza, ha a GRANT utasításban szerepel a WITH GRANT OPTION utasításrész.

IF ora_sysevent = 'GRANT'

AND ora_with_grant_option

THEN

INSERT INTO esemenyek

VALUES ('WITH GRANT OPTION');

END IF;

space_error_info(
hiba_szam OUT
NUMBER,
hiba_tipus OUT
VARCHAR2,
objektum_tulaj OUT VARCHAR2,
tablespace_nev OUT
VARCHAR2,
objektum_nev OUT
VARCHAR2,
alobjektum_nev OUT
VARCHAR2)

BOOLEAN

Igazzal tér vissza, ha valamely objektum számára elfogyott a hely. Az OUT paraméterek adnak információt az objektumról

IF space_error_info(hsz,
htip, tul, ts, obj, alobj)
THEN
DBMS_OUTPUT.PUT_LINE(
'Elfogyott a hely a(z) '
|| obj || ' objektum számára,
melynek tulajdonosa ' || tul);
END IF;