db2 在create mask return case语句中使用非确定性函数时出现问题

bt1cpqcv  于 2022-11-07  发布在  DB2
关注(0)|答案(1)|浏览(148)

我尝试在表上创建IBMi DB2掩码,如下所示:

CREATE or replace MASK IESWEBSERP.MASK_PWD_WSCONTROL ON IESWEBSERP.WSCONTROL
    FOR COLUMN WSVNDPWD    RETURN                                         
    CASE   
        WHEN (  VERIFY_GROUP_FOR_USER(SESSION_USER, 'ICC', 'IICCGRP')=1)
            THEN WSVNDPWD                                                              
        WHEN (  SESSION_USER  in ('QSQSRVR', 'QTMHHTTP', 'PROFOUNDJS', 'IESWEBSVR'))                  
            THEN WSVNDPWD  
        WHEN            IESWEBSERP.IES_CHECK_AUTH( WSDTALIB )  = 1        
            THEN WSVNDPWD
        WHEN     (WSVNDID  = IESWEBSERP.web_login_id )         
            THEN WSVNDPWD 

        ELSE    'MASKED'
    END                                                                 
ENABLE ;

问题出在IESWEBSERP.IES_CHECK_AUTH用户定义函数中使用的RETURN CASE。
根据文档,我知道RETURN CASE语句不能使用非确定性函数。因此下面是这个udf的定义:

Create or REPLACE Function IESWEBSERP.IES_CHECK_AUTH(                                
            DATA_LIBRARY CHAR(10))                                             
     returns dec(1,0)                                                
     language SQL
     NO EXTERNAL ACTION
     DETERMINISTIC
     NOT FENCED
     SECURED                                                     
  BEGIN

    declare q char(1) ;
    declare back char(1) ;
    declare @sqlStmt1 varchar(500) ;
    declare @sqlStmt varchar(500) ;
    declare myCursor cursor for myStatement;
    declare myCursor1 cursor for myStatement1;
    set q = '''';
    set @sqlStmt1 =  'select count(*) from QSYS2.TABLES WHERE TABLE_SCHEMA = ' 
                    concat q concat TRIM(DATA_LIBRARY) concat q  
                    concat ' and TABLE_NAME = ' concat q concat 'MSTCONTL' concat q;
    prepare myStatement1  from @SqlStmt1;                    
    open myCursor1;
    Fetch myCursor1 into back;
    close myCursor1;
    IF ( back = '1' )
        THEN 
            SET back = '0' ;
            set @sqlStmt =  'select count(*) from ' concat TRIM(DATA_LIBRARY) concat '.MSTCONTL 
            where USRID = SESSION_USER and (USRC2 =' concat q concat 'U' concat q 
            concat 'or USRC2 = ' concat q concat 'P' concat q concat')'; 

            prepare myStatement  from @SqlStmt;
            open myCursor;
            Fetch myCursor into back;
            close myCursor;
            IF ( back = '1' )
              THEN SET back = '1' ;
            ELSE SET back = '0' ;

            END IF ;

       ELSE SET back = '0' ;
    END IF ;

    return(back );
END;

UDF所做的一切就是检查当前会话用户的用户记录的字段MSTCONTL.USRC2的值是'U'还是'P'。如果是,它将返回值'1',这将允许用户查看字段WSVNDPWD的值,而不进行任何屏蔽。
但问题是,如果将值MSTCONTL.USRC2更新为U或P以外的值,则函数仍将返回“1”(如果之前也返回了“1”)。我认为这是因为函数被定义为DETERMINISTIC。
如果我把函数设为非确定性的,创建掩码语句就会失败。所以我不知道如何处理这种情况。我想从函数中得到一个“动态”的结果。有人能告诉我如何处理这种情况吗?

j91ykkif

j91ykkif1#

SQL语句有两种确定性:通过使用上面的deterministic关键字,您可以使函数具有全局确定性,这意味着它期望具有相同参数的每个调用总是返回与第一次调用时相同的结果。
您可以将其改为statement deterministic,我想这会达到您的目的。语句确定性意味着每次在该特定语句调用中使用该语句时,该调用都将返回相同的结果,但在下一次调用该语句时,它可能会发生变化。这意味着每次使用该语句时,它都会执行一次新的查找来缓存该值,并重用该值,直到该特定调用完成。
确定性语句和非确定性语句之间的最大区别是,如果有人在非确定性函数中更改了this的列值,理论上它可能会在处理结果的中途更改掩码。确定性语句不允许这样做,但它允许在两次单独运行语句之间更改掩码结果。
请注意,www.example.com上的文档https://www.ibm.com/docs/en/i/7.4?topic=statements-create-mask#fntarg_1确实说明不建议在SQL掩码过程中使用语句确定性,但它没有给予原因。我怀疑这是出于性能原因,因此您必须确定可能的性能或其他影响对于您的情况是否值得。

相关问题