Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Get the ABORT conflict resolution algorithm working. (CVS 362) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9be4d4c6f12056782966396dca0b8e2d |
User & Date: | drh 2002-02-02 18:49:20.000 |
Context
2002-02-03
| ||
00:56 | Five-algorithm conflict resolution appears to be working. (CVS 363) (check-in: 0115518f8e user: drh tags: trunk) | |
2002-02-02
| ||
18:49 | Get the ABORT conflict resolution algorithm working. (CVS 362) (check-in: 9be4d4c6f1 user: drh tags: trunk) | |
15:01 | Checkpoint code added to the pager. Regression tests work but the new APIs have not been tested yet. (CVS 361) (check-in: aaa53e113e user: drh tags: trunk) | |
Changes
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.47 2002/02/02 18:49:20 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. |
︙ | ︙ | |||
298 299 300 301 302 303 304 | /* ** Everything we need to know about an open database */ struct Btree { Pager *pPager; /* The page cache */ BtCursor *pCursor; /* A list of all open cursors */ PageOne *page1; /* First page of the database */ | | > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | /* ** Everything we need to know about an open database */ struct Btree { Pager *pPager; /* The page cache */ BtCursor *pCursor; /* A list of all open cursors */ PageOne *page1; /* First page of the database */ u8 inTrans; /* True if a transaction is in progress */ u8 inCkpt; /* True if there is a checkpoint on the transaction */ Hash locks; /* Key: root page number. Data: lock count */ }; typedef Btree Bt; /* ** A cursor is a pointer to a particular entry in the BTree. ** The entry is identified by its MemPage and the index in |
︙ | ︙ | |||
687 688 689 690 691 692 693 694 695 696 697 698 699 700 | ** If there is a transaction in progress, this routine is a no-op. */ static void unlockBtreeIfUnused(Btree *pBt){ if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){ sqlitepager_unref(pBt->page1); pBt->page1 = 0; pBt->inTrans = 0; } } /* ** Create a new database by initializing the first two pages of the ** file. */ | > | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | ** If there is a transaction in progress, this routine is a no-op. */ static void unlockBtreeIfUnused(Btree *pBt){ if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){ sqlitepager_unref(pBt->page1); pBt->page1 = 0; pBt->inTrans = 0; pBt->inCkpt = 0; } } /* ** Create a new database by initializing the first two pages of the ** file. */ |
︙ | ︙ | |||
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | } rc = sqlitepager_write(pBt->page1); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); } if( rc==SQLITE_OK ){ pBt->inTrans = 1; }else{ unlockBtreeIfUnused(pBt); } return rc; } /* ** Commit the transaction currently in progress. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqliteBtreeCommit(Btree *pBt){ int rc; if( pBt->inTrans==0 ) return SQLITE_ERROR; rc = sqlitepager_commit(pBt->pPager); pBt->inTrans = 0; unlockBtreeIfUnused(pBt); return rc; } /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor ** that was open at the beginning of this operation will result ** in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqliteBtreeRollback(Btree *pBt){ int rc; BtCursor *pCur; if( pBt->inTrans==0 ) return SQLITE_OK; pBt->inTrans = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pPage ){ sqlitepager_unref(pCur->pPage); pCur->pPage = 0; } } rc = sqlitepager_rollback(pBt->pPager); unlockBtreeIfUnused(pBt); return rc; } /* ** Create a new cursor for the BTree whose root is on the page ** iTable. The act of acquiring a cursor gets a read lock on ** the database file. ** ** If wrFlag==0, then the cursor can only be used for reading. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 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 | } rc = sqlitepager_write(pBt->page1); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); } if( rc==SQLITE_OK ){ pBt->inTrans = 1; pBt->inCkpt = 0; }else{ unlockBtreeIfUnused(pBt); } return rc; } /* ** Commit the transaction currently in progress. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqliteBtreeCommit(Btree *pBt){ int rc; if( pBt->inTrans==0 ) return SQLITE_ERROR; rc = sqlitepager_commit(pBt->pPager); pBt->inTrans = 0; pBt->inCkpt = 0; unlockBtreeIfUnused(pBt); return rc; } /* ** Rollback the transaction in progress. All cursors will be ** invalided by this operation. Any attempt to use a cursor ** that was open at the beginning of this operation will result ** in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ int sqliteBtreeRollback(Btree *pBt){ int rc; BtCursor *pCur; if( pBt->inTrans==0 ) return SQLITE_OK; pBt->inTrans = 0; pBt->inCkpt = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pPage ){ sqlitepager_unref(pCur->pPage); pCur->pPage = 0; } } rc = sqlitepager_rollback(pBt->pPager); unlockBtreeIfUnused(pBt); return rc; } /* ** Set the checkpoint for the current transaction. The checkpoint serves ** as a sub-transaction that can be rolled back independently of the ** main transaction. You must start a transaction before starting a ** checkpoint. The checkpoint is ended automatically if the transaction ** commits or rolls back. ** ** Only one checkpoint may be active at a time. It is an error to try ** to start a new checkpoint if another checkpoint is already active. */ int sqliteBtreeBeginCkpt(Btree *pBt){ int rc; if( !pBt->inTrans || pBt->inCkpt ) return SQLITE_ERROR; rc = sqlitepager_ckpt_begin(pBt->pPager); pBt->inCkpt = 1; return rc; } /* ** Commit a checkpoint to transaction currently in progress. If no ** checkpoint is active, this is a no-op. */ int sqliteBtreeCommitCkpt(Btree *pBt){ int rc; if( pBt->inCkpt ){ rc = sqlitepager_ckpt_commit(pBt->pPager); }else{ rc = SQLITE_OK; } return rc; } /* ** Rollback the checkpoint to the current transaction. If there ** is no active checkpoint or transaction, this routine is a no-op. ** ** All cursors will be invalided by this operation. Any attempt ** to use a cursor that was open at the beginning of this operation ** will result in an error. */ int sqliteBtreeRollbackCkpt(Btree *pBt){ int rc; BtCursor *pCur; if( pBt->inCkpt==0 ) return SQLITE_OK; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pPage ){ sqlitepager_unref(pCur->pPage); pCur->pPage = 0; } } rc = sqlitepager_ckpt_rollback(pBt->pPager); return rc; } /* ** Create a new cursor for the BTree whose root is on the page ** iTable. The act of acquiring a cursor gets a read lock on ** the database file. ** ** If wrFlag==0, then the cursor can only be used for reading. |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** | | > > > | 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 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** ** @(#) $Id: btree.h,v 1.20 2002/02/02 18:49:20 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ typedef struct Btree Btree; typedef struct BtCursor BtCursor; int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree); int sqliteBtreeClose(Btree*); int sqliteBtreeSetCacheSize(Btree*, int); int sqliteBtreeBeginTrans(Btree*); int sqliteBtreeCommit(Btree*); int sqliteBtreeRollback(Btree*); int sqliteBtreeBeginCkpt(Btree*); int sqliteBtreeCommitCkpt(Btree*); int sqliteBtreeRollbackCkpt(Btree*); int sqliteBtreeCreateTable(Btree*, int*); int sqliteBtreeCreateIndex(Btree*, int*); int sqliteBtreeDropTable(Btree*, int); int sqliteBtreeClearTable(Btree*, int); int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur); |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** COPY ** VACUUM ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** PRAGMA ** ** $Id: build.c,v 1.71 2002/02/02 18:49:20 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called after a single SQL statement has been ** parsed and we want to execute the VDBE code to implement |
︙ | ︙ | |||
1334 1335 1336 1337 1338 1339 1340 | " may not be modified", 0); pParse->nErr++; goto copy_cleanup; } v = sqliteGetVdbe(pParse); if( v ){ int openOp; | | | 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 | " may not be modified", 0); pParse->nErr++; goto copy_cleanup; } v = sqliteGetVdbe(pParse); if( v ){ int openOp; sqliteBeginMultiWriteOperation(pParse); addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeDequoteP3(v, addr); openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite; sqliteVdbeAddOp(v, openOp, 0, pTab->tnum); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ |
︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | } db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; } /* ** Generate VDBE code that prepares for doing an operation that | | > | | | | > > > > | > > > > > > > > > > > > > > > | 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 | } db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; } /* ** Generate VDBE code that prepares for doing an operation that ** might change the database. The operation will be atomic in the ** sense that it will either do its changes completely or not at ** all. So there is not need to set a checkpoint is a transaction ** is already in effect. */ void sqliteBeginWriteOperation(Parse *pParse){ Vdbe *v; v = sqliteGetVdbe(pParse); if( v==0 ) return; if( (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0); pParse->schemaVerified = 1; } } /* ** Generate VDBE code that prepares for doing an operation that ** might change the database. The operation might not be atomic in ** the sense that an error may be discovered and the operation might ** abort after some changes have been made. If we are in the middle ** of a transaction, then this sets a checkpoint. If we are not in ** a transaction, then start a transaction. */ void sqliteBeginMultiWriteOperation(Parse *pParse){ Vdbe *v; v = sqliteGetVdbe(pParse); if( v==0 ) return; if( (pParse->db->flags & SQLITE_InTrans)==0 ){ sqliteVdbeAddOp(v, OP_Transaction, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0); pParse->schemaVerified = 1; }else{ sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0); } } /* ** Generate code that concludes an operation that may have changed ** the database. This is a companion function to BeginWriteOperation(). ** If a transaction was started, then commit it. If a checkpoint was |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.40 2002/02/02 18:49:20 drh Exp $ */ #include "sqliteInt.h" /* ** This routine is call to handle SQL of the following forms: ** ** insert into TABLE (IDLIST) values(EXPRLIST) |
︙ | ︙ | |||
75 76 77 78 79 80 81 | goto insert_cleanup; } /* Allocate a VDBE */ v = sqliteGetVdbe(pParse); if( v==0 ) goto insert_cleanup; | > > > | > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | goto insert_cleanup; } /* Allocate a VDBE */ v = sqliteGetVdbe(pParse); if( v==0 ) goto insert_cleanup; if( pSelect ){ sqliteBeginMultiWriteOperation(pParse); }else{ sqliteBeginWriteOperation(pParse); } /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then this step has to generate ** all the code to implement the SELECT statement and leave the data ** in a temporary table. If data is coming from an expression list, ** then we just have to count the number of expressions. */ |
︙ | ︙ |
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.38 2002/02/02 18:49:20 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include "os.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
41 42 43 44 45 46 47 | ** file at the same time. ** ** SQLITE_WRITELOCK The page cache is writing the database. ** Access is exclusive. No other processes or ** threads can be reading or writing while one ** process is writing. ** | < < < < < < < < < < < < < < | 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 | ** file at the same time. ** ** SQLITE_WRITELOCK The page cache is writing the database. ** Access is exclusive. No other processes or ** threads can be reading or writing while one ** process is writing. ** ** The page cache comes up in SQLITE_UNLOCK. The first time a ** sqlite_page_get() occurs, the state transitions to SQLITE_READLOCK. ** After all pages have been released using sqlite_page_unref(), ** the state transitions back to SQLITE_UNLOCK. The first time ** that sqlite_page_write() is called, the state transitions to ** SQLITE_WRITELOCK. (Note that sqlite_page_write() can only be ** called on an outstanding page which means that the pager must ** be in SQLITE_READLOCK before it transitions to SQLITE_WRITELOCK.) ** The sqlite_page_rollback() and sqlite_page_commit() functions ** transition the state from SQLITE_WRITELOCK back to SQLITE_READLOCK. */ #define SQLITE_UNLOCK 0 #define SQLITE_READLOCK 1 #define SQLITE_WRITELOCK 2 /* ** Each in-memory image of a page begins with the following header. ** This header is only visible to this pager module. The client ** code that calls pager sees only the data that follows the header. */ |
︙ | ︙ | |||
250 251 252 253 254 255 256 257 258 259 260 261 | ** write lock and acquires a read lock in its place. The journal file ** is deleted and closed. */ static int pager_unwritelock(Pager *pPager){ int rc; PgHdr *pPg; if( pPager->state<SQLITE_WRITELOCK ) return SQLITE_OK; sqliteOsClose(&pPager->jfd); pPager->journalOpen = 0; sqliteOsDelete(pPager->zJournal); rc = sqliteOsReadLock(&pPager->fd); assert( rc==SQLITE_OK ); | > < | | 236 237 238 239 240 241 242 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 | ** write lock and acquires a read lock in its place. The journal file ** is deleted and closed. */ static int pager_unwritelock(Pager *pPager){ int rc; PgHdr *pPg; if( pPager->state<SQLITE_WRITELOCK ) return SQLITE_OK; sqlitepager_ckpt_commit(pPager); sqliteOsClose(&pPager->jfd); pPager->journalOpen = 0; sqliteOsDelete(pPager->zJournal); rc = sqliteOsReadLock(&pPager->fd); assert( rc==SQLITE_OK ); sqliteFree( pPager->aInJournal ); pPager->aInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; } pPager->state = SQLITE_READLOCK; return rc; } /* ** Read a single page from the journal file opened on file descriptor ** jfd. Playback this one page. */ static int pager_playback_one_page(Pager *pPager, OsFile *jfd){ int rc; PgHdr *pPg; /* An existing page in the cache */ PageRecord pgRec; rc = sqliteOsRead(jfd, &pgRec, sizeof(pgRec)); if( rc!=SQLITE_OK ) return rc; /* Sanity checking on the page */ if( pgRec.pgno>pPager->dbSize || pgRec.pgno==0 ) return SQLITE_CORRUPT; /* Playback the page. Update the in-memory copy of the page ** at the same time, if there is one. |
︙ | ︙ | |||
379 380 381 382 383 384 385 | /* ** Playback the checkpoint journal. ** ** This is similar to playing back the transaction journal but with ** a few extra twists. ** | | > | | | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | /* ** Playback the checkpoint journal. ** ** This is similar to playing back the transaction journal but with ** a few extra twists. ** ** (1) The number of pages in the database file at the start of ** the checkpoint is stored in pPager->ckptSize, not in the ** journal file itself. ** ** (2) In addition to playing back the checkpoint journal, also ** playback all pages of the transaction journal beginning ** at offset pPager->ckptJSize. */ static int pager_ckpt_playback(Pager *pPager){ int nRec; /* Number of Records */ int i; /* Loop counter */ int rc; /* Truncate the database back to its original size. */ rc = sqliteOsTruncate(&pPager->fd, pPager->ckptSize*SQLITE_PAGE_SIZE); pPager->dbSize = pPager->ckptSize; /* Figure out how many records are in the checkpoint journal. */ assert( pPager->ckptOpen && pPager->journalOpen ); sqliteOsSeek(&pPager->cpfd, 0); rc = sqliteOsFileSize(&pPager->cpfd, &nRec); |
︙ | ︙ | |||
433 434 435 436 437 438 439 | for(i=nRec-1; i>=0; i--){ rc = pager_playback_one_page(pPager, &pPager->jfd); if( rc!=SQLITE_OK ) goto end_ckpt_playback; } end_ckpt_playback: | < < < < < | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | for(i=nRec-1; i>=0; i--){ rc = pager_playback_one_page(pPager, &pPager->jfd); if( rc!=SQLITE_OK ) goto end_ckpt_playback; } end_ckpt_playback: if( rc!=SQLITE_OK ){ pPager->errMask |= PAGER_ERR_CORRUPT; rc = SQLITE_CORRUPT; } return rc; } /* ** Change the maximum number of in-memory pages that are allowed. */ |
︙ | ︙ | |||
591 592 593 594 595 596 597 | ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. */ int sqlitepager_close(Pager *pPager){ PgHdr *pPg, *pNext; switch( pPager->state ){ | < | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. */ int sqlitepager_close(Pager *pPager){ PgHdr *pPg, *pNext; switch( pPager->state ){ case SQLITE_WRITELOCK: { sqlitepager_rollback(pPager); sqliteOsUnlock(&pPager->fd); assert( pPager->journalOpen==0 ); break; } case SQLITE_READLOCK: { |
︙ | ︙ | |||
879 880 881 882 883 884 885 | } pPg->pgno = pgno; if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; }else{ pPg->inJournal = 0; } | | | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | } pPg->pgno = pgno; if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; }else{ pPg->inJournal = 0; } if( pPager->aInCkpt && (int)pgno<=pPager->ckptSize ){ pPg->inCkpt = (pPager->aInCkpt[pgno/8] & (1<<(pgno&7)))!=0; }else{ pPg->inCkpt = 0; } pPg->dirty = 0; pPg->nRef = 1; REFINFO(pPg); |
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 | pPg->inCkpt = 1; } } /* If the checkpoint journal is open and the page is not in it, ** then write the current page to the checkpoint journal. */ | | < | 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | pPg->inCkpt = 1; } } /* If the checkpoint journal is open and the page is not in it, ** then write the current page to the checkpoint journal. */ if( pPager->ckptOpen && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){ assert( pPg->inJournal ); rc = sqliteOsWrite(&pPager->cpfd, &pPg->pgno, sizeof(Pgno)); if( rc==SQLITE_OK ){ rc = sqliteOsWrite(&pPager->cpfd, pData, SQLITE_PAGE_SIZE); } if( rc!=SQLITE_OK ){ sqlitepager_rollback(pPager); |
︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 | pPager->aInCkpt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInCkpt==0 ){ sqliteOsReadLock(&pPager->fd); return SQLITE_NOMEM; } rc = sqliteOsFileSize(&pPager->jfd, &pPager->ckptJSize); if( rc ) goto ckpt_begin_failed; | | | > | < | > > > > > > | | | | | > | 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | pPager->aInCkpt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInCkpt==0 ){ sqliteOsReadLock(&pPager->fd); return SQLITE_NOMEM; } rc = sqliteOsFileSize(&pPager->jfd, &pPager->ckptJSize); if( rc ) goto ckpt_begin_failed; pPager->ckptSize = pPager->dbSize; rc = sqlitepager_opentemp(zTemp, &pPager->cpfd); if( rc ) goto ckpt_begin_failed; pPager->ckptOpen = 1; return SQLITE_OK; ckpt_begin_failed: if( pPager->aInCkpt ){ sqliteFree(pPager->aInCkpt); pPager->aInCkpt = 0; } return rc; } /* ** Commit a checkpoint. */ int sqlitepager_ckpt_commit(Pager *pPager){ if( pPager->ckptOpen ){ PgHdr *pPg; sqliteOsClose(&pPager->cpfd); pPager->ckptOpen = 0; sqliteFree( pPager->aInCkpt ); pPager->aInCkpt = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inCkpt = 0; } } return SQLITE_OK; } /* ** Rollback a checkpoint. */ int sqlitepager_ckpt_rollback(Pager *pPager){ int rc; if( pPager->ckptOpen ){ rc = pager_ckpt_playback(pPager); sqlitepager_ckpt_commit(pPager); }else{ rc = SQLITE_OK; } return rc; } #if SQLITE_TEST /* ** Print a listing of all referenced pages and their ref count. */ |
︙ | ︙ |
Changes to src/sqliteInt.h.
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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.84 2002/02/02 18:49:21 drh Exp $ */ #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> |
︙ | ︙ | |||
561 562 563 564 565 566 567 568 | char *sqlite_mprintf(const char *, ...); int sqliteExprIsConstant(Expr*); void sqliteGenerateRowDelete(Vdbe*, Table*, int); void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*); void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int); void sqliteBeginWriteOperation(Parse*); void sqliteEndWriteOperation(Parse*); | > | 561 562 563 564 565 566 567 568 569 | char *sqlite_mprintf(const char *, ...); int sqliteExprIsConstant(Expr*); void sqliteGenerateRowDelete(Vdbe*, Table*, int); void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*); void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int); void sqliteBeginWriteOperation(Parse*); void sqliteBeginMultiWriteOperation(Parse*); void sqliteEndWriteOperation(Parse*); |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.33 2002/02/02 18:49:21 drh Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. */ void sqliteUpdate( |
︙ | ︙ | |||
157 158 159 160 161 162 163 | } } /* Begin generating code. */ v = sqliteGetVdbe(pParse); if( v==0 ) goto update_cleanup; | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | } } /* Begin generating code. */ v = sqliteGetVdbe(pParse); if( v==0 ) goto update_cleanup; sqliteBeginMultiWriteOperation(pParse); /* Begin the database scan */ pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1); if( pWInfo==0 ) goto update_cleanup; /* Remember the index of every item to be updated. |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.114 2002/02/02 18:49:21 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
856 857 858 859 860 861 862 | ** ** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h ** change, be sure to change this array to match. You can use the ** "opNames.awk" awk script which is part of the source tree to regenerate ** this array, then copy and paste it into this file, if you want. */ static char *zOpName[] = { 0, | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 891 892 893 894 895 896 897 898 | ** ** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h ** change, be sure to change this array to match. You can use the ** "opNames.awk" awk script which is part of the source tree to regenerate ** this array, then copy and paste it into this file, if you want. */ static char *zOpName[] = { 0, "Transaction", "Checkpoint", "Commit", "Rollback", "ReadCookie", "SetCookie", "VerifyCookie", "Open", "OpenTemp", "OpenWrite", "OpenAux", "OpenWrAux", "Close", "MoveTo", "NewRecno", "PutIntKey", "PutStrKey", "Distinct", "Found", "NotFound", "IsUnique", "NotExists", "Delete", "Column", "KeyAsData", "Recno", "FullKey", "Rewind", "Next", "Destroy", "Clear", "CreateIndex", "CreateTable", "Reorganize", "IdxPut", "IdxDelete", "IdxRecno", "IdxGT", "IdxGE", "MemLoad", "MemStore", "ListWrite", "ListRewind", "ListRead", "ListReset", "SortPut", "SortMakeRec", "SortMakeKey", "Sort", "SortNext", "SortCallback", "SortReset", "FileOpen", "FileRead", "FileColumn", "AggReset", "AggFocus", "AggIncr", "AggNext", "AggSet", "AggGet", "SetInsert", "SetFound", "SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey", "Goto", "If", "Halt", "ColumnCount", "ColumnName", "Callback", "NullCallback", "Integer", "String", "Pop", "Dup", "Pull", "Push", "MustBeInt", "Add", "AddImm", "Subtract", "Multiply", "Divide", "Remainder", "BitAnd", "BitOr", "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", "Precision", "Min", "Max", "Like", "Glob", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", "Strlen", "Substr", "Limit", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ Btree *pBt = p->pBt; /* The backend driver */ sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ | | > | | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | int pc; /* The program counter */ Op *pOp; /* Current operation */ int rc; /* Value to return */ Btree *pBt = p->pBt; /* The backend driver */ sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ int errorAction = OE_Abort; /* Recovery action to do in case of an error */ int undoTransOnError = 0; /* If error, either ROLLBACK or COMMIT */ char zBuf[100]; /* Space to sprintf() an integer */ /* No instruction ever pushes more than a single element onto the ** stack. And the stack never grows on successive executions of the ** same loop. So the total number of instructions is an upper bound ** on the maximum stack depth required. ** |
︙ | ︙ | |||
1168 1169 1170 1171 1172 1173 1174 | ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { if( pOp->p1!=SQLITE_OK ){ rc = pOp->p1; | | | 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 | ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { if( pOp->p1!=SQLITE_OK ){ rc = pOp->p1; errorAction = pOp->p2; goto abort_due_to_error; }else{ pc = p->nOp-1; } break; } |
︙ | ︙ | |||
2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 | memcpy(zNew, zStack[tos], aStack[tos].n); zStack[tos] = zNew; aStack[tos].flags = STK_Str | STK_Dyn; } zStack[tos][aStack[tos].n-1]++; break; } /* Opcode: Transaction * * * ** ** Begin a transaction. The transaction ends when a Commit or Rollback | > > > > > > > > > > > > > > > | | | | < | 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 | memcpy(zNew, zStack[tos], aStack[tos].n); zStack[tos] = zNew; aStack[tos].flags = STK_Str | STK_Dyn; } zStack[tos][aStack[tos].n-1]++; break; } /* Opcode: Checkpoint * * * ** ** Begin a checkpoint. A checkpoint is the beginning of a operation that ** is part of a larger transaction but which might need to be rolled back ** itself without effecting the containing transaction. A checkpoint will ** be automatically committed or rollback when the VDBE halts. */ case OP_Checkpoint: { rc = sqliteBtreeBeginCkpt(pBt); if( rc==SQLITE_OK && db->pBeTemp ){ rc = sqliteBtreeBeginCkpt(pBt); } break; } /* Opcode: Transaction * * * ** ** Begin a transaction. The transaction ends when a Commit or Rollback ** opcode is encountered. Depending on the ON CONFLICT setting, the ** transaction might also be rolled back if an error is encountered. ** ** A write lock is obtained on the database file when a transaction is ** started. No other process can read or write the file while the ** transaction is underway. Starting a transaction also creates a ** rollback journal. A transaction must be started before any changes ** can be made to the database. */ case OP_Transaction: { int busy = 0; if( db->pBeTemp ){ rc = sqliteBtreeBeginTrans(db->pBeTemp); if( rc!=SQLITE_OK ){ goto abort_due_to_error; |
︙ | ︙ | |||
2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 | break; } default: { goto abort_due_to_error; } } }while( busy ); break; } /* Opcode: Commit * * * ** ** Cause all modifications to the database that have been made since the ** last Transaction to actually take effect. No additional modifications | > | 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 | break; } default: { goto abort_due_to_error; } } }while( busy ); undoTransOnError = 1; break; } /* Opcode: Commit * * * ** ** Cause all modifications to the database that have been made since the ** last Transaction to actually take effect. No additional modifications |
︙ | ︙ | |||
4462 4463 4464 4465 4466 4467 4468 | fprintf(p->trace,"\n"); } #endif } cleanup: Cleanup(p); | | > | > > > > > > > > | | | | | > | > > > > > > > > > > > > > > > | 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 | fprintf(p->trace,"\n"); } #endif } cleanup: Cleanup(p); if( rc!=SQLITE_OK ){ switch( errorAction ){ case OE_Abort: { if( !undoTransOnError ){ sqliteBtreeRollbackCkpt(pBt); if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp); break; } /* Fall through to ROLLBACK */ } case OE_Rollback: { sqliteBtreeRollback(pBt); if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp); sqliteRollbackInternalChanges(db); db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; break; } default: { if( undoTransOnError ){ sqliteBtreeCommit(pBt); if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp); sqliteCommitInternalChanges(db); db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; } break; } } }else{ sqliteBtreeCommitCkpt(pBt); if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp); } return rc; /* Jump to here if a malloc() fails. It's hard to get a malloc() ** to fail on a modern VM computer, so this code is untested. */ no_mem: sqliteSetString(pzErrMsg, "out of memory", 0); |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** ** $Id: vdbe.h,v 1.40 2002/02/02 18:49:21 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
65 66 67 68 69 70 71 | ** be sure to also update the zOpName[] array in sqliteVdbe.c to ** mirror the change. ** ** The source tree contains an AWK script named renumberOps.awk that ** can be used to renumber these opcodes when new opcodes are inserted. */ #define OP_Transaction 1 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | ** be sure to also update the zOpName[] array in sqliteVdbe.c to ** mirror the change. ** ** The source tree contains an AWK script named renumberOps.awk that ** can be used to renumber these opcodes when new opcodes are inserted. */ #define OP_Transaction 1 #define OP_Checkpoint 2 #define OP_Commit 3 #define OP_Rollback 4 #define OP_ReadCookie 5 #define OP_SetCookie 6 #define OP_VerifyCookie 7 #define OP_Open 8 #define OP_OpenTemp 9 #define OP_OpenWrite 10 #define OP_OpenAux 11 #define OP_OpenWrAux 12 #define OP_Close 13 #define OP_MoveTo 14 #define OP_NewRecno 15 #define OP_PutIntKey 16 #define OP_PutStrKey 17 #define OP_Distinct 18 #define OP_Found 19 #define OP_NotFound 20 #define OP_IsUnique 21 #define OP_NotExists 22 #define OP_Delete 23 #define OP_Column 24 #define OP_KeyAsData 25 #define OP_Recno 26 #define OP_FullKey 27 #define OP_Rewind 28 #define OP_Next 29 #define OP_Destroy 30 #define OP_Clear 31 #define OP_CreateIndex 32 #define OP_CreateTable 33 #define OP_Reorganize 34 #define OP_IdxPut 35 #define OP_IdxDelete 36 #define OP_IdxRecno 37 #define OP_IdxGT 38 #define OP_IdxGE 39 #define OP_MemLoad 40 #define OP_MemStore 41 #define OP_ListWrite 42 #define OP_ListRewind 43 #define OP_ListRead 44 #define OP_ListReset 45 #define OP_SortPut 46 #define OP_SortMakeRec 47 #define OP_SortMakeKey 48 #define OP_Sort 49 #define OP_SortNext 50 #define OP_SortCallback 51 #define OP_SortReset 52 #define OP_FileOpen 53 #define OP_FileRead 54 #define OP_FileColumn 55 #define OP_AggReset 56 #define OP_AggFocus 57 #define OP_AggIncr 58 #define OP_AggNext 59 #define OP_AggSet 60 #define OP_AggGet 61 #define OP_SetInsert 62 #define OP_SetFound 63 #define OP_SetNotFound 64 #define OP_MakeRecord 65 #define OP_MakeKey 66 #define OP_MakeIdxKey 67 #define OP_IncrKey 68 #define OP_Goto 69 #define OP_If 70 #define OP_Halt 71 #define OP_ColumnCount 72 #define OP_ColumnName 73 #define OP_Callback 74 #define OP_NullCallback 75 #define OP_Integer 76 #define OP_String 77 #define OP_Pop 78 #define OP_Dup 79 #define OP_Pull 80 #define OP_Push 81 #define OP_MustBeInt 82 #define OP_Add 83 #define OP_AddImm 84 #define OP_Subtract 85 #define OP_Multiply 86 #define OP_Divide 87 #define OP_Remainder 88 #define OP_BitAnd 89 #define OP_BitOr 90 #define OP_BitNot 91 #define OP_ShiftLeft 92 #define OP_ShiftRight 93 #define OP_AbsValue 94 #define OP_Precision 95 #define OP_Min 96 #define OP_Max 97 #define OP_Like 98 #define OP_Glob 99 #define OP_Eq 100 #define OP_Ne 101 #define OP_Lt 102 #define OP_Le 103 #define OP_Gt 104 #define OP_Ge 105 #define OP_IsNull 106 #define OP_NotNull 107 #define OP_Negative 108 #define OP_And 109 #define OP_Or 110 #define OP_Not 111 #define OP_Concat 112 #define OP_Noop 113 #define OP_Strlen 114 #define OP_Substr 115 #define OP_Limit 116 #define OP_MAX 116 /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqliteVdbeCreate(sqlite*); void sqliteVdbeCreateCallback(Vdbe*, int*); |
︙ | ︙ |
Changes to test/pager.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 page cache subsystem. # | | | 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 page cache subsystem. # # $Id: pager.test,v 1.11 2002/02/02 18:49:21 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {[info commands pager_open]!=""} { |
︙ | ︙ | |||
239 240 241 242 243 244 245 | } $i body; do_test pager-3.7.$i.3 $body {1} } do_test pager-3.99 { pager_close $::p1 } {} | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 239 240 241 242 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 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | } $i body; do_test pager-3.7.$i.3 $body {1} } do_test pager-3.99 { pager_close $::p1 } {} # tests of the checkpoint mechanism and api # do_test pager-4.0 { set v [catch { file delete -force ptf1.db set ::p1 [pager_open ptf1.db 15] } msg] if {$v} {lappend v $msg} set v } {0} do_test pager-4.1 { set g1 [page_get $::p1 1] page_write $g1 "Page-1 v0" for {set i 2} {$i<=20} {incr i} { set gx [page_get $::p1 $i] page_write $gx "Page-$i v0" page_unref $gx } pager_commit $::p1 } {} for {set i 1} {$i<=20} {incr i} { do_test pager-4.2.$i { set gx [page_get $p1 $i] set v [page_read $gx] page_unref $gx set v } "Page-$i v0" } do_test pager-4.3 { lrange [pager_stats $::p1] 0 1 } {ref 1} do_test pager-4.4 { lrange [pager_stats $::p1] 8 9 } {state 1} for {set i 1} {$i<20} {incr i} { do_test pager-4.5.$i.0 { set res {} for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] set value [page_read $gx] page_unref $gx set shouldbe "Page-$j v[expr {$i-1}]" if {$value!=$shouldbe} { lappend res $value $shouldbe } } set res } {} do_test pager-4.5.$i.1 { page_write $g1 "Page-1 v$i" lrange [pager_stats $p1] 8 9 } {state 2} do_test pager-4.5.$i.2 { for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] page_write $gx "Page-$j v$i" page_unref $gx if {$j==$i} { pager_ckpt_begin $p1 } } } {} do_test pager-4.5.$i.3 { set res {} for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] set value [page_read $gx] page_unref $gx set shouldbe "Page-$j v$i" if {$value!=$shouldbe} { lappend res $value $shouldbe } } set res } {} do_test pager-4.5.$i.4 { pager_rollback $p1 set res {} for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] set value [page_read $gx] page_unref $gx set shouldbe "Page-$j v[expr {$i-1}]" if {$value!=$shouldbe} { lappend res $value $shouldbe } } set res } {} do_test pager-4.5.$i.5 { page_write $g1 "Page-1 v$i" lrange [pager_stats $p1] 8 9 } {state 2} do_test pager-4.5.$i.6 { for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] page_write $gx "Page-$j v$i" page_unref $gx if {$j==$i} { pager_ckpt_begin $p1 } } } {} do_test pager-4.5.$i.7 { pager_ckpt_rollback $p1 for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] set value [page_read $gx] page_unref $gx if {$j<=$i || $i==1} { set shouldbe "Page-$j v$i" } else { set shouldbe "Page-$j v[expr {$i-1}]" } if {$value!=$shouldbe} { lappend res $value $shouldbe } } set res } {} do_test pager-4.5.$i.8 { for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] page_write $gx "Page-$j v$i" page_unref $gx if {$j==$i} { pager_ckpt_begin $p1 } } } {} do_test pager-4.5.$i.9 { pager_ckpt_commit $p1 for {set j 2} {$j<=20} {incr j} { set gx [page_get $p1 $j] set value [page_read $gx] page_unref $gx set shouldbe "Page-$j v$i" if {$value!=$shouldbe} { lappend res $value $shouldbe } } set res } {} do_test pager-4.5.$i.10 { pager_commit $p1 lrange [pager_stats $p1] 8 9 } {state 1} } do_test pager-4.99 { pager_close $::p1 } {} file delete -force ptf1.db } ;# end if( not mem: and has pager_open command ); finish_test |