Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a problem with OTA updates in the presence of database readers. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | ota-update |
Files: | files | file ages | folders |
SHA1: |
144bb29ffcbfe96dc10c0224113e73a8 |
User & Date: | dan 2015-02-18 17:40:05.856 |
Context
2015-02-18
| ||
20:16 | Add ota tests to increase code coverage. Fix some minor issues in error handling within the ota code. (check-in: 2b10c5d2b8 user: dan tags: ota-update) | |
17:40 | Fix a problem with OTA updates in the presence of database readers. (check-in: 144bb29ffc user: dan tags: ota-update) | |
2015-02-17
| ||
20:49 | Improve test coverage of ota code a bit. (check-in: a438fa6c9a user: dan tags: ota-update) | |
Changes
Changes to ext/ota/ota3.test.
︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | proc run_ota {target ota} { sqlite3ota ota $target $ota while { [ota step]=="SQLITE_OK" } {} ota close } forcedelete test.db-oal ota.db #-------------------------------------------------------------------- # Test that for an OTA to be applied, no corruption results if the # affinities on the source and target table do not match. # do_execsql_test 1.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b TEXT, c REAL); | > > > > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | proc run_ota {target ota} { sqlite3ota ota $target $ota while { [ota step]=="SQLITE_OK" } {} ota close } forcedelete test.db-oal ota.db db close sqlite3_shutdown sqlite3_config_uri 1 reset_db #-------------------------------------------------------------------- # Test that for an OTA to be applied, no corruption results if the # affinities on the source and target table do not match. # do_execsql_test 1.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b TEXT, c REAL); |
︙ | ︙ | |||
123 124 125 126 127 128 129 | forcedelete ota.db sqlite3 db2 ota.db db2 eval { CREATE TABLE data_x2(a, b, c, d, ota_control); INSERT INTO data_x2 VALUES(1, 'a', 2, 3, 0); } db2 close | < | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | forcedelete ota.db sqlite3 db2 ota.db db2 eval { CREATE TABLE data_x2(a, b, c, d, ota_control); INSERT INTO data_x2 VALUES(1, 'a', 2, 3, 0); } db2 close list [catch { run_ota test.db ota.db } msg] $msg } {1 SQLITE_ERROR} do_execsql_test 2.5 { PRAGMA integrity_check; } {ok} |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 | do_test 3.2 { sqlite3ota_destroy_vfs nosuchvfs sqlite3ota_destroy_vfs unix sqlite3ota_destroy_vfs win32 } {} finish_test | > > > > > > > > > > > > > > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | do_test 3.2 { sqlite3ota_destroy_vfs nosuchvfs sqlite3ota_destroy_vfs unix sqlite3ota_destroy_vfs win32 } {} #------------------------------------------------------------------------- # Test that it is an error to specify an explicit VFS that does not # include ota VFS functionality. # do_test 4.1 { testvfs tvfs sqlite3ota ota file:test.db?vfs=tvfs ota.db list [catch { ota step } msg] $msg } {0 SQLITE_ERROR} do_test 4.2 { list [catch { ota close } msg] $msg } {1 {SQLITE_ERROR - ota vfs not found}} tvfs delete finish_test |
Changes to ext/ota/ota6.test.
︙ | ︙ | |||
41 42 43 44 45 46 47 | ota close } # Test the outcome of some other client writing the db while the *-oal # file is being generated. Once this has happened, the update cannot be # progressed. # | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | ota close } # Test the outcome of some other client writing the db while the *-oal # file is being generated. Once this has happened, the update cannot be # progressed. # for {set nStep 1} {$nStep < 8} {incr nStep} { do_test 1.$nStep.1 { setup_test sqlite3ota ota test.db ota.db for {set i 0} {$i<$nStep} {incr i} {ota step} ota close sqlite3 db test.db |
︙ | ︙ | |||
64 65 66 67 68 69 70 | list [file exists test.db-oal] [file exists test.db-wal] } {1 0} do_test 1.$nStep.4 { list [catch { ota close } msg] $msg } {1 {SQLITE_BUSY - database modified during ota update}} } | < | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | list [file exists test.db-oal] [file exists test.db-wal] } {1 0} do_test 1.$nStep.4 { list [catch { ota close } msg] $msg } {1 {SQLITE_BUSY - database modified during ota update}} } # Test the outcome of some other client writing the db after the *-oal # file has been copied to the *-wal path. Once this has happened, any # other client writing to the db causes OTA to consider its job finished. # for {set nStep 8} {$nStep < 20} {incr nStep} { do_test 1.$nStep.1 { setup_test sqlite3ota ota test.db ota.db for {set i 0} {$i<$nStep} {incr i} {ota step} ota close sqlite3 db test.db execsql { INSERT INTO t1 VALUES(5, 'hello') } |
︙ | ︙ |
Changes to ext/ota/otafault.test.
︙ | ︙ | |||
33 34 35 36 37 38 39 | INSERT INTO t1 VALUES(2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); CREATE TABLE ota.data_t1(a, b, c, ota_control); INSERT INTO data_t1 VALUES(2, NULL, NULL, 1); INSERT INTO data_t1 VALUES(3, 'three', NULL, '.x.'); INSERT INTO data_t1 VALUES(4, 4, 4, 0); | > > | > > | > | > > > > > > > > > > > > > > > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | INSERT INTO t1 VALUES(2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); CREATE TABLE ota.data_t1(a, b, c, ota_control); INSERT INTO data_t1 VALUES(2, NULL, NULL, 1); INSERT INTO data_t1 VALUES(3, 'three', NULL, '.x.'); INSERT INTO data_t1 VALUES(4, 4, 4, 0); } { SELECT * FROM t1 } {1 1 1 3 three 3 4 4 4} 2 { CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE INDEX t2cb ON t2(c, b); INSERT INTO t2 VALUES('a', 'a', 'a'); INSERT INTO t2 VALUES('b', 'b', 'b'); INSERT INTO t2 VALUES('c', 'c', 'c'); CREATE TABLE ota.data_t2(a, b, c, ota_control); INSERT INTO data_t2 VALUES('b', NULL, NULL, 1); INSERT INTO data_t2 VALUES('c', 'see', NULL, '.x.'); INSERT INTO data_t2 VALUES('d', 'd', 'd', 0); } { SELECT * FROM t2 } {a a a c see c d d d} 3 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE INDEX t1cb ON t1(c, b); CREATE INDEX t2cb ON t2(c, b); CREATE TABLE ota.data_t1(a, b, c, ota_control); CREATE TABLE ota.data_t2(a, b, c, ota_control); INSERT INTO data_t1 VALUES(1, 2, 3, 0); INSERT INTO data_t2 VALUES(4, 5, 6, 0); } { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } {1 2 3 4 5 6} 4 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX t1c ON t1(c); INSERT INTO t1 VALUES('A', 'B', 'C'); INSERT INTO t1 VALUES('D', 'E', 'F'); CREATE TABLE ota.data_t1(a, b, c, ota_control); INSERT INTO data_t1 VALUES('D', NULL, NULL, 1); INSERT INTO data_t1 VALUES('A', 'Z', NULL, '.x.'); INSERT INTO data_t1 VALUES('G', 'H', 'I', 0); } { SELECT * FROM t1 ORDER BY a; } {A Z C G H I} } { catch {db close} forcedelete ota.db test.db sqlite3 db test.db execsql { PRAGMA encoding = utf16; |
︙ | ︙ | |||
133 134 135 136 137 138 139 | catch {db close} sqlite3_shutdown sqlite3_config_lookaside {*}$lookaside_config sqlite3_initialize autoinstall_test_functions | < < > > | > > > > > > > > > > > | > | 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 213 214 215 216 217 218 219 220 | catch {db close} sqlite3_shutdown sqlite3_config_lookaside {*}$lookaside_config sqlite3_initialize autoinstall_test_functions for {set iStep 0} {$iStep<=21} {incr iStep} { forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal copy_if_exists test.db.bak test.db copy_if_exists ota.db.bak ota.db sqlite3ota ota test.db ota.db for {set x 0} {$x < $::iStep} {incr x} { ota step } ota close # sqlite3 x ota.db ; puts "XYZ [x eval { SELECT * FROM ota_state } ]" ; x close copy_if_exists test.db test.db.bak.2 copy_if_exists test.db-wal test.db.bak.2-wal copy_if_exists test.db-oal test.db.bak.2-oal copy_if_exists ota.db ota.db.bak.2 do_faultsim_test 3.$tn.$iStep -faults $::f -prep { catch { db close } forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal copy_if_exists test.db.bak.2 test.db copy_if_exists test.db.bak.2-wal test.db-wal copy_if_exists test.db.bak.2-oal test.db-oal copy_if_exists ota.db.bak.2 ota.db } -body { sqlite3ota ota test.db ota.db ota step ota close } -test { if {$testresult=="SQLITE_OK"} {set testresult "SQLITE_DONE"} faultsim_test_result {*}$::reslist if {$testrc==0} { # No error occurred. If the OTA has not already been fully applied, # apply the rest of it now. Then ensure that the final state of the # target db is as expected. And that "PRAGMA integrity_check" # passes. sqlite3ota ota test.db ota.db while {[ota step] == "SQLITE_OK"} {} ota close sqlite3 db test.db faultsim_integrity_check set res [db eval $::sql] if {$res != [list {*}$::expect]} { puts "" puts "res: $res" puts "exp: $::expect" error "data not as expected!" } } } } } } finish_test |
Changes to ext/ota/sqlite3ota.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | #define OTA_STATE_IDX 3 #define OTA_STATE_ROW 4 #define OTA_STATE_PROGRESS 5 #define OTA_STATE_CKPT 6 #define OTA_STATE_COOKIE 7 #define OTA_STAGE_OAL 1 | > | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | #define OTA_STATE_IDX 3 #define OTA_STATE_ROW 4 #define OTA_STATE_PROGRESS 5 #define OTA_STATE_CKPT 6 #define OTA_STATE_COOKIE 7 #define OTA_STAGE_OAL 1 #define OTA_STAGE_MOVE 2 #define OTA_STAGE_CAPTURE 3 #define OTA_STAGE_CKPT 4 #define OTA_STAGE_DONE 5 #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state" \ "(k INTEGER PRIMARY KEY, v)" typedef struct OtaState OtaState; typedef struct OtaObjIter OtaObjIter; |
︙ | ︙ | |||
945 946 947 948 949 950 951 | p->rc = SQLITE_NOMEM; break; } } /* For a table with implicit rowids, append "old._rowid_" to the list. */ if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){ | | | 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 | p->rc = SQLITE_NOMEM; break; } } /* For a table with implicit rowids, append "old._rowid_" to the list. */ if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){ zList = otaMPrintf(p, "%z, %s._rowid_", zList, zObj); } } return zList; } /* ** Return an expression that can be used in a WHERE clause to match the |
︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 | } z = otaMPrintf(p, "%z)", z); rc = sqlite3_finalize(pXInfo); if( p->rc==SQLITE_OK ) p->rc = rc; } return z; } /* ** This function creates the second imposter table used when writing to ** a table b-tree where the table has an external primary key. If the ** iterator passed as the second argument does not currently point to ** a table (not index) with an external primary key, this function is a ** no-op. | > > > > > | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 | } z = otaMPrintf(p, "%z)", z); rc = sqlite3_finalize(pXInfo); if( p->rc==SQLITE_OK ) p->rc = rc; } return z; } static void otaFinalize(sqlite3ota *p, sqlite3_stmt *pStmt){ int rc = sqlite3_finalize(pStmt); if( p->rc==SQLITE_OK ) p->rc = rc; } /* ** This function creates the second imposter table used when writing to ** a table b-tree where the table has an external primary key. If the ** iterator passed as the second argument does not currently point to ** a table (not index) with an external primary key, this function is a ** no-op. |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 | "SELECT name FROM sqlite_master WHERE rootpage = ?" ); if( p->rc==SQLITE_OK ){ sqlite3_bind_int(pQuery, 1, tnum); if( SQLITE_ROW==sqlite3_step(pQuery) ){ zIdx = (const char*)sqlite3_column_text(pQuery, 0); } | < < < < | < | | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 | "SELECT name FROM sqlite_master WHERE rootpage = ?" ); if( p->rc==SQLITE_OK ){ sqlite3_bind_int(pQuery, 1, tnum); if( SQLITE_ROW==sqlite3_step(pQuery) ){ zIdx = (const char*)sqlite3_column_text(pQuery, 0); } } if( zIdx ){ p->rc = prepareFreeAndCollectError(p->db, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); } otaFinalize(p, pQuery); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int bKey = sqlite3_column_int(pXInfo, 5); if( bKey ){ int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); |
︙ | ︙ | |||
1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 | if( p->rc ) return; iOff = (i64)(pFrame->iDbPage-1) * p->pgsz; p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff); } } /* ** The OTA handle is currently in OTA_STAGE_OAL state, with a SHARED lock ** on the database file. This proc moves the *-oal file to the *-wal path, ** then reopens the database file (this time in vanilla, non-oal, WAL mode). ** If an error occurs, leave an error code and error message in the ota ** handle. */ static void otaMoveOalFile(sqlite3ota *p){ const char *zBase = sqlite3_db_filename(p->db, "main"); char *zWal = sqlite3_mprintf("%s-wal", zBase); char *zOal = sqlite3_mprintf("%s-oal", zBase); | > > > > > > > > > > > > > > | | > > > > > > > | 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | if( p->rc ) return; iOff = (i64)(pFrame->iDbPage-1) * p->pgsz; p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff); } } /* ** Take an EXCLUSIVE lock on the database file. */ static void otaLockDatabase(sqlite3ota *p){ if( p->rc==SQLITE_OK ){ sqlite3_file *pReal = p->pTargetFd->pReal; p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED); if( p->rc==SQLITE_OK ){ p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE); } } } /* ** The OTA handle is currently in OTA_STAGE_OAL state, with a SHARED lock ** on the database file. This proc moves the *-oal file to the *-wal path, ** then reopens the database file (this time in vanilla, non-oal, WAL mode). ** If an error occurs, leave an error code and error message in the ota ** handle. */ static void otaMoveOalFile(sqlite3ota *p){ const char *zBase = sqlite3_db_filename(p->db, "main"); char *zWal = sqlite3_mprintf("%s-wal", zBase); char *zOal = sqlite3_mprintf("%s-oal", zBase); assert( p->eStage==OTA_STAGE_MOVE ); assert( p->rc==SQLITE_OK && p->zErrmsg==0 ); if( zWal==0 || zOal==0 ){ p->rc = SQLITE_NOMEM; }else{ /* Move the *-oal file to *-wal. At this point connection p->db is ** holding a SHARED lock on the target database file (because it is ** in WAL mode). So no other connection may be writing the db. ** ** In order to ensure that there are no database readers, an EXCLUSIVE ** lock is obtained here before the *-oal is moved to *-wal. */ otaLockDatabase(p); if( p->rc==SQLITE_OK ){ otaFileSuffix3(zBase, zWal); otaFileSuffix3(zBase, zOal); rename(zOal, zWal); /* Re-open the databases. */ otaObjIterFinalize(&p->objiter); sqlite3_close(p->db); p->db = 0; otaOpenDatabase(p); otaSetupCheckpoint(p, 0); } } sqlite3_free(zWal); sqlite3_free(zOal); } /* ** The SELECT statement iterating through the keys for the current object |
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 | return p->rc; } /* ** Increment the schema cookie of the main database opened by p->db. */ static void otaIncrSchemaCookie(sqlite3ota *p){ int iCookie = 1000000; sqlite3_stmt *pStmt; | > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 | return p->rc; } /* ** Increment the schema cookie of the main database opened by p->db. */ static void otaIncrSchemaCookie(sqlite3ota *p){ if( p->rc==SQLITE_OK ){ int iCookie = 1000000; sqlite3_stmt *pStmt; p->rc = prepareAndCollectError(p->db, &pStmt, &p->zErrmsg, "PRAGMA schema_version" ); if( p->rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ iCookie = sqlite3_column_int(pStmt, 0); } p->rc = sqlite3_finalize(pStmt); } if( p->rc==SQLITE_OK ){ otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1); } } } static void otaSaveState(sqlite3ota *p, int eStage){ if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){ sqlite3_stmt *pInsert = 0; int rc; assert( p->zErrmsg==0 ); rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, sqlite3_mprintf( "INSERT OR REPLACE INTO ota.ota_state(k, v) VALUES " "(%d, %d), " "(%d, %Q), " "(%d, %Q), " "(%d, %d), " "(%d, %lld), " "(%d, %lld), " "(%d, %lld) ", OTA_STATE_STAGE, eStage, OTA_STATE_TBL, p->objiter.zTbl, OTA_STATE_IDX, p->objiter.zIdx, OTA_STATE_ROW, p->nStep, OTA_STATE_PROGRESS, p->nProgress, OTA_STATE_CKPT, p->iWalCksum, OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie ) ); assert( pInsert==0 || rc==SQLITE_OK ); if( rc==SQLITE_OK ){ sqlite3_step(pInsert); rc = sqlite3_finalize(pInsert); }else{ sqlite3_finalize(pInsert); } if( rc!=SQLITE_OK ){ p->rc = rc; } } } /* ** Step the OTA object. */ int sqlite3ota_step(sqlite3ota *p){ if( p ){ switch( p->eStage ){ |
︙ | ︙ | |||
1955 1956 1957 1958 1959 1960 1961 | } } otaObjIterNext(p, pIter); } if( p->rc==SQLITE_OK && pIter->zTbl==0 ){ | | > > > > > > < > | 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 | } } otaObjIterNext(p, pIter); } if( p->rc==SQLITE_OK && pIter->zTbl==0 ){ otaSaveState(p, OTA_STAGE_MOVE); otaIncrSchemaCookie(p); if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->db, "COMMIT", 0, 0, &p->zErrmsg); } p->eStage = OTA_STAGE_MOVE; } break; } case OTA_STAGE_MOVE: { if( p->rc==SQLITE_OK ){ otaMoveOalFile(p); p->nProgress++; } break; } case OTA_STAGE_CKPT: { if( p->nStep>=p->nFrame ){ sqlite3_file *pDb = p->pTargetFd->pReal; |
︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 | } return p->rc; }else{ return SQLITE_NOMEM; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 | } return p->rc; }else{ return SQLITE_NOMEM; } } static void otaFreeState(OtaState *p){ if( p ){ sqlite3_free(p->zTbl); sqlite3_free(p->zIdx); sqlite3_free(p); } } |
︙ | ︙ | |||
2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 | rc = prepareAndCollectError(p->db, &pStmt, &p->zErrmsg, zSelect); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ switch( sqlite3_column_int(pStmt, 0) ){ case OTA_STATE_STAGE: pRet->eStage = sqlite3_column_int(pStmt, 1); if( pRet->eStage!=OTA_STAGE_OAL && pRet->eStage!=OTA_STAGE_CKPT ){ p->rc = SQLITE_CORRUPT; } break; case OTA_STATE_TBL: | > | 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 | rc = prepareAndCollectError(p->db, &pStmt, &p->zErrmsg, zSelect); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ switch( sqlite3_column_int(pStmt, 0) ){ case OTA_STATE_STAGE: pRet->eStage = sqlite3_column_int(pStmt, 1); if( pRet->eStage!=OTA_STAGE_OAL && pRet->eStage!=OTA_STAGE_MOVE && pRet->eStage!=OTA_STAGE_CKPT ){ p->rc = SQLITE_CORRUPT; } break; case OTA_STATE_TBL: |
︙ | ︙ | |||
2232 2233 2234 2235 2236 2237 2238 | p->eStage = pState->eStage; } p->nProgress = pState->nProgress; } } assert( p->rc!=SQLITE_OK || p->eStage!=0 ); | | | | < | < > > > > > > | 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 | p->eStage = pState->eStage; } p->nProgress = pState->nProgress; } } assert( p->rc!=SQLITE_OK || p->eStage!=0 ); if( p->rc==SQLITE_OK && (p->eStage==OTA_STAGE_OAL || p->eStage==OTA_STAGE_MOVE) ){ /* Check that this is not a wal mode database. If it is, it cannot ** be updated. */ if( p->pTargetFd->pWalFd ){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("cannot update wal mode database"); } /* At this point (pTargetFd->iCookie) contains the value of the ** change-counter cookie (the thing that gets incremented when a ** transaction is committed in rollback mode) currently stored on ** page 1 of the database file. */ else if( pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie ){ p->rc = SQLITE_BUSY; p->zErrmsg = sqlite3_mprintf("database modified during ota update"); } } if( p->rc==SQLITE_OK ){ if( p->eStage==OTA_STAGE_OAL ){ /* Open the transaction */ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); } /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ p->rc = otaObjIterFirst(p, &p->objiter); } if( p->rc==SQLITE_OK ){ otaLoadTransactionState(p, pState); } }else if( p->eStage==OTA_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==OTA_STAGE_CKPT ){ otaSetupCheckpoint(p, pState); p->nStep = pState->nRow; }else if( p->eStage==OTA_STAGE_DONE ){ p->rc = SQLITE_DONE; }else{ p->rc = SQLITE_CORRUPT; |
︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 | int rc; if( p ){ /* If the update has not been fully applied, save the state in ** the ota db. If successful, this call also commits the open ** transaction on the ota db. */ assert( p->rc!=SQLITE_ROW ); | < < | < | 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 | int rc; if( p ){ /* If the update has not been fully applied, save the state in ** the ota db. If successful, this call also commits the open ** transaction on the ota db. */ assert( p->rc!=SQLITE_ROW ); otaSaveState(p, p->eStage); /* Close any open statement handles. */ otaObjIterFinalize(&p->objiter); /* Commit the transaction to the *-oal file. */ if( p->rc==SQLITE_OK && p->eStage==OTA_STAGE_OAL ){ p->rc = sqlite3_exec(p->db, "COMMIT", 0, 0, &p->zErrmsg); |
︙ | ︙ | |||
2623 2624 2625 2626 2627 2628 2629 | int rc = SQLITE_OK; #ifdef SQLITE_AMALGAMATION assert( WAL_CKPT_LOCK==1 ); #endif assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); | | | | > | | 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 | int rc = SQLITE_OK; #ifdef SQLITE_AMALGAMATION assert( WAL_CKPT_LOCK==1 ); #endif assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( pOta && (pOta->eStage==OTA_STAGE_OAL || pOta->eStage==OTA_STAGE_MOVE) ){ /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from ** taking this lock also prevents any checkpoints from occurring. ** todo: really, it's not clear why this might occur, as ** wal_autocheckpoint ought to be turned off. */ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY; }else{ int bCapture = 0; if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE) && pOta && pOta->eStage==OTA_STAGE_CAPTURE && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0) ){ bCapture = 1; } if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){ rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); if( bCapture && rc==SQLITE_OK ){ pOta->mLock |= (1 << ofst); } } } return rc; } static int otaVfsShmMap( sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp ){ ota_file *p = (ota_file*)pFile; int rc = SQLITE_OK; int eStage = (p->pOta ? p->pOta->eStage : 0); /* If not in OTA_STAGE_OAL, allow this call to pass through. Or, if this ** ota is in the OTA_STAGE_OAL state, use heap memory for *-shm space ** instead of a file on disk. */ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_MOVE ){ if( iRegion<=p->nShm ){ int nByte = (iRegion+1) * sizeof(char*); char **apNew = (char**)sqlite3_realloc(p->apShm, nByte); if( apNew==0 ){ rc = SQLITE_NOMEM; }else{ memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); |
︙ | ︙ | |||
2710 2711 2712 2713 2714 2715 2716 2717 2718 | ota_file *p = (ota_file *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){ ota_file *p = (ota_file*)pFile; int rc = SQLITE_OK; assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); | > | | 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 | ota_file *p = (ota_file *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){ ota_file *p = (ota_file*)pFile; int rc = SQLITE_OK; int eStage = (p->pOta ? p->pOta->eStage : 0); assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_MOVE ){ /* no-op */ }else{ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } return rc; } |
︙ | ︙ |