/ Check-in [2fe9f510]
Login

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

Overview
Comment:VACUUM returns SQLITE_INTERRUPT when interrupted. Ticket #593. (CVS 1228)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:2fe9f5101cb0f743532912ece3d37f6c873e7025
User & Date: drh 2004-02-12 13:02:56
Context
2004-02-12
15:31
Always reload the schema after a rollback. Ticket #594. (CVS 1229) check-in: 12c7a83f user: drh tags: trunk
13:02
VACUUM returns SQLITE_INTERRUPT when interrupted. Ticket #593. (CVS 1228) check-in: 2fe9f510 user: drh tags: trunk
2004-02-11
16:38
Only define _FILE_OFFSET_BITS if it is not already defined. Ticket #605. (CVS 1227) check-in: 300c5543 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vacuum.c.

    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains code used to implement the VACUUM command.
    13     13   **
    14     14   ** Most of the code in this file may be omitted by defining the
    15     15   ** SQLITE_OMIT_VACUUM macro.
    16     16   **
    17         -** $Id: vacuum.c,v 1.10 2004/02/11 09:46:33 drh Exp $
           17  +** $Id: vacuum.c,v 1.11 2004/02/12 13:02:56 drh Exp $
    18     18   */
    19     19   #include "sqliteInt.h"
    20     20   #include "os.h"
    21     21   
    22     22   /*
    23     23   ** A structure for holding a dynamic string - a string that can grow
    24     24   ** without bound. 
................................................................................
   104    104   /*
   105    105   ** This is the second stage callback.  Each invocation contains all the
   106    106   ** data for a single row of a single table in the original database.  This
   107    107   ** routine must write that information into the new database.
   108    108   */
   109    109   static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
   110    110     vacuumStruct *p = (vacuumStruct*)pArg;
   111         -  int rc = 0;
   112    111     const char *zSep = "(";
   113    112     int i;
   114    113   
   115    114     if( argv==0 ) return 0;
   116    115     p->s2.nUsed = 0;
   117    116     appendText(&p->s2, "INSERT INTO ", -1);
   118    117     appendQuoted(&p->s2, p->zTable);
