SQLite

Check-in [cb3cbe00be]
Login

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

Overview
Comment:Ensure master journal file is deleted when a transaction is committed. (CVS 1586)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: cb3cbe00be9a42e974688016a056053cedb55eef
User & Date: danielk1977 2004-06-14 09:35:17.000
Context
2004-06-14
09:41
Bugfix for previous checkin. (CVS 1587) (check-in: 2737505f28 user: danielk1977 tags: trunk)
09:35
Ensure master journal file is deleted when a transaction is committed. (CVS 1586) (check-in: cb3cbe00be user: danielk1977 tags: trunk)
08:26
Check the value of the schema cookie before reading the sqlite_master table. (CVS 1585) (check-in: 80c299f883 user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.219 2004/06/13 23:07:04 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.220 2004/06/14 09:35:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** A pointer to this structure is used to communicate information
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  ** Meta values are as follows:
  **    meta[0]   Schema cookie.  Changes with each schema change.
  **    meta[1]   File format of schema layer.
  **    meta[2]   Size of the page cache.
  **    meta[3]   Synchronous setting.  1:off, 2:normal, 3:full
  **    meta[4]   Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE
  **    meta[5]   Pragma temp_store value.  See comments on BtreeFactory
  **    meta[6]
  **    meta[7]
  **    meta[8]
  **    meta[9]
  **
  ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to
  ** the possible values of meta[4].
  */







|







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  ** Meta values are as follows:
  **    meta[0]   Schema cookie.  Changes with each schema change.
  **    meta[1]   File format of schema layer.
  **    meta[2]   Size of the page cache.
  **    meta[3]   Synchronous setting.  1:off, 2:normal, 3:full
  **    meta[4]   Db text encoding. 1:UTF-8 3:UTF-16 LE 4:UTF-16 BE
  **    meta[5]   Pragma temp_store value.  See comments on BtreeFactory
  **    meta[6]   
  **    meta[7]
  **    meta[8]
  **    meta[9]
  **
  ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to
  ** the possible values of meta[4].
  */
Changes to src/os.h.
144
145
146
147
148
149
150

151
152
153
154
155
156
157
int sqlite3OsDelete(const char*);
int sqlite3OsFileExists(const char*);
int sqliteOsFileRename(const char*, const char*);
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
int sqlite3OsOpenReadOnly(const char*, OsFile*);
int sqlite3OsOpenDirectory(const char*, OsFile*);

int sqlite3OsTempFileName(char*);
int sqlite3OsClose(OsFile*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, off_t offset);
int sqlite3OsSync(OsFile*);
int sqlite3OsTruncate(OsFile*, off_t size);







>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
int sqlite3OsDelete(const char*);
int sqlite3OsFileExists(const char*);
int sqliteOsFileRename(const char*, const char*);
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
int sqlite3OsOpenReadOnly(const char*, OsFile*);
int sqlite3OsOpenDirectory(const char*, OsFile*);
int sqlite3OsSyncDirectory(const char*);
int sqlite3OsTempFileName(char*);
int sqlite3OsClose(OsFile*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, off_t offset);
int sqlite3OsSync(OsFile*);
int sqlite3OsTruncate(OsFile*, off_t size);
Changes to src/os_mac.c.
387
388
389
390
391
392
393








394
395
396
397
398
399
400
  if( PBFlushFileSync(&params) != noErr ){
# endif
    return SQLITE_IOERR;
  }else{
    return SQLITE_OK;
  }
}









/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
  SimulateIOError(SQLITE_IOERR);
# ifdef _LARGE_FILE







>
>
>
>
>
>
>
>







387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  if( PBFlushFileSync(&params) != noErr ){
# endif
    return SQLITE_IOERR;
  }else{
    return SQLITE_OK;
  }
}

