-C Make\ssure\ssqlite3_thread_cleanup()\sdoes\snot\stry\sto\sallocate\smemory.\s(CVS\s2979)
-D 2006-01-19T17:42:51
+C Handle\ssome\sof\sthe\sIO\serror\sconditions\sthat\smay\soccur\sin\sa\sshared-cache\scontext.\s(CVS\s2980)
+D 2006-01-20T10:55:05
F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a
F src/attach.c 0081040e9a5d13669b6712e947688c10f030bfc1
F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2
-F src/btree.c 2ea7d4372e8ec0a8894ec13e890aedf976e4bbd1
+F src/btree.c e8ff8d76a412299cad1c9a2c4e1fd15ad48bae27
F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184
F src/build.c 15224e2fd348ad32b9044aaa5bdc912e4067da15
F src/callback.c 1bf497306c32229114f826707054df7ebe10abf2
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c 98e4e38db7d4a00647b2bb1c60d28b7ca5034c03
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c ccdd092702decc02fd3a54380c6d46c546eea5a6
+F src/pager.c 49fab8c32de2419cb549220d285c6399bc0d899e
F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f
F src/parse.y 83df51fea35f68f7e07384d75dce83d1ed30434c
F src/pragma.c 4496cc77dc35824e1c978c3d1413b8a5a4c777d3
F src/sqliteInt.h 7ddd6141a57748363fe42119f165d06260996aa3
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
F src/tclsqlite.c d650bea0248fc0a310ddc2cb94273a3a5021fddf
-F src/test1.c 1f1c9cd74b8127d0e29519362a4f0e6e45c9f255
+F src/test1.c 44e8f194ee7d95e25dc421b10ced2ec9d89632a0
F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b
-F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054
+F src/test3.c 86e99724ee898b119ed575ef9f98618afe7e5e5d
F src/test4.c 6633cb7b4a7429e938804a34f688d118c8b7f8e1
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
F src/test6.c 74d91b487c68154156eded457925d96aa2a3fdbb
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
F src/vdbeInt.h 5451cf71f229e366ac543607c0a17f36e5737ea9
F src/vdbeapi.c b5a3eacce266a657cdc0fc740b60ba480fb88649
-F src/vdbeaux.c 1b3fe25f69ec9a3616f8cd747f3b8b87a0a40f04
+F src/vdbeaux.c d9a757ed4e3eefc54408226cb781694059fe2b39
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c 53f25c5c537e4ded24549d6c8537e65d4efc42d1
F src/where.c 5215507b232e718606e0014f999912d53de32a70
F test/main.test b12f01d49a5c805a33fa6c0ef168691f63056e79
F test/malloc.test ce6d1e7e79f9db967b51e1975b50760af66db90d
F test/malloc2.test e6e321db96d6c94cb18bf82ad7215070c41e624e
-F test/malloc3.test 265644c655497242f7c0a1bb5b36c8500a5fc27c
+F test/malloc3.test 1cf2376c9495973608c021efaefb25e71bd6e21f
F test/malloc4.test 2e29d155eb4b4808019ef47eeedfcbe9e09e0f05
F test/malloc5.test 7425272e263325fda7d32cb55706e52b5c09e7e0
F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8
F test/pragma.test 8759b46702f6d8ee4f5dd520216c69dbc9080b60
F test/printf.test 9e10c74e16bf889f8495ddb3d6f5f891e75ff1b7
F test/progress.test 16496001da445e6534afb94562c286708316d82f x
-F test/quick.test 2d2cf1b50e894b19b4029dd9a68ec59599b24f18
+F test/quick.test 38d1feefe5bfd0a61aa535775448276630ecfb92
F test/quote.test 5891f2338980916cf7415484b4ce785294044adb
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
F test/rollback.test 673cd8c44c685ad54987fe7f0eeba84efa09685d
F test/server1.test e328b8e641ba8fe9273132cfef497383185dc1f5
F test/shared.test 9982a65ccf3f4eee844a19f3ab0bcd7a158a76e5
F test/shared2.test 909fc0f0277684ed29cc1b36c8e159188aec7f28
+F test/shared_err.test dea32ad1ce72c1aa88a4671b5de3900961f6c687
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 218c6184c8edec22f9b56b3c9446d27fda9c1e00
-R 1bceb1e22a686481ca5f53186e58ea75
-U drh
-Z 93ab8d9821d0109154bcc26ca1eba6f4
+P 0208e4221a2d90b5ae0755061c345d3351a30da8
+R 1b27118630fddde079e3c9acefda5965
+U danielk1977
+Z 68c504492dfd4d0600ae3c8ff35cbb3d
-0208e4221a2d90b5ae0755061c345d3351a30da8
\ No newline at end of file
+97491d4eb5fc24d8f5cc7605db844359ecc6a818
\ No newline at end of file
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.302 2006/01/19 08:43:31 danielk1977 Exp $
+** $Id: btree.c,v 1.303 2006/01/20 10:55:05 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
}
#endif
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
** Print debugging information about all cursors to standard output.
*/
assert( sqlite3pager_iswriteable(pPage->aData) );
pBt = pPage->pBt;
pParent = pPage->pParent;
- sqlite3pager_write(pParent->aData);
assert( pParent );
+ if( SQLITE_OK!=(rc = sqlite3pager_write(pParent->aData)) ){
+ return rc;
+ }
TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
#ifndef SQLITE_OMIT_QUICKBALANCE
}
#endif
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
** than in, for example, test1.c) so that it can get access to
** the definition of BtShared.
*/
-#if defined(SQLITE_TEST) && defined(TCLSH)
+#if defined(SQLITE_DEBUG) && defined(TCLSH)
#include <tcl.h>
int sqlite3_shared_cache_report(
void * clientData,
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.245 2006/01/18 18:22:43 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.246 2006/01/20 10:55:05 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
static int pager_error(Pager *pPager, int rc){
assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
if(
- rc==SQLITE_FULL ||
- rc==SQLITE_IOERR ||
+ rc==SQLITE_FULL ||
+ rc==SQLITE_IOERR ||
rc==SQLITE_CORRUPT ||
rc==SQLITE_PROTOCOL
){
store32bits(cksum, pPg, pPager->pageSize);
szPg = pPager->pageSize+8;
store32bits(pPg->pgno, pPg, -4);
+
rc = sqlite3OsWrite(pPager->jfd, &((char*)pData)[-4], szPg);
pPager->journalOff += szPg;
TRACE4("JOURNAL %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync);
CODEC(pPager, pData, pPg->pgno, 0);
*(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
+
+ /* An error has occured writing to the journal file. The
+ ** transaction will be rolled back by the layer above.
+ */
if( rc!=SQLITE_OK ){
+#if 0
sqlite3pager_rollback(pPager);
if( !pPager->errCode ){
pager_error(pPager, SQLITE_FULL);
}
+#endif
return rc;
}
+
pPager->nRec++;
assert( pPager->aInJournal!=0 );
pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
}else{
rc = pager_playback(pPager);
}
+#if 0
if( rc!=SQLITE_OK ){
rc = SQLITE_CORRUPT_BKPT;
- pager_error(pPager, SQLITE_CORRUPT);
}
+#endif
pPager->dbSize = -1;
- return rc;
+
+ /* If an error occurs during a ROLLBACK, we can no longer trust the pager
+ ** cache. So call pager_error() on the way out to make any error
+ ** persistent.
+ */
+ return pager_error(pPager, rc);
}
/*
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.199 2006/01/19 11:28:07 drh Exp $
+** $Id: test1.c,v 1.200 2006/01/20 10:55:05 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
set_options(interp);
{
+#ifdef SQLITE_DEBUG
extern int sqlite3_shared_cache_report(void *, Tcl_Interp *,
int, Tcl_Obj *CONST[]);
Tcl_CreateObjCommand(interp, "sqlite_shared_cache_report",
sqlite3_shared_cache_report, 0, 0);
+#endif
}
return TCL_OK;
}
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test3.c,v 1.64 2005/12/30 16:28:02 danielk1977 Exp $
+** $Id: test3.c,v 1.65 2006/01/20 10:55:05 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
**
** Print information about all cursors to standard output for debugging.
*/
+#ifdef SQLITE_DEBUG
static int btree_cursor_list(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
sqlite3BtreeCursorList(pBt);
return SQLITE_OK;
}
+#endif
/*
** Usage: btree_cursor ID TABLENUM WRITEABLE
** aResult[8] = Local payload size
** aResult[9] = Parent page number
*/
+#ifdef SQLITE_DEBUG
static int btree_cursor_info(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
Tcl_AppendResult(interp, &zBuf[1], 0);
return SQLITE_OK;
}
+#endif
/*
** The command is provided for the purpose of setting breakpoints.
{ "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
{ "btree_first", (Tcl_CmdProc*)btree_first },
{ "btree_last", (Tcl_CmdProc*)btree_last },
- { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
- { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
{ "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
{ "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
{ "btree_from_db", (Tcl_CmdProc*)btree_from_db },
{ "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
+#ifdef SQLITE_DEBUG
+ { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
+ { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
+#endif
};
int i;
}
}
+static void rollbackAll(sqlite3 *db, Vdbe *pVdbe){
+ abortOtherActiveVdbes(pVdbe);
+ sqlite3RollbackAll(db);
+}
+
/*
** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
sqlite3 *db = p->db;
int i;
int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
+ int isSpecialError; /* Set to true if SQLITE_NOMEM or IOERR */
+
+ /* This function contains the logic that determines if a statement or
+ ** transaction will be committed or rolled back as a result of the
+ ** execution of this virtual machine.
+ **
+ ** Special errors:
+ **
+ ** If an SQLITE_NOMEM error has occured in a statement that writes to
+ ** the database, then either a statement or transaction must be rolled
+ ** back to ensure the tree-structures are in a consistent state. A
+ ** statement transaction is rolled back if one is open, otherwise the
+ ** entire transaction must be rolled back.
+ **
+ ** If an SQLITE_IOERR error has occured in a statement that writes to
+ ** the database, then the entire transaction must be rolled back. The
+ ** I/O error may have caused garbage to be written to the journal
+ ** file. Were the transaction to continue and eventually be rolled
+ ** back that garbage might end up in the database file.
+ **
+ ** In both of the above cases, the Vdbe.errorAction variable is
+ ** ignored. If the sqlite3.autoCommit flag is false and a transaction
+ ** is rolled back, it will be set to true.
+ **
+ ** Other errors:
+ **
+ ** No error:
+ **
+ */
if( sqlite3MallocFailed() ){
p->rc = SQLITE_NOMEM;
}
-
if( p->magic!=VDBE_MAGIC_RUN ){
/* Already halted. Nothing to do. */
assert( p->magic==VDBE_MAGIC_HALT );
}
closeAllCursors(p);
checkActiveVdbeCnt(db);
- if( p->pc<0 ){
- /* No commit or rollback needed if the program never started */
- }else if( db->autoCommit && db->activeVdbeCnt==1 ){
-
- if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && p->rc!=SQLITE_NOMEM)){
- /* The auto-commit flag is true, there are no other active queries
- ** using this handle and the vdbe program was successful or hit an
- ** 'OR FAIL' constraint. This means a commit is required.
- */
- int rc = vdbeCommit(db);
- if( rc==SQLITE_BUSY ){
- return SQLITE_BUSY;
- }else if( rc!=SQLITE_OK ){
- p->rc = rc;
- sqlite3RollbackAll(db);
- }else{
- sqlite3CommitInternalChanges(db);
- }
- }else{
- sqlite3RollbackAll(db);
- }
- }else{
- if( p->rc==SQLITE_NOMEM ){
+ /* No commit or rollback needed if the program never started */
+ if( p->pc>=0 ){
+
+ /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
+ isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0);
+ if( isSpecialError ){
/* This loop does static analysis of the query to see which of the
** following three categories it falls into:
**
** Read-only
- ** Query with statement journal -> rollback statement
- ** Query without statement journal -> rollback transaction
+ ** Query with statement journal
+ ** Query without statement journal
**
** We could do something more elegant than this static analysis (i.e.
** store the type of query as part of the compliation phase), but
- ** handling malloc() failure is a fairly obscure edge case so this is
- ** probably easier.
- **
- ** Todo: This means we always override the p->errorAction value for a
- ** malloc() failure. Is there any other choice here though?
+ ** handling malloc() or IO failure is a fairly obscure edge case so
+ ** this is probably easier. Todo: Might be an opportunity to reduce
+ ** code size a very small amount though...
*/
int isReadOnly = 1;
int isStatement = 0;
break;
}
}
- if( (isReadOnly||isStatement) && p->errorAction!=OE_Rollback ){
- p->errorAction = OE_Abort;
- }else{
- p->errorAction = OE_Rollback;
+
+ /* If the query was read-only, we need do no rollback at all. Otherwise,
+ ** proceed with the special handling.
+ */
+ if( !isReadOnly ){
+ if( p->rc==SQLITE_NOMEM && isStatement ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ }else{
+ /* We are forced to roll back the active transaction. Before doing
+ ** so, abort any other statements this handle currently has active.
+ */
+ db->autoCommit = 1;
+ }
}
}
-
- if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
- xFunc = sqlite3BtreeCommitStmt;
- }else if( p->errorAction==OE_Abort ){
- xFunc = sqlite3BtreeRollbackStmt;
- }else{
- abortOtherActiveVdbes(p);
- sqlite3RollbackAll(db);
- db->autoCommit = 1;
+
+ /* If the auto-commit flag is set and this is the only active vdbe, then
+ ** we do either a commit or rollback of the current transaction.
+ **
+ ** Note: This block also runs if one of the special errors handled
+ ** above has occured.
+ */
+ if( db->autoCommit && db->activeVdbeCnt==1 ){
+ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
+ /* The auto-commit flag is true, and the vdbe program was
+ ** successful or hit an 'OR FAIL' constraint. This means a commit
+ ** is required.
+ */
+ int rc = vdbeCommit(db);
+ if( rc==SQLITE_BUSY ){
+ return SQLITE_BUSY;
+ }else if( rc!=SQLITE_OK ){
+ p->rc = rc;
+ rollbackAll(db, p);
+ }else{
+ sqlite3CommitInternalChanges(db);
+ }
+ }else{
+ rollbackAll(db, p);
+ }
+ }else if( !xFunc ){
+ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+ xFunc = sqlite3BtreeCommitStmt;
+ }else if( p->errorAction==OE_Abort ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ }else{
+ rollbackAll(db, p);
+ db->autoCommit = 1;
+ }
}
- }
-
- /* If xFunc is not NULL, then it is one of
- ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
- ** each backend. If an error occurs and the return code is still
- ** SQLITE_OK, set the return code to the new error value.
- */
- assert(!xFunc ||
- xFunc==sqlite3BtreeCommitStmt ||
- xFunc==sqlite3BtreeRollbackStmt
- );
- for(i=0; xFunc && i<db->nDb; i++){
- int rc;
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- rc = xFunc(pBt);
- if( p->rc==SQLITE_OK ) p->rc = rc;
+
+ /* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or
+ ** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs
+ ** and the return code is still SQLITE_OK, set the return code to the new
+ ** error value.
+ */
+ assert(!xFunc ||
+ xFunc==sqlite3BtreeCommitStmt ||
+ xFunc==sqlite3BtreeRollbackStmt
+ );
+ for(i=0; xFunc && i<db->nDb; i++){
+ int rc;
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ rc = xFunc(pBt);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
+ }
}
- }
-
- /* If this was an INSERT, UPDATE or DELETE, set the change counter. */
- if( p->changeCntOn && p->pc>=0 ){
- if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
- sqlite3VdbeSetChanges(db, p->nChange);
- }else{
- sqlite3VdbeSetChanges(db, 0);
+
+ /* If this was an INSERT, UPDATE or DELETE and the statement was committed,
+ ** set the change counter.
+ */
+ if( p->changeCntOn && p->pc>=0 ){
+ if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
+ sqlite3VdbeSetChanges(db, p->nChange);
+ }else{
+ sqlite3VdbeSetChanges(db, 0);
+ }
+ p->nChange = 0;
+ }
+
+ /* Rollback or commit any schema changes that occurred. */
+ if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
+ sqlite3ResetInternalSchema(db, 0);
+ db->flags = (db->flags | SQLITE_InternChanges);
}
- p->nChange = 0;
- }
-
- /* Rollback or commit any schema changes that occurred. */
- if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
- sqlite3ResetInternalSchema(db, 0);
- db->flags = (db->flags | SQLITE_InternChanges);
}
/* We have successfully halted and closed the VM. Record this fact. */
# correctly. The emphasis of these tests are the _prepare(), _step() and
# _finalize() calls.
#
-# $Id: malloc3.test,v 1.6 2006/01/10 18:27:42 danielk1977 Exp $
+# $Id: malloc3.test,v 1.7 2006/01/20 10:55:05 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
} {1 2 3 1 2 3}
}
+# Test what happens when a malloc() fails while there are other active
+# statements. This changes the way sqlite3VdbeHalt() works.
+TEST 32 {
+ if {![info exists ::STMT32]} {
+ set sql "SELECT name FROM sqlite_master"
+ set ::STMT32 [sqlite3_prepare $::DB $sql -1 DUMMY]
+ do_test $testid {
+ sqlite3_step $::STMT32
+ } {SQLITE_ROW}
+ }
+puts [execsql {SELECT * FROM ghi}]
+}
+SQL {
+ BEGIN;
+ INSERT INTO ghi SELECT * FROM ghi;
+ COMMIT;
+}
+
#
# End of test program declaration
#--------------------------------------------------------------------------
# Turn of the Tcl interface's prepared statement caching facility.
db cache size 0
-run_test $::run_test_script
+run_test $::run_test_script 76 6
# run_test [lrange $::run_test_script 0 3] 0 63
sqlite_malloc_fail 0
db close
#***********************************************************************
# This file runs all tests.
#
-# $Id: quick.test,v 1.41 2006/01/10 07:14:24 danielk1977 Exp $
+# $Id: quick.test,v 1.42 2006/01/20 10:55:05 danielk1977 Exp $
proc lshift {lvar} {
upvar $lvar l
malloc.test
malloc2.test
malloc3.test
- malloc4.test
memleak.test
misuse.test
quick.test
autovacuum_crash.test
btree8.test
utf16.test
+ shared_err.test
}
if {[sqlite3 -has-codec]} {
--- /dev/null
+# 2005 December 30
+#
+# 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.
+#
+#***********************************************************************
+#
+# The focus of the tests in this file are IO errors that occur in a shared
+# cache context. What happens to connection B if one connection A encounters
+# an IO-error whilst reading or writing the file-system?
+#
+# $Id: shared_err.test,v 1.1 2006/01/20 10:55:05 danielk1977 Exp $
+
+proc skip {args} {}
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+db close
+
+ifcapable !shared_cache||!subquery {
+ finish_test
+ return
+}
+set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
+
+skip \
+do_ioerr_test shared_ioerr-1 -tclprep {
+ sqlite3 db2 test.db
+ execsql {
+ PRAGMA read_uncommitted = 1;
+ CREATE TABLE t1(a,b,c);
+ BEGIN;
+ SELECT * FROM sqlite_master;
+ } db2
+} -sqlbody {
+ SELECT * FROM sqlite_master;
+ INSERT INTO t1 VALUES(1,2,3);
+ BEGIN TRANSACTION;
+ INSERT INTO t1 VALUES(1,2,3);
+ INSERT INTO t1 VALUES(4,5,6);
+ ROLLBACK;
+ SELECT * FROM t1;
+ BEGIN TRANSACTION;
+ INSERT INTO t1 VALUES(1,2,3);
+ INSERT INTO t1 VALUES(4,5,6);
+ COMMIT;
+ SELECT * FROM t1;
+ DELETE FROM t1 WHERE a<100;
+} -cleanup {
+ do_test shared_ioerr-$n.cleanup.1 {
+ set res [catchsql {
+ SELECT * FROM t1;
+ } db2]
+ set possible_results [list \
+ "1 {disk I/O error}" \
+ "0 {1 2 3}" \
+ "0 {1 2 3 1 2 3 4 5 6}" \
+ "0 {1 2 3 1 2 3 4 5 6 1 2 3 4 5 6}" \
+ "0 {}" \
+ ]
+ set rc [expr [lsearch -exact $possible_results $res] >= 0]
+ if {$rc != 1} {
+ puts ""
+ puts "Result: $res"
+ }
+ set rc
+ } {1}
+ db2 close
+}
+
+do_ioerr_test shared_ioerr-2 -tclprep {
+ sqlite3 db2 test.db
+ execsql {
+ PRAGMA read_uncommitted = 1;
+ BEGIN;
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1(oid) VALUES(NULL);
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ INSERT INTO t1(oid) SELECT NULL FROM t1;
+ UPDATE t1 set a = oid, b = 'abcdefghijklmnopqrstuvwxyz0123456789';
+ CREATE INDEX i1 ON t1(a);
+ COMMIT;
+ BEGIN;
+ SELECT * FROM sqlite_master;
+ } db2
+} -tclbody {
+ set ::residx 0
+ execsql {DELETE FROM t1 WHERE 0 = (a % 2);}
+ incr ::residx
+
+ # When this transaction begins the table contains 512 entries. The
+ # two statements together add 512+146 more if it succeeds.
+ # (1024/7==146)
+ execsql {BEGIN;}
+ execsql {INSERT INTO t1 SELECT a+1, b FROM t1;}
+ execsql {INSERT INTO t1 SELECT 'string' || a, b FROM t1 WHERE 0 = (a%7);}
+ execsql {COMMIT;}
+
+ incr ::residx
+} -cleanup {
+ do_test shared_ioerr-2.$n.cleanup.1 {
+ set res [catchsql {
+ SELECT max(a), min(a), count(*) FROM (SELECT a FROM t1 order by a);
+ } db2]
+ set possible_results [list \
+ {0 {1024 1 1024}} \
+ {0 {1023 1 512}} \
+ {0 {string994 1 1170}} \
+ ]
+ set idx [lsearch -exact $possible_results $res]
+ set success [expr {$idx==$::residx || $res=="1 {disk I/O error}"}]
+ if {!$success} {
+ puts ""
+ puts "Result: \"$res\" ($::residx)"
+ }
+ set success
+ } {1}
+ db2 close
+}
+
+catch {db close}
+sqlite3_enable_shared_cache $::enable_shared_cache
+finish_test
+