Тригер BEFORE INSERT с извикване на съхранена процедура (DB2 LUW 9.5)

Опитвам се да създам тригер BEFORE INSERT, който ще проверява входящата стойност на поле и ще го замени със същото поле в друг ред, ако това поле е null. Въпреки това, когато добавя израза CALL към моя тригер, се връща грешка „The trigger "ORGSTRUCT.CSTCNTR_IN" is defined with an unsupported triggered SQL statement“. Проверих документацията и видях, че курсорите не се поддържат в BEFORE (част от причината за създаването на съхранената процедура на първо място), но дори когато премахна декларацията на курсора от съхранената процедура, извикването все още генерира същата грешка .

Тригер:

CREATE TRIGGER orgstruct.cstcntr_IN
        NO CASCADE
        BEFORE INSERT ON orgstruct.tOrgs
        REFERENCING NEW AS r
        FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
    DECLARE prnt_temp BIGINT;
    DECLARE cstcntr_temp CHAR(11);

    SET prnt_temp = r.prnt;
    SET cstcntr_temp = r.cstcntr;

    CALL orgstruct.trspGetPrntCstCntr(prnt_temp,cstcntr_temp);
    SET r.cstcntr = cstcntr_temp;
END

Съхранена процедура:

CREATE PROCEDURE orgstruct.trspGetPrntCstCntr (
    IN  p_prnt              BIGINT,
    OUT p_cstcntr       CHAR(11)
)
SPECIFIC trGetPrntCstCntr
BEGIN
    IF p_prnt IS NULL THEN
        RETURN;
    END IF;

    BEGIN
        DECLARE c1 CURSOR
            FOR
                SELECT cstcntr
                FROM orgstruct.tOrgs
                WHERE id = p_prnt
            FOR READ ONLY;
        OPEN c1;
        FETCH FROM c1 INTO p_cstcntr;
        CLOSE c1;
    END;
END

Според документацията CALL е разрешено в BEFORE тригер, така че не разбирам какъв е проблемът.


person Matt    schedule 07.03.2011    source източник


Отговори (1)


Тригерът преди може да извика съхранена процедура, но съхраненият процес не може да прави нищо, което не е позволено в тригера.

Във вашия случай нивото по подразбиране на достъп до данни за SQL съхранена процедура е MODIFIES SQL DATA, което не е разрешено в тригера. Можете да пресъздадете съхранената си процедура, като промените нивото на достъп до данните на READS SQL DATA; това ще ви позволи да създадете тригера.

Въпреки това: Няма причина да се извиква съхранена процедура за нещо толкова просто; Можете да го направите с помощта на прост вграден тригер:

create trigger orgstruct.cstcntr_IN
   no cascade
   before insert on orgstruct.tOrgs
   referencing new as r
   for each row
   mode db2sql
   set r.cstcntr = case 
                     when r.p_prnt is not null 
                       then (select cstcntr from tOrgs where id = r.p_prnt fetch first 1 row only) 
                     else r.cstcntr 
                   end;

Това ще бъде МНОГО по-ефективно, защото елиминира както извикването на съхранена процедура, така и обработката на курсора вътре в съхранената процедура. Дори ако искате да използвате съхранената процедура, можете да премахнете курсора вътре в съхранената процедура и да подобрите производителността.

FYI: логиката, която публикувахте, съдържа грешка и винаги ще задава CSTCNTR на NULL. Тригерът, публикуван в този отговор, не прави това. :-)

person Ian Bjorhovde    schedule 08.03.2011