................................................................................
   123    122       if( argv[i]==0 ){
   124    123         appendText(&p->s2, "NULL", 4);
   125    124       }else{
   126    125         appendQuoted(&p->s2, argv[i]);
   127    126       }
   128    127     }
   129    128     appendText(&p->s2,")", 1);
   130         -  rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
   131         -  return rc;
          129  +  p->rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
          130  +  return p->rc;
   132    131   }
   133    132   
   134    133   /*
   135    134   ** This is the first stage callback.  Each invocation contains three
   136    135   ** arguments where are taken from the SQLITE_MASTER table of the original
   137    136   ** database:  (1) the entry type, (2) the entry name, and (3) the SQL for
   138    137   ** the entry.  In all cases, execute the SQL of the third argument.
................................................................................
   156    155       p->zTable = argv[1];
   157    156       rc = sqlite_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg);
   158    157       if( zErrMsg ){
   159    158         sqliteSetString(p->pzErrMsg, zErrMsg, (char*)0);
   160    159         sqlite_freemem(zErrMsg);
   161    160       }
   162    161     }
          162  +  if( rc!=SQLITE_ABORT ) p->rc = rc;
   163    163     return rc;
   164    164   }
   165    165   
   166    166   /*
   167    167   ** This callback is used to transfer PRAGMA settings from one database
   168    168   ** to the other.  The value in argv[0] should be passed to a pragma
   169    169   ** identified by ((vacuumStruct*)pArg)->zPragma.
   170    170   */
   171    171   static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){
   172    172     vacuumStruct *p = (vacuumStruct*)pArg;
   173         -  int rc = 0;
   174    173     char zBuf[200];
   175    174     assert( argc==1 );
   176    175     if( argv==0 ) return 0;
   177    176     assert( argv[0]!=0 );
   178    177     assert( strlen(p->zPragma)<100 );
   179    178     assert( strlen(argv[0])<30 );
   180    179     sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]);
   181         -  rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
   182         -  return rc;
          180  +  p->rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
          181  +  return p->rc;
   183    182   }
   184    183   
   185    184   /*
   186    185   ** Generate a random name of 20 character in length.
   187    186   */
   188    187   static void randomName(unsigned char *zBuf){
   189    188     static const unsigned char zChars[] =
................................................................................
   269    268     
   270    269     dbNew = sqlite_open(zTemp, 0, &zErrMsg);
   271    270     if( dbNew==0 ){
   272    271       sqliteSetString(pzErrMsg, "unable to open a temporary database at ",
   273    272          zTemp, " - ", zErrMsg, (char*)0);
   274    273       goto end_of_vacuum;
   275    274     }
   276         -  if( execsql(pzErrMsg, db, "BEGIN") ) goto end_of_vacuum;
   277         -  if( execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN") ){
          275  +  if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
          276  +  if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
   278    277       goto end_of_vacuum;
   279    278     }
   280    279     
   281    280     sVac.dbOld = db;
   282    281     sVac.dbNew = dbNew;
   283    282     sVac.pzErrMsg = pzErrMsg;
   284    283     for(i=0; rc==SQLITE_OK && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){
................................................................................
   312    311     if( dbNew ) sqlite_close(dbNew);
   313    312     sqliteOsDelete(zTemp);
   314    313     sqliteFree(zTemp);
   315    314     sqliteFree(sVac.s1.z);
   316    315     sqliteFree(sVac.s2.z);
   317    316     if( zErrMsg ) sqlite_freemem(zErrMsg);
   318    317     if( rc==SQLITE_ABORT ) rc = SQLITE_ERROR;
   319         -  return rc;
          318  +  if( sVac.rc!=SQLITE_OK ) rc = sVac.rc;
          319  +  return sVac.rc;
   320    320   #endif
   321    321   }

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.259 2004/02/11 09:46:33 drh Exp $
           46  +** $Id: vdbe.c,v 1.260 2004/02/12 13:02:56 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
   505    505     assert( p->explain==0 );
   506    506     if( sqlite_malloc_failed ) goto no_mem;
   507    507     pTos = p->pTos;
   508    508     if( p->popStack ){
   509    509       popStack(&pTos, p->popStack);
   510    510       p->popStack = 0;
   511    511     }
          512  +  CHECK_FOR_INTERRUPT;
   512    513     for(pc=p->pc; rc==SQLITE_OK; pc++){
   513    514       assert( pc>=0 && pc<p->nOp );
   514    515       assert( pTos<=&p->aStack[pc] );
   515    516   #ifdef VDBE_PROFILE
   516    517       origPc = pc;
   517    518       start = hwtime();
   518    519   #endif

Added test/interrupt.test.

            1  +# 2004 Feb 8
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this script is the sqlite_interrupt() API.
           13  +#
           14  +# $Id: interrupt.test,v 1.1 2004/02/12 13:02:57 drh Exp $
           15  +
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +
           20  +# Compute a checksum on the entire database.
           21  +#
           22  +proc cksum {{db db}} {
           23  +  set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n
           24  +  foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
           25  +    append txt [$db eval "SELECT * FROM $tbl"]\n
           26  +  }
           27  +  foreach prag {default_synchronous default_cache_size} {
           28  +    append txt $prag-[$db eval "PRAGMA $prag"]\n
           29  +  }
           30  +  set cksum [string length $txt]-[md5 $txt]
           31  +  # puts $cksum-[file size test.db]
           32  +  return $cksum
           33  +}
           34  +
           35  +# This routine attempts to execute the sql in $sql.  It triggers an
           36  +# interrupt a progressively later and later points during the processing
           37  +# and checks to make sure SQLITE_INTERRUPT is returned.  Eventually,
           38  +# the routine completes successfully.
           39  +#
           40  +proc interrupt_test {testid sql result {initcnt 0}} {
           41  +  set orig_sum [cksum]
           42  +  set i $initcnt
           43  +  while 1 {
           44  +    incr i
           45  +    set ::sqlite_interrupt_count $i
           46  +    do_test $testid.$i.1 [format {
           47  +      set ::r [catchsql %s]
           48  +      set ::code [db errorcode]
           49  +      expr {$::code==0 || $::code==9}
           50  +    } [list $sql]] 1
           51  +    if {$::code==9} {
           52  +      do_test $testid.$i.2 {
           53  +        cksum
           54  +      } $orig_sum
           55  +    } else {
           56  +      do_test $testid.$i.99 {
           57  +        set ::r
           58  +      } [list 0 $result]
           59  +      break
           60  +    }
           61  +  }
           62  +  set ::sqlite_interrupt_count 0
           63  +}
           64  +
           65  +do_test interrupt-1.1 {
           66  +  execsql {
           67  +    CREATE TABLE t1(a,b);
           68  +    SELECT name FROM sqlite_master;
           69  +  }
           70  +} {t1}
           71  +interrupt_test interrupt-1.2 {DROP TABLE t1} {}
           72  +do_test interrupt-1.3 {
           73  +  execsql {
           74  +    SELECT name FROM sqlite_master;
           75  +  }
           76  +} {}
           77  +integrity_check interrupt-1.4
           78  +
           79  +do_test interrrupt-2.1 {
           80  +  execsql {
           81  +    BEGIN;
           82  +    CREATE TABLE t1(a,b);
           83  +    INSERT INTO t1 VALUES(1,randstr(300,400));
           84  +    INSERT INTO t1 SELECT a+1, randstr(300,400) FROM t1;
           85  +    INSERT INTO t1 SELECT a+2, a || '-' || b FROM t1;
           86  +    INSERT INTO t1 SELECT a+4, a || '-' || b FROM t1;
           87  +    INSERT INTO t1 SELECT a+8, a || '-' || b FROM t1;
           88  +    INSERT INTO t1 SELECT a+16, a || '-' || b FROM t1;
           89  +    INSERT INTO t1 SELECT a+32, a || '-' || b FROM t1;
           90  +    COMMIT;
           91  +    UPDATE t1 SET b=substr(b,-5,5);
           92  +    SELECT count(*) from t1;
           93  +  }
           94  +} 64
           95  +set origsize [file size test.db]
           96  +set cksum [db eval {SELECT md5sum(a || b) FROM t1}]
           97  +interrupt_test interrupt-2.2 {VACUUM} {} 100
           98  +do_test interrupt-2.3 {
           99  +  execsql {
          100  +    SELECT md5sum(a || b) FROM t1;
          101  +  }
          102  +} $cksum
          103  +do_test interrupt-2.4 {
          104  +  expr {$::origsize>[file size test.db]}
          105  +} 1
          106  +integrity_check interrupt-2.5
          107  +
          108  +
          109  +finish_test