为什么我在这个触发器的FOR循环中出错?

时间:2015-11-24 13:25:10

标签: sql triggers db2 ibm-midrange

我正在尝试在SQL解释器中创建一个触发器,而且我遇到了一些令人头疼的问题。

CREATE TRIGGER log_permission_role_rel_update AFTER UPDATE ON permission_role_rel
REFERENCING NEW ROW as newrow OLD ROW as oldrow 
FOR EACH ROW
BEGIN ATOMIC

    /* delete old row */
    FOR SELECT * FROM TABLE(MYSCHEMA.simulate_by_permission_role_rel(oldrow.id_role, oldrow.id_permission)) simulationA
    DO
    CALL MYSCHEMA.log_proc('DELETE', 'SECVAL', 'test', '{}');
    END FOR;

    /* insert new row */
    FOR SELECT * FROM TABLE(MYSCHEMA.simulate_by_permission_role_rel(newrow.id_role, newrow.id_permission)) simulationB
    DO
    CALL MYSCHEMA.log_proc('INSERT', 'SECVAL', '{}', 'test');
    END FOR;
END;

上述声明导致错误声称指令结束无效,并突出显示第二个CALL的结尾为罪魁祸首。

SQL State: 42601
Vendor Code: -104
Message: [SQL0104] Token <END-OF-INSTRUCTION> was not valid. Valid tokens: ;.

两个FOR循环都是独立工作的,而不是当它们在同一个触发器下一起工作时。我真的不知道还有什么要尝试的。我在这做错了什么?为什么单个FOR循环工作,但不是两个?

谢谢。

修改 (编辑了解更多信息)

我在iSeries,i5 / OS 7.1上的DB2下运行。我也通过iNavigator运行所有SQL语句。

编辑#2

所有触发器似乎都是使用以下属性创建的:

...
FOR EACH ROW 
MODE DB2SQL 

SET OPTION  ALWBLK = *ALLREAD , 
ALWCPYDTA = *OPTIMIZE , 
COMMIT = *NONE , 
DECRESULT = (31, 31, 00) , 
DFTRDBCOL = MYSCHEMA, 
DYNDFTCOL = *NO , 
DYNUSRPRF = *USER , 
SRTSEQ = *HEX   
BEGIN
...

步骤:

CREATE PROCEDURE MYSCHEMA.LOG_PROC ( 
    IN OP VARCHAR(6) , 
    IN TABLENAME VARCHAR(128) , 
    IN OLDVAL VARCHAR(255) , 
    IN NEWVAL VARCHAR(255) ) 
    LANGUAGE SQL 
    SPECIFIC MYSCHEMA.LOG_PROC 
    NOT DETERMINISTIC 
    MODIFIES SQL DATA 
    CALLED ON NULL INPUT 
    SET OPTION  ALWBLK = *ALLREAD , 
    ALWCPYDTA = *OPTIMIZE , 
    COMMIT = *NONE , 
    DECRESULT = (31, 31, 00) , 
    DFTRDBCOL = MYSCHEMA , 
    DYNDFTCOL = *NO , 
    DYNUSRPRF = *USER , 
    SRTSEQ = *HEX   
    BEGIN 
    INSERT INTO AA_LEGACYLOG ( OPERATION , TABLENAME , OLDVALUE , NEWVALUE ) VALUES ( OP , TABLENAME , OLDVAL , NEWVAL ) ; 
END  ; 

功能:

