SQLite

Check-in [665b119a24]
Login

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

Overview
Comment:More coverage for pager.c. (CVS 3778)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 665b119a241a5a95f236b3ace1b25fc18ae6f0a3
User & Date: danielk1977 2007-03-31 10:00:48.000
Context
2007-03-31
13:00
The XFER optimization works if the target table lacks an integer primary key and is not empty as long as it has no indices. It always has and continues to work if the target table was empty. (CVS 3779) (check-in: 2c62ffcb86 user: drh tags: trunk)
10:00
More coverage for pager.c. (CVS 3778) (check-in: 665b119a24 user: danielk1977 tags: trunk)
03:59
Fix a long-standing memory leak in the hash table. The leak only appears following a malloc failure of a hash that copies its keys, which rarely happens and so we have not previously noticed it. (CVS 3777) (check-in: 2aae196457 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.311 2007/03/30 20:43:42 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.312 2007/03/31 10:00:48 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
602
603
604
605
606
607
608

609
610
611
612
613
614
615
** 0                         0
** 512                       512
** 100                       512
** 2000                      2048
** 
*/
static int seekJournalHdr(Pager *pPager){

  i64 offset = 0;
  i64 c = pPager->journalOff;
  if( c ){
    offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
  }
  assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
  assert( offset>=c );







>







602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
** 0                         0
** 512                       512
** 100                       512
** 2000                      2048
** 
*/
static int seekJournalHdr(Pager *pPager){
  int rc;
  i64 offset = 0;
  i64 c = pPager->journalOff;
  if( c ){
    offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager);
  }
  assert( offset%JOURNAL_HDR_SZ(pPager)==0 );
  assert( offset>=c );
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698

1699

1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
  const char *zFilename,   /* Name of the database file to open */
  int nExtra,              /* Extra bytes append to each in-memory page */
  int flags                /* flags controlling this file */
){
  Pager *pPager = 0;
  char *zFullPathname = 0;
  int nameLen;  /* Compiler is wrong. This is always initialized before use */
  OsFile *fd;
  int rc = SQLITE_OK;
  int i;
  int tempFile = 0;
  int memDb = 0;
  int readOnly = 0;
  int useJournal = (flags & PAGER_OMIT_JOURNAL)==0;
  int noReadlock = (flags & PAGER_NO_READLOCK)!=0;
  char zTemp[SQLITE_TEMPNAME_SIZE];
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
  /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to 
  ** malloc() must have already been made by this thread before it gets
  ** to this point. This means the ThreadData must have been allocated already
  ** so that ThreadData.nAlloc can be set. It would be nice to assert
  ** that ThreadData.nAlloc is non-zero, but alas this breaks test cases 
  ** written to invoke the pager directly.
  */
  ThreadData *pTsd = sqlite3ThreadData();
  assert( pTsd );
#endif

  /* If malloc() has already failed return SQLITE_NOMEM. Before even
  ** testing for this, set *ppPager to NULL so the caller knows the pager

  ** structure was never allocated. 

  */
  *ppPager = 0;
  if( sqlite3MallocFailed() ){
    return SQLITE_NOMEM;
  }
  memset(&fd, 0, sizeof(fd));

  /* Open the pager file and set zFullPathname to point at malloc()ed 
  ** memory containing the complete filename (i.e. including the directory).
  */
  if( zFilename && zFilename[0] ){
#ifndef SQLITE_OMIT_MEMORYDB
    if( strcmp(zFilename,":memory:")==0 ){







|




















|
|
>
|
>


<
<
<
<







1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704




1705
1706
1707
1708
1709
1710
1711
  const char *zFilename,   /* Name of the database file to open */
  int nExtra,              /* Extra bytes append to each in-memory page */
  int flags                /* flags controlling this file */
){
  Pager *pPager = 0;
  char *zFullPathname = 0;
  int nameLen;  /* Compiler is wrong. This is always initialized before use */
  OsFile *fd = 0;
  int rc = SQLITE_OK;
  int i;
  int tempFile = 0;
  int memDb = 0;
  int readOnly = 0;
  int useJournal = (flags & PAGER_OMIT_JOURNAL)==0;
  int noReadlock = (flags & PAGER_NO_READLOCK)!=0;
  char zTemp[SQLITE_TEMPNAME_SIZE];
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
  /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to 
  ** malloc() must have already been made by this thread before it gets
  ** to this point. This means the ThreadData must have been allocated already
  ** so that ThreadData.nAlloc can be set. It would be nice to assert
  ** that ThreadData.nAlloc is non-zero, but alas this breaks test cases 
  ** written to invoke the pager directly.
  */
  ThreadData *pTsd = sqlite3ThreadData();
  assert( pTsd );
#endif

  /* We used to test if malloc() had already failed before proceeding. 
  ** But the way this function is used in SQLite means that can never
  ** happen. Furthermore, if the malloc-failed flag is already set, 
  ** either the call to sqliteStrDup() or sqliteMalloc() below will
  ** fail shortly and SQLITE_NOMEM returned anyway.
  */
  *ppPager = 0;





  /* Open the pager file and set zFullPathname to point at malloc()ed 
  ** memory containing the complete filename (i.e. including the directory).
  */
  if( zFilename && zFilename[0] ){
#ifndef SQLITE_OMIT_MEMORYDB
    if( strcmp(zFilename,":memory:")==0 ){
2682
2683
2684
2685
2686
2687
2688




2689
2690
2691
2692
2693
2694
2695
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */

/*
** This function is called to obtain the shared lock required before
** data may be read from the pager cache. If the shared lock has already
** been obtained, this function is a no-op.




*/
static int pagerSharedLock(Pager *pPager){
  int rc = SQLITE_OK;

  if( pPager->state==PAGER_UNLOCK ){
    if( !MEMDB ){
      assert( pPager->nRef==0 );







>
>
>
>







2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */

/*
** This function is called to obtain the shared lock required before
** data may be read from the pager cache. If the shared lock has already
** been obtained, this function is a no-op.
**
** Immediately after obtaining the shared lock (if required), this function
** checks for a hot-journal file. If one is found, an emergency rollback
** is performed immediately.
*/
static int pagerSharedLock(Pager *pPager){
  int rc = SQLITE_OK;

  if( pPager->state==PAGER_UNLOCK ){
    if( !MEMDB ){
      assert( pPager->nRef==0 );
Changes to test/diskfull.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 file is testing for correct handling of disk full
# errors.
# 
# $Id: diskfull.test,v 1.4 2007/03/15 12:51:17 drh Exp $

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

set sqlite_io_error_persist 0
set sqlite_io_error_hit 0
set sqlite_io_error_pending 0







|







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 file is testing for correct handling of disk full
# errors.
# 
# $Id: diskfull.test,v 1.5 2007/03/31 10:00:48 danielk1977 Exp $

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

set sqlite_io_error_persist 0
set sqlite_io_error_hit 0
set sqlite_io_error_pending 0
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


































79

    DELETE FROM t1;
  }
} {1 {database or disk is full}}
set sqlite_diskfull_pending 0
set sqlite_io_error_hit 0
integrity_check diskfull-1.6


set go 1

set i 0
while {$go} {
  incr i
  do_test diskfull-2.$i.1 {
    set sqlite_diskfull_pending $i
    set sqlite_diskfull 0
    set r [catchsql {VACUUM}]
    if {!$sqlite_diskfull} {
      set r {1 {database or disk is full}}
      set go 0
    }
    if {$r=="1 {disk I/O error}"} {
      set r {1 {database or disk is full}}
    }
    set r
  } {1 {database or disk is full}}
  set sqlite_diskfull_pending 0
  db close
  sqlite3 db test.db
  integrity_check diskfull-2.$i.2
}



































finish_test








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

>
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    DELETE FROM t1;
  }
} {1 {database or disk is full}}
set sqlite_diskfull_pending 0
set sqlite_io_error_hit 0
integrity_check diskfull-1.6

proc do_diskfull_test {prefix sql} {
  set ::go 1
  set ::sql $sql
  set ::i 52
  while {$::go} {
    incr ::i
    do_test ${prefix}.$::i.1 {
      set ::sqlite_diskfull_pending $::i
      set ::sqlite_diskfull 0
      set r [catchsql $::sql]
      if {!$::sqlite_diskfull} {
        set r {1 {database or disk is full}}
        set ::go 0
      }
      if {$r=="1 {disk I/O error}"} {
        set r {1 {database or disk is full}}
      }
      set r
    } {1 {database or disk is full}}
    set ::sqlite_diskfull_pending 0
    db close
    sqlite3 db test.db
    integrity_check ${prefix}.$::i.2
  }
}

do_diskfull_test diskfull-2 VACUUM

# db close
# file delete -force test.db
# file delete -force test.db-journal
# sqlite3 db test.db
# 
# do_test diskfull-3.1 {
#   execsql {
#     PRAGMA default_cache_size = 10;
#     CREATE TABLE t3(a, b, UNIQUE(a, b));
#     INSERT INTO t3 VALUES( randstr(100, 100), randstr(100, 100) );
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
#     UPDATE t3 
#     SET b = (SELECT a FROM t3 WHERE rowid = (SELECT max(rowid)-1 FROM t3))
#     WHERE rowid = (SELECT max(rowid) FROM t3);
#     PRAGMA cache_size;
#   }
# } {10}
# breakpoint
# do_diskfull_test diskfull-3.2 {
#   BEGIN;
#     INSERT INTO t3 VALUES( randstr(100, 100), randstr(100, 100) );
#     UPDATE t3 SET a = b;
#   COMMIT;
# }

finish_test

Changes to test/misc7.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2006 September 4
#
# 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.
#
# $Id: misc7.test,v 1.8 2007/03/30 18:21:53 danielk1977 Exp $

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

do_test misc7-1 {
  c_misuse_test
} {}












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2006 September 4
#
# 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.
#
# $Id: misc7.test,v 1.9 2007/03/31 10:00:49 danielk1977 Exp $

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

do_test misc7-1 {
  c_misuse_test
} {}
288
289
290
291
292
293
294


































295
296
297
298
299
do_test misc7-15.2 {
  execsql {
    DELETE FROM abc WHERE rowid > 12;
    INSERT INTO abc SELECT 
            randstr(100,100), randstr(100,100), randstr(100,100) FROM abc;
  }
} {}






































finish_test







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





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
do_test misc7-15.2 {
  execsql {
    DELETE FROM abc WHERE rowid > 12;
    INSERT INTO abc SELECT 
            randstr(100,100), randstr(100,100), randstr(100,100) FROM abc;
  }
} {}

db close
file delete -force test.db
file delete -force test.db-journal
sqlite3 db test.db

do_ioerr_test misc7-16 -sqlprep {
   PRAGMA cache_size = 10;
   PRAGMA default_cache_size = 10;
   CREATE TABLE t3(a, b, UNIQUE(a, b));
   INSERT INTO t3 VALUES( randstr(100, 100), randstr(100, 100) );
   INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
   INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
   INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
   INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
   INSERT INTO t3 SELECT randstr(100, 100), randstr(100, 100) FROM t3;
   UPDATE t3 
   SET b = 'hello world'
   WHERE rowid >= (SELECT max(rowid)-1 FROM t3);
} -tclbody {
  set rc [catch {db eval {
    BEGIN;
      PRAGMA cache_size = 10;
      INSERT INTO t3 VALUES( randstr(100, 100), randstr(100, 100) );
      UPDATE t3 SET a = b;
    COMMIT;
  }} msg]

  if {!$rc || ($rc && [string first "columns" $msg]==0)} {
    set msg
  } else {
    error $msg
  }
}




finish_test
Changes to test/quick.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
#    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 runs all tests.
#
# $Id: quick.test,v 1.50 2007/03/26 13:48:14 drh Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
#    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 runs all tests.
#
# $Id: quick.test,v 1.51 2007/03/31 10:00:49 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
46
47
48
49
50
51
52

53
54
55
56
57
58
59
  crash2.test
  exclusive3.test
  loadext.test
  malloc.test
  malloc2.test
  malloc3.test
  memleak.test

  misuse.test
  quick.test
  speed1.test
  speed2.test

  autovacuum_crash.test
  btree8.test







>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  crash2.test
  exclusive3.test
  loadext.test
  malloc.test
  malloc2.test
  malloc3.test
  memleak.test
  misc7.test
  misuse.test
  quick.test
  speed1.test
  speed2.test

  autovacuum_crash.test
  btree8.test