/ Check-in [899e6070]
Login

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

Overview
Comment:Some fixes and test cases for exclusive access mode. (CVS 3714)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 899e60707bea0fabab2ff3ac8a3fbb676a539120
User & Date: danielk1977 2007-03-26 08:05:12
Context
2007-03-26
08:41
Add some documentation for pragma locking_mode. (CVS 3715) check-in: 394b174e user: danielk1977 tags: trunk
08:05
Some fixes and test cases for exclusive access mode. (CVS 3714) check-in: 899e6070 user: danielk1977 tags: trunk
2007-03-25
19:08
Add the sqlite3_prepare_v2 and sqlite3_prepare16_v2 APIs to the loadable extension interface. (CVS 3713) check-in: f02ba56d user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
868
869
870
871
872
873
874
875
876
877
878
879
880


881
882
883
884
885
886
887
...
920
921
922
923
924
925
926
927

928
929



930
931
932
933
934
935

936
937
938
939
940
941
942
...
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970

971
972
973
974
975
976
977
....
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
....
2797
2798
2799
2800
2801
2802
2803
2804

2805
2806
2807
2808
2809
2810
2811
....
2944
2945
2946
2947
2948
2949
2950

2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
....
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
....
3132
3133
3134
3135
3136
3137
3138















3139


3140
3141
3142
3143
3144
3145
3146
....
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
....
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.294 2007/03/24 16:45:05 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
................................................................................
}

/*
** Execute a rollback if a transaction is active and unlock the 
** database file. This is a no-op if the pager has already entered
** the error-state.
*/
static void pagerUnlockAndRollback(Pager *pPager){
  if( pPager->errCode ) return;
  if( pPager->state>=PAGER_RESERVED ){
    sqlite3PagerRollback(pPager);
  }
  pager_unlock(pPager);


}


/*
** Unlock the database and clear the in-memory cache.  This routine
** sets the state of the pager back to what it was when it was first
** opened.  Any outstanding pages are invalidated and subsequent attempts
................................................................................
  PgHdr *pPg;
  int rc = SQLITE_OK;
  assert( !MEMDB );
  if( pPager->state<PAGER_RESERVED ){
    return SQLITE_OK;
  }
  sqlite3PagerStmtCommit(pPager);
  if( pPager->stmtOpen ){

    sqlite3OsClose(&pPager->stfd);
    pPager->stmtOpen = 0;



  }
  if( pPager->journalOpen ){
    if( pPager->exclusiveMode ){
      sqlite3OsTruncate(pPager->jfd, 0);
      sqlite3OsSeek(pPager->jfd, 0);
      pPager->journalOff = 0;

    }else{
      sqlite3OsClose(&pPager->jfd);
      pPager->journalOpen = 0;
      sqlite3OsDelete(pPager->zJournal);
    }
    sqliteFree( pPager->aInJournal );
    pPager->aInJournal = 0;
................................................................................
  }else{
    assert( pPager->aInJournal==0 );
    assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
  }
  if( !pPager->exclusiveMode ){
    rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
    pPager->state = PAGER_SHARED;
    pPager->origDbSize = 0;
  }else{
    sqlite3PagerPagecount(pPager);
    pPager->origDbSize = pPager->dbSize;
    pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
    if( !pPager->aInJournal ){
      rc = SQLITE_NOMEM;
    }
  }

  pPager->setMaster = 0;
  pPager->needSync = 0;
  pPager->pFirstSynced = pPager->pFirst;
  pPager->dbSize = -1;
  return rc;
}

................................................................................
  char *zMaster = 0;       /* Name of master journal file if any */

  /* Figure out how many records are in the journal.  Abort early if
  ** the journal is empty.
  */
  assert( pPager->journalOpen );
  rc = sqlite3OsFileSize(pPager->jfd, &szJ);
  if( rc!=SQLITE_OK ){
    goto end_playback;
  }

  /* Read the master journal name from the journal, if it is present.
  ** If a master journal file name is specified, but the file is not
  ** present on disk, then the journal is not hot and does not need to be
  ** played back.
................................................................................
  assert( pPager!=0 );
  *ppPage = 0;
  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
    return pPager->errCode;
  }

  /* If this is the first page accessed, then get a SHARED lock
  ** on the database file.

  */
  rc = pagerSharedLock(pPager);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  assert( pPager->state!=PAGER_UNLOCK );

