-C Prevent\sthe\stcl\stest\ssuite\sfrom\sthrowing\san\sexception\swhen\sa\sthreadsafe\sSQLite\sis\slinked\sagainst\sa\snon-threadsafe\sTcl\sfor\stesting.\sPrint\sa\swarning\sinstead.\sTicket\s#3753.\s(CVS\s6389)
-D 2009-03-26T14:48:07
+C Check\sthat\sthe\sfirst\sbyte\sof\sa\spotentially\shot\sjournal\sfile\sis\snon-zero\sbefore\sbeginning\shot-journal\srollback.\sFix\sfor\s#3751\sand\s#3745.\s(CVS\s6390)
+D 2009-03-26T17:13:06
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/os_os2.c bed77dc26e3a95ce4a204936b9a1ca6fe612fcc5
F src/os_unix.c 7bf3ebde13154a97f797df1551d19cf0d2785c15
F src/os_win.c 40636702058ed4dcd35d68151bfab56d4997cdc1
-F src/pager.c da7ffd068347cdc88b477875585d53dcf2bdc4a7
+F src/pager.c 6a932669c9cd779aa03f111f1a89bc1bcf7a6465
F src/pager.h 0c9f3520c00d8a3b8e792ca56c9a11b6b02b4b0f
F src/parse.y b9ba0946a13e9f32a96044e64a3e8780269b08b0
F src/pcache.c fcf7738c83c4d3e9d45836b2334c8a368cc41274
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
F test/jrnlmode.test 32e79fa272e78ff3b734aac08db886f98f84165a
+F test/jrnlmode2.test bd846e10d463c0b6f8bded674cb07f94a0277097
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/tempdb.test b88ac8a19823cf771d742bf61eef93ef337c06b1
F test/temptable.test 5d8ca46be28cc06c887c5a77df650843b7edbae1
F test/temptrigger.test 03093be9967942623232dfdf2a63b832d4e0e4fa
-F test/tester.tcl 66546f6766029384360b24cacb3896376c5f5f69
+F test/tester.tcl ebaa00336761e1b97f56a8376178289097db43ab
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P e99e28efbbfff3e46eec0f90d566991de4406fd8
-R 1f72d75124ff1aa9ba3be363b671b72e
+P a22e7c818b2227a4c80ad84b299d11f365e3b17d
+R 4ee0c36ed6c98bbdc0cb2efb14dfd44e
U danielk1977
-Z 8663270a3bb5409566dc3bce815cb5b0
+Z 9399bffef7da619c63a0329f4e82af23
-a22e7c818b2227a4c80ad84b299d11f365e3b17d
\ No newline at end of file
+80241a050296067937d0b0529fdf0c347358f86c
\ No newline at end of file
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.572 2009/03/23 04:33:33 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.573 2009/03/26 17:13:06 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
** PAGER_SHARED state. It tests if there is a hot journal present in
** the file-system for the given pager. A hot journal is one that
** needs to be played back. According to this function, a hot-journal
-** file exists if the following three criteria are met:
+** file exists if the following criteria are met:
**
** * The journal file exists in the file system, and
** * No process holds a RESERVED or greater lock on the database file, and
-** * The database file itself is greater than 0 bytes in size.
+** * The database file itself is greater than 0 bytes in size, and
+** * The first byte of the journal file exists and is not 0x00.
**
** 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
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
** is returned.
**
-** This routine does not open the journal file to examine its
-** content. Hence, the journal might contain the name of a master
-** journal file that has been deleted, and hence not be hot. Or
-** the header of the journal might be zeroed out. This routine
-** does not discover these cases of a non-hot journal - if the
-** journal file exists and is not empty this routine assumes it
-** is hot. The pager_playback() routine will discover that the
-** journal file is not really hot and will no-op.
+** This routine does not check if there is a master journal filename
+** at the end of the file. If there is, and that master journal file
+** does not exist, then the journal file is not really hot. In this
+** case this routine will return a false-positive. The pager_playback()
+** routine will discover that the journal file is not really hot and
+** will not roll it back.
**
** If a hot-journal file is found to exist, *pExists is set to 1 and
** SQLITE_OK returned. If no hot-journal file is present, *pExists is
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
int rc; /* Return code */
- int exists = 0; /* True if a journal file is present */
- int locked = 0; /* True if some process holds a RESERVED lock */
+ int exists; /* True if a journal file is present */
assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
+ assert( !isOpen(pPager->jfd) );
*pExists = 0;
rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
if( rc==SQLITE_OK && exists ){
+ int locked; /* True if some process holds a RESERVED lock */
rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
if( rc==SQLITE_OK && !locked ){
int nPage;
+
+ /* Check the size of the database file. If it consists of 0 pages,
+ ** then delete the journal file. See the header comment above for
+ ** the reasoning here.
+ */
rc = sqlite3PagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
- if( nPage==0 ){
- sqlite3OsDelete(pVfs, pPager->zJournal, 0);
+ if( nPage==0 ){
+ rc = sqlite3OsDelete(pVfs, pPager->zJournal, 0);
}else{
- *pExists = 1;
+ /* The journal file exists and no other connection has a reserved
+ ** or greater lock on the database file. Now check that there is
+ ** at least one non-zero bytes at the start of the journal file.
+ ** If there is, then we consider this journal to be hot. If not,
+ ** it can be ignored.
+ */
+ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ if( rc==SQLITE_OK ){
+ u8 first = 0;
+ rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
+ sqlite3OsClose(pPager->jfd);
+ *pExists = (first!=0);
+ }
}
}
}
}
+
return rc;
}
sqlite3MemJournalOpen(pPager->jfd);
}else{
const int flags = /* VFS flags to open journal file */
- SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE|
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
(pPager->tempFile ?
(SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
(SQLITE_OPEN_MAIN_JOURNAL)
--- /dev/null
+# 2009 March 24
+#
+# 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.
+#
+#***********************************************************************
+#
+# $Id: jrnlmode2.test,v 1.5 2009/03/26 17:13:06 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable {!pager_pragmas} {
+ finish_test
+ return
+}
+
+#-------------------------------------------------------------------------
+# Test overview:
+#
+# jrnlmode2-1.*: Demonstrate bug #3745
+# jrnlmode2-2.*: Demonstrate bug #3751
+#
+
+do_test jrnlmode2-1.1 {
+ execsql {
+ PRAGMA journal_mode = persist;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ }
+} {persist}
+
+do_test jrnlmode2-1.2 {
+ file exists test.db-journal
+} {1}
+
+do_test jrnlmode2-1.3 {
+ sqlite3 db2 test.db
+ execsql { SELECT * FROM t1 } db2
+} {1 2}
+
+do_test jrnlmode2-1.4 {
+ execsql {
+ INSERT INTO t1 VALUES(3, 4);
+ BEGIN;
+ SELECT * FROM t1;
+ }
+ execsql { PRAGMA lock_status }
+} {main shared temp closed}
+
+do_test jrnlmode2-1.5 {
+ file exists test.db-journal
+} {1}
+
+do_test jrnlmode2-1.6 {
+ catchsql { SELECT * FROM t1 } db2
+} {0 {1 2 3 4}}
+
+do_test jrnlmode2-1.7 {
+ execsql { COMMIT }
+ catchsql { SELECT * FROM t1 } db2
+} {0 {1 2 3 4}}
+
+
+
+do_test jrnlmode2-2.1 {
+ db2 close
+ execsql { PRAGMA journal_mode = truncate }
+ execsql { INSERT INTO t1 VALUES(5, 6) }
+} {}
+
+do_test jrnlmode2-2.2 {
+ file exists test.db-journal
+} {1}
+
+do_test jrnlmode2-2.3 {
+ file size test.db-journal
+} {0}
+
+do_test jrnlmode2-2.4 {
+ sqlite3 db2 test.db -readonly 1
+ catchsql { SELECT * FROM t1 } db2
+} {0 {1 2 3 4 5 6}}
+
+do_test jrnlmode2-2.5 {
+ file delete test.db-journal
+} {}
+
+do_test jrnlmode2-2.6 {
+ sqlite3 db2 test.db -readonly 1
+ catchsql { SELECT * FROM t1 } db2
+} {0 {1 2 3 4 5 6}}
+
+catch { db2 close }
+finish_test
+
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
-# $Id: tester.tcl,v 1.140 2009/02/19 14:39:25 danielk1977 Exp $
+# $Id: tester.tcl,v 1.141 2009/03/26 17:13:06 danielk1977 Exp $
#
# What for user input before continuing. This gives an opportunity
if {$nErr>0} {
puts "Failures on these tests: $::failList"
}
+ run_thread_tests 1
if {[llength $omitList]>0} {
puts "Omitted test cases:"
set prec {}
# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)
+
+source $testdir/thread_common.tcl