/ Check-in [7bb23c2a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Clarification of the behavior of a BEFORE UPDATE trigger when the trigger changes the values of some of the columns used to compute new columns in the UPDATE.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:7bb23c2a3d37f0d5e5515b917860818906819d54a0066e1ba8e9792a82f7d279
User & Date: drh 2018-04-26 15:04:18
Context
2018-04-26
16:13
When processing an "ORDER BY ... LIMIT" that does not use an index, check whether or not a record may appear in the final result set before adding it to the sorter. Closed-Leaf check-in: 71bf91c2 user: dan tags: sorter-limit-opt
15:50
Ensure that new.* values of an UPDATE do not get clobbered after the BEFORE triggers run when unmodified columns of the row being updated are reloaded. Fix for ticket [d85fffd6ffe856092ed8da] check-in: 0a514e62 user: drh tags: trunk
15:04
Clarification of the behavior of a BEFORE UPDATE trigger when the trigger changes the values of some of the columns used to compute new columns in the UPDATE. check-in: 7bb23c2a user: drh tags: trunk
12:27
Improved VDBE comment on the OP_Param opcode. No substantial changes. check-in: 368c14da user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/update.c.

635
636
637
638
639
640
641
642
643
644
645



646
647
648
649
650
651
652
      sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
      VdbeCoverage(v);
    }else{
      sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
      VdbeCoverage(v);
    }

    /* If it did not delete it, the row-trigger may still have modified 
    ** some of the columns of the row being updated. Load the values for 
    ** all columns not modified by the update statement into their 
    ** registers in case this has happened.



    */
    for(i=0; i<pTab->nCol; i++){
      if( aXRef[i]<0 && i!=pTab->iPKey ){
        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
      }
    }
  }







|

|
|
>
>
>







635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
      sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
      VdbeCoverage(v);
    }else{
      sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
      VdbeCoverage(v);
    }

    /* If it did not delete it, the BEFORE trigger may still have modified 
    ** some of the columns of the row being updated. Load the values for 
    ** all columns not modified by the update statement into their registers
    ** in case this has happened. Only unmodified columns are reloaded.
    ** The values computed for modified columns use the values before the
    ** BEFORE trigger runs.  See test case trigger1-18.0 (added 2018-04-26)
    ** for an example.
    */
    for(i=0; i<pTab->nCol; i++){
      if( aXRef[i]<0 && i!=pTab->iPKey ){
        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
      }
    }
  }

Changes to test/trigger1.test.

724
725
726
727
728
729
730























731
  CREATE TRIGGER t17b_ai AFTER INSERT ON t17b BEGIN
    UPDATE t17b SET ss = 4;
  END;
  INSERT INTO t17a(ii) VALUES('1');
  PRAGMA integrity_check;
} {ok}
























finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  CREATE TRIGGER t17b_ai AFTER INSERT ON t17b BEGIN
    UPDATE t17b SET ss = 4;
  END;
  INSERT INTO t17a(ii) VALUES('1');
  PRAGMA integrity_check;
} {ok}

# 2018-04-26
# When a BEFORE UPDATE trigger changes a column value in a row being
# updated, and that column value is used by the UPDATE to change other
# column, the value used to compute the update is from before the trigger.
# In the example that follows, the value of "b" in "c=b" is 2 (the value
# prior to running the BEFORE UPDATE trigger) not 1000.
#
do_execsql_test trigger1-18.0 {
  CREATE TABLE t18(a PRIMARY KEY,b,c);
  INSERT INTO t18(a,b,c) VALUES(1,2,3);
  CREATE TRIGGER t18r1 BEFORE UPDATE ON t18 BEGIN
    UPDATE t18 SET b=1000 WHERE a=old.a;
  END;
  UPDATE t18 SET c=b WHERE a=1;
  SELECT * FROM t18;
} {1 1000 2}  ;# Not: 1 1000 1000 
do_execsql_test trigger1-18.1 {
  DELETE FROM t18;
  INSERT INTO t18(a,b,c) VALUES(1,2,3);
  UPDATE t18 SET c=b, b=b+1 WHERE a=1;
  SELECT * FROM t18;
} {1 3 2}     ;# Not: 1 1001 1000

finish_test