/*
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
int sqlite3OsSyncDirectory(const char *zDirname){
  return SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
  SimulateIOError(SQLITE_IOERR);
# ifdef _LARGE_FILE
Changes to src/os_unix.c.
615
616
617
618
619
620
621
















622
623
624
625
626
627
628
      fsync(id->dirfd);
      close(id->dirfd);  /* Only need to sync once, so close the directory */
      id->dirfd = -1;    /* when we are done. */
    }
    return SQLITE_OK;
  }
}

















/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
  SimulateIOError(SQLITE_IOERR);
  return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;







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







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
      fsync(id->dirfd);
      close(id->dirfd);  /* Only need to sync once, so close the directory */
      id->dirfd = -1;    /* when we are done. */
    }
    return SQLITE_OK;
  }
}

/*
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
int sqlite3OsSyncDirectory(const char *zDirname){
  int fd;
  int r;
  fd = open(zDirname, O_RDONLY|O_BINARY, 0644);
  if( fd<0 ){
    return SQLITE_CANTOPEN; 
  }
  r = fsync(fd);
  close(fd);
  return ((r==0)?SQLITE_OK:SQLITE_IOERR);
}

/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
  SimulateIOError(SQLITE_IOERR);
  return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
Changes to src/os_win.c.
285
286
287
288
289
290
291








292
293
294
295
296
297
298
  TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
  if( FlushFileBuffers(id->h) ){
    return SQLITE_OK;
  }else{
    return SQLITE_IOERR;
  }
}









/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
  LONG upperBits = nByte>>32;
  TRACE3("TRUNCATE %d %lld\n", id->h, nByte);







>
>
>
>
>
>
>
>







285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
  if( FlushFileBuffers(id->h) ){
    return SQLITE_OK;
  }else{
    return SQLITE_IOERR;
  }
}

/*
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
int sqlite3OsSyncDirectory(const char *zDirname){
  return SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
  LONG upperBits = nByte>>32;
  TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
Changes to src/vdbeaux.c.
1083
1084
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
1113
1114

1115
1116
1117
1118



1119
1120













1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
      sqlite3OsClose(&master);
      sqlite3OsDelete(zMaster);
      sqliteFree(zMaster);
      return rc;
    }
    rc = sqlite3OsSync(&master);
    if( rc!=SQLITE_OK ){

      sqliteFree(zMaster);
      return rc;
    }
    sqlite3OsClose(&master);

    /* Sync all the db files involved in the transaction. The same call
    ** sets the master journal pointer in each individual journal. If
    ** an error occurs here, do not delete the master journal file.
    **
    ** If the error occurs during the first call to sqlite3BtreeSync(),
    ** then there is a chance that the master journal file will be
    ** orphaned. But we cannot delete it, in case the master journal
    ** file name was written into the journal file before the failure
    ** occured.
    */
    for(i=0; i<db->nDb; i++){ 
      Btree *pBt = db->aDb[i].pBt;
      if( pBt && sqlite3BtreeIsInTrans(pBt) ){
        rc = sqlite3BtreeSync(pBt, zMaster);
        if( rc!=SQLITE_OK ){

          sqliteFree(zMaster);
          return rc;
        }
      }
    }

    sqliteFree(zMaster);
    zMaster = 0;

    /* Delete the master journal file. This commits the transaction. */



    rc = sqlite3OsDelete(zMaster);
    assert( rc==SQLITE_OK );














    /* All files and directories have already been synced, so the following
    ** calls to sqlite3BtreeCommit() are only closing files and deleting
    ** journals. If something goes wrong while this is happening we don't
    ** really care. The integrity of the transaction is already guarenteed,
    ** but some stray 'cold' journals may be lying around. Returning an
    ** error code won't help matters.
    */
    for(i=0; i<db->nDb; i++){ 
      Btree *pBt = db->aDb[i].pBt;
      if( pBt ){
        sqlite3BtreeCommit(pBt);







>



<
















>





>



|
>
>
>


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




|







1083
1084
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
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
      sqlite3OsClose(&master);
      sqlite3OsDelete(zMaster);
      sqliteFree(zMaster);
      return rc;
    }
    rc = sqlite3OsSync(&master);
    if( rc!=SQLITE_OK ){
      sqlite3OsClose(&master);
      sqliteFree(zMaster);
      return rc;
    }


    /* Sync all the db files involved in the transaction. The same call
    ** sets the master journal pointer in each individual journal. If
    ** an error occurs here, do not delete the master journal file.
    **
    ** If the error occurs during the first call to sqlite3BtreeSync(),
    ** then there is a chance that the master journal file will be
    ** orphaned. But we cannot delete it, in case the master journal
    ** file name was written into the journal file before the failure
    ** occured.
    */
    for(i=0; i<db->nDb; i++){ 
      Btree *pBt = db->aDb[i].pBt;
      if( pBt && sqlite3BtreeIsInTrans(pBt) ){
        rc = sqlite3BtreeSync(pBt, zMaster);
        if( rc!=SQLITE_OK ){
          sqlite3OsClose(&master);
          sqliteFree(zMaster);
          return rc;
        }
      }
    }
    sqlite3OsClose(&master);
    sqliteFree(zMaster);
    zMaster = 0;

    /* Delete the master journal file. This commits the transaction. After
    ** doing this the directory is synced again before any individual
    ** transaction files are deleted.
    */
    rc = sqlite3OsDelete(zMaster);
    assert( rc==SQLITE_OK );
    rc = sqlite3OsSyncDirectory(zMainFile);
    if( rc!=SQLITE_OK ){
      /* This is not good. The master journal file has been deleted, but
      ** the directory sync failed. There is no completely safe course of
      ** action from here. The individual journals contain the name of the
      ** master journal file, but there is no way of knowing if that
      ** master journal exists now or if it will exist after the operating
      ** system crash that may follow the fsync() failure.
      */
      assert(0);
      sqliteFree(zMaster);
      return rc;
    }

    /* All files and directories have already been synced, so the following
    ** calls to sqlite3BtreeCommit() are only closing files and deleting
    ** journals. If something goes wrong while this is happening we don't
    ** really care. The integrity of the transaction is already guaranteed,
    ** but some stray 'cold' journals may be lying around. Returning an
    ** error code won't help matters.
    */
    for(i=0; i<db->nDb; i++){ 
      Btree *pBt = db->aDb[i].pBt;
      if( pBt ){
        sqlite3BtreeCommit(pBt);
Changes to test/attach2.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.16 2004/06/12 02:17:15 drh Exp $
#

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


# Ticket #354







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.17 2004/06/14 09:35:17 danielk1977 Exp $
#

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


# Ticket #354
299
300
301
302
303
304
305
306










































307






do_test attach2-4.15 {
  execsql {SELECT * FROM t1} db2
} {1 2 1 2}

db close
db2 close
file delete -force test2.db











































finish_test














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

>
>
>
>
>
>
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
do_test attach2-4.15 {
  execsql {SELECT * FROM t1} db2
} {1 2 1 2}

db close
db2 close
file delete -force test2.db

if 0 {

# These tests - attach2-5.* - check that the master journal file is deleted
# correctly when a multi-file transaction is committed or rolled back.
#
# Update: It's not actually created if a rollback occurs, so that test
# doesn't really prove too much.
foreach f [glob test.db*] {file delete -force $f}
do_test attach2-5.1 {
  sqlite db test.db
  execsql {
    ATTACH 'test.db2' AS aux;
  }
} {}
do_test attach2-5.2 {
  execsql {
    BEGIN;
    CREATE TABLE tbl(a, b, c);
    CREATE TABLE aux.tbl(a, b, c);
    COMMIT;
  }
} {}
do_test attach2-5.3 {
  glob test.db*
} {test.db test.db2}
do_test attach2-5.4 {
  execsql {
    BEGIN;
    DROP TABLE aux.tbl;
    DROP TABLE tbl;
    ROLLBACK;
  }
} {}
do_test attach2-5.5 {
  glob test.db*
} {test.db test.db2}

db close

}


finish_test