【问题标题】:Trigger stopped behaving as expected after MariaDB upgrade (from 10.1 to 10.4.6)MariaDB 升级(从 10.1 到 10.4.6)后触发器停止运行
【发布时间】:2019-11-15 14:50:33
【问题描述】:

自从我升级到 MariaDB 10.4.6 后,我的 BEFORE INSERT 触发器之一出现问题。

触发器定义如下(去掉无用的部分)

 CREATE TRIGGER `trg_bins_stock`
 BEFORE INSERT ON `stock`
 FOR EACH ROW
 BEGIN  

DECLARE maxprice DOUBLE DEFAULT NULL;
DECLARE errormsg VARCHAR(255) DEFAULT '';

select  MAX(price)  into maxprice 
FROM view_articles
where view_articles.id_ref = NEW.id_ref;

IF (maxprice is null) THEN

  SET errormsg = CONCAT("INSERT ERROR : missing line in view_articles [art ref :  ",  NEW.id_ref ,  "]");

  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errormsg; 

END IF;

END

当插入“stock”表时,即使我不应该得到自定义错误,例如消息“INSERT ERROR : missing line in view_articles [art ref:11757]”

查询:

select  MAX(price)  
    FROM view_articles
    where view_articles.id_ref = 11757;

不返回 null,所以我不应该触发这个错误。

到目前为止我测试过的内容:

  • 触发器中“maxprice”的值实际上是 NULL(因此 if 子句没有问题)。
  • 如果我修改触发器以在选择查询中将 11757 代替 NEW.id_ref,则 maxprice 不为 NULL。
  • 如果我创建一个类似于我的视图“view_articles”的表“table_articles”,并执行 INSERT INTO table_articles SELECT * FROM view_articles,然后修改我的触发器以使用表而不是 看来,maxprice 也不为空。

附加信息:

Sql 模式设置为 'NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' 。 创建视图、表、触发器以及用于插入表的用户是相同的,并且具有“授予 . 的所有权限”。 在 debian 9 上使用 mariadb 10.4.6(按照升级说明页面从 10.1 升级)进行测试,并在 Windows 机器上全新安装相同版本,并从转储中加载 db。

编辑更多信息、测试和解决方法: view_articles 定义(简化)如下:

CREATE VIEW view_articles  AS 
 SELECT articles2.id_ref as id_ref, articles2.pricing as price
  from articles2 
 UNION 
SELECT articles.id_article as id_ref, articles.price as price 
  from articles

如果我直接在触发器中使用此语句代替视图,我仍然会遇到同样的问题,但这有效:

IF(new.id_ref <0) THEN 
 select MAX(articles2.pricing) INTO maxprix    
      from articles2  WHERE articles2.id_ref =  new.id_ref ;
ELSE 
 select MAX(articles.price) INTO maxprix 
 from articles WHERE articles.id_article = new.id_ref ;
END IF;

那么,现在是否禁止在触发器中使用带有 UNION 子句的视图?或者这是一个错误?

我对我的解决方法并不十分满意,因为有一天我可能在“文章”表中有负 ID,而在“文章 2”中可能有正 ID,即使现在不是这样。所以我仍然欢迎更优雅的解决方案。

【问题讨论】:

  • 如果我替换“view_articles.id_ref = NEW.id_ref;”通过“view_articles.id_ref NEW.id_ref;”然后我得到一个 maxprice 的值。不是我想要的,但它证明触发器可以从视图中读取,它只是在条件的“相等”部分失败......但为什么对我来说仍然是一个谜( id_ref 的类型为 INT(11) )
  • 您检查过触发器中的 NEW.id_ref 值吗?它是提供的还是自动递增的? NVM,它在错误消息中,所以它被提供了。
  • @fifonik 是的,NEW.id_ref 的值在我的自定义错误消息中正确返回,它不是自动递增的。当我将它用于桌子而不是我的视野时,它也可以工作。
  • view_articles 是否使用stock 表?不使用聚合函数 (SELECT price FROM view_articles WHERE ... LIMIT 1) 是否有效?
  • @fifonik 我在描述中添加了详细信息。该视图不使用“库存”表。为 LIMIT 1 更改 MAX ( ) 并不能解决问题。

