Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some specialized custom VFS implementations to intercept and implement the expected pager-related effects of this pragma. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | ota-update |
Files: | files | file ages | folders |
SHA1: |
209f672e588b54dfbfb83c7859cacdc4 |
User & Date: | dan 2014-09-03 19:30:32.283 |
Context
2014-09-04
| ||
11:03 | Avoid calling sqlite3OsFetch() on a file-handle for which the xFetch method is NULL. (check-in: 071f7f2dec user: dan tags: ota-update) | |
2014-09-03
| ||
19:30 | Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some specialized custom VFS implementations to intercept and implement the expected pager-related effects of this pragma. (check-in: 209f672e58 user: dan tags: ota-update) | |
08:25 | Add a command line program that uses the extension. This serves as example code and is also useful for performance testing. (check-in: ffa1524ef2 user: dan tags: ota-update) | |
Changes
Changes to ext/ota/ota2.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 | #*********************************************************************** # set testdir [file join [file dirname $argv0] .. .. test] source $testdir/tester.tcl set ::testprefix ota2 do_execsql_test 1.0 { | > < < < | | > | > > | | > | | | | | | > > > > > > > | | | | | < | | < | < | < | | < | > > | > | > > > | > | 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 | #*********************************************************************** # set testdir [file join [file dirname $argv0] .. .. test] source $testdir/tester.tcl set ::testprefix ota2 forcedelete test.db-oal do_execsql_test 1.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } {} do_test 1.1 { glob test.db* } {test.db} do_execsql_test 1.2 { PRAGMA pager_ota_mode = 1; INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); SELECT * FROM t1; } {1 2 3 4 5 6} do_test 1.3 { glob test.db* } {test.db test.db-oal} do_test 1.4 { sqlite3 db2 test.db db2 eval { SELECT * FROM t1 } } {1 2} do_test 1.5 { catchsql { INSERT INTO t1 VALUES(7, 8) } db2 } {1 {database is locked}} db2 close db close sqlite3 db test.db do_execsql_test 1.6 { PRAGMA pager_ota_mode = 1; SELECT * FROM t1; } {1 2 3 4 5 6} do_execsql_test 1.7 { INSERT INTO t1 VALUES(7,8); SELECT * FROM t1; } {1 2 3 4 5 6 7 8} db close sqlite3 db2 test.db do_test 1.8 { execsql { BEGIN; SELECT * FROM t1 } db2 } {1 2} do_test 1.9 { file rename test.db-oal test.db-wal execsql { SELECT * FROM t1 } db2 } {1 2} do_test 1.10 { execsql { COMMIT; SELECT * FROM t1 } db2 } {1 2 3 4 5 6 7 8} finish_test |
Changes to ext/ota/sqlite3ota.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** May you share freely, never taking more than you give. ** ************************************************************************* */ #include <assert.h> #include <string.h> #include "sqlite3.h" #include "sqlite3ota.h" /* ** The ota_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table contains at most a ** single row: ** | > > < < | > | 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 | ** May you share freely, never taking more than you give. ** ************************************************************************* */ #include <assert.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include "sqlite3.h" #include "sqlite3ota.h" /* ** The ota_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table contains at most a ** single row: ** ** "tbl" -> Table currently being written (target database names). ** ** "idx" -> Index currently being written (target database names). ** Or, if the main table is being written, a NULL value. ** ** "row" -> Last rowid processed from ota database table (i.e. data_%). ** ** "progress" -> total number of key/value b-tree operations performed ** so far as part of this ota update. */ #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota_state" \ "(tbl, idx, row, progress)" typedef struct OtaTblIter OtaTblIter; typedef struct OtaIdxIter OtaIdxIter; typedef struct OtaState OtaState; /* ** Iterator used to iterate through all data tables in the OTA. As follows: ** ** OtaTblIter iter; ** for(rc=tblIterFirst(db, &iter); ** rc==SQLITE_OK && iter.zTarget; |
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | int nCol; /* Number of columns in index */ int *aiCol; /* Array of column indexes */ sqlite3_stmt *pWriter; /* Index writer */ sqlite3_stmt *pSelect; /* Select to read values in index order */ }; struct sqlite3ota { sqlite3 *dbDest; /* Target db */ sqlite3 *dbOta; /* Ota db */ int rc; /* Value returned by last ota_step() call */ char *zErrmsg; /* Error message if rc!=SQLITE_OK */ OtaTblIter tbliter; /* Used to iterate through tables */ OtaIdxIter idxiter; /* Used to iterate through indexes */ }; | > > > > > > > | 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 | int nCol; /* Number of columns in index */ int *aiCol; /* Array of column indexes */ sqlite3_stmt *pWriter; /* Index writer */ sqlite3_stmt *pSelect; /* Select to read values in index order */ }; struct OtaState { char *zTbl; char *zIdx; sqlite3_int64 iRow; }; struct sqlite3ota { sqlite3 *dbDest; /* Target db */ sqlite3 *dbOta; /* Ota db */ char *zTarget; /* Path to target db */ int rc; /* Value returned by last ota_step() call */ char *zErrmsg; /* Error message if rc!=SQLITE_OK */ OtaTblIter tbliter; /* Used to iterate through tables */ OtaIdxIter idxiter; /* Used to iterate through indexes */ }; |
︙ | ︙ | |||
502 503 504 505 506 507 508 | const char *zErr = sqlite3_errmsg(*pDb); p->zErrmsg = sqlite3_mprintf("sqlite3_open(): %s", zErr); } } } static void otaSaveTransactionState(sqlite3ota *p){ | | < < < < | < < < < < < < < < < < | | > > | > | | | < < | | | < < | | | < < > > > > > > > > > | > > | < < | | < < < | < < < < | > > > > > > > | > > > > > > | > > > > > > > > > > > > > > | > > | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | > | > > > > > > > > | > > > | | | | < > > > > > > > > > > > > > > | > > > > > > > > > > > | > > < | > > | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 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 | const char *zErr = sqlite3_errmsg(*pDb); p->zErrmsg = sqlite3_mprintf("sqlite3_open(): %s", zErr); } } } static void otaSaveTransactionState(sqlite3ota *p){ sqlite3_stmt *pSelect; char *zInsert; pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect); zInsert = sqlite3_mprintf( "INSERT OR REPLACE INTO ota_state(rowid, tbl, idx, row, progress)" "VALUES(1, %Q, %Q, %lld, NULL)", p->tbliter.zTarget, p->idxiter.zIndex, sqlite3_column_int64(pSelect, 0) ); if( zInsert==0 ){ p->rc = SQLITE_NOMEM; }else{ p->rc = sqlite3_exec(p->dbOta, zInsert, 0, 0, &p->zErrmsg); if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, &p->zErrmsg); } } sqlite3_free(zInsert); } /* ** Allocate an OtaState object and load the contents of the ota_state ** table into it. Return a pointer to the new object. It is the ** responsibility of the caller to eventually free the object using ** sqlite3_free(). ** ** If an error occurs, leave an error code and message in the ota handle ** and return NULL. */ static OtaState *otaLoadState(sqlite3ota *p){ const char *zSelect = "SELECT tbl, idx, row, progress FROM ota_state"; OtaState *pRet = 0; sqlite3_stmt *pStmt; int rc; assert( p->rc==SQLITE_OK ); rc = prepareAndCollectError(p->dbOta, zSelect, &pStmt, &p->zErrmsg); if( rc==SQLITE_OK ){ if( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zIdx = (const char*)sqlite3_column_text(pStmt, 1); const char *zTbl = (const char*)sqlite3_column_text(pStmt, 0); int nIdx = zIdx ? (strlen(zIdx) + 1) : 0; int nTbl = strlen(zTbl) + 1; int nByte = sizeof(OtaState) + nTbl + nIdx; pRet = (OtaState*)sqlite3_malloc(nByte); if( pRet ){ pRet->zTbl = (char*)&pRet[1]; memcpy(pRet->zTbl, sqlite3_column_text(pStmt, 0), nTbl); if( zIdx ){ pRet->zIdx = &pRet->zTbl[nTbl]; memcpy(pRet->zIdx, zIdx, nIdx); }else{ pRet->zIdx = 0; } pRet->iRow = sqlite3_column_int64(pStmt, 2); } }else{ pRet = (OtaState*)sqlite3_malloc(sizeof(OtaState)); if( pRet ){ memset(pRet, 0, sizeof(*pRet)); } } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK && pRet==0 ) rc = SQLITE_NOMEM; if( rc!=SQLITE_OK ){ sqlite3_free(pRet); pRet = 0; } } p->rc = rc; return pRet; } static void otaLoadTransactionState(sqlite3ota *p, OtaState *pState){ assert( p->rc==SQLITE_OK ); if( pState->zTbl ){ int rc; while( rc==SQLITE_OK && p->tbliter.zTarget && sqlite3_stricmp(p->tbliter.zTarget, pState->zTbl) ){ rc = tblIterNext(&p->tbliter); } if( rc==SQLITE_OK && !p->tbliter.zTarget ){ rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); } if( rc==SQLITE_OK && pState->zIdx ){ rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter); while( rc==SQLITE_OK && p->idxiter.zIndex && sqlite3_stricmp(p->idxiter.zIndex, pState->zIdx) ){ rc = idxIterNext(&p->idxiter); } if( rc==SQLITE_OK && !p->idxiter.zIndex ){ rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); } } if( rc==SQLITE_OK ){ rc = otaPrepareAll(p); } if( rc==SQLITE_OK ){ sqlite3_stmt *pSelect; pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect); while( sqlite3_column_int64(pSelect, 0)!=pState->iRow ){ rc = sqlite3_step(pSelect); if( rc!=SQLITE_ROW ) break; } if( rc==SQLITE_ROW ){ rc = SQLITE_OK; }else{ rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("ota_state mismatch error"); } } p->rc = rc; } } /* ** Move the "*-oal" file corresponding to the target database to the ** "*-wal" location. If an error occurs, leave an error code and error ** message in the ota handle. */ static void otaMoveOalFile(sqlite3ota *p){ char *zWal = sqlite3_mprintf("%s-wal", p->zTarget); char *zOal = sqlite3_mprintf("%s-oal", p->zTarget); assert( p->rc==SQLITE_DONE && p->zErrmsg==0 ); if( zWal==0 || zOal==0 ){ p->rc = SQLITE_NOMEM; }else{ rename(zOal, zWal); } sqlite3_free(zWal); sqlite3_free(zOal); } /* ** If there is a "*-oal" file in the file-system corresponding to the ** target database in the file-system, delete it. If an error occurs, ** leave an error code and error message in the ota handle. */ static void otaDeleteOalFile(sqlite3ota *p){ char *zOal = sqlite3_mprintf("%s-oal", p->zTarget); assert( p->rc==SQLITE_OK && p->zErrmsg==0 ); unlink(zOal); sqlite3_free(zOal); } /* ** Open and return a new OTA handle. */ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){ sqlite3ota *p; int nTarget = strlen(zTarget); p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1); if( p ){ OtaState *pState = 0; /* Open the target database */ memset(p, 0, sizeof(sqlite3ota)); p->zTarget = (char*)&p[1]; memcpy(p->zTarget, zTarget, nTarget+1); otaOpenDatabase(p, &p->dbDest, zTarget); otaOpenDatabase(p, &p->dbOta, zOta); /* If it has not already been created, create the ota_state table */ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbOta, OTA_CREATE_STATE, 0, 0, &p->zErrmsg); } if( p->rc==SQLITE_OK ){ pState = otaLoadState(p); if( pState && pState->zTbl==0 ){ otaDeleteOalFile(p); } } if( p->rc==SQLITE_OK ){ const char *zScript = "PRAGMA journal_mode=off;" "PRAGMA pager_ota_mode=1;" "PRAGMA ota_mode=1;" "BEGIN IMMEDIATE;" ; p->rc = sqlite3_exec(p->dbDest, zScript, 0, 0, &p->zErrmsg); } if( p->rc==SQLITE_OK ){ const char *zScript = "BEGIN IMMEDIATE"; p->rc = sqlite3_exec(p->dbOta, zScript, 0, 0, &p->zErrmsg); } /* Point the table iterator at the first table */ if( p->rc==SQLITE_OK ){ p->rc = tblIterFirst(p->dbOta, &p->tbliter); } if( p->rc==SQLITE_OK ){ otaLoadTransactionState(p, pState); } sqlite3_free(pState); } return p; } static void otaCloseHandle(sqlite3 *db){ int rc = sqlite3_close(db); |
︙ | ︙ | |||
686 687 688 689 690 691 692 | otaSaveTransactionState(p); } /* Close all open statement handles. */ tblIterFinalize(&p->tbliter); idxIterFinalize(&p->idxiter); | | < | > > > > > > < < | 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 | otaSaveTransactionState(p); } /* Close all open statement handles. */ tblIterFinalize(&p->tbliter); idxIterFinalize(&p->idxiter); /* Commit the transaction to the *-oal file. */ if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){ rc = sqlite3_exec(p->dbDest, "COMMIT", 0, 0, &p->zErrmsg); if( rc!=SQLITE_OK ) p->rc = rc; } otaCloseHandle(p->dbDest); otaCloseHandle(p->dbOta); if( p->rc==SQLITE_DONE ){ otaMoveOalFile(p); } rc = p->rc; *pzErrmsg = p->zErrmsg; sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } return rc; } |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
2042 2043 2044 2045 2046 2047 2048 | } #endif *ppBtree = p; btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ | | | 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 | } #endif *ppBtree = p; btree_open_out: if( rc!=SQLITE_OK ){ if( pBt && pBt->pPager ){ sqlite3PagerClose(pBt->pPager); } sqlite3_free(pBt); sqlite3_free(p); *ppBtree = 0; }else{ /* If the B-Tree was successfully opened, set the pager-cache size to the ** default value. Except, when opening on an existing shared pager-cache, |
︙ | ︙ | |||
2171 2172 2173 2174 2175 2176 2177 | if( !p->sharable || removeFromSharingList(pBt) ){ /* The pBt is no longer on the sharing list, so we can access ** it without having to hold the mutex. ** ** Clean out and delete the BtShared object. */ assert( !pBt->pCursor ); | | | 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 | if( !p->sharable || removeFromSharingList(pBt) ){ /* The pBt is no longer on the sharing list, so we can access ** it without having to hold the mutex. ** ** Clean out and delete the BtShared object. */ assert( !pBt->pCursor ); sqlite3PagerClose(pBt->pPager); if( pBt->xFreeSchema && pBt->pSchema ){ pBt->xFreeSchema(pBt->pSchema); } sqlite3DbFree(0, pBt->pSchema); freeTempSpace(pBt); sqlite3_free(pBt); } |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
626 627 628 629 630 631 632 633 634 635 636 637 638 639 | u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ /************************************************************************** ** The following block contains those class members that change during ** routine opertion. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe | > | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ u8 otaMode; /* True if in ota_mode */ /************************************************************************** ** The following block contains those class members that change during ** routine opertion. Class members not in this block are either fixed ** when the pager is first created or else only change when there is a ** significant mode change (such as changing the page_size, locking_mode, ** or the journal_mode). From another view, these class members describe |
︙ | ︙ | |||
819 820 821 822 823 824 825 826 827 828 829 830 831 832 | #else # define pagerUseWal(x) 0 # define pagerRollbackWal(x) 0 # define pagerWalFrames(v,w,x,y) 0 # define pagerOpenWalIfPresent(z) SQLITE_OK # define pagerBeginReadTransaction(z) SQLITE_OK #endif #ifndef NDEBUG /* ** Usage: ** ** assert( assert_pager_state(pPager) ); ** | > > | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 | #else # define pagerUseWal(x) 0 # define pagerRollbackWal(x) 0 # define pagerWalFrames(v,w,x,y) 0 # define pagerOpenWalIfPresent(z) SQLITE_OK # define pagerBeginReadTransaction(z) SQLITE_OK #endif static int pagerOpenWalInternal(Pager*, int*); #ifndef NDEBUG /* ** Usage: ** ** assert( assert_pager_state(pPager) ); ** |
︙ | ︙ | |||
2002 2003 2004 2005 2006 2007 2008 | } if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } | | | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | } if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } if( !pPager->exclusiveMode && !pPager->otaMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); pPager->changeCountDone = 0; } pPager->eState = PAGER_READER; pPager->setMaster = 0; |
︙ | ︙ | |||
3943 3944 3945 3946 3947 3948 3949 | ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ | | | | | 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 | ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); pagerFreeMapHdrs(pPager); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, (pPager->otaMode?0:pTmp) ); pPager->pWal = 0; #endif pager_reset(pPager); if( MEMDB ){ pager_unlock(pPager); }else{ |
︙ | ︙ | |||
5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 | } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); #ifndef SQLITE_OMIT_WAL assert( pPager->pWal==0 || rc==SQLITE_OK ); #endif } if( pagerUseWal(pPager) ){ assert( rc==SQLITE_OK ); | > > > > > > | 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 | } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); if( rc==SQLITE_OK && pPager->otaMode ){ int nWal = sqlite3Strlen30(pPager->zWal); pPager->zWal[nWal-3] = 'o'; rc = pagerOpenWalInternal(pPager, 0); } #ifndef SQLITE_OMIT_WAL assert( pPager->pWal==0 || rc==SQLITE_OK ); #endif } if( pagerUseWal(pPager) ){ assert( rc==SQLITE_OK ); |
︙ | ︙ | |||
7114 7115 7116 7117 7118 7119 7120 | } /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, | | < < < < < < < < < < < < < < < < | | 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 | } /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode || pPager->otaMode, pPager->journalSizeLimit, &pPager->pWal ); } pagerFixMaplimit(pPager); return rc; } static int pagerOpenWalInternal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ ){ int rc = SQLITE_OK; /* Return code */ assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_OPEN || pbOpen ); |
︙ | ︙ | |||
7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 | } }else{ *pbOpen = 1; } return rc; } /* ** This function is called to close the connection to the log file prior ** to switching from WAL to rollback mode. ** ** Before closing the log file, this function attempts to take an ** EXCLUSIVE lock on the database file. If this cannot be obtained, an | > > > > > > > > > > > > > > > > > > > > > > > | 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 | } }else{ *pbOpen = 1; } return rc; } /* ** The caller must be holding a SHARED lock on the database file to call ** this function. ** ** If the pager passed as the first argument is open on a real database ** file (not a temp file or an in-memory database), and the WAL file ** is not already open, make an attempt to open it now. If successful, ** return SQLITE_OK. If an error occurs or the VFS used by the pager does ** not support the xShmXXX() methods, return an error code. *pbOpen is ** not modified in either case. ** ** If the pager is open on a temp-file (or in-memory database), or if ** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK ** without doing anything. */ int sqlite3PagerOpenWal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ ){ if( pPager->otaMode ) return SQLITE_CANTOPEN; return pagerOpenWalInternal(pPager, pbOpen); } /* ** This function is called to close the connection to the log file prior ** to switching from WAL to rollback mode. ** ** Before closing the log file, this function attempts to take an ** EXCLUSIVE lock on the database file. If this cannot be obtained, an |
︙ | ︙ | |||
7265 7266 7267 7268 7269 7270 7271 7272 7273 | ** is empty, return 0. */ int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState==PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif #endif /* SQLITE_OMIT_DISKIO */ | > > > > > > > > > > > | 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 | ** is empty, return 0. */ int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState==PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif /* ** Set or clear the "OTA mode" flag. */ int sqlite3PagerSetOtaMode(Pager *pPager, int bOta){ if( pPager->pWal || pPager->eState!=PAGER_OPEN ){ return SQLITE_ERROR; } pPager->otaMode = (u8)bOta; return SQLITE_OK; } #endif /* SQLITE_OMIT_DISKIO */ |
Changes to src/pager.h.
︙ | ︙ | |||
108 109 110 111 112 113 114 | Pager **ppPager, const char*, int, int, int, void(*)(DbPage*) ); | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | Pager **ppPager, const char*, int, int, int, void(*)(DbPage*) ); int sqlite3PagerClose(Pager *pPager); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u32*, int); int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); |
︙ | ︙ | |||
205 206 207 208 209 210 211 212 213 | #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif int sqlite3PagerSaveState(Pager *pPager, void **ppState, int *pnState); int sqlite3PagerRestoreState(Pager *pPager, const void *pState, int nState); #endif /* _PAGER_H_ */ | > > | 205 206 207 208 209 210 211 212 213 214 215 | #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif int sqlite3PagerSaveState(Pager *pPager, void **ppState, int *pnState); int sqlite3PagerRestoreState(Pager *pPager, const void *pState, int nState); int sqlite3PagerSetOtaMode(Pager *pPager, int bOta); #endif /* _PAGER_H_ */ |
Changes to src/pragma.c.
︙ | ︙ | |||
49 50 51 52 53 54 55 | #define PragTyp_JOURNAL_MODE 18 #define PragTyp_JOURNAL_SIZE_LIMIT 19 #define PragTyp_LOCK_PROXY_FILE 20 #define PragTyp_LOCKING_MODE 21 #define PragTyp_PAGE_COUNT 22 #define PragTyp_MMAP_SIZE 23 #define PragTyp_PAGE_SIZE 24 | > | | | | | | | | | | | | | | | | | | 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 | #define PragTyp_JOURNAL_MODE 18 #define PragTyp_JOURNAL_SIZE_LIMIT 19 #define PragTyp_LOCK_PROXY_FILE 20 #define PragTyp_LOCKING_MODE 21 #define PragTyp_PAGE_COUNT 22 #define PragTyp_MMAP_SIZE 23 #define PragTyp_PAGE_SIZE 24 #define PragTyp_PAGER_OTA_MODE 25 #define PragTyp_SECURE_DELETE 26 #define PragTyp_SHRINK_MEMORY 27 #define PragTyp_SOFT_HEAP_LIMIT 28 #define PragTyp_STATS 29 #define PragTyp_SYNCHRONOUS 30 #define PragTyp_TABLE_INFO 31 #define PragTyp_TEMP_STORE 32 #define PragTyp_TEMP_STORE_DIRECTORY 33 #define PragTyp_THREADS 34 #define PragTyp_WAL_AUTOCHECKPOINT 35 #define PragTyp_WAL_CHECKPOINT 36 #define PragTyp_ACTIVATE_EXTENSIONS 37 #define PragTyp_HEXKEY 38 #define PragTyp_KEY 39 #define PragTyp_REKEY 40 #define PragTyp_LOCK_STATUS 41 #define PragTyp_PARSER_TRACE 42 #define PragFlag_NeedSchema 0x01 static const struct sPragmaNames { const char *const zName; /* Name of pragma */ u8 ePragTyp; /* PragTyp_XXX value */ u8 mPragFlag; /* Zero or more PragFlag_XXX values */ u32 iArg; /* Extra argument */ } aPragmaNames[] = { |
︙ | ︙ | |||
319 320 321 322 323 324 325 326 327 328 329 330 331 332 | /* ePragFlag: */ PragFlag_NeedSchema, /* iArg: */ 0 }, { /* zName: */ "page_size", /* ePragTyp: */ PragTyp_PAGE_SIZE, /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif #if defined(SQLITE_DEBUG) { /* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_PARSER_TRACE, /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) | > > > > | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | /* ePragFlag: */ PragFlag_NeedSchema, /* iArg: */ 0 }, { /* zName: */ "page_size", /* ePragTyp: */ PragTyp_PAGE_SIZE, /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif { /* zName: */ "pager_ota_mode", /* ePragTyp: */ PragTyp_PAGER_OTA_MODE, /* ePragFlag: */ 0, /* iArg: */ 0 }, #if defined(SQLITE_DEBUG) { /* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_PARSER_TRACE, /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) |
︙ | ︙ | |||
472 473 474 475 476 477 478 | #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) { /* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlag: */ 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; | | > | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) { /* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlag: */ 0, /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; /* Number of pragmas: 59 on by default, 72 total. */ /* Number of pragmas: 58 on by default, 71 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ /* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or ** unrecognized string argument. The FULL option is disallowed |
︙ | ︙ | |||
865 866 867 868 869 870 871 872 873 874 875 876 877 878 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } break; } #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* ** PRAGMA [database.]page_size ** PRAGMA [database.]page_size=N ** ** The first form reports the current setting for the | > > > > > > > > > > > > > | 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 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } break; } #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */ /* ** PRAGMA [database.]pager_ota_mode=[01] */ case PragTyp_PAGER_OTA_MODE: { Btree *pBt = pDb->pBt; assert( pBt!=0 ); if( zRight ){ int iArg = !!sqlite3Atoi(zRight); rc = sqlite3PagerSetOtaMode(sqlite3BtreePager(pBt), iArg); } break; } #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* ** PRAGMA [database.]page_size ** PRAGMA [database.]page_size=N ** ** The first form reports the current setting for the |
︙ | ︙ |
Changes to src/test2.c.
︙ | ︙ | |||
85 86 87 88 89 90 91 | int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); rc = sqlite3PagerClose(pPager); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } |
︙ | ︙ |
Changes to tool/mkpragmatab.tcl.
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 | NAME: activate_extensions IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) NAME: soft_heap_limit NAME: threads } fconfigure stdout -translation lf set name {} set type {} set if {} set flags {} set arg 0 | > > > > > > | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | NAME: activate_extensions IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) NAME: soft_heap_limit NAME: threads NAME: pager_ota_mode NAME: ota_mode TYPE: FLAG ARG: SQLITE_OtaMode } fconfigure stdout -translation lf set name {} set type {} set if {} set flags {} set arg 0 |
︙ | ︙ |