Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | More rollback problems: Fix two more errors introduced by checking (410) that can cause database corruption after a ROLLBACK. Also add new tests to make sure everything is working this time. (CVS 663) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
f6e24d5ccbcfcf5863ffbd65860dafa2 |
User & Date: | drh 2002-07-07 16:52:47.000 |
Context
2002-07-07
| ||
17:12 | Fix for Win32: The %p format on Win32 does not prepend a "0x" as it should. (CVS 665) (check-in: ee86704daf user: drh tags: trunk) | |
16:52 | More rollback problems: Fix two more errors introduced by checking (410) that can cause database corruption after a ROLLBACK. Also add new tests to make sure everything is working this time. (CVS 663) (check-in: f6e24d5ccb user: drh tags: trunk) | |
2002-07-06
| ||
16:34 | Version 2.5.5 (CVS 662) (check-in: 6284c65c17 user: drh tags: trunk) | |
Changes
Changes to VERSION.
|
| | | 1 | 2.5.6 |
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2001 September 15 ** ** 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: btree.c,v 1.65 2002/07/07 16:52:47 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 | MemPage *pMemPage; if( pgno==0 ){ assert( pOvfl!=0 ); pgno = sqlitepager_pagenumber(pOvfl); } assert( pgno>2 ); rc = sqlitepager_write(pPage1); if( rc ){ return rc; } pPage1->nFree++; if( pPage1->nFree>0 && pPage1->freeList ){ OverflowPage *pFreeIdx; | > > > > > > | 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 | MemPage *pMemPage; if( pgno==0 ){ assert( pOvfl!=0 ); pgno = sqlitepager_pagenumber(pOvfl); } assert( pgno>2 ); pMemPage = (MemPage*)pPage; pMemPage->isInit = 0; if( pMemPage->pParent ){ sqlitepager_unref(pMemPage->pParent); pMemPage->pParent = 0; } rc = sqlitepager_write(pPage1); if( rc ){ return rc; } pPage1->nFree++; if( pPage1->nFree>0 && pPage1->freeList ){ OverflowPage *pFreeIdx; |
︙ | ︙ | |||
1602 1603 1604 1605 1606 1607 1608 | if( rc ){ if( needUnref ) sqlitepager_unref(pOvfl); return rc; } pOvfl->iNext = pPage1->freeList; pPage1->freeList = pgno; memset(pOvfl->aPayload, 0, OVERFLOW_SIZE); | < < < < < < | 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | if( rc ){ if( needUnref ) sqlitepager_unref(pOvfl); return rc; } pOvfl->iNext = pPage1->freeList; pPage1->freeList = pgno; memset(pOvfl->aPayload, 0, OVERFLOW_SIZE); if( needUnref ) rc = sqlitepager_unref(pOvfl); return rc; } /* ** Erase all the data out of a cell. This involves returning overflow ** pages back the freelist. |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** ** $Id: func.c,v 1.22 2002/07/07 16:52:47 drh Exp $ */ #include <ctype.h> #include <math.h> #include <stdlib.h> #include <assert.h> #include "sqliteInt.h" |
︙ | ︙ | |||
243 244 245 246 247 248 249 250 251 252 253 254 255 256 | */ static void nullifFunc(sqlite_func *context, int argc, const char **argv){ if( argv[0]!=0 && sqliteCompare(argv[0],argv[1])!=0 ){ sqlite_set_result_string(context, argv[0], -1); } } /* ** An instance of the following structure holds the context of a ** sum() or avg() aggregate computation. */ typedef struct SumCtx SumCtx; struct SumCtx { double sum; /* Sum of terms */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | */ static void nullifFunc(sqlite_func *context, int argc, const char **argv){ if( argv[0]!=0 && sqliteCompare(argv[0],argv[1])!=0 ){ sqlite_set_result_string(context, argv[0], -1); } } #ifdef SQLITE_TEST /* ** This function generates a string of random characters. Used for ** generating test data. */ static void randStr(sqlite_func *context, int argc, const char **argv){ static const char zSrc[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ".-!,:*^+=_|?/<> "; int iMin, iMax, n, r, i; char zBuf[1000]; if( argc>=1 ){ iMin = atoi(argv[0]); if( iMin<0 ) iMin = 0; if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; }else{ iMin = 1; } if( argc>=2 ){ iMax = atoi(argv[1]); if( iMax<iMin ) iMax = iMin; if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf); }else{ iMax = 50; } n = iMin; if( iMax>iMin ){ r = sqliteRandomInteger(); if( r<0 ) r = -r; n += r%(iMax + 1 - iMin); } r = 0; for(i=0; i<n; i++){ r = (r + sqliteRandomByte())% (sizeof(zSrc)-1); zBuf[i] = zSrc[r]; } zBuf[n] = 0; sqlite_set_result_string(context, zBuf, n); } #endif /* ** An instance of the following structure holds the context of a ** sum() or avg() aggregate computation. */ typedef struct SumCtx SumCtx; struct SumCtx { double sum; /* Sum of terms */ |
︙ | ︙ | |||
434 435 436 437 438 439 440 441 442 443 444 445 446 447 | { "coalesce", 0, 0, 0 }, { "coalesce", 1, 0, 0 }, { "ifnull", 2, SQLITE_ARGS, ifnullFunc }, { "random", -1, SQLITE_NUMERIC, randomFunc }, { "like", 2, SQLITE_NUMERIC, likeFunc }, { "glob", 2, SQLITE_NUMERIC, globFunc }, { "nullif", 2, SQLITE_ARGS, nullifFunc }, }; static struct { char *zName; int nArg; int dataType; void (*xStep)(sqlite_func*,int,const char**); void (*xFinalize)(sqlite_func*); | > > > | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | { "coalesce", 0, 0, 0 }, { "coalesce", 1, 0, 0 }, { "ifnull", 2, SQLITE_ARGS, ifnullFunc }, { "random", -1, SQLITE_NUMERIC, randomFunc }, { "like", 2, SQLITE_NUMERIC, likeFunc }, { "glob", 2, SQLITE_NUMERIC, globFunc }, { "nullif", 2, SQLITE_ARGS, nullifFunc }, #ifdef SQLITE_TEST { "randstr", 2, SQLITE_TEXT, randStr }, #endif }; static struct { char *zName; int nArg; int dataType; void (*xStep)(sqlite_func*,int,const char**); void (*xFinalize)(sqlite_func*); |
︙ | ︙ |
Changes to src/os.c.
︙ | ︙ | |||
713 714 715 716 717 718 719 | } /* ** Get information to seed the random number generator. */ int sqliteOsRandomSeed(char *zBuf){ static int once = 1; | > > > > > > | | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | } /* ** Get information to seed the random number generator. */ int sqliteOsRandomSeed(char *zBuf){ static int once = 1; #ifdef SQLITE_TEST /* When testing, always use the same random number sequence. ** This makes the tests repeatable. */ memset(zBuf, 0, 256); #endif #if OS_UNIX && !defined(SQLITE_TEST) int pid; time((time_t*)zBuf); pid = getpid(); memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); #endif #if OS_WIN && !defined(SQLITE_TEST) GetSystemTime((LPSYSTEMTIME)zBuf); #endif if( once ){ int seed; memcpy(&seed, zBuf, sizeof(seed)); srand(seed); once = 0; |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** 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. ** | | | 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.49 2002/07/07 16:52:47 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include "os.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
70 71 72 73 74 75 76 | struct PgHdr { Pager *pPager; /* The pager to which this page belongs */ Pgno pgno; /* The page number for this page */ PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ int nRef; /* Number of users of this page */ PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */ PgHdr *pNextAll, *pPrevAll; /* A list of all pages */ | | | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | struct PgHdr { Pager *pPager; /* The pager to which this page belongs */ Pgno pgno; /* The page number for this page */ PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ int nRef; /* Number of users of this page */ PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */ PgHdr *pNextAll, *pPrevAll; /* A list of all pages */ u8 inJournal; /* TRUE if has been written to journal */ u8 inCkpt; /* TRUE if written to the checkpoint journal */ u8 dirty; /* TRUE if we need to write back changes */ u8 alwaysRollback; /* Disable dont_rollback() for this page */ /* SQLITE_PAGE_SIZE bytes of page data follow this header */ /* Pager.nExtra bytes of local data follow the page data */ }; /* ** Convert a pointer to a PgHdr into a pointer to its data ** and back again. |
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 128 129 130 131 132 | u8 noSync; /* Do not sync the journal if true */ u8 state; /* SQLITE_UNLOCK, _READLOCK or _WRITELOCK */ u8 errMask; /* One of several kinds of errors */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyFile; /* True if database file has changed in any way */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInCkpt; /* One bit for each page in the database */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pAll; /* List of all pages */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number of PgHdr */ }; | > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | u8 noSync; /* Do not sync the journal if true */ u8 state; /* SQLITE_UNLOCK, _READLOCK or _WRITELOCK */ u8 errMask; /* One of several kinds of errors */ u8 tempFile; /* zFilename is a temporary file */ u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyFile; /* True if database file has changed in any way */ u8 alwaysRollback; /* Disable dont_rollback() for all pages */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInCkpt; /* One bit for each page in the database */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pAll; /* List of all pages */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number of PgHdr */ }; |
︙ | ︙ | |||
856 857 858 859 860 861 862 863 864 865 866 867 868 869 | *ppPage = 0; return SQLITE_IOERR; } pPg = pPager->pFirst; } assert( pPg->nRef==0 ); assert( pPg->dirty==0 ); /* Unlink the old page from the free list and the hash table */ if( pPg->pPrevFree ){ pPg->pPrevFree->pNextFree = pPg->pNextFree; }else{ assert( pPager->pFirst==pPg ); | > > > > > > > > > > > > | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | *ppPage = 0; return SQLITE_IOERR; } pPg = pPager->pFirst; } assert( pPg->nRef==0 ); assert( pPg->dirty==0 ); /* If the page we are recyclying is marked as alwaysRollback, then ** set the global alwaysRollback flag, thus disabling the ** sqlite_dont_rollback() optimization for the rest of this transaction. ** It is necessary to do this because the page marked alwaysRollback ** might be reloaded at a later time but at that point we won't remember ** that is was marked alwaysRollback. This means that all pages must ** be marked as alwaysRollback from here on out. */ if( pPg->alwaysRollback ){ pPager->alwaysRollback = 1; } /* Unlink the old page from the free list and the hash table */ if( pPg->pPrevFree ){ pPg->pPrevFree->pNextFree = pPg->pNextFree; }else{ assert( pPager->pFirst==pPg ); |
︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 | pPager->aInJournal = 0; sqliteOsReadLock(&pPager->fd); return SQLITE_CANTOPEN; } pPager->journalOpen = 1; pPager->needSync = 0; pPager->dirtyFile = 0; pPager->state = SQLITE_WRITELOCK; sqlitepager_pagecount(pPager); pPager->origDbSize = pPager->dbSize; rc = sqliteOsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); if( rc==SQLITE_OK ){ rc = sqliteOsWrite(&pPager->jfd, &pPager->dbSize, sizeof(Pgno)); } | > | 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | pPager->aInJournal = 0; sqliteOsReadLock(&pPager->fd); return SQLITE_CANTOPEN; } pPager->journalOpen = 1; pPager->needSync = 0; pPager->dirtyFile = 0; pPager->alwaysRollback = 0; pPager->state = SQLITE_WRITELOCK; sqlitepager_pagecount(pPager); pPager->origDbSize = pPager->dbSize; rc = sqliteOsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); if( rc==SQLITE_OK ){ rc = sqliteOsWrite(&pPager->jfd, &pPager->dbSize, sizeof(Pgno)); } |
︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 | ** rollback journal. */ void sqlitepager_dont_rollback(void *pData){ PgHdr *pPg = DATA_TO_PGHDR(pData); Pager *pPager = pPg->pPager; if( pPager->state!=SQLITE_WRITELOCK || pPager->journalOpen==0 ) return; | | | 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | ** rollback journal. */ void sqlitepager_dont_rollback(void *pData){ PgHdr *pPg = DATA_TO_PGHDR(pData); Pager *pPager = pPg->pPager; if( pPager->state!=SQLITE_WRITELOCK || pPager->journalOpen==0 ) return; if( pPg->alwaysRollback || pPager->alwaysRollback ) return; if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){ assert( pPager->aInJournal!=0 ); pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); pPg->inJournal = 1; if( pPager->ckptInUse ){ pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7); pPg->inCkpt = 1; |
︙ | ︙ |
Changes to test/all.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2001 September 15 # # 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 runs all tests. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2001 September 15 # # 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 runs all tests. # # $Id: all.test,v 1.15 2002/07/07 16:52:47 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl rename finish_test really_finish_test proc finish_test {} {memleak_check} if {[file exists ./sqlite_test_count]} { |
︙ | ︙ | |||
30 31 32 33 34 35 36 | set LeakList {} set EXCLUDE { all.test quick.test malloc.test misuse.test | < > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | set LeakList {} set EXCLUDE { all.test quick.test malloc.test misuse.test } # btree2.test for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} { if {$Counter%2} { set ::SETUP_SQL {PRAGMA default_synchronous=off;} } else { catch {unset ::SETUP_SQL} } |
︙ | ︙ |
Changes to test/quick.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2001 September 15 # # 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 runs all tests. # | | > | 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 | # 2001 September 15 # # 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 runs all tests. # # $Id: quick.test,v 1.3 2002/07/07 16:52:47 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl rename finish_test really_finish_test proc finish_test {} {} set ISQUICK 1 set EXCLUDE { all.test quick.test btree2.test malloc.test } |
︙ | ︙ |
Changes to test/trans.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # 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. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # 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: trans.test,v 1.13 2002/07/07 16:52:47 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create several tables to work with. |
︙ | ︙ | |||
801 802 803 804 805 806 807 | execsql {SELECT md5sum(x,y,z) FROM t2} } $checksum do_test trans-8.2 { execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master} } $checksum2 integrity_check trans-8.3 | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | execsql {SELECT md5sum(x,y,z) FROM t2} } $checksum do_test trans-8.2 { execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master} } $checksum2 integrity_check trans-8.3 # In the following sequence of tests, compute the MD5 sum of the content # of a table, make lots of modifications to that table, then do a rollback. # Verify that after the rollback, the MD5 checksum is unchanged. # do_test trans-9.1 { execsql { PRAGMA cache_size=10; BEGIN; CREATE TABLE t3(x TEXT); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 VALUES(randstr(10,400)); INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; INSERT INTO t3 SELECT randstr(10,400) FROM t3; COMMIT; SELECT count(*) FROM t3; } } {1024} # The following procedure computes a "signature" for table "t3". If # T3 changes in any way, the signature should change. # # This is used to test ROLLBACK. We gather a signature for t3, then # make lots of changes to t3, then rollback and take another signature. # The two signatures should be the same. # proc signature {} { return [db eval {SELECT count(*), md5sum(x) FROM t3}] } # Repeat the following group of tests 20 times for quick testing and # 40 times for full testing. Each iteration of the test makes table # t3 a little larger, and thus takes a little longer, so doing 40 tests # is more than 2.0 times slower than doing 20 tests. Considerably more. # if {[info exists ISQUICK]} { set limit 20 } else { set limit 40 } # Do rollbacks. Make sure the signature does not change. # for {set i 2} {$i<=$limit} {incr i} { set ::sig [signature] set cnt [lindex $::sig 0] do_test trans-9.$i.1-$cnt { execsql { BEGIN; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; ROLLBACK; } signature } $sig do_test trans-9.$i.2-$cnt { execsql { BEGIN; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; DELETE FROM t3 WHERE random()%10!=0; INSERT INTO t3 SELECT randstr(10,10)||x FROM t3; ROLLBACK; } signature } $sig if {$i<$limit} { do_test trans-9.$i.9-$cnt { execsql { INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE random()%10==0; } } {} } } finish_test |
Changes to www/changes.tcl.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2002 Jly 6 (2.5.5)} { <li>Fix a bug which could cause database corruption during a rollback. This bugs was introduced in version 2.4.0 by the freelist optimization of checking [410].</li> <li>Fix a bug in aggregate functions for VIEWs.</li> <li>Other minor changes and enhancements.</li> | > > > > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2002 Jly 7 (2.5.6)} { <li>Fix more problems with rollback. Enhance the test suite to exercise the rollback logic extensively in order to prevent any future problems. </li> } chng {2002 Jly 6 (2.5.5)} { <li>Fix a bug which could cause database corruption during a rollback. This bugs was introduced in version 2.4.0 by the freelist optimization of checking [410].</li> <li>Fix a bug in aggregate functions for VIEWs.</li> <li>Other minor changes and enhancements.</li> |
︙ | ︙ |