................................................................................
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
  PgHdr *pPg;

  assert( pPager!=0 );
  assert( pgno!=0 );

  if( pPager->state==PAGER_UNLOCK ){

    return 0;
  }
  if( (pPager->errCode && pPager->errCode!=SQLITE_FULL) ){
    return 0;
  }
  pPg = pager_lookup(pPager, pgno);
  if( pPg==0 ) return 0;
  page_ref(pPg);
  return pPg;
}
................................................................................
  
    /* When all pages reach the freelist, drop the read lock from
    ** the database file.
    */
    pPager->nRef--;
    assert( pPager->nRef>=0 );
    if( pPager->nRef==0 ){
      /* pager_reset(pPager); */
      pagerUnlockAndRollback(pPager);
    }
  }
  return SQLITE_OK;
}

/*
................................................................................
      }
      pPager->dirtyCache = 0;
      TRACE2("TRANSACTION %d\n", PAGERID(pPager));
      if( pPager->useJournal && !pPager->tempFile ){
        rc = pager_open_journal(pPager);
      }
    }















  }


  return rc;
}

/*
** Make a page dirty.  Set its dirty flag and add it to the dirty
** page list.
*/
................................................................................
  TRACE2("ROLLBACK %d\n", PAGERID(pPager));
  if( MEMDB ){
    PgHdr *p;
    for(p=pPager->pAll; p; p=p->pNextAll){
      PgHistory *pHist;
      assert( !p->alwaysRollback );
      if( !p->dirty ){
        assert( p->inJournal==0 );
        assert( p->inStmt==0 );
        assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig );
        assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
        continue;
      }

      pHist = PGHDR_TO_HIST(p, pPager);
      if( pHist->pOrig ){
................................................................................
    if( pPager->state>=PAGER_EXCLUSIVE ){
      pager_playback(pPager, 0);
    }
    return pPager->errCode;
  }
  if( pPager->state==PAGER_RESERVED ){
    int rc2;
    /* rc = pager_reload_cache(pPager); */
    rc = pager_playback(pPager, 0);
    rc2 = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = rc2;
    }
  }else{
    rc = pager_playback(pPager, 0);







|







 







|
|
|
|

|
>
>







 







|
>
|
|
>
>
>






>







 







|
|
<
<
<
<
<
|
<
>







 







|







 







|
>







 







>


|







 







<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>







 







<
<







 







<







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
...
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
...
962
963
964
965
966
967
968
969
970





971

972
973
974
975
976
977
978
979
....
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
....
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
....
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
....
3004
3005
3006
3007
3008
3009
3010

3011
3012
3013
3014
3015
3016
3017
....
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
....
3630
3631
3632
3633
3634
3635
3636


3637
3638
3639
3640
3641
3642
3643
....
3673
3674
3675
3676
3677
3678
3679

3680
3681
3682
3683
3684
3685
3686
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.295 2007/03/26 08:05:12 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
................................................................................
}

/*
** Execute a rollback if a transaction is active and unlock the 
** database file. This is a no-op if the pager has already entered
** the error-state.
*/
static void pagerUnlockAndRollback(Pager *p){
  if( p->errCode ) return;
  if( p->state>=PAGER_RESERVED ){
    sqlite3PagerRollback(p);
  }
  pager_unlock(p);
  assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) );
  assert( p->errCode || !p->stmtOpen || p->exclusiveMode );
}