标签: mysql triggers mariadb


【解决方案1】:

这是一个影响 MariaDB 10.2、10.3 和 10.4 版本的错误。必须解决它,直到修复错误。 MariaDB 错误跟踪链接:https://jira.mariadb.org/browse/MDEV-19975

【讨论】:

    【解决方案2】:

    我无法重现该问题:

    MariaDB [(none)]> USE `_`;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    
    MariaDB [_]> SELECT VERSION();
    +----------------+
    | VERSION()      |
    +----------------+
    | 10.4.6-MariaDB |
    +----------------+
    1 row in set (0.000 sec)
    
    MariaDB [_]> SELECT @@global.sql_mode, @@session.sql_mode\G
    *************************** 1. row ***************************
     @@global.sql_mode: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    @@session.sql_mode: STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    1 row in set (0.000 sec)
    
    MariaDB [_]> DROP VIEW IF EXISTS `view_articles`;
    Query OK, 0 rows affected (0.000 sec)
    
    MariaDB [_]> DROP TABLE IF EXISTS `articles`, `stock`;
    Query OK, 0 rows affected (0.002 sec)
    
    MariaDB [_]> CREATE TABLE IF NOT EXISTS `stock`(
        ->   `id_ref` INT NOT NULL
        -> );
    Query OK, 0 rows affected (0.001 sec)
    
    MariaDB [_]> CREATE TABLE IF NOT EXISTS `articles`(
        ->   `id_article` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        ->   `price` NUMERIC(10, 2)
        -> );
    Query OK, 0 rows affected (0.001 sec)
    
    MariaDB [_]> CREATE VIEW `view_articles`  AS
        -> SELECT `articles`.`id_article` `id_ref`, `articles`.`price`
        -> FROM `articles`;
    Query OK, 0 rows affected (0.000 sec)
    
    MariaDB [_]> DELIMITER //
    
    MariaDB [_]> CREATE TRIGGER `trg_bins_stock` BEFORE INSERT ON `stock`
        -> FOR EACH ROW
        -> BEGIN
        ->   DECLARE `maxprice` NUMERIC(10, 2) DEFAULT NULL;
        ->   DECLARE `errormsg` VARCHAR(255) DEFAULT '';
        -> 
        ->   SELECT MAX(`price`) INTO `maxprice`
        ->   FROM `view_articles`
        ->   WHERE `view_articles`.`id_ref` = NEW.`id_ref`;
        -> 
        ->   IF (`maxprice` IS NULL) THEN
        ->     SET `errormsg` := CONCAT('INSERT ERROR: missing line in view_articles [art ref: ',  NEW.`id_ref` ,  ']');
        ->     SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = `errormsg`; 
        ->   END IF;
        -> END//
    Query OK, 0 rows affected (0.000 sec)
    
    MariaDB [_]> DELIMITER ;
    
    MariaDB [_]> INSERT INTO `articles`
        -> VALUES (11757, 2000);
    Query OK, 1 row affected (0.000 sec)
    
    MariaDB [_]> SELECT `id_article`, `price`
        -> FROM `articles`;
    +------------+---------+
    | id_article | price   |
    +------------+---------+
    |      11757 | 2000.00 |
    +------------+---------+
    1 row in set (0.000 sec)
    
    MariaDB [_]> INSERT INTO `stock`
        -> VALUES (11757);
    Query OK, 1 row affected (0.001 sec)
    
    MariaDB [_]> SELECT `id_ref`
        -> FROM `stock`;
    +--------+
    | id_ref |
    +--------+
    |  11757 |
    +--------+
    1 row in set (0.000 sec)
    
    MariaDB [_]> INSERT INTO `stock`
        -> VALUES (1);
    ERROR 1644 (45000): INSERT ERROR: missing line in view_articles [art ref: 1]
    

    【讨论】:

    • 您的视图中缺少 UNION 子句。 MariaDB 团队已确认该错误。
    猜你喜欢
    • 2020-02-01
    • 1970-01-01
    • 2013-10-12
    • 2021-08-31
    • 2017-02-09
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    相关资源
    最近更新 更多