/ Check-in [26b2e1ae]
Login

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

Overview
Comment:Additional coverage testing. (CVS 3823)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 26b2e1aede3f776134b2d6e941d17a907843e650
User & Date: drh 2007-04-06 18:23:18
Context
2007-04-06
21:42
Changes to test scripts to support alternative configurations. (CVS 3824) check-in: 3471a226 user: drh tags: trunk
18:23
Additional coverage testing. (CVS 3823) check-in: 26b2e1ae user: drh tags: trunk
15:02
Binary file I/O infrastructure added and used to increase test coverage for detection of corrupt database files. (CVS 3822) check-in: 479b3d96 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
...
996
997
998
999
1000
1001
1002

1003
1004

1005
1006

1007
1008
1009
1010
1011
1012
1013
....
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
** *id unchanged.
*/
static int unixOpenDirectory(
  OsFile *id,
  const char *zDirname
){
  unixFile *pFile = (unixFile*)id;
  if( pFile==0 ){
    /* Do not open the directory if the corresponding file is not already
    ** open. */
    return SQLITE_CANTOPEN;
  }
  SET_THREADID(pFile);
  assert( pFile->dirfd<0 );
  pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
  if( pFile->dirfd<0 ){
    return SQLITE_CANTOPEN; 
  }
  OSTRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
................................................................................
*/
static int seekAndRead(unixFile *id, void *pBuf, int cnt){
  int got;
  i64 newOffset;
  TIMER_START;
#if defined(USE_PREAD)
  got = pread(id->h, pBuf, cnt, id->offset);

#elif defined(USE_PREAD64)
  got = pread64(id->h, pBuf, cnt, id->offset);

#else
  newOffset = lseek(id->h, id->offset, SEEK_SET);

  if( newOffset!=id->offset ){
    return -1;
  }
  got = read(id->h, pBuf, cnt);
#endif
  TIMER_END;
  OSTRACE5("READ    %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
................................................................................
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
static int unixRead(OsFile *id, void *pBuf, int amt){
  int got;
  assert( id );
  got = seekAndRead((unixFile*)id, pBuf, amt);
  SimulateIOError( got = -1 );
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    return SQLITE_IOERR_READ;
  }else{
    memset(&((char*)pBuf)[got], 0, amt-got);
    return SQLITE_IOERR_SHORT_READ;







|
<
<
<
<







 







>


>


>







 







<







915
916
917
918
919
920
921
922




923
924
925
926
927
928
929
...
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
....
1021
1022
1023
1024
1025
1026
1027

1028
1029
1030
1031
1032
1033
1034
** *id unchanged.
*/
static int unixOpenDirectory(
  OsFile *id,
  const char *zDirname
){
  unixFile *pFile = (unixFile*)id;
  assert( pFile!=0 );




  SET_THREADID(pFile);
  assert( pFile->dirfd<0 );
  pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
  if( pFile->dirfd<0 ){
    return SQLITE_CANTOPEN; 
  }
  OSTRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
................................................................................
*/
static int seekAndRead(unixFile *id, void *pBuf, int cnt){
  int got;
  i64 newOffset;
  TIMER_START;
#if defined(USE_PREAD)
  got = pread(id->h, pBuf, cnt, id->offset);
  SimulateIOError( got = -1 );
#elif defined(USE_PREAD64)
  got = pread64(id->h, pBuf, cnt, id->offset);
  SimulateIOError( got = -1 );
#else
  newOffset = lseek(id->h, id->offset, SEEK_SET);
  SimulateIOError( newOffset-- );
  if( newOffset!=id->offset ){
    return -1;
  }
  got = read(id->h, pBuf, cnt);
#endif
  TIMER_END;
  OSTRACE5("READ    %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
................................................................................
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
static int unixRead(OsFile *id, void *pBuf, int amt){
  int got;
  assert( id );
  got = seekAndRead((unixFile*)id, pBuf, amt);

  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    return SQLITE_IOERR_READ;
  }else{
    memset(&((char*)pBuf)[got], 0, amt-got);
    return SQLITE_IOERR_SHORT_READ;

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2504
2505
2506
2507
2508
2509
2510
2511


2512


2513
2514
2515
2516
2517
2518
2519
** 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.323 2007/04/05 17:15:53 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
................................................................................
**
** If the current size of the database file is 0 but a journal file
** exists, that is probably an old journal left over from a prior
** database with the same name.  Just delete the journal.
*/
static int hasHotJournal(Pager *pPager){
  if( !pPager->useJournal ) return 0;
  if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;


  if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0;


  if( sqlite3PagerPagecount(pPager)==0 ){
    sqlite3OsDelete(pPager->zJournal);
    return 0;
  }else{
    return 1;
  }
}







|







 







|
>
>
|
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
** 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.324 2007/04/06 18:23:18 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
................................................................................
**
** If the current size of the database file is 0 but a journal file
** exists, that is probably an old journal left over from a prior
** database with the same name.  Just delete the journal.
*/
static int hasHotJournal(Pager *pPager){
  if( !pPager->useJournal ) return 0;
  if( !sqlite3OsFileExists(pPager->zJournal) ){
    return 0;
  }
  if( sqlite3OsCheckReservedLock(pPager->fd) ){
    return 0;
  }
  if( sqlite3PagerPagecount(pPager)==0 ){
    sqlite3OsDelete(pPager->zJournal);
    return 0;
  }else{
    return 1;
  }
}

Added test/lock4.test.



























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
# 2007 April 6
#
# 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.  The
# focus of this script is database locks.
#
# $Id: lock4.test,v 1.3 2007/04/06 18:23:19 drh Exp $


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

# Initialize the test.db database so that it is non-empty
#
do_test lock4-1.1 {
  db eval {CREATE TABLE t1(x)}
  file delete -force test2.db test2.db-journal
  sqlite3 db2 test2.db
  db2 eval {CREATE TABLE t2(x)}
  db2 close
  list [file size test.db] [file size test2.db]
} {2048 2048}

# Create a script to drive a separate process that will
#
#     1.  Create a second database test2.db
#     2.  Get an exclusive lock on test2.db
#     3.  Add an entry to test.db in table t1, waiting as necessary.
#     4.  Commit the change to test2.db.
#
# Meanwhile, this process will:
# 
#     A.  Get an exclusive lock on test.db
#     B.  Attempt to read from test2.db but get an SQLITE_BUSY error.
#     C.  Commit the changes to test.db thus alloing the other process
#         to continue.
#
do_test lock4-1.2 {
  set out [open test2-script.tcl w]
  puts $out "set sqlite_pending_byte [set sqlite_pending_byte]"
  puts $out {
     sqlite3 db2 test2.db
     db2 eval {
        BEGIN;
        INSERT INTO t2 VALUES(2);
     }
     sqlite3 db test.db
     db timeout 1000000
     db eval {
        INSERT INTO t1 VALUES(2);
     }
     db2 eval COMMIT
     exit
  }
  close $out
  db eval {
     BEGIN;
     INSERT INTO t1 VALUES(1);
  }
  exec [info nameofexec] ./test2-script.tcl &
  while {![file exists test2.db-journal]} {
    after 10
  }
  sqlite3 db2 test2.db
  catchsql {
    INSERT INTO t2 VALUES(1)
  } db2
} {1 {database is locked}}
do_test lock4-1.3 {
  db eval {
     COMMIT;
  }
  while {[file exists test2.db-journal]} {
    after 10
  }
  db2 eval {
     SELECT * FROM t2
  }
} {2}

    
do_test lock4-999.1 {
  rename db2 {}
} {}

finish_test

Changes to tool/lempar.c.

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
%%
};
#endif /* NDEBUG */

/*
** This function returns the symbolic name associated with a token
** value.
*/
const char *ParseTokenName(int tokenType){
#ifndef NDEBUG
  if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
    return yyTokenName[tokenType];
  }else{
    return "Unknown";
  }
#else
  return "";
#endif
}

#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.
*/
static void yyGrowStack(yyParser *p){
  int newSize;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







206
207
208
209
210
211
212















213
214
215
216
217
218
219
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
%%
};
#endif /* NDEBUG */

















#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.
*/
static void yyGrowStack(yyParser *p){
  int newSize;