数据库
首页 > 数据库> > mysql – 触发内部动态SQL的替代方案?

mysql – 触发内部动态SQL的替代方案?

作者:互联网

我的数据库有以下表格:

    TAG
    ----------------------
    | tag_id | tag_name  |
    ----------------------

    TAG_VALUE: Stores values associated to each tag
    ----------------------------------------
    | tag_id | insertion_timestamp | value |
    ----------------------------------------

    ALARM: Defines alarms for each tag
    -------------------------------------
    | alarm_id | tag_id | function_name |
    -------------------------------------

    ALARM ACTIVATION: Stores information regarding each time the alarms were triggered
    -----------------------------------------------------
    | alarm_id | activation_timestamp | activation_value|
    -----------------------------------------------------

因此,每次在TAG_VALUE中插入新值时,我都需要检查该新值是否触发与其标记关联的任何警报.由于警报之间没有通用标准,我只是存储一个函数名称,稍后将用它来确定是否应该触发警报

TAG_VALUE具有以下AFTER_INSERT触发器:

CREATE DEFINER=`root`@`localhost` TRIGGER `mydb`.`tag_value_AFTER_INSERT` AFTER INSERT ON `tag_value` FOR EACH ROW
BEGIN
call sp_alarm_handler(NEW.tag_value, NEW.tag_id);
END

sp_alarm_handler编码如下:

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_alarm_handler`(IN tag_value VARCHAR(255), IN value_tag_id INT(11))
    BEGIN

    DECLARE exit_loop BOOLEAN;
    DECLARE v_alarm_id INT(11);
    DECLARE function_name VARCHAR(255);
    DECLARE value_triggers_alarm TINYINT(1);

    DECLARE custom_alarm_cur CURSOR FOR
    Select alarm_id, function_name From vw_custom_alarms where tag_id = value_tag_id;


    DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;

    OPEN custom_alarm_cur;

    custom_alarm_lp: LOOP

        FETCH custom_alarm_cur into v_alarm_id, function_name;

        IF exit_loop THEN
        leave custom_alarm_lp;
        END IF;

        #************************************************
        #*********HERE'S THE DYNAMIC SQL PIECE'**********
        #************************************************
        set @query = CONCAT('Select ',function_name,'(',tag_value,')', 'into @value_triggers_alarm');
        PREPARE stmt FROM @query;
        Execute stmt;

        IF fn_is_alarm_active(v_alarm_id) = 0 THEN

            If @value_triggers_alarm = 1 THEN
                    INSERT INTO alarm_activation(alarm_id, activation_timestamp, activation_value)
                    VALUES (v_alarm_id, NOW(), tag_value);
            end if;

        ELSE IF @value_triggers_alarm = 0 THEN
            call sp_deactivate_alarm(v_alarm_id);

            END IF;
        END IF;



    END LOOP custom_alarm_lp;
    Close custom_alarm_cur;

    END

这给了我一个错误1336:1336:存储函数或触发器中不允许动态SQL
在我的案例中是否有任何解决方法?

解决方法:

如果要检查的列表是不变的,那么拼出它们而不是构建测试. (不可行)

但是,大概情况并非如此……

计划A:用PROCEDURE调用替换需要调用触发器的INSERT.该例程包含INSERT以及您提供的其余代码.

计划B:与计划A一样,但在应用程序代码中执行.

注意:A或B将被包装在BEGIN … COMMIT中以使其成为“原子”.

底线:触发器不能做任何事情.

执行A(我认为这会阻止其他人绕过存储过程.)

> CREATE USER special @ … … – 一个新用户
> GRANT INSERT ON db.tbl to special @ … – 让它进入
>存储过程将是SECURITY special @ … – 将proc作为“特殊”运行,以便它可以执行INSERT
>从其他人中删除该表的INSERT PRIVILEGE. (这会变得混乱,或者可能是不必要的.)(如果表位于当前没有人可访问的单独数据库中,则可能会有所帮助.)
>(我的直觉说还有一步.我会把它作为’为读者练习’.)

标签:mysql,dynamic-sql,prepared-statement,mysql-workbench,trigger
来源: https://codeday.me/bug/20190806/1602877.html