diff --git a/manifest b/manifest index 2f812b2429..2f56094a56 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Handle\scorrupt\sjournal\sfile\sheaders\scorrectly.\s(CVS\s1674) -D 2004-06-23T01:05:27 +C Test\scases\sto\sverify\srecovery\safter\sa\scrash.\s(CVS\s1675) +D 2004-06-23T10:43:10 F Makefile.in 0a3d7aaefa50717bd550b0cf568a51072c4c103c F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -44,13 +44,13 @@ F src/os.h 2f5ea879b784bc82aac8022a3e8fe00b73c83d67 F src/os_common.h ba1b7306e16e2091718f2c48db0fe6c1d7a31bb8 F src/os_mac.c 3d31e26be1411acfb7961033098631b4f3486fdf F src/os_mac.h 51d2445f47e182ed32d3bd6937f81070c6fd9bd4 -F src/os_test.c db4df491bad874c095b1a9d4db346990cfd56ae0 -F src/os_test.h acacfe7e7bb78dd99865f16cfa822426b177d2ab +F src/os_test.c ab55524911b66395c39ff8f465dfee0ba1ba06e4 +F src/os_test.h 6a26a4978492e4bbdbf385554958418ff02db162 F src/os_unix.c 39e73ed02fc992a6bfc52200ea26704633412cc0 F src/os_unix.h 00c1f82b526ab2fb7ee5ddd555ea4ed68363c93a F src/os_win.c 84549f6cc815237533c5d0eb3697352b03478d96 F src/os_win.h babd4e912967c6b09088cfe38a45e8005a07ba44 -F src/pager.c 42297421e9e7646f99b332c69f3f8085c1d765bf +F src/pager.c ec34fbae1a23228cb3743cf7cd8eba1af8e4cd5c F src/pager.h bc58d32a9dee464f7268fb68652c130a4216e438 F src/parse.y 097438674976355a10cf177bd97326c548820b86 F src/pragma.c 0750e1c360647dbe0a991f16133b0fe5e42e5039 @@ -62,7 +62,7 @@ F src/sqlite.h.in 1f400a561fca3b1df73677d2d97046425d47cae4 F src/sqliteInt.h dd796b6abc6d50505fe33c54f0143d7000681a41 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c 8d093146332b2f0cbf2a8ebe8597d481619308a3 -F src/test1.c 7ecde02fdecff651250f11d96da73d484a4ff764 +F src/test1.c a7e559240e677671224d2d13b4d1dab284e23c20 F src/test2.c dafd8bd314a554bf376c6d3a8c83fd69219f5a40 F src/test3.c 7247090d15a5a43823079b6fd8dad1ed3cccdedf F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2 @@ -104,7 +104,7 @@ F test/collate4.test 0e9fc08ffcf6eddf72e354a15de06688fa86db31 F test/collate5.test 1dd5f0f508c46667f9d4606c7950c414b0bdc0d5 F test/collate6.test 2a45768914f04c1447a69d1358bbede376552675 F test/conflict.test c5b849b01cfbe0a4f63a90cba6f68e2fe3a75f87 -F test/crash.test fa7c6ef4d1ac1aa2d14d8afd1583cef8f8e2a0e4 +F test/crash.test 01b4a1cf195678138810f973ec9e2e6cef731d3e F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d F test/delete.test 4f0c86e2bebdc822d179c80697b1ceabe6bbcd07 @@ -229,7 +229,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 563ba3ac02f64da27ab17f3edbe8e56bfd0293fb F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P e2f7f182987fbfe8611ead8bd1f12b2e8b47f6dc -R 8314e42b760c1a8a452b6f1accd15858 +P 46107da7eddbdda8b582e2ece2dc41222a70330a +R 2d06dadbd77bf8c7d6cc2f4d941e75d8 U danielk1977 -Z 0fc9a3cf7f51cb64d701f7be6ce96ff8 +Z eb0225a30546e9d6f49bf0fdd5127daf diff --git a/manifest.uuid b/manifest.uuid index 6307d2cddf..4f2cbbfea8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -46107da7eddbdda8b582e2ece2dc41222a70330a \ No newline at end of file +41868d79ac5b3c496c4d87ca6b4ee7c17ef38965 \ No newline at end of file diff --git a/src/os_test.c b/src/os_test.c index 663453d67b..ce40552770 100644 --- a/src/os_test.c +++ b/src/os_test.c @@ -60,41 +60,54 @@ /* -** The crash-seed. Accessed via functions crashseed() and -** sqlite3SetCrashseed(). +** The following variables control when a simulated crash occurs. +** +** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of +** a file that SQLite will call sqlite3OsSync() on. Each time this happens +** iCrashDelay is decremented. If iCrashDelay is zero after being +** decremented, a "crash" occurs during the sync() operation. +** +** In other words, a crash occurs the iCrashDelay'th time zCrashFile is +** synced. */ -static int crashseed_var = 0; +static int iCrashDelay = 0; +char zCrashFile[256]; /* -** This function is used to set the value of the 'crash-seed' integer. -** -** If the crash-seed is 0, the default value, then whenever sqlite3OsSync() -** or sqlite3OsClose() is called, the write cache is written to disk before -** the os_unix.c Sync() or Close() function is called. -** -** If the crash-seed is non-zero, then it is used to determine a subset of -** the write-cache to actually write to disk before calling Sync() or -** Close() in os_unix.c. The actual subset of writes selected is not -** significant, except that it is constant for a given value of the -** crash-seed and cache contents. Before returning, exit(-1) is invoked. +** Set the value of the two crash parameters. */ -void sqlite3SetCrashseed(int seed){ +void sqlite3SetCrashParams(int iDelay, char const *zFile){ sqlite3OsEnterMutex(); - crashseed_var = seed; + assert( strlen(zFile)<256 ); + strcpy(zCrashFile, zFile); + iCrashDelay = iDelay; sqlite3OsLeaveMutex(); } /* -** Retrieve the current value of the crash-seed. +** File zPath is being sync()ed. Return non-zero if this should +** cause a crash. */ -static int crashseed(){ - int i; +static int crashRequired(char const *zPath){ + int r; + int n; sqlite3OsEnterMutex(); - i = crashseed_var; + n = strlen(zCrashFile); + if( zCrashFile[n-1]=='*' ){ + n--; + }else if( strlen(zPath)>n ){ + n = strlen(zPath); + } + r = ( + iCrashDelay>0 && + !strncmp(zPath, zCrashFile, n) && + --iCrashDelay==0 + )?1:0; sqlite3OsLeaveMutex(); - return i; + return r; } + static OsTestFile *pAllFiles = 0; /* @@ -177,6 +190,8 @@ static int cacheBlock(OsTestFile *pFile, int blk){ return SQLITE_OK; } +/* #define TRACE_WRITECACHE */ + /* ** Write the cache of pFile to disk. If crash is non-zero, randomly ** skip blocks when writing. The cache is deleted before returning. @@ -197,16 +212,13 @@ static int writeCache2(OsTestFile *pFile, int crash){ sqlite3Randomness(1, &random); if( random & 0x01 ){ skip = 1; -/* - printf("Not writing block %d of %s\n", i, pFile->zName); -*/ +#ifdef TRACE_WRITECACHE +printf("Not writing block %d of %s\n", i, pFile->zName); }else{ -/* - printf("Writing block %d of %s\n", i, pFile->zName); -*/ +printf("Writing block %d of %s\n", i, pFile->zName); +#endif } } - if( rc==SQLITE_OK ){ rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i)); } @@ -235,18 +247,22 @@ static int writeCache2(OsTestFile *pFile, int crash){ ** Write the cache to disk. */ static int writeCache(OsTestFile *pFile){ - int cs = crashseed(); - if( cs==1 ){ - /* FIX ME: writeCache2() should be called on all open files here. */ - OsTestFile *pFile; - for(pFile=pAllFiles; pFile; pFile=pFile->pNext){ - writeCache2(pFile, 1); + if( pFile->apBlk ){ + int c = crashRequired(pFile->zName); + if( c ){ + OsTestFile *p; +#ifdef TRACE_WRITECACHE + printf("Crash during sync of %s\n", pFile->zName); +#endif + for(p=pAllFiles; p; p=p->pNext){ + writeCache2(p, 1); + } + exit(-1); + }else{ + return writeCache2(pFile, 0); } - exit(-1); - }else{ - if( cs>0 ) sqlite3SetCrashseed(cs-1); - return writeCache2(pFile, 0); } + return SQLITE_OK; } /* diff --git a/src/os_test.h b/src/os_test.h index f569687207..256eaaf17a 100644 --- a/src/os_test.h +++ b/src/os_test.h @@ -34,6 +34,6 @@ struct OsTestFile { OsTestFile *pNext; }; -void sqlite3SetCrashseed(int seed); +void sqlite3SetCrashParams(int iDelay, char const *zFile); #endif /* _SQLITE_OS_UNIX_H_ */ diff --git a/src/pager.c b/src/pager.c index 9e46ef899c..85e09e3eff 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.136 2004/06/23 01:05:27 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.137 2004/06/23 10:43:10 danielk1977 Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -479,11 +479,15 @@ static int pager_unwritelock(Pager *pPager){ pPg->dirty = 0; pPg->needSync = 0; } + pPager->dirtyCache = 0; + pPager->nMaster = 0; + pPager->nRec = 0; }else{ assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; + pPager->origDbSize = 0; return SQLITE_OK; } @@ -508,7 +512,12 @@ static int pager_unwritelock(Pager *pPager){ ** chance of failing the checksum and thus detecting the problem. */ static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){ - u32 cksum = pPager->cksumInit + pgno; + u32 cksum = pPager->cksumInit; + int i = pPager->pageSize-200; + while( i>0 ){ + cksum += aData[i]; + i -= 200; + } return cksum; } @@ -840,7 +849,9 @@ static int pager_playback(Pager *pPager, int useJournalSize){ /* (2) Read the number of pages stored in the journal. */ rc = read32bits(&pPager->jfd, (u32*)&nRec); if( rc ) goto end_playback; - if( nRec==0xffffffff || useJournalSize ){ + if( nRec==0xffffffff || useJournalSize || + nRec>(szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager) + ){ nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); } @@ -1007,6 +1018,8 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){ } if( mxPage>10 ){ pPager->mxPage = mxPage; + }else{ + pPager->mxPage = 10; } } @@ -2409,19 +2422,6 @@ int sqlite3pager_commit(Pager *pPager){ return rc; } assert( pPager->journalOpen ); -#if 0 - rc = syncJournal(pPager, 0); - if( rc!=SQLITE_OK ){ - goto commit_abort; - } - pPg = pager_get_all_dirty_pages(pPager); - if( pPg ){ - rc = pager_write_pagelist(pPg); - if( rc || (!pPager->noSync && sqlite3OsSync(&pPager->fd)!=SQLITE_OK) ){ - goto commit_abort; - } - } -#endif rc = sqlite3pager_sync(pPager, 0); if( rc!=SQLITE_OK ){ goto commit_abort; diff --git a/src/test1.c b/src/test1.c index 7aa1468e44..aedda2dd73 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.83 2004/06/22 13:12:52 danielk1977 Exp $ +** $Id: test1.c,v 1.84 2004/06/23 10:43:11 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -984,24 +984,24 @@ bad_args: return TCL_ERROR; } -static int sqlite3_crashseed( +static int sqlite3_crashparams( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef OS_TEST - int seed; - if( objc!=2 ) goto bad_args; - if( Tcl_GetIntFromObj(interp, objv[1], &seed) ) return TCL_ERROR; - sqlite3SetCrashseed(seed); + int delay; + if( objc!=3 ) goto bad_args; + if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR; + sqlite3SetCrashParams(delay, Tcl_GetString(objv[2])); #endif return TCL_OK; #ifdef OS_TEST bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", - Tcl_GetStringFromObj(objv[0], 0), "", 0); + Tcl_GetStringFromObj(objv[0], 0), " ", 0); return TCL_ERROR; #endif } @@ -2068,7 +2068,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3OsLock", test_sqlite3OsLock, 0 }, { "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 }, { "add_test_collate", test_collate, 0 }, - { "sqlite3_crashseed", sqlite3_crashseed, 0 }, + { "sqlite3_crashparams", sqlite3_crashparams, 0 }, }; int i; diff --git a/test/crash.test b/test/crash.test index e287c33051..88ababf3f0 100644 --- a/test/crash.test +++ b/test/crash.test @@ -10,74 +10,297 @@ #*********************************************************************** # This file implements regression tests for SQLite library. # -# $Id: crash.test,v 1.2 2004/06/23 01:05:27 danielk1977 Exp $ +# $Id: crash.test,v 1.3 2004/06/23 10:43:15 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl +set repeats 100 +# set repeats 5 + # This proc execs a seperate process that crashes midway through executing # the SQL script $sql on database test.db. # -# Argument $crashdelay indicates the number of file closes or syncs to wait -# before crashing. When a crash occurs a random subset of unsynced writes -# are written into any open files. -proc crashsql {crashdelay sql} { +# The crash occurs during a sync() of file $crashfile. When the crash +# occurs a random subset of all unsynced writes made by the process are +# written into the files on disk. Argument $crashdelay indicates the +# number of file syncs to wait before crashing. +# +# The return value is a list of two elements. The first element is a +# boolean, indicating whether or not the process actually crashed or +# reported some other error. The second element in the returned list is the +# error message. This is "child process exited abnormally" if the crash +# occured. +proc crashsql {crashdelay crashfile sql} { + set cfile [file join [pwd] $crashfile] set f [open crash.tcl w] - puts $f "sqlite3_crashseed $crashdelay" + puts $f "sqlite3_crashparams $crashdelay $cfile" puts $f "sqlite3 db test.db" + puts $f "db eval {pragma full_synchronous = 1}" puts $f "db eval {" puts $f "$sql" puts $f "}" close $f - exec [file join . crashtest] crash.tcl + set r [catch { + exec [file join . crashtest] crash.tcl + } msg] + lappend r $msg } +# The following procedure computes a "signature" for table "abc". If +# abc changes in any way, the signature should change. +proc signature {} { + return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}] +} +proc signature2 {} { + return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}] +} + +# Use a small pager-cache for these tests. +do_test crash-0.1 { + execsql { pragma default_cache_size = 10 } +} {} + +#-------------------------------------------------------------------------- # Simple crash test: # # crash-1.1: Create a database with a table with two rows. # crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during -# journal-sync +# the first journal-sync. # crash-1.3: Ensure the database is in the same state as after crash-1.1. # crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during -# database-sync +# the first database-sync. # crash-1.5: Ensure the database is in the same state as after crash-1.1. # +# Tests 1.6 through 1.9 are the same as 1.2 through 1.5, except the crash +# is requested on the second sync of each file. This doesn't happen in +# such a small test case, so these tests are just to verify that the +# test infrastructure operates as expected. +# do_test crash-1.1 { execsql { CREATE TABLE abc(a, b, c); INSERT INTO abc VALUES(1, 2, 3); INSERT INTO abc VALUES(4, 5, 6); } -} {} + set ::sig [signature] + expr 0 +} {0} do_test crash-1.2 { - catch { - crashsql 1 { - DELETE FROM abc WHERE a = 1; - } - } msg - set msg -} {child process exited abnormally} + crashsql 1 test.db-journal { + DELETE FROM abc WHERE a = 1; + } +} {1 {child process exited abnormally}} + +# exit + do_test crash-1.3 { - catchsql { - SELECT * FROM abc; - } -} {0 {1 2 3 4 5 6}} + signature +} $::sig do_test crash-1.4 { - catch { - crashsql 1 { - DELETE FROM abc WHERE a = 1; - } - } msg - set msg -} {child process exited abnormally} + crashsql 1 test.db { + DELETE FROM abc WHERE a = 1; + } +} {1 {child process exited abnormally}} do_test crash-1.5 { + signature +} $::sig +do_test crash-1.6 { + crashsql 2 test.db-journal { + DELETE FROM abc WHERE a = 1; + } +} {0 {}} +do_test crash-1.7 { catchsql { SELECT * FROM abc; } -} {0 {1 2 3 4 5 6}} +} {0 {4 5 6}} +do_test crash-1.8 { + crashsql 2 test.db { + DELETE FROM abc WHERE a = 4; + } +} {0 {}} +do_test crash-1.9 { + catchsql { + SELECT * FROM abc; + } +} {0 {}} + +#-------------------------------------------------------------------------- +# The following tests test recovery when both the database file and the the +# journal file contain corrupt data. This can happen after pages are +# written to the database file before a transaction is committed due to +# cache-pressure. +# +# crash-2.1: Insert 18 pages of data into the database. +# crash-2.2: Check the database file size looks ok. +# crash-2.3: Delete 15 or so pages (with a 10 page page-cache), then crash. +# crash-2.4: Ensure the database is in the same state as after crash-2.1. +# +# Test cases crash-2.5 and crash-2.6 check that the database is OK if the +# crash occurs during the main database file sync. But this isn't really +# different from the crash-1.* cases. +# +do_test crash-2.1 { + execsql { BEGIN } + for {set n 0} {$n < 1000} {incr n} { + execsql "INSERT INTO abc VALUES($n, [expr 2*$n], [expr 3*$n])" + } + execsql { COMMIT } + set ::sig [signature] + execsql { SELECT sum(a), sum(b), sum(c) from abc } +} {499500 999000 1498500} +do_test crash-2.2 { + expr [file size test.db] / 1024 +} {19} +do_test crash-2.3 { + crashsql 2 test.db-journal { + DELETE FROM abc WHERE a < 800; + } +} {1 {child process exited abnormally}} +do_test crash-2.4 { + signature +} $sig +do_test crash-2.5 { + crashsql 1 test.db { + DELETE FROM abc WHERE a<800; + } +} {1 {child process exited abnormally}} +do_test crash-2.6 { + signature +} $sig + +#-------------------------------------------------------------------------- +# The crash-3.* test cases are essentially the same test as test case +# crash-2.*, but with a more complicated data set. +# +# The test is repeated a few times with different seeds for the random +# number generator in the crashing executable. Because there is no way to +# seed the random number generator directly, some SQL is added to the test +# case to 'use up' a different quantity random numbers before the test SQL +# is executed. +# + +# Make sure the file is much bigger than the pager-cache (10 pages). This +# ensures that cache-spills happen regularly. +do_test crash-3.0 { + execsql { + INSERT INTO abc SELECT * FROM abc; + INSERT INTO abc SELECT * FROM abc; + INSERT INTO abc SELECT * FROM abc; + INSERT INTO abc SELECT * FROM abc; + INSERT INTO abc SELECT * FROM abc; + } + expr [file size test.db] / 1024 +} {554} +for {set i 1} {$i < $repeats} {incr i} { + set sig [signature] + do_test crash-3.$i.1 { + crashsql [expr $i%5 + 1] test.db-journal " + BEGIN; + SELECT random() FROM abc LIMIT $i; + INSERT INTO abc VALUES(randstr(10,10), 0, 0); + DELETE FROM abc WHERE random()%10!=0; + COMMIT; + " + } {1 {child process exited abnormally}} + do_test crash-3.$i.2 { + signature + } $sig +} + +#-------------------------------------------------------------------------- +# The following test cases - crash-4.* - test the correct recovery of the +# database when a crash occurs during a multi-file transaction. +# +# crash-4.1.*: Test recovery when crash occurs during sync() of the +# main database journal file. +# crash-4.2.*: Test recovery when crash occurs during sync() of an +# attached database journal file. +# crash-4.3.*: Test recovery when crash occurs during sync() of the master +# journal file. +# +do_test crash-4.0 { + file delete -force test2.db + file delete -force test2.db-journal + sqlite3 db2 test2.db + execsql {pragma default_cache_size = 10} db2 + db2 close + execsql { + ATTACH 'test2.db' AS aux; + CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc; + } + expr [file size test2.db] / 1024 +} {559} + +for {set i 1} {$i < $repeats} {incr i} { + set sig [signature] + set sig2 [signature2] + do_test crash-4.1.$i.1 { + crashsql [expr $i%5 + 1] test.db-journal " + ATTACH 'test2.db' AS aux; + BEGIN; + SELECT random() FROM abc LIMIT $i; + INSERT INTO abc VALUES(randstr(10,10), 0, 0); + DELETE FROM abc WHERE random()%10!=0; + INSERT INTO abc2 VALUES(randstr(10,10), 0, 0); + DELETE FROM abc2 WHERE random()%10!=0; + COMMIT; + " + } {1 {child process exited abnormally}} + do_test crash-4.1.$i.2 { + signature + } $sig + do_test crash-4.1.$i.3 { + signature2 + } $sig2 +} +for {set i 1} {$i < $repeats} {incr i} { + set sig [signature] + set sig2 [signature2] + do_test crash-4.2.$i.1 { + crashsql [expr $i%5 + 1] test2.db-journal " + ATTACH 'test2.db' AS aux; + BEGIN; + SELECT random() FROM abc LIMIT $i; + INSERT INTO abc VALUES(randstr(10,10), 0, 0); + DELETE FROM abc WHERE random()%10!=0; + INSERT INTO abc2 VALUES(randstr(10,10), 0, 0); + DELETE FROM abc2 WHERE random()%10!=0; + COMMIT; + " + } {1 {child process exited abnormally}} + do_test crash-4.2.$i.2 { + signature + } $sig + do_test crash-4.2.$i.3 { + signature2 + } $sig2 +} +for {set i 1} {$i < 5} {incr i} { + set sig [signature] + set sig2 [signature2] + do_test crash-4.3.$i.1 { + crashsql 1 test.db-mj* " + ATTACH 'test2.db' AS aux; + BEGIN; + SELECT random() FROM abc LIMIT $i; + INSERT INTO abc VALUES(randstr(10,10), 0, 0); + DELETE FROM abc WHERE random()%10!=0; + INSERT INTO abc2 VALUES(randstr(10,10), 0, 0); + DELETE FROM abc2 WHERE random()%10!=0; + COMMIT; + " + } {1 {child process exited abnormally}} + do_test crash-4.3.$i.2 { + signature + } $sig + do_test crash-4.3.$i.3 { + signature2 + } $sig2 +} finish_test -