/ Check-in [33454b56]
Login

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

Overview
Comment:Have queries interrupted by the progress-handler return SQLITE_INTERRUPT. Rollback any active transaction if a DML statement returns SQLITE_INTERRUPT. (CVS 4061)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 33454b5691637da7ded7d18d7f5726b796260c6b
User & Date: danielk1977 2007-06-13 16:49:49
Context
2007-06-14
20:57
The C-api reference documentation is now generated directly from comments in the sqlite3.h header file. (CVS 4062) check-in: d93c41e9 user: drh tags: trunk
2007-06-13
16:49
Have queries interrupted by the progress-handler return SQLITE_INTERRUPT. Rollback any active transaction if a DML statement returns SQLITE_INTERRUPT. (CVS 4061) check-in: 33454b56 user: danielk1977 tags: trunk
15:22
Fix for #2409. Return SQLITE_IOERR_BLOCKED instead of SQLITE_BUSY in cases where failure to obtain a database lock leaves the cache in an inconsistent state. See additional information at CorruptionFollowingBusyError. (CVS 4060) check-in: ce2c9925 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
543
544
545
546
547
548
549
550
551
552
553
554
555


556
557
558
559
560
561
562
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.624 2007/06/07 19:08:34 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <math.h>
#include "vdbeInt.h"

................................................................................
    ** If the progress callback returns non-zero, exit the virtual machine with
    ** a return code SQLITE_ABORT.
    */
    if( db->xProgress ){
      if( db->nProgressOps==nProgressOps ){
        if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
        if( db->xProgress(db->pProgressArg)!=0 ){
          sqlite3SafetyOn(db);
          rc = SQLITE_ABORT;
          continue; /* skip to the next iteration of the for loop */
        }
        nProgressOps = 0;
        if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;


      }
      nProgressOps++;
    }
#endif

#ifndef NDEBUG
    /* This is to check that the return value of static function







|







 







|
<
<

<

>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
543
544
545
546
547
548
549
550


551

552
553
554
555
556
557
558
559
560
561
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.625 2007/06/13 16:49:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <math.h>
#include "vdbeInt.h"

................................................................................
    ** If the progress callback returns non-zero, exit the virtual machine with
    ** a return code SQLITE_ABORT.
    */
    if( db->xProgress ){
      if( db->nProgressOps==nProgressOps ){
        if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
        if( db->xProgress(db->pProgressArg)!=0 ){
          sqlite3_interrupt(db);


        }

        if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
        CHECK_FOR_INTERRUPT;
        nProgressOps = 0;
      }
      nProgressOps++;
    }
#endif

