/ Check-in [715cecb8]
Login

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

Overview
Comment:Fix a VDBE stack overflow issue with the UPDATE statement.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | branch-3.3.6
Files: files | file ages | folders
SHA1:715cecb8c795a28f312544031884622827358eda
User & Date: drh 2009-09-03 19:43:49
Context
2009-09-03
19:43
Fix a VDBE stack overflow issue with the UPDATE statement. Leaf check-in: 715cecb8 user: drh tags: branch-3.3.6
2006-06-06
13:34
Version 3.3.6 (CVS 3206) check-in: c11cb07e user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/update.c.

86
87
88
89
90
91
92

93
94
95
96
97
98
99
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
391
392
393
394
395
396
397
398
399


400

401
402
403
404
405
406
407
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRowid;         /* True if the record number is being changed */
  Expr *pRowidExpr = 0;  /* Expression defining the new record number */
  int openAll = 0;       /* True if all indices need to be opened */
  AuthContext sContext;  /* The authorization context */
  NameContext sNC;       /* The name-context to resolve expressions in */
  int iDb;               /* Database containing the table being updated */


#ifndef SQLITE_OMIT_TRIGGER
  int isView;                  /* Trying to update a view */
  int triggers_exist = 0;      /* True if any row triggers exist */
#endif

  int newIdx      = -1;  /* index of trigger "new" temp table       */
................................................................................

    /* The top of the update loop for when there are triggers.
    */
    addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);

    if( !isView ){
      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
      /* Open a cursor and make it point to the record that is
      ** being updated.
      */
      sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
    }
    sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);

................................................................................
    ** the old data for each record to be updated because some columns
    ** might not change and we will need to copy the old value.
    ** Also, the old data is needed to delete the old index entires.
    ** So make the cursor point at the old record.
    */
    if( !triggers_exist ){
      addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
    }


    sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);


    /* If the record number will change, push the record number as it
    ** will be after the update. (The old record number is currently
    ** on top of the stack.)
    */
    if( chngRowid ){
      sqlite3ExprCode(pParse, pRowidExpr);







>







 







<







 







<

>
>

>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
303
304
305
306
307
308
309

310
311
312
313
314
315
316
...
391
392
393
394
395
396
397

398
399
400
401
402
403
404
405
406
407
408
409
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRowid;         /* True if the record number is being changed */
  Expr *pRowidExpr = 0;  /* Expression defining the new record number */
  int openAll = 0;       /* True if all indices need to be opened */
  AuthContext sContext;  /* The authorization context */
  NameContext sNC;       /* The name-context to resolve expressions in */
  int iDb;               /* Database containing the table being updated */
  int regRowid;          /* Memory holding rowid to be updated */

#ifndef SQLITE_OMIT_TRIGGER
  int isView;                  /* Trying to update a view */
  int triggers_exist = 0;      /* True if any row triggers exist */
#endif

  int newIdx      = -1;  /* index of trigger "new" temp table       */
................................................................................

    /* The top of the update loop for when there are triggers.
    */
    addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);

    if( !isView ){
      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);

      /* Open a cursor and make it point to the record that is
      ** being updated.
      */
      sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
    }
    sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);

