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