CREATE FUNCTION MYSCHEMA.SIMULATE_BY_PERMISSION_ROLE_REL ( 
    ARG_ID_ROLE INTEGER , 
    ARG_ID_PERMISSION INTEGER ) 
    RETURNS TABLE ( 
    USRCODE VARCHAR(10) , 
    SECURABLE VARCHAR(12) , 
    LG_INDX VARCHAR(1) , 
    LG_VALO VARCHAR(10) , 
    LG_ATRB VARCHAR(6) )   
    LANGUAGE SQL 
    SPECIFIC MYSCHEMA.SIMULATE_BY_PERMISSION_ROLE_REL 
    NOT DETERMINISTIC 
    READS SQL DATA 
    CALLED ON NULL INPUT 
    SET OPTION  ALWBLK = *ALLREAD , 
    ALWCPYDTA = *OPTIMIZE , 
    COMMIT = *NONE , 
    DECRESULT = (31, 31, 00) , 
    DFTRDBCOL = MYSCHEMA , 
    DYNDFTCOL = *NO , 
    DYNUSRPRF = *USER , 
    SRTSEQ = *HEX   
    RETURN ( 
        SELECT DISTINCT A . USER_REF , P . SECURABLE , P . LG_INDX , P . LG_VALO , P . LG_ATRB 
        FROM ROLE R , PERMISSION P , ACTOR A , ACTOR_ROLE_REL 

        WHERE R . ID = ARG_ID_ROLE 
        AND P . ID = ARG_ID_PERMISSION   

        AND ACTOR_ROLE_REL . ID_ACTOR = ACTOR . ID 
        AND ACTOR_ROLE_REL . ID_ROLE = R . ID 

        GROUP BY A . USER_REF , P . SECURABLE , P . LG_INDX , P . LG_VALO , P . LG_ATRB  
    )  ; 

2 个答案:

答案 0 :(得分:1)

这可能是Error SQL0104 when creating a function in System i V7R1的副本;我给出的链接是该讨论中的具体答案,但最好是阅读整个讨论。该讨论得出了我在下面做出的类似结论,问题是缺少应用于OP使用的IBM i 7.1系统的PTF \维护,因为解决 FOR语句的问题<缺陷 { {3}}不包括可选的cursor-name CURSOR FOR子句时;即可选子句实际上是必需 ,直到修复已应用。

以下脚本应该足够喜欢 OP给出的[省略每个SET OPTION中的DFTRDBCOL和UDTF上的硬编码返回],运行正常以创建触发器,的情况下,使用RUNSQLSTM服务器端工具\ SQL脚本处理器和iACS运行SQL,在IBM i 7.1上使用RUNSQLSTM服务器端工具\ SQL脚本处理器[我没有Win OS哪个加载并尝试iNav]客户端工具\ SQL脚本处理器。注意:脚本末尾的最后一个DROP只是一个失败的额外语句,放在那里强调触发器中BEGIN的END之后的多余分号不会造成任何困难,我甚至添加了另一个分号作为语句 - 分离器,这也没有困难。我认为自OP问题以来,要么纠正了一个缺陷,要么

drop   table qtemp.AA_LEGACYLOG
;
create table qtemp.AA_LEGACYLOG
  ( OPERATION         VARCHAR(  6)
  , TABLENAME         VARCHAR(128)
  , OLDVALUE          VARCHAR(255)
  , NEWVALUE          VARCHAR(255)
  )
;
drop   PROCEDURE  LOG_PROC
;
CREATE PROCEDURE  LOG_PROC
 (  IN OP VARCHAR(6)
 ,  IN TABLENAME VARCHAR(128)
 ,  IN OLDVAL VARCHAR(255)
 ,  IN NEWVAL VARCHAR(255)
 )  LANGUAGE SQL
    SPECIFIC  LOG_PROC
    NOT DETERMINISTIC
    MODIFIES SQL DATA
    CALLED ON NULL INPUT
    SET OPTION  ALWBLK = *ALLREAD
             ,  ALWCPYDTA = *OPTIMIZE
             ,  COMMIT = *NONE
             ,  DECRESULT = (31, 31, 00)
             ,  DYNDFTCOL = *NO
             ,  DYNUSRPRF = *USER
             ,  SRTSEQ = *HEX
BEGIN
    INSERT INTO QTEMP.AA_LEGACYLOG
      ( OPERATION , TABLENAME , OLDVALUE , NEWVALUE )  VALUES
      (        OP , TABLENAME , OLDVAL   , NEWVAL   )
    ;