#ifndef NDEBUG
    /* This is to check that the return value of static function

Changes to src/vdbeaux.c.

1354
1355
1356
1357
1358
1359
1360

1361
1362
1363
1364
1365
1366
1367
1368
  checkActiveVdbeCnt(db);

  /* No commit or rollback needed if the program never started */
  if( p->pc>=0 ){
    int mrc;   /* Primary error code from p->rc */
    /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
    mrc = p->rc & 0xff;

    isSpecialError = ((mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR)?1:0);
    if( isSpecialError ){
      /* This loop does static analysis of the query to see which of the
      ** following three categories it falls into:
      **
      **     Read-only
      **     Query with statement journal
      **     Query without statement journal







>
|







1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
  checkActiveVdbeCnt(db);

  /* No commit or rollback needed if the program never started */
  if( p->pc>=0 ){
    int mrc;   /* Primary error code from p->rc */
    /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
    mrc = p->rc & 0xff;
    isSpecialError = (
        (mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT)?1:0);
    if( isSpecialError ){
      /* This loop does static analysis of the query to see which of the
      ** following three categories it falls into:
      **
      **     Read-only
      **     Query with statement journal
      **     Query without statement journal

Changes to test/interrupt.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
118
119
120
121
122
123
124




125
126
127
128
129
130
131
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#    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 script is the sqlite_interrupt() API.
#
# $Id: interrupt.test,v 1.14 2007/05/15 16:51:37 drh Exp $


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

# Compute a checksum on the entire database.
................................................................................
}
integrity_check interrupt-2.6

# Ticket #594.  If an interrupt occurs in the middle of a transaction
# and that transaction is later rolled back, the internal schema tables do
# not reset.
#




ifcapable tempdb {
  for {set i 1} {$i<50} {incr i 5} {
    do_test interrupt-3.$i.1 {
      execsql {
        BEGIN;
        CREATE TEMP TABLE t2(x,y);
        SELECT name FROM sqlite_temp_master;
................................................................................
        INSERT INTO t2 SELECT * FROM t1;
      }
    } {1 interrupted}
    do_test interrupt-3.$i.3 {
      execsql {
        SELECT name FROM sqlite_temp_master;
      }
    } {t2}
    do_test interrupt-3.$i.4 {
      catchsql {
        ROLLBACK
      }
    } {0 {}}
    do_test interrupt-3.$i.5 {
      catchsql {SELECT name FROM sqlite_temp_master};
      execsql {
        SELECT name FROM sqlite_temp_master;
      }
    } {}
  }







|







 







>
>
>
>







 







|




|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#    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 script is the sqlite_interrupt() API.
#
# $Id: interrupt.test,v 1.15 2007/06/13 16:49:49 danielk1977 Exp $


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

# Compute a checksum on the entire database.
................................................................................
}
integrity_check interrupt-2.6

# Ticket #594.  If an interrupt occurs in the middle of a transaction
# and that transaction is later rolled back, the internal schema tables do
# not reset.
#
# UPDATE: Interrupting a DML statement in the middle of a transaction now
# causes the transaction to roll back. Leaving the transaction open after
# an SQL statement was interrupted halfway through risks database corruption.
#
ifcapable tempdb {
  for {set i 1} {$i<50} {incr i 5} {
    do_test interrupt-3.$i.1 {
      execsql {
        BEGIN;
        CREATE TEMP TABLE t2(x,y);
        SELECT name FROM sqlite_temp_master;
................................................................................
        INSERT INTO t2 SELECT * FROM t1;
      }
    } {1 interrupted}
    do_test interrupt-3.$i.3 {
      execsql {
        SELECT name FROM sqlite_temp_master;
      }
    } {}
    do_test interrupt-3.$i.4 {
      catchsql {
        ROLLBACK
      }
    } {1 {cannot rollback - no transaction is active}}
    do_test interrupt-3.$i.5 {
      catchsql {SELECT name FROM sqlite_temp_master};
      execsql {
        SELECT name FROM sqlite_temp_master;
      }
    } {}
  }

Changes to test/progress.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
93
94
95
96
97
98
99
100
101



102
103
104
105
106
107
108
109
110
111
112
113
114


115
116
117
118
119
120
121
122
123
124
125
...
139
140
141
142
143
144
145
146
147
148
149
150
151
#    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 testing the 'progress callback'.
#
# $Id: progress.test,v 1.6 2006/05/26 19:57:20 drh Exp $

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

# If the progress callback is not available in this build, skip this
# whole file.
ifcapable !progress {
................................................................................
    INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 9
  }
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Test that an active transaction remains active and not rolled back after the
# progress query abandons a query. 



do_test progress-1.3 {

  db progress 0 ""
  execsql BEGIN
  execsql {
    INSERT INTO t1 VALUES(11)
  }
  db progress 1 "expr 1"
  catchsql {
    INSERT INTO t1 VALUES(12)
  }
  db progress 0 ""
  execsql COMMIT


  execsql {
    SELECT count(*) FROM t1
  }
} 11

# Check that a value of 0 for N means no progress callback
do_test progress-1.4 {
  set counter 0
  db progress 0 "[namespace code {incr counter}] ; expr 0"
  execsql {
    SELECT * FROM t1;
................................................................................
    set ::rx [db eval {SELECT count(*) FROM t1}]
    return [expr 0]
  }
  db progress 10 set_rx
  db eval {
    SELECT sum(a) FROM t1
  }
} {66}
do_test progress-1.6 {
  set ::rx
} {11}

finish_test







|







 







|
|
>
>
>












|
>
>



|







 







|


|


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
144
145
146
147
148
149
150
151
152
153
154
155
156
#    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 testing the 'progress callback'.
#
# $Id: progress.test,v 1.7 2007/06/13 16:49:49 danielk1977 Exp $

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

# If the progress callback is not available in this build, skip this
# whole file.
ifcapable !progress {
................................................................................
    INSERT INTO t1 SELECT a+10 FROM t1 WHERE a < 9
  }
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Test that an active transaction remains active and not rolled back 
# after the progress query abandons a query. 
#
# UPDATE: It is now recognised that this is a sure route to database
# corruption. So the transaction is rolled back.
do_test progress-1.3 {

  db progress 0 ""
  execsql BEGIN
  execsql {
    INSERT INTO t1 VALUES(11)
  }
  db progress 1 "expr 1"
  catchsql {
    INSERT INTO t1 VALUES(12)
  }
  db progress 0 ""
  catchsql COMMIT
} {1 {cannot commit - no transaction is active}}
do_test progress-1.3.1 {
  execsql {
    SELECT count(*) FROM t1
  }
} 10

# Check that a value of 0 for N means no progress callback
do_test progress-1.4 {
  set counter 0
  db progress 0 "[namespace code {incr counter}] ; expr 0"
  execsql {
    SELECT * FROM t1;
................................................................................
    set ::rx [db eval {SELECT count(*) FROM t1}]
    return [expr 0]
  }
  db progress 10 set_rx
  db eval {
    SELECT sum(a) FROM t1
  }
} {55}
do_test progress-1.6 {
  set ::rx
} {10}

finish_test