【问题标题】:Why am I getting an error with this trigger's FOR loops?为什么此触发器的 FOR 循环出现错误?
【发布时间】:2015-11-24 13:25:09
【问题描述】:

我正在尝试在 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  
    )  ; 

【问题讨论】:

  • 看看这是否有帮助:stackoverflow.com/questions/13266700/…
  • 我似乎根本无法更改终止符。我也尝试过 --#SET TERMINATOR %,但也不起作用。 db2 似乎不支持 iseries,尽管到目前为止我还没有找到可行的替代方案(我正在使用 ibm 的 i navigator)。有什么想法吗?
  • DB2 的操作系统版本是什么? (也可能什么是 DB2 组 PTF 级别?)create a trigger in a SQL interpreter 是什么意思?是否全部通过 iNav(仅向服务器发送语句)?语句终止符在这里不是问题。
  • 顺便说一句,触发器创建属性应该编辑到问题中。
  • 谢谢。是的,这一切都是通过 iNav 实现的。我现在无法访问系统,但我会在早上编辑问题。但是,触发器创建属性是什么意思?

标签: sql triggers db2 ibm-midrange


【解决方案1】:

这大概是Error SQL0104 when creating a function in System i V7R1的副本;我提供的链接是该讨论中的特定答案,但最好阅读整个讨论。该讨论得出了我在下面得出的类似结论,即问题在于 OP 使用的 IBM i 7.1 系统缺少 PTF\维护,因为解析 FOR 语句时存在问题\缺陷@ 987654322@ 当不包括可选的cursor-name CURSOR FOR子句时;即 optional 子句实际上是 mandatory 直到修复已应用。

以下脚本应该与 OP 提供的内容充分类似 [在每个 SET OPTION 中省略 DFTRDBCOL 并在 UDTF 上硬编码返回],运行良好以创建触发器,没有任何终止错误,在 IBM i 7.1 上,从 2015/317 开始累积维护,同时使用 RUNSQLSTM 服务器端工具\SQL-script-processor 和 iACS Run 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
;

【讨论】:

    【解决方案2】:

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

    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 要执行哪个文件。

    【讨论】:

    • 请注意,OP 没有使用“db2 命令行界面”。相反,正在使用基于客户端的 SQL [iNav Run SQL] 脚本环境。根据我的经验,DB2 for i SQL parser\syntax-checker 将尾随分号视为语句分隔符 [或语句终止符] 没有任何困难;即,除了可能包含一个多余的尾随分号之外,不会发出除可能的低严重性\非终止“空语句”之外的错误。 OP 的 CREATE TRIGGER 源在 IBM DB2 for i 7.1 的运行 SQL 语句 (RUNSQLSTM) 解释器中编译没有错误
    猜你喜欢
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 2021-04-30
    • 2018-05-08
    • 2016-08-13
    • 2017-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多