-C Simplify\sthe\strigger\slogic\sfor\sDELETE,\sINSERT,\sand\sUPDATE.\s(CVS\s2157)
-D 2004-12-07T14:06:13
+C Only\sevaluate\sexpressions\sonce\sfor\sUPDATE\sand\sINSERT\sstatements\sthat\nhave\sBEFORE\striggers.\s\sFix\sfor\sticket\s#980.\s(CVS\s2158)
+D 2004-12-07T15:41:49
F Makefile.in da09f379b80c8cd78d78abaa0f32ca90a124e884
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
F src/cursor.c f883813759742068890b1f699335872bfa8fdf41
F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f
F src/delete.c 4a70ac0bd0159fe38efdaf2cb44723256b0f7b37
-F src/expr.c 7987e5f50c189d4c2550f247f8039c06ea272345
+F src/expr.c d61efc526449a7a4c725325a3001a614cbcc3bed
F src/func.c b668e5ad043176049454c95a6a780367a0e8f6bb
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
-F src/insert.c 094972ccacff759042b0692b558a8ac114e5d417
+F src/insert.c 0b9077c6752530e9919a8c84375cfa2c4652260a
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
F src/main.c fc383dc9cf03847b96e5ed9942696467725cfdfd
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
F src/select.c 36cc9da999596578566e167d310e99f2005a7f03
F src/shell.c e8f4f486cbf6e60d81173146ac8a6522c930fa51
F src/sqlite.h.in fa75850f412808afd38fddc1fd6456f4efc6fb97
-F src/sqliteInt.h 3343e12d160d49fcca224c29ee39f5e6d6f980db
+F src/sqliteInt.h e0c5c1af95e975645c7a09b151af258d6fca1c53
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c 68b45ae5a96424abdc1732cb03b1efbb0c1821b3
F src/test1.c b7d94c54e58f95452387a5cabdf98b2be8059f29
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
F src/tokenize.c 2ad3d1ae1a0a70746db0b31a0a74f58050a3c39a
F src/trigger.c 98f3b07c08ba01b34cff139ef9687883d325ae8e
-F src/update.c 67a95e5c24cbedb7f943cd95c1082c112b401f25
+F src/update.c aa92fa2203b2233008dd75a1e97c4b441be24a7f
F src/utf.c e45ce11be6922408cd381561721f6cca7d3b992a
F src/util.c 4a8db4e97a3cfda12ad8dda3e77dd2d00ad1de5e
F src/vacuum.c 705256e1111521fa04f0029de7f1667bc131d015
F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
F test/trigger4.test e7c0812b14750754602468f15495260e8c6625e0
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
+F test/trigger6.test 88b4c0c9f67e4244af39627538526bbaf97132f5
F test/types.test f0a98d10c5ecc9865d19dc94486f9873afc6bb6b
F test/types2.test f23c147a2ab3e51d5dbcfa9987200db5acba7aa7
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
-P 7b20f2b71f679e72b6cb3b78ccb31b4e7c4bd48b
-R d980a20ed4665faa1df32ccf64263d38
+P 8e164ab27771aced9a592ea4b7c27e9f184181a5
+R a25e54595d969baf18fc12c2ed784b4c
U drh
-Z dcfe3e605fa32f759f8dbe1e7c83903c
+Z c29cc9b7f0c7e31234ed5d8c1f56e385
-8e164ab27771aced9a592ea4b7c27e9f184181a5
\ No newline at end of file
+4852186aca3be6ea40069b6831079197e5fa757a
\ No newline at end of file
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.174 2004/11/23 01:47:30 drh Exp $
+** $Id: expr.c,v 1.175 2004/12/07 15:41:49 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
}
}
+/*
+** Generate code that evalutes the given expression and leaves the result
+** on the stack. See also sqlite3ExprCode().
+**
+** This routine might also cache the result and modify the pExpr tree
+** so that it will make use of the cached result on subsequent evaluations
+** rather than evaluate the whole expression again. Trivial expressions are
+** not cached. If the expression is cached, its result is stored in a
+** memory location.
+*/
+void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr){
+ Vdbe *v = pParse->pVdbe;
+ int iMem;
+ int addr1, addr2;
+ if( v==0 ) return;
+ addr1 = sqlite3VdbeCurrentAddr(v);
+ sqlite3ExprCode(pParse, pExpr);
+ addr2 = sqlite3VdbeCurrentAddr(v);
+ if( addr2>addr1+1 || sqlite3VdbeGetOp(v, addr1)->opcode==OP_Function ){
+ iMem = pExpr->iTable = pParse->nMem++;
+ sqlite3VdbeAddOp(v, OP_MemStore, iMem, 0);
+ pExpr->op = TK_REGISTER;
+ }
+}
+
/*
** Generate code that pushes the value of every element of the given
** expression list onto the stack.
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.127 2004/12/07 14:06:13 drh Exp $
+** $Id: insert.c,v 1.128 2004/12/07 15:41:49 drh Exp $
*/
#include "sqliteInt.h"
}else if( pSelect ){
sqlite3VdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
}else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr);
+ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.345 2004/12/07 14:06:13 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.346 2004/12/07 15:41:49 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**, Fetch*);
void sqlite3WhereEnd(WhereInfo*);
void sqlite3ExprCode(Parse*, Expr*);
+void sqlite3ExprCodeAndCache(Parse*, Expr*);
int sqlite3ExprCodeExprList(Parse*, ExprList*);
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.98 2004/12/07 14:06:13 drh Exp $
+** $Id: update.c,v 1.99 2004/12/07 15:41:49 drh Exp $
*/
#include "sqliteInt.h"
/* Generate the NEW table
*/
if( chngRecno ){
- sqlite3ExprCode(pParse, pRecnoExpr);
+ sqlite3ExprCodeAndCache(pParse, pRecnoExpr);
}else{
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
}
- for(i=0; i<pTab->nCol; i++){ /* TODO: Factor out this loop as common code */
+ for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
continue;
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
}else{
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
+ sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
--- /dev/null
+# 2004 December 07
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file implements tests to make sure expression of an INSERT
+# and UPDATE statement are only evaluated once. See ticket #980.
+# If an expression uses a function that has side-effects or which
+# is not deterministic (ex: random()) then we want to make sure
+# that the same evaluation occurs for the actual INSERT/UPDATE and
+# for the NEW.* fields of any triggers that fire.
+#
+# $Id: trigger6.test,v 1.1 2004/12/07 15:41:50 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable {!trigger} {
+ finish_test
+ return
+}
+
+do_test trigger6-1.1 {
+ execsql {
+ CREATE TABLE t1(x, y);
+ CREATE TABLE log(a, b, c);
+ CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN
+ INSERT INTO log VALUES(1, new.x, new.y);
+ END;
+ CREATE TRIGGER r2 BEFORE UPDATE ON t1 BEGIN
+ INSERT INTO log VALUES(2, new.x, new.y);
+ END;
+ }
+ set ::trigger6_cnt 0
+ proc trigger6_counter {args} {
+ incr ::trigger6_cnt
+ return $::trigger6_cnt
+ }
+ db function counter trigger6_counter
+ execsql {
+ INSERT INTO t1 VALUES(1,counter());
+ SELECT * FROM t1;
+ }
+} {1 1}
+do_test trigger6-1.2 {
+ execsql {
+ SELECT * FROM log;
+ }
+} {1 1 1}
+do_test trigger6-1.3 {
+ execsql {
+ DELETE FROM t1;
+ DELETE FROM log;
+ INSERT INTO t1 VALUES(2,counter(2,3)+4);
+ SELECT * FROM t1;
+ }
+} {2 6.0}
+do_test trigger6-1.4 {
+ execsql {
+ SELECT * FROM log;
+ }
+} {1 2 6.0}
+do_test trigger6-1.5 {
+ execsql {
+ DELETE FROM log;
+ UPDATE t1 SET y=counter(5);
+ SELECT * FROM t1;
+ }
+} {2 3}
+do_test trigger6-1.6 {
+ execsql {
+ SELECT * FROM log;
+ }
+} {2 2 3}
+
+finish_test