................................................................................
    ** the old data for each record to be updated because some columns
    ** might not change and we will need to copy the old value.
    ** Also, the old data is needed to delete the old index entires.
    ** So make the cursor point at the old record.
    */
    if( !triggers_exist ){
      addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);

    }
    regRowid = pParse->nMem++;
    sqlite3VdbeAddOp(v, OP_MemStore, regRowid, 0);
    sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
    sqlite3VdbeAddOp(v, OP_MemLoad, regRowid, 0);

    /* If the record number will change, push the record number as it
    ** will be after the update. (The old record number is currently
    ** on top of the stack.)
    */
    if( chngRowid ){
      sqlite3ExprCode(pParse, pRowidExpr);

Added test/bb20090903.test.









































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 2009 Sep 03
#
# 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.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

proc moverows {x} {
  db eval {UPDATE t1 SET x=x+1000}
  return $x
}

do_test bb20090903-1.0 {
  db eval {
    CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
    INSERT INTO t1 VALUES(1,1);
    INSERT INTO t1 VALUES(2,2);
    INSERT INTO t1 SELECT x+2, y+2 FROM t1;
    INSERT INTO t1 SELECT x+4, y+4 FROM t1;
    INSERT INTO t1 SELECT x+8, y+8 FROM t1;
    INSERT INTO t1 SELECT x+16, y+16 FROM t1;
    INSERT INTO t1 SELECT x+32, y+32 FROM t1;
  }
  db function moverows moverows
  db eval {
    UPDATE t1 SET y=moverows(y);
  }
  db eval {
    SELECT * FROM t1;
  }
} {1 1 1001 1 1002 2 1003 3 1004 4 1005 5 1006 6 1007 7 1008 8 1009 9 1010 10 1011 11 1012 12 1013 13 1014 14 1015 15 1016 16 1017 17 1018 18 1019 19 1020 20 1021 21 1022 22 1023 23 1024 24 1025 25 1026 26 1027 27 1028 28 1029 29 1030 30 1031 31 1032 32 1033 33 1034 34 1035 35 1036 36 1037 37 1038 38 1039 39 1040 40 1041 41 1042 42 1043 43 1044 44 1045 45 1046 46 1047 47 1048 48 1049 49 1050 50 1051 51 1052 52 1053 53 1054 54 1055 55 1056 56 1057 57 1058 58 1059 59 1060 60 1061 61 1062 62 1063 63 1064 64}

do_test bb20090903-1.2 {
  db eval {
    DELETE FROM t1 WHERE x<1000;
    UPDATE t1 SET x=x-1000;
    SELECT count(*) FROM t1;
    SELECT count(*) FROM t1 WHERE x!=y;
  }
} {64 0}

do_test bb20090903-1.3 {
  db eval {
    CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
    INSERT INTO t2 SELECT * FROM t1;
    CREATE TRIGGER r2a AFTER UPDATE ON t2 BEGIN
      DELETE FROM t2;
    END;
    UPDATE t2 SET x=x+1000;
    SELECT * FROM t2;
  }
} {}

do_test bb20090903-1.4 {
  db eval {
    INSERT INTO t2 SELECT * FROM t1;
    DROP TRIGGER r2a;
    CREATE TRIGGER r2a BEFORE UPDATE ON t2 BEGIN
      DELETE FROM t2;
    END;
    UPDATE t2 SET x=x+1000;
    SELECT * FROM t2;
  }
} {}

do_test bb20090903-1.5 {
  db eval {
    INSERT INTO t2 SELECT * FROM t1;
    CREATE TABLE t3(x);
    DROP TRIGGER r2a;
    CREATE TRIGGER r2a AFTER UPDATE ON t2 BEGIN
      INSERT INTO t3 VALUES(old.x);
    END;
    UPDATE t2 SET x=x+1000;
    SELECT * FROM t3;
  }
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64}

do_test bb20090903-1.6 {
  db eval {
    DELETE FROM t2;
    INSERT INTO t2 SELECT * FROM t1;
    DROP TRIGGER r2a;
    CREATE TRIGGER r2a AFTER UPDATE ON t2 BEGIN
      DELETE FROM t2 WHERE x>10 AND x<1000;
    END;
    UPDATE t2 SET x=x+1000;
    SELECT * FROM t2;
  }
} {1001 1 1002 2 1003 3 1004 4 1005 5 1006 6 1007 7 1008 8 1009 9 1010 10}

do_test bb20090903-1.7 {
  db eval {
    DELETE FROM t2;
    INSERT INTO t2 SELECT * FROM t1;
    DROP TRIGGER r2a;
    CREATE TRIGGER r2a BEFORE UPDATE ON t2 BEGIN
      DELETE FROM t2 WHERE x>10 AND x<1000;
    END;
    UPDATE t2 SET x=x+1000;
    SELECT * FROM t2;
  }
} {1001 1 1002 2 1003 3 1004 4 1005 5 1006 6 1007 7 1008 8 1009 9 1010 10}



finish_test