/*
** Unlock the database and clear the in-memory cache.  This routine
** sets the state of the pager back to what it was when it was first
** opened.  Any outstanding pages are invalidated and subsequent attempts
................................................................................
  PgHdr *pPg;
  int rc = SQLITE_OK;
  assert( !MEMDB );
  if( pPager->state<PAGER_RESERVED ){
    return SQLITE_OK;
  }
  sqlite3PagerStmtCommit(pPager);
  if( pPager->stmtOpen && !pPager->exclusiveMode ){
    if( pPager->exclusiveMode ){
      sqlite3OsClose(&pPager->stfd);
      pPager->stmtOpen = 0;
    }else{
      sqlite3OsTruncate(pPager->stfd, 0);
    }
  }
  if( pPager->journalOpen ){
    if( pPager->exclusiveMode ){
      sqlite3OsTruncate(pPager->jfd, 0);
      sqlite3OsSeek(pPager->jfd, 0);
      pPager->journalOff = 0;
      pPager->journalStarted = 0;
    }else{
      sqlite3OsClose(&pPager->jfd);
      pPager->journalOpen = 0;
      sqlite3OsDelete(pPager->zJournal);
    }
    sqliteFree( pPager->aInJournal );
    pPager->aInJournal = 0;
................................................................................
  }else{
    assert( pPager->aInJournal==0 );
    assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
  }
  if( !pPager->exclusiveMode ){
    rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
    pPager->state = PAGER_SHARED;
  }else if( pPager->state==PAGER_SYNCED ){
    pPager->state = PAGER_EXCLUSIVE;





  }

  pPager->origDbSize = 0;
  pPager->setMaster = 0;
  pPager->needSync = 0;
  pPager->pFirstSynced = pPager->pFirst;
  pPager->dbSize = -1;
  return rc;
}

................................................................................
  char *zMaster = 0;       /* Name of master journal file if any */

  /* Figure out how many records are in the journal.  Abort early if
  ** the journal is empty.
  */
  assert( pPager->journalOpen );
  rc = sqlite3OsFileSize(pPager->jfd, &szJ);
  if( rc!=SQLITE_OK || szJ==0 ){
    goto end_playback;
  }

  /* Read the master journal name from the journal, if it is present.
  ** If a master journal file name is specified, but the file is not
  ** present on disk, then the journal is not hot and does not need to be
  ** played back.
................................................................................
  assert( pPager!=0 );
  *ppPage = 0;
  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
    return pPager->errCode;
  }

  /* If this is the first page accessed, then get a SHARED lock
  ** on the database file. pagerSharedLock() is a no-op if 
  ** a database lock is already held.
  */
  rc = pagerSharedLock(pPager);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  assert( pPager->state!=PAGER_UNLOCK );

................................................................................
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
  PgHdr *pPg;

  assert( pPager!=0 );
  assert( pgno!=0 );

  if( pPager->state==PAGER_UNLOCK ){
    assert( !pPager->pAll || pPager->exclusiveMode );
    return 0;
  }
  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
    return 0;
  }
  pPg = pager_lookup(pPager, pgno);
  if( pPg==0 ) return 0;
  page_ref(pPg);
  return pPg;
}
................................................................................
  
    /* When all pages reach the freelist, drop the read lock from
    ** the database file.
    */
    pPager->nRef--;
    assert( pPager->nRef>=0 );
    if( pPager->nRef==0 ){

      pagerUnlockAndRollback(pPager);
    }
  }
  return SQLITE_OK;
}

/*
................................................................................
      }
      pPager->dirtyCache = 0;
      TRACE2("TRANSACTION %d\n", PAGERID(pPager));
      if( pPager->useJournal && !pPager->tempFile ){
        rc = pager_open_journal(pPager);
      }
    }
  }else if( pPager->journalOpen && pPager->journalOff==0 ){
    /* This happens when the pager was in exclusive-access mode last
    ** time a (read or write) transaction was successfully concluded
    ** by this connection. Instead of deleting the journal file it was 
    ** kept open and truncated to 0 bytes.
    */
    assert( pPager->nRec==0 );
    assert( pPager->origDbSize==0 );
    sqlite3PagerPagecount(pPager);
    pPager->origDbSize = pPager->dbSize;
    pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
    if( !pPager->aInJournal ){
      rc = SQLITE_NOMEM;
    }else{
      rc = writeJournalHdr(pPager);
    }
  }
  assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
  return rc;
}