END
;
drop table    permission_role_rel
;
create table  permission_role_rel
( ID_ROLE       INTEGER
, ID_PERMISSION INTEGER
)
;
drop   FUNCTION  SIMULATE_BY_PERMISSION_ROLE_REL
;
CREATE FUNCTION  SIMULATE_BY_PERMISSION_ROLE_REL
  ( ARG_ID_ROLE INTEGER
  , ARG_ID_PERMISSION INTEGER
  ) RETURNS TABLE
  ( USRCODE VARCHAR(10)
  , SECURABLE VARCHAR(12)
  , LG_INDX VARCHAR(1)
  , LG_VALO VARCHAR(10)
  , LG_ATRB VARCHAR(6)
  ) LANGUAGE SQL
    SPECIFIC  SIMULATE_BY_PERMISSION_ROLE_REL
    NOT DETERMINISTIC
    READS SQL DATA
    CALLED ON NULL INPUT
    SET OPTION  ALWBLK = *ALLREAD
  , ALWCPYDTA = *OPTIMIZE
  , COMMIT = *NONE
  , DECRESULT = (31, 31, 00)
  , DYNDFTCOL = *NO
  , DYNUSRPRF = *USER
  , SRTSEQ = *HEX
RETURN
 ( select 'code', 'capable', 'I', 'VALO', 'ATTR'
   from qsys2.qsqptabl
 )
;
CREATE TRIGGER log_permission_role_rel_update
       AFTER UPDATE ON permission_role_rel
REFERENCING NEW ROW as newrow
            OLD ROW as oldrow
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC

    /* delete old row */
    FOR SELECT *
        FROM TABLE
          ( simulate_by_permission_role_rel(oldrow.id_role, oldrow.id_permission)
          ) simulationA
    DO
      CALL log_proc('DELETE', 'SECVAL', 'test', '{}') ;
    END FOR;

   /* insert new row */
    FOR SELECT *
        FROM TABLE
          ( simulate_by_permission_role_rel(newrow.id_role, newrow.id_permission)
          ) simulationB
    DO
      CALL log_proc('INSERT', 'SECVAL', '{}', 'test');
    END FOR;
END;
;
drop table qtemp.permission_test
;

答案 1 :(得分:0)

我看到你的函数中有分号结尾行,以及结束你的函数声明的分号。用@符号结束你的函数声明:

CREATE FUNCTION MYSCHEMA.SIMULATE_BY_PERMISSION_ROLE_REL ( 
    ARG_ID_ROLE INTEGER , 
    ARG_ID_PERMISSION INTEGER ) 
    RETURNS TABLE ( 
    USRCODE VARCHAR(10) , 
    SECURABLE VARCHAR(12) , 
    LG_INDX VARCHAR(1) , 
    LG_VALO VARCHAR(10) , 
    LG_ATRB VARCHAR(6) )   
    LANGUAGE SQL 
    SPECIFIC MYSCHEMA.SIMULATE_BY_PERMISSION_ROLE_REL 
    NOT DETERMINISTIC 
    READS SQL DATA 
    CALLED ON NULL INPUT 
    SET OPTION  ALWBLK = *ALLREAD , 
    ALWCPYDTA = *OPTIMIZE , 
    COMMIT = *NONE , 
    DECRESULT = (31, 31, 00) , 
    DFTRDBCOL = MYSCHEMA , 
    DYNDFTCOL = *NO , 
    DYNUSRPRF = *USER , 
    SRTSEQ = *HEX   
    RETURN ( 
        SELECT DISTINCT A . USER_REF , P . SECURABLE , P . LG_INDX , P . LG_VALO , P . LG_ATRB 
        FROM ROLE R , PERMISSION P , ACTOR A , ACTOR_ROLE_REL 

        WHERE R . ID = ARG_ID_ROLE 
        AND P . ID = ARG_ID_PERMISSION   

        AND ACTOR_ROLE_REL . ID_ACTOR = ACTOR . ID 
        AND ACTOR_ROLE_REL . ID_ROLE = R . ID 

        GROUP BY A . USER_REF , P . SECURABLE , P . LG_INDX , P . LG_VALO , P . LG_ATRB  
    ) @

然后将其保存到文件c:\ db \ simulate_by_permission_role_rel.sql

然后使用以下命令执行:

db2 connect to mydb
db2 -td@ -f c:\db\simulate_by_permission_role_rel.sql
db2 connect reset

-td @告诉db2命令行界面将@符号解释为语句终止符。 -f告诉db2 cli要执行哪个文件。