Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/sqlite/src/src/btree.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* | - | ||||||||||||||||||
2 | ** 2004 April 6 | - | ||||||||||||||||||
3 | ** | - | ||||||||||||||||||
4 | ** The author disclaims copyright to this source code. In place of | - | ||||||||||||||||||
5 | ** a legal notice, here is a blessing: | - | ||||||||||||||||||
6 | ** | - | ||||||||||||||||||
7 | ** May you do good and not evil. | - | ||||||||||||||||||
8 | ** May you find forgiveness for yourself and forgive others. | - | ||||||||||||||||||
9 | ** May you share freely, never taking more than you give. | - | ||||||||||||||||||
10 | ** | - | ||||||||||||||||||
11 | ************************************************************************* | - | ||||||||||||||||||
12 | ** This file implements an external (disk-based) database using BTrees. | - | ||||||||||||||||||
13 | ** See the header comment on "btreeInt.h" for additional information. | - | ||||||||||||||||||
14 | ** Including a description of file format and an overview of operation. | - | ||||||||||||||||||
15 | */ | - | ||||||||||||||||||
16 | #include "btreeInt.h" | - | ||||||||||||||||||
17 | - | |||||||||||||||||||
18 | /* | - | ||||||||||||||||||
19 | ** The header string that appears at the beginning of every | - | ||||||||||||||||||
20 | ** SQLite database. | - | ||||||||||||||||||
21 | */ | - | ||||||||||||||||||
22 | static const char zMagicHeader[] = SQLITE_FILE_HEADER; | - | ||||||||||||||||||
23 | - | |||||||||||||||||||
24 | /* | - | ||||||||||||||||||
25 | ** Set this global variable to 1 to enable tracing using the TRACE | - | ||||||||||||||||||
26 | ** macro. | - | ||||||||||||||||||
27 | */ | - | ||||||||||||||||||
28 | #if 0 | - | ||||||||||||||||||
29 | int sqlite3BtreeTrace=1; /* True to enable tracing */ | - | ||||||||||||||||||
30 | # define TRACE(X) if(sqlite3BtreeTrace){printf X;fflush(stdout);} | - | ||||||||||||||||||
31 | #else | - | ||||||||||||||||||
32 | # define TRACE(X) | - | ||||||||||||||||||
33 | #endif | - | ||||||||||||||||||
34 | - | |||||||||||||||||||
35 | /* | - | ||||||||||||||||||
36 | ** Extract a 2-byte big-endian integer from an array of unsigned bytes. | - | ||||||||||||||||||
37 | ** But if the value is zero, make it 65536. | - | ||||||||||||||||||
38 | ** | - | ||||||||||||||||||
39 | ** This routine is used to extract the "offset to cell content area" value | - | ||||||||||||||||||
40 | ** from the header of a btree page. If the page size is 65536 and the page | - | ||||||||||||||||||
41 | ** is empty, the offset should be 65536, but the 2-byte value stores zero. | - | ||||||||||||||||||
42 | ** This routine makes the necessary adjustment to 65536. | - | ||||||||||||||||||
43 | */ | - | ||||||||||||||||||
44 | #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) | - | ||||||||||||||||||
45 | - | |||||||||||||||||||
46 | /* | - | ||||||||||||||||||
47 | ** Values passed as the 5th argument to allocateBtreePage() | - | ||||||||||||||||||
48 | */ | - | ||||||||||||||||||
49 | #define BTALLOC_ANY 0 /* Allocate any page */ | - | ||||||||||||||||||
50 | #define BTALLOC_EXACT 1 /* Allocate exact page if possible */ | - | ||||||||||||||||||
51 | #define BTALLOC_LE 2 /* Allocate any page <= the parameter */ | - | ||||||||||||||||||
52 | - | |||||||||||||||||||
53 | /* | - | ||||||||||||||||||
54 | ** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not | - | ||||||||||||||||||
55 | ** defined, or 0 if it is. For example: | - | ||||||||||||||||||
56 | ** | - | ||||||||||||||||||
57 | ** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum); | - | ||||||||||||||||||
58 | */ | - | ||||||||||||||||||
59 | #ifndef SQLITE_OMIT_AUTOVACUUM | - | ||||||||||||||||||
60 | #define IfNotOmitAV(expr) (expr) | - | ||||||||||||||||||
61 | #else | - | ||||||||||||||||||
62 | #define IfNotOmitAV(expr) 0 | - | ||||||||||||||||||
63 | #endif | - | ||||||||||||||||||
64 | - | |||||||||||||||||||
65 | #ifndef SQLITE_OMIT_SHARED_CACHE | - | ||||||||||||||||||
66 | /* | - | ||||||||||||||||||
67 | ** A list of BtShared objects that are eligible for participation | - | ||||||||||||||||||
68 | ** in shared cache. This variable has file scope during normal builds, | - | ||||||||||||||||||
69 | ** but the test harness needs to access it so we make it global for | - | ||||||||||||||||||
70 | ** test builds. | - | ||||||||||||||||||
71 | ** | - | ||||||||||||||||||
72 | ** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER. | - | ||||||||||||||||||
73 | */ | - | ||||||||||||||||||
74 | #ifdef SQLITE_TEST | - | ||||||||||||||||||
75 | BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; | - | ||||||||||||||||||
76 | #else | - | ||||||||||||||||||
77 | static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; | - | ||||||||||||||||||
78 | #endif | - | ||||||||||||||||||
79 | #endif /* SQLITE_OMIT_SHARED_CACHE */ | - | ||||||||||||||||||
80 | - | |||||||||||||||||||
81 | #ifndef SQLITE_OMIT_SHARED_CACHE | - | ||||||||||||||||||
82 | /* | - | ||||||||||||||||||
83 | ** Enable or disable the shared pager and schema features. | - | ||||||||||||||||||
84 | ** | - | ||||||||||||||||||
85 | ** This routine has no effect on existing database connections. | - | ||||||||||||||||||
86 | ** The shared cache setting effects only future calls to | - | ||||||||||||||||||
87 | ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). | - | ||||||||||||||||||
88 | */ | - | ||||||||||||||||||
89 | int sqlite3_enable_shared_cache(int enable){ | - | ||||||||||||||||||
90 | sqlite3GlobalConfig.sharedCacheEnabled = enable; | - | ||||||||||||||||||
91 | return SQLITE_OK; executed 114 times by 1 test: return 0; Executed by:
| 114 | ||||||||||||||||||
92 | } | - | ||||||||||||||||||
93 | #endif | - | ||||||||||||||||||
94 | - | |||||||||||||||||||
95 | - | |||||||||||||||||||
96 | - | |||||||||||||||||||
97 | #ifdef SQLITE_OMIT_SHARED_CACHE | - | ||||||||||||||||||
98 | /* | - | ||||||||||||||||||
99 | ** The functions querySharedCacheTableLock(), setSharedCacheTableLock(), | - | ||||||||||||||||||
100 | ** and clearAllSharedCacheTableLocks() | - | ||||||||||||||||||
101 | ** manipulate entries in the BtShared.pLock linked list used to store | - | ||||||||||||||||||
102 | ** shared-cache table level locks. If the library is compiled with the | - | ||||||||||||||||||
103 | ** shared-cache feature disabled, then there is only ever one user | - | ||||||||||||||||||
104 | ** of each BtShared structure and so this locking is not necessary. | - | ||||||||||||||||||
105 | ** So define the lock related functions as no-ops. | - | ||||||||||||||||||
106 | */ | - | ||||||||||||||||||
107 | #define querySharedCacheTableLock(a,b,c) SQLITE_OK | - | ||||||||||||||||||
108 | #define setSharedCacheTableLock(a,b,c) SQLITE_OK | - | ||||||||||||||||||
109 | #define clearAllSharedCacheTableLocks(a) | - | ||||||||||||||||||
110 | #define downgradeAllSharedCacheTableLocks(a) | - | ||||||||||||||||||
111 | #define hasSharedCacheTableLock(a,b,c,d) 1 | - | ||||||||||||||||||
112 | #define hasReadConflicts(a, b) 0 | - | ||||||||||||||||||
113 | #endif | - | ||||||||||||||||||
114 | - | |||||||||||||||||||
115 | /* | - | ||||||||||||||||||
116 | ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single | - | ||||||||||||||||||
117 | ** (MemPage*) as an argument. The (MemPage*) must not be NULL. | - | ||||||||||||||||||
118 | ** | - | ||||||||||||||||||
119 | ** If SQLITE_DEBUG is not defined, then this macro is equivalent to | - | ||||||||||||||||||
120 | ** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message | - | ||||||||||||||||||
121 | ** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented | - | ||||||||||||||||||
122 | ** with the page number and filename associated with the (MemPage*). | - | ||||||||||||||||||
123 | */ | - | ||||||||||||||||||
124 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
125 | int corruptPageError(int lineno, MemPage *p){ | - | ||||||||||||||||||
126 | char *zMsg; | - | ||||||||||||||||||
127 | sqlite3BeginBenignMalloc(); | - | ||||||||||||||||||
128 | zMsg = sqlite3_mprintf("database corruption page %d of %s", | - | ||||||||||||||||||
129 | (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) | - | ||||||||||||||||||
130 | ); | - | ||||||||||||||||||
131 | sqlite3EndBenignMalloc(); | - | ||||||||||||||||||
132 | if( zMsg ){ | - | ||||||||||||||||||
133 | sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); | - | ||||||||||||||||||
134 | } | - | ||||||||||||||||||
135 | sqlite3_free(zMsg); | - | ||||||||||||||||||
136 | return SQLITE_CORRUPT_BKPT; | - | ||||||||||||||||||
137 | } | - | ||||||||||||||||||
138 | # define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) | - | ||||||||||||||||||
139 | #else | - | ||||||||||||||||||
140 | # define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) | - | ||||||||||||||||||
141 | #endif | - | ||||||||||||||||||
142 | - | |||||||||||||||||||
143 | #ifndef SQLITE_OMIT_SHARED_CACHE | - | ||||||||||||||||||
144 | - | |||||||||||||||||||
145 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
146 | /* | - | ||||||||||||||||||
147 | **** This function is only used as part of an assert() statement. *** | - | ||||||||||||||||||
148 | ** | - | ||||||||||||||||||
149 | ** Check to see if pBtree holds the required locks to read or write to the | - | ||||||||||||||||||
150 | ** table with root page iRoot. Return 1 if it does and 0 if not. | - | ||||||||||||||||||
151 | ** | - | ||||||||||||||||||
152 | ** For example, when writing to a table with root-page iRoot via | - | ||||||||||||||||||
153 | ** Btree connection pBtree: | - | ||||||||||||||||||
154 | ** | - | ||||||||||||||||||
155 | ** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) ); | - | ||||||||||||||||||
156 | ** | - | ||||||||||||||||||
157 | ** When writing to an index that resides in a sharable database, the | - | ||||||||||||||||||
158 | ** caller should have first obtained a lock specifying the root page of | - | ||||||||||||||||||
159 | ** the corresponding table. This makes things a bit more complicated, | - | ||||||||||||||||||
160 | ** as this module treats each table as a separate structure. To determine | - | ||||||||||||||||||
161 | ** the table corresponding to the index being written, this | - | ||||||||||||||||||
162 | ** function has to search through the database schema. | - | ||||||||||||||||||
163 | ** | - | ||||||||||||||||||
164 | ** Instead of a lock on the table/index rooted at page iRoot, the caller may | - | ||||||||||||||||||
165 | ** hold a write-lock on the schema table (root page 1). This is also | - | ||||||||||||||||||
166 | ** acceptable. | - | ||||||||||||||||||
167 | */ | - | ||||||||||||||||||
168 | static int hasSharedCacheTableLock( | - | ||||||||||||||||||
169 | Btree *pBtree, /* Handle that must hold lock */ | - | ||||||||||||||||||
170 | Pgno iRoot, /* Root page of b-tree */ | - | ||||||||||||||||||
171 | int isIndex, /* True if iRoot is the root of an index b-tree */ | - | ||||||||||||||||||
172 | int eLockType /* Required lock type (READ_LOCK or WRITE_LOCK) */ | - | ||||||||||||||||||
173 | ){ | - | ||||||||||||||||||
174 | Schema *pSchema = (Schema *)pBtree->pBt->pSchema; | - | ||||||||||||||||||
175 | Pgno iTab = 0; | - | ||||||||||||||||||
176 | BtLock *pLock; | - | ||||||||||||||||||
177 | - | |||||||||||||||||||
178 | /* If this database is not shareable, or if the client is reading | - | ||||||||||||||||||
179 | ** and has the read-uncommitted flag set, then no lock is required. | - | ||||||||||||||||||
180 | ** Return true immediately. | - | ||||||||||||||||||
181 | */ | - | ||||||||||||||||||
182 | if( (pBtree->sharable==0) | - | ||||||||||||||||||
183 | || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit)) | - | ||||||||||||||||||
184 | ){ | - | ||||||||||||||||||
185 | return 1; | - | ||||||||||||||||||
186 | } | - | ||||||||||||||||||
187 | - | |||||||||||||||||||
188 | /* If the client is reading or writing an index and the schema is | - | ||||||||||||||||||
189 | ** not loaded, then it is too difficult to actually check to see if | - | ||||||||||||||||||
190 | ** the correct locks are held. So do not bother - just return true. | - | ||||||||||||||||||
191 | ** This case does not come up very often anyhow. | - | ||||||||||||||||||
192 | */ | - | ||||||||||||||||||
193 | if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){ | - | ||||||||||||||||||
194 | return 1; | - | ||||||||||||||||||
195 | } | - | ||||||||||||||||||
196 | - | |||||||||||||||||||
197 | /* Figure out the root-page that the lock should be held on. For table | - | ||||||||||||||||||
198 | ** b-trees, this is just the root page of the b-tree being read or | - | ||||||||||||||||||
199 | ** written. For index b-trees, it is the root page of the associated | - | ||||||||||||||||||
200 | ** table. */ | - | ||||||||||||||||||
201 | if( isIndex ){ | - | ||||||||||||||||||
202 | HashElem *p; | - | ||||||||||||||||||
203 | for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ | - | ||||||||||||||||||
204 | Index *pIdx = (Index *)sqliteHashData(p); | - | ||||||||||||||||||
205 | if( pIdx->tnum==(int)iRoot ){ | - | ||||||||||||||||||
206 | if( iTab ){ | - | ||||||||||||||||||
207 | /* Two or more indexes share the same root page. There must | - | ||||||||||||||||||
208 | ** be imposter tables. So just return true. The assert is not | - | ||||||||||||||||||
209 | ** useful in that case. */ | - | ||||||||||||||||||
210 | return 1; | - | ||||||||||||||||||
211 | } | - | ||||||||||||||||||
212 | iTab = pIdx->pTable->tnum; | - | ||||||||||||||||||
213 | } | - | ||||||||||||||||||
214 | } | - | ||||||||||||||||||
215 | }else{ | - | ||||||||||||||||||
216 | iTab = iRoot; | - | ||||||||||||||||||
217 | } | - | ||||||||||||||||||
218 | - | |||||||||||||||||||
219 | /* Search for the required lock. Either a write-lock on root-page iTab, a | - | ||||||||||||||||||
220 | ** write-lock on the schema table, or (if the client is reading) a | - | ||||||||||||||||||
221 | ** read-lock on iTab will suffice. Return 1 if any of these are found. */ | - | ||||||||||||||||||
222 | for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){ | - | ||||||||||||||||||
223 | if( pLock->pBtree==pBtree | - | ||||||||||||||||||
224 | && (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1)) | - | ||||||||||||||||||
225 | && pLock->eLock>=eLockType | - | ||||||||||||||||||
226 | ){ | - | ||||||||||||||||||
227 | return 1; | - | ||||||||||||||||||
228 | } | - | ||||||||||||||||||
229 | } | - | ||||||||||||||||||
230 | - | |||||||||||||||||||
231 | /* Failed to find the required lock. */ | - | ||||||||||||||||||
232 | return 0; | - | ||||||||||||||||||
233 | } | - | ||||||||||||||||||
234 | #endif /* SQLITE_DEBUG */ | - | ||||||||||||||||||
235 | - | |||||||||||||||||||
236 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
237 | /* | - | ||||||||||||||||||
238 | **** This function may be used as part of assert() statements only. **** | - | ||||||||||||||||||
239 | ** | - | ||||||||||||||||||
240 | ** Return true if it would be illegal for pBtree to write into the | - | ||||||||||||||||||
241 | ** table or index rooted at iRoot because other shared connections are | - | ||||||||||||||||||
242 | ** simultaneously reading that same table or index. | - | ||||||||||||||||||
243 | ** | - | ||||||||||||||||||
244 | ** It is illegal for pBtree to write if some other Btree object that | - | ||||||||||||||||||
245 | ** shares the same BtShared object is currently reading or writing | - | ||||||||||||||||||
246 | ** the iRoot table. Except, if the other Btree object has the | - | ||||||||||||||||||
247 | ** read-uncommitted flag set, then it is OK for the other object to | - | ||||||||||||||||||
248 | ** have a read cursor. | - | ||||||||||||||||||
249 | ** | - | ||||||||||||||||||
250 | ** For example, before writing to any part of the table or index | - | ||||||||||||||||||
251 | ** rooted at page iRoot, one should call: | - | ||||||||||||||||||
252 | ** | - | ||||||||||||||||||
253 | ** assert( !hasReadConflicts(pBtree, iRoot) ); | - | ||||||||||||||||||
254 | */ | - | ||||||||||||||||||
255 | static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ | - | ||||||||||||||||||
256 | BtCursor *p; | - | ||||||||||||||||||
257 | for(p=pBtree->pBt->pCursor; p; p=p->pNext){ | - | ||||||||||||||||||
258 | if( p->pgnoRoot==iRoot | - | ||||||||||||||||||
259 | && p->pBtree!=pBtree | - | ||||||||||||||||||
260 | && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit) | - | ||||||||||||||||||
261 | ){ | - | ||||||||||||||||||
262 | return 1; | - | ||||||||||||||||||
263 | } | - | ||||||||||||||||||
264 | } | - | ||||||||||||||||||
265 | return 0; | - | ||||||||||||||||||
266 | } | - | ||||||||||||||||||
267 | #endif /* #ifdef SQLITE_DEBUG */ | - | ||||||||||||||||||
268 | - | |||||||||||||||||||
269 | /* | - | ||||||||||||||||||
270 | ** Query to see if Btree handle p may obtain a lock of type eLock | - | ||||||||||||||||||
271 | ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return | - | ||||||||||||||||||
272 | ** SQLITE_OK if the lock may be obtained (by calling | - | ||||||||||||||||||
273 | ** setSharedCacheTableLock()), or SQLITE_LOCKED if not. | - | ||||||||||||||||||
274 | */ | - | ||||||||||||||||||
275 | static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ | - | ||||||||||||||||||
276 | BtShared *pBt = p->pBt; | - | ||||||||||||||||||
277 | BtLock *pIter; | - | ||||||||||||||||||
278 | - | |||||||||||||||||||
279 | assert( sqlite3BtreeHoldsMutex(p) ); | - | ||||||||||||||||||
280 | assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); | - | ||||||||||||||||||
281 | assert( p->db!=0 ); | - | ||||||||||||||||||
282 | assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 ); | - | ||||||||||||||||||
283 | - | |||||||||||||||||||
284 | /* If requesting a write-lock, then the Btree must have an open write | - | ||||||||||||||||||
285 | ** transaction on this file. And, obviously, for this to be so there | - | ||||||||||||||||||
286 | ** must be an open write transaction on the file itself. | - | ||||||||||||||||||
287 | */ | - | ||||||||||||||||||
288 | assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) ); | - | ||||||||||||||||||
289 | assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE ); | - | ||||||||||||||||||
290 | - | |||||||||||||||||||
291 | /* This routine is a no-op if the shared-cache is not enabled */ | - | ||||||||||||||||||
292 | if( !p->sharable ){
| 7439-895956 | ||||||||||||||||||
293 | return SQLITE_OK; executed 895956 times by 436 tests: return 0; Executed by:
| 895956 | ||||||||||||||||||
294 | } | - | ||||||||||||||||||
295 | - | |||||||||||||||||||
296 | /* If some other connection is holding an exclusive lock, the | - | ||||||||||||||||||
297 | ** requested lock may not be obtained. | - | ||||||||||||||||||
298 | */ | - | ||||||||||||||||||
299 | if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){
| 6-5667 | ||||||||||||||||||
300 | sqlite3ConnectionBlocked(p->db, pBt->pWriter->db); | - | ||||||||||||||||||
301 | return SQLITE_LOCKED_SHAREDCACHE; executed 6 times by 1 test: return (6 | (1<<8)); Executed by:
| 6 | ||||||||||||||||||
302 | } | - | ||||||||||||||||||
303 | - | |||||||||||||||||||
304 | for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
| 6163-7378 | ||||||||||||||||||
305 | /* The condition (pIter->eLock!=eLock) in the following if(...) | - | ||||||||||||||||||
306 | ** statement is a simplification of: | - | ||||||||||||||||||
307 | ** | - | ||||||||||||||||||
308 | ** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK) | - | ||||||||||||||||||
309 | ** | - | ||||||||||||||||||
310 | ** since we know that if eLock==WRITE_LOCK, then no other connection | - | ||||||||||||||||||
311 | ** may hold a WRITE_LOCK on any table in this file (since there can | - | ||||||||||||||||||
312 | ** only be a single writer). | - | ||||||||||||||||||
313 | */ | - | ||||||||||||||||||
314 | assert( pIter->eLock==READ_LOCK || pIter->eLock==WRITE_LOCK ); | - | ||||||||||||||||||
315 | assert( eLock==READ_LOCK || pIter->pBtree==p || pIter->eLock==READ_LOCK); | - | ||||||||||||||||||
316 | if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){
| 55-4286 | ||||||||||||||||||
317 | sqlite3ConnectionBlocked(p->db, pIter->pBtree->db); | - | ||||||||||||||||||
318 | if( eLock==WRITE_LOCK ){
| 18-37 | ||||||||||||||||||
319 | assert( p==pBt->pWriter ); | - | ||||||||||||||||||
320 | pBt->btsFlags |= BTS_PENDING; | - | ||||||||||||||||||
321 | } executed 18 times by 1 test: end of block Executed by:
| 18 | ||||||||||||||||||
322 | return SQLITE_LOCKED_SHAREDCACHE; executed 55 times by 1 test: return (6 | (1<<8)); Executed by:
| 55 | ||||||||||||||||||
323 | } | - | ||||||||||||||||||
324 | } executed 6108 times by 1 test: end of block Executed by:
| 6108 | ||||||||||||||||||
325 | return SQLITE_OK; executed 7378 times by 1 test: return 0; Executed by:
| 7378 | ||||||||||||||||||
326 | } | - | ||||||||||||||||||
327 | #endif /* !SQLITE_OMIT_SHARED_CACHE */ | - | ||||||||||||||||||
328 | - | |||||||||||||||||||
329 | #ifndef SQLITE_OMIT_SHARED_CACHE | - | ||||||||||||||||||
330 | /* | - | ||||||||||||||||||
331 | ** Add a lock on the table with root-page iTable to the shared-btree used | - | ||||||||||||||||||
332 | ** by Btree handle p. Parameter eLock must be either READ_LOCK or | - | ||||||||||||||||||
333 | ** WRITE_LOCK. | - | ||||||||||||||||||
334 | ** | - | ||||||||||||||||||
335 | ** This function assumes the following: | - | ||||||||||||||||||
336 | ** | - | ||||||||||||||||||
337 | ** (a) The specified Btree object p is connected to a sharable | - | ||||||||||||||||||
338 | ** database (one with the BtShared.sharable flag set), and | - | ||||||||||||||||||
339 | ** | - | ||||||||||||||||||
340 | ** (b) No other Btree objects hold a lock that conflicts | - | ||||||||||||||||||
341 | ** with the requested lock (i.e. querySharedCacheTableLock() has | - | ||||||||||||||||||
342 | ** already been called and returned SQLITE_OK). | - | ||||||||||||||||||
343 | ** | - | ||||||||||||||||||
344 | ** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM | - | ||||||||||||||||||
345 | ** is returned if a malloc attempt fails. | - | ||||||||||||||||||
346 | */ | - | ||||||||||||||||||
347 | static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ | - | ||||||||||||||||||
348 | BtShared *pBt = p->pBt; | - | ||||||||||||||||||
349 | BtLock *pLock = 0; | - | ||||||||||||||||||
350 | BtLock *pIter; | - | ||||||||||||||||||
351 | - | |||||||||||||||||||
352 | assert( sqlite3BtreeHoldsMutex(p) ); | - | ||||||||||||||||||
353 | assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); | - | ||||||||||||||||||
354 | assert( p->db!=0 ); | - | ||||||||||||||||||
355 | - | |||||||||||||||||||
356 | /* A connection with the read-uncommitted flag set will never try to | - | ||||||||||||||||||
357 | ** obtain a read-lock using this function. The only read-lock obtained | - | ||||||||||||||||||
358 | ** by a connection in read-uncommitted mode is on the sqlite_master | - | ||||||||||||||||||
359 | ** table, and that lock is obtained in BtreeBeginTrans(). */ | - | ||||||||||||||||||
360 | assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); | - | ||||||||||||||||||
361 | - | |||||||||||||||||||
362 | /* This function should only be called on a sharable b-tree after it | - | ||||||||||||||||||
363 | ** has been determined that no other b-tree holds a conflicting lock. */ | - | ||||||||||||||||||
364 | assert( p->sharable ); | - | ||||||||||||||||||
365 | assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) ); | - | ||||||||||||||||||
366 | - | |||||||||||||||||||
367 | /* First search the list for an existing lock on this table. */ | - | ||||||||||||||||||
368 | for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
| 713-2383 | ||||||||||||||||||
369 | if( pIter->iTable==iTable && pIter->pBtree==p ){
| 31-1279 | ||||||||||||||||||
370 | pLock = pIter; | - | ||||||||||||||||||
371 | break; executed 1073 times by 1 test: break; Executed by:
| 1073 | ||||||||||||||||||
372 | } | - | ||||||||||||||||||
373 | } executed 1310 times by 1 test: end of block Executed by:
| 1310 | ||||||||||||||||||
374 | - | |||||||||||||||||||
375 | /* If the above search did not find a BtLock struct associating Btree p | - | ||||||||||||||||||
376 | ** with table iTable, allocate one and link it into the list. | - | ||||||||||||||||||
377 | */ | - | ||||||||||||||||||
378 | if( !pLock ){
| 713-1073 | ||||||||||||||||||
379 | pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); | - | ||||||||||||||||||
380 | if( !pLock ){
| 0-713 | ||||||||||||||||||
381 | return SQLITE_NOMEM_BKPT; never executed: return 7; | 0 | ||||||||||||||||||
382 | } | - | ||||||||||||||||||
383 | pLock->iTable = iTable; | - | ||||||||||||||||||
384 | pLock->pBtree = p; | - | ||||||||||||||||||
385 | pLock->pNext = pBt->pLock; | - | ||||||||||||||||||
386 | pBt->pLock = pLock; | - | ||||||||||||||||||
387 | } executed 713 times by 1 test: end of block Executed by:
| 713 | ||||||||||||||||||
388 | - | |||||||||||||||||||
389 | /* Set the BtLock.eLock variable to the maximum of the current lock | - | ||||||||||||||||||
390 | ** and the requested lock. This means if a write-lock was already held | - | ||||||||||||||||||
391 | ** and a read-lock requested, we don't incorrectly downgrade the lock. | - | ||||||||||||||||||
392 | */ | - | ||||||||||||||||||
393 | assert( WRITE_LOCK>READ_LOCK ); | - | ||||||||||||||||||
394 | if( eLock>pLock->eLock ){
| 860-926 | ||||||||||||||||||
395 | pLock->eLock = eLock; | - | ||||||||||||||||||
396 | } executed 926 times by 1 test: end of block Executed by:
| 926 | ||||||||||||||||||
397 | - | |||||||||||||||||||
398 | return SQLITE_OK; executed 1786 times by 1 test: return 0; Executed by:
| 1786 | ||||||||||||||||||
399 | } | - | ||||||||||||||||||
400 | #endif /* !SQLITE_OMIT_SHARED_CACHE */ | - | ||||||||||||||||||
401 | - | |||||||||||||||||||
402 | #ifndef SQLITE_OMIT_SHARED_CACHE | - | ||||||||||||||||||
403 | /* | - | ||||||||||||||||||
404 | ** Release all the table locks (locks obtained via calls to | - | ||||||||||||||||||
405 | ** the setSharedCacheTableLock() procedure) held by Btree object p. | - | ||||||||||||||||||
406 | ** | - | ||||||||||||||||||
407 | ** This function assumes that Btree p has an open read or write | - | ||||||||||||||||||
408 | ** transaction. If it does not, then the BTS_PENDING flag | - | ||||||||||||||||||
409 | ** may be incorrectly cleared. | - | ||||||||||||||||||
410 | */ | - | ||||||||||||||||||
411 | static void clearAllSharedCacheTableLocks(Btree *p){ | - | ||||||||||||||||||
412 | BtShared *pBt = p->pBt; | - | ||||||||||||||||||
413 | BtLock **ppIter = &pBt->pLock; | - | ||||||||||||||||||
414 | - | |||||||||||||||||||
415 | assert( sqlite3BtreeHoldsMutex(p) ); | - | ||||||||||||||||||
416 | assert( p->sharable || 0==*ppIter ); | - | ||||||||||||||||||
417 | assert( p->inTrans>0 ); | - | ||||||||||||||||||
418 | - | |||||||||||||||||||
419 | while( *ppIter ){
| 2515-260919 | ||||||||||||||||||
420 | BtLock *pLock = *ppIter; | - | ||||||||||||||||||
421 | assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree ); | - | ||||||||||||||||||
422 | assert( pLock->pBtree->inTrans>=pLock->eLock ); | - | ||||||||||||||||||
423 | if( pLock->pBtree==p ){
| 615-1900 | ||||||||||||||||||
424 | *ppIter = pLock->pNext; | - | ||||||||||||||||||
425 | assert( pLock->iTable!=1 || pLock==&p->lock ); | - | ||||||||||||||||||
426 | if( pLock->iTable!=1 ){
| 713-1187 | ||||||||||||||||||
427 | sqlite3_free(pLock); | - | ||||||||||||||||||
428 | } executed 713 times by 1 test: end of block Executed by:
| 713 | ||||||||||||||||||
429 | }else{ executed 1900 times by 1 test: end of block Executed by:
| 1900 | ||||||||||||||||||
430 | ppIter = &pLock->pNext; | - | ||||||||||||||||||
431 | } executed 615 times by 1 test: end of block Executed by:
| 615 | ||||||||||||||||||
432 | } | - | ||||||||||||||||||
433 | - | |||||||||||||||||||
434 | assert( (pBt->btsFlags & BTS_PENDING)==0 || pBt->pWriter ); | - | ||||||||||||||||||
435 | if( pBt->pWriter==p ){
| 98458-162461 | ||||||||||||||||||
436 | pBt->pWriter = 0; | - | ||||||||||||||||||
437 | pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); | - | ||||||||||||||||||
438 | }else if( pBt->nTransaction==2 ){ executed 162461 times by 62 tests: end of block Executed by:
| 70-162461 | ||||||||||||||||||
439 | /* This function is called when Btree p is concluding its | - | ||||||||||||||||||
440 | ** transaction. If there currently exists a writer, and p is not | - | ||||||||||||||||||
441 | ** that writer, then the number of locks held by connections other | - | ||||||||||||||||||
442 | ** than the writer must be about to drop to zero. In this case | - | ||||||||||||||||||
443 | ** set the BTS_PENDING flag to 0. | - | ||||||||||||||||||
444 | ** | - | ||||||||||||||||||
445 | ** If there is not currently a writer, then BTS_PENDING must | - | ||||||||||||||||||
446 | ** be zero already. So this next line is harmless in that case. | - | ||||||||||||||||||
447 | */ | - | ||||||||||||||||||
448 | pBt->btsFlags &= ~BTS_PENDING; | - | ||||||||||||||||||
449 | } executed 70 times by 1 test: end of block Executed by:
| 70 | ||||||||||||||||||
450 | } executed 260919 times by 435 tests: end of block Executed by:
| 260919 | ||||||||||||||||||
451 | - | |||||||||||||||||||
452 | /* | - | ||||||||||||||||||
453 | ** This function changes all write-locks held by Btree p into read-locks. | - | ||||||||||||||||||
454 | */ | - | ||||||||||||||||||
455 | static void downgradeAllSharedCacheTableLocks(Btree *p){ | - | ||||||||||||||||||
456 | BtShared *pBt = p->pBt; | - | ||||||||||||||||||
457 | if( pBt->pWriter==p ){
| 1106-144045 | ||||||||||||||||||
458 | BtLock *pLock; | - | ||||||||||||||||||
459 | pBt->pWriter = 0; | - | ||||||||||||||||||
460 | pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); | - | ||||||||||||||||||
461 | for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){
| 2-1106 | ||||||||||||||||||
462 | assert( pLock->eLock==READ_LOCK || pLock->pBtree==p ); | - | ||||||||||||||||||
463 | pLock->eLock = READ_LOCK; | - | ||||||||||||||||||
464 | } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
465 | } executed 1106 times by 1 test: end of block Executed by:
| 1106 | ||||||||||||||||||
466 | } executed 145151 times by 1 test: end of block Executed by:
| 145151 | ||||||||||||||||||
467 | - | |||||||||||||||||||
468 | #endif /* SQLITE_OMIT_SHARED_CACHE */ | - | ||||||||||||||||||
469 | - | |||||||||||||||||||
470 | static void releasePage(MemPage *pPage); /* Forward reference */ | - | ||||||||||||||||||
471 | static void releasePageOne(MemPage *pPage); /* Forward reference */ | - | ||||||||||||||||||
472 | static void releasePageNotNull(MemPage *pPage); /* Forward reference */ | - | ||||||||||||||||||
473 | - | |||||||||||||||||||
474 | /* | - | ||||||||||||||||||
475 | ***** This routine is used inside of assert() only **** | - | ||||||||||||||||||
476 | ** | - | ||||||||||||||||||
477 | ** Verify that the cursor holds the mutex on its BtShared | - | ||||||||||||||||||
478 | */ | - | ||||||||||||||||||
479 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
480 | static int cursorHoldsMutex(BtCursor *p){ | - | ||||||||||||||||||
481 | return sqlite3_mutex_held(p->pBt->mutex); | - | ||||||||||||||||||
482 | } | - | ||||||||||||||||||
483 | - | |||||||||||||||||||
484 | /* Verify that the cursor and the BtShared agree about what is the current | - | ||||||||||||||||||
485 | ** database connetion. This is important in shared-cache mode. If the database | - | ||||||||||||||||||
486 | ** connection pointers get out-of-sync, it is possible for routines like | - | ||||||||||||||||||
487 | ** btreeInitPage() to reference an stale connection pointer that references a | - | ||||||||||||||||||
488 | ** a connection that has already closed. This routine is used inside assert() | - | ||||||||||||||||||
489 | ** statements only and for the purpose of double-checking that the btree code | - | ||||||||||||||||||
490 | ** does keep the database connection pointers up-to-date. | - | ||||||||||||||||||
491 | */ | - | ||||||||||||||||||
492 | static int cursorOwnsBtShared(BtCursor *p){ | - | ||||||||||||||||||
493 | assert( cursorHoldsMutex(p) ); | - | ||||||||||||||||||
494 | return (p->pBtree->db==p->pBt->db); | - | ||||||||||||||||||
495 | } | - | ||||||||||||||||||
496 | #endif | - | ||||||||||||||||||
497 | - | |||||||||||||||||||
498 | /* | - | ||||||||||||||||||
499 | ** Invalidate the overflow cache of the cursor passed as the first argument. | - | ||||||||||||||||||
500 | ** on the shared btree structure pBt. | - | ||||||||||||||||||
501 | */ | - | ||||||||||||||||||
502 | #define invalidateOverflowCache(pCur) (pCur->curFlags &= ~BTCF_ValidOvfl) | - | ||||||||||||||||||
503 | - | |||||||||||||||||||
504 | /* | - | ||||||||||||||||||
505 | ** Invalidate the overflow page-list cache for all cursors opened | - | ||||||||||||||||||
506 | ** on the shared btree structure pBt. | - | ||||||||||||||||||
507 | */ | - | ||||||||||||||||||
508 | static void invalidateAllOverflowCache(BtShared *pBt){ | - | ||||||||||||||||||
509 | BtCursor *p; | - | ||||||||||||||||||
510 | assert( sqlite3_mutex_held(pBt->mutex) ); | - | ||||||||||||||||||
511 | for(p=pBt->pCursor; p; p=p->pNext){
| 448-15011 | ||||||||||||||||||
512 | invalidateOverflowCache(p); | - | ||||||||||||||||||
513 | } executed 448 times by 1 test: end of block Executed by:
| 448 | ||||||||||||||||||
514 | } executed 15011 times by 4 tests: end of block Executed by:
| 15011 | ||||||||||||||||||
515 | - | |||||||||||||||||||
516 | #ifndef SQLITE_OMIT_INCRBLOB | - | ||||||||||||||||||
517 | /* | - | ||||||||||||||||||
518 | ** This function is called before modifying the contents of a table | - | ||||||||||||||||||
519 | ** to invalidate any incrblob cursors that are open on the | - | ||||||||||||||||||
520 | ** row or one of the rows being modified. | - | ||||||||||||||||||
521 | ** | - | ||||||||||||||||||
522 | ** If argument isClearTable is true, then the entire contents of the | - | ||||||||||||||||||
523 | ** table is about to be deleted. In this case invalidate all incrblob | - | ||||||||||||||||||
524 | ** cursors open on any row within the table with root-page pgnoRoot. | - | ||||||||||||||||||
525 | ** | - | ||||||||||||||||||
526 | ** Otherwise, if argument isClearTable is false, then the row with | - | ||||||||||||||||||
527 | ** rowid iRow is being replaced or deleted. In this case invalidate | - | ||||||||||||||||||
528 | ** only those incrblob cursors open on that specific row. | - | ||||||||||||||||||
529 | */ | - | ||||||||||||||||||
530 | static void invalidateIncrblobCursors( | - | ||||||||||||||||||
531 | Btree *pBtree, /* The database file to check */ | - | ||||||||||||||||||
532 | Pgno pgnoRoot, /* The table that might be changing */ | - | ||||||||||||||||||
533 | i64 iRow, /* The rowid that might be changing */ | - | ||||||||||||||||||
534 | int isClearTable /* True if all rows are being deleted */ | - | ||||||||||||||||||
535 | ){ | - | ||||||||||||||||||
536 | BtCursor *p; | - | ||||||||||||||||||
537 | if( pBtree->hasIncrblobCur==0 ) return; executed 7100521 times by 391 tests: return; Executed by:
| 225-7100521 | ||||||||||||||||||
538 | assert( sqlite3BtreeHoldsMutex(pBtree) ); | - | ||||||||||||||||||
539 | pBtree->hasIncrblobCur = 0; | - | ||||||||||||||||||
540 | for(p=pBtree->pBt->pCursor; p; p=p->pNext){
| 225-12324 | ||||||||||||||||||
541 | if( (p->curFlags & BTCF_Incrblob)!=0 ){
| 343-11981 | ||||||||||||||||||
542 | pBtree->hasIncrblobCur = 1; | - | ||||||||||||||||||
543 | if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
| 10-11971 | ||||||||||||||||||
544 | p->eState = CURSOR_INVALID; | - | ||||||||||||||||||
545 | } executed 117 times by 1 test: end of block Executed by:
| 117 | ||||||||||||||||||
546 | } executed 11981 times by 1 test: end of block Executed by:
| 11981 | ||||||||||||||||||
547 | } executed 12324 times by 1 test: end of block Executed by:
| 12324 | ||||||||||||||||||
548 | } executed 225 times by 1 test: end of block Executed by:
| 225 | ||||||||||||||||||
549 | - | |||||||||||||||||||
550 | #else | - | ||||||||||||||||||
551 | /* Stub function when INCRBLOB is omitted */ | - | ||||||||||||||||||
552 | #define invalidateIncrblobCursors(w,x,y,z) | - | ||||||||||||||||||
553 | #endif /* SQLITE_OMIT_INCRBLOB */ | - | ||||||||||||||||||
554 | - | |||||||||||||||||||
555 | /* | - | ||||||||||||||||||
556 | ** Set bit pgno of the BtShared.pHasContent bitvec. This is called | - | ||||||||||||||||||
557 | ** when a page that previously contained data becomes a free-list leaf | - | ||||||||||||||||||
558 | ** page. | - | ||||||||||||||||||
559 | ** | - | ||||||||||||||||||
560 | ** The BtShared.pHasContent bitvec exists to work around an obscure | - | ||||||||||||||||||
561 | ** bug caused by the interaction of two useful IO optimizations surrounding | - | ||||||||||||||||||
562 | ** free-list leaf pages: | - | ||||||||||||||||||
563 | ** | - | ||||||||||||||||||
564 | ** 1) When all data is deleted from a page and the page becomes | - | ||||||||||||||||||
565 | ** a free-list leaf page, the page is not written to the database | - | ||||||||||||||||||
566 | ** (as free-list leaf pages contain no meaningful data). Sometimes | - | ||||||||||||||||||
567 | ** such a page is not even journalled (as it will not be modified, | - | ||||||||||||||||||
568 | ** why bother journalling it?). | - | ||||||||||||||||||
569 | ** | - | ||||||||||||||||||
570 | ** 2) When a free-list leaf page is reused, its content is not read | - | ||||||||||||||||||
571 | ** from the database or written to the journal file (why should it | - | ||||||||||||||||||
572 | ** be, if it is not at all meaningful?). | - | ||||||||||||||||||
573 | ** | - | ||||||||||||||||||
574 | ** By themselves, these optimizations work fine and provide a handy | - | ||||||||||||||||||
575 | ** performance boost to bulk delete or insert operations. However, if | - | ||||||||||||||||||
576 | ** a page is moved to the free-list and then reused within the same | - | ||||||||||||||||||
577 | ** transaction, a problem comes up. If the page is not journalled when | - | ||||||||||||||||||
578 | ** it is moved to the free-list and it is also not journalled when it | - | ||||||||||||||||||
579 | ** is extracted from the free-list and reused, then the original data | - | ||||||||||||||||||
580 | ** may be lost. In the event of a rollback, it may not be possible | - | ||||||||||||||||||
581 | ** to restore the database to its original configuration. | - | ||||||||||||||||||
582 | ** | - | ||||||||||||||||||
583 | ** The solution is the BtShared.pHasContent bitvec. Whenever a page is | - | ||||||||||||||||||
584 | ** moved to become a free-list leaf page, the corresponding bit is | - | ||||||||||||||||||
585 | ** set in the bitvec. Whenever a leaf page is extracted from the free-list, | - | ||||||||||||||||||
586 | ** optimization 2 above is omitted if the corresponding bit is already | - | ||||||||||||||||||
587 | ** set in BtShared.pHasContent. The contents of the bitvec are cleared | - | ||||||||||||||||||
588 | ** at the end of every transaction. | - | ||||||||||||||||||
589 | */ | - | ||||||||||||||||||
590 | static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ | - | ||||||||||||||||||
591 | int rc = SQLITE_OK; | - | ||||||||||||||||||
592 | if( !pBt->pHasContent ){
| 3112-264587 | ||||||||||||||||||
593 | assert( pgno<=pBt->nPage ); | - | ||||||||||||||||||
594 | pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage); | - | ||||||||||||||||||
595 | if( !pBt->pHasContent ){
| 1-3111 | ||||||||||||||||||
596 | rc = SQLITE_NOMEM_BKPT; | - | ||||||||||||||||||
597 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
598 | } executed 3112 times by 15 tests: end of block Executed by:
| 3112 | ||||||||||||||||||
599 | if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
| 1-267698 | ||||||||||||||||||
600 | rc = sqlite3BitvecSet(pBt->pHasContent, pgno); | - | ||||||||||||||||||
601 | } executed 241569 times by 15 tests: end of block Executed by:
| 241569 | ||||||||||||||||||
602 | return rc; executed 267699 times by 15 tests: return rc; Executed by:
| 267699 | ||||||||||||||||||
603 | } | - | ||||||||||||||||||
604 | - | |||||||||||||||||||
605 | /* | - | ||||||||||||||||||
606 | ** Query the BtShared.pHasContent vector. | - | ||||||||||||||||||
607 | ** | - | ||||||||||||||||||
608 | ** This function is called when a free-list leaf page is removed from the | - | ||||||||||||||||||
609 | ** free-list for reuse. It returns false if it is safe to retrieve the | - | ||||||||||||||||||
610 | ** page from the pager layer with the 'no-content' flag set. True otherwise. | - | ||||||||||||||||||
611 | */ | - | ||||||||||||||||||
612 | static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ | - | ||||||||||||||||||
613 | Bitvec *p = pBt->pHasContent; | - | ||||||||||||||||||
614 | return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno))); executed 148719 times by 11 tests: return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno))); Executed by:
| 1704-148719 | ||||||||||||||||||
615 | } | - | ||||||||||||||||||
616 | - | |||||||||||||||||||
617 | /* | - | ||||||||||||||||||
618 | ** Clear (destroy) the BtShared.pHasContent bitvec. This should be | - | ||||||||||||||||||
619 | ** invoked at the conclusion of each write-transaction. | - | ||||||||||||||||||
620 | */ | - | ||||||||||||||||||
621 | static void btreeClearHasContent(BtShared *pBt){ | - | ||||||||||||||||||
622 | sqlite3BitvecDestroy(pBt->pHasContent); | - | ||||||||||||||||||
623 | pBt->pHasContent = 0; | - | ||||||||||||||||||
624 | } executed 163567 times by 62 tests: end of block Executed by:
| 163567 | ||||||||||||||||||
625 | - | |||||||||||||||||||
626 | /* | - | ||||||||||||||||||
627 | ** Release all of the apPage[] pages for a cursor. | - | ||||||||||||||||||
628 | */ | - | ||||||||||||||||||
629 | static void btreeReleaseAllCursorPages(BtCursor *pCur){ | - | ||||||||||||||||||
630 | int i; | - | ||||||||||||||||||
631 | if( pCur->iPage>=0 ){
| 2150169-5508367 | ||||||||||||||||||
632 | for(i=0; i<pCur->iPage; i++){
| 2150169-2465930 | ||||||||||||||||||
633 | releasePageNotNull(pCur->apPage[i]); | - | ||||||||||||||||||
634 | } executed 2465930 times by 108 tests: end of block Executed by:
| 2465930 | ||||||||||||||||||
635 | releasePageNotNull(pCur->pPage); | - | ||||||||||||||||||
636 | pCur->iPage = -1; | - | ||||||||||||||||||
637 | } executed 2150169 times by 434 tests: end of block Executed by:
| 2150169 | ||||||||||||||||||
638 | } executed 7658536 times by 435 tests: end of block Executed by:
| 7658536 | ||||||||||||||||||
639 | - | |||||||||||||||||||
640 | /* | - | ||||||||||||||||||
641 | ** The cursor passed as the only argument must point to a valid entry | - | ||||||||||||||||||
642 | ** when this function is called (i.e. have eState==CURSOR_VALID). This | - | ||||||||||||||||||
643 | ** function saves the current cursor key in variables pCur->nKey and | - | ||||||||||||||||||
644 | ** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error | - | ||||||||||||||||||
645 | ** code otherwise. | - | ||||||||||||||||||
646 | ** | - | ||||||||||||||||||
647 | ** If the cursor is open on an intkey table, then the integer key | - | ||||||||||||||||||
648 | ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to | - | ||||||||||||||||||
649 | ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is | - | ||||||||||||||||||
650 | ** set to point to a malloced buffer pCur->nKey bytes in size containing | - | ||||||||||||||||||
651 | ** the key. | - | ||||||||||||||||||
652 | */ | - | ||||||||||||||||||
653 | static int saveCursorKey(BtCursor *pCur){ | - | ||||||||||||||||||
654 | int rc = SQLITE_OK; | - | ||||||||||||||||||
655 | assert( CURSOR_VALID==pCur->eState ); | - | ||||||||||||||||||
656 | assert( 0==pCur->pKey ); | - | ||||||||||||||||||
657 | assert( cursorHoldsMutex(pCur) ); | - | ||||||||||||||||||
658 | - | |||||||||||||||||||
659 | if( pCur->curIntKey ){
| 1717-176149 | ||||||||||||||||||
660 | /* Only the rowid is required for a table btree */ | - | ||||||||||||||||||
661 | pCur->nKey = sqlite3BtreeIntegerKey(pCur); | - | ||||||||||||||||||
662 | }else{ executed 176149 times by 17 tests: end of block Executed by:
| 176149 | ||||||||||||||||||
663 | /* For an index btree, save the complete key content */ | - | ||||||||||||||||||
664 | void *pKey; | - | ||||||||||||||||||
665 | pCur->nKey = sqlite3BtreePayloadSize(pCur); | - | ||||||||||||||||||
666 | pKey = sqlite3Malloc( pCur->nKey ); | - | ||||||||||||||||||
667 | if( pKey ){
| 0-1717 | ||||||||||||||||||
668 | rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); | - | ||||||||||||||||||
669 | if( rc==SQLITE_OK ){
| 0-1717 | ||||||||||||||||||
670 | pCur->pKey = pKey; | - | ||||||||||||||||||
671 | }else{ executed 1717 times by 1 test: end of block Executed by:
| 1717 | ||||||||||||||||||
672 | sqlite3_free(pKey); | - | ||||||||||||||||||
673 | } never executed: end of block | 0 | ||||||||||||||||||
674 | }else{ | - | ||||||||||||||||||
675 | rc = SQLITE_NOMEM_BKPT; | - | ||||||||||||||||||
676 | } never executed: end of block | 0 | ||||||||||||||||||
677 | } | - | ||||||||||||||||||
678 | assert( !pCur->curIntKey || !pCur->pKey ); | - | ||||||||||||||||||
679 | return rc; executed 177866 times by 17 tests: return rc; Executed by:
| 177866 | ||||||||||||||||||
680 | } | - | ||||||||||||||||||
681 | - | |||||||||||||||||||
682 | /* | - | ||||||||||||||||||
683 | ** Save the current cursor position in the variables BtCursor.nKey | - | ||||||||||||||||||
684 | ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. | - | ||||||||||||||||||
685 | ** | - | ||||||||||||||||||
686 | ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) | - | ||||||||||||||||||
687 | ** prior to calling this routine. | - | ||||||||||||||||||
688 | */ | - | ||||||||||||||||||
689 | static int saveCursorPosition(BtCursor *pCur){ | - | ||||||||||||||||||
690 | int rc; | - | ||||||||||||||||||
691 | - | |||||||||||||||||||
692 | assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); | - | ||||||||||||||||||
693 | assert( 0==pCur->pKey ); | - | ||||||||||||||||||
694 | assert( cursorHoldsMutex(pCur) ); | - | ||||||||||||||||||
695 | - | |||||||||||||||||||
696 | if( pCur->eState==CURSOR_SKIPNEXT ){
| 15237-26005 | ||||||||||||||||||
697 | pCur->eState = CURSOR_VALID; | - | ||||||||||||||||||
698 | }else{ executed 15237 times by 1 test: end of block Executed by:
| 15237 | ||||||||||||||||||
699 | pCur->skipNext = 0; | - | ||||||||||||||||||
700 | } executed 26005 times by 13 tests: end of block Executed by:
| 26005 | ||||||||||||||||||
701 | - | |||||||||||||||||||
702 | rc = saveCursorKey(pCur); | - | ||||||||||||||||||
703 | if( rc==SQLITE_OK ){
| 0-41242 | ||||||||||||||||||
704 | btreeReleaseAllCursorPages(pCur); | - | ||||||||||||||||||
705 | pCur->eState = CURSOR_REQUIRESEEK; | - | ||||||||||||||||||
706 | } executed 41242 times by 13 tests: end of block Executed by:
| 41242 | ||||||||||||||||||
707 | - | |||||||||||||||||||
708 | pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast); | - | ||||||||||||||||||
709 | return rc; executed 41242 times by 13 tests: return rc; Executed by:
| 41242 | ||||||||||||||||||
710 | } | - | ||||||||||||||||||
711 | - | |||||||||||||||||||
712 | /* Forward reference */ | - | ||||||||||||||||||
713 | static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); | - | ||||||||||||||||||
714 | - | |||||||||||||||||||
715 | /* | - | ||||||||||||||||||
716 | ** Save the positions of all cursors (except pExcept) that are open on | - | ||||||||||||||||||
717 | ** the table with root-page iRoot. "Saving the cursor position" means that | - | ||||||||||||||||||
718 | ** the location in the btree is remembered in such a way that it can be | - | ||||||||||||||||||
719 | ** moved back to the same spot after the btree has been modified. This | - | ||||||||||||||||||
720 | ** routine is called just before cursor pExcept is used to modify the | - | ||||||||||||||||||
721 | ** table, for example in BtreeDelete() or BtreeInsert(). | - | ||||||||||||||||||
722 | ** | - | ||||||||||||||||||
723 | ** If there are two or more cursors on the same btree, then all such | - | ||||||||||||||||||
724 | ** cursors should have their BTCF_Multiple flag set. The btreeCursor() | - | ||||||||||||||||||
725 | ** routine enforces that rule. This routine only needs to be called in | - | ||||||||||||||||||
726 | ** the uncommon case when pExpect has the BTCF_Multiple flag set. | - | ||||||||||||||||||
727 | ** | - | ||||||||||||||||||
728 | ** If pExpect!=NULL and if no other cursors are found on the same root-page, | - | ||||||||||||||||||
729 | ** then the BTCF_Multiple flag on pExpect is cleared, to avoid another | - | ||||||||||||||||||
730 | ** pointless call to this routine. | - | ||||||||||||||||||
731 | ** | - | ||||||||||||||||||
732 | ** Implementation note: This routine merely checks to see if any cursors | - | ||||||||||||||||||
733 | ** need to be saved. It calls out to saveCursorsOnList() in the (unusual) | - | ||||||||||||||||||
734 | ** event that cursors are in need to being saved. | - | ||||||||||||||||||
735 | */ | - | ||||||||||||||||||
736 | static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ | - | ||||||||||||||||||
737 | BtCursor *p; | - | ||||||||||||||||||
738 | assert( sqlite3_mutex_held(pBt->mutex) ); | - | ||||||||||||||||||
739 | assert( pExcept==0 || pExcept->pBt==pBt ); | - | ||||||||||||||||||
740 | for(p=pBt->pCursor; p; p=p->pNext){
| 160273-1517187 | ||||||||||||||||||
741 | if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break; executed 802570 times by 15 tests: break; Executed by:
| 334-924161 | ||||||||||||||||||
742 | } executed 714617 times by 18 tests: end of block Executed by:
| 714617 | ||||||||||||||||||
743 | if( p ) return saveCursorsOnList(p, iRoot, pExcept); executed 802570 times by 15 tests: return saveCursorsOnList(p, iRoot, pExcept); Executed by:
| 160273-802570 | ||||||||||||||||||
744 | if( pExcept ) pExcept->curFlags &= ~BTCF_Multiple; executed 604 times by 1 test: pExcept->curFlags &= ~0x20; Executed by:
| 604-159669 | ||||||||||||||||||
745 | return SQLITE_OK; executed 160273 times by 71 tests: return 0; Executed by:
| 160273 | ||||||||||||||||||
746 | } | - | ||||||||||||||||||
747 | - | |||||||||||||||||||
748 | /* This helper routine to saveAllCursors does the actual work of saving | - | ||||||||||||||||||
749 | ** the cursors if and when a cursor is found that actually requires saving. | - | ||||||||||||||||||
750 | ** The common case is that no cursors need to be saved, so this routine is | - | ||||||||||||||||||
751 | ** broken out from its caller to avoid unnecessary stack pointer movement. | - | ||||||||||||||||||
752 | */ | - | ||||||||||||||||||
753 | static int SQLITE_NOINLINE saveCursorsOnList( | - | ||||||||||||||||||
754 | BtCursor *p, /* The first cursor that needs saving */ | - | ||||||||||||||||||
755 | Pgno iRoot, /* Only save cursor with this iRoot. Save all if zero */ | - | ||||||||||||||||||
756 | BtCursor *pExcept /* Do not save this cursor */ | - | ||||||||||||||||||
757 | ){ | - | ||||||||||||||||||
758 | do{ | - | ||||||||||||||||||
759 | if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
| 536-7358596 | ||||||||||||||||||
760 | if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
| 15237-5580337 | ||||||||||||||||||
761 | int rc = saveCursorPosition(p); | - | ||||||||||||||||||
762 | if( SQLITE_OK!=rc ){
| 0-41036 | ||||||||||||||||||
763 | return rc; never executed: return rc; | 0 | ||||||||||||||||||
764 | } | - | ||||||||||||||||||
765 | }else{ executed 41036 times by 13 tests: end of block Executed by:
| 41036 | ||||||||||||||||||
766 | testcase( p->iPage>=0 ); | - | ||||||||||||||||||
767 | btreeReleaseAllCursorPages(p); | - | ||||||||||||||||||
768 | } executed 5565100 times by 5 tests: end of block Executed by:
| 5565100 | ||||||||||||||||||
769 | } | - | ||||||||||||||||||
770 | p = p->pNext; | - | ||||||||||||||||||
771 | }while( p ); executed 7495087 times by 15 tests: end of block Executed by:
| 802570-7495087 | ||||||||||||||||||
772 | return SQLITE_OK; executed 802570 times by 15 tests: return 0; Executed by:
| 802570 | ||||||||||||||||||
773 | } | - | ||||||||||||||||||
774 | - | |||||||||||||||||||
775 | /* | - | ||||||||||||||||||
776 | ** Clear the current cursor position. | - | ||||||||||||||||||
777 | */ | - | ||||||||||||||||||
778 | void sqlite3BtreeClearCursor(BtCursor *pCur){ | - | ||||||||||||||||||
779 | assert( cursorHoldsMutex(pCur) ); | - | ||||||||||||||||||
780 | sqlite3_free(pCur->pKey); | - | ||||||||||||||||||
781 | pCur->pKey = 0; | - | ||||||||||||||||||
782 | pCur->eState = CURSOR_INVALID; | - | ||||||||||||||||||
783 | } executed 42078 times by 1 test: end of block Executed by:
| 42078 | ||||||||||||||||||
784 | - | |||||||||||||||||||
785 | /* | - | ||||||||||||||||||
786 | ** In this version of BtreeMoveto, pKey is a packed index record | - | ||||||||||||||||||
787 | ** such as is generated by the OP_MakeRecord opcode. Unpack the | - | ||||||||||||||||||
788 | ** record and then call BtreeMovetoUnpacked() to do the work. | - | ||||||||||||||||||
789 | */ | - | ||||||||||||||||||
790 | static int btreeMoveto( | - | ||||||||||||||||||
791 | BtCursor *pCur, /* Cursor open on the btree to be searched */ | - | ||||||||||||||||||
792 | const void *pKey, /* Packed key if the btree is an index */ | - | ||||||||||||||||||
793 | i64 nKey, /* Integer key for tables. Size of pKey for indices */ | - | ||||||||||||||||||
794 | int bias, /* Bias search to the high end */ | - | ||||||||||||||||||
795 | int *pRes /* Write search results here */ | - | ||||||||||||||||||
796 | ){ | - | ||||||||||||||||||
797 | int rc; /* Status code */ | - | ||||||||||||||||||
798 | UnpackedRecord *pIdxKey; /* Unpacked index key */ | - | ||||||||||||||||||
799 | - | |||||||||||||||||||
800 | if( pKey ){
| 49445-137562 | ||||||||||||||||||
801 | assert( nKey==(i64)(int)nKey ); | - | ||||||||||||||||||
802 | pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); | - | ||||||||||||||||||
803 | if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; never executed: return 7;
| 0-49445 | ||||||||||||||||||
804 | sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey); | - | ||||||||||||||||||
805 | if( pIdxKey->nField==0 ){
| 0-49445 | ||||||||||||||||||
806 | rc = SQLITE_CORRUPT_BKPT; | - | ||||||||||||||||||
807 | goto moveto_done; never executed: goto moveto_done; | 0 | ||||||||||||||||||
808 | } | - | ||||||||||||||||||
809 | }else{ executed 49445 times by 1 test: end of block Executed by:
| 49445 | ||||||||||||||||||
810 | pIdxKey = 0; | - | ||||||||||||||||||
811 | } executed 137562 times by 5 tests: end of block Executed by:
| 137562 | ||||||||||||||||||
812 | rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); | - | ||||||||||||||||||
813 | moveto_done: code before this statement executed 187007 times by 5 tests: moveto_done: Executed by:
| 187007 | ||||||||||||||||||
814 | if( pIdxKey ){
| 49445-137562 | ||||||||||||||||||
815 | sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); | - | ||||||||||||||||||
816 | } executed 49445 times by 1 test: end of block Executed by:
| 49445 | ||||||||||||||||||
817 | return rc; executed 187007 times by 5 tests: return rc; Executed by:
| 187007 | ||||||||||||||||||
818 | } | - | ||||||||||||||||||
819 | - | |||||||||||||||||||
820 | /* | - | ||||||||||||||||||
821 | ** Restore the cursor to the position it was in (or as close to as possible) | - | ||||||||||||||||||
822 | ** when saveCursorPosition() was called. Note that this call deletes the | - | ||||||||||||||||||
823 | ** saved position info stored by saveCursorPosition(), so there can be | - | ||||||||||||||||||
824 | ** at most one effective restoreCursorPosition() call after each | - | ||||||||||||||||||
825 | ** saveCursorPosition(). | - | ||||||||||||||||||
826 | */ | - | ||||||||||||||||||
827 | static int btreeRestoreCursorPosition(BtCursor *pCur){ | - | ||||||||||||||||||
828 | int rc; | - | ||||||||||||||||||
829 | int skipNext; | - | ||||||||||||||||||
830 | assert( cursorOwnsBtShared(pCur) ); | - | ||||||||||||||||||
831 | assert( pCur->eState>=CURSOR_REQUIRESEEK ); | - | ||||||||||||||||||
832 | if( pCur->eState==CURSOR_FAULT ){
| 4-137954 | ||||||||||||||||||
833 | return pCur->skipNext; executed 4 times by 1 test: return pCur->skipNext; Executed by:
| 4 | ||||||||||||||||||
834 | } | - | ||||||||||||||||||
835 | pCur->eState = CURSOR_INVALID; | - | ||||||||||||||||||
836 | rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); | - | ||||||||||||||||||
837 | if( rc==SQLITE_OK ){
| 0-137954 | ||||||||||||||||||
838 | sqlite3_free(pCur->pKey); | - | ||||||||||||||||||
839 | pCur->pKey = 0; | - | ||||||||||||||||||
840 | assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); | - | ||||||||||||||||||
841 | pCur->skipNext |= skipNext; | - | ||||||||||||||||||
842 | if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
| 796-136623 | ||||||||||||||||||
843 | pCur->eState = CURSOR_SKIPNEXT; | - | ||||||||||||||||||
844 | } executed 135827 times by 5 tests: end of block Executed by:
| 135827 | ||||||||||||||||||
845 | } executed 137954 times by 5 tests: end of block Executed by:
| 137954 | ||||||||||||||||||
846 | return rc; executed 137954 times by 5 tests: return rc; Executed by:
| 137954 | ||||||||||||||||||
847 | } | - | ||||||||||||||||||
848 | - | |||||||||||||||||||
849 | #define restoreCursorPosition(p) \ | - | ||||||||||||||||||
850 | (p->eState>=CURSOR_REQUIRESEEK ? \ | - | ||||||||||||||||||
851 | btreeRestoreCursorPosition(p) : \ | - | ||||||||||||||||||
852 | SQLITE_OK) | - | ||||||||||||||||||
853 | - | |||||||||||||||||||
854 | /* | - | ||||||||||||||||||
855 | ** Determine whether or not a cursor has moved from the position where | - | ||||||||||||||||||
856 | ** it was last placed, or has been invalidated for any other reason. | - | ||||||||||||||||||
857 | ** Cursors can move when the row they are pointing at is deleted out | - | ||||||||||||||||||
858 | ** from under them, for example. Cursor might also move if a btree | - | ||||||||||||||||||
859 | ** is rebalanced. | - | ||||||||||||||||||
860 | ** | - | ||||||||||||||||||
861 | ** Calling this routine with a NULL cursor pointer returns false. | - | ||||||||||||||||||
862 | ** | - | ||||||||||||||||||
863 | ** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor | - | ||||||||||||||||||
864 | ** back to where it ought to be if this routine returns true. | - | ||||||||||||||||||
865 | */ | - | ||||||||||||||||||
866 | int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ | - | ||||||||||||||||||
867 | assert( EIGHT_BYTE_ALIGNMENT(pCur) | - | ||||||||||||||||||
868 | || pCur==sqlite3BtreeFakeValidCursor() ); | - | ||||||||||||||||||
869 | assert( offsetof(BtCursor, eState)==0 ); | - | ||||||||||||||||||
870 | assert( sizeof(pCur->eState)==1 ); | - | ||||||||||||||||||
871 | return CURSOR_VALID != *(u8*)pCur; executed 38716744 times by 434 tests: return 0 != *(u8*)pCur; Executed by:
| 38716744 | ||||||||||||||||||
872 | } | - | ||||||||||||||||||
873 | - | |||||||||||||||||||
874 | /* | - | ||||||||||||||||||
875 | ** Return a pointer to a fake BtCursor object that will always answer | - | ||||||||||||||||||
876 | ** false to the sqlite3BtreeCursorHasMoved() routine above. The fake | - | ||||||||||||||||||
877 | ** cursor returned must not be used with any other Btree interface. | - | ||||||||||||||||||
878 | */ | - | ||||||||||||||||||
879 | BtCursor *sqlite3BtreeFakeValidCursor(void){ | - | ||||||||||||||||||
880 | static u8 fakeCursor = CURSOR_VALID; | - | ||||||||||||||||||
881 | assert( offsetof(BtCursor, eState)==0 ); | - | ||||||||||||||||||
882 | return (BtCursor*)&fakeCursor; executed 58178 times by 1 test: return (BtCursor*)&fakeCursor; Executed by:
| 58178 | ||||||||||||||||||
883 | } | - | ||||||||||||||||||
884 | - | |||||||||||||||||||
885 | /* | - | ||||||||||||||||||
886 | ** This routine restores a cursor back to its original position after it | - | ||||||||||||||||||
887 | ** has been moved by some outside activity (such as a btree rebalance or | - | ||||||||||||||||||
888 | ** a row having been deleted out from under the cursor). | - | ||||||||||||||||||
889 | ** | - | ||||||||||||||||||
890 | ** On success, the *pDifferentRow parameter is false if the cursor is left | - | ||||||||||||||||||
891 | ** pointing at exactly the same row. *pDifferntRow is the row the cursor | - | ||||||||||||||||||
892 | ** was pointing to has been deleted, forcing the cursor to point to some | - | ||||||||||||||||||
893 | ** nearby row. | - | ||||||||||||||||||
894 | ** | - | ||||||||||||||||||
895 | ** This routine should only be called for a cursor that just returned | - | ||||||||||||||||||
896 | ** TRUE from sqlite3BtreeCursorHasMoved(). | - | ||||||||||||||||||
897 | */ | - | ||||||||||||||||||
898 | int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ | - | ||||||||||||||||||
899 | int rc; | - | ||||||||||||||||||
900 | - | |||||||||||||||||||
901 | assert( pCur!=0 ); | - | ||||||||||||||||||
902 | assert( pCur->eState!=CURSOR_VALID ); | - | ||||||||||||||||||
903 | rc = restoreCursorPosition(pCur);
| 50-1606 | ||||||||||||||||||
904 | if( rc ){
| 1-1655 | ||||||||||||||||||
905 | *pDifferentRow = 1; | - | ||||||||||||||||||
906 | return rc; executed 1 time by 1 test: return rc; Executed by:
| 1 | ||||||||||||||||||
907 | } | - | ||||||||||||||||||
908 | if( pCur->eState!=CURSOR_VALID ){
| 24-1631 | ||||||||||||||||||
909 | *pDifferentRow = 1; | - | ||||||||||||||||||
910 | }else{ executed 1631 times by 1 test: end of block Executed by:
| 1631 | ||||||||||||||||||
911 | assert( pCur->skipNext==0 ); | - | ||||||||||||||||||
912 | *pDifferentRow = 0; | - | ||||||||||||||||||
913 | } executed 24 times by 1 test: end of block Executed by:
| 24 | ||||||||||||||||||
914 | return SQLITE_OK; executed 1655 times by 1 test: return 0; Executed by:
| 1655 | ||||||||||||||||||
915 | } | - | ||||||||||||||||||
916 | - | |||||||||||||||||||
917 | #ifdef SQLITE_ENABLE_CURSOR_HINTS | - | ||||||||||||||||||
918 | /* | - | ||||||||||||||||||
919 | ** Provide hints to the cursor. The particular hint given (and the type | - | ||||||||||||||||||
920 | ** and number of the varargs parameters) is determined by the eHintType | - | ||||||||||||||||||
921 | ** parameter. See the definitions of the BTREE_HINT_* macros for details. | - | ||||||||||||||||||
922 | */ | - | ||||||||||||||||||
923 | void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ | - | ||||||||||||||||||
924 | /* Used only by system that substitute their own storage engine */ | - | ||||||||||||||||||
925 | } | - | ||||||||||||||||||
926 | #endif | - | ||||||||||||||||||
927 | - | |||||||||||||||||||
928 | /* | - | ||||||||||||||||||
929 | ** Provide flag hints to the cursor. | - | ||||||||||||||||||
930 | */ | - | ||||||||||||||||||
931 | void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ | - | ||||||||||||||||||
932 | assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); | - | ||||||||||||||||||
933 | pCur->hints = x; | - | ||||||||||||||||||
934 | } executed 1856225 times by 435 tests: end of block Executed by:
| 1856225 | ||||||||||||||||||
935 | - | |||||||||||||||||||
936 | - | |||||||||||||||||||
937 | #ifndef SQLITE_OMIT_AUTOVACUUM | - | ||||||||||||||||||
938 | /* | - | ||||||||||||||||||
939 | ** Given a page number of a regular database page, return the page | - | ||||||||||||||||||
940 | ** number for the pointer-map page that contains the entry for the | - | ||||||||||||||||||
941 | ** input page number. | - | ||||||||||||||||||
942 | ** | - | ||||||||||||||||||
943 | ** Return 0 (not a valid page) for pgno==1 since there is | - | ||||||||||||||||||
944 | ** no pointer map associated with page 1. The integrity_check logic | - | ||||||||||||||||||
945 | ** requires that ptrmapPageno(*,1)!=1. | - | ||||||||||||||||||
946 | */ | - | ||||||||||||||||||
947 | static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ | - | ||||||||||||||||||
948 | int nPagesPerMapPage; | - | ||||||||||||||||||
949 | Pgno iPtrMap, ret; | - | ||||||||||||||||||
950 | assert( sqlite3_mutex_held(pBt->mutex) ); | - | ||||||||||||||||||
951 | if( pgno<2 ) return 0; executed 15391 times by 14 tests: return 0; Executed by:
| 15391-2199107 | ||||||||||||||||||
952 | nPagesPerMapPage = (pBt->usableSize/5)+1; | - | ||||||||||||||||||
953 | iPtrMap = (pgno-2)/nPagesPerMapPage; | - | ||||||||||||||||||
954 | ret = (iPtrMap*nPagesPerMapPage) + 2; | - | ||||||||||||||||||
955 | if( ret==PENDING_BYTE_PAGE(pBt) ){
| 98669-2100438 | ||||||||||||||||||
956 | ret++; | - | ||||||||||||||||||
957 | } executed 98669 times by 2 tests: end of block Executed by:
| 98669 | ||||||||||||||||||
958 | return ret; executed 2199107 times by 15 tests: return ret; Executed by:
| 2199107 | ||||||||||||||||||
959 | } | - | ||||||||||||||||||
960 | - | |||||||||||||||||||
961 | /* | - | ||||||||||||||||||
962 | ** Write an entry into the pointer map. | - | ||||||||||||||||||
963 | ** | - | ||||||||||||||||||
964 | ** This routine updates the pointer map entry for page number 'key' | - | ||||||||||||||||||
965 | ** so that it maps to type 'eType' and parent page number 'pgno'. | - | ||||||||||||||||||
966 | ** | - | ||||||||||||||||||
967 | ** If *pRC is initially non-zero (non-SQLITE_OK) then this routine is | - | ||||||||||||||||||
968 | ** a no-op. If an error occurs, the appropriate error code is written | - | ||||||||||||||||||
969 | ** into *pRC. | - | ||||||||||||||||||
970 | */ | - | ||||||||||||||||||
971 | static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ | - | ||||||||||||||||||
972 | DbPage *pDbPage; /* The pointer map page */ | - | ||||||||||||||||||
973 | u8 *pPtrmap; /* The pointer map data */ | - | ||||||||||||||||||
974 | Pgno iPtrmap; /* The pointer map page number */ | - | ||||||||||||||||||
975 | int offset; /* Offset in pointer map page */ | - | ||||||||||||||||||
976 | int rc; /* Return code from subfunctions */ | - | ||||||||||||||||||
977 | - | |||||||||||||||||||
978 | if( *pRC ) return; executed 5 times by 1 test: return; Executed by:
| 5-243598 | ||||||||||||||||||
979 | - | |||||||||||||||||||
980 | assert( sqlite3_mutex_held(pBt->mutex) ); | - | ||||||||||||||||||
981 | /* The master-journal page number must never be used as a pointer map page */ | - | ||||||||||||||||||
982 | assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); | - | ||||||||||||||||||
983 | - | |||||||||||||||||||
984 | assert( pBt->autoVacuum ); | - | ||||||||||||||||||
985 | if( key==0 ){
| 1-243597 | ||||||||||||||||||
986 | *pRC = SQLITE_CORRUPT_BKPT; | - | ||||||||||||||||||
987 | return; executed 1 time by 1 test: return; Executed by:
| 1 | ||||||||||||||||||
988 | } | - | ||||||||||||||||||
989 | iPtrmap = PTRMAP_PAGENO(pBt, key); | - | ||||||||||||||||||
990 | rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); | - | ||||||||||||||||||
991 | if( rc!=SQLITE_OK ){
| 8-243589 | ||||||||||||||||||
992 | *pRC = rc; | - | ||||||||||||||||||
993 | return; executed 8 times by 1 test: return; Executed by:
| 8 | ||||||||||||||||||
994 | } | - | ||||||||||||||||||
995 | offset = PTRMAP_PTROFFSET(iPtrmap, key); | - | ||||||||||||||||||
996 | if( offset<0 ){
| 0-243589 | ||||||||||||||||||
997 | *pRC = SQLITE_CORRUPT_BKPT; | - | ||||||||||||||||||
998 | goto ptrmap_exit; never executed: goto ptrmap_exit; | 0 | ||||||||||||||||||
999 | } | - | ||||||||||||||||||
1000 | assert( offset <= (int)pBt->usableSize-5 ); | - | ||||||||||||||||||
1001 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); | - | ||||||||||||||||||
1002 | - | |||||||||||||||||||
1003 | if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
| 9059-135539 | ||||||||||||||||||
1004 | TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); | - | ||||||||||||||||||
1005 | *pRC= rc = sqlite3PagerWrite(pDbPage); | - | ||||||||||||||||||
1006 | if( rc==SQLITE_OK ){
| 30-234500 | ||||||||||||||||||
1007 | pPtrmap[offset] = eType; | - | ||||||||||||||||||
1008 | put4byte(&pPtrmap[offset+1], parent); | - | ||||||||||||||||||
1009 | } executed 234500 times by 4 tests: end of block Executed by:
| 234500 | ||||||||||||||||||
1010 | } executed 234530 times by 4 tests: end of block Executed by:
| 234530 | ||||||||||||||||||
1011 | - | |||||||||||||||||||
1012 | ptrmap_exit: code before this statement executed 243589 times by 4 tests: ptrmap_exit: Executed by:
| 243589 | ||||||||||||||||||
1013 | sqlite3PagerUnref(pDbPage); | - | ||||||||||||||||||
1014 | } executed 243589 times by 4 tests: end of block Executed by:
| 243589 | ||||||||||||||||||
1015 | - | |||||||||||||||||||
1016 | /* | - | ||||||||||||||||||
1017 | ** Read an entry from the pointer map. | - | ||||||||||||||||||
1018 | ** | - | ||||||||||||||||||
1019 | ** This routine retrieves the pointer map entry for page 'key', writing | - | ||||||||||||||||||
1020 | ** the type and parent page number to *pEType and *pPgno respectively. | - | ||||||||||||||||||
1021 | ** An error code is returned if something goes wrong, otherwise SQLITE_OK. | - | ||||||||||||||||||
1022 | */ | - | ||||||||||||||||||
1023 | static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ | - | ||||||||||||||||||
1024 | DbPage *pDbPage; /* The pointer map page */ | - | ||||||||||||||||||
1025 | int iPtrmap; /* Pointer map page index */ | - | ||||||||||||||||||
1026 | u8 *pPtrmap; /* Pointer map page data */ | - | ||||||||||||||||||
1027 | int offset; /* Offset of entry in pointer map */ | - | ||||||||||||||||||
1028 | int rc; | - | ||||||||||||||||||
1029 | - | |||||||||||||||||||
1030 | assert( sqlite3_mutex_held(pBt->mutex) ); | - | ||||||||||||||||||
1031 | - | |||||||||||||||||||
1032 | iPtrmap = PTRMAP_PAGENO(pBt, key); | - | ||||||||||||||||||
1033 | rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0); | - | ||||||||||||||||||
1034 | if( rc!=0 ){
| 0-298203 | ||||||||||||||||||
1035 | return rc; never executed: return rc; | 0 | ||||||||||||||||||
1036 | } | - | ||||||||||||||||||
1037 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); | - | ||||||||||||||||||
1038 | - | |||||||||||||||||||
1039 | offset = PTRMAP_PTROFFSET(iPtrmap, key); | - | ||||||||||||||||||
1040 | if( offset<0 ){
| 0-298203 | ||||||||||||||||||
1041 | sqlite3PagerUnref(pDbPage); | - | ||||||||||||||||||
1042 | return SQLITE_CORRUPT_BKPT; never executed: return sqlite3CorruptError(1042); | 0 | ||||||||||||||||||
1043 | } | - | ||||||||||||||||||
1044 | assert( offset <= (int)pBt->usableSize-5 ); | - | ||||||||||||||||||
1045 | assert( pEType!=0 ); | - | ||||||||||||||||||
1046 | *pEType = pPtrmap[offset]; | - | ||||||||||||||||||
1047 | if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); executed 290806 times by 4 tests: *pPgno = sqlite3Get4byte(&pPtrmap[offset+1]); Executed by:
| 7397-290806 | ||||||||||||||||||
1048 | - | |||||||||||||||||||
1049 | sqlite3PagerUnref(pDbPage); | - | ||||||||||||||||||
1050 | if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); executed 28 times by 1 test: return sqlite3CorruptError(1050); Executed by:
| 14-298189 | ||||||||||||||||||
1051 | return SQLITE_OK; executed 298175 times by 4 tests: return 0; Executed by:
| 298175 | ||||||||||||||||||
1052 | } | - | ||||||||||||||||||
1053 | - | |||||||||||||||||||
1054 | #else /* if defined SQLITE_OMIT_AUTOVACUUM */ | - | ||||||||||||||||||
1055 | #define ptrmapPut(w,x,y,z,rc) | - | ||||||||||||||||||
1056 | #define ptrmapGet(w,x,y,z) SQLITE_OK | - | ||||||||||||||||||
1057 | #define ptrmapPutOvflPtr(x, y, rc) | - | ||||||||||||||||||
1058 | #endif | - | ||||||||||||||||||
1059 | - | |||||||||||||||||||
1060 | /* | - | ||||||||||||||||||
1061 | ** Given a btree page and a cell index (0 means the first cell on | - | ||||||||||||||||||
1062 | ** the page, 1 means the second cell, and so forth) return a pointer | - | ||||||||||||||||||
1063 | ** to the cell content. | - | ||||||||||||||||||
1064 | ** | - | ||||||||||||||||||
1065 | ** findCellPastPtr() does the same except it skips past the initial | - | ||||||||||||||||||
1066 | ** 4-byte child pointer found on interior pages, if there is one. | - | ||||||||||||||||||
1067 | ** | - | ||||||||||||||||||
1068 | ** This routine works only for pages that do not contain overflow cells. | - | ||||||||||||||||||
1069 | */ | - | ||||||||||||||||||
1070 | #define findCell(P,I) \ | - | ||||||||||||||||||
1071 | ((P)->aData + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)]))) | - | ||||||||||||||||||
1072 | #define findCellPastPtr(P,I) \ | - | ||||||||||||||||||
1073 | ((P)->aDataOfst + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)]))) | - | ||||||||||||||||||
1074 | - | |||||||||||||||||||
1075 | - | |||||||||||||||||||
1076 | /* | - | ||||||||||||||||||
1077 | ** This is common tail processing for btreeParseCellPtr() and | - | ||||||||||||||||||
1078 | ** btreeParseCellPtrIndex() for the case when the cell does not fit entirely | - | ||||||||||||||||||
1079 | ** on a single B-tree page. Make necessary adjustments to the CellInfo | - | ||||||||||||||||||
1080 | ** structure. | - | ||||||||||||||||||
1081 | */ | - | ||||||||||||||||||
1082 | static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( | - | ||||||||||||||||||
1083 | MemPage *pPage, /* Page containing the cell */ | - | ||||||||||||||||||
1084 | u8 *pCell, /* Pointer to the cell text. */ | - | ||||||||||||||||||
1085 | CellInfo *pInfo /* Fill in this structure */ | - | ||||||||||||||||||
1086 | ){ | - | ||||||||||||||||||
1087 | /* If the payload will not fit completely on the local page, we have | - | ||||||||||||||||||
1088 | ** to decide how much to store locally and how much to spill onto | - | ||||||||||||||||||
1089 | ** overflow pages. The strategy is to minimize the amount of unused | - | ||||||||||||||||||
1090 | ** space on overflow pages while keeping the amount of local storage | - | ||||||||||||||||||
1091 | ** in between minLocal and maxLocal. | - | ||||||||||||||||||
1092 | ** | - | ||||||||||||||||||
1093 | ** Warning: changing the way overflow payload is distributed in any | - | ||||||||||||||||||
1094 | ** way will result in an incompatible file format. | - | ||||||||||||||||||
1095 | */ | - | ||||||||||||||||||
1096 | int minLocal; /* Minimum amount of payload held locally */ | - | ||||||||||||||||||
1097 | int maxLocal; /* Maximum amount of payload held locally */ | - | ||||||||||||||||||
1098 | int surplus; /* Overflow payload available for local storage */ | - | ||||||||||||||||||
1099 | - | |||||||||||||||||||
1100 | minLocal = pPage->minLocal; | - | ||||||||||||||||||
1101 | maxLocal = pPage->maxLocal; | - | ||||||||||||||||||
1102 | surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4); | - | ||||||||||||||||||
1103 | testcase( surplus==maxLocal ); | - | ||||||||||||||||||
1104 | testcase( surplus==maxLocal+1 ); | - | ||||||||||||||||||
1105 | if( surplus <= maxLocal ){
| 234484-1988974 | ||||||||||||||||||
1106 | pInfo->nLocal = (u16)surplus; | - | ||||||||||||||||||
1107 | }else{ executed 234484 times by 6 tests: end of block Executed by:
| 234484 | ||||||||||||||||||
1108 | pInfo->nLocal = (u16)minLocal; | - | ||||||||||||||||||
1109 | } executed 1988974 times by 363 tests: end of block Executed by:
| 1988974 | ||||||||||||||||||
1110 | pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; | - | ||||||||||||||||||
1111 | } executed 2223458 times by 366 tests: end of block Executed by:
| 2223458 | ||||||||||||||||||
1112 | - | |||||||||||||||||||
1113 | /* | - | ||||||||||||||||||
1114 | ** The following routines are implementations of the MemPage.xParseCell() | - | ||||||||||||||||||
1115 | ** method. | - | ||||||||||||||||||
1116 | ** | - | ||||||||||||||||||
1117 | ** Parse a cell content block and fill in the CellInfo structure. | - | ||||||||||||||||||
1118 | ** | - | ||||||||||||||||||
1119 | ** btreeParseCellPtr() => table btree leaf nodes | - | ||||||||||||||||||
1120 | ** btreeParseCellNoPayload() => table btree internal nodes | - | ||||||||||||||||||
1121 | ** btreeParseCellPtrIndex() => index btree nodes | - | ||||||||||||||||||
1122 | ** | - | ||||||||||||||||||
1123 | ** There is also a wrapper function btreeParseCell() that works for | - | ||||||||||||||||||
1124 | ** all MemPage types and that references the cell by index rather than | - | ||||||||||||||||||
1125 | ** by pointer. | - | ||||||||||||||||||
1126 | */ | - | ||||||||||||||||||
1127 | static void btreeParseCellPtrNoPayload( | - | ||||||||||||||||||
1128 | MemPage *pPage, /* Page containing the cell */ | - | ||||||||||||||||||
1129 | u8 *pCell, /* Pointer to the cell text. */ | - | ||||||||||||||||||
1130 | CellInfo *pInfo /* Fill in this structure */ | - | ||||||||||||||||||
1131 | ){ | - | ||||||||||||||||||
1132 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | - | ||||||||||||||||||
1133 | assert( pPage->leaf==0 ); | - | ||||||||||||||||||
1134 | assert( pPage->childPtrSize==4 ); | - | ||||||||||||||||||
1135 | #ifndef SQLITE_DEBUG | - | ||||||||||||||||||
1136 | UNUSED_PARAMETER(pPage); | - | ||||||||||||||||||
1137 | #endif | - | ||||||||||||||||||
1138 | pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); | - | ||||||||||||||||||
1139 | pInfo->nPayload = 0; | - | ||||||||||||||||||
1140 | pInfo->nLocal = 0; | - | ||||||||||||||||||
1141 | pInfo->pPayload = 0; | - | ||||||||||||||||||
1142 | return; executed 1045684 times by 11 tests: return; Executed by:
| 1045684 | ||||||||||||||||||
1143 | } | - | ||||||||||||||||||
1144 | static void btreeParseCellPtr( | - | ||||||||||||||||||
1145 | MemPage *pPage, /* Page containing the cell */ | - | ||||||||||||||||||
1146 | u8 *pCell, /* Pointer to the cell text. */ | - | ||||||||||||||||||
1147 | CellInfo *pInfo /* Fill in this structure */ | - | ||||||||||||||||||
1148 | ){ | - | ||||||||||||||||||
1149 | u8 *pIter; /* For scanning through pCell */ | - | ||||||||||||||||||
1150 | u32 nPayload; /* Number of bytes of cell payload */ | - | ||||||||||||||||||
1151 | u64 iKey; /* Extracted Key value */ | - | ||||||||||||||||||
1152 | - | |||||||||||||||||||
1153 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | - | ||||||||||||||||||
1154 | assert( pPage->leaf==0 || pPage->leaf==1 ); | - | ||||||||||||||||||
1155 | assert( pPage->intKeyLeaf ); | - | ||||||||||||||||||
1156 | assert( pPage->childPtrSize==0 ); | - | ||||||||||||||||||
1157 | pIter = pCell; | - | ||||||||||||||||||
1158 | - | |||||||||||||||||||
1159 | /* The next block of code is equivalent to: | - | ||||||||||||||||||
1160 | ** | - | ||||||||||||||||||
1161 | ** pIter += getVarint32(pIter, nPayload); | - | ||||||||||||||||||
1162 | ** | - | ||||||||||||||||||
1163 | ** The code is inlined to avoid a function call. | - | ||||||||||||||||||
1164 | */ | - | ||||||||||||||||||
1165 | nPayload = *pIter; | - | ||||||||||||||||||
1166 | if( nPayload>=0x80 ){
| 6147891-21728801 | ||||||||||||||||||
1167 | u8 *pEnd = &pIter[8]; | - | ||||||||||||||||||
1168 | nPayload &= 0x7f; | - | ||||||||||||||||||
1169 | do{ | - | ||||||||||||||||||
1170 | nPayload = (nPayload<<7) | (*++pIter & 0x7f); | - | ||||||||||||||||||
1171 | }while( (*pIter)>=0x80 && pIter<pEnd ); executed 6149960 times by 371 tests: end of block Executed by:
| 0-6149960 | ||||||||||||||||||
1172 | } executed 6147891 times by 371 tests: end of block Executed by:
| 6147891 | ||||||||||||||||||
1173 | pIter++; | - | ||||||||||||||||||
1174 | - | |||||||||||||||||||
1175 | /* The next block of code is equivalent to: | - | ||||||||||||||||||
1176 | ** | - | ||||||||||||||||||
1177 | ** pIter += getVarint(pIter, (u64*)&pInfo->nKey); | - | ||||||||||||||||||
1178 | ** | - | ||||||||||||||||||
1179 | ** The code is inlined to avoid a function call. | - | ||||||||||||||||||
1180 | */ | - | ||||||||||||||||||
1181 | iKey = *pIter; | - | ||||||||||||||||||
1182 | if( iKey>=0x80 ){
| 7150982-20725710 | ||||||||||||||||||
1183 | u8 *pEnd = &pIter[7]; | - | ||||||||||||||||||
1184 | iKey &= 0x7f; | - | ||||||||||||||||||
1185 | while(1){ | - | ||||||||||||||||||
1186 | iKey = (iKey<<7) | (*++pIter & 0x7f); | - | ||||||||||||||||||
1187 | if( (*pIter)<0x80 ) break; executed 20690487 times by 8 tests: break; Executed by:
| 8785356-20690487 | ||||||||||||||||||
1188 | if( pIter>=pEnd ){
| 35223-8750133 | ||||||||||||||||||
1189 | iKey = (iKey<<8) | *++pIter; | - | ||||||||||||||||||
1190 | break; executed 35223 times by 1 test: break; Executed by:
| 35223 | ||||||||||||||||||
1191 | } | - | ||||||||||||||||||
1192 | } executed 8750133 times by 1 test: end of block Executed by:
| 8750133 | ||||||||||||||||||
1193 | } executed 20725710 times by 8 tests: end of block Executed by:
| 20725710 | ||||||||||||||||||
1194 | pIter++; | - | ||||||||||||||||||
1195 | - | |||||||||||||||||||
1196 | pInfo->nKey = *(i64*)&iKey; | - | ||||||||||||||||||
1197 | pInfo->nPayload = nPayload; | - | ||||||||||||||||||
1198 | pInfo->pPayload = pIter; | - | ||||||||||||||||||
1199 | testcase( nPayload==pPage->maxLocal ); | - | ||||||||||||||||||
1200 | testcase( nPayload==pPage->maxLocal+1 ); | - | ||||||||||||||||||
1201 | if( nPayload<=pPage->maxLocal ){
| 677737-27198955 | ||||||||||||||||||
1202 | /* This is the (easy) common case where the entire payload fits | - | ||||||||||||||||||
1203 | ** on the local page. No overflow is required. | - | ||||||||||||||||||
1204 | */ | - | ||||||||||||||||||
1205 | pInfo->nSize = nPayload + (u16)(pIter - pCell); | - | ||||||||||||||||||
1206 | if( pInfo->nSize<4 ) pInfo->nSize = 4; executed 82184 times by 1 test: pInfo->nSize = 4; Executed by:
| 82184-27116771 | ||||||||||||||||||
1207 | pInfo->nLocal = (u16)nPayload; | - | ||||||||||||||||||
1208 | }else{ executed 27198955 times by 434 tests: end of block Executed by:
| 27198955 | ||||||||||||||||||
1209 | btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); | - | ||||||||||||||||||
1210 | } executed 677737 times by 12 tests: end of block Executed by:
| 677737 | ||||||||||||||||||
1211 | } | - | ||||||||||||||||||
1212 | static void btreeParseCellPtrIndex( | - | ||||||||||||||||||
1213 | MemPage *pPage, /* Page containing the cell */ | - | ||||||||||||||||||
1214 | u8 *pCell, /* Pointer to the cell text. */ | - | ||||||||||||||||||
1215 | CellInfo *pInfo /* Fill in this structure */ | - | ||||||||||||||||||
1216 | ){ | - | ||||||||||||||||||
1217 | u8 *pIter; /* For scanning through pCell */ | - | ||||||||||||||||||
1218 | u32 nPayload; /* Number of bytes of cell payload */ | - | ||||||||||||||||||
1219 | - | |||||||||||||||||||
1220 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | - | ||||||||||||||||||
1221 | assert( pPage->leaf==0 || pPage->leaf==1 ); | - | ||||||||||||||||||
1222 | assert( pPage->intKeyLeaf==0 ); | - | ||||||||||||||||||
1223 | pIter = pCell + pPage->childPtrSize; | - | ||||||||||||||||||
1224 | nPayload = *pIter; | - | ||||||||||||||||||
1225 | if( nPayload>=0x80 ){
| 1656399-3905391 | ||||||||||||||||||
1226 | u8 *pEnd = &pIter[8]; | - | ||||||||||||||||||
1227 | nPayload &= 0x7f; | - | ||||||||||||||||||
1228 | do{ | - | ||||||||||||||||||
1229 | nPayload = (nPayload<<7) | (*++pIter & 0x7f); | - | ||||||||||||||||||
1230 | }while( *(pIter)>=0x80 && pIter<pEnd ); executed 1656970 times by 364 tests: end of block Executed by:
| 0-1656970 | ||||||||||||||||||
1231 | } executed 1656399 times by 364 tests: end of block Executed by:
| 1656399 | ||||||||||||||||||
1232 | pIter++; | - | ||||||||||||||||||
1233 | pInfo->nKey = nPayload; | - | ||||||||||||||||||
1234 | pInfo->nPayload = nPayload; | - | ||||||||||||||||||
1235 | pInfo->pPayload = pIter; | - | ||||||||||||||||||
1236 | testcase( nPayload==pPage->maxLocal ); | - | ||||||||||||||||||
1237 | testcase( nPayload==pPage->maxLocal+1 ); | - | ||||||||||||||||||
1238 | if( nPayload<=pPage->maxLocal ){
| 1545721-4016069 | ||||||||||||||||||
1239 | /* This is the (easy) common case where the entire payload fits | - | ||||||||||||||||||
1240 | ** on the local page. No overflow is required. | - | ||||||||||||||||||
1241 | */ | - | ||||||||||||||||||
1242 | pInfo->nSize = nPayload + (u16)(pIter - pCell); | - | ||||||||||||||||||
1243 | if( pInfo->nSize<4 ) pInfo->nSize = 4; executed 1330 times by 1 test: pInfo->nSize = 4; Executed by:
| 1330-4014739 | ||||||||||||||||||
1244 | pInfo->nLocal = (u16)nPayload; | - | ||||||||||||||||||
1245 | }else{ executed 4016069 times by 12 tests: end of block Executed by:
| 4016069 | ||||||||||||||||||
1246 | btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo); | - | ||||||||||||||||||
1247 | } executed 1545721 times by 360 tests: end of block Executed by:
| 1545721 | ||||||||||||||||||
1248 | } | - | ||||||||||||||||||
1249 | static void btreeParseCell( | - | ||||||||||||||||||
1250 | MemPage *pPage, /* Page containing the cell */ | - | ||||||||||||||||||
1251 | int iCell, /* The cell index. First cell is 0 */ | - | ||||||||||||||||||
1252 | CellInfo *pInfo /* Fill in this structure */ | - | ||||||||||||||||||
1253 | ){ | - | ||||||||||||||||||
1254 | pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo); | - | ||||||||||||||||||
1255 | } executed 25531974 times by 434 tests: end of block Executed by:
| 25531974 | ||||||||||||||||||
1256 | - | |||||||||||||||||||
1257 | /* | - | ||||||||||||||||||
1258 | ** The following routines are implementations of the MemPage.xCellSize | - | ||||||||||||||||||
1259 | ** method. | - | ||||||||||||||||||
1260 | ** | - | ||||||||||||||||||
1261 | ** Compute the total number of bytes that a Cell needs in the cell | - | ||||||||||||||||||
1262 | ** data area of the btree-page. The return number includes the cell | - | ||||||||||||||||||
1263 | ** data header and the local payload, but not any overflow page or | - | ||||||||||||||||||
1264 | ** the space used by the cell pointer. | - | ||||||||||||||||||
1265 | ** | - | ||||||||||||||||||
1266 | ** cellSizePtrNoPayload() => table internal nodes | - | ||||||||||||||||||
1267 | ** cellSizePtr() => all index nodes & table leaf nodes | - | ||||||||||||||||||
1268 | */ | - | ||||||||||||||||||
1269 | static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ | - | ||||||||||||||||||
1270 | u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */ | - | ||||||||||||||||||
1271 | u8 *pEnd; /* End mark for a varint */ | - | ||||||||||||||||||
1272 | u32 nSize; /* Size value to return */ | - | ||||||||||||||||||
1273 | - | |||||||||||||||||||
1274 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
1275 | /* The value returned by this function should always be the same as | - | ||||||||||||||||||
1276 | ** the (CellInfo.nSize) value found by doing a full parse of the | - | ||||||||||||||||||
1277 | ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of | - | ||||||||||||||||||
1278 | ** this function verifies that this invariant is not violated. */ | - | ||||||||||||||||||
1279 | CellInfo debuginfo; | - | ||||||||||||||||||
1280 | pPage->xParseCell(pPage, pCell, &debuginfo); | - | ||||||||||||||||||
1281 | #endif | - | ||||||||||||||||||
1282 | - | |||||||||||||||||||
1283 | nSize = *pIter; | - | ||||||||||||||||||
1284 | if( nSize>=0x80 ){
| 2437989-6690991 | ||||||||||||||||||
1285 | pEnd = &pIter[8]; | - | ||||||||||||||||||
1286 | nSize &= 0x7f; | - | ||||||||||||||||||
1287 | do{ | - | ||||||||||||||||||
1288 | nSize = (nSize<<7) | (*++pIter & 0x7f); | - | ||||||||||||||||||
1289 | }while( *(pIter)>=0x80 && pIter<pEnd ); executed 2438917 times by 332 tests: end of block Executed by:
| 0-2438917 | ||||||||||||||||||
1290 | } executed 2437989 times by 332 tests: end of block Executed by:
| 2437989 | ||||||||||||||||||
1291 | pIter++; | - | ||||||||||||||||||
1292 | if( pPage->intKey ){
| 3577329-5551651 | ||||||||||||||||||
1293 | /* pIter now points at the 64-bit integer key value, a variable length | - | ||||||||||||||||||
1294 | ** integer. The following block moves pIter to point at the first byte | - | ||||||||||||||||||
1295 | ** past the end of the key value. */ | - | ||||||||||||||||||
1296 | pEnd = &pIter[9]; | - | ||||||||||||||||||
1297 | while( (*pIter++)&0x80 && pIter<pEnd ); executed 4429462 times by 6 tests: ; Executed by:
| 197-4429659 | ||||||||||||||||||
1298 | } executed 3577329 times by 26 tests: end of block Executed by:
| 3577329 | ||||||||||||||||||
1299 | testcase( nSize==pPage->maxLocal ); | - | ||||||||||||||||||
1300 | testcase( nSize==pPage->maxLocal+1 ); | - | ||||||||||||||||||
1301 | if( nSize<=pPage->maxLocal ){
| 245452-8883528 | ||||||||||||||||||
1302 | nSize += (u32)(pIter - pCell); | - | ||||||||||||||||||
1303 | if( nSize<4 ) nSize = 4; executed 894 times by 1 test: nSize = 4; Executed by:
| 894-8882634 | ||||||||||||||||||
1304 | }else{ executed 8883528 times by 25 tests: end of block Executed by:
| 8883528 | ||||||||||||||||||
1305 | int minLocal = pPage->minLocal; | - | ||||||||||||||||||
1306 | nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); | - | ||||||||||||||||||
1307 | testcase( nSize==pPage->maxLocal ); | - | ||||||||||||||||||
1308 | testcase( nSize==pPage->maxLocal+1 ); | - | ||||||||||||||||||
1309 | if( nSize>pPage->maxLocal ){
| 64469-180983 | ||||||||||||||||||
1310 | nSize = minLocal; | - | ||||||||||||||||||
1311 | } executed 180983 times by 324 tests: end of block Executed by:
| 180983 | ||||||||||||||||||
1312 | nSize += 4 + (u16)(pIter - pCell); | - | ||||||||||||||||||
1313 | } executed 245452 times by 325 tests: end of block Executed by:
| 245452 | ||||||||||||||||||
1314 | assert( nSize==debuginfo.nSize || CORRUPT_DB ); | - | ||||||||||||||||||
1315 | return (u16)nSize; executed 9128980 times by 339 tests: return (u16)nSize; Executed by:
| 9128980 | ||||||||||||||||||
1316 | } | - | ||||||||||||||||||
1317 | static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){ | - | ||||||||||||||||||
1318 | u8 *pIter = pCell + 4; /* For looping over bytes of pCell */ | - | ||||||||||||||||||
1319 | u8 *pEnd; /* End mark for a varint */ | - | ||||||||||||||||||
1320 | - | |||||||||||||||||||
1321 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
1322 | /* The value returned by this function should always be the same as | - | ||||||||||||||||||
1323 | ** the (CellInfo.nSize) value found by doing a full parse of the | - | ||||||||||||||||||
1324 | ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of | - | ||||||||||||||||||
1325 | ** this function verifies that this invariant is not violated. */ | - | ||||||||||||||||||
1326 | CellInfo debuginfo; | - | ||||||||||||||||||
1327 | pPage->xParseCell(pPage, pCell, &debuginfo); | - | ||||||||||||||||||
1328 | #else | - | ||||||||||||||||||
1329 | UNUSED_PARAMETER(pPage); | - | ||||||||||||||||||
1330 | #endif | - | ||||||||||||||||||
1331 | - | |||||||||||||||||||
1332 | assert( pPage->childPtrSize==4 ); | - | ||||||||||||||||||
1333 | pEnd = pIter + 9; | - | ||||||||||||||||||
1334 | while( (*pIter++)&0x80 && pIter<pEnd ); executed 2538054 times by 4 tests: ; Executed by:
| 29-2538083 | ||||||||||||||||||
1335 | assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB ); | - | ||||||||||||||||||
1336 | return (u16)(pIter - pCell); executed 2376016 times by 9 tests: return (u16)(pIter - pCell); Executed by:
| 2376016 | ||||||||||||||||||
1337 | } | - | ||||||||||||||||||
1338 | - | |||||||||||||||||||
1339 | - | |||||||||||||||||||
1340 | #ifdef SQLITE_DEBUG | - | ||||||||||||||||||
1341 | /* This variation on cellSizePtr() is used inside of assert() statements | - | ||||||||||||||||||
1342 | ** only. */ | - | ||||||||||||||||||
1343 | static u16 cellSize(MemPage *pPage, int iCell){ | - | ||||||||||||||||||
1344 | return pPage->xCellSize(pPage, findCell(pPage, iCell)); | - | ||||||||||||||||||
1345 | } | - | ||||||||||||||||||
1346 | #endif | - | ||||||||||||||||||
1347 | - | |||||||||||||||||||
1348 | #ifndef SQLITE_OMIT_AUTOVACUUM | - | ||||||||||||||||||
1349 | /* | - | ||||||||||||||||||
1350 | ** If the cell pCell, part of page pPage contains a pointer | - | ||||||||||||||||||
1351 | ** to an overflow page, insert an entry into the pointer-map | - | ||||||||||||||||||
1352 | ** for the overflow page. | - | ||||||||||||||||||
1353 | */ | - | ||||||||||||||||||
1354 | static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ | - | ||||||||||||||||||
1355 | CellInfo info; | - | ||||||||||||||||||
1356 | if( *pRC ) return; executed 4 times by 1 test: return; Executed by:
| 4-795784 | ||||||||||||||||||
1357 | assert( pCell!=0 ); | - | ||||||||||||||||||
1358 | pPage->xParseCell(pPage, pCell, &info); | - | ||||||||||||||||||
1359 | if( info.nLocal<info.nPayload ){
| 34050-761734 | ||||||||||||||||||
1360 | Pgno ovfl = get4byte(&pCell[info.nSize-4]); | - | ||||||||||||||||||
1361 | ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); | - | ||||||||||||||||||
1362 | } executed 34050 times by 3 tests: end of block Executed by:
| 34050 | ||||||||||||||||||
1363 | } executed 795784 times by 4 tests: end of block Executed by:
| 795784 | ||||||||||||||||||
1364 | #endif | - | ||||||||||||||||||
1365 | - | |||||||||||||||||||
1366 | - | |||||||||||||||||||
1367 | /* | - | ||||||||||||||||||
1368 | ** Defragment the page given. This routine reorganizes cells within the | - | ||||||||||||||||||
1369 | ** page so that there are no free-blocks on the free-block list. | - | ||||||||||||||||||
1370 | ** | - | ||||||||||||||||||
1371 | ** Parameter nMaxFrag is the maximum amount of fragmented space that may be | - | ||||||||||||||||||
1372 | ** present in the page after this routine returns. | - | ||||||||||||||||||
1373 | ** | - | ||||||||||||||||||
1374 | ** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a | - | ||||||||||||||||||
1375 | ** b-tree page so that there are no freeblocks or fragment bytes, all | - | ||||||||||||||||||
1376 | ** unused bytes are contained in the unallocated space region, and all | - | ||||||||||||||||||
1377 | ** cells are packed tightly at the end of the page. | - | ||||||||||||||||||
1378 | */ | - | ||||||||||||||||||
1379 | static int defragmentPage(MemPage *pPage, int nMaxFrag){ | - | ||||||||||||||||||
1380 | int i; /* Loop counter */ | - | ||||||||||||||||||
1381 | int pc; /* Address of the i-th cell */ | - | ||||||||||||||||||
1382 | int hdr; /* Offset to the page header */ | - | ||||||||||||||||||
1383 | int size; /* Size of a cell */ | - | ||||||||||||||||||
1384 | int usableSize; /* Number of usable bytes on a page */ | - | ||||||||||||||||||
1385 | int cellOffset; /* Offset to the cell pointer array */ | - | ||||||||||||||||||
1386 | int cbrk; /* Offset to the cell content area */ | - | ||||||||||||||||||
1387 | int nCell; /* Number of cells on the page */ | - | ||||||||||||||||||
1388 | unsigned char *data; /* The page data */ | - | ||||||||||||||||||
1389 | unsigned char *temp; /* Temp area for cell content */ | - | ||||||||||||||||||
1390 | unsigned char *src; /* Source of content */ | - | ||||||||||||||||||
1391 | int iCellFirst; /* First allowable cell index */ | - | ||||||||||||||||||
1392 | int iCellLast; /* Last possible cell index */ | - | ||||||||||||||||||
1393 | - | |||||||||||||||||||
1394 | assert( sqlite3PagerIswriteable(pPage->pDbPage) ); | - | ||||||||||||||||||
1395 | assert( pPage->pBt!=0 ); | - | ||||||||||||||||||
1396 | assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); | - | ||||||||||||||||||
1397 | assert( pPage->nOverflow==0 ); | - | ||||||||||||||||||
1398 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | - | ||||||||||||||||||
1399 | temp = 0; | - | ||||||||||||||||||
1400 | src = data = pPage->aData; | - | ||||||||||||||||||
1401 | hdr = pPage->hdrOffset; | - | ||||||||||||||||||
1402 | cellOffset = pPage->cellOffset; | - | ||||||||||||||||||
1403 | nCell = pPage->nCell; | - | ||||||||||||||||||
1404 | assert( nCell==get2byte(&data[hdr+3]) ); | - | ||||||||||||||||||
1405 | iCellFirst = cellOffset + 2*nCell; | - | ||||||||||||||||||
1406 | usableSize = pPage->pBt->usableSize; | - | ||||||||||||||||||
1407 | - | |||||||||||||||||||
1408 | /* This block handles pages with two or fewer free blocks and nMaxFrag | - | ||||||||||||||||||
1409 | ** or fewer fragmented bytes. In this case it is faster to move the | - | ||||||||||||||||||
1410 | ** two (or one) blocks of cells using memmove() and add the required | - | ||||||||||||||||||
1411 | ** offsets to each pointer in the cell-pointer array than it is to | - | ||||||||||||||||||
1412 | ** reconstruct the entire page. */ | - | ||||||||||||||||||
1413 | if( (int)data[hdr+7]<=nMaxFrag ){
| 2533-26211 | ||||||||||||||||||
1414 | int iFree = get2byte(&data[hdr+1]); | - | ||||||||||||||||||
1415 | if( iFree ){
| 1-26210 | ||||||||||||||||||
1416 | int iFree2 = get2byte(&data[iFree]); | - | ||||||||||||||||||
1417 | - | |||||||||||||||||||
1418 | /* pageFindSlot() has already verified that free blocks are sorted | - | ||||||||||||||||||
1419 | ** in order of offset within the page, and that no block extends | - | ||||||||||||||||||
1420 | ** past the end of the page. Provided the two free slots do not | - | ||||||||||||||||||
1421 | ** overlap, this guarantees that the memmove() calls below will not | - | ||||||||||||||||||
1422 | ** overwrite the usableSize byte buffer, even if the database page | - | ||||||||||||||||||
1423 | ** is corrupt. */ | - | ||||||||||||||||||
1424 | assert( iFree2==0 || iFree2>iFree ); | - | ||||||||||||||||||
1425 | assert( iFree+get2byte(&data[iFree+2]) <= usableSize ); | - | ||||||||||||||||||
1426 | assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize ); | - | ||||||||||||||||||
1427 | - | |||||||||||||||||||
1428 | if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
| 1-24334 | ||||||||||||||||||
1429 | u8 *pEnd = &data[cellOffset + nCell*2]; | - | ||||||||||||||||||
1430 | u8 *pAddr; | - | ||||||||||||||||||
1431 | int sz2 = 0; | - | ||||||||||||||||||
1432 | int sz = get2byte(&data[iFree+2]); | - | ||||||||||||||||||
1433 | int top = get2byte(&data[hdr+5]); | - | ||||||||||||||||||
1434 | if( top>=iFree ){
| 0-26014 | ||||||||||||||||||
1435 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1435); | 0 | ||||||||||||||||||
1436 | } | - | ||||||||||||||||||
1437 | if( iFree2 ){
| 1680-24334 | ||||||||||||||||||
1438 | assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */ | - | ||||||||||||||||||
1439 | sz2 = get2byte(&data[iFree2+2]); | - | ||||||||||||||||||
1440 | assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize ); | - | ||||||||||||||||||
1441 | memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); | - | ||||||||||||||||||
1442 | sz += sz2; | - | ||||||||||||||||||
1443 | } executed 1680 times by 2 tests: end of block Executed by:
| 1680 | ||||||||||||||||||
1444 | cbrk = top+sz; | - | ||||||||||||||||||
1445 | assert( cbrk+(iFree-top) <= usableSize ); | - | ||||||||||||||||||
1446 | memmove(&data[cbrk], &data[top], iFree-top); | - | ||||||||||||||||||
1447 | for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
| 26014-507323 | ||||||||||||||||||
1448 | pc = get2byte(pAddr); | - | ||||||||||||||||||
1449 | if( pc<iFree ){ put2byte(pAddr, pc+sz); } executed 280058 times by 3 tests: end of block Executed by:
| 227265-280058 | ||||||||||||||||||
1450 | else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); } executed 14302 times by 2 tests: end of block Executed by:
| 14302-212963 | ||||||||||||||||||
1451 | } executed 507323 times by 3 tests: end of block Executed by:
| 507323 | ||||||||||||||||||
1452 | goto defragment_out; executed 26014 times by 3 tests: goto defragment_out; Executed by:
| 26014 | ||||||||||||||||||
1453 | } | - | ||||||||||||||||||
1454 | } executed 196 times by 1 test: end of block Executed by:
| 196 | ||||||||||||||||||
1455 | } executed 197 times by 1 test: end of block Executed by:
| 197 | ||||||||||||||||||
1456 | - | |||||||||||||||||||
1457 | cbrk = usableSize; | - | ||||||||||||||||||
1458 | iCellLast = usableSize - 4; | - | ||||||||||||||||||
1459 | for(i=0; i<nCell; i++){
| 2730-171575 | ||||||||||||||||||
1460 | u8 *pAddr; /* The i-th cell pointer */ | - | ||||||||||||||||||
1461 | pAddr = &data[cellOffset + i*2]; | - | ||||||||||||||||||
1462 | pc = get2byte(pAddr); | - | ||||||||||||||||||
1463 | testcase( pc==iCellFirst ); | - | ||||||||||||||||||
1464 | testcase( pc==iCellLast ); | - | ||||||||||||||||||
1465 | /* These conditions have already been verified in btreeInitPage() | - | ||||||||||||||||||
1466 | ** if PRAGMA cell_size_check=ON. | - | ||||||||||||||||||
1467 | */ | - | ||||||||||||||||||
1468 | if( pc<iCellFirst || pc>iCellLast ){
| 0-171575 | ||||||||||||||||||
1469 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1469); | 0 | ||||||||||||||||||
1470 | } | - | ||||||||||||||||||
1471 | assert( pc>=iCellFirst && pc<=iCellLast ); | - | ||||||||||||||||||
1472 | size = pPage->xCellSize(pPage, &src[pc]); | - | ||||||||||||||||||
1473 | cbrk -= size; | - | ||||||||||||||||||
1474 | if( cbrk<iCellFirst || pc+size>usableSize ){
| 0-171575 | ||||||||||||||||||
1475 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1475); | 0 | ||||||||||||||||||
1476 | } | - | ||||||||||||||||||
1477 | assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); | - | ||||||||||||||||||
1478 | testcase( cbrk+size==usableSize ); | - | ||||||||||||||||||
1479 | testcase( pc+size==usableSize ); | - | ||||||||||||||||||
1480 | put2byte(pAddr, cbrk); | - | ||||||||||||||||||
1481 | if( temp==0 ){
| 8557-163018 | ||||||||||||||||||
1482 | int x; | - | ||||||||||||||||||
1483 | if( cbrk==pc ) continue; executed 6636 times by 1 test: continue; Executed by:
| 1921-6636 | ||||||||||||||||||
1484 | temp = sqlite3PagerTempSpace(pPage->pBt->pPager); | - | ||||||||||||||||||
1485 | x = get2byte(&data[hdr+5]); | - | ||||||||||||||||||
1486 | memcpy(&temp[x], &data[x], (cbrk+size) - x); | - | ||||||||||||||||||
1487 | src = temp; | - | ||||||||||||||||||
1488 | } executed 1921 times by 1 test: end of block Executed by:
| 1921 | ||||||||||||||||||
1489 | memcpy(&data[cbrk], &src[pc], size); | - | ||||||||||||||||||
1490 | } executed 164939 times by 1 test: end of block Executed by:
| 164939 | ||||||||||||||||||
1491 | data[hdr+7] = 0; | - | ||||||||||||||||||
1492 | - | |||||||||||||||||||
1493 | defragment_out: code before this statement executed 2730 times by 1 test: defragment_out: Executed by:
| 2730 | ||||||||||||||||||
1494 | if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
| 1-28743 | ||||||||||||||||||
1495 | return SQLITE_CORRUPT_PAGE(pPage); executed 1 time by 1 test: return sqlite3CorruptError(1495); Executed by:
| 1 | ||||||||||||||||||
1496 | } | - | ||||||||||||||||||
1497 | assert( cbrk>=iCellFirst ); | - | ||||||||||||||||||
1498 | put2byte(&data[hdr+5], cbrk); | - | ||||||||||||||||||
1499 | data[hdr+1] = 0; | - | ||||||||||||||||||
1500 | data[hdr+2] = 0; | - | ||||||||||||||||||
1501 | memset(&data[iCellFirst], 0, cbrk-iCellFirst); | - | ||||||||||||||||||
1502 | assert( sqlite3PagerIswriteable(pPage->pDbPage) ); | - | ||||||||||||||||||
1503 | return SQLITE_OK; executed 28743 times by 3 tests: return 0; Executed by:
| 28743 | ||||||||||||||||||
1504 | } | - | ||||||||||||||||||
1505 | - | |||||||||||||||||||
1506 | /* | - | ||||||||||||||||||
1507 | ** Search the free-list on page pPg for space to store a cell nByte bytes in | - | ||||||||||||||||||
1508 | ** size. If one can be found, return a pointer to the space and remove it | - | ||||||||||||||||||
1509 | ** from the free-list. | - | ||||||||||||||||||
1510 | ** | - | ||||||||||||||||||
1511 | ** If no suitable space can be found on the free-list, return NULL. | - | ||||||||||||||||||
1512 | ** | - | ||||||||||||||||||
1513 | ** This function may detect corruption within pPg. If corruption is | - | ||||||||||||||||||
1514 | ** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. | - | ||||||||||||||||||
1515 | ** | - | ||||||||||||||||||
1516 | ** Slots on the free list that are between 1 and 3 bytes larger than nByte | - | ||||||||||||||||||
1517 | ** will be ignored if adding the extra space to the fragmentation count | - | ||||||||||||||||||
1518 | ** causes the fragmentation count to exceed 60. | - | ||||||||||||||||||
1519 | */ | - | ||||||||||||||||||
1520 | static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ | - | ||||||||||||||||||
1521 | const int hdr = pPg->hdrOffset; | - | ||||||||||||||||||
1522 | u8 * const aData = pPg->aData; | - | ||||||||||||||||||
1523 | int iAddr = hdr + 1; | - | ||||||||||||||||||
1524 | int pc = get2byte(&aData[iAddr]); | - | ||||||||||||||||||
1525 | int x; | - | ||||||||||||||||||
1526 | int usableSize = pPg->pBt->usableSize; | - | ||||||||||||||||||
1527 | int size; /* Size of the free slot */ | - | ||||||||||||||||||
1528 | - | |||||||||||||||||||
1529 | assert( pc>0 ); | - | ||||||||||||||||||
1530 | while( pc<=usableSize-4 ){
| 0-3835600 | ||||||||||||||||||
1531 | /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each | - | ||||||||||||||||||
1532 | ** freeblock form a big-endian integer which is the size of the freeblock | - | ||||||||||||||||||
1533 | ** in bytes, including the 4-byte header. */ | - | ||||||||||||||||||
1534 | size = get2byte(&aData[pc+2]); | - | ||||||||||||||||||
1535 | if( (x = size - nByte)>=0 ){
| 297937-3537663 | ||||||||||||||||||
1536 | testcase( x==4 ); | - | ||||||||||||||||||
1537 | testcase( x==3 ); | - | ||||||||||||||||||
1538 | if( size+pc > usableSize ){
| 0-3537663 | ||||||||||||||||||
1539 | *pRc = SQLITE_CORRUPT_PAGE(pPg); | - | ||||||||||||||||||
1540 | return 0; never executed: return 0; | 0 | ||||||||||||||||||
1541 | }else if( x<4 ){
| 1076151-2461512 | ||||||||||||||||||
1542 | /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total | - | ||||||||||||||||||
1543 | ** number of bytes in fragments may not exceed 60. */ | - | ||||||||||||||||||
1544 | if( aData[hdr+7]>57 ) return 0; executed 51 times by 1 test: return 0; Executed by:
| 51-1076100 | ||||||||||||||||||
1545 | - | |||||||||||||||||||
1546 | /* Remove the slot from the free-list. Update the number of | - | ||||||||||||||||||
1547 | ** fragmented bytes within the page. */ | - | ||||||||||||||||||
1548 | memcpy(&aData[iAddr], &aData[pc], 2); | - | ||||||||||||||||||
1549 | aData[hdr+7] += (u8)x; | - | ||||||||||||||||||
1550 | }else{ executed 1076100 times by 334 tests: end of block Executed by:
| 1076100 | ||||||||||||||||||
1551 | /* The slot remains on the free-list. Reduce its size to account | - | ||||||||||||||||||
1552 | ** for the portion used by the new allocation. */ | - | ||||||||||||||||||
1553 | put2byte(&aData[pc+2], x); | - | ||||||||||||||||||
1554 | } executed 2461512 times by 337 tests: end of block Executed by:
| 2461512 | ||||||||||||||||||
1555 | return &aData[pc + x]; executed 3537612 times by 354 tests: return &aData[pc + x]; Executed by:
| 3537612 | ||||||||||||||||||
1556 | } | - | ||||||||||||||||||
1557 | iAddr = pc; | - | ||||||||||||||||||
1558 | pc = get2byte(&aData[pc]); | - | ||||||||||||||||||
1559 | if( pc<iAddr+size ) break; executed 164660 times by 20 tests: break; Executed by:
| 133277-164660 | ||||||||||||||||||
1560 | } executed 133277 times by 6 tests: end of block Executed by:
| 133277 | ||||||||||||||||||
1561 | if( pc ){
| 1-164659 | ||||||||||||||||||
1562 | *pRc = SQLITE_CORRUPT_PAGE(pPg); | - | ||||||||||||||||||
1563 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
1564 | - | |||||||||||||||||||
1565 | return 0; executed 164660 times by 20 tests: return 0; Executed by:
| 164660 | ||||||||||||||||||
1566 | } | - | ||||||||||||||||||
1567 | - | |||||||||||||||||||
1568 | /* | - | ||||||||||||||||||
1569 | ** Allocate nByte bytes of space from within the B-Tree page passed | - | ||||||||||||||||||
1570 | ** as the first argument. Write into *pIdx the index into pPage->aData[] | - | ||||||||||||||||||
1571 | ** of the first byte of allocated space. Return either SQLITE_OK or | - | ||||||||||||||||||
1572 | ** an error code (usually SQLITE_CORRUPT). | - | ||||||||||||||||||
1573 | ** | - | ||||||||||||||||||
1574 | ** The caller guarantees that there is sufficient space to make the | - | ||||||||||||||||||
1575 | ** allocation. This routine might need to defragment in order to bring | - | ||||||||||||||||||
1576 | ** all the space together, however. This routine will avoid using | - | ||||||||||||||||||
1577 | ** the first two bytes past the cell pointer area since presumably this | - | ||||||||||||||||||
1578 | ** allocation is being made in order to insert a new cell, so we will | - | ||||||||||||||||||
1579 | ** also end up needing a new cell pointer. | - | ||||||||||||||||||
1580 | */ | - | ||||||||||||||||||
1581 | static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ | - | ||||||||||||||||||
1582 | const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ | - | ||||||||||||||||||
1583 | u8 * const data = pPage->aData; /* Local cache of pPage->aData */ | - | ||||||||||||||||||
1584 | int top; /* First byte of cell content area */ | - | ||||||||||||||||||
1585 | int rc = SQLITE_OK; /* Integer return code */ | - | ||||||||||||||||||
1586 | int gap; /* First byte of gap between cell pointers and cell content */ | - | ||||||||||||||||||
1587 | - | |||||||||||||||||||
1588 | assert( sqlite3PagerIswriteable(pPage->pDbPage) ); | - | ||||||||||||||||||
1589 | assert( pPage->pBt ); | - | ||||||||||||||||||
1590 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | - | ||||||||||||||||||
1591 | assert( nByte>=0 ); /* Minimum cell size is 4 */ | - | ||||||||||||||||||
1592 | assert( pPage->nFree>=nByte ); | - | ||||||||||||||||||
1593 | assert( pPage->nOverflow==0 ); | - | ||||||||||||||||||
1594 | assert( nByte < (int)(pPage->pBt->usableSize-8) ); | - | ||||||||||||||||||
1595 | - | |||||||||||||||||||
1596 | assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); | - | ||||||||||||||||||
1597 | gap = pPage->cellOffset + 2*pPage->nCell; | - | ||||||||||||||||||
1598 | assert( gap<=65536 ); | - | ||||||||||||||||||
1599 | /* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size | - | ||||||||||||||||||
1600 | ** and the reserved space is zero (the usual value for reserved space) | - | ||||||||||||||||||
1601 | ** then the cell content offset of an empty page wants to be 65536. | - | ||||||||||||||||||
1602 | ** However, that integer is too large to be stored in a 2-byte unsigned | - | ||||||||||||||||||
1603 | ** integer, so a value of 0 is used in its place. */ | - | ||||||||||||||||||
1604 | top = get2byte(&data[hdr+5]); | - | ||||||||||||||||||
1605 | assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */ | - | ||||||||||||||||||
1606 | if( gap>top ){
| 613-8529244 | ||||||||||||||||||
1607 | if( top==0 && pPage->pBt->usableSize==65536 ){
| 0-613 | ||||||||||||||||||
1608 | top = 65536; | - | ||||||||||||||||||
1609 | }else{ executed 613 times by 1 test: end of block Executed by:
| 613 | ||||||||||||||||||
1610 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1610); | 0 | ||||||||||||||||||
1611 | } | - | ||||||||||||||||||
1612 | } | - | ||||||||||||||||||
1613 | - | |||||||||||||||||||
1614 | /* If there is enough space between gap and top for one more cell pointer | - | ||||||||||||||||||
1615 | ** array entry offset, and if the freelist is not empty, then search the | - | ||||||||||||||||||
1616 | ** freelist looking for a free slot big enough to satisfy the request. | - | ||||||||||||||||||
1617 | */ | - | ||||||||||||||||||
1618 | testcase( gap+2==top ); | - | ||||||||||||||||||
1619 | testcase( gap+1==top ); | - | ||||||||||||||||||
1620 | testcase( gap==top ); | - | ||||||||||||||||||
1621 | if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
| 731-7104893 | ||||||||||||||||||
1622 | u8 *pSpace = pageFindSlot(pPage, nByte, &rc); | - | ||||||||||||||||||
1623 | if( pSpace ){
| 47510-1377911 | ||||||||||||||||||
1624 | assert( pSpace>=data && (pSpace - data)<65536 ); | - | ||||||||||||||||||
1625 | *pIdx = (int)(pSpace - data); | - | ||||||||||||||||||
1626 | return SQLITE_OK; executed 1377911 times by 351 tests: return 0; Executed by:
| 1377911 | ||||||||||||||||||
1627 | }else if( rc ){
| 1-47509 | ||||||||||||||||||
1628 | return rc; executed 1 time by 1 test: return rc; Executed by:
| 1 | ||||||||||||||||||
1629 | } | - | ||||||||||||||||||
1630 | } executed 47509 times by 20 tests: end of block Executed by:
| 47509 | ||||||||||||||||||
1631 | - | |||||||||||||||||||
1632 | /* The request could not be fulfilled using a freelist slot. Check | - | ||||||||||||||||||
1633 | ** to see if defragmentation is necessary. | - | ||||||||||||||||||
1634 | */ | - | ||||||||||||||||||
1635 | testcase( gap+2+nByte==top ); | - | ||||||||||||||||||
1636 | if( gap+2+nByte>top ){
| 27708-7124237 | ||||||||||||||||||
1637 | assert( pPage->nCell>0 || CORRUPT_DB ); | - | ||||||||||||||||||
1638 | rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); | - | ||||||||||||||||||
1639 | if( rc ) return rc; executed 1 time by 1 test: return rc; Executed by:
| 1-27707 | ||||||||||||||||||
1640 | top = get2byteNotZero(&data[hdr+5]); | - | ||||||||||||||||||
1641 | assert( gap+2+nByte<=top ); | - | ||||||||||||||||||
1642 | } executed 27707 times by 3 tests: end of block Executed by:
| 27707 | ||||||||||||||||||
1643 | - | |||||||||||||||||||
1644 | - | |||||||||||||||||||
1645 | /* Allocate memory from the gap in between the cell pointer array | - | ||||||||||||||||||
1646 | ** and the cell content area. The btreeInitPage() call has already | - | ||||||||||||||||||
1647 | ** validated the freelist. Given that the freelist is valid, there | - | ||||||||||||||||||
1648 | ** is no way that the allocation can extend off the end of the page. | - | ||||||||||||||||||
1649 | ** The assert() below verifies the previous sentence. | - | ||||||||||||||||||
1650 | */ | - | ||||||||||||||||||
1651 | top -= nByte; | - | ||||||||||||||||||
1652 | put2byte(&data[hdr+5], top); | - | ||||||||||||||||||
1653 | assert( top+nByte <= (int)pPage->pBt->usableSize ); | - | ||||||||||||||||||
1654 | *pIdx = top; | - | ||||||||||||||||||
1655 | return SQLITE_OK; executed 7151944 times by 385 tests: return 0; Executed by:
| 7151944 | ||||||||||||||||||
1656 | } | - | ||||||||||||||||||
1657 | - | |||||||||||||||||||
1658 | /* | - | ||||||||||||||||||
1659 | ** Return a section of the pPage->aData to the freelist. | - | ||||||||||||||||||
1660 | ** The first byte of the new free block is pPage->aData[iStart] | - | ||||||||||||||||||
1661 | ** and the size of the block is iSize bytes. | - | ||||||||||||||||||
1662 | ** | - | ||||||||||||||||||
1663 | ** Adjacent freeblocks are coalesced. | - | ||||||||||||||||||
1664 | ** | - | ||||||||||||||||||
1665 | ** Note that even though the freeblock list was checked by btreeInitPage(), | - | ||||||||||||||||||
1666 | ** that routine will not detect overlap between cells or freeblocks. Nor | - | ||||||||||||||||||
1667 | ** does it detect cells or freeblocks that encrouch into the reserved bytes | - | ||||||||||||||||||
1668 | ** at the end of the page. So do additional corruption checks inside this | - | ||||||||||||||||||
1669 | ** routine and return SQLITE_CORRUPT if any problems are found. | - | ||||||||||||||||||
1670 | */ | - | ||||||||||||||||||
1671 | static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ | - | ||||||||||||||||||
1672 | u16 iPtr; /* Address of ptr to next freeblock */ | - | ||||||||||||||||||
1673 | u16 iFreeBlk; /* Address of the next freeblock */ | - | ||||||||||||||||||
1674 | u8 hdr; /* Page header size. 0 or 100 */ | - | ||||||||||||||||||
1675 | u8 nFrag = 0; /* Reduction in fragmentation */ | - | ||||||||||||||||||
1676 | u16 iOrigSize = iSize; /* Original value of iSize */ | - | ||||||||||||||||||
1677 | u16 x; /* Offset to cell content area */ | - | ||||||||||||||||||
1678 | u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ | - | ||||||||||||||||||
1679 | unsigned char *data = pPage->aData; /* Page content */ | - | ||||||||||||||||||
1680 | - | |||||||||||||||||||
1681 | assert( pPage->pBt!=0 ); | - | ||||||||||||||||||
1682 | assert( sqlite3PagerIswriteable(pPage->pDbPage) ); | - | ||||||||||||||||||
1683 | assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); | - | ||||||||||||||||||
1684 | assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); | - | ||||||||||||||||||
1685 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | - | ||||||||||||||||||
1686 | assert( iSize>=4 ); /* Minimum cell size is 4 */ | - | ||||||||||||||||||
1687 | assert( iStart<=pPage->pBt->usableSize-4 ); | - | ||||||||||||||||||
1688 | - | |||||||||||||||||||
1689 | /* The list of freeblocks must be in ascending order. Find the | - | ||||||||||||||||||
1690 | ** spot on the list where iStart should be inserted. | - | ||||||||||||||||||
1691 | */ | - | ||||||||||||||||||
1692 | hdr = pPage->hdrOffset; | - | ||||||||||||||||||
1693 | iPtr = hdr + 1; | - | ||||||||||||||||||
1694 | if( data[iPtr+1]==0 && data[iPtr]==0 ){
| 2650-2670733 | ||||||||||||||||||
1695 | iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */ | - | ||||||||||||||||||
1696 | }else{ executed 2668083 times by 364 tests: end of block Executed by:
| 2668083 | ||||||||||||||||||
1697 | while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
| 1552911-2761655 | ||||||||||||||||||
1698 | if( iFreeBlk<iPtr+4 ){
| 367865-2393790 | ||||||||||||||||||
1699 | if( iFreeBlk==0 ) break; executed 367865 times by 325 tests: break; Executed by:
| 0-367865 | ||||||||||||||||||
1700 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1700); | 0 | ||||||||||||||||||
1701 | } | - | ||||||||||||||||||
1702 | iPtr = iFreeBlk; | - | ||||||||||||||||||
1703 | } executed 2393790 times by 326 tests: end of block Executed by:
| 2393790 | ||||||||||||||||||
1704 | if( iFreeBlk>pPage->pBt->usableSize-4 ){
| 0-1920776 | ||||||||||||||||||
1705 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1705); | 0 | ||||||||||||||||||
1706 | } | - | ||||||||||||||||||
1707 | assert( iFreeBlk>iPtr || iFreeBlk==0 ); | - | ||||||||||||||||||
1708 | - | |||||||||||||||||||
1709 | /* At this point: | - | ||||||||||||||||||
1710 | ** iFreeBlk: First freeblock after iStart, or zero if none | - | ||||||||||||||||||
1711 | ** iPtr: The address of a pointer to iFreeBlk | - | ||||||||||||||||||
1712 | ** | - | ||||||||||||||||||
1713 | ** Check to see if iFreeBlk should be coalesced onto the end of iStart. | - | ||||||||||||||||||
1714 | */ | - | ||||||||||||||||||
1715 | if( iFreeBlk && iEnd+3>=iFreeBlk ){
| 367865-1552911 | ||||||||||||||||||
1716 | nFrag = iFreeBlk - iEnd; | - | ||||||||||||||||||
1717 | if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1717);
| 0-905117 | ||||||||||||||||||
1718 | iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); | - | ||||||||||||||||||
1719 | if( iEnd > pPage->pBt->usableSize ){
| 0-905117 | ||||||||||||||||||
1720 | return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1720); | 0 | ||||||||||||||||||
1721 | } | - | ||||||||||||||||||
1722 | iSize = iEnd - iStart; | - | ||||||||||||||||||
1723 | iFreeBlk = get2byte(&data[iFreeBlk]); | - | ||||||||||||||||||
1724 | } executed 905117 times by 286 tests: end of block Executed by:
| 905117 | ||||||||||||||||||
1725 | - | |||||||||||||||||||
1726 | /* If iPtr is another freeblock (that is, if iPtr is not the freelist | - | ||||||||||||||||||
1727 | ** pointer in the page header) then check to see if iStart should be | - | ||||||||||||||||||
1728 | ** coalesced onto the end of iPtr. | - | ||||||||||||||||||
1729 | */ | - | ||||||||||||||||||
1730 | if( iPtr>hdr+1 ){
| 928687-992089 | ||||||||||||||||||
1731 | int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); | - | ||||||||||||||||||
1732 | if( iPtrEnd+3>=iStart ){
| 395365-596724 | ||||||||||||||||||
1733 | if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1733);
| 0-395365 | ||||||||||||||||||
1734 | nFrag += iStart - iPtrEnd; | - | ||||||||||||||||||
1735 | iSize = iEnd - iPtr; | - | ||||||||||||||||||
1736 | iStart = iPtr; | - | ||||||||||||||||||
1737 | } executed 395365 times by 322 tests: end of block Executed by:
| 395365 | ||||||||||||||||||
1738 | } executed 992089 times by 326 tests: end of block Executed by:
| 992089 | ||||||||||||||||||
1739 | if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1739);
| 0-1920776 | ||||||||||||||||||
1740 | data[hdr+7] -= nFrag; | - | ||||||||||||||||||
1741 | } executed 1920776 times by 333 tests: end of block Executed by:
| 1920776 | ||||||||||||||||||
1742 | x = get2byte(&data[hdr+5]); | - | ||||||||||||||||||
1743 | if( iStart<=x ){
| 2035555-2553304 | ||||||||||||||||||
1744 | /* The new freeblock is at the beginning of the cell content area, | - | ||||||||||||||||||
1745 | ** so just extend the cell content area rather than create another | - | ||||||||||||||||||
1746 | ** freelist entry */ | - | ||||||||||||||||||
1747 | if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage); never executed: return sqlite3CorruptError(1747);
| 0-2035555 | ||||||||||||||||||
1748 | put2byte(&data[hdr+1], iFreeBlk); | - | ||||||||||||||||||
1749 | put2byte(&data[hdr+5], iEnd); | - | ||||||||||||||||||
1750 | }else{ executed 2035555 times by 348 tests: end of block Executed by:
| 2035555 | ||||||||||||||||||
1751 | /* Insert the new freeblock into the freelist */ | - | ||||||||||||||||||
1752 | put2byte(&data[iPtr], iStart); | - | ||||||||||||||||||
1753 | } executed 2553304 times by 357 tests: end of block Executed by:
| 2553304 | ||||||||||||||||||
1754 | if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
| 1-4588858 | ||||||||||||||||||
1755 | /* Overwrite deleted information with zeros when the secure_delete | - | ||||||||||||||||||
1756 | ** option is enabled */ | - | ||||||||||||||||||
1757 | memset(&data[iStart], 0, iSize); | - | ||||||||||||||||||
1758 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
1759 | put2byte(&data[iStart], iFreeBlk); | - | ||||||||||||||||||
1760 | put2byte(&data[iStart+2], iSize); | - | ||||||||||||||||||
1761 | pPage->nFree += iOrigSize; | - | ||||||||||||||||||
1762 | return SQLITE_OK; executed 4588859 times by 367 tests: return 0; Executed by:
| 4588859 | ||||||||||||||||||
1763 | } | - | ||||||||||||||||||
1764 | - | |||||||||||||||||||
1765 | /* | - | ||||||||||||||||||
1766 | ** Decode the flags byte (the first byte of the header) for a page | - | ||||||||||||||||||
1767 | ** and initialize fields of the MemPage structure accordingly. | - | ||||||||||||||||||
1768 | ** | - | ||||||||||||||||||
1769 | ** Only the following combinations are supported. Anything different | - | ||||||||||||||||||
1770 | ** indicates a corrupt database files: | - | ||||||||||||||||||
1771 | ** | - | ||||||||||||||||||
1772 | ** PTF_ZERODATA | - | ||||||||||||||||||
1773 | ** PTF_ZERODATA | PTF_LEAF | - | ||||||||||||||||||
1774 | ** PTF_LEAFDATA | PTF_INTKEY |