SQLite

Check-in [0fedf74e30]
Login

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

Overview
Comment:When a statement causes a ROLLBACK due to an ON CONFLICT clause, other active VMs abort. (CVS 1778)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0fedf74e30026afe2c8caacff3d62cf5c1b1f528
User & Date: drh 2004-06-30 11:14:19.000
Context
2004-06-30
11:28
Skip bigfile.test on Mac OS X. Darwin does not handle large sparse files efficiently and so this test takes a really long time. (CVS 1779) (check-in: a3c38a6d28 user: drh tags: trunk)
11:14
When a statement causes a ROLLBACK due to an ON CONFLICT clause, other active VMs abort. (CVS 1778) (check-in: 0fedf74e30 user: drh tags: trunk)
10:54
Make sure vacuum.test closes all files. (CVS 1777) (check-in: 4077f9a30b user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbeInt.h.
338
339
340
341
342
343
344
345
346


347
348
349
350
351
352
353
  int nResColumn;         /* Number of columns in one row of the result set */
  char **azResColumn;     /* Values for one row of result */ 
  int popStack;           /* Pop the stack this much on entry to VdbeExec() */
  char *zErrMsg;          /* Error message written here */
  u8 resOnStack;          /* True if there are result values on the stack */
  u8 explain;             /* True if EXPLAIN present on SQL command */
  u8 autoCommitOn;        /* True if autocommit got turned on by this program */
  int nChange;            /* Number of db changes made since last reset */
  u8 changeCntOn;         /* True to update the change-counter */


};

/*
** The following are allowed values for Vdbe.magic
*/
#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
#define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */







<

>
>







338
339
340
341
342
343
344

345
346
347
348
349
350
351
352
353
354
  int nResColumn;         /* Number of columns in one row of the result set */
  char **azResColumn;     /* Values for one row of result */ 
  int popStack;           /* Pop the stack this much on entry to VdbeExec() */
  char *zErrMsg;          /* Error message written here */
  u8 resOnStack;          /* True if there are result values on the stack */
  u8 explain;             /* True if EXPLAIN present on SQL command */
  u8 autoCommitOn;        /* True if autocommit got turned on by this program */

  u8 changeCntOn;         /* True to update the change-counter */
  u8 aborted;             /* True if ROLLBACK in another VM causes an abort */
  int nChange;            /* Number of db changes made since last reset */
};

/*
** The following are allowed values for Vdbe.magic
*/
#define VDBE_MAGIC_INIT     0x26bceaa5    /* Building a VDBE program */
#define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */
Changes to src/vdbeapi.c.
145
146
147
148
149
150
151



152
153
154
155
156
157
158
  Vdbe *p = (Vdbe*)pStmt;
  sqlite *db;
  int rc;

  if( p->magic!=VDBE_MAGIC_RUN ){
    return SQLITE_MISUSE;
  }



  db = p->db;
  if( sqlite3SafetyOn(db) ){
    p->rc = SQLITE_MISUSE;
    return SQLITE_MISUSE;
  }
  if( p->pc<0 ){
    db->activeVdbeCnt++;







>
>
>







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  Vdbe *p = (Vdbe*)pStmt;
  sqlite *db;
  int rc;

  if( p->magic!=VDBE_MAGIC_RUN ){
    return SQLITE_MISUSE;
  }
  if( p->aborted ){
    return SQLITE_ABORT;
  }
  db = p->db;
  if( sqlite3SafetyOn(db) ){
    p->rc = SQLITE_MISUSE;
    return SQLITE_MISUSE;
  }
  if( p->pc<0 ){
    db->activeVdbeCnt++;
Changes to src/vdbeaux.c.
1085
1086
1087
1088
1089
1090
1091














1092
1093
1094
1095
1096
1097
1098
        sqlite3BtreeCommit(pBt);
      }
    }
  }

  return rc;
}