/*
** Make a page dirty.  Set its dirty flag and add it to the dirty
** page list.
*/
................................................................................
  TRACE2("ROLLBACK %d\n", PAGERID(pPager));
  if( MEMDB ){
    PgHdr *p;
    for(p=pPager->pAll; p; p=p->pNextAll){
      PgHistory *pHist;
      assert( !p->alwaysRollback );
      if( !p->dirty ){


        assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig );
        assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
        continue;
      }

      pHist = PGHDR_TO_HIST(p, pPager);
      if( pHist->pOrig ){
................................................................................
    if( pPager->state>=PAGER_EXCLUSIVE ){
      pager_playback(pPager, 0);
    }
    return pPager->errCode;
  }
  if( pPager->state==PAGER_RESERVED ){
    int rc2;

    rc = pager_playback(pPager, 0);
    rc2 = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = rc2;
    }
  }else{
    rc = pager_playback(pPager, 0);

Changes to test/exclusive.test.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287





288
289
290
291
292
293
294
295
296
297
298
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
#    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.
#
# $Id: exclusive.test,v 1.1 2007/03/24 16:45:05 danielk1977 Exp $

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

ifcapable {!pager_pragmas} {
  finish_test
  return
................................................................................
do_test exclusive-3.4 {
  execsql {
    BEGIN;
    UPDATE abc SET a = 1, b = 2, c = 3;
    ROLLBACK;
    SELECT * FROM abc;
  }
} {1 2 3}
do_test exclusive-3.5 {
  filestate test.db-journal
} {1 0}
do_test exclusive-3.6 {
  execsql {
    PRAGMA locking_mode = normal;
    SELECT * FROM abc;
  }
  filestate test.db-journal
} {0 0}






# The following procedure computes a "signature" for table "t3".  If
# T3 changes in any way, the signature should change.  
#
# This is used to test ROLLBACK.  We gather a signature for t3, then
# make lots of changes to t3, then rollback and take another signature.
# The two signatures should be the same.
#
proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}

if 0 {

do_test exclusive-4.0 {
  execsql { PRAGMA default_cache_size=10; }
  db close
  sqlite3 db test.db
  execsql { PRAGMA locking_mode = exclusive; }

  execsql {
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    COMMIT;

    SELECT count(*) FROM t3;

  }
} {1024}
set sig [signature]
do_test exclusive-4.1 {
  execsql {
    BEGIN;
    DELETE FROM t3 WHERE random()%10!=0;
    INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
    INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;

    ROLLBACK;
  }
  signature
} $sig









}














































































finish_test








|







 







|










>
>
>
>
>












<
<

<
<
<

>









<
<
<
<
<

>
|
>
|
<
|






>



|

>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
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
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
#    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.
#
# $Id: exclusive.test,v 1.2 2007/03/26 08:05:12 danielk1977 Exp $

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

ifcapable {!pager_pragmas} {
  finish_test
  return
................................................................................
do_test exclusive-3.4 {
  execsql {
    BEGIN;
    UPDATE abc SET a = 1, b = 2, c = 3;
    ROLLBACK;
    SELECT * FROM abc;
  }
} {A B C}
do_test exclusive-3.5 {
  filestate test.db-journal
} {1 0}
do_test exclusive-3.6 {
  execsql {
    PRAGMA locking_mode = normal;
    SELECT * FROM abc;
  }
  filestate test.db-journal
} {0 0}

#----------------------------------------------------------------------
# Tests exclusive-4.X - test that rollback works correctly when
# in exclusive-access mode.
#

# The following procedure computes a "signature" for table "t3".  If
# T3 changes in any way, the signature should change.  
#
# This is used to test ROLLBACK.  We gather a signature for t3, then
# make lots of changes to t3, then rollback and take another signature.
# The two signatures should be the same.
#
proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}



do_test exclusive-4.0 {



  execsql { PRAGMA locking_mode = exclusive; }
  execsql { PRAGMA default_cache_size = 10; }
  execsql {
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;





    COMMIT;
  }
  execsql {SELECT count(*) FROM t3;}
} {32}


set ::X [signature]
do_test exclusive-4.1 {
  execsql {
    BEGIN;
    DELETE FROM t3 WHERE random()%10!=0;
    INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
    INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
    SELECT count(*) FROM t3;
    ROLLBACK;
  }
  signature
} $::X

do_test exclusive-4.2 {
  execsql {
    BEGIN;
    DELETE FROM t3 WHERE random()%10!=0;
    INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
    DELETE FROM t3 WHERE random()%10!=0;
    INSERT INTO t3 SELECT randstr(10,10)||x FROM t3;
    ROLLBACK;
  }
  signature
} $::X

do_test exclusive-4.3 {
  execsql {
    INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE random()%10==0;
  }
} {}

do_test exclusive-4.4 {
  catch {set ::X [signature]}
} {0}
do_test exclusive-4.5 {
  execsql {
    PRAGMA locking_mode = NORMAL;
    DROP TABLE t3;
    DROP TABLE abc;
  }
} {normal}

#----------------------------------------------------------------------
# Tests exclusive-5.X - test that statement journals are truncated
# instead of deleted when in exclusive access mode.
#
#set sqlite_os_trace 1
do_test exclusive-5.0 {
  execsql {
    CREATE TABLE abc(a UNIQUE, b UNIQUE, c UNIQUE);
    BEGIN;
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc SELECT a+1, b+1, c+1 FROM abc;
  }
} {}
do_test exclusive-5.1 {
  # Three files are open: The db, journal and statement-journal.
  set sqlite_open_file_count
} {3}
do_test exclusive-5.2 {
  execsql {
    COMMIT;
  }
  # One file open: the db.
  set sqlite_open_file_count
} {1}
do_test exclusive-5.3 {
  execsql {
    PRAGMA locking_mode = exclusive;
    BEGIN;
    INSERT INTO abc VALUES(5, 6, 7);
  }
  # Two files open: the db and journal.
  set sqlite_open_file_count
} {2}
do_test exclusive-5.4 {
  execsql {
    INSERT INTO abc SELECT a+10, b+10, c+10 FROM abc;
  }
  # Three files are open: The db, journal and statement-journal.
  set sqlite_open_file_count
} {3}
do_test exclusive-5.5 {
  execsql {
    COMMIT;
  }
  # Three files are still open: The db, journal and statement-journal.
  set sqlite_open_file_count
} {3}
do_test exclusive-5.6 {
  execsql {
    PRAGMA locking_mode = normal;
    SELECT * FROM abc;
  }
} {normal 1 2 3 2 3 4 5 6 7 11 12 13 12 13 14 15 16 17}
do_test exclusive-5.7 {
  # Just the db open.
  set sqlite_open_file_count
} {1}

finish_test

Changes to test/trans.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
#    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 database locks.
#
# $Id: trans.test,v 1.33 2007/03/24 16:45:05 danielk1977 Exp $


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


# Create several tables to work with.
................................................................................
#
do_test trans-9.1 {
  execsql {
    PRAGMA default_cache_size=10;
  }
  db close
  sqlite3 db test.db
  # execsql { PRAGMA locking_mode = exclusive; }
  execsql {
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;







|







 







<







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
811
812
813
814
815
816
817

818
819
820
821
822
823
824
#    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 database locks.
#
# $Id: trans.test,v 1.34 2007/03/26 08:05:12 danielk1977 Exp $


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


# Create several tables to work with.
................................................................................
#
do_test trans-9.1 {
  execsql {
    PRAGMA default_cache_size=10;
  }
  db close
  sqlite3 db test.db

  execsql {
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;