Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-42128

INSERT SELECT ON DUPLICATE KEY rejects NULL before a BEFORE UPDATE trigger can replace it

    XMLWordPrintable

Details

    Description

      INSERT ... SELECT ... ON DUPLICATE KEY UPDATE raises error 1048 when its update expression assigns NULL to a NOT NULL column, even though a BEFORE UPDATE trigger replaces that NULL with 99. The equivalent VALUES form invokes the trigger successfully.

      This occurs when INSERT SELECT handles a duplicate key, its update list assigns NULL to a NOT NULL column, and a BEFORE UPDATE trigger replaces that value.

      Steps to reproduce

      1. Run the following SQL as one script in the MariaDB command-line client. The procedure handler captures the candidate error so the remaining observations and cleanup execute.

      CREATE DATABASE trigger_test;
      USE trigger_test;
      SET SESSION sql_mode='STRICT_ALL_TABLES';
      CREATE TABLE t1 (id INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
      CREATE TRIGGER bu BEFORE UPDATE ON t1 FOR EACH ROW SET NEW.b=COALESCE(NEW.b,99);
      INSERT INTO t1 VALUES (1,5);
       
      INSERT INTO t1 (id,b) VALUES (1,2)
        ON DUPLICATE KEY UPDATE b=NULL;
      SELECT 'control', b, b=99 AS oracle FROM t1 WHERE id=1;
      UPDATE t1 SET b=5 WHERE id=1;
       
      DELIMITER //
      CREATE PROCEDURE run_case()
      BEGIN
        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
          GET DIAGNOSTICS CONDITION 1 @errno=MYSQL_ERRNO, @message=MESSAGE_TEXT;
        SET @errno=0, @message='';
        INSERT INTO t1 (id,b)
          SELECT 1,2 UNION ALL SELECT 2,3
          ON DUPLICATE KEY UPDATE b=NULL;
      END//
      DELIMITER ;
       
      CALL run_case();
      SELECT 'candidate_error', @errno, @message;
      SELECT 'candidate_rows', id,b FROM t1 ORDER BY id;
      SELECT 'candidate_oracle',
             @errno=0
             AND COUNT(*)=2
             AND SUM(id=1 AND b=99)=1
             AND SUM(id=2 AND b=3)=1
      FROM t1;
       
      DROP DATABASE trigger_test;
      SELECT 'cleanup', COUNT(*)=0
      FROM information_schema.schemata
      WHERE schema_name='trigger_test';

      Actual result

      The VALUES control succeeds and shows that the trigger replaces NULL with 99. The INSERT SELECT form instead raises error 1048, leaves the original row unchanged at (1,5), and does not insert (2,3):

      control             99    1
      candidate_error     1048  Column 'b' cannot be null
      candidate_rows      1     5
      candidate_oracle    0
      cleanup             1

      The script completes without a server interruption.

      Expected result

      The INSERT SELECT form should apply the same duplicate-key update semantics as the successful VALUES control. The BEFORE UPDATE trigger should receive NEW.b=NULL, replace it with 99, and allow the statement to finish without an error. The final rows should be exactly (1,99) and (2,3), and candidate_oracle should return 1.

      Attachments

        Issue Links

          Activity

            People

              midenok Aleksey Midenkov
              Milo liu
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.