Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add savepoint2.test, a file containing savepoint tests similar to tests in trans.test and avtrans.test. And a few savepoint bug fixes. (CVS 6039) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
98a53d91f6c0c2692d3b56687fdaba8e |
User & Date: | danielk1977 2008-12-18 15:45:07.000 |
Context
2008-12-18
| ||
18:31 | Increase test coverage of new savepoint code. (CVS 6040) (check-in: d915718d0b user: danielk1977 tags: trunk) | |
15:45 | Add savepoint2.test, a file containing savepoint tests similar to tests in trans.test and avtrans.test. And a few savepoint bug fixes. (CVS 6039) (check-in: 98a53d91f6 user: danielk1977 tags: trunk) | |
05:30 | Fix a bug in icuOpen() in fts2. (CVS 6038) (check-in: b9c722bd96 user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 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. ** ************************************************************************* ** $Id: btree.c,v 1.550 2008/12/18 15:45:07 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 | } #endif } trans_begun: if( rc==SQLITE_OK && wrflag ){ rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); } btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_AUTOVACUUM | > > > > > | 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 | } #endif } trans_begun: if( rc==SQLITE_OK && wrflag ){ /* This call makes sure that the pager has the correct number of ** open savepoints. If the second parameter is greater than 0 and ** the sub-journal is not already open, then it will be opened here. */ rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); } btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
2736 2737 2738 2739 2740 2741 2742 | rc = SQLITE_OK; }else{ /* At the pager level, a statement transaction is a savepoint with ** an index greater than all savepoints created explicitly using ** SQL statements. It is illegal to open, release or rollback any ** such savepoints while the statement transaction savepoint is active. */ | < | | 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 | rc = SQLITE_OK; }else{ /* At the pager level, a statement transaction is a savepoint with ** an index greater than all savepoints created explicitly using ** SQL statements. It is illegal to open, release or rollback any ** such savepoints while the statement transaction savepoint is active. */ rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint+1); } pBt->inStmt = 1; } sqlite3BtreeLeave(p); return rc; } |
︙ | ︙ | |||
2793 2794 2795 2796 2797 2798 2799 | sqlite3BtreeLeave(p); return rc; } /* ** The second argument to this function, op, is always SAVEPOINT_ROLLBACK ** or SAVEPOINT_RELEASE. This function either releases or rolls back the | | | > > > > > > | 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 | sqlite3BtreeLeave(p); return rc; } /* ** The second argument to this function, op, is always SAVEPOINT_ROLLBACK ** or SAVEPOINT_RELEASE. This function either releases or rolls back the ** savepoint identified by parameter iSavepoint, depending on the value ** of op. ** ** Normally, iSavepoint is greater than or equal to zero. However, if op is ** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the ** contents of the entire transaction are rolled back. This is different ** from a normal transaction rollback, as no locks are released and the ** transaction remains open. */ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ int rc = SQLITE_OK; if( p && p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; assert( pBt->inStmt==0 ); assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK ); |
︙ | ︙ |
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.516 2008/12/18 15:45:07 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" /* ** Macros for troubleshooting. Normally turned off */ |
︙ | ︙ | |||
1645 1646 1647 1648 1649 1650 1651 | u32 nJRec; /* Number of Journal Records */ u32 dummy; rc = readJournalHdr(pPager, szJ, &nJRec, &dummy); assert( rc!=SQLITE_DONE ); if( nJRec==0 ){ nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } | | | 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 | u32 nJRec; /* Number of Journal Records */ u32 dummy; rc = readJournalHdr(pPager, szJ, &nJRec, &dummy); assert( rc!=SQLITE_DONE ); if( nJRec==0 ){ nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } for(ii=0; rc==SQLITE_OK && ii<nJRec && pPager->journalOff<szJ; ii++){ rc = pager_playback_one_page(pPager, 1, pPager->journalOff, pDone); assert( rc!=SQLITE_DONE ); } } assert( rc!=SQLITE_OK || pPager->journalOff==szJ ); /* Now roll back pages from the sub-journal. */ |
︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 | ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */ if( pList->pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pList->pgno-1)*(i64)pPager->pageSize; char *pData = CODEC2(pPager, pList->pData, pList->pgno, 6); PAGERTRACE4("STORE %d page %d hash(%08x)\n", PAGERID(pPager), pList->pgno, pager_pagehash(pList)); IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno)); rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); PAGER_INCR(sqlite3_pager_writedb_count); PAGER_INCR(pPager->nWrite); if( pList->pgno==1 ){ | > | 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 | ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */ if( pList->pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pList->pgno-1)*(i64)pPager->pageSize; char *pData = CODEC2(pPager, pList->pData, pList->pgno, 6); PAGERTRACE4("STORE %d page %d hash(%08x)\n", PAGERID(pPager), pList->pgno, pager_pagehash(pList)); IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno)); rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); PAGER_INCR(sqlite3_pager_writedb_count); PAGER_INCR(pPager->nWrite); if( pList->pgno==1 ){ |
︙ | ︙ | |||
3544 3545 3546 3547 3548 3549 3550 | PgHdr *pPgHdr; u32 change_counter; int rc = SQLITE_OK; #ifndef SQLITE_ENABLE_ATOMIC_WRITE assert( isDirect==0 ); /* isDirect is only true for atomic writes */ #endif | | | 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 | PgHdr *pPgHdr; u32 change_counter; int rc = SQLITE_OK; #ifndef SQLITE_ENABLE_ATOMIC_WRITE assert( isDirect==0 ); /* isDirect is only true for atomic writes */ #endif if( !pPager->changeCountDone && pPager->dbSize>0 ){ /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr); if( rc!=SQLITE_OK ) return rc; if( !isDirect ){ rc = sqlite3PagerWrite(pPgHdr); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
3896 3897 3898 3899 3900 3901 3902 | /* ** Ensure that there are at least nSavepoint savepoints open. */ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ int rc = SQLITE_OK; | | | 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 | /* ** Ensure that there are at least nSavepoint savepoints open. */ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ int rc = SQLITE_OK; if( nSavepoint>pPager->nSavepoint && pPager->useJournal ){ int ii; /* Either the sub-journal is open or there are no active savepoints. */ assert( pPager->nSavepoint==0 || pPager->sjfd->pMethods ); /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM ** if the allocation fails. Otherwise, zero the new portion in case a |
︙ | ︙ | |||
3921 3922 3923 3924 3925 3926 3927 | ); pPager->aSavepoint = aNew; ii = pPager->nSavepoint; pPager->nSavepoint = nSavepoint; /* Populate the PagerSavepoint structures just allocated. */ for(/* no-op */; ii<nSavepoint; ii++){ | | | 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 | ); pPager->aSavepoint = aNew; ii = pPager->nSavepoint; pPager->nSavepoint = nSavepoint; /* Populate the PagerSavepoint structures just allocated. */ for(/* no-op */; ii<nSavepoint; ii++){ assert( pPager->dbSizeValid ); aNew[ii].nOrig = pPager->dbSize; aNew[ii].iOffset = (pPager->journalOpen ? pPager->journalOff : 0); aNew[ii].iSubRec = pPager->stmtNRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); if( !aNew[ii].pInSavepoint ){ return SQLITE_NOMEM; } |
︙ | ︙ |
Added test/savepoint2.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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | # 2008 December 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: savepoint2.test,v 1.1 2008/12/18 15:45:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Tests in this file are quite similar to those run by trans.test and # avtrans.test. # proc signature {} { return [db eval {SELECT count(*), md5sum(x) FROM t3}] } do_test savepoint2-1 { execsql { PRAGMA cache_size=10; } db close sqlite3 db test.db execsql { 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} unset -nocomplain ::sig unset -nocomplain SQL set iterations 20 set SQL(1) { 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; } set SQL(2) { 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; } set SQL(3) { UPDATE t3 SET x = randstr(10, 400) WHERE random()%10; INSERT INTO t3 SELECT x FROM t3 WHERE random()%10; DELETE FROM t3 WHERE random()%10; } set SQL(4) { INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE (random()%10 == 0); } for {set ii 2} {$ii < ($iterations+2)} {incr ii} { # Record the database signature. Optionally (every second run) open a # transaction. In all cases open savepoint "one", which may or may # not be a transaction savepoint, depending on whether or not a real # transaction has been opened. # do_test savepoint2-$ii.1 { if {$ii % 2} { execsql BEGIN } set ::sig(one) [signature] execsql "SAVEPOINT one" } {} # Execute some SQL on the database. Then rollback to savepoint "one". # Check that the database signature is as it was when "one" was opened. # do_test savepoint2-$ii.2 { execsql $SQL(1) execsql "ROLLBACK to one" signature } $::sig(one) integrity_check savepoint2-$ii.2.1 # Execute some SQL. Then open savepoint "two". Savepoint "two" is therefore # nested in savepoint "one". # do_test savepoint2-$ii.3 { execsql $SQL(1) set ::sig(two) [signature] execsql "SAVEPOINT two" } {} # More SQL changes. The rollback to savepoint "two". Check that the # signature is as it was when savepoint "two" was opened. # do_test savepoint2-$ii.4 { execsql $SQL(2) execsql "ROLLBACK to two" signature } $::sig(two) integrity_check savepoint2-$ii.4.1 # More SQL changes. The rollback to savepoint "two". Check that the # signature is as it was when savepoint "two" was opened. # do_test savepoint2-$ii.5 { execsql $SQL(2) execsql "SAVEPOINT three" execsql $SQL(3) execsql "RELEASE three" execsql "ROLLBACK to one" signature } $::sig(one) # By this point the database is in the same state as it was at the # top of the for{} loop (everything having been rolled back by the # "ROLLBACK TO one" command above). So make a few changes to the # database and COMMIT the open transaction, so that the next iteration # of the for{} loop works on a different dataset. # # The transaction being committed here may have been opened normally using # "BEGIN", or may have been opened using a transaction savepoint created # by the "SAVEPOINT one" statement. # do_test savepoint2-$ii.6 { execsql $SQL(4) execsql COMMIT sqlite3_get_autocommit db } {1} integrity_check savepoint2-$ii.6.1 } unset -nocomplain ::sig unset -nocomplain SQL finish_test |