/* 
** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
** currently active. An assertion fails if the two counts do not match.
**
** This is a no-op if NDEBUG is defined.







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







1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
        sqlite3BtreeCommit(pBt);
      }
    }
  }

  return rc;
}

/*
** Find every active VM other than pVdbe and change its status to
** aborted.  This happens when on VM causes a rollback.
*/
static void abortOtherActiveVdbes(Vdbe *pVdbe){
  Vdbe *pOther;
  for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
    if( pOther==pVdbe ) continue;
    if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
    closeAllCursors(pOther);
    pOther->aborted = 1;
  }
}

/* 
** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
** currently active. An assertion fails if the two counts do not match.
**
** This is a no-op if NDEBUG is defined.
1179
1180
1181
1182
1183
1184
1185

1186
1187
1188
1189
1190
1191
1192
    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
      xFunc = sqlite3BtreeCommitStmt;
    }else if( p->errorAction==OE_Abort ){
      xFunc = sqlite3BtreeRollbackStmt;
    }else{
      xFunc = sqlite3BtreeRollback;
      db->autoCommit = 1;

    }
  }
  p->autoCommitOn = 0;

  /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
  ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
  ** each backend. If an error occurs and the return code is still







>







1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
      xFunc = sqlite3BtreeCommitStmt;
    }else if( p->errorAction==OE_Abort ){
      xFunc = sqlite3BtreeRollbackStmt;
    }else{
      xFunc = sqlite3BtreeRollback;
      db->autoCommit = 1;
      abortOtherActiveVdbes(p);
    }
  }
  p->autoCommitOn = 0;

  /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
  ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
  ** each backend. If an error occurs and the return code is still
1241
1242
1243
1244
1245
1246
1247

1248
1249
1250
1251
1252
1253
1254
        sqlite3VdbePrintOp(out, i, &p->aOp[i]);
      }
      fclose(out);
    }
  }
#endif
  p->magic = VDBE_MAGIC_INIT;

  return p->rc;
}

/*
** Clean up and delete a VDBE after execution.  Return an integer which is
** the result code.  Write any error message text into *pzErrMsg.
*/







>







1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
        sqlite3VdbePrintOp(out, i, &p->aOp[i]);
      }
      fclose(out);
    }
  }
#endif
  p->magic = VDBE_MAGIC_INIT;
  p->aborted = 0;
  return p->rc;
}

/*
** Clean up and delete a VDBE after execution.  Return an integer which is
** the result code.  Write any error message text into *pzErrMsg.
*/
Added test/rollback.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
# 2004 June 30
#
# 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.  The
# focus of this file is verifying that a rollback in one statement
# caused by an ON CONFLICT ROLLBACK clause aborts any other pending
# statements.
#
# $Id: rollback.test,v 1.1 2004/06/30 11:14:19 drh Exp $

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

db close
set DB [sqlite3 db test.db]

do_test rollback-1.1 {
  execsql {
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(1);
    INSERT INTO t1 VALUES(2);
    INSERT INTO t1 VALUES(3);
    INSERT INTO t1 VALUES(4);
    SELECT * FROM t1;
  }
} {1 2 3 4}

do_test rollback-1.2 {
  execsql {
    CREATE TABLE t3(a unique on conflict rollback);
    INSERT INTO t3 SELECT a FROM t1;
    BEGIN;
    INSERT INTO t1 SELECT * FROM t1;
  }
} {}
do_test rollback-1.3 {
  set STMT [sqlite3_prepare $DB "SELECT a FROM t1" -1 TAIL]
  sqlite3_step $STMT
} {SQLITE_ROW}

# This causes a ROLLBACK, which deletes the table out from underneath the
# SELECT statement.
#
do_test rollback-1.4 {
  catchsql {
    INSERT INTO t3 SELECT a FROM t1;
  }
} {1 {column a is not unique}}

# Try to continue with the SELECT statement
#
do_test rollback-1.5 {
  sqlite3_step $STMT
} {SQLITE_ABORT}

# Restart the SELECT statement
#
do_test rollback-1.6 {
  sqlite3_reset $STMT
} {}
do_test rollback-1.7 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test rollback-1.8 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test rollback-1.9 {
  sqlite3_finalize $STMT
} {SQLITE_OK}

finish_test