From 7bf9ec1c26d1d09f6b65ce1d8f11d967f6f81227 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 22 Nov 2014 09:09:50 +0000 Subject: [PATCH] Add SQLITE_ENABLE_OTA pre-processor directives so that this branch may be compiled with or without OTA. FossilOrigin-Name: 600cefdd4d29c1de4d107fa7ddeb76a18edce4f5 --- ext/ota/sqlite3ota.c | 10 +++- manifest | 34 ++++++------ manifest.uuid | 2 +- src/main.c | 2 + src/pager.c | 40 +++++++++++--- src/pragma.c | 8 ++- src/sqlite.h.in | 122 +++++++++++++++++++++++-------------------- src/sqliteInt.h | 7 ++- src/test_config.c | 6 +++ src/trigger.c | 2 +- src/vdbeblob.c | 11 +++- src/wal.c | 107 +++++++++++++++++++++++++++---------- test/ota.test | 4 +- tool/mkpragmatab.tcl | 2 + 14 files changed, 239 insertions(+), 118 deletions(-) diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index 8613c179f6..6c3c99434e 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -17,6 +17,8 @@ #include #include "sqlite3.h" + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_OTA) #include "sqlite3ota.h" @@ -1662,12 +1664,18 @@ static int test_sqlite3ota( return TCL_OK; } + int SqliteOta_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlite3ota", test_sqlite3ota, 0, 0); return TCL_OK; } - #endif /* ifdef SQLITE_TEST */ +#else /* !SQLITE_CORE || SQLITE_ENABLE_OTA */ +# ifdef SQLITE_TEST +#include +int SqliteOta_Init(Tcl_Interp *interp){ return TCL_OK; } +# endif +#endif diff --git a/manifest b/manifest index bb2073b96b..5d142cd5c1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\slatest\strunk\schanges\swith\sthis\sbranch. -D 2014-11-21T14:37:24.898 +C Add\sSQLITE_ENABLE_OTA\spre-processor\sdirectives\sso\sthat\sthis\sbranch\smay\sbe\scompiled\swith\sor\swithout\sOTA. +D 2014-11-22T09:09:50.320 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -135,7 +135,7 @@ F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda F ext/ota/ota9.test d9ad30ccb4e08f878e382876fe67752309538af9 F ext/ota/otafault.test be02466863015a583cc0ceb6aca871a5e6f7a71b -F ext/ota/sqlite3ota.c 07ef7b72358ed422b69a10e4702ab131041e2896 +F ext/ota/sqlite3ota.c accfada2ab182dc52225e7345f656520a4e8db22 F ext/ota/sqlite3ota.h 04577b00c456aacb99be9c8b55572a6e3ca9aa27 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b @@ -209,7 +209,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 -F src/main.c e2adfa1e7bef8b553a1e7c250cc02bcb109d15f2 +F src/main.c cd819123ed552a15c37bd2fd5360db25015dc461 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@ -230,13 +230,13 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7 F src/os_win.c a9e500dd963fb1f67d7860e58b5772abe6123862 F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 -F src/pager.c c2a4795e65b5794248dadd7c8bb65a8d9145995e +F src/pager.c 9fe27a768be53dbe0a818ae10791dc36100a0e76 F src/pager.h c6157af66a9999797629968921133f67716f8f9f F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98 -F src/pragma.c 272b122a873fc756e999c319f8e81de55ef39d5c +F src/pragma.c 8e0087a5ae6e60ac9ed48df19025cb423e3c8c34 F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7 F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 @@ -244,10 +244,10 @@ F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd -F src/sqlite.h.in 972125a6b4ea1891d2428cc55302c71f0fb1adb3 +F src/sqlite.h.in f60a24616a6a7e622266e723ed141f0c6131514e F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h d96b5f3ee07d35b52aa54a279028105b33a9592c +F src/sqliteInt.h 32d7becef5cbd9a1118608921ec99f00f96c6e5d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc @@ -266,7 +266,7 @@ F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e F src/test_blob.c 1f2e3e25255b731c4fcf15ee7990d06347cb6c09 F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f -F src/test_config.c 035c17a173937d019b8dfc1d524f9d3fc8123504 +F src/test_config.c 7d50e35f5e94235863c9bac448f63b0d141119e5 F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f @@ -300,7 +300,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6de09362b657f19ba83e5fa521ee715787ce9fee F src/tokenize.c cc9016e5007fc5e76789079616d2f26741bcc689 -F src/trigger.c eb921d1292aca83d515bde5881df71df91d962d6 +F src/trigger.c 6dcdf46a21acf4d4e011c809b2c971e63f797a1a F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 @@ -310,12 +310,12 @@ F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 F src/vdbeaux.c 5ce4f414147a3bc3cbcf00ec57f2606c25791629 -F src/vdbeblob.c 845c24601a4f107f4829725fa0c672b93b816bab +F src/vdbeblob.c 317c71482ed73b0966db2d1c4e20839be3e9fe79 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 -F src/wal.c e8fe2d73c40066872f97db5809ea62f285175825 +F src/wal.c d5c581b635951cf5513ec9699d118b32323443f3 F src/wal.h 0d3ba0c3f1b4c25796cb213568a84b9f9063f465 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/where.c e275cb74731a3351a9da6ba8280bd5054db6192d @@ -777,7 +777,7 @@ F test/orderby5.test 8f08a54836d21fb7c70245360751aedd1c2286fb F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859 F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 -F test/ota.test d81a211dfbdf9fe02b5ad50c86f8a5df924391f5 +F test/ota.test 3a8d97cbf8f7210dc6a638797c4e4cd674036927 F test/ovfl.test 4f7ca651cba5c059a12d8c67dddd49bec5747799 F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71 @@ -1200,7 +1200,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh 5dc5010e2e748a9e1bba67baca5956a2c2deda7b F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl 22c85e67987ad7d2e8789c48506ec95b99a90c08 +F tool/mkpragmatab.tcl 7c9f48bfe61ba0e4018868bf34b2450026c24ae1 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 88a1e3b0c769773fb7a9ebb363ffc603a4ac21d8 F tool/mksqlite3c.tcl e72c0c97fe1a105fa9616483e652949be2199fe6 @@ -1236,7 +1236,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 14139542b68fbf01632a1b149cd6fca4bb01efa6 b1e6c02f8b9a2afaa12ac15a33e3f698c3be27d6 -R 0115f003ae5ca012270e27f3f42f3f8e +P 7ef44c5b5bd30bcc4ef59ed172b9ce9ac6a843f6 +R a969a1e9314cd2ef179f3839efd0b8ec U dan -Z 7ed6e391881cc7d739c6ad1cb9d3b777 +Z bba2f4cd69d571c58d439710133b8bb2 diff --git a/manifest.uuid b/manifest.uuid index ab5ea12dd7..3c2a061073 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7ef44c5b5bd30bcc4ef59ed172b9ce9ac6a843f6 \ No newline at end of file +600cefdd4d29c1de4d107fa7ddeb76a18edce4f5 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 2ba085d9ea..12dd56e2a1 100644 --- a/src/main.c +++ b/src/main.c @@ -1960,6 +1960,7 @@ int sqlite3_wal_checkpoint_v2( #endif } +#ifdef SQLITE_ENABLE_OTA /* ** Open an incremental checkpoint handle. */ @@ -1984,6 +1985,7 @@ int sqlite3_ckpt_open( sqlite3_mutex_leave(db->mutex); return rc; } +#endif /* SQLITE_ENABLE_OTA */ /* diff --git a/src/pager.c b/src/pager.c index db511c3f20..3508a9f937 100644 --- a/src/pager.c +++ b/src/pager.c @@ -642,7 +642,9 @@ struct Pager { 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 */ +#ifdef SQLITE_ENABLE_OTA u8 otaMode; /* Non-zero if in ota_mode */ +#endif /************************************************************************** ** The following block contains those class members that change during @@ -716,6 +718,16 @@ struct Pager { #endif }; +/* +** Return the value of the pager otaMode flag (0, 1 or 2). Or, if +** SQLITE_ENABLE_OTA is not defined, return constant value 0. +*/ +#ifdef SQLITE_ENABLE_OTA +# define PagerOtaMode(pPager) ((pPager)->otaMode) +#else +# define PagerOtaMode(pPager) 0 +#endif + /* ** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains ** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS @@ -2029,7 +2041,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } - if( !pPager->exclusiveMode && !pPager->otaMode + if( !pPager->exclusiveMode && !PagerOtaMode(pPager) && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); @@ -3985,7 +3997,7 @@ int sqlite3PagerClose(Pager *pPager){ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, - pPager->ckptSyncFlags, pPager->pageSize, (pPager->otaMode?0:pTmp) + pPager->ckptSyncFlags, pPager->pageSize, (PagerOtaMode(pPager)?0:pTmp) ); pPager->pWal = 0; #endif @@ -5191,7 +5203,7 @@ int sqlite3PagerSharedLock(Pager *pPager){ ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); - if( rc==SQLITE_OK && pPager->otaMode ){ + if( rc==SQLITE_OK && PagerOtaMode(pPager) ){ int nWal = sqlite3Strlen30(pPager->zWal); pPager->zWal[nWal-3] = 'o'; rc = pagerOpenWalInternal(pPager, 0); @@ -5205,13 +5217,15 @@ int sqlite3PagerSharedLock(Pager *pPager){ if( pagerUseWal(pPager) ){ assert( rc==SQLITE_OK ); rc = pagerBeginReadTransaction(pPager); - if( rc==SQLITE_OK && pPager->otaMode==1 ){ + if( rc==SQLITE_OK && PagerOtaMode(pPager)==1 ){ rc = sqlite3WalCheckSalt(pPager->pWal, pPager->fd); if( rc!=SQLITE_OK ){ sqlite3WalClose(pPager->pWal, 0, 0, 0); pPager->pWal = 0; }else{ +#ifdef SQLITE_ENABLE_OTA pPager->otaMode = 2; +#endif } } } @@ -7105,7 +7119,7 @@ void sqlite3PagerClearCache(Pager *pPager){ */ int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; - if( pPager->pWal && pPager->otaMode==0 ){ + if( pPager->pWal && PagerOtaMode(pPager)==0 ){ rc = sqlite3WalCheckpoint(pPager->pWal, eMode, pPager->xBusyHandler, pPager->pBusyHandlerArg, pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, @@ -7172,7 +7186,7 @@ static int pagerOpenWal(Pager *pPager){ */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, - pPager->fd, pPager->zWal, pPager->exclusiveMode || pPager->otaMode, + pPager->fd, pPager->zWal, pPager->exclusiveMode || PagerOtaMode(pPager), pPager->journalSizeLimit, &pPager->pWal ); } @@ -7181,6 +7195,14 @@ static int pagerOpenWal(Pager *pPager){ return rc; } +/* +** Open the WAL file if it is not open. If it is already open, set *pbOpen +** to 1 before returning. Return SQLITE_OK if successful, or an SQLite error +** code otherwise. +** +** The difference between this function and sqlite3PagerOpenWal() is that +** PagerOpenWal() does not open the WAL file if the pager is in OTA mode. +*/ static int pagerOpenWalInternal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ @@ -7230,7 +7252,7 @@ int sqlite3PagerOpenWal( Pager *pPager, /* Pager object */ int *pbOpen /* OUT: Set to true if call is a no-op */ ){ - if( pPager->otaMode ) return SQLITE_CANTOPEN; + if( PagerOtaMode(pPager) ) return SQLITE_CANTOPEN_BKPT; return pagerOpenWalInternal(pPager, pbOpen); } @@ -7287,7 +7309,7 @@ int sqlite3PagerCloseWal(Pager *pPager){ ** of pseudo-random data. */ void sqlite3PagerWalSalt(Pager *pPager, u32 *aSalt){ - if( pPager->otaMode ){ + if( PagerOtaMode(pPager) ){ memcpy(aSalt, pPager->dbFileVers, 8); }else{ sqlite3_randomness(8, aSalt); @@ -7310,6 +7332,7 @@ int sqlite3PagerWalFramesize(Pager *pPager){ } #endif +#ifdef SQLITE_ENABLE_OTA /* ** Set or clear the "OTA mode" flag. */ @@ -7341,5 +7364,6 @@ int sqlite3PagerWalCheckpointStart( ); } } +#endif /* !SQLITE_ENABLE_OTA */ #endif /* SQLITE_OMIT_DISKIO */ diff --git a/src/pragma.c b/src/pragma.c index 5b89237014..140d496abb 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -310,10 +310,12 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif +#if defined(SQLITE_ENABLE_OTA) { /* zName: */ "ota_mode", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlag: */ 0, /* iArg: */ SQLITE_OtaMode }, +#endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) { /* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, @@ -324,10 +326,12 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif +#if defined(SQLITE_ENABLE_OTA) { /* zName: */ "pager_ota_mode", /* ePragTyp: */ PragTyp_PAGER_OTA_MODE, /* ePragFlag: */ 0, /* iArg: */ 0 }, +#endif #if defined(SQLITE_DEBUG) { /* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_PARSER_TRACE, @@ -481,7 +485,7 @@ static const struct sPragmaNames { /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 59 on by default, 72 total. */ +/* Number of pragmas: 57 on by default, 72 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ @@ -896,6 +900,7 @@ void sqlite3Pragma( ** Other clients see a rollback-mode database on which the pager_ota_mode ** client is holding a SHARED lock. */ +#ifdef SQLITE_ENABLE_OTA case PragTyp_PAGER_OTA_MODE: { Btree *pBt = pDb->pBt; assert( pBt!=0 ); @@ -916,6 +921,7 @@ void sqlite3Pragma( } break; } +#endif /* SQLITE_ENABLE_OTA */ #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e5e98d2a8a..2d8d5fd773 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7445,62 +7445,6 @@ int sqlite3_vtab_on_conflict(sqlite3 *); /* #define SQLITE_ABORT 4 // Also an error code */ #define SQLITE_REPLACE 5 -/* -** Allocate a statement handle that may be used to write directly to an -** index b-tree. This allows the user to create a corrupt database. Once -** the statement handle is allocated, it may be used with the same APIs -** as any statement handle created with sqlite3_prepare(). -** -** The statement writes to the index specified by parameter zIndex, which -** must be in the "main" database. If argument bDelete is false, then each -** time the statement is sqlite3_step()ed, an entry is inserted into the -** b-tree index. If it is true, then an entry may be deleted (or may not, if -** the specified key is not found) each time the statement is -** sqlite3_step()ed. -** -** If statement compilation is successful, *ppStmt is set to point to the -** new statement handle and SQLITE_OK is returned. Otherwise, if an error -** occurs, *ppStmt is set to NULL and an error code returned. An error -** message may be left in the database handle in this case. -** -** If statement compilation succeeds, output variable *pnCol is set to the -** total number of columns in the index, including the primary key columns -** at the end. Variable *paiCol is set to point to an array *pnCol entries -** in size. Each entry is the table column index, numbered from zero from left -** to right, of the corresponding index column. For example, if: -** -** CREATE TABLE t1(a, b, c, d); -** CREATE INDEX i1 ON t1(b, c); -** -** then *pnCol is 3 and *paiCol points to an array containing {1, 2, -1}. -** If table t1 had an explicit INTEGER PRIMARY KEY, then the "-1" in the -** *paiCol array would be replaced by its column index. Or if: -** -** CREATE TABLE t2(a, b, c, d, PRIMARY KEY(d, c)) WITHOUT ROWID; -** CREATE INDEX i2 ON t2(a); -** -** then (*pnCol) is 3 and *paiCol points to an array containing {0, 3, 2}. -** -** The lifetime of the array is the same as that of the statement handle - -** it is automatically freed when the statement handle is passed to -** sqlite3_finalize(). -** -** The statement has (*pnCol) SQL variables that values may be bound to. -** They correspond to the values used to create the index key that is -** inserted or deleted when the statement is stepped. -** -** If the index is a UNIQUE index, the usual checking and error codes apply -** to insert operations. -*/ -int sqlite3_index_writer( - sqlite3 *db, - int bDelete, /* Zero for insert, non-zero for delete */ - const char *zIndex, /* Index to write to */ - sqlite3_stmt**, /* OUT: New statement handle */ - const char ***pazColl, /* OUT: Collation sequences for each column */ - int **paiCol, int *pnCol /* OUT: See above */ -); - /* ** CAPI3REF: Prepared Statement Scan Status Opcodes ** KEYWORDS: {scanstatus options} @@ -7594,6 +7538,66 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( */ SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); +/* +** Allocate a statement handle that may be used to write directly to an +** index b-tree. This allows the user to create a corrupt database. Once +** the statement handle is allocated, it may be used with the same APIs +** as any statement handle created with sqlite3_prepare(). +** +** The statement writes to the index specified by parameter zIndex, which +** must be in the "main" database. If argument bDelete is false, then each +** time the statement is sqlite3_step()ed, an entry is inserted into the +** b-tree index. If it is true, then an entry may be deleted (or may not, if +** the specified key is not found) each time the statement is +** sqlite3_step()ed. +** +** If statement compilation is successful, *ppStmt is set to point to the +** new statement handle and SQLITE_OK is returned. Otherwise, if an error +** occurs, *ppStmt is set to NULL and an error code returned. An error +** message may be left in the database handle in this case. +** +** If statement compilation succeeds, output variable *pnCol is set to the +** total number of columns in the index, including the primary key columns +** at the end. Variable *paiCol is set to point to an array *pnCol entries +** in size. Each entry is the table column index, numbered from zero from left +** to right, of the corresponding index column. For example, if: +** +** CREATE TABLE t1(a, b, c, d); +** CREATE INDEX i1 ON t1(b, c); +** +** then *pnCol is 3 and *paiCol points to an array containing {1, 2, -1}. +** If table t1 had an explicit INTEGER PRIMARY KEY, then the "-1" in the +** *paiCol array would be replaced by its column index. Or if: +** +** CREATE TABLE t2(a, b, c, d, PRIMARY KEY(d, c)) WITHOUT ROWID; +** CREATE INDEX i2 ON t2(a); +** +** then (*pnCol) is 3 and *paiCol points to an array containing {0, 3, 2}. +** +** The lifetime of the array is the same as that of the statement handle - +** it is automatically freed when the statement handle is passed to +** sqlite3_finalize(). +** +** The statement has (*pnCol) SQL variables that values may be bound to. +** They correspond to the values used to create the index key that is +** inserted or deleted when the statement is stepped. +** +** If the index is a UNIQUE index, the usual checking and error codes apply +** to insert operations. +** +** This API is only available if SQLITE_ENABLE_OTA is defined at compile +** time. It is intended for use by the OTA extension only. As such, it is +** subject to change or removal at any point. +*/ +int sqlite3_index_writer( + sqlite3 *db, + int bDelete, /* Zero for insert, non-zero for delete */ + const char *zIndex, /* Index to write to */ + sqlite3_stmt**, /* OUT: New statement handle */ + const char ***pazColl, /* OUT: Collation sequence for each column */ + int **paiCol, int *pnCol /* OUT: See above */ +); + /* ** Incremental checkpoint API. ** @@ -7622,9 +7626,13 @@ SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); ** The contents of this buffer may be passed to a later call to ** sqlite3_ckpt_open() to restart the checkpoint. The second output variable ** is set to the size of the buffer in bytes. +** +** These APIs are only available if SQLITE_ENABLE_OTA is defined at compile +** time. They are intended for use by the OTA extension only. As such, they +** are subject to change or removal at any point. */ typedef struct sqlite3_ckpt sqlite3_ckpt; -int sqlite3_ckpt_open(sqlite3*, unsigned char *a, int n, sqlite3_ckpt **ppCkpt); +int sqlite3_ckpt_open(sqlite3*, unsigned char*, int n, sqlite3_ckpt **ppCkpt); int sqlite3_ckpt_step(sqlite3_ckpt*); int sqlite3_ckpt_close(sqlite3_ckpt*, unsigned char **pa, int *pn); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8bc737d199..b89214354e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1196,8 +1196,11 @@ struct sqlite3 { #define SQLITE_QueryOnly 0x02000000 /* Disable database changes */ #define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */ -#define SQLITE_OtaMode 0x08000000 /* True in "ota mode" */ - +#ifdef SQLITE_ENABLE_OTA +# define SQLITE_OtaMode 0x08000000 /* True in "ota mode" */ +#else +# define SQLITE_OtaMode 0x00000000 +#endif /* ** Bits of the sqlite3.dbOptFlags field that are used by the diff --git a/src/test_config.c b/src/test_config.c index 834113b33b..93f6083838 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -430,6 +430,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_ENABLE_OTA + Tcl_SetVar2(interp, "sqlite_options", "ota", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "ota", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_PAGER_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/trigger.c b/src/trigger.c index f837e23b5a..44b9b89fcc 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -50,7 +50,7 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; Trigger *pList = 0; /* List of triggers to return */ - int bOta = !!(pParse->db->flags & SQLITE_OtaMode); + const int bOta = !!(pParse->db->flags & SQLITE_OtaMode); if( pParse->disableTriggers ){ return 0; diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 8565844f21..e033468e96 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -467,6 +467,11 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ return rc; } +#ifdef SQLITE_ENABLE_OTA +/* +** Allocate and populate the output arrays returned by the +** sqlite3_index_writer() function. +*/ static int indexWriterOutputVars( sqlite3 *db, Index *pIdx, @@ -529,7 +534,10 @@ static int indexWriterOutputVars( return SQLITE_OK; } - +/* +** Prepare and return an SQL statement handle that can be used to write +** directly to an index b-tree. +*/ int sqlite3_index_writer( sqlite3 *db, int bDelete, @@ -634,5 +642,6 @@ index_writer_out: sqlite3_mutex_leave(db->mutex); return rc; } +#endif /* SQLITE_ENABLE_OTA */ #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ diff --git a/src/wal.c b/src/wal.c index ba86d84b73..bb8c0f806e 100644 --- a/src/wal.c +++ b/src/wal.c @@ -483,7 +483,14 @@ struct WalIterator { }; /* -** walCheckpoint +** An object of the following type is used to store state information for +** an ongoing checkpoint operation. For normal checkpoints, the instance +** is allocated on the stack by the walCheckpoint() function. For the special +** incremental checkpoints performed by OTA clients, it is allocated in +** heap memory by sqlite3WalCheckpointStart(). +** +** See the implementations of walCheckpointStart(), walCheckpointStep() and +** walCheckpointFinalize() for further details. */ typedef struct WalCkpt WalCkpt; struct WalCkpt { @@ -1642,8 +1649,15 @@ static int walPagesize(Wal *pWal){ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); } +/* +** Initialize the contents of the WalCkpt object indicated by the final +** argument and begin a checkpoint operation. The CKPT lock must already +** be held when this function is called. +** +** Return SQLITE_OK if successful or an error code otherwise. +*/ static int walCheckpointStart( - Wal *pWal, + Wal *pWal, /* Wal connection */ u8 *aBuf, /* Page-sized temporary buffer */ int nBuf, /* Size of aBuf[] in bytes */ int (*xBusy)(void*), /* Function to call when busy (or NULL) */ @@ -1655,7 +1669,6 @@ static int walCheckpointStart( int i; /* Iterator variable */ memset(p, 0, sizeof(WalCkpt)); - if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ return SQLITE_CORRUPT_BKPT; } @@ -1729,6 +1742,12 @@ static int walCheckpointStart( return rc; } +/* +** Attempt to copy the next frame from the wal file to the database file. If +** there are no more frames to copy to the database file return SQLITE_DONE. +** If the frame is successfully copied, return SQLITE_OK. Or, if an error +** occurs, return an SQLite error code. +*/ static int walCheckpointStep(WalCkpt *p){ u32 iDbpage = 0; /* Next database page to write */ u32 iFrame = 0; /* Wal frame containing data for iDbpage */ @@ -1760,6 +1779,16 @@ static int walCheckpointStep(WalCkpt *p){ return rc; } +/* +** The current round of checkpointing work using the object indicated by +** the only argument is now finished. If no error occcurred, this function +** saves the results to shared memory (i.e. updates the WalCkptInfo.nBackfill +** variable), and truncates and syncs the database file as required. +** +** All dynamic resources currently held by the WalCkpt object are released. +** It is the responsibility of the caller to delete the WalCkpt itself if +** required. +*/ static int walCheckpointFinalize(WalCkpt *p){ if( p->pIter ){ int rc = p->rc; @@ -1780,9 +1809,15 @@ static int walCheckpointFinalize(WalCkpt *p){ p->pInfo->nBackfill = p->mxSafeFrame; } p->rc = rc; - }else if( rc==SQLITE_OK && p->sync_flags ){ - /* If work was not completed, but no error has occured. */ - p->rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags); + }else{ +#ifdef SQLITE_ENABLE_OTA + if( rc==SQLITE_OK && p->sync_flags ){ + /* If work was not completed, but no error has occured. */ + p->rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags); + } +#else + assert( rc!=SQLITE_OK ); +#endif } /* Release the reader lock held while backfilling */ @@ -1846,7 +1881,6 @@ static int walCheckpoint( /* Step the checkpoint object until it reports something other than ** SQLITE_OK. */ while( SQLITE_OK==(rc = walCheckpointStep(&sC)) ); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; rc = walCheckpointFinalize(&sC); /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal @@ -1893,8 +1927,8 @@ static void walLimitSize(Wal *pWal, i64 nMax){ /* ** Close a connection to a log file. ** -** If parameter zBuf is not NULL, attempt to obtain an exclusive lock -** and run a checkpoint. +** If parameter zBuf is not NULL, also attempt to obtain an exclusive +** lock and run a checkpoint. */ int sqlite3WalClose( Wal *pWal, /* Wal to close */ @@ -1914,7 +1948,10 @@ int sqlite3WalClose( ** ** The EXCLUSIVE lock is not released before returning. */ - if( zBuf ){ +#ifdef SQLITE_ENABLE_OTA + if( zBuf ) /* In non-OTA builds, zBuf is always non-NULL */ +#endif + { rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE); if( rc==SQLITE_OK ){ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ @@ -3071,6 +3108,11 @@ int sqlite3WalCheckpoint( return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc); } +#ifdef SQLITE_ENABLE_OTA + +/* +** Step the checkpoint object passed as the first argument. +*/ int sqlite3_ckpt_step(sqlite3_ckpt *pCkpt){ int rc; WalCkpt *p = (WalCkpt*)pCkpt; @@ -3080,6 +3122,14 @@ int sqlite3_ckpt_step(sqlite3_ckpt *pCkpt){ return rc; } +/* +** Close the checkpoint object passed as the first argument. If the checkpoint +** was completed, zero the two output variables. Otherwise, set *paState to +** point to a buffer containing data that may be passed to a subsequent +** call to ckpt_open() to resume the checkpoint. In this case *pnState is +** set to the size of the buffer in bytes. The buffer should be eventually +** freed by the caller using sqlite3_free(). +*/ int sqlite3_ckpt_close(sqlite3_ckpt *pCkpt, u8 **paState, int *pnState){ int rc; WalCkpt *p = (WalCkpt*)pCkpt; @@ -3192,6 +3242,25 @@ int sqlite3WalCheckpointStart( return rc; } +/* +** Unless the wal file is empty, check that the 8 bytes of salt stored in +** the wal header are identical to those in the buffer indicated by the +** second argument. If they are not, return SQLITE_BUSY_SNAPSHOT. Otherwise, +** if the buffers match or the WAL file is empty, return SQLITE_OK. +*/ +int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file *pFd){ + int rc = SQLITE_OK; + if( pWal->hdr.mxFrame>0 ){ + u8 aData[16]; + rc = sqlite3OsRead(pFd, aData, sizeof(aData), 24); + if( rc==SQLITE_OK && memcmp(pWal->hdr.aSalt, aData, 8) ){ + rc = SQLITE_BUSY_SNAPSHOT; + } + } + return rc; +} +#endif /* SQLITE_ENABLE_OTA */ + /* Return the value to pass to a sqlite3_wal_hook callback, the ** number of frames in the WAL at the point of the last commit since ** sqlite3WalCallback() was called. If no commits have occurred since @@ -3276,24 +3345,6 @@ int sqlite3WalHeapMemory(Wal *pWal){ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); } -/* -** Unless the wal file is empty, check that the 8 bytes of salt stored in -** the wal header are identical to those in the buffer indicated by the -** second argument. If they are not, return SQLITE_BUSY_SNAPSHOT. Otherwise, -** if the buffers match or the WAL file is empty, return SQLITE_OK. -*/ -int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file *pFd){ - int rc = SQLITE_OK; - if( pWal->hdr.mxFrame>0 ){ - u8 aData[16]; - rc = sqlite3OsRead(pFd, aData, sizeof(aData), 24); - if( rc==SQLITE_OK && memcmp(pWal->hdr.aSalt, aData, 8) ){ - rc = SQLITE_BUSY_SNAPSHOT; - } - } - return rc; -} - #ifdef SQLITE_ENABLE_ZIPVFS /* ** If the argument is not NULL, it points to a Wal object that holds a diff --git a/test/ota.test b/test/ota.test index 676666d91f..9dc01c2b3a 100644 --- a/test/ota.test +++ b/test/ota.test @@ -11,6 +11,8 @@ set testdir [file dirname $argv0] source $testdir/permutations.test -run_test_suite ota +ifcapable !ota { finish_test ; return } +run_test_suite ota finish_test + diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 613b565553..3c36a6c011 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -298,10 +298,12 @@ set pragma_def { NAME: threads NAME: pager_ota_mode + IF: defined(SQLITE_ENABLE_OTA) NAME: ota_mode TYPE: FLAG ARG: SQLITE_OtaMode + IF: defined(SQLITE_ENABLE_OTA) } fconfigure stdout -translation lf set name {} -- 2.47.2