wasCSharpSQLite – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.Diagnostics; |
||
3 | using System.Text; |
||
4 | |||
5 | using i64 = System.Int64; |
||
6 | using u8 = System.Byte; |
||
7 | using u16 = System.UInt16; |
||
8 | using u32 = System.UInt32; |
||
9 | using u64 = System.UInt64; |
||
10 | using sqlite3_int64 = System.Int64; |
||
11 | using Pgno = System.UInt32; |
||
12 | |||
13 | namespace Community.CsharpSqlite |
||
14 | { |
||
15 | using DbPage = Sqlite3.PgHdr; |
||
16 | |||
17 | public partial class Sqlite3 |
||
18 | { |
||
19 | /* |
||
20 | ** 2004 April 6 |
||
21 | ** |
||
22 | ** The author disclaims copyright to this source code. In place of |
||
23 | ** a legal notice, here is a blessing: |
||
24 | ** |
||
25 | ** May you do good and not evil. |
||
26 | ** May you find forgiveness for yourself and forgive others. |
||
27 | ** May you share freely, never taking more than you give. |
||
28 | ** |
||
29 | ** This file implements a external (disk-based) database using BTrees. |
||
30 | ** See the header comment on "btreeInt.h" for additional information. |
||
31 | ** Including a description of file format and an overview of operation. |
||
32 | ************************************************************************* |
||
33 | ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
||
34 | ** C#-SQLite is an independent reimplementation of the SQLite software library |
||
35 | ** |
||
36 | ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2 |
||
37 | ** |
||
38 | ************************************************************************* |
||
39 | */ |
||
40 | //#include "btreeInt.h" |
||
41 | |||
42 | /* |
||
43 | ** The header string that appears at the beginning of every |
||
44 | ** SQLite database. |
||
45 | */ |
||
46 | static byte[] zMagicHeader = Encoding.UTF8.GetBytes( SQLITE_FILE_HEADER ); |
||
47 | |||
48 | /* |
||
49 | ** Set this global variable to 1 to enable tracing using the TRACE |
||
50 | ** macro. |
||
51 | */ |
||
52 | #if TRACE |
||
53 | static bool sqlite3BtreeTrace=false; /* True to enable tracing */ |
||
54 | //# define TRACE(X) if(sqlite3BtreeTrace){printf X;fflush(stdout);} |
||
55 | static void TRACE(string X, params object[] ap) { if (sqlite3BtreeTrace) printf(X, ap); } |
||
56 | #else |
||
57 | //# define TRACE(X) |
||
58 | static void TRACE( string X, params object[] ap ) |
||
59 | { |
||
60 | } |
||
61 | #endif |
||
62 | |||
63 | /* |
||
64 | ** Extract a 2-byte big-endian integer from an array of unsigned bytes. |
||
65 | ** But if the value is zero, make it 65536. |
||
66 | ** |
||
67 | ** This routine is used to extract the "offset to cell content area" value |
||
68 | ** from the header of a btree page. If the page size is 65536 and the page |
||
69 | ** is empty, the offset should be 65536, but the 2-byte value stores zero. |
||
70 | ** This routine makes the necessary adjustment to 65536. |
||
71 | */ |
||
72 | //#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) |
||
73 | static int get2byteNotZero( byte[] X, int offset ) |
||
74 | { |
||
75 | return ( ( ( ( (int)get2byte( X, offset ) ) - 1 ) & 0xffff ) + 1 ); |
||
76 | } |
||
77 | |||
78 | #if !SQLITE_OMIT_SHARED_CACHE |
||
79 | /* |
||
80 | ** A list of BtShared objects that are eligible for participation |
||
81 | ** in shared cache. This variable has file scope during normal builds, |
||
82 | ** but the test harness needs to access it so we make it global for |
||
83 | ** test builds. |
||
84 | ** |
||
85 | ** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER. |
||
86 | */ |
||
87 | #if SQLITE_TEST |
||
88 | BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; |
||
89 | #else |
||
90 | static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; |
||
91 | #endif |
||
92 | #endif //* SQLITE_OMIT_SHARED_CACHE */ |
||
93 | |||
94 | #if !SQLITE_OMIT_SHARED_CACHE |
||
95 | /* |
||
96 | ** Enable or disable the shared pager and schema features. |
||
97 | ** |
||
98 | ** This routine has no effect on existing database connections. |
||
99 | ** The shared cache setting effects only future calls to |
||
100 | ** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). |
||
101 | */ |
||
102 | int sqlite3_enable_shared_cache(int enable){ |
||
103 | sqlite3GlobalConfig.sharedCacheEnabled = enable; |
||
104 | return SQLITE_OK; |
||
105 | } |
||
106 | #endif |
||
107 | |||
108 | |||
109 | |||
110 | #if SQLITE_OMIT_SHARED_CACHE |
||
111 | /* |
||
112 | ** The functions querySharedCacheTableLock(), setSharedCacheTableLock(), |
||
113 | ** and clearAllSharedCacheTableLocks() |
||
114 | ** manipulate entries in the BtShared.pLock linked list used to store |
||
115 | ** shared-cache table level locks. If the library is compiled with the |
||
116 | ** shared-cache feature disabled, then there is only ever one user |
||
117 | ** of each BtShared structure and so this locking is not necessary. |
||
118 | ** So define the lock related functions as no-ops. |
||
119 | */ |
||
120 | //#define querySharedCacheTableLock(a,b,c) SQLITE_OK |
||
121 | static int querySharedCacheTableLock( Btree p, Pgno iTab, u8 eLock ) |
||
122 | { |
||
123 | return SQLITE_OK; |
||
124 | } |
||
125 | |||
126 | //#define setSharedCacheTableLock(a,b,c) SQLITE_OK |
||
127 | //#define clearAllSharedCacheTableLocks(a) |
||
128 | static void clearAllSharedCacheTableLocks( Btree a ) |
||
129 | { |
||
130 | } |
||
131 | //#define downgradeAllSharedCacheTableLocks(a) |
||
132 | static void downgradeAllSharedCacheTableLocks( Btree a ) |
||
133 | { |
||
134 | } |
||
135 | //#define hasSharedCacheTableLock(a,b,c,d) 1 |
||
136 | static bool hasSharedCacheTableLock( Btree a, Pgno b, int c, int d ) |
||
137 | { |
||
138 | return true; |
||
139 | } |
||
140 | //#define hasReadConflicts(a, b) 0 |
||
141 | static bool hasReadConflicts( Btree a, Pgno b ) |
||
142 | { |
||
143 | return false; |
||
144 | } |
||
145 | #endif |
||
146 | |||
147 | #if !SQLITE_OMIT_SHARED_CACHE |
||
148 | |||
149 | #if SQLITE_DEBUG |
||
150 | /* |
||
151 | **** This function is only used as part of an assert() statement. *** |
||
152 | ** |
||
153 | ** Check to see if pBtree holds the required locks to read or write to the |
||
154 | ** table with root page iRoot. Return 1 if it does and 0 if not. |
||
155 | ** |
||
156 | ** For example, when writing to a table with root-page iRoot via |
||
157 | ** Btree connection pBtree: |
||
158 | ** |
||
159 | ** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) ); |
||
160 | ** |
||
161 | ** When writing to an index that resides in a sharable database, the |
||
162 | ** caller should have first obtained a lock specifying the root page of |
||
163 | ** the corresponding table. This makes things a bit more complicated, |
||
164 | ** as this module treats each table as a separate structure. To determine |
||
165 | ** the table corresponding to the index being written, this |
||
166 | ** function has to search through the database schema. |
||
167 | ** |
||
168 | ** Instead of a lock on the table/index rooted at page iRoot, the caller may |
||
169 | ** hold a write-lock on the schema table (root page 1). This is also |
||
170 | ** acceptable. |
||
171 | */ |
||
172 | static int hasSharedCacheTableLock( |
||
173 | Btree pBtree, /* Handle that must hold lock */ |
||
174 | Pgno iRoot, /* Root page of b-tree */ |
||
175 | int isIndex, /* True if iRoot is the root of an index b-tree */ |
||
176 | int eLockType /* Required lock type (READ_LOCK or WRITE_LOCK) */ |
||
177 | ){ |
||
178 | Schema pSchema = (Schema *)pBtree.pBt.pSchema; |
||
179 | Pgno iTab = 0; |
||
180 | BtLock pLock; |
||
181 | |||
182 | /* If this database is not shareable, or if the client is reading |
||
183 | ** and has the read-uncommitted flag set, then no lock is required. |
||
184 | ** Return true immediately. |
||
185 | */ |
||
186 | if( (pBtree.sharable==null) |
||
187 | || (eLockType==READ_LOCK && (pBtree.db.flags & SQLITE_ReadUncommitted)) |
||
188 | ){ |
||
189 | return 1; |
||
190 | } |
||
191 | |||
192 | /* If the client is reading or writing an index and the schema is |
||
193 | ** not loaded, then it is too difficult to actually check to see if |
||
194 | ** the correct locks are held. So do not bother - just return true. |
||
195 | ** This case does not come up very often anyhow. |
||
196 | */ |
||
197 | if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){ |
||
198 | return 1; |
||
199 | } |
||
200 | |||
201 | /* Figure out the root-page that the lock should be held on. For table |
||
202 | ** b-trees, this is just the root page of the b-tree being read or |
||
203 | ** written. For index b-trees, it is the root page of the associated |
||
204 | ** table. */ |
||
205 | if( isIndex ){ |
||
206 | HashElem p; |
||
207 | for(p=sqliteHashFirst(pSchema.idxHash); p!=null; p=sqliteHashNext(p)){ |
||
208 | Index pIdx = (Index *)sqliteHashData(p); |
||
209 | if( pIdx.tnum==(int)iRoot ){ |
||
210 | iTab = pIdx.pTable.tnum; |
||
211 | } |
||
212 | } |
||
213 | }else{ |
||
214 | iTab = iRoot; |
||
215 | } |
||
216 | |||
217 | /* Search for the required lock. Either a write-lock on root-page iTab, a |
||
218 | ** write-lock on the schema table, or (if the client is reading) a |
||
219 | ** read-lock on iTab will suffice. Return 1 if any of these are found. */ |
||
220 | for(pLock=pBtree.pBt.pLock; pLock; pLock=pLock.pNext){ |
||
221 | if( pLock.pBtree==pBtree |
||
222 | && (pLock.iTable==iTab || (pLock.eLock==WRITE_LOCK && pLock.iTable==1)) |
||
223 | && pLock.eLock>=eLockType |
||
224 | ){ |
||
225 | return 1; |
||
226 | } |
||
227 | } |
||
228 | |||
229 | /* Failed to find the required lock. */ |
||
230 | return 0; |
||
231 | } |
||
232 | |||
233 | #endif //* SQLITE_DEBUG */ |
||
234 | |||
235 | #if SQLITE_DEBUG |
||
236 | /* |
||
237 | ** This function may be used as part of assert() statements only. **** |
||
238 | ** |
||
239 | ** Return true if it would be illegal for pBtree to write into the |
||
240 | ** table or index rooted at iRoot because other shared connections are |
||
241 | ** simultaneously reading that same table or index. |
||
242 | ** |
||
243 | ** It is illegal for pBtree to write if some other Btree object that |
||
244 | ** shares the same BtShared object is currently reading or writing |
||
245 | ** the iRoot table. Except, if the other Btree object has the |
||
246 | ** read-uncommitted flag set, then it is OK for the other object to |
||
247 | ** have a read cursor. |
||
248 | ** |
||
249 | ** For example, before writing to any part of the table or index |
||
250 | ** rooted at page iRoot, one should call: |
||
251 | ** |
||
252 | ** assert( !hasReadConflicts(pBtree, iRoot) ); |
||
253 | */ |
||
254 | static int hasReadConflicts(Btree pBtree, Pgno iRoot){ |
||
255 | BtCursor p; |
||
256 | for(p=pBtree.pBt.pCursor; p!=null; p=p.pNext){ |
||
257 | if( p.pgnoRoot==iRoot |
||
258 | && p.pBtree!=pBtree |
||
259 | && 0==(p.pBtree.db.flags & SQLITE_ReadUncommitted) |
||
260 | ){ |
||
261 | return 1; |
||
262 | } |
||
263 | } |
||
264 | return 0; |
||
265 | } |
||
266 | #endif //* #if SQLITE_DEBUG */ |
||
267 | |||
268 | /* |
||
269 | ** Query to see if Btree handle p may obtain a lock of type eLock |
||
270 | ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return |
||
271 | ** SQLITE_OK if the lock may be obtained (by calling |
||
272 | ** setSharedCacheTableLock()), or SQLITE_LOCKED if not. |
||
273 | */ |
||
274 | static int querySharedCacheTableLock(Btree p, Pgno iTab, u8 eLock){ |
||
275 | BtShared pBt = p.pBt; |
||
276 | BtLock pIter; |
||
277 | |||
278 | Debug.Assert( sqlite3BtreeHoldsMutex(p) ); |
||
279 | Debug.Assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); |
||
280 | Debug.Assert( p.db!=null ); |
||
281 | Debug.Assert( !(p.db.flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); |
||
282 | |||
283 | /* If requesting a write-lock, then the Btree must have an open write |
||
284 | ** transaction on this file. And, obviously, for this to be so there |
||
285 | ** must be an open write transaction on the file itself. |
||
286 | */ |
||
287 | Debug.Assert( eLock==READ_LOCK || (p==pBt.pWriter && p.inTrans==TRANS_WRITE) ); |
||
288 | Debug.Assert( eLock==READ_LOCK || pBt.inTransaction==TRANS_WRITE ); |
||
289 | |||
290 | /* This routine is a no-op if the shared-cache is not enabled */ |
||
291 | if( !p.sharable ){ |
||
292 | return SQLITE_OK; |
||
293 | } |
||
294 | |||
295 | /* If some other connection is holding an exclusive lock, the |
||
296 | ** requested lock may not be obtained. |
||
297 | */ |
||
298 | if( pBt.pWriter!=p && pBt.isExclusive ){ |
||
299 | sqlite3ConnectionBlocked(p.db, pBt.pWriter.db); |
||
300 | return SQLITE_LOCKED_SHAREDCACHE; |
||
301 | } |
||
302 | |||
303 | for(pIter=pBt.pLock; pIter; pIter=pIter.pNext){ |
||
304 | /* The condition (pIter.eLock!=eLock) in the following if(...) |
||
305 | ** statement is a simplification of: |
||
306 | ** |
||
307 | ** (eLock==WRITE_LOCK || pIter.eLock==WRITE_LOCK) |
||
308 | ** |
||
309 | ** since we know that if eLock==WRITE_LOCK, then no other connection |
||
310 | ** may hold a WRITE_LOCK on any table in this file (since there can |
||
311 | ** only be a single writer). |
||
312 | */ |
||
313 | Debug.Assert( pIter.eLock==READ_LOCK || pIter.eLock==WRITE_LOCK ); |
||
314 | Debug.Assert( eLock==READ_LOCK || pIter.pBtree==p || pIter.eLock==READ_LOCK); |
||
315 | if( pIter.pBtree!=p && pIter.iTable==iTab && pIter.eLock!=eLock ){ |
||
316 | sqlite3ConnectionBlocked(p.db, pIter.pBtree.db); |
||
317 | if( eLock==WRITE_LOCK ){ |
||
318 | Debug.Assert( p==pBt.pWriter ); |
||
319 | pBt.isPending = 1; |
||
320 | } |
||
321 | return SQLITE_LOCKED_SHAREDCACHE; |
||
322 | } |
||
323 | } |
||
324 | return SQLITE_OK; |
||
325 | } |
||
326 | #endif //* !SQLITE_OMIT_SHARED_CACHE */ |
||
327 | |||
328 | #if !SQLITE_OMIT_SHARED_CACHE |
||
329 | /* |
||
330 | ** Add a lock on the table with root-page iTable to the shared-btree used |
||
331 | ** by Btree handle p. Parameter eLock must be either READ_LOCK or |
||
332 | ** WRITE_LOCK. |
||
333 | ** |
||
334 | ** This function assumes the following: |
||
335 | ** |
||
336 | ** (a) The specified Btree object p is connected to a sharable |
||
337 | ** database (one with the BtShared.sharable flag set), and |
||
338 | ** |
||
339 | ** (b) No other Btree objects hold a lock that conflicts |
||
340 | ** with the requested lock (i.e. querySharedCacheTableLock() has |
||
341 | ** already been called and returned SQLITE_OK). |
||
342 | ** |
||
343 | ** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM |
||
344 | ** is returned if a malloc attempt fails. |
||
345 | */ |
||
346 | static int setSharedCacheTableLock(Btree p, Pgno iTable, u8 eLock){ |
||
347 | BtShared pBt = p.pBt; |
||
348 | BtLock pLock = 0; |
||
349 | BtLock pIter; |
||
350 | |||
351 | Debug.Assert( sqlite3BtreeHoldsMutex(p) ); |
||
352 | Debug.Assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); |
||
353 | Debug.Assert( p.db!=null ); |
||
354 | |||
355 | /* A connection with the read-uncommitted flag set will never try to |
||
356 | ** obtain a read-lock using this function. The only read-lock obtained |
||
357 | ** by a connection in read-uncommitted mode is on the sqlite_master |
||
358 | ** table, and that lock is obtained in BtreeBeginTrans(). */ |
||
359 | Debug.Assert( 0==(p.db.flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK ); |
||
360 | |||
361 | /* This function should only be called on a sharable b-tree after it |
||
362 | ** has been determined that no other b-tree holds a conflicting lock. */ |
||
363 | Debug.Assert( p.sharable ); |
||
364 | Debug.Assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) ); |
||
365 | |||
366 | /* First search the list for an existing lock on this table. */ |
||
367 | for(pIter=pBt.pLock; pIter; pIter=pIter.pNext){ |
||
368 | if( pIter.iTable==iTable && pIter.pBtree==p ){ |
||
369 | pLock = pIter; |
||
370 | break; |
||
371 | } |
||
372 | } |
||
373 | |||
374 | /* If the above search did not find a BtLock struct associating Btree p |
||
375 | ** with table iTable, allocate one and link it into the list. |
||
376 | */ |
||
377 | if( !pLock ){ |
||
378 | pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock)); |
||
379 | if( !pLock ){ |
||
380 | return SQLITE_NOMEM; |
||
381 | } |
||
382 | pLock.iTable = iTable; |
||
383 | pLock.pBtree = p; |
||
384 | pLock.pNext = pBt.pLock; |
||
385 | pBt.pLock = pLock; |
||
386 | } |
||
387 | |||
388 | /* Set the BtLock.eLock variable to the maximum of the current lock |
||
389 | ** and the requested lock. This means if a write-lock was already held |
||
390 | ** and a read-lock requested, we don't incorrectly downgrade the lock. |
||
391 | */ |
||
392 | Debug.Assert( WRITE_LOCK>READ_LOCK ); |
||
393 | if( eLock>pLock.eLock ){ |
||
394 | pLock.eLock = eLock; |
||
395 | } |
||
396 | |||
397 | return SQLITE_OK; |
||
398 | } |
||
399 | #endif //* !SQLITE_OMIT_SHARED_CACHE */ |
||
400 | |||
401 | #if !SQLITE_OMIT_SHARED_CACHE |
||
402 | /* |
||
403 | ** Release all the table locks (locks obtained via calls to |
||
404 | ** the setSharedCacheTableLock() procedure) held by Btree object p. |
||
405 | ** |
||
406 | ** This function assumes that Btree p has an open read or write |
||
407 | ** transaction. If it does not, then the BtShared.isPending variable |
||
408 | ** may be incorrectly cleared. |
||
409 | */ |
||
410 | static void clearAllSharedCacheTableLocks(Btree p){ |
||
411 | BtShared pBt = p.pBt; |
||
412 | BtLock **ppIter = &pBt.pLock; |
||
413 | |||
414 | Debug.Assert( sqlite3BtreeHoldsMutex(p) ); |
||
415 | Debug.Assert( p.sharable || 0==*ppIter ); |
||
416 | Debug.Assert( p.inTrans>0 ); |
||
417 | |||
418 | while( ppIter ){ |
||
419 | BtLock pLock = ppIter; |
||
420 | Debug.Assert( pBt.isExclusive==null || pBt.pWriter==pLock.pBtree ); |
||
421 | Debug.Assert( pLock.pBtree.inTrans>=pLock.eLock ); |
||
422 | if( pLock.pBtree==p ){ |
||
423 | ppIter = pLock.pNext; |
||
424 | Debug.Assert( pLock.iTable!=1 || pLock==&p.lock ); |
||
425 | if( pLock.iTable!=1 ){ |
||
426 | pLock=null;//sqlite3_free(ref pLock); |
||
427 | } |
||
428 | }else{ |
||
429 | ppIter = &pLock.pNext; |
||
430 | } |
||
431 | } |
||
432 | |||
433 | Debug.Assert( pBt.isPending==null || pBt.pWriter ); |
||
434 | if( pBt.pWriter==p ){ |
||
435 | pBt.pWriter = 0; |
||
436 | pBt.isExclusive = 0; |
||
437 | pBt.isPending = 0; |
||
438 | }else if( pBt.nTransaction==2 ){ |
||
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 isPending flag to 0. |
||
444 | ** |
||
445 | ** If there is not currently a writer, then BtShared.isPending must |
||
446 | ** be zero already. So this next line is harmless in that case. |
||
447 | */ |
||
448 | pBt.isPending = 0; |
||
449 | } |
||
450 | } |
||
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 ){ |
||
458 | BtLock pLock; |
||
459 | pBt.pWriter = 0; |
||
460 | pBt.isExclusive = 0; |
||
461 | pBt.isPending = 0; |
||
462 | for(pLock=pBt.pLock; pLock; pLock=pLock.pNext){ |
||
463 | Debug.Assert( pLock.eLock==READ_LOCK || pLock.pBtree==p ); |
||
464 | pLock.eLock = READ_LOCK; |
||
465 | } |
||
466 | } |
||
467 | } |
||
468 | |||
469 | #endif //* SQLITE_OMIT_SHARED_CACHE */ |
||
470 | |||
471 | //static void releasePage(MemPage pPage); /* Forward reference */ |
||
472 | |||
473 | /* |
||
474 | ***** This routine is used inside of assert() only **** |
||
475 | ** |
||
476 | ** Verify that the cursor holds the mutex on its BtShared |
||
477 | */ |
||
478 | #if SQLITE_DEBUG |
||
479 | static bool cursorHoldsMutex( BtCursor p ) |
||
480 | { |
||
481 | return sqlite3_mutex_held( p.pBt.mutex ); |
||
482 | } |
||
483 | #else |
||
484 | static bool cursorHoldsMutex(BtCursor p) { return true; } |
||
485 | #endif |
||
486 | |||
487 | |||
488 | #if !SQLITE_OMIT_INCRBLOB |
||
489 | /* |
||
490 | ** Invalidate the overflow page-list cache for cursor pCur, if any. |
||
491 | */ |
||
492 | static void invalidateOverflowCache(BtCursor pCur){ |
||
493 | Debug.Assert( cursorHoldsMutex(pCur) ); |
||
494 | //sqlite3_free(ref pCur.aOverflow); |
||
495 | pCur.aOverflow = null; |
||
496 | } |
||
497 | |||
498 | /* |
||
499 | ** Invalidate the overflow page-list cache for all cursors opened |
||
500 | ** on the shared btree structure pBt. |
||
501 | */ |
||
502 | static void invalidateAllOverflowCache(BtShared pBt){ |
||
503 | BtCursor p; |
||
504 | Debug.Assert( sqlite3_mutex_held(pBt.mutex) ); |
||
505 | for(p=pBt.pCursor; p!=null; p=p.pNext){ |
||
506 | invalidateOverflowCache(p); |
||
507 | } |
||
508 | } |
||
509 | |||
510 | /* |
||
511 | ** This function is called before modifying the contents of a table |
||
512 | ** to invalidate any incrblob cursors that are open on the |
||
513 | ** row or one of the rows being modified. |
||
514 | ** |
||
515 | ** If argument isClearTable is true, then the entire contents of the |
||
516 | ** table is about to be deleted. In this case invalidate all incrblob |
||
517 | ** cursors open on any row within the table with root-page pgnoRoot. |
||
518 | ** |
||
519 | ** Otherwise, if argument isClearTable is false, then the row with |
||
520 | ** rowid iRow is being replaced or deleted. In this case invalidate |
||
521 | ** only those incrblob cursors open on that specific row. |
||
522 | */ |
||
523 | static void invalidateIncrblobCursors( |
||
524 | Btree pBtree, /* The database file to check */ |
||
525 | i64 iRow, /* The rowid that might be changing */ |
||
526 | int isClearTable /* True if all rows are being deleted */ |
||
527 | ){ |
||
528 | BtCursor p; |
||
529 | BtShared pBt = pBtree.pBt; |
||
530 | Debug.Assert( sqlite3BtreeHoldsMutex(pBtree) ); |
||
531 | for(p=pBt.pCursor; p!=null; p=p.pNext){ |
||
532 | if( p.isIncrblobHandle && (isClearTable || p.info.nKey==iRow) ){ |
||
533 | p.eState = CURSOR_INVALID; |
||
534 | } |
||
535 | } |
||
536 | } |
||
537 | |||
538 | #else |
||
539 | /* Stub functions when INCRBLOB is omitted */ |
||
540 | //#define invalidateOverflowCache(x) |
||
541 | static void invalidateOverflowCache( BtCursor pCur ) |
||
542 | { |
||
543 | } |
||
544 | //#define invalidateAllOverflowCache(x) |
||
545 | static void invalidateAllOverflowCache( BtShared pBt ) |
||
546 | { |
||
547 | } |
||
548 | //#define invalidateIncrblobCursors(x,y,z) |
||
549 | static void invalidateIncrblobCursors( Btree x, i64 y, int z ) |
||
550 | { |
||
551 | } |
||
552 | #endif //* SQLITE_OMIT_INCRBLOB */ |
||
553 | |||
554 | /* |
||
555 | ** Set bit pgno of the BtShared.pHasContent bitvec. This is called |
||
556 | ** when a page that previously contained data becomes a free-list leaf |
||
557 | ** page. |
||
558 | ** |
||
559 | ** The BtShared.pHasContent bitvec exists to work around an obscure |
||
560 | ** bug caused by the interaction of two useful IO optimizations surrounding |
||
561 | ** free-list leaf pages: |
||
562 | ** |
||
563 | ** 1) When all data is deleted from a page and the page becomes |
||
564 | ** a free-list leaf page, the page is not written to the database |
||
565 | ** (as free-list leaf pages contain no meaningful data). Sometimes |
||
566 | ** such a page is not even journalled (as it will not be modified, |
||
567 | ** why bother journalling it?). |
||
568 | ** |
||
569 | ** 2) When a free-list leaf page is reused, its content is not read |
||
570 | ** from the database or written to the journal file (why should it |
||
571 | ** be, if it is not at all meaningful?). |
||
572 | ** |
||
573 | ** By themselves, these optimizations work fine and provide a handy |
||
574 | ** performance boost to bulk delete or insert operations. However, if |
||
575 | ** a page is moved to the free-list and then reused within the same |
||
576 | ** transaction, a problem comes up. If the page is not journalled when |
||
577 | ** it is moved to the free-list and it is also not journalled when it |
||
578 | ** is extracted from the free-list and reused, then the original data |
||
579 | ** may be lost. In the event of a rollback, it may not be possible |
||
580 | ** to restore the database to its original configuration. |
||
581 | ** |
||
582 | ** The solution is the BtShared.pHasContent bitvec. Whenever a page is |
||
583 | ** moved to become a free-list leaf page, the corresponding bit is |
||
584 | ** set in the bitvec. Whenever a leaf page is extracted from the free-list, |
||
585 | ** optimization 2 above is omitted if the corresponding bit is already |
||
586 | ** set in BtShared.pHasContent. The contents of the bitvec are cleared |
||
587 | ** at the end of every transaction. |
||
588 | */ |
||
589 | static int btreeSetHasContent( BtShared pBt, Pgno pgno ) |
||
590 | { |
||
591 | int rc = SQLITE_OK; |
||
592 | if ( null == pBt.pHasContent ) |
||
593 | { |
||
594 | Debug.Assert( pgno <= pBt.nPage ); |
||
595 | pBt.pHasContent = sqlite3BitvecCreate( pBt.nPage ); |
||
596 | //if ( null == pBt.pHasContent ) |
||
597 | //{ |
||
598 | // rc = SQLITE_NOMEM; |
||
599 | //} |
||
600 | } |
||
601 | if ( rc == SQLITE_OK && pgno <= sqlite3BitvecSize( pBt.pHasContent ) ) |
||
602 | { |
||
603 | rc = sqlite3BitvecSet( pBt.pHasContent, pgno ); |
||
604 | } |
||
605 | return rc; |
||
606 | } |
||
607 | |||
608 | /* |
||
609 | ** Query the BtShared.pHasContent vector. |
||
610 | ** |
||
611 | ** This function is called when a free-list leaf page is removed from the |
||
612 | ** free-list for reuse. It returns false if it is safe to retrieve the |
||
613 | ** page from the pager layer with the 'no-content' flag set. True otherwise. |
||
614 | */ |
||
615 | static bool btreeGetHasContent( BtShared pBt, Pgno pgno ) |
||
616 | { |
||
617 | Bitvec p = pBt.pHasContent; |
||
618 | return ( p != null && ( pgno > sqlite3BitvecSize( p ) || sqlite3BitvecTest( p, pgno ) != 0 ) ); |
||
619 | } |
||
620 | |||
621 | /* |
||
622 | ** Clear (destroy) the BtShared.pHasContent bitvec. This should be |
||
623 | ** invoked at the conclusion of each write-transaction. |
||
624 | */ |
||
625 | static void btreeClearHasContent( BtShared pBt ) |
||
626 | { |
||
627 | sqlite3BitvecDestroy( ref pBt.pHasContent ); |
||
628 | pBt.pHasContent = null; |
||
629 | } |
||
630 | |||
631 | /* |
||
632 | ** Save the current cursor position in the variables BtCursor.nKey |
||
633 | ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. |
||
634 | ** |
||
635 | ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) |
||
636 | ** prior to calling this routine. |
||
637 | */ |
||
638 | static int saveCursorPosition( BtCursor pCur ) |
||
639 | { |
||
640 | int rc; |
||
641 | |||
642 | Debug.Assert( CURSOR_VALID == pCur.eState ); |
||
643 | Debug.Assert( null == pCur.pKey ); |
||
644 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
645 | |||
646 | rc = sqlite3BtreeKeySize( pCur, ref pCur.nKey ); |
||
647 | Debug.Assert( rc == SQLITE_OK ); /* KeySize() cannot fail */ |
||
648 | |||
649 | /* If this is an intKey table, then the above call to BtreeKeySize() |
||
650 | ** stores the integer key in pCur.nKey. In this case this value is |
||
651 | ** all that is required. Otherwise, if pCur is not open on an intKey |
||
652 | ** table, then malloc space for and store the pCur.nKey bytes of key |
||
653 | ** data. |
||
654 | */ |
||
655 | if ( 0 == pCur.apPage[0].intKey ) |
||
656 | { |
||
657 | byte[] pKey = sqlite3Malloc( (int)pCur.nKey ); |
||
658 | //if( pKey !=null){ |
||
659 | rc = sqlite3BtreeKey( pCur, 0, (u32)pCur.nKey, pKey ); |
||
660 | if ( rc == SQLITE_OK ) |
||
661 | { |
||
662 | pCur.pKey = pKey; |
||
663 | } |
||
664 | //else{ |
||
665 | // sqlite3_free(ref pKey); |
||
666 | //} |
||
667 | //}else{ |
||
668 | // rc = SQLITE_NOMEM; |
||
669 | //} |
||
670 | } |
||
671 | Debug.Assert( 0 == pCur.apPage[0].intKey || null == pCur.pKey ); |
||
672 | |||
673 | if ( rc == SQLITE_OK ) |
||
674 | { |
||
675 | int i; |
||
676 | for ( i = 0; i <= pCur.iPage; i++ ) |
||
677 | { |
||
678 | releasePage( pCur.apPage[i] ); |
||
679 | pCur.apPage[i] = null; |
||
680 | } |
||
681 | pCur.iPage = -1; |
||
682 | pCur.eState = CURSOR_REQUIRESEEK; |
||
683 | } |
||
684 | |||
685 | invalidateOverflowCache( pCur ); |
||
686 | return rc; |
||
687 | } |
||
688 | |||
689 | /* |
||
690 | ** Save the positions of all cursors (except pExcept) that are open on |
||
691 | ** the table with root-page iRoot. Usually, this is called just before cursor |
||
692 | ** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). |
||
693 | */ |
||
694 | static int saveAllCursors( BtShared pBt, Pgno iRoot, BtCursor pExcept ) |
||
695 | { |
||
696 | BtCursor p; |
||
697 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
698 | Debug.Assert( pExcept == null || pExcept.pBt == pBt ); |
||
699 | for ( p = pBt.pCursor; p != null; p = p.pNext ) |
||
700 | { |
||
701 | if ( p != pExcept && ( 0 == iRoot || p.pgnoRoot == iRoot ) && |
||
702 | p.eState == CURSOR_VALID ) |
||
703 | { |
||
704 | int rc = saveCursorPosition( p ); |
||
705 | if ( SQLITE_OK != rc ) |
||
706 | { |
||
707 | return rc; |
||
708 | } |
||
709 | } |
||
710 | } |
||
711 | return SQLITE_OK; |
||
712 | } |
||
713 | |||
714 | /* |
||
715 | ** Clear the current cursor position. |
||
716 | */ |
||
717 | static void sqlite3BtreeClearCursor( BtCursor pCur ) |
||
718 | { |
||
719 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
720 | sqlite3_free( ref pCur.pKey ); |
||
721 | pCur.eState = CURSOR_INVALID; |
||
722 | } |
||
723 | |||
724 | /* |
||
725 | ** In this version of BtreeMoveto, pKey is a packed index record |
||
726 | ** such as is generated by the OP_MakeRecord opcode. Unpack the |
||
727 | ** record and then call BtreeMovetoUnpacked() to do the work. |
||
728 | */ |
||
729 | static int btreeMoveto( |
||
730 | BtCursor pCur, /* Cursor open on the btree to be searched */ |
||
731 | byte[] pKey, /* Packed key if the btree is an index */ |
||
732 | i64 nKey, /* Integer key for tables. Size of pKey for indices */ |
||
733 | int bias, /* Bias search to the high end */ |
||
734 | ref int pRes /* Write search results here */ |
||
735 | ) |
||
736 | { |
||
737 | int rc; /* Status code */ |
||
738 | UnpackedRecord pIdxKey; /* Unpacked index key */ |
||
739 | UnpackedRecord aSpace = new UnpackedRecord();//char aSpace[150]; /* Temp space for pIdxKey - to avoid a malloc */ |
||
740 | |||
741 | if ( pKey != null ) |
||
742 | { |
||
743 | Debug.Assert( nKey == (i64)(int)nKey ); |
||
744 | pIdxKey = sqlite3VdbeRecordUnpack( pCur.pKeyInfo, (int)nKey, pKey, |
||
745 | aSpace, 16 );//sizeof( aSpace ) ); |
||
746 | //if ( pIdxKey == null ) |
||
747 | // return SQLITE_NOMEM; |
||
748 | } |
||
749 | else |
||
750 | { |
||
751 | pIdxKey = null; |
||
752 | } |
||
753 | rc = sqlite3BtreeMovetoUnpacked( pCur, pIdxKey, nKey, bias != 0 ? 1 : 0, ref pRes ); |
||
754 | |||
755 | if ( pKey != null ) |
||
756 | { |
||
757 | sqlite3VdbeDeleteUnpackedRecord( pIdxKey ); |
||
758 | } |
||
759 | return rc; |
||
760 | } |
||
761 | |||
762 | /* |
||
763 | ** Restore the cursor to the position it was in (or as close to as possible) |
||
764 | ** when saveCursorPosition() was called. Note that this call deletes the |
||
765 | ** saved position info stored by saveCursorPosition(), so there can be |
||
766 | ** at most one effective restoreCursorPosition() call after each |
||
767 | ** saveCursorPosition(). |
||
768 | */ |
||
769 | static int btreeRestoreCursorPosition( BtCursor pCur ) |
||
770 | { |
||
771 | int rc; |
||
772 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
773 | Debug.Assert( pCur.eState >= CURSOR_REQUIRESEEK ); |
||
774 | if ( pCur.eState == CURSOR_FAULT ) |
||
775 | { |
||
776 | return pCur.skipNext; |
||
777 | } |
||
778 | pCur.eState = CURSOR_INVALID; |
||
779 | rc = btreeMoveto( pCur, pCur.pKey, pCur.nKey, 0, ref pCur.skipNext ); |
||
780 | if ( rc == SQLITE_OK ) |
||
781 | { |
||
782 | //sqlite3_free(ref pCur.pKey); |
||
783 | pCur.pKey = null; |
||
784 | Debug.Assert( pCur.eState == CURSOR_VALID || pCur.eState == CURSOR_INVALID ); |
||
785 | } |
||
786 | return rc; |
||
787 | } |
||
788 | |||
789 | //#define restoreCursorPosition(p) \ |
||
790 | // (p.eState>=CURSOR_REQUIRESEEK ? \ |
||
791 | // btreeRestoreCursorPosition(p) : \ |
||
792 | // SQLITE_OK) |
||
793 | static int restoreCursorPosition( BtCursor pCur ) |
||
794 | { |
||
795 | if ( pCur.eState >= CURSOR_REQUIRESEEK ) |
||
796 | return btreeRestoreCursorPosition( pCur ); |
||
797 | else |
||
798 | return SQLITE_OK; |
||
799 | } |
||
800 | |||
801 | /* |
||
802 | ** Determine whether or not a cursor has moved from the position it |
||
803 | ** was last placed at. Cursors can move when the row they are pointing |
||
804 | ** at is deleted out from under them. |
||
805 | ** |
||
806 | ** This routine returns an error code if something goes wrong. The |
||
807 | ** integer pHasMoved is set to one if the cursor has moved and 0 if not. |
||
808 | */ |
||
809 | static int sqlite3BtreeCursorHasMoved( BtCursor pCur, ref int pHasMoved ) |
||
810 | { |
||
811 | int rc; |
||
812 | |||
813 | rc = restoreCursorPosition( pCur ); |
||
814 | if ( rc != 0 ) |
||
815 | { |
||
816 | pHasMoved = 1; |
||
817 | return rc; |
||
818 | } |
||
819 | if ( pCur.eState != CURSOR_VALID || pCur.skipNext != 0 ) |
||
820 | { |
||
821 | pHasMoved = 1; |
||
822 | } |
||
823 | else |
||
824 | { |
||
825 | pHasMoved = 0; |
||
826 | } |
||
827 | return SQLITE_OK; |
||
828 | } |
||
829 | |||
830 | #if !SQLITE_OMIT_AUTOVACUUM |
||
831 | /* |
||
832 | ** Given a page number of a regular database page, return the page |
||
833 | ** number for the pointer-map page that contains the entry for the |
||
834 | ** input page number. |
||
835 | ** |
||
836 | ** Return 0 (not a valid page) for pgno==1 since there is |
||
837 | ** no pointer map associated with page 1. The integrity_check logic |
||
838 | ** requires that ptrmapPageno(*,1)!=1. |
||
839 | */ |
||
840 | static Pgno ptrmapPageno( BtShared pBt, Pgno pgno ) |
||
841 | { |
||
842 | int nPagesPerMapPage; |
||
843 | Pgno iPtrMap, ret; |
||
844 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
845 | if ( pgno < 2 ) |
||
846 | return 0; |
||
847 | nPagesPerMapPage = (int)( pBt.usableSize / 5 + 1 ); |
||
848 | iPtrMap = (Pgno)( ( pgno - 2 ) / nPagesPerMapPage ); |
||
849 | ret = (Pgno)( iPtrMap * nPagesPerMapPage ) + 2; |
||
850 | if ( ret == PENDING_BYTE_PAGE( pBt ) ) |
||
851 | { |
||
852 | ret++; |
||
853 | } |
||
854 | return ret; |
||
855 | } |
||
856 | |||
857 | /* |
||
858 | ** Write an entry into the pointer map. |
||
859 | ** |
||
860 | ** This routine updates the pointer map entry for page number 'key' |
||
861 | ** so that it maps to type 'eType' and parent page number 'pgno'. |
||
862 | ** |
||
863 | ** If pRC is initially non-zero (non-SQLITE_OK) then this routine is |
||
864 | ** a no-op. If an error occurs, the appropriate error code is written |
||
865 | ** into pRC. |
||
866 | */ |
||
867 | static void ptrmapPut( BtShared pBt, Pgno key, u8 eType, Pgno parent, ref int pRC ) |
||
868 | { |
||
869 | PgHdr pDbPage = new PgHdr(); /* The pointer map page */ |
||
870 | u8[] pPtrmap; /* The pointer map data */ |
||
871 | Pgno iPtrmap; /* The pointer map page number */ |
||
872 | int offset; /* Offset in pointer map page */ |
||
873 | int rc; /* Return code from subfunctions */ |
||
874 | |||
875 | if ( pRC != 0 ) |
||
876 | return; |
||
877 | |||
878 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
879 | /* The master-journal page number must never be used as a pointer map page */ |
||
880 | Debug.Assert( false == PTRMAP_ISPAGE( pBt, PENDING_BYTE_PAGE( pBt ) ) ); |
||
881 | |||
882 | Debug.Assert( pBt.autoVacuum ); |
||
883 | if ( key == 0 ) |
||
884 | { |
||
885 | pRC = SQLITE_CORRUPT_BKPT(); |
||
886 | return; |
||
887 | } |
||
888 | iPtrmap = PTRMAP_PAGENO( pBt, key ); |
||
889 | rc = sqlite3PagerGet( pBt.pPager, iPtrmap, ref pDbPage ); |
||
890 | if ( rc != SQLITE_OK ) |
||
891 | { |
||
892 | pRC = rc; |
||
893 | return; |
||
894 | } |
||
895 | offset = (int)PTRMAP_PTROFFSET( iPtrmap, key ); |
||
896 | if ( offset < 0 ) |
||
897 | { |
||
898 | pRC = SQLITE_CORRUPT_BKPT(); |
||
899 | goto ptrmap_exit; |
||
900 | } |
||
901 | Debug.Assert( offset <= (int)pBt.usableSize - 5 ); |
||
902 | pPtrmap = sqlite3PagerGetData( pDbPage ); |
||
903 | |||
904 | if ( eType != pPtrmap[offset] || sqlite3Get4byte( pPtrmap, offset + 1 ) != parent ) |
||
905 | { |
||
906 | TRACE( "PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent ); |
||
907 | pRC = rc = sqlite3PagerWrite( pDbPage ); |
||
908 | if ( rc == SQLITE_OK ) |
||
909 | { |
||
910 | pPtrmap[offset] = eType; |
||
911 | sqlite3Put4byte( pPtrmap, offset + 1, parent ); |
||
912 | } |
||
913 | } |
||
914 | |||
915 | ptrmap_exit: |
||
916 | sqlite3PagerUnref( pDbPage ); |
||
917 | } |
||
918 | |||
919 | /* |
||
920 | ** Read an entry from the pointer map. |
||
921 | ** |
||
922 | ** This routine retrieves the pointer map entry for page 'key', writing |
||
923 | ** the type and parent page number to pEType and pPgno respectively. |
||
924 | ** An error code is returned if something goes wrong, otherwise SQLITE_OK. |
||
925 | */ |
||
926 | static int ptrmapGet( BtShared pBt, Pgno key, ref u8 pEType, ref Pgno pPgno ) |
||
927 | { |
||
928 | PgHdr pDbPage = new PgHdr();/* The pointer map page */ |
||
929 | int iPtrmap; /* Pointer map page index */ |
||
930 | u8[] pPtrmap; /* Pointer map page data */ |
||
931 | int offset; /* Offset of entry in pointer map */ |
||
932 | int rc; |
||
933 | |||
934 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
935 | |||
936 | iPtrmap = (int)PTRMAP_PAGENO( pBt, key ); |
||
937 | rc = sqlite3PagerGet( pBt.pPager, (u32)iPtrmap, ref pDbPage ); |
||
938 | if ( rc != 0 ) |
||
939 | { |
||
940 | return rc; |
||
941 | } |
||
942 | pPtrmap = sqlite3PagerGetData( pDbPage ); |
||
943 | |||
944 | offset = (int)PTRMAP_PTROFFSET( (u32)iPtrmap, key ); |
||
945 | if ( offset < 0 ) |
||
946 | { |
||
947 | sqlite3PagerUnref( pDbPage ); |
||
948 | return SQLITE_CORRUPT_BKPT(); |
||
949 | } |
||
950 | Debug.Assert( offset <= (int)pBt.usableSize - 5 ); |
||
951 | // Under C# pEType will always exist. No need to test; // |
||
952 | //Debug.Assert( pEType != 0 ); |
||
953 | pEType = pPtrmap[offset]; |
||
954 | // Under C# pPgno will always exist. No need to test; // |
||
955 | //if ( pPgno != 0 ) |
||
956 | pPgno = sqlite3Get4byte( pPtrmap, offset + 1 ); |
||
957 | |||
958 | sqlite3PagerUnref( pDbPage ); |
||
959 | if ( pEType < 1 || pEType > 5 ) |
||
960 | return SQLITE_CORRUPT_BKPT(); |
||
961 | return SQLITE_OK; |
||
962 | } |
||
963 | |||
964 | #else //* if defined SQLITE_OMIT_AUTOVACUUM */ |
||
965 | //#define ptrmapPut(w,x,y,z,rc) |
||
966 | //#define ptrmapGet(w,x,y,z) SQLITE_OK |
||
967 | //#define ptrmapPutOvflPtr(x, y, rc) |
||
968 | #endif |
||
969 | |||
970 | /* |
||
971 | ** Given a btree page and a cell index (0 means the first cell on |
||
972 | ** the page, 1 means the second cell, and so forth) return a pointer |
||
973 | ** to the cell content. |
||
974 | ** |
||
975 | ** This routine works only for pages that do not contain overflow cells. |
||
976 | */ |
||
977 | //#define findCell(P,I) \ |
||
978 | // ((P).aData + ((P).maskPage & get2byte((P).aData[(P).cellOffset+2*(I)]))) |
||
979 | static int findCell( MemPage pPage, int iCell ) |
||
980 | { |
||
981 | return get2byte( pPage.aData, pPage.cellOffset + 2 * ( iCell ) ); |
||
982 | } |
||
983 | |||
984 | //#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I))))) |
||
985 | static u8[] findCellv2( u8[] pPage, u16 iCell, u16 O, int I ) |
||
986 | { |
||
987 | Debugger.Break(); |
||
988 | return pPage; |
||
989 | } |
||
990 | |||
991 | |||
992 | /* |
||
993 | ** This a more complex version of findCell() that works for |
||
994 | ** pages that do contain overflow cells. |
||
995 | */ |
||
996 | static int findOverflowCell( MemPage pPage, int iCell ) |
||
997 | { |
||
998 | int i; |
||
999 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1000 | for ( i = pPage.nOverflow - 1; i >= 0; i-- ) |
||
1001 | { |
||
1002 | int k; |
||
1003 | _OvflCell pOvfl; |
||
1004 | pOvfl = pPage.aOvfl[i]; |
||
1005 | k = pOvfl.idx; |
||
1006 | if ( k <= iCell ) |
||
1007 | { |
||
1008 | if ( k == iCell ) |
||
1009 | { |
||
1010 | //return pOvfl.pCell; |
||
1011 | return -i - 1; // Negative Offset means overflow cells |
||
1012 | } |
||
1013 | iCell--; |
||
1014 | } |
||
1015 | } |
||
1016 | return findCell( pPage, iCell ); |
||
1017 | } |
||
1018 | |||
1019 | /* |
||
1020 | ** Parse a cell content block and fill in the CellInfo structure. There |
||
1021 | ** are two versions of this function. btreeParseCell() takes a |
||
1022 | ** cell index as the second argument and btreeParseCellPtr() |
||
1023 | ** takes a pointer to the body of the cell as its second argument. |
||
1024 | ** |
||
1025 | ** Within this file, the parseCell() macro can be called instead of |
||
1026 | ** btreeParseCellPtr(). Using some compilers, this will be faster. |
||
1027 | */ |
||
1028 | //OVERLOADS |
||
1029 | static void btreeParseCellPtr( |
||
1030 | MemPage pPage, /* Page containing the cell */ |
||
1031 | int iCell, /* Pointer to the cell text. */ |
||
1032 | ref CellInfo pInfo /* Fill in this structure */ |
||
1033 | ) |
||
1034 | { |
||
1035 | btreeParseCellPtr( pPage, pPage.aData, iCell, ref pInfo ); |
||
1036 | } |
||
1037 | static void btreeParseCellPtr( |
||
1038 | MemPage pPage, /* Page containing the cell */ |
||
1039 | byte[] pCell, /* The actual data */ |
||
1040 | ref CellInfo pInfo /* Fill in this structure */ |
||
1041 | ) |
||
1042 | { |
||
1043 | btreeParseCellPtr( pPage, pCell, 0, ref pInfo ); |
||
1044 | } |
||
1045 | static void btreeParseCellPtr( |
||
1046 | MemPage pPage, /* Page containing the cell */ |
||
1047 | u8[] pCell, /* Pointer to the cell text. */ |
||
1048 | int iCell, /* Pointer to the cell text. */ |
||
1049 | ref CellInfo pInfo /* Fill in this structure */ |
||
1050 | ) |
||
1051 | { |
||
1052 | u16 n; /* Number bytes in cell content header */ |
||
1053 | u32 nPayload = 0; /* Number of bytes of cell payload */ |
||
1054 | |||
1055 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1056 | |||
1057 | if ( pInfo.pCell != pCell ) |
||
1058 | pInfo.pCell = pCell; |
||
1059 | pInfo.iCell = iCell; |
||
1060 | Debug.Assert( pPage.leaf == 0 || pPage.leaf == 1 ); |
||
1061 | n = pPage.childPtrSize; |
||
1062 | Debug.Assert( n == 4 - 4 * pPage.leaf ); |
||
1063 | if ( pPage.intKey != 0 ) |
||
1064 | { |
||
1065 | if ( pPage.hasData != 0 ) |
||
1066 | { |
||
1067 | n += (u16)getVarint32( pCell, iCell + n, out nPayload ); |
||
1068 | } |
||
1069 | else |
||
1070 | { |
||
1071 | nPayload = 0; |
||
1072 | } |
||
1073 | n += (u16)getVarint( pCell, iCell + n, out pInfo.nKey ); |
||
1074 | pInfo.nData = nPayload; |
||
1075 | } |
||
1076 | else |
||
1077 | { |
||
1078 | pInfo.nData = 0; |
||
1079 | n += (u16)getVarint32( pCell, iCell + n, out nPayload ); |
||
1080 | pInfo.nKey = nPayload; |
||
1081 | } |
||
1082 | pInfo.nPayload = nPayload; |
||
1083 | pInfo.nHeader = n; |
||
1084 | testcase( nPayload == pPage.maxLocal ); |
||
1085 | testcase( nPayload == pPage.maxLocal + 1 ); |
||
1086 | if ( likely( nPayload <= pPage.maxLocal ) ) |
||
1087 | { |
||
1088 | /* This is the (easy) common case where the entire payload fits |
||
1089 | ** on the local page. No overflow is required. |
||
1090 | */ |
||
1091 | if ( ( pInfo.nSize = (u16)( n + nPayload ) ) < 4 ) |
||
1092 | pInfo.nSize = 4; |
||
1093 | pInfo.nLocal = (u16)nPayload; |
||
1094 | pInfo.iOverflow = 0; |
||
1095 | } |
||
1096 | else |
||
1097 | { |
||
1098 | /* If the payload will not fit completely on the local page, we have |
||
1099 | ** to decide how much to store locally and how much to spill onto |
||
1100 | ** overflow pages. The strategy is to minimize the amount of unused |
||
1101 | ** space on overflow pages while keeping the amount of local storage |
||
1102 | ** in between minLocal and maxLocal. |
||
1103 | ** |
||
1104 | ** Warning: changing the way overflow payload is distributed in any |
||
1105 | ** way will result in an incompatible file format. |
||
1106 | */ |
||
1107 | int minLocal; /* Minimum amount of payload held locally */ |
||
1108 | int maxLocal; /* Maximum amount of payload held locally */ |
||
1109 | int surplus; /* Overflow payload available for local storage */ |
||
1110 | |||
1111 | minLocal = pPage.minLocal; |
||
1112 | maxLocal = pPage.maxLocal; |
||
1113 | surplus = (int)( minLocal + ( nPayload - minLocal ) % ( pPage.pBt.usableSize - 4 ) ); |
||
1114 | testcase( surplus == maxLocal ); |
||
1115 | testcase( surplus == maxLocal + 1 ); |
||
1116 | if ( surplus <= maxLocal ) |
||
1117 | { |
||
1118 | pInfo.nLocal = (u16)surplus; |
||
1119 | } |
||
1120 | else |
||
1121 | { |
||
1122 | pInfo.nLocal = (u16)minLocal; |
||
1123 | } |
||
1124 | pInfo.iOverflow = (u16)( pInfo.nLocal + n ); |
||
1125 | pInfo.nSize = (u16)( pInfo.iOverflow + 4 ); |
||
1126 | } |
||
1127 | } |
||
1128 | //#define parseCell(pPage, iCell, pInfo) \ |
||
1129 | // btreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo)) |
||
1130 | static void parseCell( MemPage pPage, int iCell, ref CellInfo pInfo ) |
||
1131 | { |
||
1132 | btreeParseCellPtr( pPage, findCell( pPage, iCell ), ref pInfo ); |
||
1133 | } |
||
1134 | |||
1135 | static void btreeParseCell( |
||
1136 | MemPage pPage, /* Page containing the cell */ |
||
1137 | int iCell, /* The cell index. First cell is 0 */ |
||
1138 | ref CellInfo pInfo /* Fill in this structure */ |
||
1139 | ) |
||
1140 | { |
||
1141 | parseCell( pPage, iCell, ref pInfo ); |
||
1142 | } |
||
1143 | |||
1144 | /* |
||
1145 | ** Compute the total number of bytes that a Cell needs in the cell |
||
1146 | ** data area of the btree-page. The return number includes the cell |
||
1147 | ** data header and the local payload, but not any overflow page or |
||
1148 | ** the space used by the cell pointer. |
||
1149 | */ |
||
1150 | // Alternative form for C# |
||
1151 | static u16 cellSizePtr( MemPage pPage, int iCell ) |
||
1152 | { |
||
1153 | CellInfo info = new CellInfo(); |
||
1154 | byte[] pCell = new byte[13]; |
||
1155 | // Minimum Size = (2 bytes of Header or (4) Child Pointer) + (maximum of) 9 bytes data |
||
1156 | if ( iCell < 0 )// Overflow Cell |
||
1157 | Buffer.BlockCopy( pPage.aOvfl[-( iCell + 1 )].pCell, 0, pCell, 0, pCell.Length < pPage.aOvfl[-( iCell + 1 )].pCell.Length ? pCell.Length : pPage.aOvfl[-( iCell + 1 )].pCell.Length ); |
||
1158 | else if ( iCell >= pPage.aData.Length + 1 - pCell.Length ) |
||
1159 | Buffer.BlockCopy( pPage.aData, iCell, pCell, 0, pPage.aData.Length - iCell ); |
||
1160 | else |
||
1161 | Buffer.BlockCopy( pPage.aData, iCell, pCell, 0, pCell.Length ); |
||
1162 | btreeParseCellPtr( pPage, pCell, ref info ); |
||
1163 | return info.nSize; |
||
1164 | } |
||
1165 | |||
1166 | // Alternative form for C# |
||
1167 | static u16 cellSizePtr( MemPage pPage, byte[] pCell, int offset ) |
||
1168 | { |
||
1169 | CellInfo info = new CellInfo(); |
||
1170 | info.pCell = sqlite3Malloc( pCell.Length ); |
||
1171 | Buffer.BlockCopy( pCell, offset, info.pCell, 0, pCell.Length - offset ); |
||
1172 | btreeParseCellPtr( pPage, info.pCell, ref info ); |
||
1173 | return info.nSize; |
||
1174 | } |
||
1175 | |||
1176 | static u16 cellSizePtr( MemPage pPage, u8[] pCell ) |
||
1177 | { |
||
1178 | int _pIter = pPage.childPtrSize; //u8 pIter = &pCell[pPage.childPtrSize]; |
||
1179 | u32 nSize = 0; |
||
1180 | |||
1181 | #if SQLITE_DEBUG || DEBUG |
||
1182 | /* The value returned by this function should always be the same as |
||
1183 | ** the (CellInfo.nSize) value found by doing a full parse of the |
||
1184 | ** cell. If SQLITE_DEBUG is defined, an Debug.Assert() at the bottom of |
||
1185 | ** this function verifies that this invariant is not violated. */ |
||
1186 | CellInfo debuginfo = new CellInfo(); |
||
1187 | btreeParseCellPtr( pPage, pCell, ref debuginfo ); |
||
1188 | #else |
||
1189 | CellInfo debuginfo = new CellInfo(); |
||
1190 | #endif |
||
1191 | |||
1192 | if ( pPage.intKey != 0 ) |
||
1193 | { |
||
1194 | int pEnd; |
||
1195 | if ( pPage.hasData != 0 ) |
||
1196 | { |
||
1197 | _pIter += getVarint32( pCell, out nSize );// pIter += getVarint32( pIter, out nSize ); |
||
1198 | } |
||
1199 | else |
||
1200 | { |
||
1201 | nSize = 0; |
||
1202 | } |
||
1203 | |||
1204 | /* pIter now points at the 64-bit integer key value, a variable length |
||
1205 | ** integer. The following block moves pIter to point at the first byte |
||
1206 | ** past the end of the key value. */ |
||
1207 | pEnd = _pIter + 9;//pEnd = &pIter[9]; |
||
1208 | while ( ( ( pCell[_pIter++] ) & 0x80 ) != 0 && _pIter < pEnd ) |
||
1209 | ;//while( (pIter++)&0x80 && pIter<pEnd ); |
||
1210 | } |
||
1211 | else |
||
1212 | { |
||
1213 | _pIter += getVarint32( pCell, _pIter, out nSize ); //pIter += getVarint32( pIter, out nSize ); |
||
1214 | } |
||
1215 | |||
1216 | testcase( nSize == pPage.maxLocal ); |
||
1217 | testcase( nSize == pPage.maxLocal + 1 ); |
||
1218 | if ( nSize > pPage.maxLocal ) |
||
1219 | { |
||
1220 | int minLocal = pPage.minLocal; |
||
1221 | nSize = (u32)( minLocal + ( nSize - minLocal ) % ( pPage.pBt.usableSize - 4 ) ); |
||
1222 | testcase( nSize == pPage.maxLocal ); |
||
1223 | testcase( nSize == pPage.maxLocal + 1 ); |
||
1224 | if ( nSize > pPage.maxLocal ) |
||
1225 | { |
||
1226 | nSize = (u32)minLocal; |
||
1227 | } |
||
1228 | nSize += 4; |
||
1229 | } |
||
1230 | nSize += (uint)_pIter;//nSize += (u32)(pIter - pCell); |
||
1231 | |||
1232 | /* The minimum size of any cell is 4 bytes. */ |
||
1233 | if ( nSize < 4 ) |
||
1234 | { |
||
1235 | nSize = 4; |
||
1236 | } |
||
1237 | |||
1238 | Debug.Assert( nSize == debuginfo.nSize ); |
||
1239 | return (u16)nSize; |
||
1240 | } |
||
1241 | |||
1242 | #if SQLITE_DEBUG |
||
1243 | /* This variation on cellSizePtr() is used inside of assert() statements |
||
1244 | ** only. */ |
||
1245 | static u16 cellSize( MemPage pPage, int iCell ) |
||
1246 | { |
||
1247 | return cellSizePtr( pPage, findCell( pPage, iCell ) ); |
||
1248 | } |
||
1249 | #else |
||
1250 | static int cellSize(MemPage pPage, int iCell) { return -1; } |
||
1251 | #endif |
||
1252 | |||
1253 | #if !SQLITE_OMIT_AUTOVACUUM |
||
1254 | /* |
||
1255 | ** If the cell pCell, part of page pPage contains a pointer |
||
1256 | ** to an overflow page, insert an entry into the pointer-map |
||
1257 | ** for the overflow page. |
||
1258 | */ |
||
1259 | static void ptrmapPutOvflPtr( MemPage pPage, int pCell, ref int pRC ) |
||
1260 | { |
||
1261 | if ( pRC != 0 ) |
||
1262 | return; |
||
1263 | CellInfo info = new CellInfo(); |
||
1264 | Debug.Assert( pCell != 0 ); |
||
1265 | btreeParseCellPtr( pPage, pCell, ref info ); |
||
1266 | Debug.Assert( ( info.nData + ( pPage.intKey != 0 ? 0 : info.nKey ) ) == info.nPayload ); |
||
1267 | if ( info.iOverflow != 0 ) |
||
1268 | { |
||
1269 | Pgno ovfl = sqlite3Get4byte( pPage.aData, pCell, info.iOverflow ); |
||
1270 | ptrmapPut( pPage.pBt, ovfl, PTRMAP_OVERFLOW1, pPage.pgno, ref pRC ); |
||
1271 | } |
||
1272 | } |
||
1273 | |||
1274 | static void ptrmapPutOvflPtr( MemPage pPage, u8[] pCell, ref int pRC ) |
||
1275 | { |
||
1276 | if ( pRC != 0 ) |
||
1277 | return; |
||
1278 | CellInfo info = new CellInfo(); |
||
1279 | Debug.Assert( pCell != null ); |
||
1280 | btreeParseCellPtr( pPage, pCell, ref info ); |
||
1281 | Debug.Assert( ( info.nData + ( pPage.intKey != 0 ? 0 : info.nKey ) ) == info.nPayload ); |
||
1282 | if ( info.iOverflow != 0 ) |
||
1283 | { |
||
1284 | Pgno ovfl = sqlite3Get4byte( pCell, info.iOverflow ); |
||
1285 | ptrmapPut( pPage.pBt, ovfl, PTRMAP_OVERFLOW1, pPage.pgno, ref pRC ); |
||
1286 | } |
||
1287 | } |
||
1288 | #endif |
||
1289 | |||
1290 | |||
1291 | /* |
||
1292 | ** Defragment the page given. All Cells are moved to the |
||
1293 | ** end of the page and all free space is collected into one |
||
1294 | ** big FreeBlk that occurs in between the header and cell |
||
1295 | ** pointer array and the cell content area. |
||
1296 | */ |
||
1297 | static int defragmentPage( MemPage pPage ) |
||
1298 | { |
||
1299 | int i; /* Loop counter */ |
||
1300 | int pc; /* Address of a i-th cell */ |
||
1301 | int addr; /* Offset of first byte after cell pointer array */ |
||
1302 | int hdr; /* Offset to the page header */ |
||
1303 | int size; /* Size of a cell */ |
||
1304 | int usableSize; /* Number of usable bytes on a page */ |
||
1305 | int cellOffset; /* Offset to the cell pointer array */ |
||
1306 | int cbrk; /* Offset to the cell content area */ |
||
1307 | int nCell; /* Number of cells on the page */ |
||
1308 | byte[] data; /* The page data */ |
||
1309 | byte[] temp; /* Temp area for cell content */ |
||
1310 | int iCellFirst; /* First allowable cell index */ |
||
1311 | int iCellLast; /* Last possible cell index */ |
||
1312 | |||
1313 | |||
1314 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
1315 | Debug.Assert( pPage.pBt != null ); |
||
1316 | Debug.Assert( pPage.pBt.usableSize <= SQLITE_MAX_PAGE_SIZE ); |
||
1317 | Debug.Assert( pPage.nOverflow == 0 ); |
||
1318 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1319 | temp = sqlite3PagerTempSpace( pPage.pBt.pPager ); |
||
1320 | data = pPage.aData; |
||
1321 | hdr = pPage.hdrOffset; |
||
1322 | cellOffset = pPage.cellOffset; |
||
1323 | nCell = pPage.nCell; |
||
1324 | Debug.Assert( nCell == get2byte( data, hdr + 3 ) ); |
||
1325 | usableSize = (int)pPage.pBt.usableSize; |
||
1326 | cbrk = get2byte( data, hdr + 5 ); |
||
1327 | Buffer.BlockCopy( data, cbrk, temp, cbrk, usableSize - cbrk );//memcpy( temp[cbrk], ref data[cbrk], usableSize - cbrk ); |
||
1328 | cbrk = usableSize; |
||
1329 | iCellFirst = cellOffset + 2 * nCell; |
||
1330 | iCellLast = usableSize - 4; |
||
1331 | for ( i = 0; i < nCell; i++ ) |
||
1332 | { |
||
1333 | int pAddr; /* The i-th cell pointer */ |
||
1334 | pAddr = cellOffset + i * 2; // &data[cellOffset + i * 2]; |
||
1335 | pc = get2byte( data, pAddr ); |
||
1336 | testcase( pc == iCellFirst ); |
||
1337 | testcase( pc == iCellLast ); |
||
1338 | #if !SQLITE_ENABLE_OVERSIZE_CELL_CHECK |
||
1339 | /* These conditions have already been verified in btreeInitPage() |
||
1340 | ** if SQLITE_ENABLE_OVERSIZE_CELL_CHECK is defined |
||
1341 | */ |
||
1342 | if ( pc < iCellFirst || pc > iCellLast ) |
||
1343 | { |
||
1344 | return SQLITE_CORRUPT_BKPT(); |
||
1345 | } |
||
1346 | #endif |
||
1347 | Debug.Assert( pc >= iCellFirst && pc <= iCellLast ); |
||
1348 | size = cellSizePtr( pPage, temp, pc ); |
||
1349 | cbrk -= size; |
||
1350 | #if SQLITE_ENABLE_OVERSIZE_CELL_CHECK |
||
1351 | if ( cbrk < iCellFirst || pc + size > usableSize ) |
||
1352 | { |
||
1353 | return SQLITE_CORRUPT_BKPT(); |
||
1354 | } |
||
1355 | #else |
||
1356 | if ( cbrk < iCellFirst || pc + size > usableSize ) |
||
1357 | { |
||
1358 | return SQLITE_CORRUPT_BKPT(); |
||
1359 | } |
||
1360 | #endif |
||
1361 | Debug.Assert( cbrk + size <= usableSize && cbrk >= iCellFirst ); |
||
1362 | testcase( cbrk + size == usableSize ); |
||
1363 | testcase( pc + size == usableSize ); |
||
1364 | Buffer.BlockCopy( temp, pc, data, cbrk, size );//memcpy(data[cbrk], ref temp[pc], size); |
||
1365 | put2byte( data, pAddr, cbrk ); |
||
1366 | } |
||
1367 | Debug.Assert( cbrk >= iCellFirst ); |
||
1368 | put2byte( data, hdr + 5, cbrk ); |
||
1369 | data[hdr + 1] = 0; |
||
1370 | data[hdr + 2] = 0; |
||
1371 | data[hdr + 7] = 0; |
||
1372 | addr = cellOffset + 2 * nCell; |
||
1373 | Array.Clear( data, addr, cbrk - addr ); //memset(data[iCellFirst], 0, cbrk-iCellFirst); |
||
1374 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
1375 | if ( cbrk - iCellFirst != pPage.nFree ) |
||
1376 | { |
||
1377 | return SQLITE_CORRUPT_BKPT(); |
||
1378 | } |
||
1379 | return SQLITE_OK; |
||
1380 | } |
||
1381 | |||
1382 | /* |
||
1383 | ** Allocate nByte bytes of space from within the B-Tree page passed |
||
1384 | ** as the first argument. Write into pIdx the index into pPage.aData[] |
||
1385 | ** of the first byte of allocated space. Return either SQLITE_OK or |
||
1386 | ** an error code (usually SQLITE_CORRUPT). |
||
1387 | ** |
||
1388 | ** The caller guarantees that there is sufficient space to make the |
||
1389 | ** allocation. This routine might need to defragment in order to bring |
||
1390 | ** all the space together, however. This routine will avoid using |
||
1391 | ** the first two bytes past the cell pointer area since presumably this |
||
1392 | ** allocation is being made in order to insert a new cell, so we will |
||
1393 | ** also end up needing a new cell pointer. |
||
1394 | */ |
||
1395 | static int allocateSpace( MemPage pPage, int nByte, ref int pIdx ) |
||
1396 | { |
||
1397 | int hdr = pPage.hdrOffset; /* Local cache of pPage.hdrOffset */ |
||
1398 | u8[] data = pPage.aData; /* Local cache of pPage.aData */ |
||
1399 | int nFrag; /* Number of fragmented bytes on pPage */ |
||
1400 | int top; /* First byte of cell content area */ |
||
1401 | int gap; /* First byte of gap between cell pointers and cell content */ |
||
1402 | int rc; /* Integer return code */ |
||
1403 | u32 usableSize; /* Usable size of the page */ |
||
1404 | |||
1405 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
1406 | Debug.Assert( pPage.pBt != null ); |
||
1407 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1408 | Debug.Assert( nByte >= 0 ); /* Minimum cell size is 4 */ |
||
1409 | Debug.Assert( pPage.nFree >= nByte ); |
||
1410 | Debug.Assert( pPage.nOverflow == 0 ); |
||
1411 | usableSize = pPage.pBt.usableSize; |
||
1412 | Debug.Assert( nByte < usableSize - 8 ); |
||
1413 | |||
1414 | nFrag = data[hdr + 7]; |
||
1415 | Debug.Assert( pPage.cellOffset == hdr + 12 - 4 * pPage.leaf ); |
||
1416 | gap = pPage.cellOffset + 2 * pPage.nCell; |
||
1417 | top = get2byteNotZero( data, hdr + 5 ); |
||
1418 | if ( gap > top ) |
||
1419 | return SQLITE_CORRUPT_BKPT(); |
||
1420 | testcase( gap + 2 == top ); |
||
1421 | testcase( gap + 1 == top ); |
||
1422 | testcase( gap == top ); |
||
1423 | |||
1424 | if ( nFrag >= 60 ) |
||
1425 | { |
||
1426 | /* Always defragment highly fragmented pages */ |
||
1427 | rc = defragmentPage( pPage ); |
||
1428 | if ( rc != 0 ) |
||
1429 | return rc; |
||
1430 | top = get2byteNotZero( data, hdr + 5 ); |
||
1431 | } |
||
1432 | else if ( gap + 2 <= top ) |
||
1433 | { |
||
1434 | /* Search the freelist looking for a free slot big enough to satisfy |
||
1435 | ** the request. The allocation is made from the first free slot in |
||
1436 | ** the list that is large enough to accomadate it. |
||
1437 | */ |
||
1438 | int pc, addr; |
||
1439 | for ( addr = hdr + 1; ( pc = get2byte( data, addr ) ) > 0; addr = pc ) |
||
1440 | { |
||
1441 | int size; /* Size of free slot */ |
||
1442 | if ( pc > usableSize - 4 || pc < addr + 4 ) |
||
1443 | { |
||
1444 | return SQLITE_CORRUPT_BKPT(); |
||
1445 | } |
||
1446 | size = get2byte( data, pc + 2 ); |
||
1447 | if ( size >= nByte ) |
||
1448 | { |
||
1449 | int x = size - nByte; |
||
1450 | testcase( x == 4 ); |
||
1451 | testcase( x == 3 ); |
||
1452 | if ( x < 4 ) |
||
1453 | { |
||
1454 | /* Remove the slot from the free-list. Update the number of |
||
1455 | ** fragmented bytes within the page. */ |
||
1456 | data[addr + 0] = data[pc + 0]; |
||
1457 | data[addr + 1] = data[pc + 1]; //memcpy( data[addr], ref data[pc], 2 ); |
||
1458 | data[hdr + 7] = (u8)( nFrag + x ); |
||
1459 | } |
||
1460 | else if ( size + pc > usableSize ) |
||
1461 | { |
||
1462 | return SQLITE_CORRUPT_BKPT(); |
||
1463 | } |
||
1464 | else |
||
1465 | { |
||
1466 | /* The slot remains on the free-list. Reduce its size to account |
||
1467 | ** for the portion used by the new allocation. */ |
||
1468 | put2byte( data, pc + 2, x ); |
||
1469 | } |
||
1470 | pIdx = pc + x; |
||
1471 | return SQLITE_OK; |
||
1472 | } |
||
1473 | } |
||
1474 | } |
||
1475 | |||
1476 | /* Check to make sure there is enough space in the gap to satisfy |
||
1477 | ** the allocation. If not, defragment. |
||
1478 | */ |
||
1479 | testcase( gap + 2 + nByte == top ); |
||
1480 | if ( gap + 2 + nByte > top ) |
||
1481 | { |
||
1482 | rc = defragmentPage( pPage ); |
||
1483 | if ( rc != 0 ) |
||
1484 | return rc; |
||
1485 | top = get2byteNotZero( data, hdr + 5 ); |
||
1486 | Debug.Assert( gap + nByte <= top ); |
||
1487 | } |
||
1488 | |||
1489 | |||
1490 | /* Allocate memory from the gap in between the cell pointer array |
||
1491 | ** and the cell content area. The btreeInitPage() call has already |
||
1492 | ** validated the freelist. Given that the freelist is valid, there |
||
1493 | ** is no way that the allocation can extend off the end of the page. |
||
1494 | ** The Debug.Assert() below verifies the previous sentence. |
||
1495 | */ |
||
1496 | top -= nByte; |
||
1497 | put2byte( data, hdr + 5, top ); |
||
1498 | Debug.Assert( top + nByte <= (int)pPage.pBt.usableSize ); |
||
1499 | pIdx = top; |
||
1500 | return SQLITE_OK; |
||
1501 | } |
||
1502 | |||
1503 | /* |
||
1504 | ** Return a section of the pPage.aData to the freelist. |
||
1505 | ** The first byte of the new free block is pPage.aDisk[start] |
||
1506 | ** and the size of the block is "size" bytes. |
||
1507 | ** |
||
1508 | ** Most of the effort here is involved in coalesing adjacent |
||
1509 | ** free blocks into a single big free block. |
||
1510 | */ |
||
1511 | static int freeSpace( MemPage pPage, u32 start, int size ) |
||
1512 | { |
||
1513 | return freeSpace( pPage, (int)start, size ); |
||
1514 | } |
||
1515 | static int freeSpace( MemPage pPage, int start, int size ) |
||
1516 | { |
||
1517 | int addr, pbegin, hdr; |
||
1518 | int iLast; /* Largest possible freeblock offset */ |
||
1519 | byte[] data = pPage.aData; |
||
1520 | |||
1521 | Debug.Assert( pPage.pBt != null ); |
||
1522 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
1523 | Debug.Assert( start >= pPage.hdrOffset + 6 + pPage.childPtrSize ); |
||
1524 | Debug.Assert( ( start + size ) <= (int)pPage.pBt.usableSize ); |
||
1525 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1526 | Debug.Assert( size >= 0 ); /* Minimum cell size is 4 */ |
||
1527 | |||
1528 | if ( pPage.pBt.secureDelete ) |
||
1529 | { |
||
1530 | /* Overwrite deleted information with zeros when the secure_delete |
||
1531 | ** option is enabled */ |
||
1532 | Array.Clear( data, start, size );// memset(&data[start], 0, size); |
||
1533 | } |
||
1534 | |||
1535 | /* Add the space back into the linked list of freeblocks. Note that |
||
1536 | ** even though the freeblock list was checked by btreeInitPage(), |
||
1537 | ** btreeInitPage() did not detect overlapping cells or |
||
1538 | ** freeblocks that overlapped cells. Nor does it detect when the |
||
1539 | ** cell content area exceeds the value in the page header. If these |
||
1540 | ** situations arise, then subsequent insert operations might corrupt |
||
1541 | ** the freelist. So we do need to check for corruption while scanning |
||
1542 | ** the freelist. |
||
1543 | */ |
||
1544 | hdr = pPage.hdrOffset; |
||
1545 | addr = hdr + 1; |
||
1546 | iLast = (int)pPage.pBt.usableSize - 4; |
||
1547 | Debug.Assert( start <= iLast ); |
||
1548 | while ( ( pbegin = get2byte( data, addr ) ) < start && pbegin > 0 ) |
||
1549 | { |
||
1550 | if ( pbegin < addr + 4 ) |
||
1551 | { |
||
1552 | return SQLITE_CORRUPT_BKPT(); |
||
1553 | } |
||
1554 | addr = pbegin; |
||
1555 | } |
||
1556 | if ( pbegin > iLast ) |
||
1557 | { |
||
1558 | return SQLITE_CORRUPT_BKPT(); |
||
1559 | } |
||
1560 | Debug.Assert( pbegin > addr || pbegin == 0 ); |
||
1561 | put2byte( data, addr, start ); |
||
1562 | put2byte( data, start, pbegin ); |
||
1563 | put2byte( data, start + 2, size ); |
||
1564 | pPage.nFree = (u16)( pPage.nFree + size ); |
||
1565 | |||
1566 | /* Coalesce adjacent free blocks */ |
||
1567 | addr = hdr + 1; |
||
1568 | while ( ( pbegin = get2byte( data, addr ) ) > 0 ) |
||
1569 | { |
||
1570 | int pnext, psize, x; |
||
1571 | Debug.Assert( pbegin > addr ); |
||
1572 | Debug.Assert( pbegin <= (int)pPage.pBt.usableSize - 4 ); |
||
1573 | pnext = get2byte( data, pbegin ); |
||
1574 | psize = get2byte( data, pbegin + 2 ); |
||
1575 | if ( pbegin + psize + 3 >= pnext && pnext > 0 ) |
||
1576 | { |
||
1577 | int frag = pnext - ( pbegin + psize ); |
||
1578 | if ( ( frag < 0 ) || ( frag > (int)data[hdr + 7] ) ) |
||
1579 | { |
||
1580 | return SQLITE_CORRUPT_BKPT(); |
||
1581 | } |
||
1582 | data[hdr + 7] -= (u8)frag; |
||
1583 | x = get2byte( data, pnext ); |
||
1584 | put2byte( data, pbegin, x ); |
||
1585 | x = pnext + get2byte( data, pnext + 2 ) - pbegin; |
||
1586 | put2byte( data, pbegin + 2, x ); |
||
1587 | } |
||
1588 | else |
||
1589 | { |
||
1590 | addr = pbegin; |
||
1591 | } |
||
1592 | } |
||
1593 | |||
1594 | /* If the cell content area begins with a freeblock, remove it. */ |
||
1595 | if ( data[hdr + 1] == data[hdr + 5] && data[hdr + 2] == data[hdr + 6] ) |
||
1596 | { |
||
1597 | int top; |
||
1598 | pbegin = get2byte( data, hdr + 1 ); |
||
1599 | put2byte( data, hdr + 1, get2byte( data, pbegin ) ); //memcpy( data[hdr + 1], ref data[pbegin], 2 ); |
||
1600 | top = get2byte( data, hdr + 5 ) + get2byte( data, pbegin + 2 ); |
||
1601 | put2byte( data, hdr + 5, top ); |
||
1602 | } |
||
1603 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
1604 | return SQLITE_OK; |
||
1605 | } |
||
1606 | |||
1607 | /* |
||
1608 | ** Decode the flags byte (the first byte of the header) for a page |
||
1609 | ** and initialize fields of the MemPage structure accordingly. |
||
1610 | ** |
||
1611 | ** Only the following combinations are supported. Anything different |
||
1612 | ** indicates a corrupt database files: |
||
1613 | ** |
||
1614 | ** PTF_ZERODATA |
||
1615 | ** PTF_ZERODATA | PTF_LEAF |
||
1616 | ** PTF_LEAFDATA | PTF_INTKEY |
||
1617 | ** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF |
||
1618 | */ |
||
1619 | static int decodeFlags( MemPage pPage, int flagByte ) |
||
1620 | { |
||
1621 | BtShared pBt; /* A copy of pPage.pBt */ |
||
1622 | |||
1623 | Debug.Assert( pPage.hdrOffset == ( pPage.pgno == 1 ? 100 : 0 ) ); |
||
1624 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1625 | pPage.leaf = (u8)( flagByte >> 3 ); |
||
1626 | Debug.Assert( PTF_LEAF == 1 << 3 ); |
||
1627 | flagByte &= ~PTF_LEAF; |
||
1628 | pPage.childPtrSize = (u8)( 4 - 4 * pPage.leaf ); |
||
1629 | pBt = pPage.pBt; |
||
1630 | if ( flagByte == ( PTF_LEAFDATA | PTF_INTKEY ) ) |
||
1631 | { |
||
1632 | pPage.intKey = 1; |
||
1633 | pPage.hasData = pPage.leaf; |
||
1634 | pPage.maxLocal = pBt.maxLeaf; |
||
1635 | pPage.minLocal = pBt.minLeaf; |
||
1636 | } |
||
1637 | else if ( flagByte == PTF_ZERODATA ) |
||
1638 | { |
||
1639 | pPage.intKey = 0; |
||
1640 | pPage.hasData = 0; |
||
1641 | pPage.maxLocal = pBt.maxLocal; |
||
1642 | pPage.minLocal = pBt.minLocal; |
||
1643 | } |
||
1644 | else |
||
1645 | { |
||
1646 | return SQLITE_CORRUPT_BKPT(); |
||
1647 | } |
||
1648 | return SQLITE_OK; |
||
1649 | } |
||
1650 | |||
1651 | /* |
||
1652 | ** Initialize the auxiliary information for a disk block. |
||
1653 | ** |
||
1654 | ** Return SQLITE_OK on success. If we see that the page does |
||
1655 | ** not contain a well-formed database page, then return |
||
1656 | ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not |
||
1657 | ** guarantee that the page is well-formed. It only shows that |
||
1658 | ** we failed to detect any corruption. |
||
1659 | */ |
||
1660 | static int btreeInitPage( MemPage pPage ) |
||
1661 | { |
||
1662 | |||
1663 | Debug.Assert( pPage.pBt != null ); |
||
1664 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1665 | Debug.Assert( pPage.pgno == sqlite3PagerPagenumber( pPage.pDbPage ) ); |
||
1666 | Debug.Assert( pPage == sqlite3PagerGetExtra( pPage.pDbPage ) ); |
||
1667 | Debug.Assert( pPage.aData == sqlite3PagerGetData( pPage.pDbPage ) ); |
||
1668 | |||
1669 | if ( 0 == pPage.isInit ) |
||
1670 | { |
||
1671 | u16 pc; /* Address of a freeblock within pPage.aData[] */ |
||
1672 | u8 hdr; /* Offset to beginning of page header */ |
||
1673 | u8[] data; /* Equal to pPage.aData */ |
||
1674 | BtShared pBt; /* The main btree structure */ |
||
1675 | int usableSize; /* Amount of usable space on each page */ |
||
1676 | u16 cellOffset; /* Offset from start of page to first cell pointer */ |
||
1677 | int nFree; /* Number of unused bytes on the page */ |
||
1678 | int top; /* First byte of the cell content area */ |
||
1679 | int iCellFirst; /* First allowable cell or freeblock offset */ |
||
1680 | int iCellLast; /* Last possible cell or freeblock offset */ |
||
1681 | |||
1682 | pBt = pPage.pBt; |
||
1683 | |||
1684 | hdr = pPage.hdrOffset; |
||
1685 | data = pPage.aData; |
||
1686 | if ( decodeFlags( pPage, data[hdr] ) != 0 ) |
||
1687 | return SQLITE_CORRUPT_BKPT(); |
||
1688 | Debug.Assert( pBt.pageSize >= 512 && pBt.pageSize <= 65536 ); |
||
1689 | pPage.maskPage = (u16)( pBt.pageSize - 1 ); |
||
1690 | pPage.nOverflow = 0; |
||
1691 | usableSize = (int)pBt.usableSize; |
||
1692 | pPage.cellOffset = ( cellOffset = (u16)( hdr + 12 - 4 * pPage.leaf ) ); |
||
1693 | top = get2byteNotZero( data, hdr + 5 ); |
||
1694 | pPage.nCell = (u16)( get2byte( data, hdr + 3 ) ); |
||
1695 | if ( pPage.nCell > MX_CELL( pBt ) ) |
||
1696 | { |
||
1697 | /* To many cells for a single page. The page must be corrupt */ |
||
1698 | return SQLITE_CORRUPT_BKPT(); |
||
1699 | } |
||
1700 | testcase( pPage.nCell == MX_CELL( pBt ) ); |
||
1701 | |||
1702 | /* A malformed database page might cause us to read past the end |
||
1703 | ** of page when parsing a cell. |
||
1704 | ** |
||
1705 | ** The following block of code checks early to see if a cell extends |
||
1706 | ** past the end of a page boundary and causes SQLITE_CORRUPT to be |
||
1707 | ** returned if it does. |
||
1708 | */ |
||
1709 | iCellFirst = cellOffset + 2 * pPage.nCell; |
||
1710 | iCellLast = usableSize - 4; |
||
1711 | #if SQLITE_ENABLE_OVERSIZE_CELL_CHECK |
||
1712 | { |
||
1713 | int i; /* Index into the cell pointer array */ |
||
1714 | int sz; /* Size of a cell */ |
||
1715 | |||
1716 | if ( 0 == pPage.leaf ) |
||
1717 | iCellLast--; |
||
1718 | for ( i = 0; i < pPage.nCell; i++ ) |
||
1719 | { |
||
1720 | pc = (u16)get2byte( data, cellOffset + i * 2 ); |
||
1721 | testcase( pc == iCellFirst ); |
||
1722 | testcase( pc == iCellLast ); |
||
1723 | if ( pc < iCellFirst || pc > iCellLast ) |
||
1724 | { |
||
1725 | return SQLITE_CORRUPT_BKPT(); |
||
1726 | } |
||
1727 | sz = cellSizePtr( pPage, data, pc ); |
||
1728 | testcase( pc + sz == usableSize ); |
||
1729 | if ( pc + sz > usableSize ) |
||
1730 | { |
||
1731 | return SQLITE_CORRUPT_BKPT(); |
||
1732 | } |
||
1733 | } |
||
1734 | if ( 0 == pPage.leaf ) |
||
1735 | iCellLast++; |
||
1736 | } |
||
1737 | #endif |
||
1738 | |||
1739 | /* Compute the total free space on the page */ |
||
1740 | pc = (u16)get2byte( data, hdr + 1 ); |
||
1741 | nFree = (u16)( data[hdr + 7] + top ); |
||
1742 | while ( pc > 0 ) |
||
1743 | { |
||
1744 | u16 next, size; |
||
1745 | if ( pc < iCellFirst || pc > iCellLast ) |
||
1746 | { |
||
1747 | /* Start of free block is off the page */ |
||
1748 | return SQLITE_CORRUPT_BKPT(); |
||
1749 | } |
||
1750 | next = (u16)get2byte( data, pc ); |
||
1751 | size = (u16)get2byte( data, pc + 2 ); |
||
1752 | if ( ( next > 0 && next <= pc + size + 3 ) || pc + size > usableSize ) |
||
1753 | { |
||
1754 | /* Free blocks must be in ascending order. And the last byte of |
||
1755 | ** the free-block must lie on the database page. */ |
||
1756 | return SQLITE_CORRUPT_BKPT(); |
||
1757 | } |
||
1758 | nFree = (u16)( nFree + size ); |
||
1759 | pc = next; |
||
1760 | } |
||
1761 | |||
1762 | /* At this point, nFree contains the sum of the offset to the start |
||
1763 | ** of the cell-content area plus the number of free bytes within |
||
1764 | ** the cell-content area. If this is greater than the usable-size |
||
1765 | ** of the page, then the page must be corrupted. This check also |
||
1766 | ** serves to verify that the offset to the start of the cell-content |
||
1767 | ** area, according to the page header, lies within the page. |
||
1768 | */ |
||
1769 | if ( nFree > usableSize ) |
||
1770 | { |
||
1771 | return SQLITE_CORRUPT_BKPT(); |
||
1772 | } |
||
1773 | pPage.nFree = (u16)( nFree - iCellFirst ); |
||
1774 | pPage.isInit = 1; |
||
1775 | } |
||
1776 | return SQLITE_OK; |
||
1777 | } |
||
1778 | |||
1779 | /* |
||
1780 | ** Set up a raw page so that it looks like a database page holding |
||
1781 | ** no entries. |
||
1782 | */ |
||
1783 | static void zeroPage( MemPage pPage, int flags ) |
||
1784 | { |
||
1785 | byte[] data = pPage.aData; |
||
1786 | BtShared pBt = pPage.pBt; |
||
1787 | u8 hdr = pPage.hdrOffset; |
||
1788 | u16 first; |
||
1789 | |||
1790 | Debug.Assert( sqlite3PagerPagenumber( pPage.pDbPage ) == pPage.pgno ); |
||
1791 | Debug.Assert( sqlite3PagerGetExtra( pPage.pDbPage ) == pPage ); |
||
1792 | Debug.Assert( sqlite3PagerGetData( pPage.pDbPage ) == data ); |
||
1793 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
1794 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
1795 | if ( pBt.secureDelete ) |
||
1796 | { |
||
1797 | Array.Clear( data, hdr, (int)( pBt.usableSize - hdr ) );//memset(&data[hdr], 0, pBt->usableSize - hdr); |
||
1798 | } |
||
1799 | |||
1800 | data[hdr] = (u8)flags; |
||
1801 | first = (u16)( hdr + 8 + 4 * ( ( flags & PTF_LEAF ) == 0 ? 1 : 0 ) ); |
||
1802 | Array.Clear( data, hdr + 1, 4 );//memset(data[hdr+1], 0, 4); |
||
1803 | data[hdr + 7] = 0; |
||
1804 | put2byte( data, hdr + 5, pBt.usableSize ); |
||
1805 | pPage.nFree = (u16)( pBt.usableSize - first ); |
||
1806 | decodeFlags( pPage, flags ); |
||
1807 | pPage.hdrOffset = hdr; |
||
1808 | pPage.cellOffset = first; |
||
1809 | pPage.nOverflow = 0; |
||
1810 | Debug.Assert( pBt.pageSize >= 512 && pBt.pageSize <= 65536 ); |
||
1811 | pPage.maskPage = (u16)( pBt.pageSize - 1 ); |
||
1812 | pPage.nCell = 0; |
||
1813 | pPage.isInit = 1; |
||
1814 | } |
||
1815 | |||
1816 | |||
1817 | /* |
||
1818 | ** Convert a DbPage obtained from the pager into a MemPage used by |
||
1819 | ** the btree layer. |
||
1820 | */ |
||
1821 | static MemPage btreePageFromDbPage( DbPage pDbPage, Pgno pgno, BtShared pBt ) |
||
1822 | { |
||
1823 | MemPage pPage = (MemPage)sqlite3PagerGetExtra( pDbPage ); |
||
1824 | pPage.aData = sqlite3PagerGetData( pDbPage ); |
||
1825 | pPage.pDbPage = pDbPage; |
||
1826 | pPage.pBt = pBt; |
||
1827 | pPage.pgno = pgno; |
||
1828 | pPage.hdrOffset = (u8)( pPage.pgno == 1 ? 100 : 0 ); |
||
1829 | return pPage; |
||
1830 | } |
||
1831 | |||
1832 | /* |
||
1833 | ** Get a page from the pager. Initialize the MemPage.pBt and |
||
1834 | ** MemPage.aData elements if needed. |
||
1835 | ** |
||
1836 | ** If the noContent flag is set, it means that we do not care about |
||
1837 | ** the content of the page at this time. So do not go to the disk |
||
1838 | ** to fetch the content. Just fill in the content with zeros for now. |
||
1839 | ** If in the future we call sqlite3PagerWrite() on this page, that |
||
1840 | ** means we have started to be concerned about content and the disk |
||
1841 | ** read should occur at that point. |
||
1842 | */ |
||
1843 | static int btreeGetPage( |
||
1844 | BtShared pBt, /* The btree */ |
||
1845 | Pgno pgno, /* Number of the page to fetch */ |
||
1846 | ref MemPage ppPage, /* Return the page in this parameter */ |
||
1847 | int noContent /* Do not load page content if true */ |
||
1848 | ) |
||
1849 | { |
||
1850 | int rc; |
||
1851 | DbPage pDbPage = null; |
||
1852 | |||
1853 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
1854 | rc = sqlite3PagerAcquire( pBt.pPager, pgno, ref pDbPage, (u8)noContent ); |
||
1855 | if ( rc != 0 ) |
||
1856 | return rc; |
||
1857 | ppPage = btreePageFromDbPage( pDbPage, pgno, pBt ); |
||
1858 | return SQLITE_OK; |
||
1859 | } |
||
1860 | |||
1861 | /* |
||
1862 | ** Retrieve a page from the pager cache. If the requested page is not |
||
1863 | ** already in the pager cache return NULL. Initialize the MemPage.pBt and |
||
1864 | ** MemPage.aData elements if needed. |
||
1865 | */ |
||
1866 | static MemPage btreePageLookup( BtShared pBt, Pgno pgno ) |
||
1867 | { |
||
1868 | DbPage pDbPage; |
||
1869 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
1870 | pDbPage = sqlite3PagerLookup( pBt.pPager, pgno ); |
||
1871 | if ( pDbPage ) |
||
1872 | { |
||
1873 | return btreePageFromDbPage( pDbPage, pgno, pBt ); |
||
1874 | } |
||
1875 | return null; |
||
1876 | } |
||
1877 | |||
1878 | /* |
||
1879 | ** Return the size of the database file in pages. If there is any kind of |
||
1880 | ** error, return ((unsigned int)-1). |
||
1881 | */ |
||
1882 | static Pgno btreePagecount( BtShared pBt ) |
||
1883 | { |
||
1884 | return pBt.nPage; |
||
1885 | } |
||
1886 | static Pgno sqlite3BtreeLastPage( Btree p ) |
||
1887 | { |
||
1888 | Debug.Assert( sqlite3BtreeHoldsMutex( p ) ); |
||
1889 | Debug.Assert( ( ( p.pBt.nPage ) & 0x8000000 ) == 0 ); |
||
1890 | return (Pgno)btreePagecount( p.pBt ); |
||
1891 | } |
||
1892 | |||
1893 | |||
1894 | |||
1895 | /* |
||
1896 | ** Get a page from the pager and initialize it. This routine is just a |
||
1897 | ** convenience wrapper around separate calls to btreeGetPage() and |
||
1898 | ** btreeInitPage(). |
||
1899 | ** |
||
1900 | ** If an error occurs, then the value ppPage is set to is undefined. It |
||
1901 | ** may remain unchanged, or it may be set to an invalid value. |
||
1902 | */ |
||
1903 | static int getAndInitPage( |
||
1904 | BtShared pBt, /* The database file */ |
||
1905 | Pgno pgno, /* Number of the page to get */ |
||
1906 | ref MemPage ppPage /* Write the page pointer here */ |
||
1907 | ) |
||
1908 | { |
||
1909 | int rc; |
||
1910 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
1911 | |||
1912 | if ( pgno > btreePagecount( pBt ) ) |
||
1913 | { |
||
1914 | rc = SQLITE_CORRUPT_BKPT(); |
||
1915 | } |
||
1916 | else |
||
1917 | { |
||
1918 | rc = btreeGetPage( pBt, pgno, ref ppPage, 0 ); |
||
1919 | if ( rc == SQLITE_OK ) |
||
1920 | { |
||
1921 | rc = btreeInitPage( ppPage ); |
||
1922 | if ( rc != SQLITE_OK ) |
||
1923 | { |
||
1924 | releasePage( ppPage ); |
||
1925 | } |
||
1926 | } |
||
1927 | } |
||
1928 | |||
1929 | testcase( pgno == 0 ); |
||
1930 | Debug.Assert( pgno != 0 || rc == SQLITE_CORRUPT ); |
||
1931 | |||
1932 | return rc; |
||
1933 | } |
||
1934 | |||
1935 | /* |
||
1936 | ** Release a MemPage. This should be called once for each prior |
||
1937 | ** call to btreeGetPage. |
||
1938 | */ |
||
1939 | static void releasePage( MemPage pPage ) |
||
1940 | { |
||
1941 | if ( pPage != null ) |
||
1942 | { |
||
1943 | Debug.Assert( pPage.aData != null ); |
||
1944 | Debug.Assert( pPage.pBt != null ); |
||
1945 | //TODO -- find out why corrupt9 & diskfull fail on this tests |
||
1946 | //Debug.Assert( sqlite3PagerGetExtra( pPage.pDbPage ) == pPage ); |
||
1947 | //Debug.Assert( sqlite3PagerGetData( pPage.pDbPage ) == pPage.aData ); |
||
1948 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1949 | sqlite3PagerUnref( pPage.pDbPage ); |
||
1950 | } |
||
1951 | } |
||
1952 | |||
1953 | /* |
||
1954 | ** During a rollback, when the pager reloads information into the cache |
||
1955 | ** so that the cache is restored to its original state at the start of |
||
1956 | ** the transaction, for each page restored this routine is called. |
||
1957 | ** |
||
1958 | ** This routine needs to reset the extra data section at the end of the |
||
1959 | ** page to agree with the restored data. |
||
1960 | */ |
||
1961 | static void pageReinit( DbPage pData ) |
||
1962 | { |
||
1963 | MemPage pPage; |
||
1964 | pPage = sqlite3PagerGetExtra( pData ); |
||
1965 | Debug.Assert( sqlite3PagerPageRefcount( pData ) > 0 ); |
||
1966 | if ( pPage.isInit != 0 ) |
||
1967 | { |
||
1968 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
1969 | pPage.isInit = 0; |
||
1970 | if ( sqlite3PagerPageRefcount( pData ) > 1 ) |
||
1971 | { |
||
1972 | /* pPage might not be a btree page; it might be an overflow page |
||
1973 | ** or ptrmap page or a free page. In those cases, the following |
||
1974 | ** call to btreeInitPage() will likely return SQLITE_CORRUPT. |
||
1975 | ** But no harm is done by this. And it is very important that |
||
1976 | ** btreeInitPage() be called on every btree page so we make |
||
1977 | ** the call for every page that comes in for re-initing. */ |
||
1978 | btreeInitPage( pPage ); |
||
1979 | } |
||
1980 | } |
||
1981 | } |
||
1982 | |||
1983 | /* |
||
1984 | ** Invoke the busy handler for a btree. |
||
1985 | */ |
||
1986 | static int btreeInvokeBusyHandler( object pArg ) |
||
1987 | { |
||
1988 | BtShared pBt = (BtShared)pArg; |
||
1989 | Debug.Assert( pBt.db != null ); |
||
1990 | Debug.Assert( sqlite3_mutex_held( pBt.db.mutex ) ); |
||
1991 | return sqlite3InvokeBusyHandler( pBt.db.busyHandler ); |
||
1992 | } |
||
1993 | |||
1994 | /* |
||
1995 | ** Open a database file. |
||
1996 | ** |
||
1997 | ** zFilename is the name of the database file. If zFilename is NULL |
||
1998 | ** then an ephemeral database is created. The ephemeral database might |
||
1999 | ** be exclusively in memory, or it might use a disk-based memory cache. |
||
2000 | ** Either way, the ephemeral database will be automatically deleted |
||
2001 | ** when sqlite3BtreeClose() is called. |
||
2002 | ** |
||
2003 | ** If zFilename is ":memory:" then an in-memory database is created |
||
2004 | ** that is automatically destroyed when it is closed. |
||
2005 | ** |
||
2006 | ** The "flags" parameter is a bitmask that might contain bits |
||
2007 | ** BTREE_OMIT_JOURNAL and/or BTREE_NO_READLOCK. The BTREE_NO_READLOCK |
||
2008 | ** bit is also set if the SQLITE_NoReadlock flags is set in db->flags. |
||
2009 | ** These flags are passed through into sqlite3PagerOpen() and must |
||
2010 | ** be the same values as PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK. |
||
2011 | ** |
||
2012 | ** If the database is already opened in the same database connection |
||
2013 | ** and we are in shared cache mode, then the open will fail with an |
||
2014 | ** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared |
||
2015 | ** objects in the same database connection since doing so will lead |
||
2016 | ** to problems with locking. |
||
2017 | */ |
||
2018 | static int sqlite3BtreeOpen( |
||
2019 | sqlite3_vfs pVfs, /* VFS to use for this b-tree */ |
||
2020 | string zFilename, /* Name of the file containing the BTree database */ |
||
2021 | sqlite3 db, /* Associated database handle */ |
||
2022 | ref Btree ppBtree, /* Pointer to new Btree object written here */ |
||
2023 | int flags, /* Options */ |
||
2024 | int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ |
||
2025 | ) |
||
2026 | { |
||
2027 | BtShared pBt = null; /* Shared part of btree structure */ |
||
2028 | Btree p; /* Handle to return */ |
||
2029 | sqlite3_mutex mutexOpen = null; /* Prevents a race condition. Ticket #3537 */ |
||
2030 | int rc = SQLITE_OK; /* Result code from this function */ |
||
2031 | u8 nReserve; /* Byte of unused space on each page */ |
||
2032 | byte[] zDbHeader = new byte[100]; /* Database header content */ |
||
2033 | |||
2034 | /* True if opening an ephemeral, temporary database */ |
||
2035 | bool isTempDb = string.IsNullOrEmpty( zFilename );//zFilename==0 || zFilename[0]==0; |
||
2036 | |||
2037 | /* Set the variable isMemdb to true for an in-memory database, or |
||
2038 | ** false for a file-based database. |
||
2039 | */ |
||
2040 | #if SQLITE_OMIT_MEMORYDB |
||
2041 | bool isMemdb = false; |
||
2042 | #else |
||
2043 | bool isMemdb = ( zFilename == ":memory:" ) |
||
2044 | || ( isTempDb && sqlite3TempInMemory( db ) ); |
||
2045 | |||
2046 | #endif |
||
2047 | |||
2048 | Debug.Assert( db != null ); |
||
2049 | Debug.Assert( pVfs != null ); |
||
2050 | Debug.Assert( sqlite3_mutex_held( db.mutex ) ); |
||
2051 | Debug.Assert( ( flags & 0xff ) == flags ); /* flags fit in 8 bits */ |
||
2052 | |||
2053 | /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ |
||
2054 | Debug.Assert( ( flags & BTREE_UNORDERED ) == 0 || ( flags & BTREE_SINGLE ) != 0 ); |
||
2055 | |||
2056 | /* A BTREE_SINGLE database is always a temporary and/or ephemeral */ |
||
2057 | Debug.Assert( ( flags & BTREE_SINGLE ) == 0 || isTempDb ); |
||
2058 | |||
2059 | if ( ( db.flags & SQLITE_NoReadlock ) != 0 ) |
||
2060 | { |
||
2061 | flags |= BTREE_NO_READLOCK; |
||
2062 | } |
||
2063 | if ( isMemdb ) |
||
2064 | { |
||
2065 | flags |= BTREE_MEMORY; |
||
2066 | } |
||
2067 | if ( ( vfsFlags & SQLITE_OPEN_MAIN_DB ) != 0 && ( isMemdb || isTempDb ) ) |
||
2068 | { |
||
2069 | vfsFlags = ( vfsFlags & ~SQLITE_OPEN_MAIN_DB ) | SQLITE_OPEN_TEMP_DB; |
||
2070 | } |
||
2071 | |||
2072 | p = new Btree();//sqlite3MallocZero(sizeof(Btree)); |
||
2073 | //if( !p ){ |
||
2074 | // return SQLITE_NOMEM; |
||
2075 | //} |
||
2076 | p.inTrans = TRANS_NONE; |
||
2077 | p.db = db; |
||
2078 | #if !SQLITE_OMIT_SHARED_CACHE |
||
2079 | p.lock.pBtree = p; |
||
2080 | p.lock.iTable = 1; |
||
2081 | #endif |
||
2082 | |||
2083 | #if !(SQLITE_OMIT_SHARED_CACHE) && !(SQLITE_OMIT_DISKIO) |
||
2084 | /* |
||
2085 | ** If this Btree is a candidate for shared cache, try to find an |
||
2086 | ** existing BtShared object that we can share with |
||
2087 | */ |
||
2088 | if( !isMemdb && !isTempDb ){ |
||
2089 | if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ |
||
2090 | int nFullPathname = pVfs.mxPathname+1; |
||
2091 | string zFullPathname = sqlite3Malloc(nFullPathname); |
||
2092 | sqlite3_mutex *mutexShared; |
||
2093 | p.sharable = 1; |
||
2094 | if( !zFullPathname ){ |
||
2095 | p = null;//sqlite3_free(ref p); |
||
2096 | return SQLITE_NOMEM; |
||
2097 | } |
||
2098 | sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); |
||
2099 | mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); |
||
2100 | sqlite3_mutex_enter(mutexOpen); |
||
2101 | mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); |
||
2102 | sqlite3_mutex_enter(mutexShared); |
||
2103 | for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt.pNext){ |
||
2104 | Debug.Assert( pBt.nRef>0 ); |
||
2105 | if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt.pPager)) |
||
2106 | && sqlite3PagerVfs(pBt.pPager)==pVfs ){ |
||
2107 | int iDb; |
||
2108 | for(iDb=db.nDb-1; iDb>=0; iDb--){ |
||
2109 | Btree pExisting = db.aDb[iDb].pBt; |
||
2110 | if( pExisting && pExisting.pBt==pBt ){ |
||
2111 | sqlite3_mutex_leave(mutexShared); |
||
2112 | sqlite3_mutex_leave(mutexOpen); |
||
2113 | zFullPathname = null;//sqlite3_free(ref zFullPathname); |
||
2114 | p=null;//sqlite3_free(ref p); |
||
2115 | return SQLITE_CONSTRAINT; |
||
2116 | } |
||
2117 | } |
||
2118 | p.pBt = pBt; |
||
2119 | pBt.nRef++; |
||
2120 | break; |
||
2121 | } |
||
2122 | } |
||
2123 | sqlite3_mutex_leave(mutexShared); |
||
2124 | zFullPathname=null;//sqlite3_free(ref zFullPathname); |
||
2125 | } |
||
2126 | #if SQLITE_DEBUG |
||
2127 | else{ |
||
2128 | /* In debug mode, we mark all persistent databases as sharable |
||
2129 | ** even when they are not. This exercises the locking code and |
||
2130 | ** gives more opportunity for asserts(sqlite3_mutex_held()) |
||
2131 | ** statements to find locking problems. |
||
2132 | */ |
||
2133 | p.sharable = 1; |
||
2134 | } |
||
2135 | #endif |
||
2136 | } |
||
2137 | #endif |
||
2138 | if ( pBt == null ) |
||
2139 | { |
||
2140 | /* |
||
2141 | ** The following asserts make sure that structures used by the btree are |
||
2142 | ** the right size. This is to guard against size changes that result |
||
2143 | ** when compiling on a different architecture. |
||
2144 | */ |
||
2145 | // These are defined as constants in the CLI specifications. |
||
2146 | // (See, for example, C# spec sections 18.5.8 and 4.1.4) |
||
2147 | ////Debug.Assert( sizeof( i64 ) == 8 || sizeof( i64 ) == 4 ); |
||
2148 | ////Debug.Assert( sizeof( u64 ) == 8 || sizeof( u64 ) == 4 ); |
||
2149 | ////Debug.Assert( sizeof( u32 ) == 4 ); |
||
2150 | ////Debug.Assert( sizeof( u16 ) == 2 ); |
||
2151 | ////Debug.Assert( sizeof( Pgno ) == 4 ); |
||
2152 | |||
2153 | pBt = new BtShared();//sqlite3MallocZero( sizeof(pBt) ); |
||
2154 | //if( pBt==null ){ |
||
2155 | // rc = SQLITE_NOMEM; |
||
2156 | // goto btree_open_out; |
||
2157 | //} |
||
2158 | rc = sqlite3PagerOpen( pVfs, out pBt.pPager, zFilename, |
||
2159 | EXTRA_SIZE, flags, vfsFlags, pageReinit ); |
||
2160 | if ( rc == SQLITE_OK ) |
||
2161 | { |
||
2162 | rc = sqlite3PagerReadFileheader( pBt.pPager, zDbHeader.Length, zDbHeader ); |
||
2163 | } |
||
2164 | if ( rc != SQLITE_OK ) |
||
2165 | { |
||
2166 | goto btree_open_out; |
||
2167 | } |
||
2168 | pBt.openFlags = (u8)flags; |
||
2169 | pBt.db = db; |
||
2170 | sqlite3PagerSetBusyhandler( pBt.pPager, btreeInvokeBusyHandler, pBt ); |
||
2171 | p.pBt = pBt; |
||
2172 | |||
2173 | pBt.pCursor = null; |
||
2174 | pBt.pPage1 = null; |
||
2175 | pBt.readOnly = sqlite3PagerIsreadonly( pBt.pPager ); |
||
2176 | #if SQLITE_SECURE_DELETE |
||
2177 | pBt.secureDelete = true; |
||
2178 | #endif |
||
2179 | pBt.pageSize = (u32)( ( zDbHeader[16] << 8 ) | ( zDbHeader[17] << 16 ) ); |
||
2180 | if ( pBt.pageSize < 512 || pBt.pageSize > SQLITE_MAX_PAGE_SIZE |
||
2181 | || ( ( pBt.pageSize - 1 ) & pBt.pageSize ) != 0 ) |
||
2182 | { |
||
2183 | pBt.pageSize = 0; |
||
2184 | #if !SQLITE_OMIT_AUTOVACUUM |
||
2185 | /* If the magic name ":memory:" will create an in-memory database, then |
||
2186 | ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if |
||
2187 | ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if |
||
2188 | ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a |
||
2189 | ** regular file-name. In this case the auto-vacuum applies as per normal. |
||
2190 | */ |
||
2191 | if (zFilename != null && zFilename.Length > 0 && !isMemdb ) |
||
2192 | { |
||
2193 | pBt.autoVacuum = ( SQLITE_DEFAULT_AUTOVACUUM != 0 ); |
||
2194 | pBt.incrVacuum = ( SQLITE_DEFAULT_AUTOVACUUM == 2 ); |
||
2195 | } |
||
2196 | #endif |
||
2197 | nReserve = 0; |
||
2198 | } |
||
2199 | else |
||
2200 | { |
||
2201 | nReserve = zDbHeader[20]; |
||
2202 | pBt.pageSizeFixed = true; |
||
2203 | #if !SQLITE_OMIT_AUTOVACUUM |
||
2204 | pBt.autoVacuum = sqlite3Get4byte( zDbHeader, 36 + 4 * 4 ) != 0; |
||
2205 | pBt.incrVacuum = sqlite3Get4byte( zDbHeader, 36 + 7 * 4 ) != 0; |
||
2206 | #endif |
||
2207 | } |
||
2208 | rc = sqlite3PagerSetPagesize( pBt.pPager, ref pBt.pageSize, nReserve ); |
||
2209 | if ( rc != 0 ) |
||
2210 | goto btree_open_out; |
||
2211 | pBt.usableSize = (u16)( pBt.pageSize - nReserve ); |
||
2212 | Debug.Assert( ( pBt.pageSize & 7 ) == 0 ); /* 8-byte alignment of pageSize */ |
||
2213 | |||
2214 | #if !(SQLITE_OMIT_SHARED_CACHE) && !(SQLITE_OMIT_DISKIO) |
||
2215 | /* Add the new BtShared object to the linked list sharable BtShareds. |
||
2216 | */ |
||
2217 | if( p.sharable ){ |
||
2218 | sqlite3_mutex *mutexShared; |
||
2219 | pBt.nRef = 1; |
||
2220 | mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); |
||
2221 | if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ |
||
2222 | pBt.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); |
||
2223 | if( pBt.mutex==null ){ |
||
2224 | rc = SQLITE_NOMEM; |
||
2225 | db.mallocFailed = 0; |
||
2226 | goto btree_open_out; |
||
2227 | } |
||
2228 | } |
||
2229 | sqlite3_mutex_enter(mutexShared); |
||
2230 | pBt.pNext = GLOBAL(BtShared*,sqlite3SharedCacheList); |
||
2231 | GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt; |
||
2232 | sqlite3_mutex_leave(mutexShared); |
||
2233 | } |
||
2234 | #endif |
||
2235 | } |
||
2236 | |||
2237 | #if !(SQLITE_OMIT_SHARED_CACHE) && !(SQLITE_OMIT_DISKIO) |
||
2238 | /* If the new Btree uses a sharable pBtShared, then link the new |
||
2239 | ** Btree into the list of all sharable Btrees for the same connection. |
||
2240 | ** The list is kept in ascending order by pBt address. |
||
2241 | */ |
||
2242 | if( p.sharable ){ |
||
2243 | int i; |
||
2244 | Btree pSib; |
||
2245 | for(i=0; i<db.nDb; i++){ |
||
2246 | if( (pSib = db.aDb[i].pBt)!=null && pSib.sharable ){ |
||
2247 | while( pSib.pPrev ){ pSib = pSib.pPrev; } |
||
2248 | if( p.pBt<pSib.pBt ){ |
||
2249 | p.pNext = pSib; |
||
2250 | p.pPrev = 0; |
||
2251 | pSib.pPrev = p; |
||
2252 | }else{ |
||
2253 | while( pSib.pNext && pSib.pNext.pBt<p.pBt ){ |
||
2254 | pSib = pSib.pNext; |
||
2255 | } |
||
2256 | p.pNext = pSib.pNext; |
||
2257 | p.pPrev = pSib; |
||
2258 | if( p.pNext ){ |
||
2259 | p.pNext.pPrev = p; |
||
2260 | } |
||
2261 | pSib.pNext = p; |
||
2262 | } |
||
2263 | break; |
||
2264 | } |
||
2265 | } |
||
2266 | } |
||
2267 | #endif |
||
2268 | ppBtree = p; |
||
2269 | |||
2270 | btree_open_out: |
||
2271 | if ( rc != SQLITE_OK ) |
||
2272 | { |
||
2273 | if ( pBt != null && pBt.pPager != null ) |
||
2274 | { |
||
2275 | sqlite3PagerClose( pBt.pPager ); |
||
2276 | } |
||
2277 | pBt = null; // sqlite3_free(ref pBt); |
||
2278 | p = null; // sqlite3_free(ref p); |
||
2279 | ppBtree = null; |
||
2280 | } |
||
2281 | else |
||
2282 | { |
||
2283 | /* If the B-Tree was successfully opened, set the pager-cache size to the |
||
2284 | ** default value. Except, when opening on an existing shared pager-cache, |
||
2285 | ** do not change the pager-cache size. |
||
2286 | */ |
||
2287 | if ( sqlite3BtreeSchema( p, 0, null ) == null ) |
||
2288 | { |
||
2289 | sqlite3PagerSetCachesize( p.pBt.pPager, SQLITE_DEFAULT_CACHE_SIZE ); |
||
2290 | } |
||
2291 | |||
2292 | } |
||
2293 | if ( mutexOpen != null ) |
||
2294 | { |
||
2295 | Debug.Assert( sqlite3_mutex_held( mutexOpen ) ); |
||
2296 | sqlite3_mutex_leave( mutexOpen ); |
||
2297 | } |
||
2298 | return rc; |
||
2299 | } |
||
2300 | |||
2301 | /* |
||
2302 | ** Decrement the BtShared.nRef counter. When it reaches zero, |
||
2303 | ** remove the BtShared structure from the sharing list. Return |
||
2304 | ** true if the BtShared.nRef counter reaches zero and return |
||
2305 | ** false if it is still positive. |
||
2306 | */ |
||
2307 | static bool removeFromSharingList( BtShared pBt ) |
||
2308 | { |
||
2309 | #if !SQLITE_OMIT_SHARED_CACHE |
||
2310 | sqlite3_mutex pMaster; |
||
2311 | BtShared pList; |
||
2312 | bool removed = false; |
||
2313 | |||
2314 | Debug.Assert( sqlite3_mutex_notheld(pBt.mutex) ); |
||
2315 | pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); |
||
2316 | sqlite3_mutex_enter(pMaster); |
||
2317 | pBt.nRef--; |
||
2318 | if( pBt.nRef<=0 ){ |
||
2319 | if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){ |
||
2320 | GLOBAL(BtShared*,sqlite3SharedCacheList) = pBt.pNext; |
||
2321 | }else{ |
||
2322 | pList = GLOBAL(BtShared*,sqlite3SharedCacheList); |
||
2323 | while( ALWAYS(pList) && pList.pNext!=pBt ){ |
||
2324 | pList=pList.pNext; |
||
2325 | } |
||
2326 | if( ALWAYS(pList) ){ |
||
2327 | pList.pNext = pBt.pNext; |
||
2328 | } |
||
2329 | } |
||
2330 | if( SQLITE_THREADSAFE ){ |
||
2331 | sqlite3_mutex_free(pBt.mutex); |
||
2332 | } |
||
2333 | removed = true; |
||
2334 | } |
||
2335 | sqlite3_mutex_leave(pMaster); |
||
2336 | return removed; |
||
2337 | #else |
||
2338 | return true; |
||
2339 | #endif |
||
2340 | } |
||
2341 | |||
2342 | /* |
||
2343 | ** Make sure pBt.pTmpSpace points to an allocation of |
||
2344 | ** MX_CELL_SIZE(pBt) bytes. |
||
2345 | */ |
||
2346 | static void allocateTempSpace( BtShared pBt ) |
||
2347 | { |
||
2348 | if ( null == pBt.pTmpSpace ) |
||
2349 | { |
||
2350 | pBt.pTmpSpace = sqlite3Malloc( pBt.pageSize ); |
||
2351 | } |
||
2352 | } |
||
2353 | |||
2354 | /* |
||
2355 | ** Free the pBt.pTmpSpace allocation |
||
2356 | */ |
||
2357 | static void freeTempSpace( BtShared pBt ) |
||
2358 | { |
||
2359 | sqlite3PageFree( ref pBt.pTmpSpace ); |
||
2360 | } |
||
2361 | |||
2362 | /* |
||
2363 | ** Close an open database and invalidate all cursors. |
||
2364 | */ |
||
2365 | static int sqlite3BtreeClose( ref Btree p ) |
||
2366 | { |
||
2367 | BtShared pBt = p.pBt; |
||
2368 | BtCursor pCur; |
||
2369 | |||
2370 | /* Close all cursors opened via this handle. */ |
||
2371 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
2372 | sqlite3BtreeEnter( p ); |
||
2373 | pCur = pBt.pCursor; |
||
2374 | while ( pCur != null ) |
||
2375 | { |
||
2376 | BtCursor pTmp = pCur; |
||
2377 | pCur = pCur.pNext; |
||
2378 | if ( pTmp.pBtree == p ) |
||
2379 | { |
||
2380 | sqlite3BtreeCloseCursor( pTmp ); |
||
2381 | } |
||
2382 | } |
||
2383 | |||
2384 | /* Rollback any active transaction and free the handle structure. |
||
2385 | ** The call to sqlite3BtreeRollback() drops any table-locks held by |
||
2386 | ** this handle. |
||
2387 | */ |
||
2388 | sqlite3BtreeRollback( p ); |
||
2389 | sqlite3BtreeLeave( p ); |
||
2390 | |||
2391 | /* If there are still other outstanding references to the shared-btree |
||
2392 | ** structure, return now. The remainder of this procedure cleans |
||
2393 | ** up the shared-btree. |
||
2394 | */ |
||
2395 | Debug.Assert( p.wantToLock == 0 && !p.locked ); |
||
2396 | if ( !p.sharable || removeFromSharingList( pBt ) ) |
||
2397 | { |
||
2398 | /* The pBt is no longer on the sharing list, so we can access |
||
2399 | ** it without having to hold the mutex. |
||
2400 | ** |
||
2401 | ** Clean out and delete the BtShared object. |
||
2402 | */ |
||
2403 | Debug.Assert( null == pBt.pCursor ); |
||
2404 | sqlite3PagerClose( pBt.pPager ); |
||
2405 | if ( pBt.xFreeSchema != null && pBt.pSchema != null ) |
||
2406 | { |
||
2407 | pBt.xFreeSchema( pBt.pSchema ); |
||
2408 | } |
||
2409 | pBt.pSchema = null;// sqlite3DbFree(0, pBt->pSchema); |
||
2410 | //freeTempSpace(pBt); |
||
2411 | pBt = null; //sqlite3_free(ref pBt); |
||
2412 | } |
||
2413 | |||
2414 | #if !SQLITE_OMIT_SHARED_CACHE |
||
2415 | Debug.Assert( p.wantToLock==null ); |
||
2416 | Debug.Assert( p.locked==null ); |
||
2417 | if( p.pPrev ) p.pPrev.pNext = p.pNext; |
||
2418 | if( p.pNext ) p.pNext.pPrev = p.pPrev; |
||
2419 | #endif |
||
2420 | |||
2421 | //sqlite3_free(ref p); |
||
2422 | return SQLITE_OK; |
||
2423 | } |
||
2424 | |||
2425 | /* |
||
2426 | ** Change the limit on the number of pages allowed in the cache. |
||
2427 | ** |
||
2428 | ** The maximum number of cache pages is set to the absolute |
||
2429 | ** value of mxPage. If mxPage is negative, the pager will |
||
2430 | ** operate asynchronously - it will not stop to do fsync()s |
||
2431 | ** to insure data is written to the disk surface before |
||
2432 | ** continuing. Transactions still work if synchronous is off, |
||
2433 | ** and the database cannot be corrupted if this program |
||
2434 | ** crashes. But if the operating system crashes or there is |
||
2435 | ** an abrupt power failure when synchronous is off, the database |
||
2436 | ** could be left in an inconsistent and unrecoverable state. |
||
2437 | ** Synchronous is on by default so database corruption is not |
||
2438 | ** normally a worry. |
||
2439 | */ |
||
2440 | static int sqlite3BtreeSetCacheSize( Btree p, int mxPage ) |
||
2441 | { |
||
2442 | BtShared pBt = p.pBt; |
||
2443 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
2444 | sqlite3BtreeEnter( p ); |
||
2445 | sqlite3PagerSetCachesize( pBt.pPager, mxPage ); |
||
2446 | sqlite3BtreeLeave( p ); |
||
2447 | return SQLITE_OK; |
||
2448 | } |
||
2449 | |||
2450 | /* |
||
2451 | ** Change the way data is synced to disk in order to increase or decrease |
||
2452 | ** how well the database resists damage due to OS crashes and power |
||
2453 | ** failures. Level 1 is the same as asynchronous (no syncs() occur and |
||
2454 | ** there is a high probability of damage) Level 2 is the default. There |
||
2455 | ** is a very low but non-zero probability of damage. Level 3 reduces the |
||
2456 | ** probability of damage to near zero but with a write performance reduction. |
||
2457 | */ |
||
2458 | #if !SQLITE_OMIT_PAGER_PRAGMAS |
||
2459 | static int sqlite3BtreeSetSafetyLevel( |
||
2460 | Btree p, /* The btree to set the safety level on */ |
||
2461 | int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */ |
||
2462 | int fullSync, /* PRAGMA fullfsync. */ |
||
2463 | int ckptFullSync /* PRAGMA checkpoint_fullfync */ |
||
2464 | ) |
||
2465 | { |
||
2466 | BtShared pBt = p.pBt; |
||
2467 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
2468 | Debug.Assert( level >= 1 && level <= 3 ); |
||
2469 | sqlite3BtreeEnter( p ); |
||
2470 | sqlite3PagerSetSafetyLevel( pBt.pPager, level, fullSync, ckptFullSync ); |
||
2471 | sqlite3BtreeLeave( p ); |
||
2472 | return SQLITE_OK; |
||
2473 | } |
||
2474 | #endif |
||
2475 | |||
2476 | /* |
||
2477 | ** Return TRUE if the given btree is set to safety level 1. In other |
||
2478 | ** words, return TRUE if no sync() occurs on the disk files. |
||
2479 | */ |
||
2480 | static int sqlite3BtreeSyncDisabled( Btree p ) |
||
2481 | { |
||
2482 | BtShared pBt = p.pBt; |
||
2483 | int rc; |
||
2484 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
2485 | sqlite3BtreeEnter( p ); |
||
2486 | Debug.Assert( pBt != null && pBt.pPager != null ); |
||
2487 | rc = sqlite3PagerNosync( pBt.pPager ) ? 1 : 0; |
||
2488 | sqlite3BtreeLeave( p ); |
||
2489 | return rc; |
||
2490 | } |
||
2491 | |||
2492 | /* |
||
2493 | ** Change the default pages size and the number of reserved bytes per page. |
||
2494 | ** Or, if the page size has already been fixed, return SQLITE_READONLY |
||
2495 | ** without changing anything. |
||
2496 | ** |
||
2497 | ** The page size must be a power of 2 between 512 and 65536. If the page |
||
2498 | ** size supplied does not meet this constraint then the page size is not |
||
2499 | ** changed. |
||
2500 | ** |
||
2501 | ** Page sizes are constrained to be a power of two so that the region |
||
2502 | ** of the database file used for locking (beginning at PENDING_BYTE, |
||
2503 | ** the first byte past the 1GB boundary, 0x40000000) needs to occur |
||
2504 | ** at the beginning of a page. |
||
2505 | ** |
||
2506 | ** If parameter nReserve is less than zero, then the number of reserved |
||
2507 | ** bytes per page is left unchanged. |
||
2508 | ** |
||
2509 | ** If iFix!=0 then the pageSizeFixed flag is set so that the page size |
||
2510 | ** and autovacuum mode can no longer be changed. |
||
2511 | */ |
||
2512 | static int sqlite3BtreeSetPageSize( Btree p, int pageSize, int nReserve, int iFix ) |
||
2513 | { |
||
2514 | int rc = SQLITE_OK; |
||
2515 | BtShared pBt = p.pBt; |
||
2516 | Debug.Assert( nReserve >= -1 && nReserve <= 255 ); |
||
2517 | sqlite3BtreeEnter( p ); |
||
2518 | if ( pBt.pageSizeFixed ) |
||
2519 | { |
||
2520 | sqlite3BtreeLeave( p ); |
||
2521 | return SQLITE_READONLY; |
||
2522 | } |
||
2523 | if ( nReserve < 0 ) |
||
2524 | { |
||
2525 | nReserve = (int)( pBt.pageSize - pBt.usableSize ); |
||
2526 | } |
||
2527 | Debug.Assert( nReserve >= 0 && nReserve <= 255 ); |
||
2528 | if ( pageSize >= 512 && pageSize <= SQLITE_MAX_PAGE_SIZE && |
||
2529 | ( ( pageSize - 1 ) & pageSize ) == 0 ) |
||
2530 | { |
||
2531 | Debug.Assert( ( pageSize & 7 ) == 0 ); |
||
2532 | Debug.Assert( null == pBt.pPage1 && null == pBt.pCursor ); |
||
2533 | pBt.pageSize = (u32)pageSize; |
||
2534 | // freeTempSpace(pBt); |
||
2535 | } |
||
2536 | rc = sqlite3PagerSetPagesize( pBt.pPager, ref pBt.pageSize, nReserve ); |
||
2537 | pBt.usableSize = (u16)( pBt.pageSize - nReserve ); |
||
2538 | if ( iFix != 0 ) |
||
2539 | pBt.pageSizeFixed = true; |
||
2540 | sqlite3BtreeLeave( p ); |
||
2541 | return rc; |
||
2542 | } |
||
2543 | |||
2544 | /* |
||
2545 | ** Return the currently defined page size |
||
2546 | */ |
||
2547 | static int sqlite3BtreeGetPageSize( Btree p ) |
||
2548 | { |
||
2549 | return (int)p.pBt.pageSize; |
||
2550 | } |
||
2551 | |||
2552 | #if !(SQLITE_OMIT_PAGER_PRAGMAS) || !(SQLITE_OMIT_VACUUM) |
||
2553 | /* |
||
2554 | ** Return the number of bytes of space at the end of every page that |
||
2555 | ** are intentually left unused. This is the "reserved" space that is |
||
2556 | ** sometimes used by extensions. |
||
2557 | */ |
||
2558 | static int sqlite3BtreeGetReserve( Btree p ) |
||
2559 | { |
||
2560 | int n; |
||
2561 | sqlite3BtreeEnter( p ); |
||
2562 | n = (int)( p.pBt.pageSize - p.pBt.usableSize ); |
||
2563 | sqlite3BtreeLeave( p ); |
||
2564 | return n; |
||
2565 | } |
||
2566 | |||
2567 | /* |
||
2568 | ** Set the maximum page count for a database if mxPage is positive. |
||
2569 | ** No changes are made if mxPage is 0 or negative. |
||
2570 | ** Regardless of the value of mxPage, return the maximum page count. |
||
2571 | */ |
||
2572 | static Pgno sqlite3BtreeMaxPageCount( Btree p, int mxPage ) |
||
2573 | { |
||
2574 | Pgno n; |
||
2575 | sqlite3BtreeEnter( p ); |
||
2576 | n = sqlite3PagerMaxPageCount( p.pBt.pPager, mxPage ); |
||
2577 | sqlite3BtreeLeave( p ); |
||
2578 | return n; |
||
2579 | } |
||
2580 | |||
2581 | /* |
||
2582 | ** Set the secureDelete flag if newFlag is 0 or 1. If newFlag is -1, |
||
2583 | ** then make no changes. Always return the value of the secureDelete |
||
2584 | ** setting after the change. |
||
2585 | */ |
||
2586 | static int sqlite3BtreeSecureDelete( Btree p, int newFlag ) |
||
2587 | { |
||
2588 | int b; |
||
2589 | if ( p == null ) |
||
2590 | return 0; |
||
2591 | sqlite3BtreeEnter( p ); |
||
2592 | if ( newFlag >= 0 ) |
||
2593 | { |
||
2594 | p.pBt.secureDelete = ( newFlag != 0 ); |
||
2595 | } |
||
2596 | b = p.pBt.secureDelete ? 1 : 0; |
||
2597 | sqlite3BtreeLeave( p ); |
||
2598 | return b; |
||
2599 | } |
||
2600 | #endif //* !(SQLITE_OMIT_PAGER_PRAGMAS) || !(SQLITE_OMIT_VACUUM) */ |
||
2601 | |||
2602 | /* |
||
2603 | ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' |
||
2604 | ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it |
||
2605 | ** is disabled. The default value for the auto-vacuum property is |
||
2606 | ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. |
||
2607 | */ |
||
2608 | static int sqlite3BtreeSetAutoVacuum( Btree p, int autoVacuum ) |
||
2609 | { |
||
2610 | #if SQLITE_OMIT_AUTOVACUUM |
||
2611 | return SQLITE_READONLY; |
||
2612 | #else |
||
2613 | BtShared pBt = p.pBt; |
||
2614 | int rc = SQLITE_OK; |
||
2615 | u8 av = (u8)autoVacuum; |
||
2616 | |||
2617 | sqlite3BtreeEnter( p ); |
||
2618 | if ( pBt.pageSizeFixed && ( av != 0 ) != pBt.autoVacuum ) |
||
2619 | { |
||
2620 | rc = SQLITE_READONLY; |
||
2621 | } |
||
2622 | else |
||
2623 | { |
||
2624 | pBt.autoVacuum = av != 0; |
||
2625 | pBt.incrVacuum = av == 2; |
||
2626 | } |
||
2627 | sqlite3BtreeLeave( p ); |
||
2628 | return rc; |
||
2629 | #endif |
||
2630 | } |
||
2631 | |||
2632 | /* |
||
2633 | ** Return the value of the 'auto-vacuum' property. If auto-vacuum is |
||
2634 | ** enabled 1 is returned. Otherwise 0. |
||
2635 | */ |
||
2636 | static int sqlite3BtreeGetAutoVacuum( Btree p ) |
||
2637 | { |
||
2638 | #if SQLITE_OMIT_AUTOVACUUM |
||
2639 | return BTREE_AUTOVACUUM_NONE; |
||
2640 | #else |
||
2641 | int rc; |
||
2642 | sqlite3BtreeEnter( p ); |
||
2643 | rc = ( |
||
2644 | ( !p.pBt.autoVacuum ) ? BTREE_AUTOVACUUM_NONE : |
||
2645 | ( !p.pBt.incrVacuum ) ? BTREE_AUTOVACUUM_FULL : |
||
2646 | BTREE_AUTOVACUUM_INCR |
||
2647 | ); |
||
2648 | sqlite3BtreeLeave( p ); |
||
2649 | return rc; |
||
2650 | #endif |
||
2651 | } |
||
2652 | |||
2653 | |||
2654 | /* |
||
2655 | ** Get a reference to pPage1 of the database file. This will |
||
2656 | ** also acquire a readlock on that file. |
||
2657 | ** |
||
2658 | ** SQLITE_OK is returned on success. If the file is not a |
||
2659 | ** well-formed database file, then SQLITE_CORRUPT is returned. |
||
2660 | ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM |
||
2661 | ** is returned if we run out of memory. |
||
2662 | */ |
||
2663 | static int lockBtree( BtShared pBt ) |
||
2664 | { |
||
2665 | int rc; /* Result code from subfunctions */ |
||
2666 | MemPage pPage1 = null; /* Page 1 of the database file */ |
||
2667 | Pgno nPage; /* Number of pages in the database */ |
||
2668 | Pgno nPageFile = 0; /* Number of pages in the database file */ |
||
2669 | ////Pgno nPageHeader; /* Number of pages in the database according to hdr */ |
||
2670 | |||
2671 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
2672 | Debug.Assert( pBt.pPage1 == null ); |
||
2673 | rc = sqlite3PagerSharedLock( pBt.pPager ); |
||
2674 | if ( rc != SQLITE_OK ) |
||
2675 | return rc; |
||
2676 | rc = btreeGetPage( pBt, 1, ref pPage1, 0 ); |
||
2677 | if ( rc != SQLITE_OK ) |
||
2678 | return rc; |
||
2679 | |||
2680 | /* Do some checking to help insure the file we opened really is |
||
2681 | ** a valid database file. |
||
2682 | */ |
||
2683 | nPage = sqlite3Get4byte( pPage1.aData, 28 );//get4byte(28+(u8*)pPage1->aData); |
||
2684 | ////nPageHeader = nPage; |
||
2685 | sqlite3PagerPagecount( pBt.pPager, out nPageFile ); |
||
2686 | if ( nPage == 0 || memcmp( pPage1.aData, 24, pPage1.aData, 92, 4 ) != 0 )//memcmp(24 + (u8*)pPage1.aData, 92 + (u8*)pPage1.aData, 4) != 0) |
||
2687 | { |
||
2688 | nPage = nPageFile; |
||
2689 | } |
||
2690 | if ( nPage > 0 ) |
||
2691 | { |
||
2692 | u32 pageSize; |
||
2693 | u32 usableSize; |
||
2694 | u8[] page1 = pPage1.aData; |
||
2695 | rc = SQLITE_NOTADB; |
||
2696 | if ( memcmp( page1, zMagicHeader, 16 ) != 0 ) |
||
2697 | { |
||
2698 | goto page1_init_failed; |
||
2699 | } |
||
2700 | |||
2701 | #if SQLITE_OMIT_WAL |
||
2702 | if ( page1[18] > 1 ) |
||
2703 | { |
||
2704 | pBt.readOnly = true; |
||
2705 | } |
||
2706 | if ( page1[19] > 1 ) |
||
2707 | { |
||
2708 | pBt.pSchema.file_format = page1[19]; |
||
2709 | goto page1_init_failed; |
||
2710 | } |
||
2711 | #else |
||
2712 | if( page1[18]>2 ){ |
||
2713 | pBt.readOnly = true; |
||
2714 | } |
||
2715 | if( page1[19]>2 ){ |
||
2716 | goto page1_init_failed; |
||
2717 | } |
||
2718 | |||
2719 | /* If the write version is set to 2, this database should be accessed |
||
2720 | ** in WAL mode. If the log is not already open, open it now. Then |
||
2721 | ** return SQLITE_OK and return without populating BtShared.pPage1. |
||
2722 | ** The caller detects this and calls this function again. This is |
||
2723 | ** required as the version of page 1 currently in the page1 buffer |
||
2724 | ** may not be the latest version - there may be a newer one in the log |
||
2725 | ** file. |
||
2726 | */ |
||
2727 | if( page1[19]==2 && pBt.doNotUseWAL==false ){ |
||
2728 | int isOpen = 0; |
||
2729 | rc = sqlite3PagerOpenWal(pBt.pPager, ref isOpen); |
||
2730 | if( rc!=SQLITE_OK ){ |
||
2731 | goto page1_init_failed; |
||
2732 | }else if( isOpen==0 ){ |
||
2733 | releasePage(pPage1); |
||
2734 | return SQLITE_OK; |
||
2735 | } |
||
2736 | rc = SQLITE_NOTADB; |
||
2737 | } |
||
2738 | #endif |
||
2739 | |||
2740 | /* The maximum embedded fraction must be exactly 25%. And the minimum |
||
2741 | ** embedded fraction must be 12.5% for both leaf-data and non-leaf-data. |
||
2742 | ** The original design allowed these amounts to vary, but as of |
||
2743 | ** version 3.6.0, we require them to be fixed. |
||
2744 | */ |
||
2745 | if ( memcmp( page1, 21, "\x0040\x0020\x0020", 3 ) != 0 )// "\100\040\040" |
||
2746 | { |
||
2747 | goto page1_init_failed; |
||
2748 | } |
||
2749 | pageSize = (u32)( ( page1[16] << 8 ) | ( page1[17] << 16 ) ); |
||
2750 | if ( ( ( pageSize - 1 ) & pageSize ) != 0 |
||
2751 | || pageSize > SQLITE_MAX_PAGE_SIZE |
||
2752 | || pageSize <= 256 |
||
2753 | ) |
||
2754 | { |
||
2755 | goto page1_init_failed; |
||
2756 | } |
||
2757 | Debug.Assert( ( pageSize & 7 ) == 0 ); |
||
2758 | usableSize = pageSize - page1[20]; |
||
2759 | if ( pageSize != pBt.pageSize ) |
||
2760 | { |
||
2761 | /* After reading the first page of the database assuming a page size |
||
2762 | ** of BtShared.pageSize, we have discovered that the page-size is |
||
2763 | ** actually pageSize. Unlock the database, leave pBt.pPage1 at |
||
2764 | ** zero and return SQLITE_OK. The caller will call this function |
||
2765 | ** again with the correct page-size. |
||
2766 | */ |
||
2767 | releasePage( pPage1 ); |
||
2768 | pBt.usableSize = usableSize; |
||
2769 | pBt.pageSize = pageSize; |
||
2770 | // freeTempSpace(pBt); |
||
2771 | rc = sqlite3PagerSetPagesize( pBt.pPager, ref pBt.pageSize, |
||
2772 | (int)( pageSize - usableSize ) ); |
||
2773 | return rc; |
||
2774 | } |
||
2775 | if ( ( pBt.db.flags & SQLITE_RecoveryMode ) == 0 && nPage > nPageFile ) |
||
2776 | { |
||
2777 | rc = SQLITE_CORRUPT_BKPT(); |
||
2778 | goto page1_init_failed; |
||
2779 | } |
||
2780 | if ( usableSize < 480 ) |
||
2781 | { |
||
2782 | goto page1_init_failed; |
||
2783 | } |
||
2784 | pBt.pageSize = pageSize; |
||
2785 | pBt.usableSize = usableSize; |
||
2786 | #if !SQLITE_OMIT_AUTOVACUUM |
||
2787 | pBt.autoVacuum = ( sqlite3Get4byte( page1, 36 + 4 * 4 ) != 0 ); |
||
2788 | pBt.incrVacuum = ( sqlite3Get4byte( page1, 36 + 7 * 4 ) != 0 ); |
||
2789 | #endif |
||
2790 | } |
||
2791 | |||
2792 | /* maxLocal is the maximum amount of payload to store locally for |
||
2793 | ** a cell. Make sure it is small enough so that at least minFanout |
||
2794 | ** cells can will fit on one page. We assume a 10-byte page header. |
||
2795 | ** Besides the payload, the cell must store: |
||
2796 | ** 2-byte pointer to the cell |
||
2797 | ** 4-byte child pointer |
||
2798 | ** 9-byte nKey value |
||
2799 | ** 4-byte nData value |
||
2800 | ** 4-byte overflow page pointer |
||
2801 | ** So a cell consists of a 2-byte pointer, a header which is as much as |
||
2802 | ** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow |
||
2803 | ** page pointer. |
||
2804 | */ |
||
2805 | pBt.maxLocal = (u16)( ( pBt.usableSize - 12 ) * 64 / 255 - 23 ); |
||
2806 | pBt.minLocal = (u16)( ( pBt.usableSize - 12 ) * 32 / 255 - 23 ); |
||
2807 | pBt.maxLeaf = (u16)( pBt.usableSize - 35 ); |
||
2808 | pBt.minLeaf = (u16)( ( pBt.usableSize - 12 ) * 32 / 255 - 23 ); |
||
2809 | Debug.Assert( pBt.maxLeaf + 23 <= MX_CELL_SIZE( pBt ) ); |
||
2810 | pBt.pPage1 = pPage1; |
||
2811 | pBt.nPage = nPage; |
||
2812 | return SQLITE_OK; |
||
2813 | |||
2814 | page1_init_failed: |
||
2815 | releasePage( pPage1 ); |
||
2816 | pBt.pPage1 = null; |
||
2817 | return rc; |
||
2818 | } |
||
2819 | |||
2820 | /* |
||
2821 | ** If there are no outstanding cursors and we are not in the middle |
||
2822 | ** of a transaction but there is a read lock on the database, then |
||
2823 | ** this routine unrefs the first page of the database file which |
||
2824 | ** has the effect of releasing the read lock. |
||
2825 | ** |
||
2826 | ** If there is a transaction in progress, this routine is a no-op. |
||
2827 | */ |
||
2828 | static void unlockBtreeIfUnused( BtShared pBt ) |
||
2829 | { |
||
2830 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
2831 | Debug.Assert( pBt.pCursor == null || pBt.inTransaction > TRANS_NONE ); |
||
2832 | if ( pBt.inTransaction == TRANS_NONE && pBt.pPage1 != null ) |
||
2833 | { |
||
2834 | Debug.Assert( pBt.pPage1.aData != null ); |
||
2835 | //Debug.Assert( sqlite3PagerRefcount( pBt.pPager ) == 1 ); |
||
2836 | releasePage( pBt.pPage1 ); |
||
2837 | pBt.pPage1 = null; |
||
2838 | } |
||
2839 | } |
||
2840 | |||
2841 | /* |
||
2842 | ** If pBt points to an empty file then convert that empty file |
||
2843 | ** into a new empty database by initializing the first page of |
||
2844 | ** the database. |
||
2845 | */ |
||
2846 | static int newDatabase( BtShared pBt ) |
||
2847 | { |
||
2848 | MemPage pP1; |
||
2849 | byte[] data; |
||
2850 | int rc; |
||
2851 | |||
2852 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
2853 | if ( pBt.nPage > 0 ) |
||
2854 | { |
||
2855 | return SQLITE_OK; |
||
2856 | } |
||
2857 | pP1 = pBt.pPage1; |
||
2858 | Debug.Assert( pP1 != null ); |
||
2859 | data = pP1.aData; |
||
2860 | rc = sqlite3PagerWrite( pP1.pDbPage ); |
||
2861 | if ( rc != 0 ) |
||
2862 | return rc; |
||
2863 | Buffer.BlockCopy( zMagicHeader, 0, data, 0, 16 );// memcpy(data, zMagicHeader, sizeof(zMagicHeader)); |
||
2864 | Debug.Assert( zMagicHeader.Length == 16 ); |
||
2865 | data[16] = (u8)( ( pBt.pageSize >> 8 ) & 0xff ); |
||
2866 | data[17] = (u8)( ( pBt.pageSize >> 16 ) & 0xff ); |
||
2867 | data[18] = 1; |
||
2868 | data[19] = 1; |
||
2869 | Debug.Assert( pBt.usableSize <= pBt.pageSize && pBt.usableSize + 255 >= pBt.pageSize ); |
||
2870 | data[20] = (u8)( pBt.pageSize - pBt.usableSize ); |
||
2871 | data[21] = 64; |
||
2872 | data[22] = 32; |
||
2873 | data[23] = 32; |
||
2874 | //memset(&data[24], 0, 100-24); |
||
2875 | zeroPage( pP1, PTF_INTKEY | PTF_LEAF | PTF_LEAFDATA ); |
||
2876 | pBt.pageSizeFixed = true; |
||
2877 | #if !SQLITE_OMIT_AUTOVACUUM |
||
2878 | Debug.Assert( pBt.autoVacuum == true || pBt.autoVacuum == false ); |
||
2879 | Debug.Assert( pBt.incrVacuum == true || pBt.incrVacuum == false ); |
||
2880 | sqlite3Put4byte( data, 36 + 4 * 4, pBt.autoVacuum ? 1 : 0 ); |
||
2881 | sqlite3Put4byte( data, 36 + 7 * 4, pBt.incrVacuum ? 1 : 0 ); |
||
2882 | #endif |
||
2883 | pBt.nPage = 1; |
||
2884 | data[31] = 1; |
||
2885 | return SQLITE_OK; |
||
2886 | } |
||
2887 | |||
2888 | /* |
||
2889 | ** Attempt to start a new transaction. A write-transaction |
||
2890 | ** is started if the second argument is nonzero, otherwise a read- |
||
2891 | ** transaction. If the second argument is 2 or more and exclusive |
||
2892 | ** transaction is started, meaning that no other process is allowed |
||
2893 | ** to access the database. A preexisting transaction may not be |
||
2894 | ** upgraded to exclusive by calling this routine a second time - the |
||
2895 | ** exclusivity flag only works for a new transaction. |
||
2896 | ** |
||
2897 | ** A write-transaction must be started before attempting any |
||
2898 | ** changes to the database. None of the following routines |
||
2899 | ** will work unless a transaction is started first: |
||
2900 | ** |
||
2901 | ** sqlite3BtreeCreateTable() |
||
2902 | ** sqlite3BtreeCreateIndex() |
||
2903 | ** sqlite3BtreeClearTable() |
||
2904 | ** sqlite3BtreeDropTable() |
||
2905 | ** sqlite3BtreeInsert() |
||
2906 | ** sqlite3BtreeDelete() |
||
2907 | ** sqlite3BtreeUpdateMeta() |
||
2908 | ** |
||
2909 | ** If an initial attempt to acquire the lock fails because of lock contention |
||
2910 | ** and the database was previously unlocked, then invoke the busy handler |
||
2911 | ** if there is one. But if there was previously a read-lock, do not |
||
2912 | ** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is |
||
2913 | ** returned when there is already a read-lock in order to avoid a deadlock. |
||
2914 | ** |
||
2915 | ** Suppose there are two processes A and B. A has a read lock and B has |
||
2916 | ** a reserved lock. B tries to promote to exclusive but is blocked because |
||
2917 | ** of A's read lock. A tries to promote to reserved but is blocked by B. |
||
2918 | ** One or the other of the two processes must give way or there can be |
||
2919 | ** no progress. By returning SQLITE_BUSY and not invoking the busy callback |
||
2920 | ** when A already has a read lock, we encourage A to give up and let B |
||
2921 | ** proceed. |
||
2922 | */ |
||
2923 | static int sqlite3BtreeBeginTrans( Btree p, int wrflag ) |
||
2924 | { |
||
2925 | BtShared pBt = p.pBt; |
||
2926 | int rc = SQLITE_OK; |
||
2927 | |||
2928 | sqlite3BtreeEnter( p ); |
||
2929 | btreeIntegrity( p ); |
||
2930 | |||
2931 | /* If the btree is already in a write-transaction, or it |
||
2932 | ** is already in a read-transaction and a read-transaction |
||
2933 | ** is requested, this is a no-op. |
||
2934 | */ |
||
2935 | if ( p.inTrans == TRANS_WRITE || ( p.inTrans == TRANS_READ && 0 == wrflag ) ) |
||
2936 | { |
||
2937 | goto trans_begun; |
||
2938 | } |
||
2939 | |||
2940 | /* Write transactions are not possible on a read-only database */ |
||
2941 | if ( pBt.readOnly && wrflag != 0 ) |
||
2942 | { |
||
2943 | rc = SQLITE_READONLY; |
||
2944 | goto trans_begun; |
||
2945 | } |
||
2946 | |||
2947 | #if !SQLITE_OMIT_SHARED_CACHE |
||
2948 | /* If another database handle has already opened a write transaction |
||
2949 | ** on this shared-btree structure and a second write transaction is |
||
2950 | ** requested, return SQLITE_LOCKED. |
||
2951 | */ |
||
2952 | if( (wrflag && pBt.inTransaction==TRANS_WRITE) || pBt.isPending ){ |
||
2953 | sqlite3 pBlock = pBt.pWriter.db; |
||
2954 | }else if( wrflag>1 ){ |
||
2955 | BtLock pIter; |
||
2956 | for(pIter=pBt.pLock; pIter; pIter=pIter.pNext){ |
||
2957 | if( pIter.pBtree!=p ){ |
||
2958 | pBlock = pIter.pBtree.db; |
||
2959 | break; |
||
2960 | } |
||
2961 | } |
||
2962 | } |
||
2963 | if( pBlock ){ |
||
2964 | sqlite3ConnectionBlocked(p.db, pBlock); |
||
2965 | rc = SQLITE_LOCKED_SHAREDCACHE; |
||
2966 | goto trans_begun; |
||
2967 | } |
||
2968 | #endif |
||
2969 | |||
2970 | /* Any read-only or read-write transaction implies a read-lock on |
||
2971 | ** page 1. So if some other shared-cache client already has a write-lock |
||
2972 | ** on page 1, the transaction cannot be opened. */ |
||
2973 | rc = querySharedCacheTableLock( p, MASTER_ROOT, READ_LOCK ); |
||
2974 | if ( SQLITE_OK != rc ) |
||
2975 | goto trans_begun; |
||
2976 | |||
2977 | pBt.initiallyEmpty = pBt.nPage == 0; |
||
2978 | do |
||
2979 | { |
||
2980 | /* Call lockBtree() until either pBt.pPage1 is populated or |
||
2981 | ** lockBtree() returns something other than SQLITE_OK. lockBtree() |
||
2982 | ** may return SQLITE_OK but leave pBt.pPage1 set to 0 if after |
||
2983 | ** reading page 1 it discovers that the page-size of the database |
||
2984 | ** file is not pBt.pageSize. In this case lockBtree() will update |
||
2985 | ** pBt.pageSize to the page-size of the file on disk. |
||
2986 | */ |
||
2987 | while ( pBt.pPage1 == null && SQLITE_OK == ( rc = lockBtree( pBt ) ) ) |
||
2988 | ; |
||
2989 | |||
2990 | if ( rc == SQLITE_OK && wrflag != 0 ) |
||
2991 | { |
||
2992 | if ( pBt.readOnly ) |
||
2993 | { |
||
2994 | rc = SQLITE_READONLY; |
||
2995 | } |
||
2996 | else |
||
2997 | { |
||
2998 | rc = sqlite3PagerBegin( pBt.pPager, wrflag > 1, sqlite3TempInMemory( p.db ) ? 1 : 0 ); |
||
2999 | if ( rc == SQLITE_OK ) |
||
3000 | { |
||
3001 | rc = newDatabase( pBt ); |
||
3002 | } |
||
3003 | } |
||
3004 | } |
||
3005 | |||
3006 | if ( rc != SQLITE_OK ) |
||
3007 | { |
||
3008 | unlockBtreeIfUnused( pBt ); |
||
3009 | } |
||
3010 | } while ( ( rc & 0xFF ) == SQLITE_BUSY && pBt.inTransaction == TRANS_NONE && |
||
3011 | btreeInvokeBusyHandler( pBt ) != 0 ); |
||
3012 | |||
3013 | if ( rc == SQLITE_OK ) |
||
3014 | { |
||
3015 | if ( p.inTrans == TRANS_NONE ) |
||
3016 | { |
||
3017 | pBt.nTransaction++; |
||
3018 | #if !SQLITE_OMIT_SHARED_CACHE |
||
3019 | if( p.sharable ){ |
||
3020 | Debug.Assert( p.lock.pBtree==p && p.lock.iTable==1 ); |
||
3021 | p.lock.eLock = READ_LOCK; |
||
3022 | p.lock.pNext = pBt.pLock; |
||
3023 | pBt.pLock = &p.lock; |
||
3024 | } |
||
3025 | #endif |
||
3026 | } |
||
3027 | p.inTrans = ( wrflag != 0 ? TRANS_WRITE : TRANS_READ ); |
||
3028 | if ( p.inTrans > pBt.inTransaction ) |
||
3029 | { |
||
3030 | pBt.inTransaction = p.inTrans; |
||
3031 | } |
||
3032 | if ( wrflag != 0 ) |
||
3033 | { |
||
3034 | MemPage pPage1 = pBt.pPage1; |
||
3035 | #if !SQLITE_OMIT_SHARED_CACHE |
||
3036 | Debug.Assert( !pBt.pWriter ); |
||
3037 | pBt.pWriter = p; |
||
3038 | pBt.isExclusive = (u8)(wrflag>1); |
||
3039 | #endif |
||
3040 | /* If the db-size header field is incorrect (as it may be if an old |
||
3041 | ** client has been writing the database file), update it now. Doing |
||
3042 | ** this sooner rather than later means the database size can safely |
||
3043 | ** re-read the database size from page 1 if a savepoint or transaction |
||
3044 | ** rollback occurs within the transaction. |
||
3045 | */ |
||
3046 | if ( pBt.nPage != sqlite3Get4byte( pPage1.aData, 28 ) ) |
||
3047 | { |
||
3048 | rc = sqlite3PagerWrite( pPage1.pDbPage ); |
||
3049 | if ( rc == SQLITE_OK ) |
||
3050 | { |
||
3051 | sqlite3Put4byte( pPage1.aData, (u32)28, pBt.nPage ); |
||
3052 | } |
||
3053 | } |
||
3054 | } |
||
3055 | } |
||
3056 | |||
3057 | |||
3058 | trans_begun: |
||
3059 | if ( rc == SQLITE_OK && wrflag != 0 ) |
||
3060 | { |
||
3061 | /* This call makes sure that the pager has the correct number of |
||
3062 | ** open savepoints. If the second parameter is greater than 0 and |
||
3063 | ** the sub-journal is not already open, then it will be opened here. |
||
3064 | */ |
||
3065 | rc = sqlite3PagerOpenSavepoint( pBt.pPager, p.db.nSavepoint ); |
||
3066 | } |
||
3067 | |||
3068 | btreeIntegrity( p ); |
||
3069 | sqlite3BtreeLeave( p ); |
||
3070 | return rc; |
||
3071 | } |
||
3072 | |||
3073 | #if !SQLITE_OMIT_AUTOVACUUM |
||
3074 | |||
3075 | /* |
||
3076 | ** Set the pointer-map entries for all children of page pPage. Also, if |
||
3077 | ** pPage contains cells that point to overflow pages, set the pointer |
||
3078 | ** map entries for the overflow pages as well. |
||
3079 | */ |
||
3080 | static int setChildPtrmaps( MemPage pPage ) |
||
3081 | { |
||
3082 | int i; /* Counter variable */ |
||
3083 | int nCell; /* Number of cells in page pPage */ |
||
3084 | int rc; /* Return code */ |
||
3085 | BtShared pBt = pPage.pBt; |
||
3086 | u8 isInitOrig = pPage.isInit; |
||
3087 | Pgno pgno = pPage.pgno; |
||
3088 | |||
3089 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
3090 | rc = btreeInitPage( pPage ); |
||
3091 | if ( rc != SQLITE_OK ) |
||
3092 | { |
||
3093 | goto set_child_ptrmaps_out; |
||
3094 | } |
||
3095 | nCell = pPage.nCell; |
||
3096 | |||
3097 | for ( i = 0; i < nCell; i++ ) |
||
3098 | { |
||
3099 | int pCell = findCell( pPage, i ); |
||
3100 | |||
3101 | ptrmapPutOvflPtr( pPage, pCell, ref rc ); |
||
3102 | |||
3103 | if ( 0 == pPage.leaf ) |
||
3104 | { |
||
3105 | Pgno childPgno = sqlite3Get4byte( pPage.aData, pCell ); |
||
3106 | ptrmapPut( pBt, childPgno, PTRMAP_BTREE, pgno, ref rc ); |
||
3107 | } |
||
3108 | } |
||
3109 | |||
3110 | if ( 0 == pPage.leaf ) |
||
3111 | { |
||
3112 | Pgno childPgno = sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ); |
||
3113 | ptrmapPut( pBt, childPgno, PTRMAP_BTREE, pgno, ref rc ); |
||
3114 | } |
||
3115 | |||
3116 | set_child_ptrmaps_out: |
||
3117 | pPage.isInit = isInitOrig; |
||
3118 | return rc; |
||
3119 | } |
||
3120 | |||
3121 | /* |
||
3122 | ** Somewhere on pPage is a pointer to page iFrom. Modify this pointer so |
||
3123 | ** that it points to iTo. Parameter eType describes the type of pointer to |
||
3124 | ** be modified, as follows: |
||
3125 | ** |
||
3126 | ** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child |
||
3127 | ** page of pPage. |
||
3128 | ** |
||
3129 | ** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow |
||
3130 | ** page pointed to by one of the cells on pPage. |
||
3131 | ** |
||
3132 | ** PTRMAP_OVERFLOW2: pPage is an overflow-page. The pointer points at the next |
||
3133 | ** overflow page in the list. |
||
3134 | */ |
||
3135 | static int modifyPagePointer( MemPage pPage, Pgno iFrom, Pgno iTo, u8 eType ) |
||
3136 | { |
||
3137 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
3138 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
3139 | if ( eType == PTRMAP_OVERFLOW2 ) |
||
3140 | { |
||
3141 | /* The pointer is always the first 4 bytes of the page in this case. */ |
||
3142 | if ( sqlite3Get4byte( pPage.aData ) != iFrom ) |
||
3143 | { |
||
3144 | return SQLITE_CORRUPT_BKPT(); |
||
3145 | } |
||
3146 | sqlite3Put4byte( pPage.aData, iTo ); |
||
3147 | } |
||
3148 | else |
||
3149 | { |
||
3150 | u8 isInitOrig = pPage.isInit; |
||
3151 | int i; |
||
3152 | int nCell; |
||
3153 | |||
3154 | btreeInitPage( pPage ); |
||
3155 | nCell = pPage.nCell; |
||
3156 | |||
3157 | for ( i = 0; i < nCell; i++ ) |
||
3158 | { |
||
3159 | int pCell = findCell( pPage, i ); |
||
3160 | if ( eType == PTRMAP_OVERFLOW1 ) |
||
3161 | { |
||
3162 | CellInfo info = new CellInfo(); |
||
3163 | btreeParseCellPtr( pPage, pCell, ref info ); |
||
3164 | if ( info.iOverflow != 0 ) |
||
3165 | { |
||
3166 | if ( iFrom == sqlite3Get4byte( pPage.aData, pCell, info.iOverflow ) ) |
||
3167 | { |
||
3168 | sqlite3Put4byte( pPage.aData, pCell + info.iOverflow, (int)iTo ); |
||
3169 | break; |
||
3170 | } |
||
3171 | } |
||
3172 | } |
||
3173 | else |
||
3174 | { |
||
3175 | if ( sqlite3Get4byte( pPage.aData, pCell ) == iFrom ) |
||
3176 | { |
||
3177 | sqlite3Put4byte( pPage.aData, pCell, (int)iTo ); |
||
3178 | break; |
||
3179 | } |
||
3180 | } |
||
3181 | } |
||
3182 | |||
3183 | if ( i == nCell ) |
||
3184 | { |
||
3185 | if ( eType != PTRMAP_BTREE || |
||
3186 | sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ) != iFrom ) |
||
3187 | { |
||
3188 | return SQLITE_CORRUPT_BKPT(); |
||
3189 | } |
||
3190 | sqlite3Put4byte( pPage.aData, pPage.hdrOffset + 8, iTo ); |
||
3191 | } |
||
3192 | |||
3193 | pPage.isInit = isInitOrig; |
||
3194 | } |
||
3195 | return SQLITE_OK; |
||
3196 | } |
||
3197 | |||
3198 | |||
3199 | /* |
||
3200 | ** Move the open database page pDbPage to location iFreePage in the |
||
3201 | ** database. The pDbPage reference remains valid. |
||
3202 | ** |
||
3203 | ** The isCommit flag indicates that there is no need to remember that |
||
3204 | ** the journal needs to be sync()ed before database page pDbPage.pgno |
||
3205 | ** can be written to. The caller has already promised not to write to that |
||
3206 | ** page. |
||
3207 | */ |
||
3208 | static int relocatePage( |
||
3209 | BtShared pBt, /* Btree */ |
||
3210 | MemPage pDbPage, /* Open page to move */ |
||
3211 | u8 eType, /* Pointer map 'type' entry for pDbPage */ |
||
3212 | Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ |
||
3213 | Pgno iFreePage, /* The location to move pDbPage to */ |
||
3214 | int isCommit /* isCommit flag passed to sqlite3PagerMovepage */ |
||
3215 | ) |
||
3216 | { |
||
3217 | MemPage pPtrPage = new MemPage(); /* The page that contains a pointer to pDbPage */ |
||
3218 | Pgno iDbPage = pDbPage.pgno; |
||
3219 | Pager pPager = pBt.pPager; |
||
3220 | int rc; |
||
3221 | |||
3222 | Debug.Assert( eType == PTRMAP_OVERFLOW2 || eType == PTRMAP_OVERFLOW1 || |
||
3223 | eType == PTRMAP_BTREE || eType == PTRMAP_ROOTPAGE ); |
||
3224 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
3225 | Debug.Assert( pDbPage.pBt == pBt ); |
||
3226 | |||
3227 | /* Move page iDbPage from its current location to page number iFreePage */ |
||
3228 | TRACE( "AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", |
||
3229 | iDbPage, iFreePage, iPtrPage, eType ); |
||
3230 | rc = sqlite3PagerMovepage( pPager, pDbPage.pDbPage, iFreePage, isCommit ); |
||
3231 | if ( rc != SQLITE_OK ) |
||
3232 | { |
||
3233 | return rc; |
||
3234 | } |
||
3235 | pDbPage.pgno = iFreePage; |
||
3236 | |||
3237 | /* If pDbPage was a btree-page, then it may have child pages and/or cells |
||
3238 | ** that point to overflow pages. The pointer map entries for all these |
||
3239 | ** pages need to be changed. |
||
3240 | ** |
||
3241 | ** If pDbPage is an overflow page, then the first 4 bytes may store a |
||
3242 | ** pointer to a subsequent overflow page. If this is the case, then |
||
3243 | ** the pointer map needs to be updated for the subsequent overflow page. |
||
3244 | */ |
||
3245 | if ( eType == PTRMAP_BTREE || eType == PTRMAP_ROOTPAGE ) |
||
3246 | { |
||
3247 | rc = setChildPtrmaps( pDbPage ); |
||
3248 | if ( rc != SQLITE_OK ) |
||
3249 | { |
||
3250 | return rc; |
||
3251 | } |
||
3252 | } |
||
3253 | else |
||
3254 | { |
||
3255 | Pgno nextOvfl = sqlite3Get4byte( pDbPage.aData ); |
||
3256 | if ( nextOvfl != 0 ) |
||
3257 | { |
||
3258 | ptrmapPut( pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage, ref rc ); |
||
3259 | if ( rc != SQLITE_OK ) |
||
3260 | { |
||
3261 | return rc; |
||
3262 | } |
||
3263 | } |
||
3264 | } |
||
3265 | |||
3266 | /* Fix the database pointer on page iPtrPage that pointed at iDbPage so |
||
3267 | ** that it points at iFreePage. Also fix the pointer map entry for |
||
3268 | ** iPtrPage. |
||
3269 | */ |
||
3270 | if ( eType != PTRMAP_ROOTPAGE ) |
||
3271 | { |
||
3272 | rc = btreeGetPage( pBt, iPtrPage, ref pPtrPage, 0 ); |
||
3273 | if ( rc != SQLITE_OK ) |
||
3274 | { |
||
3275 | return rc; |
||
3276 | } |
||
3277 | rc = sqlite3PagerWrite( pPtrPage.pDbPage ); |
||
3278 | if ( rc != SQLITE_OK ) |
||
3279 | { |
||
3280 | releasePage( pPtrPage ); |
||
3281 | return rc; |
||
3282 | } |
||
3283 | rc = modifyPagePointer( pPtrPage, iDbPage, iFreePage, eType ); |
||
3284 | releasePage( pPtrPage ); |
||
3285 | if ( rc == SQLITE_OK ) |
||
3286 | { |
||
3287 | ptrmapPut( pBt, iFreePage, eType, iPtrPage, ref rc ); |
||
3288 | } |
||
3289 | } |
||
3290 | return rc; |
||
3291 | } |
||
3292 | |||
3293 | /* Forward declaration required by incrVacuumStep(). */ |
||
3294 | //static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); |
||
3295 | |||
3296 | /* |
||
3297 | ** Perform a single step of an incremental-vacuum. If successful, |
||
3298 | ** return SQLITE_OK. If there is no work to do (and therefore no |
||
3299 | ** point in calling this function again), return SQLITE_DONE. |
||
3300 | ** |
||
3301 | ** More specificly, this function attempts to re-organize the |
||
3302 | ** database so that the last page of the file currently in use |
||
3303 | ** is no longer in use. |
||
3304 | ** |
||
3305 | ** If the nFin parameter is non-zero, this function assumes |
||
3306 | ** that the caller will keep calling incrVacuumStep() until |
||
3307 | ** it returns SQLITE_DONE or an error, and that nFin is the |
||
3308 | ** number of pages the database file will contain after this |
||
3309 | ** process is complete. If nFin is zero, it is assumed that |
||
3310 | ** incrVacuumStep() will be called a finite amount of times |
||
3311 | ** which may or may not empty the freelist. A full autovacuum |
||
3312 | ** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==null. |
||
3313 | */ |
||
3314 | static int incrVacuumStep( BtShared pBt, Pgno nFin, Pgno iLastPg ) |
||
3315 | { |
||
3316 | Pgno nFreeList; /* Number of pages still on the free-list */ |
||
3317 | int rc; |
||
3318 | |||
3319 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
3320 | Debug.Assert( iLastPg > nFin ); |
||
3321 | |||
3322 | if ( !PTRMAP_ISPAGE( pBt, iLastPg ) && iLastPg != PENDING_BYTE_PAGE( pBt ) ) |
||
3323 | { |
||
3324 | u8 eType = 0; |
||
3325 | Pgno iPtrPage = 0; |
||
3326 | |||
3327 | nFreeList = sqlite3Get4byte( pBt.pPage1.aData, 36 ); |
||
3328 | if ( nFreeList == 0 ) |
||
3329 | { |
||
3330 | return SQLITE_DONE; |
||
3331 | } |
||
3332 | |||
3333 | rc = ptrmapGet( pBt, iLastPg, ref eType, ref iPtrPage ); |
||
3334 | if ( rc != SQLITE_OK ) |
||
3335 | { |
||
3336 | return rc; |
||
3337 | } |
||
3338 | if ( eType == PTRMAP_ROOTPAGE ) |
||
3339 | { |
||
3340 | return SQLITE_CORRUPT_BKPT(); |
||
3341 | } |
||
3342 | |||
3343 | if ( eType == PTRMAP_FREEPAGE ) |
||
3344 | { |
||
3345 | if ( nFin == 0 ) |
||
3346 | { |
||
3347 | /* Remove the page from the files free-list. This is not required |
||
3348 | ** if nFin is non-zero. In that case, the free-list will be |
||
3349 | ** truncated to zero after this function returns, so it doesn't |
||
3350 | ** matter if it still contains some garbage entries. |
||
3351 | */ |
||
3352 | Pgno iFreePg = 0; |
||
3353 | MemPage pFreePg = new MemPage(); |
||
3354 | rc = allocateBtreePage( pBt, ref pFreePg, ref iFreePg, iLastPg, 1 ); |
||
3355 | if ( rc != SQLITE_OK ) |
||
3356 | { |
||
3357 | return rc; |
||
3358 | } |
||
3359 | Debug.Assert( iFreePg == iLastPg ); |
||
3360 | releasePage( pFreePg ); |
||
3361 | } |
||
3362 | } |
||
3363 | else |
||
3364 | { |
||
3365 | Pgno iFreePg = 0; /* Index of free page to move pLastPg to */ |
||
3366 | MemPage pLastPg = new MemPage(); |
||
3367 | |||
3368 | rc = btreeGetPage( pBt, iLastPg, ref pLastPg, 0 ); |
||
3369 | if ( rc != SQLITE_OK ) |
||
3370 | { |
||
3371 | return rc; |
||
3372 | } |
||
3373 | |||
3374 | /* If nFin is zero, this loop runs exactly once and page pLastPg |
||
3375 | ** is swapped with the first free page pulled off the free list. |
||
3376 | ** |
||
3377 | ** On the other hand, if nFin is greater than zero, then keep |
||
3378 | ** looping until a free-page located within the first nFin pages |
||
3379 | ** of the file is found. |
||
3380 | */ |
||
3381 | do |
||
3382 | { |
||
3383 | MemPage pFreePg = new MemPage(); |
||
3384 | rc = allocateBtreePage( pBt, ref pFreePg, ref iFreePg, 0, 0 ); |
||
3385 | if ( rc != SQLITE_OK ) |
||
3386 | { |
||
3387 | releasePage( pLastPg ); |
||
3388 | return rc; |
||
3389 | } |
||
3390 | releasePage( pFreePg ); |
||
3391 | } while ( nFin != 0 && iFreePg > nFin ); |
||
3392 | Debug.Assert( iFreePg < iLastPg ); |
||
3393 | |||
3394 | rc = sqlite3PagerWrite( pLastPg.pDbPage ); |
||
3395 | if ( rc == SQLITE_OK ) |
||
3396 | { |
||
3397 | rc = relocatePage( pBt, pLastPg, eType, iPtrPage, iFreePg, ( nFin != 0 ) ? 1 : 0 ); |
||
3398 | } |
||
3399 | releasePage( pLastPg ); |
||
3400 | if ( rc != SQLITE_OK ) |
||
3401 | { |
||
3402 | return rc; |
||
3403 | } |
||
3404 | } |
||
3405 | } |
||
3406 | |||
3407 | if ( nFin == 0 ) |
||
3408 | { |
||
3409 | iLastPg--; |
||
3410 | while ( iLastPg == PENDING_BYTE_PAGE( pBt ) || PTRMAP_ISPAGE( pBt, iLastPg ) ) |
||
3411 | { |
||
3412 | if ( PTRMAP_ISPAGE( pBt, iLastPg ) ) |
||
3413 | { |
||
3414 | MemPage pPg = new MemPage(); |
||
3415 | rc = btreeGetPage( pBt, iLastPg, ref pPg, 0 ); |
||
3416 | if ( rc != SQLITE_OK ) |
||
3417 | { |
||
3418 | return rc; |
||
3419 | } |
||
3420 | rc = sqlite3PagerWrite( pPg.pDbPage ); |
||
3421 | releasePage( pPg ); |
||
3422 | if ( rc != SQLITE_OK ) |
||
3423 | { |
||
3424 | return rc; |
||
3425 | } |
||
3426 | } |
||
3427 | iLastPg--; |
||
3428 | } |
||
3429 | sqlite3PagerTruncateImage( pBt.pPager, iLastPg ); |
||
3430 | pBt.nPage = iLastPg; |
||
3431 | } |
||
3432 | return SQLITE_OK; |
||
3433 | } |
||
3434 | |||
3435 | /* |
||
3436 | ** A write-transaction must be opened before calling this function. |
||
3437 | ** It performs a single unit of work towards an incremental vacuum. |
||
3438 | ** |
||
3439 | ** If the incremental vacuum is finished after this function has run, |
||
3440 | ** SQLITE_DONE is returned. If it is not finished, but no error occurred, |
||
3441 | ** SQLITE_OK is returned. Otherwise an SQLite error code. |
||
3442 | */ |
||
3443 | static int sqlite3BtreeIncrVacuum( Btree p ) |
||
3444 | { |
||
3445 | int rc; |
||
3446 | BtShared pBt = p.pBt; |
||
3447 | |||
3448 | sqlite3BtreeEnter( p ); |
||
3449 | Debug.Assert( pBt.inTransaction == TRANS_WRITE && p.inTrans == TRANS_WRITE ); |
||
3450 | if ( !pBt.autoVacuum ) |
||
3451 | { |
||
3452 | rc = SQLITE_DONE; |
||
3453 | } |
||
3454 | else |
||
3455 | { |
||
3456 | invalidateAllOverflowCache( pBt ); |
||
3457 | rc = incrVacuumStep( pBt, 0, btreePagecount( pBt ) ); |
||
3458 | if ( rc == SQLITE_OK ) |
||
3459 | { |
||
3460 | rc = sqlite3PagerWrite( pBt.pPage1.pDbPage ); |
||
3461 | sqlite3Put4byte( pBt.pPage1.aData, (u32)28, pBt.nPage );//put4byte(&pBt->pPage1->aData[28], pBt->nPage); |
||
3462 | } |
||
3463 | } |
||
3464 | sqlite3BtreeLeave( p ); |
||
3465 | return rc; |
||
3466 | } |
||
3467 | |||
3468 | /* |
||
3469 | ** This routine is called prior to sqlite3PagerCommit when a transaction |
||
3470 | ** is commited for an auto-vacuum database. |
||
3471 | ** |
||
3472 | ** If SQLITE_OK is returned, then pnTrunc is set to the number of pages |
||
3473 | ** the database file should be truncated to during the commit process. |
||
3474 | ** i.e. the database has been reorganized so that only the first pnTrunc |
||
3475 | ** pages are in use. |
||
3476 | */ |
||
3477 | static int autoVacuumCommit( BtShared pBt ) |
||
3478 | { |
||
3479 | int rc = SQLITE_OK; |
||
3480 | Pager pPager = pBt.pPager; |
||
3481 | // VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager) ); |
||
3482 | #if !NDEBUG || DEBUG |
||
3483 | int nRef = sqlite3PagerRefcount( pPager ); |
||
3484 | #else |
||
3485 | int nRef=0; |
||
3486 | #endif |
||
3487 | |||
3488 | |||
3489 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
3490 | invalidateAllOverflowCache( pBt ); |
||
3491 | Debug.Assert( pBt.autoVacuum ); |
||
3492 | if ( !pBt.incrVacuum ) |
||
3493 | { |
||
3494 | Pgno nFin; /* Number of pages in database after autovacuuming */ |
||
3495 | Pgno nFree; /* Number of pages on the freelist initially */ |
||
3496 | Pgno nPtrmap; /* Number of PtrMap pages to be freed */ |
||
3497 | Pgno iFree; /* The next page to be freed */ |
||
3498 | int nEntry; /* Number of entries on one ptrmap page */ |
||
3499 | Pgno nOrig; /* Database size before freeing */ |
||
3500 | |||
3501 | nOrig = btreePagecount( pBt ); |
||
3502 | if ( PTRMAP_ISPAGE( pBt, nOrig ) || nOrig == PENDING_BYTE_PAGE( pBt ) ) |
||
3503 | { |
||
3504 | /* It is not possible to create a database for which the final page |
||
3505 | ** is either a pointer-map page or the pending-byte page. If one |
||
3506 | ** is encountered, this indicates corruption. |
||
3507 | */ |
||
3508 | return SQLITE_CORRUPT_BKPT(); |
||
3509 | } |
||
3510 | |||
3511 | nFree = sqlite3Get4byte( pBt.pPage1.aData, 36 ); |
||
3512 | nEntry = (int)pBt.usableSize / 5; |
||
3513 | nPtrmap = (Pgno)( ( nFree - nOrig + PTRMAP_PAGENO( pBt, nOrig ) + (Pgno)nEntry ) / nEntry ); |
||
3514 | nFin = nOrig - nFree - nPtrmap; |
||
3515 | if ( nOrig > PENDING_BYTE_PAGE( pBt ) && nFin < PENDING_BYTE_PAGE( pBt ) ) |
||
3516 | { |
||
3517 | nFin--; |
||
3518 | } |
||
3519 | while ( PTRMAP_ISPAGE( pBt, nFin ) || nFin == PENDING_BYTE_PAGE( pBt ) ) |
||
3520 | { |
||
3521 | nFin--; |
||
3522 | } |
||
3523 | if ( nFin > nOrig ) |
||
3524 | return SQLITE_CORRUPT_BKPT(); |
||
3525 | |||
3526 | for ( iFree = nOrig; iFree > nFin && rc == SQLITE_OK; iFree-- ) |
||
3527 | { |
||
3528 | rc = incrVacuumStep( pBt, nFin, iFree ); |
||
3529 | } |
||
3530 | if ( ( rc == SQLITE_DONE || rc == SQLITE_OK ) && nFree > 0 ) |
||
3531 | { |
||
3532 | rc = sqlite3PagerWrite( pBt.pPage1.pDbPage ); |
||
3533 | sqlite3Put4byte( pBt.pPage1.aData, 32, 0 ); |
||
3534 | sqlite3Put4byte( pBt.pPage1.aData, 36, 0 ); |
||
3535 | sqlite3Put4byte( pBt.pPage1.aData, (u32)28, nFin ); |
||
3536 | sqlite3PagerTruncateImage( pBt.pPager, nFin ); |
||
3537 | pBt.nPage = nFin; |
||
3538 | } |
||
3539 | if ( rc != SQLITE_OK ) |
||
3540 | { |
||
3541 | sqlite3PagerRollback( pPager ); |
||
3542 | } |
||
3543 | } |
||
3544 | |||
3545 | Debug.Assert( nRef == sqlite3PagerRefcount( pPager ) ); |
||
3546 | return rc; |
||
3547 | } |
||
3548 | |||
3549 | #else //* ifndef SQLITE_OMIT_AUTOVACUUM */ |
||
3550 | //# define setChildPtrmaps(x) SQLITE_OK |
||
3551 | #endif |
||
3552 | |||
3553 | /* |
||
3554 | ** This routine does the first phase of a two-phase commit. This routine |
||
3555 | ** causes a rollback journal to be created (if it does not already exist) |
||
3556 | ** and populated with enough information so that if a power loss occurs |
||
3557 | ** the database can be restored to its original state by playing back |
||
3558 | ** the journal. Then the contents of the journal are flushed out to |
||
3559 | ** the disk. After the journal is safely on oxide, the changes to the |
||
3560 | ** database are written into the database file and flushed to oxide. |
||
3561 | ** At the end of this call, the rollback journal still exists on the |
||
3562 | ** disk and we are still holding all locks, so the transaction has not |
||
3563 | ** committed. See sqlite3BtreeCommitPhaseTwo() for the second phase of the |
||
3564 | ** commit process. |
||
3565 | ** |
||
3566 | ** This call is a no-op if no write-transaction is currently active on pBt. |
||
3567 | ** |
||
3568 | ** Otherwise, sync the database file for the btree pBt. zMaster points to |
||
3569 | ** the name of a master journal file that should be written into the |
||
3570 | ** individual journal file, or is NULL, indicating no master journal file |
||
3571 | ** (single database transaction). |
||
3572 | ** |
||
3573 | ** When this is called, the master journal should already have been |
||
3574 | ** created, populated with this journal pointer and synced to disk. |
||
3575 | ** |
||
3576 | ** Once this is routine has returned, the only thing required to commit |
||
3577 | ** the write-transaction for this database file is to delete the journal. |
||
3578 | */ |
||
3579 | static int sqlite3BtreeCommitPhaseOne( Btree p, string zMaster ) |
||
3580 | { |
||
3581 | int rc = SQLITE_OK; |
||
3582 | if ( p.inTrans == TRANS_WRITE ) |
||
3583 | { |
||
3584 | BtShared pBt = p.pBt; |
||
3585 | sqlite3BtreeEnter( p ); |
||
3586 | #if !SQLITE_OMIT_AUTOVACUUM |
||
3587 | if ( pBt.autoVacuum ) |
||
3588 | { |
||
3589 | rc = autoVacuumCommit( pBt ); |
||
3590 | if ( rc != SQLITE_OK ) |
||
3591 | { |
||
3592 | sqlite3BtreeLeave( p ); |
||
3593 | return rc; |
||
3594 | } |
||
3595 | } |
||
3596 | #endif |
||
3597 | rc = sqlite3PagerCommitPhaseOne( pBt.pPager, zMaster, false ); |
||
3598 | sqlite3BtreeLeave( p ); |
||
3599 | } |
||
3600 | return rc; |
||
3601 | } |
||
3602 | |||
3603 | /* |
||
3604 | ** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback() |
||
3605 | ** at the conclusion of a transaction. |
||
3606 | */ |
||
3607 | static void btreeEndTransaction( Btree p ) |
||
3608 | { |
||
3609 | BtShared pBt = p.pBt; |
||
3610 | Debug.Assert( sqlite3BtreeHoldsMutex( p ) ); |
||
3611 | |||
3612 | btreeClearHasContent( pBt ); |
||
3613 | if ( p.inTrans > TRANS_NONE && p.db.activeVdbeCnt > 1 ) |
||
3614 | { |
||
3615 | /* If there are other active statements that belong to this database |
||
3616 | ** handle, downgrade to a read-only transaction. The other statements |
||
3617 | ** may still be reading from the database. */ |
||
3618 | |||
3619 | downgradeAllSharedCacheTableLocks( p ); |
||
3620 | p.inTrans = TRANS_READ; |
||
3621 | } |
||
3622 | else |
||
3623 | { |
||
3624 | /* If the handle had any kind of transaction open, decrement the |
||
3625 | ** transaction count of the shared btree. If the transaction count |
||
3626 | ** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused() |
||
3627 | ** call below will unlock the pager. */ |
||
3628 | if ( p.inTrans != TRANS_NONE ) |
||
3629 | { |
||
3630 | clearAllSharedCacheTableLocks( p ); |
||
3631 | pBt.nTransaction--; |
||
3632 | if ( 0 == pBt.nTransaction ) |
||
3633 | { |
||
3634 | pBt.inTransaction = TRANS_NONE; |
||
3635 | } |
||
3636 | } |
||
3637 | |||
3638 | /* Set the current transaction state to TRANS_NONE and unlock the |
||
3639 | ** pager if this call closed the only read or write transaction. */ |
||
3640 | p.inTrans = TRANS_NONE; |
||
3641 | unlockBtreeIfUnused( pBt ); |
||
3642 | } |
||
3643 | |||
3644 | btreeIntegrity( p ); |
||
3645 | } |
||
3646 | |||
3647 | /* |
||
3648 | ** Commit the transaction currently in progress. |
||
3649 | ** |
||
3650 | ** This routine implements the second phase of a 2-phase commit. The |
||
3651 | ** sqlite3BtreeCommitPhaseOne() routine does the first phase and should |
||
3652 | ** be invoked prior to calling this routine. The sqlite3BtreeCommitPhaseOne() |
||
3653 | ** routine did all the work of writing information out to disk and flushing the |
||
3654 | ** contents so that they are written onto the disk platter. All this |
||
3655 | ** routine has to do is delete or truncate or zero the header in the |
||
3656 | ** the rollback journal (which causes the transaction to commit) and |
||
3657 | ** drop locks. |
||
3658 | ** |
||
3659 | ** Normally, if an error occurs while the pager layer is attempting to |
||
3660 | ** finalize the underlying journal file, this function returns an error and |
||
3661 | ** the upper layer will attempt a rollback. However, if the second argument |
||
3662 | ** is non-zero then this b-tree transaction is part of a multi-file |
||
3663 | ** transaction. In this case, the transaction has already been committed |
||
3664 | ** (by deleting a master journal file) and the caller will ignore this |
||
3665 | ** functions return code. So, even if an error occurs in the pager layer, |
||
3666 | ** reset the b-tree objects internal state to indicate that the write |
||
3667 | ** transaction has been closed. This is quite safe, as the pager will have |
||
3668 | ** transitioned to the error state. |
||
3669 | ** |
||
3670 | ** This will release the write lock on the database file. If there |
||
3671 | ** are no active cursors, it also releases the read lock. |
||
3672 | */ |
||
3673 | static int sqlite3BtreeCommitPhaseTwo( Btree p, int bCleanup) |
||
3674 | { |
||
3675 | if ( p.inTrans == TRANS_NONE ) |
||
3676 | return SQLITE_OK; |
||
3677 | sqlite3BtreeEnter( p ); |
||
3678 | btreeIntegrity( p ); |
||
3679 | |||
3680 | /* If the handle has a write-transaction open, commit the shared-btrees |
||
3681 | ** transaction and set the shared state to TRANS_READ. |
||
3682 | */ |
||
3683 | if ( p.inTrans == TRANS_WRITE ) |
||
3684 | { |
||
3685 | int rc; |
||
3686 | BtShared pBt = p.pBt; |
||
3687 | Debug.Assert( pBt.inTransaction == TRANS_WRITE ); |
||
3688 | Debug.Assert( pBt.nTransaction > 0 ); |
||
3689 | rc = sqlite3PagerCommitPhaseTwo( pBt.pPager ); |
||
3690 | if ( rc != SQLITE_OK && bCleanup == 0 ) |
||
3691 | { |
||
3692 | sqlite3BtreeLeave( p ); |
||
3693 | return rc; |
||
3694 | } |
||
3695 | pBt.inTransaction = TRANS_READ; |
||
3696 | } |
||
3697 | |||
3698 | btreeEndTransaction( p ); |
||
3699 | sqlite3BtreeLeave( p ); |
||
3700 | return SQLITE_OK; |
||
3701 | } |
||
3702 | |||
3703 | /* |
||
3704 | ** Do both phases of a commit. |
||
3705 | */ |
||
3706 | static int sqlite3BtreeCommit( Btree p ) |
||
3707 | { |
||
3708 | int rc; |
||
3709 | sqlite3BtreeEnter( p ); |
||
3710 | rc = sqlite3BtreeCommitPhaseOne( p, null ); |
||
3711 | if ( rc == SQLITE_OK ) |
||
3712 | { |
||
3713 | rc = sqlite3BtreeCommitPhaseTwo( p, 0 ); |
||
3714 | } |
||
3715 | sqlite3BtreeLeave( p ); |
||
3716 | return rc; |
||
3717 | } |
||
3718 | |||
3719 | #if !NDEBUG || DEBUG |
||
3720 | /* |
||
3721 | ** Return the number of write-cursors open on this handle. This is for use |
||
3722 | ** in Debug.Assert() expressions, so it is only compiled if NDEBUG is not |
||
3723 | ** defined. |
||
3724 | ** |
||
3725 | ** For the purposes of this routine, a write-cursor is any cursor that |
||
3726 | ** is capable of writing to the databse. That means the cursor was |
||
3727 | ** originally opened for writing and the cursor has not be disabled |
||
3728 | ** by having its state changed to CURSOR_FAULT. |
||
3729 | */ |
||
3730 | static int countWriteCursors( BtShared pBt ) |
||
3731 | { |
||
3732 | BtCursor pCur; |
||
3733 | int r = 0; |
||
3734 | for ( pCur = pBt.pCursor; pCur != null; pCur = pCur.pNext ) |
||
3735 | { |
||
3736 | if ( pCur.wrFlag != 0 && pCur.eState != CURSOR_FAULT ) |
||
3737 | r++; |
||
3738 | } |
||
3739 | return r; |
||
3740 | } |
||
3741 | #else |
||
3742 | static int countWriteCursors(BtShared pBt) { return -1; } |
||
3743 | #endif |
||
3744 | |||
3745 | /* |
||
3746 | ** This routine sets the state to CURSOR_FAULT and the error |
||
3747 | ** code to errCode for every cursor on BtShared that pBtree |
||
3748 | ** references. |
||
3749 | ** |
||
3750 | ** Every cursor is tripped, including cursors that belong |
||
3751 | ** to other database connections that happen to be sharing |
||
3752 | ** the cache with pBtree. |
||
3753 | ** |
||
3754 | ** This routine gets called when a rollback occurs. |
||
3755 | ** All cursors using the same cache must be tripped |
||
3756 | ** to prevent them from trying to use the btree after |
||
3757 | ** the rollback. The rollback may have deleted tables |
||
3758 | ** or moved root pages, so it is not sufficient to |
||
3759 | ** save the state of the cursor. The cursor must be |
||
3760 | ** invalidated. |
||
3761 | */ |
||
3762 | static void sqlite3BtreeTripAllCursors( Btree pBtree, int errCode ) |
||
3763 | { |
||
3764 | BtCursor p; |
||
3765 | sqlite3BtreeEnter( pBtree ); |
||
3766 | for ( p = pBtree.pBt.pCursor; p != null; p = p.pNext ) |
||
3767 | { |
||
3768 | int i; |
||
3769 | sqlite3BtreeClearCursor( p ); |
||
3770 | p.eState = CURSOR_FAULT; |
||
3771 | p.skipNext = errCode; |
||
3772 | for ( i = 0; i <= p.iPage; i++ ) |
||
3773 | { |
||
3774 | releasePage( p.apPage[i] ); |
||
3775 | p.apPage[i] = null; |
||
3776 | } |
||
3777 | } |
||
3778 | sqlite3BtreeLeave( pBtree ); |
||
3779 | } |
||
3780 | |||
3781 | /* |
||
3782 | ** Rollback the transaction in progress. All cursors will be |
||
3783 | ** invalided by this operation. Any attempt to use a cursor |
||
3784 | ** that was open at the beginning of this operation will result |
||
3785 | ** in an error. |
||
3786 | ** |
||
3787 | ** This will release the write lock on the database file. If there |
||
3788 | ** are no active cursors, it also releases the read lock. |
||
3789 | */ |
||
3790 | static int sqlite3BtreeRollback( Btree p ) |
||
3791 | { |
||
3792 | int rc; |
||
3793 | BtShared pBt = p.pBt; |
||
3794 | MemPage pPage1 = new MemPage(); |
||
3795 | |||
3796 | sqlite3BtreeEnter( p ); |
||
3797 | rc = saveAllCursors( pBt, 0, null ); |
||
3798 | #if !SQLITE_OMIT_SHARED_CACHE |
||
3799 | if( rc!=SQLITE_OK ){ |
||
3800 | /* This is a horrible situation. An IO or malloc() error occurred whilst |
||
3801 | ** trying to save cursor positions. If this is an automatic rollback (as |
||
3802 | ** the result of a constraint, malloc() failure or IO error) then |
||
3803 | ** the cache may be internally inconsistent (not contain valid trees) so |
||
3804 | ** we cannot simply return the error to the caller. Instead, abort |
||
3805 | ** all queries that may be using any of the cursors that failed to save. |
||
3806 | */ |
||
3807 | sqlite3BtreeTripAllCursors(p, rc); |
||
3808 | } |
||
3809 | #endif |
||
3810 | btreeIntegrity( p ); |
||
3811 | |||
3812 | if ( p.inTrans == TRANS_WRITE ) |
||
3813 | { |
||
3814 | int rc2; |
||
3815 | |||
3816 | Debug.Assert( TRANS_WRITE == pBt.inTransaction ); |
||
3817 | rc2 = sqlite3PagerRollback( pBt.pPager ); |
||
3818 | if ( rc2 != SQLITE_OK ) |
||
3819 | { |
||
3820 | rc = rc2; |
||
3821 | } |
||
3822 | |||
3823 | /* The rollback may have destroyed the pPage1.aData value. So |
||
3824 | ** call btreeGetPage() on page 1 again to make |
||
3825 | ** sure pPage1.aData is set correctly. */ |
||
3826 | if ( btreeGetPage( pBt, 1, ref pPage1, 0 ) == SQLITE_OK ) |
||
3827 | { |
||
3828 | Pgno nPage = sqlite3Get4byte( pPage1.aData, 28 ); |
||
3829 | testcase( nPage == 0 ); |
||
3830 | if ( nPage == 0 ) |
||
3831 | sqlite3PagerPagecount( pBt.pPager, out nPage ); |
||
3832 | testcase( pBt.nPage != nPage ); |
||
3833 | pBt.nPage = nPage; |
||
3834 | releasePage( pPage1 ); |
||
3835 | } |
||
3836 | Debug.Assert( countWriteCursors( pBt ) == 0 ); |
||
3837 | pBt.inTransaction = TRANS_READ; |
||
3838 | } |
||
3839 | |||
3840 | btreeEndTransaction( p ); |
||
3841 | sqlite3BtreeLeave( p ); |
||
3842 | return rc; |
||
3843 | } |
||
3844 | |||
3845 | /* |
||
3846 | ** Start a statement subtransaction. The subtransaction can can be rolled |
||
3847 | ** back independently of the main transaction. You must start a transaction |
||
3848 | ** before starting a subtransaction. The subtransaction is ended automatically |
||
3849 | ** if the main transaction commits or rolls back. |
||
3850 | ** |
||
3851 | ** Statement subtransactions are used around individual SQL statements |
||
3852 | ** that are contained within a BEGIN...COMMIT block. If a constraint |
||
3853 | ** error occurs within the statement, the effect of that one statement |
||
3854 | ** can be rolled back without having to rollback the entire transaction. |
||
3855 | ** |
||
3856 | ** A statement sub-transaction is implemented as an anonymous savepoint. The |
||
3857 | ** value passed as the second parameter is the total number of savepoints, |
||
3858 | ** including the new anonymous savepoint, open on the B-Tree. i.e. if there |
||
3859 | ** are no active savepoints and no other statement-transactions open, |
||
3860 | ** iStatement is 1. This anonymous savepoint can be released or rolled back |
||
3861 | ** using the sqlite3BtreeSavepoint() function. |
||
3862 | */ |
||
3863 | static int sqlite3BtreeBeginStmt( Btree p, int iStatement ) |
||
3864 | { |
||
3865 | int rc; |
||
3866 | BtShared pBt = p.pBt; |
||
3867 | sqlite3BtreeEnter( p ); |
||
3868 | Debug.Assert( p.inTrans == TRANS_WRITE ); |
||
3869 | Debug.Assert( !pBt.readOnly ); |
||
3870 | Debug.Assert( iStatement > 0 ); |
||
3871 | Debug.Assert( iStatement > p.db.nSavepoint ); |
||
3872 | Debug.Assert( pBt.inTransaction == TRANS_WRITE ); |
||
3873 | /* At the pager level, a statement transaction is a savepoint with |
||
3874 | ** an index greater than all savepoints created explicitly using |
||
3875 | ** SQL statements. It is illegal to open, release or rollback any |
||
3876 | ** such savepoints while the statement transaction savepoint is active. |
||
3877 | */ |
||
3878 | rc = sqlite3PagerOpenSavepoint( pBt.pPager, iStatement ); |
||
3879 | sqlite3BtreeLeave( p ); |
||
3880 | return rc; |
||
3881 | } |
||
3882 | |||
3883 | /* |
||
3884 | ** The second argument to this function, op, is always SAVEPOINT_ROLLBACK |
||
3885 | ** or SAVEPOINT_RELEASE. This function either releases or rolls back the |
||
3886 | ** savepoint identified by parameter iSavepoint, depending on the value |
||
3887 | ** of op. |
||
3888 | ** |
||
3889 | ** Normally, iSavepoint is greater than or equal to zero. However, if op is |
||
3890 | ** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the |
||
3891 | ** contents of the entire transaction are rolled back. This is different |
||
3892 | ** from a normal transaction rollback, as no locks are released and the |
||
3893 | ** transaction remains open. |
||
3894 | */ |
||
3895 | static int sqlite3BtreeSavepoint( Btree p, int op, int iSavepoint ) |
||
3896 | { |
||
3897 | int rc = SQLITE_OK; |
||
3898 | if ( p != null && p.inTrans == TRANS_WRITE ) |
||
3899 | { |
||
3900 | BtShared pBt = p.pBt; |
||
3901 | Debug.Assert( op == SAVEPOINT_RELEASE || op == SAVEPOINT_ROLLBACK ); |
||
3902 | Debug.Assert( iSavepoint >= 0 || ( iSavepoint == -1 && op == SAVEPOINT_ROLLBACK ) ); |
||
3903 | sqlite3BtreeEnter( p ); |
||
3904 | rc = sqlite3PagerSavepoint( pBt.pPager, op, iSavepoint ); |
||
3905 | if ( rc == SQLITE_OK ) |
||
3906 | { |
||
3907 | if ( iSavepoint < 0 && pBt.initiallyEmpty ) |
||
3908 | pBt.nPage = 0; |
||
3909 | rc = newDatabase( pBt ); |
||
3910 | pBt.nPage = sqlite3Get4byte( pBt.pPage1.aData, 28 ); |
||
3911 | /* The database size was written into the offset 28 of the header |
||
3912 | ** when the transaction started, so we know that the value at offset |
||
3913 | ** 28 is nonzero. */ |
||
3914 | Debug.Assert( pBt.nPage > 0 ); |
||
3915 | } |
||
3916 | sqlite3BtreeLeave( p ); |
||
3917 | } |
||
3918 | return rc; |
||
3919 | } |
||
3920 | |||
3921 | /* |
||
3922 | ** Create a new cursor for the BTree whose root is on the page |
||
3923 | ** iTable. If a read-only cursor is requested, it is assumed that |
||
3924 | ** the caller already has at least a read-only transaction open |
||
3925 | ** on the database already. If a write-cursor is requested, then |
||
3926 | ** the caller is assumed to have an open write transaction. |
||
3927 | ** |
||
3928 | ** If wrFlag==null, then the cursor can only be used for reading. |
||
3929 | ** If wrFlag==1, then the cursor can be used for reading or for |
||
3930 | ** writing if other conditions for writing are also met. These |
||
3931 | ** are the conditions that must be met in order for writing to |
||
3932 | ** be allowed: |
||
3933 | ** |
||
3934 | ** 1: The cursor must have been opened with wrFlag==1 |
||
3935 | ** |
||
3936 | ** 2: Other database connections that share the same pager cache |
||
3937 | ** but which are not in the READ_UNCOMMITTED state may not have |
||
3938 | ** cursors open with wrFlag==null on the same table. Otherwise |
||
3939 | ** the changes made by this write cursor would be visible to |
||
3940 | ** the read cursors in the other database connection. |
||
3941 | ** |
||
3942 | ** 3: The database must be writable (not on read-only media) |
||
3943 | ** |
||
3944 | ** 4: There must be an active transaction. |
||
3945 | ** |
||
3946 | ** No checking is done to make sure that page iTable really is the |
||
3947 | ** root page of a b-tree. If it is not, then the cursor acquired |
||
3948 | ** will not work correctly. |
||
3949 | ** |
||
3950 | ** It is assumed that the sqlite3BtreeCursorZero() has been called |
||
3951 | ** on pCur to initialize the memory space prior to invoking this routine. |
||
3952 | */ |
||
3953 | static int btreeCursor( |
||
3954 | Btree p, /* The btree */ |
||
3955 | int iTable, /* Root page of table to open */ |
||
3956 | int wrFlag, /* 1 to write. 0 read-only */ |
||
3957 | KeyInfo pKeyInfo, /* First arg to comparison function */ |
||
3958 | BtCursor pCur /* Space for new cursor */ |
||
3959 | ) |
||
3960 | { |
||
3961 | BtShared pBt = p.pBt; /* Shared b-tree handle */ |
||
3962 | |||
3963 | Debug.Assert( sqlite3BtreeHoldsMutex( p ) ); |
||
3964 | Debug.Assert( wrFlag == 0 || wrFlag == 1 ); |
||
3965 | |||
3966 | /* The following Debug.Assert statements verify that if this is a sharable |
||
3967 | ** b-tree database, the connection is holding the required table locks, |
||
3968 | ** and that no other connection has any open cursor that conflicts with |
||
3969 | ** this lock. */ |
||
3970 | Debug.Assert( hasSharedCacheTableLock( p, (u32)iTable, pKeyInfo != null ? 1 : 0, wrFlag + 1 ) ); |
||
3971 | Debug.Assert( wrFlag == 0 || !hasReadConflicts( p, (u32)iTable ) ); |
||
3972 | |||
3973 | /* Assert that the caller has opened the required transaction. */ |
||
3974 | Debug.Assert( p.inTrans > TRANS_NONE ); |
||
3975 | Debug.Assert( wrFlag == 0 || p.inTrans == TRANS_WRITE ); |
||
3976 | Debug.Assert( pBt.pPage1 != null && pBt.pPage1.aData != null ); |
||
3977 | |||
3978 | if ( NEVER( wrFlag != 0 && pBt.readOnly ) ) |
||
3979 | { |
||
3980 | return SQLITE_READONLY; |
||
3981 | } |
||
3982 | if ( iTable == 1 && btreePagecount( pBt ) == 0 ) |
||
3983 | { |
||
3984 | return SQLITE_EMPTY; |
||
3985 | } |
||
3986 | |||
3987 | /* Now that no other errors can occur, finish filling in the BtCursor |
||
3988 | ** variables and link the cursor into the BtShared list. */ |
||
3989 | pCur.pgnoRoot = (Pgno)iTable; |
||
3990 | pCur.iPage = -1; |
||
3991 | pCur.pKeyInfo = pKeyInfo; |
||
3992 | pCur.pBtree = p; |
||
3993 | pCur.pBt = pBt; |
||
3994 | pCur.wrFlag = (u8)wrFlag; |
||
3995 | pCur.pNext = pBt.pCursor; |
||
3996 | if ( pCur.pNext != null ) |
||
3997 | { |
||
3998 | pCur.pNext.pPrev = pCur; |
||
3999 | } |
||
4000 | pBt.pCursor = pCur; |
||
4001 | pCur.eState = CURSOR_INVALID; |
||
4002 | pCur.cachedRowid = 0; |
||
4003 | return SQLITE_OK; |
||
4004 | } |
||
4005 | static int sqlite3BtreeCursor( |
||
4006 | Btree p, /* The btree */ |
||
4007 | int iTable, /* Root page of table to open */ |
||
4008 | int wrFlag, /* 1 to write. 0 read-only */ |
||
4009 | KeyInfo pKeyInfo, /* First arg to xCompare() */ |
||
4010 | BtCursor pCur /* Write new cursor here */ |
||
4011 | ) |
||
4012 | { |
||
4013 | int rc; |
||
4014 | sqlite3BtreeEnter( p ); |
||
4015 | rc = btreeCursor( p, iTable, wrFlag, pKeyInfo, pCur ); |
||
4016 | sqlite3BtreeLeave( p ); |
||
4017 | return rc; |
||
4018 | } |
||
4019 | |||
4020 | /* |
||
4021 | ** Return the size of a BtCursor object in bytes. |
||
4022 | ** |
||
4023 | ** This interfaces is needed so that users of cursors can preallocate |
||
4024 | ** sufficient storage to hold a cursor. The BtCursor object is opaque |
||
4025 | ** to users so they cannot do the sizeof() themselves - they must call |
||
4026 | ** this routine. |
||
4027 | */ |
||
4028 | static int sqlite3BtreeCursorSize() |
||
4029 | { |
||
4030 | return -1; // Not Used -- return ROUND8(sizeof(BtCursor)); |
||
4031 | } |
||
4032 | |||
4033 | /* |
||
4034 | ** Initialize memory that will be converted into a BtCursor object. |
||
4035 | ** |
||
4036 | ** The simple approach here would be to memset() the entire object |
||
4037 | ** to zero. But it turns out that the apPage[] and aiIdx[] arrays |
||
4038 | ** do not need to be zeroed and they are large, so we can save a lot |
||
4039 | ** of run-time by skipping the initialization of those elements. |
||
4040 | */ |
||
4041 | static void sqlite3BtreeCursorZero( BtCursor p ) |
||
4042 | { |
||
4043 | p.Clear(); // memset( p, 0, offsetof( BtCursor, iPage ) ); |
||
4044 | } |
||
4045 | |||
4046 | /* |
||
4047 | ** Set the cached rowid value of every cursor in the same database file |
||
4048 | ** as pCur and having the same root page number as pCur. The value is |
||
4049 | ** set to iRowid. |
||
4050 | ** |
||
4051 | ** Only positive rowid values are considered valid for this cache. |
||
4052 | ** The cache is initialized to zero, indicating an invalid cache. |
||
4053 | ** A btree will work fine with zero or negative rowids. We just cannot |
||
4054 | ** cache zero or negative rowids, which means tables that use zero or |
||
4055 | ** negative rowids might run a little slower. But in practice, zero |
||
4056 | ** or negative rowids are very uncommon so this should not be a problem. |
||
4057 | */ |
||
4058 | static void sqlite3BtreeSetCachedRowid( BtCursor pCur, sqlite3_int64 iRowid ) |
||
4059 | { |
||
4060 | BtCursor p; |
||
4061 | for ( p = pCur.pBt.pCursor; p != null; p = p.pNext ) |
||
4062 | { |
||
4063 | if ( p.pgnoRoot == pCur.pgnoRoot ) |
||
4064 | p.cachedRowid = iRowid; |
||
4065 | } |
||
4066 | Debug.Assert( pCur.cachedRowid == iRowid ); |
||
4067 | } |
||
4068 | |||
4069 | /* |
||
4070 | ** Return the cached rowid for the given cursor. A negative or zero |
||
4071 | ** return value indicates that the rowid cache is invalid and should be |
||
4072 | ** ignored. If the rowid cache has never before been set, then a |
||
4073 | ** zero is returned. |
||
4074 | */ |
||
4075 | static sqlite3_int64 sqlite3BtreeGetCachedRowid( BtCursor pCur ) |
||
4076 | { |
||
4077 | return pCur.cachedRowid; |
||
4078 | } |
||
4079 | |||
4080 | /* |
||
4081 | ** Close a cursor. The read lock on the database file is released |
||
4082 | ** when the last cursor is closed. |
||
4083 | */ |
||
4084 | static int sqlite3BtreeCloseCursor( BtCursor pCur ) |
||
4085 | { |
||
4086 | Btree pBtree = pCur.pBtree; |
||
4087 | if ( pBtree != null ) |
||
4088 | { |
||
4089 | int i; |
||
4090 | BtShared pBt = pCur.pBt; |
||
4091 | sqlite3BtreeEnter( pBtree ); |
||
4092 | sqlite3BtreeClearCursor( pCur ); |
||
4093 | if ( pCur.pPrev != null ) |
||
4094 | { |
||
4095 | pCur.pPrev.pNext = pCur.pNext; |
||
4096 | } |
||
4097 | else |
||
4098 | { |
||
4099 | pBt.pCursor = pCur.pNext; |
||
4100 | } |
||
4101 | if ( pCur.pNext != null ) |
||
4102 | { |
||
4103 | pCur.pNext.pPrev = pCur.pPrev; |
||
4104 | } |
||
4105 | for ( i = 0; i <= pCur.iPage; i++ ) |
||
4106 | { |
||
4107 | releasePage( pCur.apPage[i] ); |
||
4108 | } |
||
4109 | unlockBtreeIfUnused( pBt ); |
||
4110 | invalidateOverflowCache( pCur ); |
||
4111 | /* sqlite3_free(ref pCur); */ |
||
4112 | sqlite3BtreeLeave( pBtree ); |
||
4113 | } |
||
4114 | return SQLITE_OK; |
||
4115 | } |
||
4116 | |||
4117 | /* |
||
4118 | ** Make sure the BtCursor* given in the argument has a valid |
||
4119 | ** BtCursor.info structure. If it is not already valid, call |
||
4120 | ** btreeParseCell() to fill it in. |
||
4121 | ** |
||
4122 | ** BtCursor.info is a cache of the information in the current cell. |
||
4123 | ** Using this cache reduces the number of calls to btreeParseCell(). |
||
4124 | ** |
||
4125 | ** 2007-06-25: There is a bug in some versions of MSVC that cause the |
||
4126 | ** compiler to crash when getCellInfo() is implemented as a macro. |
||
4127 | ** But there is a measureable speed advantage to using the macro on gcc |
||
4128 | ** (when less compiler optimizations like -Os or -O0 are used and the |
||
4129 | ** compiler is not doing agressive inlining.) So we use a real function |
||
4130 | ** for MSVC and a macro for everything else. Ticket #2457. |
||
4131 | */ |
||
4132 | #if !NDEBUG |
||
4133 | static void assertCellInfo( BtCursor pCur ) |
||
4134 | { |
||
4135 | CellInfo info; |
||
4136 | int iPage = pCur.iPage; |
||
4137 | info = new CellInfo();//memset(info, 0, sizeof(info)); |
||
4138 | btreeParseCell( pCur.apPage[iPage], pCur.aiIdx[iPage], ref info ); |
||
4139 | Debug.Assert( info.GetHashCode() == pCur.info.GetHashCode() || info.Equals( pCur.info ) );//memcmp(info, pCur.info, sizeof(info))==0 ); |
||
4140 | } |
||
4141 | #else |
||
4142 | // #define assertCellInfo(x) |
||
4143 | static void assertCellInfo(BtCursor pCur) { } |
||
4144 | #endif |
||
4145 | |||
4146 | ////#if _MSC_VER |
||
4147 | /* Use a real function in MSVC to work around bugs in that compiler. */ |
||
4148 | static void getCellInfo( BtCursor pCur ) |
||
4149 | { |
||
4150 | if ( pCur.info.nSize == 0 ) |
||
4151 | { |
||
4152 | int iPage = pCur.iPage; |
||
4153 | btreeParseCell( pCur.apPage[iPage], pCur.aiIdx[iPage], ref pCur.info ); |
||
4154 | pCur.validNKey = true; |
||
4155 | } |
||
4156 | else |
||
4157 | { |
||
4158 | assertCellInfo( pCur ); |
||
4159 | } |
||
4160 | } |
||
4161 | ////#else //* if not _MSC_VER */ |
||
4162 | ///* Use a macro in all other compilers so that the function is inlined */ |
||
4163 | ////#define getCellInfo(pCur) \ |
||
4164 | //// if( pCur.info.nSize==null ){ \ |
||
4165 | //// int iPage = pCur.iPage; \ |
||
4166 | //// btreeParseCell(pCur.apPage[iPage],pCur.aiIdx[iPage],&pCur.info); \ |
||
4167 | //// pCur.validNKey = true; \ |
||
4168 | //// }else{ \ |
||
4169 | //// assertCellInfo(pCur); \ |
||
4170 | //// } |
||
4171 | ////#endif //* _MSC_VER */ |
||
4172 | |||
4173 | #if !NDEBUG //* The next routine used only within Debug.Assert() statements */ |
||
4174 | /* |
||
4175 | ** Return true if the given BtCursor is valid. A valid cursor is one |
||
4176 | ** that is currently pointing to a row in a (non-empty) table. |
||
4177 | ** This is a verification routine is used only within Debug.Assert() statements. |
||
4178 | */ |
||
4179 | static bool sqlite3BtreeCursorIsValid( BtCursor pCur ) |
||
4180 | { |
||
4181 | return pCur != null && pCur.eState == CURSOR_VALID; |
||
4182 | } |
||
4183 | #else |
||
4184 | static bool sqlite3BtreeCursorIsValid(BtCursor pCur) { return true; } |
||
4185 | #endif //* NDEBUG */ |
||
4186 | |||
4187 | /* |
||
4188 | ** Set pSize to the size of the buffer needed to hold the value of |
||
4189 | ** the key for the current entry. If the cursor is not pointing |
||
4190 | ** to a valid entry, pSize is set to 0. |
||
4191 | ** |
||
4192 | ** For a table with the INTKEY flag set, this routine returns the key |
||
4193 | ** itself, not the number of bytes in the key. |
||
4194 | ** |
||
4195 | ** The caller must position the cursor prior to invoking this routine. |
||
4196 | ** |
||
4197 | ** This routine cannot fail. It always returns SQLITE_OK. |
||
4198 | */ |
||
4199 | static int sqlite3BtreeKeySize( BtCursor pCur, ref i64 pSize ) |
||
4200 | { |
||
4201 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4202 | Debug.Assert( pCur.eState == CURSOR_INVALID || pCur.eState == CURSOR_VALID ); |
||
4203 | if ( pCur.eState != CURSOR_VALID ) |
||
4204 | { |
||
4205 | pSize = 0; |
||
4206 | } |
||
4207 | else |
||
4208 | { |
||
4209 | getCellInfo( pCur ); |
||
4210 | pSize = pCur.info.nKey; |
||
4211 | } |
||
4212 | return SQLITE_OK; |
||
4213 | } |
||
4214 | |||
4215 | /* |
||
4216 | ** Set pSize to the number of bytes of data in the entry the |
||
4217 | ** cursor currently points to. |
||
4218 | ** |
||
4219 | ** The caller must guarantee that the cursor is pointing to a non-NULL |
||
4220 | ** valid entry. In other words, the calling procedure must guarantee |
||
4221 | ** that the cursor has Cursor.eState==CURSOR_VALID. |
||
4222 | ** |
||
4223 | ** Failure is not possible. This function always returns SQLITE_OK. |
||
4224 | ** It might just as well be a procedure (returning void) but we continue |
||
4225 | ** to return an integer result code for historical reasons. |
||
4226 | */ |
||
4227 | static int sqlite3BtreeDataSize( BtCursor pCur, ref u32 pSize ) |
||
4228 | { |
||
4229 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4230 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4231 | getCellInfo( pCur ); |
||
4232 | pSize = pCur.info.nData; |
||
4233 | return SQLITE_OK; |
||
4234 | } |
||
4235 | |||
4236 | /* |
||
4237 | ** Given the page number of an overflow page in the database (parameter |
||
4238 | ** ovfl), this function finds the page number of the next page in the |
||
4239 | ** linked list of overflow pages. If possible, it uses the auto-vacuum |
||
4240 | ** pointer-map data instead of reading the content of page ovfl to do so. |
||
4241 | ** |
||
4242 | ** If an error occurs an SQLite error code is returned. Otherwise: |
||
4243 | ** |
||
4244 | ** The page number of the next overflow page in the linked list is |
||
4245 | ** written to pPgnoNext. If page ovfl is the last page in its linked |
||
4246 | ** list, pPgnoNext is set to zero. |
||
4247 | ** |
||
4248 | ** If ppPage is not NULL, and a reference to the MemPage object corresponding |
||
4249 | ** to page number pOvfl was obtained, then ppPage is set to point to that |
||
4250 | ** reference. It is the responsibility of the caller to call releasePage() |
||
4251 | ** on ppPage to free the reference. In no reference was obtained (because |
||
4252 | ** the pointer-map was used to obtain the value for pPgnoNext), then |
||
4253 | ** ppPage is set to zero. |
||
4254 | */ |
||
4255 | static int getOverflowPage( |
||
4256 | BtShared pBt, /* The database file */ |
||
4257 | Pgno ovfl, /* Current overflow page number */ |
||
4258 | out MemPage ppPage, /* OUT: MemPage handle (may be NULL) */ |
||
4259 | out Pgno pPgnoNext /* OUT: Next overflow page number */ |
||
4260 | ) |
||
4261 | { |
||
4262 | Pgno next = 0; |
||
4263 | MemPage pPage = null; |
||
4264 | ppPage = null; |
||
4265 | int rc = SQLITE_OK; |
||
4266 | |||
4267 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
4268 | // Debug.Assert( pPgnoNext); |
||
4269 | |||
4270 | #if !SQLITE_OMIT_AUTOVACUUM |
||
4271 | /* Try to find the next page in the overflow list using the |
||
4272 | ** autovacuum pointer-map pages. Guess that the next page in |
||
4273 | ** the overflow list is page number (ovfl+1). If that guess turns |
||
4274 | ** out to be wrong, fall back to loading the data of page |
||
4275 | ** number ovfl to determine the next page number. |
||
4276 | */ |
||
4277 | if ( pBt.autoVacuum ) |
||
4278 | { |
||
4279 | Pgno pgno = 0; |
||
4280 | Pgno iGuess = ovfl + 1; |
||
4281 | u8 eType = 0; |
||
4282 | |||
4283 | while ( PTRMAP_ISPAGE( pBt, iGuess ) || iGuess == PENDING_BYTE_PAGE( pBt ) ) |
||
4284 | { |
||
4285 | iGuess++; |
||
4286 | } |
||
4287 | |||
4288 | if ( iGuess <= btreePagecount( pBt ) ) |
||
4289 | { |
||
4290 | rc = ptrmapGet( pBt, iGuess, ref eType, ref pgno ); |
||
4291 | if ( rc == SQLITE_OK && eType == PTRMAP_OVERFLOW2 && pgno == ovfl ) |
||
4292 | { |
||
4293 | next = iGuess; |
||
4294 | rc = SQLITE_DONE; |
||
4295 | } |
||
4296 | } |
||
4297 | } |
||
4298 | #endif |
||
4299 | |||
4300 | Debug.Assert( next == 0 || rc == SQLITE_DONE ); |
||
4301 | if ( rc == SQLITE_OK ) |
||
4302 | { |
||
4303 | rc = btreeGetPage( pBt, ovfl, ref pPage, 0 ); |
||
4304 | Debug.Assert( rc == SQLITE_OK || pPage == null ); |
||
4305 | if ( rc == SQLITE_OK ) |
||
4306 | { |
||
4307 | next = sqlite3Get4byte( pPage.aData ); |
||
4308 | } |
||
4309 | } |
||
4310 | |||
4311 | pPgnoNext = next; |
||
4312 | if ( ppPage != null ) |
||
4313 | { |
||
4314 | ppPage = pPage; |
||
4315 | } |
||
4316 | else |
||
4317 | { |
||
4318 | releasePage( pPage ); |
||
4319 | } |
||
4320 | return ( rc == SQLITE_DONE ? SQLITE_OK : rc ); |
||
4321 | } |
||
4322 | |||
4323 | /* |
||
4324 | ** Copy data from a buffer to a page, or from a page to a buffer. |
||
4325 | ** |
||
4326 | ** pPayload is a pointer to data stored on database page pDbPage. |
||
4327 | ** If argument eOp is false, then nByte bytes of data are copied |
||
4328 | ** from pPayload to the buffer pointed at by pBuf. If eOp is true, |
||
4329 | ** then sqlite3PagerWrite() is called on pDbPage and nByte bytes |
||
4330 | ** of data are copied from the buffer pBuf to pPayload. |
||
4331 | ** |
||
4332 | ** SQLITE_OK is returned on success, otherwise an error code. |
||
4333 | */ |
||
4334 | static int copyPayload( |
||
4335 | byte[] pPayload, /* Pointer to page data */ |
||
4336 | u32 payloadOffset, /* Offset into page data */ |
||
4337 | byte[] pBuf, /* Pointer to buffer */ |
||
4338 | u32 pBufOffset, /* Offset into buffer */ |
||
4339 | u32 nByte, /* Number of bytes to copy */ |
||
4340 | int eOp, /* 0 . copy from page, 1 . copy to page */ |
||
4341 | DbPage pDbPage /* Page containing pPayload */ |
||
4342 | ) |
||
4343 | { |
||
4344 | if ( eOp != 0 ) |
||
4345 | { |
||
4346 | /* Copy data from buffer to page (a write operation) */ |
||
4347 | int rc = sqlite3PagerWrite( pDbPage ); |
||
4348 | if ( rc != SQLITE_OK ) |
||
4349 | { |
||
4350 | return rc; |
||
4351 | } |
||
4352 | Buffer.BlockCopy( pBuf, (int)pBufOffset, pPayload, (int)payloadOffset, (int)nByte );// memcpy( pPayload, pBuf, nByte ); |
||
4353 | } |
||
4354 | else |
||
4355 | { |
||
4356 | /* Copy data from page to buffer (a read operation) */ |
||
4357 | Buffer.BlockCopy( pPayload, (int)payloadOffset, pBuf, (int)pBufOffset, (int)nByte );//memcpy(pBuf, pPayload, nByte); |
||
4358 | } |
||
4359 | return SQLITE_OK; |
||
4360 | } |
||
4361 | //static int copyPayload( |
||
4362 | // byte[] pPayload, /* Pointer to page data */ |
||
4363 | // byte[] pBuf, /* Pointer to buffer */ |
||
4364 | // int nByte, /* Number of bytes to copy */ |
||
4365 | // int eOp, /* 0 -> copy from page, 1 -> copy to page */ |
||
4366 | // DbPage pDbPage /* Page containing pPayload */ |
||
4367 | //){ |
||
4368 | // if( eOp!=0 ){ |
||
4369 | // /* Copy data from buffer to page (a write operation) */ |
||
4370 | // int rc = sqlite3PagerWrite(pDbPage); |
||
4371 | // if( rc!=SQLITE_OK ){ |
||
4372 | // return rc; |
||
4373 | // } |
||
4374 | // memcpy(pPayload, pBuf, nByte); |
||
4375 | // }else{ |
||
4376 | // /* Copy data from page to buffer (a read operation) */ |
||
4377 | // memcpy(pBuf, pPayload, nByte); |
||
4378 | // } |
||
4379 | // return SQLITE_OK; |
||
4380 | //} |
||
4381 | |||
4382 | /* |
||
4383 | ** This function is used to read or overwrite payload information |
||
4384 | ** for the entry that the pCur cursor is pointing to. If the eOp |
||
4385 | ** parameter is 0, this is a read operation (data copied into |
||
4386 | ** buffer pBuf). If it is non-zero, a write (data copied from |
||
4387 | ** buffer pBuf). |
||
4388 | ** |
||
4389 | ** A total of "amt" bytes are read or written beginning at "offset". |
||
4390 | ** Data is read to or from the buffer pBuf. |
||
4391 | ** |
||
4392 | ** The content being read or written might appear on the main page |
||
4393 | ** or be scattered out on multiple overflow pages. |
||
4394 | ** |
||
4395 | ** If the BtCursor.isIncrblobHandle flag is set, and the current |
||
4396 | ** cursor entry uses one or more overflow pages, this function |
||
4397 | ** allocates space for and lazily popluates the overflow page-list |
||
4398 | ** cache array (BtCursor.aOverflow). Subsequent calls use this |
||
4399 | ** cache to make seeking to the supplied offset more efficient. |
||
4400 | ** |
||
4401 | ** Once an overflow page-list cache has been allocated, it may be |
||
4402 | ** invalidated if some other cursor writes to the same table, or if |
||
4403 | ** the cursor is moved to a different row. Additionally, in auto-vacuum |
||
4404 | ** mode, the following events may invalidate an overflow page-list cache. |
||
4405 | ** |
||
4406 | ** * An incremental vacuum, |
||
4407 | ** * A commit in auto_vacuum="full" mode, |
||
4408 | ** * Creating a table (may require moving an overflow page). |
||
4409 | */ |
||
4410 | static int accessPayload( |
||
4411 | BtCursor pCur, /* Cursor pointing to entry to read from */ |
||
4412 | u32 offset, /* Begin reading this far into payload */ |
||
4413 | u32 amt, /* Read this many bytes */ |
||
4414 | byte[] pBuf, /* Write the bytes into this buffer */ |
||
4415 | int eOp /* zero to read. non-zero to write. */ |
||
4416 | ) |
||
4417 | { |
||
4418 | u32 pBufOffset = 0; |
||
4419 | byte[] aPayload; |
||
4420 | int rc = SQLITE_OK; |
||
4421 | u32 nKey; |
||
4422 | int iIdx = 0; |
||
4423 | MemPage pPage = pCur.apPage[pCur.iPage]; /* Btree page of current entry */ |
||
4424 | BtShared pBt = pCur.pBt; /* Btree this cursor belongs to */ |
||
4425 | |||
4426 | Debug.Assert( pPage != null ); |
||
4427 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4428 | Debug.Assert( pCur.aiIdx[pCur.iPage] < pPage.nCell ); |
||
4429 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4430 | |||
4431 | getCellInfo( pCur ); |
||
4432 | aPayload = pCur.info.pCell; //pCur.info.pCell + pCur.info.nHeader; |
||
4433 | nKey = (u32)( pPage.intKey != 0 ? 0 : (int)pCur.info.nKey ); |
||
4434 | |||
4435 | if ( NEVER( offset + amt > nKey + pCur.info.nData ) |
||
4436 | || pCur.info.nLocal > pBt.usableSize//&aPayload[pCur.info.nLocal] > &pPage.aData[pBt.usableSize] |
||
4437 | ) |
||
4438 | { |
||
4439 | /* Trying to read or write past the end of the data is an error */ |
||
4440 | return SQLITE_CORRUPT_BKPT(); |
||
4441 | } |
||
4442 | |||
4443 | /* Check if data must be read/written to/from the btree page itself. */ |
||
4444 | if ( offset < pCur.info.nLocal ) |
||
4445 | { |
||
4446 | int a = (int)amt; |
||
4447 | if ( a + offset > pCur.info.nLocal ) |
||
4448 | { |
||
4449 | a = (int)( pCur.info.nLocal - offset ); |
||
4450 | } |
||
4451 | rc = copyPayload( aPayload, (u32)( offset + pCur.info.iCell + pCur.info.nHeader ), pBuf, pBufOffset, (u32)a, eOp, pPage.pDbPage ); |
||
4452 | offset = 0; |
||
4453 | pBufOffset += (u32)a; //pBuf += a; |
||
4454 | amt -= (u32)a; |
||
4455 | } |
||
4456 | else |
||
4457 | { |
||
4458 | offset -= pCur.info.nLocal; |
||
4459 | } |
||
4460 | |||
4461 | if ( rc == SQLITE_OK && amt > 0 ) |
||
4462 | { |
||
4463 | u32 ovflSize = (u32)( pBt.usableSize - 4 ); /* Bytes content per ovfl page */ |
||
4464 | Pgno nextPage; |
||
4465 | |||
4466 | nextPage = sqlite3Get4byte( aPayload, pCur.info.nLocal + pCur.info.iCell + pCur.info.nHeader ); |
||
4467 | |||
4468 | #if !SQLITE_OMIT_INCRBLOB |
||
4469 | /* If the isIncrblobHandle flag is set and the BtCursor.aOverflow[] |
||
4470 | ** has not been allocated, allocate it now. The array is sized at |
||
4471 | ** one entry for each overflow page in the overflow chain. The |
||
4472 | ** page number of the first overflow page is stored in aOverflow[0], |
||
4473 | ** etc. A value of 0 in the aOverflow[] array means "not yet known" |
||
4474 | ** (the cache is lazily populated). |
||
4475 | */ |
||
4476 | if( pCur.isIncrblobHandle && !pCur.aOverflow ){ |
||
4477 | int nOvfl = (pCur.info.nPayload-pCur.info.nLocal+ovflSize-1)/ovflSize; |
||
4478 | pCur.aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); |
||
4479 | /* nOvfl is always positive. If it were zero, fetchPayload would have |
||
4480 | ** been used instead of this routine. */ |
||
4481 | if( ALWAYS(nOvfl) && !pCur.aOverflow ){ |
||
4482 | rc = SQLITE_NOMEM; |
||
4483 | } |
||
4484 | } |
||
4485 | |||
4486 | /* If the overflow page-list cache has been allocated and the |
||
4487 | ** entry for the first required overflow page is valid, skip |
||
4488 | ** directly to it. |
||
4489 | */ |
||
4490 | if( pCur.aOverflow && pCur.aOverflow[offset/ovflSize] ){ |
||
4491 | iIdx = (offset/ovflSize); |
||
4492 | nextPage = pCur.aOverflow[iIdx]; |
||
4493 | offset = (offset%ovflSize); |
||
4494 | } |
||
4495 | #endif |
||
4496 | |||
4497 | for ( ; rc == SQLITE_OK && amt > 0 && nextPage != 0; iIdx++ ) |
||
4498 | { |
||
4499 | |||
4500 | #if !SQLITE_OMIT_INCRBLOB |
||
4501 | /* If required, populate the overflow page-list cache. */ |
||
4502 | if( pCur.aOverflow ){ |
||
4503 | Debug.Assert(!pCur.aOverflow[iIdx] || pCur.aOverflow[iIdx]==nextPage); |
||
4504 | pCur.aOverflow[iIdx] = nextPage; |
||
4505 | } |
||
4506 | #endif |
||
4507 | |||
4508 | MemPage MemPageDummy = null; |
||
4509 | if ( offset >= ovflSize ) |
||
4510 | { |
||
4511 | /* The only reason to read this page is to obtain the page |
||
4512 | ** number for the next page in the overflow chain. The page |
||
4513 | ** data is not required. So first try to lookup the overflow |
||
4514 | ** page-list cache, if any, then fall back to the getOverflowPage() |
||
4515 | ** function. |
||
4516 | */ |
||
4517 | #if !SQLITE_OMIT_INCRBLOB |
||
4518 | if( pCur.aOverflow && pCur.aOverflow[iIdx+1] ){ |
||
4519 | nextPage = pCur.aOverflow[iIdx+1]; |
||
4520 | } else |
||
4521 | #endif |
||
4522 | rc = getOverflowPage( pBt, nextPage, out MemPageDummy, out nextPage ); |
||
4523 | offset -= ovflSize; |
||
4524 | } |
||
4525 | else |
||
4526 | { |
||
4527 | /* Need to read this page properly. It contains some of the |
||
4528 | ** range of data that is being read (eOp==null) or written (eOp!=null). |
||
4529 | */ |
||
4530 | PgHdr pDbPage = new PgHdr(); |
||
4531 | int a = (int)amt; |
||
4532 | rc = sqlite3PagerGet( pBt.pPager, nextPage, ref pDbPage ); |
||
4533 | if ( rc == SQLITE_OK ) |
||
4534 | { |
||
4535 | aPayload = sqlite3PagerGetData( pDbPage ); |
||
4536 | nextPage = sqlite3Get4byte( aPayload ); |
||
4537 | if ( a + offset > ovflSize ) |
||
4538 | { |
||
4539 | a = (int)( ovflSize - offset ); |
||
4540 | } |
||
4541 | rc = copyPayload( aPayload, offset + 4, pBuf, pBufOffset, (u32)a, eOp, pDbPage ); |
||
4542 | sqlite3PagerUnref( pDbPage ); |
||
4543 | offset = 0; |
||
4544 | amt -= (u32)a; |
||
4545 | pBufOffset += (u32)a;//pBuf += a; |
||
4546 | } |
||
4547 | } |
||
4548 | } |
||
4549 | } |
||
4550 | |||
4551 | if ( rc == SQLITE_OK && amt > 0 ) |
||
4552 | { |
||
4553 | return SQLITE_CORRUPT_BKPT(); |
||
4554 | } |
||
4555 | return rc; |
||
4556 | } |
||
4557 | |||
4558 | /* |
||
4559 | ** Read part of the key associated with cursor pCur. Exactly |
||
4560 | ** "amt" bytes will be transfered into pBuf[]. The transfer |
||
4561 | ** begins at "offset". |
||
4562 | ** |
||
4563 | ** The caller must ensure that pCur is pointing to a valid row |
||
4564 | ** in the table. |
||
4565 | ** |
||
4566 | ** Return SQLITE_OK on success or an error code if anything goes |
||
4567 | ** wrong. An error is returned if "offset+amt" is larger than |
||
4568 | ** the available payload. |
||
4569 | */ |
||
4570 | static int sqlite3BtreeKey( BtCursor pCur, u32 offset, u32 amt, byte[] pBuf ) |
||
4571 | { |
||
4572 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4573 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4574 | Debug.Assert( pCur.iPage >= 0 && pCur.apPage[pCur.iPage] != null ); |
||
4575 | Debug.Assert( pCur.aiIdx[pCur.iPage] < pCur.apPage[pCur.iPage].nCell ); |
||
4576 | return accessPayload( pCur, offset, amt, pBuf, 0 ); |
||
4577 | } |
||
4578 | |||
4579 | /* |
||
4580 | ** Read part of the data associated with cursor pCur. Exactly |
||
4581 | ** "amt" bytes will be transfered into pBuf[]. The transfer |
||
4582 | ** begins at "offset". |
||
4583 | ** |
||
4584 | ** Return SQLITE_OK on success or an error code if anything goes |
||
4585 | ** wrong. An error is returned if "offset+amt" is larger than |
||
4586 | ** the available payload. |
||
4587 | */ |
||
4588 | static int sqlite3BtreeData( BtCursor pCur, u32 offset, u32 amt, byte[] pBuf ) |
||
4589 | { |
||
4590 | int rc; |
||
4591 | |||
4592 | #if !SQLITE_OMIT_INCRBLOB |
||
4593 | if ( pCur.eState==CURSOR_INVALID ){ |
||
4594 | return SQLITE_ABORT; |
||
4595 | } |
||
4596 | #endif |
||
4597 | |||
4598 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4599 | rc = restoreCursorPosition( pCur ); |
||
4600 | if ( rc == SQLITE_OK ) |
||
4601 | { |
||
4602 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4603 | Debug.Assert( pCur.iPage >= 0 && pCur.apPage[pCur.iPage] != null ); |
||
4604 | Debug.Assert( pCur.aiIdx[pCur.iPage] < pCur.apPage[pCur.iPage].nCell ); |
||
4605 | rc = accessPayload( pCur, offset, amt, pBuf, 0 ); |
||
4606 | } |
||
4607 | return rc; |
||
4608 | } |
||
4609 | |||
4610 | /* |
||
4611 | ** Return a pointer to payload information from the entry that the |
||
4612 | ** pCur cursor is pointing to. The pointer is to the beginning of |
||
4613 | ** the key if skipKey==null and it points to the beginning of data if |
||
4614 | ** skipKey==1. The number of bytes of available key/data is written |
||
4615 | ** into pAmt. If pAmt==null, then the value returned will not be |
||
4616 | ** a valid pointer. |
||
4617 | ** |
||
4618 | ** This routine is an optimization. It is common for the entire key |
||
4619 | ** and data to fit on the local page and for there to be no overflow |
||
4620 | ** pages. When that is so, this routine can be used to access the |
||
4621 | ** key and data without making a copy. If the key and/or data spills |
||
4622 | ** onto overflow pages, then accessPayload() must be used to reassemble |
||
4623 | ** the key/data and copy it into a preallocated buffer. |
||
4624 | ** |
||
4625 | ** The pointer returned by this routine looks directly into the cached |
||
4626 | ** page of the database. The data might change or move the next time |
||
4627 | ** any btree routine is called. |
||
4628 | */ |
||
4629 | static byte[] fetchPayload( |
||
4630 | BtCursor pCur, /* Cursor pointing to entry to read from */ |
||
4631 | ref int pAmt, /* Write the number of available bytes here */ |
||
4632 | ref int outOffset, /* Offset into Buffer */ |
||
4633 | bool skipKey /* read beginning at data if this is true */ |
||
4634 | ) |
||
4635 | { |
||
4636 | byte[] aPayload; |
||
4637 | MemPage pPage; |
||
4638 | u32 nKey; |
||
4639 | u32 nLocal; |
||
4640 | |||
4641 | Debug.Assert( pCur != null && pCur.iPage >= 0 && pCur.apPage[pCur.iPage] != null ); |
||
4642 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4643 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4644 | outOffset = -1; |
||
4645 | pPage = pCur.apPage[pCur.iPage]; |
||
4646 | Debug.Assert( pCur.aiIdx[pCur.iPage] < pPage.nCell ); |
||
4647 | if ( NEVER( pCur.info.nSize == 0 ) ) |
||
4648 | { |
||
4649 | btreeParseCell( pCur.apPage[pCur.iPage], pCur.aiIdx[pCur.iPage], |
||
4650 | ref pCur.info ); |
||
4651 | } |
||
4652 | //aPayload = pCur.info.pCell; |
||
4653 | //aPayload += pCur.info.nHeader; |
||
4654 | aPayload = sqlite3Malloc( pCur.info.nSize - pCur.info.nHeader ); |
||
4655 | if ( pPage.intKey != 0 ) |
||
4656 | { |
||
4657 | nKey = 0; |
||
4658 | } |
||
4659 | else |
||
4660 | { |
||
4661 | nKey = (u32)pCur.info.nKey; |
||
4662 | } |
||
4663 | if ( skipKey ) |
||
4664 | { |
||
4665 | //aPayload += nKey; |
||
4666 | outOffset = (int)( pCur.info.iCell + pCur.info.nHeader + nKey ); |
||
4667 | Buffer.BlockCopy( pCur.info.pCell, outOffset, aPayload, 0, (int)( pCur.info.nSize - pCur.info.nHeader - nKey ) ); |
||
4668 | nLocal = pCur.info.nLocal - nKey; |
||
4669 | } |
||
4670 | else |
||
4671 | { |
||
4672 | outOffset = (int)( pCur.info.iCell + pCur.info.nHeader ); |
||
4673 | Buffer.BlockCopy( pCur.info.pCell, outOffset, aPayload, 0, pCur.info.nSize - pCur.info.nHeader ); |
||
4674 | nLocal = pCur.info.nLocal; |
||
4675 | Debug.Assert( nLocal <= nKey ); |
||
4676 | } |
||
4677 | pAmt = (int)nLocal; |
||
4678 | return aPayload; |
||
4679 | } |
||
4680 | |||
4681 | /* |
||
4682 | ** For the entry that cursor pCur is point to, return as |
||
4683 | ** many bytes of the key or data as are available on the local |
||
4684 | ** b-tree page. Write the number of available bytes into pAmt. |
||
4685 | ** |
||
4686 | ** The pointer returned is ephemeral. The key/data may move |
||
4687 | ** or be destroyed on the next call to any Btree routine, |
||
4688 | ** including calls from other threads against the same cache. |
||
4689 | ** Hence, a mutex on the BtShared should be held prior to calling |
||
4690 | ** this routine. |
||
4691 | ** |
||
4692 | ** These routines is used to get quick access to key and data |
||
4693 | ** in the common case where no overflow pages are used. |
||
4694 | */ |
||
4695 | static byte[] sqlite3BtreeKeyFetch( BtCursor pCur, ref int pAmt, ref int outOffset ) |
||
4696 | { |
||
4697 | byte[] p = null; |
||
4698 | Debug.Assert( sqlite3_mutex_held( pCur.pBtree.db.mutex ) ); |
||
4699 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4700 | if ( ALWAYS( pCur.eState == CURSOR_VALID ) ) |
||
4701 | { |
||
4702 | p = fetchPayload( pCur, ref pAmt, ref outOffset, false ); |
||
4703 | } |
||
4704 | return p; |
||
4705 | } |
||
4706 | static byte[] sqlite3BtreeDataFetch( BtCursor pCur, ref int pAmt, ref int outOffset ) |
||
4707 | { |
||
4708 | byte[] p = null; |
||
4709 | Debug.Assert( sqlite3_mutex_held( pCur.pBtree.db.mutex ) ); |
||
4710 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4711 | if ( ALWAYS( pCur.eState == CURSOR_VALID ) ) |
||
4712 | { |
||
4713 | p = fetchPayload( pCur, ref pAmt, ref outOffset, true ); |
||
4714 | } |
||
4715 | return p; |
||
4716 | } |
||
4717 | |||
4718 | /* |
||
4719 | ** Move the cursor down to a new child page. The newPgno argument is the |
||
4720 | ** page number of the child page to move to. |
||
4721 | ** |
||
4722 | ** This function returns SQLITE_CORRUPT if the page-header flags field of |
||
4723 | ** the new child page does not match the flags field of the parent (i.e. |
||
4724 | ** if an intkey page appears to be the parent of a non-intkey page, or |
||
4725 | ** vice-versa). |
||
4726 | */ |
||
4727 | static int moveToChild( BtCursor pCur, u32 newPgno ) |
||
4728 | { |
||
4729 | int rc; |
||
4730 | int i = pCur.iPage; |
||
4731 | MemPage pNewPage = new MemPage(); |
||
4732 | BtShared pBt = pCur.pBt; |
||
4733 | |||
4734 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4735 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4736 | Debug.Assert( pCur.iPage < BTCURSOR_MAX_DEPTH ); |
||
4737 | if ( pCur.iPage >= ( BTCURSOR_MAX_DEPTH - 1 ) ) |
||
4738 | { |
||
4739 | return SQLITE_CORRUPT_BKPT(); |
||
4740 | } |
||
4741 | rc = getAndInitPage( pBt, newPgno, ref pNewPage ); |
||
4742 | if ( rc != 0 ) |
||
4743 | return rc; |
||
4744 | pCur.apPage[i + 1] = pNewPage; |
||
4745 | pCur.aiIdx[i + 1] = 0; |
||
4746 | pCur.iPage++; |
||
4747 | |||
4748 | pCur.info.nSize = 0; |
||
4749 | pCur.validNKey = false; |
||
4750 | if ( pNewPage.nCell < 1 || pNewPage.intKey != pCur.apPage[i].intKey ) |
||
4751 | { |
||
4752 | return SQLITE_CORRUPT_BKPT(); |
||
4753 | } |
||
4754 | return SQLITE_OK; |
||
4755 | } |
||
4756 | |||
4757 | #if !NDEBUG |
||
4758 | /* |
||
4759 | ** Page pParent is an internal (non-leaf) tree page. This function |
||
4760 | ** asserts that page number iChild is the left-child if the iIdx'th |
||
4761 | ** cell in page pParent. Or, if iIdx is equal to the total number of |
||
4762 | ** cells in pParent, that page number iChild is the right-child of |
||
4763 | ** the page. |
||
4764 | */ |
||
4765 | static void assertParentIndex( MemPage pParent, int iIdx, Pgno iChild ) |
||
4766 | { |
||
4767 | Debug.Assert( iIdx <= pParent.nCell ); |
||
4768 | if ( iIdx == pParent.nCell ) |
||
4769 | { |
||
4770 | Debug.Assert( sqlite3Get4byte( pParent.aData, pParent.hdrOffset + 8 ) == iChild ); |
||
4771 | } |
||
4772 | else |
||
4773 | { |
||
4774 | Debug.Assert( sqlite3Get4byte( pParent.aData, findCell( pParent, iIdx ) ) == iChild ); |
||
4775 | } |
||
4776 | } |
||
4777 | #else |
||
4778 | //# define assertParentIndex(x,y,z) |
||
4779 | static void assertParentIndex(MemPage pParent, int iIdx, Pgno iChild) { } |
||
4780 | #endif |
||
4781 | |||
4782 | /* |
||
4783 | ** Move the cursor up to the parent page. |
||
4784 | ** |
||
4785 | ** pCur.idx is set to the cell index that contains the pointer |
||
4786 | ** to the page we are coming from. If we are coming from the |
||
4787 | ** right-most child page then pCur.idx is set to one more than |
||
4788 | ** the largest cell index. |
||
4789 | */ |
||
4790 | static void moveToParent( BtCursor pCur ) |
||
4791 | { |
||
4792 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4793 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4794 | Debug.Assert( pCur.iPage > 0 ); |
||
4795 | Debug.Assert( pCur.apPage[pCur.iPage] != null ); |
||
4796 | assertParentIndex( |
||
4797 | pCur.apPage[pCur.iPage - 1], |
||
4798 | pCur.aiIdx[pCur.iPage - 1], |
||
4799 | pCur.apPage[pCur.iPage].pgno |
||
4800 | ); |
||
4801 | releasePage( pCur.apPage[pCur.iPage] ); |
||
4802 | pCur.iPage--; |
||
4803 | pCur.info.nSize = 0; |
||
4804 | pCur.validNKey = false; |
||
4805 | } |
||
4806 | |||
4807 | /* |
||
4808 | ** Move the cursor to point to the root page of its b-tree structure. |
||
4809 | ** |
||
4810 | ** If the table has a virtual root page, then the cursor is moved to point |
||
4811 | ** to the virtual root page instead of the actual root page. A table has a |
||
4812 | ** virtual root page when the actual root page contains no cells and a |
||
4813 | ** single child page. This can only happen with the table rooted at page 1. |
||
4814 | ** |
||
4815 | ** If the b-tree structure is empty, the cursor state is set to |
||
4816 | ** CURSOR_INVALID. Otherwise, the cursor is set to point to the first |
||
4817 | ** cell located on the root (or virtual root) page and the cursor state |
||
4818 | ** is set to CURSOR_VALID. |
||
4819 | ** |
||
4820 | ** If this function returns successfully, it may be assumed that the |
||
4821 | ** page-header flags indicate that the [virtual] root-page is the expected |
||
4822 | ** kind of b-tree page (i.e. if when opening the cursor the caller did not |
||
4823 | ** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D, |
||
4824 | ** indicating a table b-tree, or if the caller did specify a KeyInfo |
||
4825 | ** structure the flags byte is set to 0x02 or 0x0A, indicating an index |
||
4826 | ** b-tree). |
||
4827 | */ |
||
4828 | static int moveToRoot( BtCursor pCur ) |
||
4829 | { |
||
4830 | MemPage pRoot; |
||
4831 | int rc = SQLITE_OK; |
||
4832 | Btree p = pCur.pBtree; |
||
4833 | BtShared pBt = p.pBt; |
||
4834 | |||
4835 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4836 | Debug.Assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); |
||
4837 | Debug.Assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); |
||
4838 | Debug.Assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); |
||
4839 | if ( pCur.eState >= CURSOR_REQUIRESEEK ) |
||
4840 | { |
||
4841 | if ( pCur.eState == CURSOR_FAULT ) |
||
4842 | { |
||
4843 | Debug.Assert( pCur.skipNext != SQLITE_OK ); |
||
4844 | return pCur.skipNext; |
||
4845 | } |
||
4846 | sqlite3BtreeClearCursor( pCur ); |
||
4847 | } |
||
4848 | |||
4849 | if ( pCur.iPage >= 0 ) |
||
4850 | { |
||
4851 | int i; |
||
4852 | for ( i = 1; i <= pCur.iPage; i++ ) |
||
4853 | { |
||
4854 | releasePage( pCur.apPage[i] ); |
||
4855 | } |
||
4856 | pCur.iPage = 0; |
||
4857 | } |
||
4858 | else |
||
4859 | { |
||
4860 | rc = getAndInitPage( pBt, pCur.pgnoRoot, ref pCur.apPage[0] ); |
||
4861 | if ( rc != SQLITE_OK ) |
||
4862 | { |
||
4863 | pCur.eState = CURSOR_INVALID; |
||
4864 | return rc; |
||
4865 | } |
||
4866 | pCur.iPage = 0; |
||
4867 | |||
4868 | /* If pCur.pKeyInfo is not NULL, then the caller that opened this cursor |
||
4869 | ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is |
||
4870 | ** NULL, the caller expects a table b-tree. If this is not the case, |
||
4871 | ** return an SQLITE_CORRUPT error. */ |
||
4872 | Debug.Assert( pCur.apPage[0].intKey == 1 || pCur.apPage[0].intKey == 0 ); |
||
4873 | if ( ( pCur.pKeyInfo == null ) != ( pCur.apPage[0].intKey != 0 ) ) |
||
4874 | { |
||
4875 | return SQLITE_CORRUPT_BKPT(); |
||
4876 | } |
||
4877 | } |
||
4878 | |||
4879 | /* Assert that the root page is of the correct type. This must be the |
||
4880 | ** case as the call to this function that loaded the root-page (either |
||
4881 | ** this call or a previous invocation) would have detected corruption |
||
4882 | ** if the assumption were not true, and it is not possible for the flags |
||
4883 | ** byte to have been modified while this cursor is holding a reference |
||
4884 | ** to the page. */ |
||
4885 | pRoot = pCur.apPage[0]; |
||
4886 | Debug.Assert( pRoot.pgno == pCur.pgnoRoot ); |
||
4887 | Debug.Assert( pRoot.isInit != 0 && ( pCur.pKeyInfo == null ) == ( pRoot.intKey != 0 ) ); |
||
4888 | |||
4889 | pCur.aiIdx[0] = 0; |
||
4890 | pCur.info.nSize = 0; |
||
4891 | pCur.atLast = 0; |
||
4892 | pCur.validNKey = false; |
||
4893 | |||
4894 | if ( pRoot.nCell == 0 && 0 == pRoot.leaf ) |
||
4895 | { |
||
4896 | Pgno subpage; |
||
4897 | if ( pRoot.pgno != 1 ) |
||
4898 | return SQLITE_CORRUPT_BKPT(); |
||
4899 | subpage = sqlite3Get4byte( pRoot.aData, pRoot.hdrOffset + 8 ); |
||
4900 | pCur.eState = CURSOR_VALID; |
||
4901 | rc = moveToChild( pCur, subpage ); |
||
4902 | } |
||
4903 | else |
||
4904 | { |
||
4905 | pCur.eState = ( ( pRoot.nCell > 0 ) ? CURSOR_VALID : CURSOR_INVALID ); |
||
4906 | } |
||
4907 | return rc; |
||
4908 | } |
||
4909 | |||
4910 | /* |
||
4911 | ** Move the cursor down to the left-most leaf entry beneath the |
||
4912 | ** entry to which it is currently pointing. |
||
4913 | ** |
||
4914 | ** The left-most leaf is the one with the smallest key - the first |
||
4915 | ** in ascending order. |
||
4916 | */ |
||
4917 | static int moveToLeftmost( BtCursor pCur ) |
||
4918 | { |
||
4919 | Pgno pgno; |
||
4920 | int rc = SQLITE_OK; |
||
4921 | MemPage pPage; |
||
4922 | |||
4923 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4924 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4925 | while ( rc == SQLITE_OK && 0 == ( pPage = pCur.apPage[pCur.iPage] ).leaf ) |
||
4926 | { |
||
4927 | Debug.Assert( pCur.aiIdx[pCur.iPage] < pPage.nCell ); |
||
4928 | pgno = sqlite3Get4byte( pPage.aData, findCell( pPage, pCur.aiIdx[pCur.iPage] ) ); |
||
4929 | rc = moveToChild( pCur, pgno ); |
||
4930 | } |
||
4931 | return rc; |
||
4932 | } |
||
4933 | |||
4934 | /* |
||
4935 | ** Move the cursor down to the right-most leaf entry beneath the |
||
4936 | ** page to which it is currently pointing. Notice the difference |
||
4937 | ** between moveToLeftmost() and moveToRightmost(). moveToLeftmost() |
||
4938 | ** finds the left-most entry beneath the *entry* whereas moveToRightmost() |
||
4939 | ** finds the right-most entry beneath the page*. |
||
4940 | ** |
||
4941 | ** The right-most entry is the one with the largest key - the last |
||
4942 | ** key in ascending order. |
||
4943 | */ |
||
4944 | static int moveToRightmost( BtCursor pCur ) |
||
4945 | { |
||
4946 | Pgno pgno; |
||
4947 | int rc = SQLITE_OK; |
||
4948 | MemPage pPage = null; |
||
4949 | |||
4950 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4951 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
4952 | while ( rc == SQLITE_OK && 0 == ( pPage = pCur.apPage[pCur.iPage] ).leaf ) |
||
4953 | { |
||
4954 | pgno = sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ); |
||
4955 | pCur.aiIdx[pCur.iPage] = pPage.nCell; |
||
4956 | rc = moveToChild( pCur, pgno ); |
||
4957 | } |
||
4958 | if ( rc == SQLITE_OK ) |
||
4959 | { |
||
4960 | pCur.aiIdx[pCur.iPage] = (u16)( pPage.nCell - 1 ); |
||
4961 | pCur.info.nSize = 0; |
||
4962 | pCur.validNKey = false; |
||
4963 | } |
||
4964 | return rc; |
||
4965 | } |
||
4966 | |||
4967 | /* Move the cursor to the first entry in the table. Return SQLITE_OK |
||
4968 | ** on success. Set pRes to 0 if the cursor actually points to something |
||
4969 | ** or set pRes to 1 if the table is empty. |
||
4970 | */ |
||
4971 | static int sqlite3BtreeFirst( BtCursor pCur, ref int pRes ) |
||
4972 | { |
||
4973 | int rc; |
||
4974 | |||
4975 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
4976 | Debug.Assert( sqlite3_mutex_held( pCur.pBtree.db.mutex ) ); |
||
4977 | rc = moveToRoot( pCur ); |
||
4978 | if ( rc == SQLITE_OK ) |
||
4979 | { |
||
4980 | if ( pCur.eState == CURSOR_INVALID ) |
||
4981 | { |
||
4982 | Debug.Assert( pCur.apPage[pCur.iPage].nCell == 0 ); |
||
4983 | pRes = 1; |
||
4984 | } |
||
4985 | else |
||
4986 | { |
||
4987 | Debug.Assert( pCur.apPage[pCur.iPage].nCell > 0 ); |
||
4988 | pRes = 0; |
||
4989 | rc = moveToLeftmost( pCur ); |
||
4990 | } |
||
4991 | } |
||
4992 | return rc; |
||
4993 | } |
||
4994 | |||
4995 | /* Move the cursor to the last entry in the table. Return SQLITE_OK |
||
4996 | ** on success. Set pRes to 0 if the cursor actually points to something |
||
4997 | ** or set pRes to 1 if the table is empty. |
||
4998 | */ |
||
4999 | static int sqlite3BtreeLast( BtCursor pCur, ref int pRes ) |
||
5000 | { |
||
5001 | int rc; |
||
5002 | |||
5003 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
5004 | Debug.Assert( sqlite3_mutex_held( pCur.pBtree.db.mutex ) ); |
||
5005 | |||
5006 | /* If the cursor already points to the last entry, this is a no-op. */ |
||
5007 | if ( CURSOR_VALID == pCur.eState && pCur.atLast != 0 ) |
||
5008 | { |
||
5009 | #if SQLITE_DEBUG |
||
5010 | /* This block serves to Debug.Assert() that the cursor really does point |
||
5011 | ** to the last entry in the b-tree. */ |
||
5012 | int ii; |
||
5013 | for ( ii = 0; ii < pCur.iPage; ii++ ) |
||
5014 | { |
||
5015 | Debug.Assert( pCur.aiIdx[ii] == pCur.apPage[ii].nCell ); |
||
5016 | } |
||
5017 | Debug.Assert( pCur.aiIdx[pCur.iPage] == pCur.apPage[pCur.iPage].nCell - 1 ); |
||
5018 | Debug.Assert( pCur.apPage[pCur.iPage].leaf != 0 ); |
||
5019 | #endif |
||
5020 | return SQLITE_OK; |
||
5021 | } |
||
5022 | |||
5023 | rc = moveToRoot( pCur ); |
||
5024 | if ( rc == SQLITE_OK ) |
||
5025 | { |
||
5026 | if ( CURSOR_INVALID == pCur.eState ) |
||
5027 | { |
||
5028 | Debug.Assert( pCur.apPage[pCur.iPage].nCell == 0 ); |
||
5029 | pRes = 1; |
||
5030 | } |
||
5031 | else |
||
5032 | { |
||
5033 | Debug.Assert( pCur.eState == CURSOR_VALID ); |
||
5034 | pRes = 0; |
||
5035 | rc = moveToRightmost( pCur ); |
||
5036 | pCur.atLast = (u8)( rc == SQLITE_OK ? 1 : 0 ); |
||
5037 | } |
||
5038 | } |
||
5039 | return rc; |
||
5040 | } |
||
5041 | |||
5042 | /* Move the cursor so that it points to an entry near the key |
||
5043 | ** specified by pIdxKey or intKey. Return a success code. |
||
5044 | ** |
||
5045 | ** For INTKEY tables, the intKey parameter is used. pIdxKey |
||
5046 | ** must be NULL. For index tables, pIdxKey is used and intKey |
||
5047 | ** is ignored. |
||
5048 | ** |
||
5049 | ** If an exact match is not found, then the cursor is always |
||
5050 | ** left pointing at a leaf page which would hold the entry if it |
||
5051 | ** were present. The cursor might point to an entry that comes |
||
5052 | ** before or after the key. |
||
5053 | ** |
||
5054 | ** An integer is written into pRes which is the result of |
||
5055 | ** comparing the key with the entry to which the cursor is |
||
5056 | ** pointing. The meaning of the integer written into |
||
5057 | ** pRes is as follows: |
||
5058 | ** |
||
5059 | ** pRes<0 The cursor is left pointing at an entry that |
||
5060 | ** is smaller than intKey/pIdxKey or if the table is empty |
||
5061 | ** and the cursor is therefore left point to nothing. |
||
5062 | ** |
||
5063 | ** pRes==null The cursor is left pointing at an entry that |
||
5064 | ** exactly matches intKey/pIdxKey. |
||
5065 | ** |
||
5066 | ** pRes>0 The cursor is left pointing at an entry that |
||
5067 | ** is larger than intKey/pIdxKey. |
||
5068 | ** |
||
5069 | */ |
||
5070 | static int sqlite3BtreeMovetoUnpacked( |
||
5071 | BtCursor pCur, /* The cursor to be moved */ |
||
5072 | UnpackedRecord pIdxKey, /* Unpacked index key */ |
||
5073 | i64 intKey, /* The table key */ |
||
5074 | int biasRight, /* If true, bias the search to the high end */ |
||
5075 | ref int pRes /* Write search results here */ |
||
5076 | ) |
||
5077 | { |
||
5078 | int rc; |
||
5079 | |||
5080 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
5081 | Debug.Assert( sqlite3_mutex_held( pCur.pBtree.db.mutex ) ); |
||
5082 | // Not needed in C# // Debug.Assert( pRes != 0 ); |
||
5083 | Debug.Assert( ( pIdxKey == null ) == ( pCur.pKeyInfo == null ) ); |
||
5084 | |||
5085 | /* If the cursor is already positioned at the point we are trying |
||
5086 | ** to move to, then just return without doing any work */ |
||
5087 | if ( pCur.eState == CURSOR_VALID && pCur.validNKey |
||
5088 | && pCur.apPage[0].intKey != 0 |
||
5089 | ) |
||
5090 | { |
||
5091 | if ( pCur.info.nKey == intKey ) |
||
5092 | { |
||
5093 | pRes = 0; |
||
5094 | return SQLITE_OK; |
||
5095 | } |
||
5096 | if ( pCur.atLast != 0 && pCur.info.nKey < intKey ) |
||
5097 | { |
||
5098 | pRes = -1; |
||
5099 | return SQLITE_OK; |
||
5100 | } |
||
5101 | } |
||
5102 | |||
5103 | rc = moveToRoot( pCur ); |
||
5104 | if ( rc != 0 ) |
||
5105 | { |
||
5106 | return rc; |
||
5107 | } |
||
5108 | Debug.Assert( pCur.apPage[pCur.iPage] != null ); |
||
5109 | Debug.Assert( pCur.apPage[pCur.iPage].isInit != 0 ); |
||
5110 | Debug.Assert( pCur.apPage[pCur.iPage].nCell > 0 || pCur.eState == CURSOR_INVALID ); |
||
5111 | if ( pCur.eState == CURSOR_INVALID ) |
||
5112 | { |
||
5113 | pRes = -1; |
||
5114 | Debug.Assert( pCur.apPage[pCur.iPage].nCell == 0 ); |
||
5115 | return SQLITE_OK; |
||
5116 | } |
||
5117 | Debug.Assert( pCur.apPage[0].intKey != 0 || pIdxKey != null ); |
||
5118 | for ( ; ; ) |
||
5119 | { |
||
5120 | int lwr, upr, idx; |
||
5121 | Pgno chldPg; |
||
5122 | MemPage pPage = pCur.apPage[pCur.iPage]; |
||
5123 | int c; |
||
5124 | |||
5125 | /* pPage.nCell must be greater than zero. If this is the root-page |
||
5126 | ** the cursor would have been INVALID above and this for(;;) loop |
||
5127 | ** not run. If this is not the root-page, then the moveToChild() routine |
||
5128 | ** would have already detected db corruption. Similarly, pPage must |
||
5129 | ** be the right kind (index or table) of b-tree page. Otherwise |
||
5130 | ** a moveToChild() or moveToRoot() call would have detected corruption. */ |
||
5131 | Debug.Assert( pPage.nCell > 0 ); |
||
5132 | Debug.Assert( pPage.intKey == ( ( pIdxKey == null ) ? 1 : 0 ) ); |
||
5133 | lwr = 0; |
||
5134 | upr = pPage.nCell - 1; |
||
5135 | if ( biasRight != 0 ) |
||
5136 | { |
||
5137 | pCur.aiIdx[pCur.iPage] = (u16)( idx = upr ); |
||
5138 | } |
||
5139 | else |
||
5140 | { |
||
5141 | pCur.aiIdx[pCur.iPage] = (u16)( idx = ( upr + lwr ) / 2 ); |
||
5142 | } |
||
5143 | for ( ; ; ) |
||
5144 | { |
||
5145 | int pCell; /* Pointer to current cell in pPage */ |
||
5146 | |||
5147 | Debug.Assert( idx == pCur.aiIdx[pCur.iPage] ); |
||
5148 | pCur.info.nSize = 0; |
||
5149 | pCell = findCell( pPage, idx ) + pPage.childPtrSize; |
||
5150 | if ( pPage.intKey != 0 ) |
||
5151 | { |
||
5152 | i64 nCellKey = 0; |
||
5153 | if ( pPage.hasData != 0 ) |
||
5154 | { |
||
5155 | u32 Dummy0 = 0; |
||
5156 | pCell += getVarint32( pPage.aData, pCell, out Dummy0 ); |
||
5157 | } |
||
5158 | getVarint( pPage.aData, pCell, out nCellKey ); |
||
5159 | if ( nCellKey == intKey ) |
||
5160 | { |
||
5161 | c = 0; |
||
5162 | } |
||
5163 | else if ( nCellKey < intKey ) |
||
5164 | { |
||
5165 | c = -1; |
||
5166 | } |
||
5167 | else |
||
5168 | { |
||
5169 | Debug.Assert( nCellKey > intKey ); |
||
5170 | c = +1; |
||
5171 | } |
||
5172 | pCur.validNKey = true; |
||
5173 | pCur.info.nKey = nCellKey; |
||
5174 | } |
||
5175 | else |
||
5176 | { |
||
5177 | /* The maximum supported page-size is 65536 bytes. This means that |
||
5178 | ** the maximum number of record bytes stored on an index B-Tree |
||
5179 | ** page is less than 16384 bytes and may be stored as a 2-byte |
||
5180 | ** varint. This information is used to attempt to avoid parsing |
||
5181 | ** the entire cell by checking for the cases where the record is |
||
5182 | ** stored entirely within the b-tree page by inspecting the first |
||
5183 | ** 2 bytes of the cell. |
||
5184 | */ |
||
5185 | int nCell = pPage.aData[pCell + 0]; //pCell[0]; |
||
5186 | if ( 0 == ( nCell & 0x80 ) && nCell <= pPage.maxLocal ) |
||
5187 | { |
||
5188 | /* This branch runs if the record-size field of the cell is a |
||
5189 | ** single byte varint and the record fits entirely on the main |
||
5190 | ** b-tree page. */ |
||
5191 | c = sqlite3VdbeRecordCompare( nCell, pPage.aData, pCell + 1, pIdxKey ); //c = sqlite3VdbeRecordCompare( nCell, (void*)&pCell[1], pIdxKey ); |
||
5192 | } |
||
5193 | else if ( 0 == ( pPage.aData[pCell + 1] & 0x80 )//!(pCell[1] & 0x80) |
||
5194 | && ( nCell = ( ( nCell & 0x7f ) << 7 ) + pPage.aData[pCell + 1] ) <= pPage.maxLocal//pCell[1])<=pPage.maxLocal |
||
5195 | ) |
||
5196 | { |
||
5197 | /* The record-size field is a 2 byte varint and the record |
||
5198 | ** fits entirely on the main b-tree page. */ |
||
5199 | c = sqlite3VdbeRecordCompare( nCell, pPage.aData, pCell + 2, pIdxKey ); //c = sqlite3VdbeRecordCompare( nCell, (void*)&pCell[2], pIdxKey ); |
||
5200 | } |
||
5201 | else |
||
5202 | { |
||
5203 | /* The record flows over onto one or more overflow pages. In |
||
5204 | ** this case the whole cell needs to be parsed, a buffer allocated |
||
5205 | ** and accessPayload() used to retrieve the record into the |
||
5206 | ** buffer before VdbeRecordCompare() can be called. */ |
||
5207 | u8[] pCellKey; |
||
5208 | u8[] pCellBody = new u8[pPage.aData.Length - pCell + pPage.childPtrSize]; |
||
5209 | Buffer.BlockCopy( pPage.aData, pCell - pPage.childPtrSize, pCellBody, 0, pCellBody.Length );// u8 * const pCellBody = pCell - pPage->childPtrSize; |
||
5210 | btreeParseCellPtr( pPage, pCellBody, ref pCur.info ); |
||
5211 | nCell = (int)pCur.info.nKey; |
||
5212 | pCellKey = sqlite3Malloc( nCell ); |
||
5213 | //if ( pCellKey == null ) |
||
5214 | //{ |
||
5215 | // rc = SQLITE_NOMEM; |
||
5216 | // goto moveto_finish; |
||
5217 | //} |
||
5218 | rc = accessPayload( pCur, 0, (u32)nCell, pCellKey, 0 ); |
||
5219 | if ( rc != 0 ) |
||
5220 | { |
||
5221 | pCellKey = null;// sqlite3_free(ref pCellKey ); |
||
5222 | goto moveto_finish; |
||
5223 | } |
||
5224 | c = sqlite3VdbeRecordCompare( nCell, pCellKey, pIdxKey ); |
||
5225 | pCellKey = null;// sqlite3_free(ref pCellKey ); |
||
5226 | } |
||
5227 | } |
||
5228 | if ( c == 0 ) |
||
5229 | { |
||
5230 | if ( pPage.intKey != 0 && 0 == pPage.leaf ) |
||
5231 | { |
||
5232 | lwr = idx; |
||
5233 | upr = lwr - 1; |
||
5234 | break; |
||
5235 | } |
||
5236 | else |
||
5237 | { |
||
5238 | pRes = 0; |
||
5239 | rc = SQLITE_OK; |
||
5240 | goto moveto_finish; |
||
5241 | } |
||
5242 | } |
||
5243 | if ( c < 0 ) |
||
5244 | { |
||
5245 | lwr = idx + 1; |
||
5246 | } |
||
5247 | else |
||
5248 | { |
||
5249 | upr = idx - 1; |
||
5250 | } |
||
5251 | if ( lwr > upr ) |
||
5252 | { |
||
5253 | break; |
||
5254 | } |
||
5255 | pCur.aiIdx[pCur.iPage] = (u16)( idx = ( lwr + upr ) / 2 ); |
||
5256 | } |
||
5257 | Debug.Assert( lwr == upr + 1 ); |
||
5258 | Debug.Assert( pPage.isInit != 0 ); |
||
5259 | if ( pPage.leaf != 0 ) |
||
5260 | { |
||
5261 | chldPg = 0; |
||
5262 | } |
||
5263 | else if ( lwr >= pPage.nCell ) |
||
5264 | { |
||
5265 | chldPg = sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ); |
||
5266 | } |
||
5267 | else |
||
5268 | { |
||
5269 | chldPg = sqlite3Get4byte( pPage.aData, findCell( pPage, lwr ) ); |
||
5270 | } |
||
5271 | if ( chldPg == 0 ) |
||
5272 | { |
||
5273 | Debug.Assert( pCur.aiIdx[pCur.iPage] < pCur.apPage[pCur.iPage].nCell ); |
||
5274 | pRes = c; |
||
5275 | rc = SQLITE_OK; |
||
5276 | goto moveto_finish; |
||
5277 | } |
||
5278 | pCur.aiIdx[pCur.iPage] = (u16)lwr; |
||
5279 | pCur.info.nSize = 0; |
||
5280 | pCur.validNKey = false; |
||
5281 | rc = moveToChild( pCur, chldPg ); |
||
5282 | if ( rc != 0 ) |
||
5283 | goto moveto_finish; |
||
5284 | } |
||
5285 | moveto_finish: |
||
5286 | return rc; |
||
5287 | } |
||
5288 | |||
5289 | |||
5290 | /* |
||
5291 | ** Return TRUE if the cursor is not pointing at an entry of the table. |
||
5292 | ** |
||
5293 | ** TRUE will be returned after a call to sqlite3BtreeNext() moves |
||
5294 | ** past the last entry in the table or sqlite3BtreePrev() moves past |
||
5295 | ** the first entry. TRUE is also returned if the table is empty. |
||
5296 | */ |
||
5297 | static bool sqlite3BtreeEof( BtCursor pCur ) |
||
5298 | { |
||
5299 | /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries |
||
5300 | ** have been deleted? This API will need to change to return an error code |
||
5301 | ** as well as the boolean result value. |
||
5302 | */ |
||
5303 | return ( CURSOR_VALID != pCur.eState ); |
||
5304 | } |
||
5305 | |||
5306 | /* |
||
5307 | ** Advance the cursor to the next entry in the database. If |
||
5308 | ** successful then set pRes=0. If the cursor |
||
5309 | ** was already pointing to the last entry in the database before |
||
5310 | ** this routine was called, then set pRes=1. |
||
5311 | */ |
||
5312 | static int sqlite3BtreeNext( BtCursor pCur, ref int pRes ) |
||
5313 | { |
||
5314 | int rc; |
||
5315 | int idx; |
||
5316 | MemPage pPage; |
||
5317 | |||
5318 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
5319 | rc = restoreCursorPosition( pCur ); |
||
5320 | if ( rc != SQLITE_OK ) |
||
5321 | { |
||
5322 | return rc; |
||
5323 | } |
||
5324 | // Not needed in C# // Debug.Assert( pRes != 0 ); |
||
5325 | if ( CURSOR_INVALID == pCur.eState ) |
||
5326 | { |
||
5327 | pRes = 1; |
||
5328 | return SQLITE_OK; |
||
5329 | } |
||
5330 | if ( pCur.skipNext > 0 ) |
||
5331 | { |
||
5332 | pCur.skipNext = 0; |
||
5333 | pRes = 0; |
||
5334 | return SQLITE_OK; |
||
5335 | } |
||
5336 | pCur.skipNext = 0; |
||
5337 | |||
5338 | pPage = pCur.apPage[pCur.iPage]; |
||
5339 | idx = ++pCur.aiIdx[pCur.iPage]; |
||
5340 | Debug.Assert( pPage.isInit != 0 ); |
||
5341 | Debug.Assert( idx <= pPage.nCell ); |
||
5342 | |||
5343 | pCur.info.nSize = 0; |
||
5344 | pCur.validNKey = false; |
||
5345 | if ( idx >= pPage.nCell ) |
||
5346 | { |
||
5347 | if ( 0 == pPage.leaf ) |
||
5348 | { |
||
5349 | rc = moveToChild( pCur, sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ) ); |
||
5350 | if ( rc != 0 ) |
||
5351 | return rc; |
||
5352 | rc = moveToLeftmost( pCur ); |
||
5353 | pRes = 0; |
||
5354 | return rc; |
||
5355 | } |
||
5356 | do |
||
5357 | { |
||
5358 | if ( pCur.iPage == 0 ) |
||
5359 | { |
||
5360 | pRes = 1; |
||
5361 | pCur.eState = CURSOR_INVALID; |
||
5362 | return SQLITE_OK; |
||
5363 | } |
||
5364 | moveToParent( pCur ); |
||
5365 | pPage = pCur.apPage[pCur.iPage]; |
||
5366 | } while ( pCur.aiIdx[pCur.iPage] >= pPage.nCell ); |
||
5367 | pRes = 0; |
||
5368 | if ( pPage.intKey != 0 ) |
||
5369 | { |
||
5370 | rc = sqlite3BtreeNext( pCur, ref pRes ); |
||
5371 | } |
||
5372 | else |
||
5373 | { |
||
5374 | rc = SQLITE_OK; |
||
5375 | } |
||
5376 | return rc; |
||
5377 | } |
||
5378 | pRes = 0; |
||
5379 | if ( pPage.leaf != 0 ) |
||
5380 | { |
||
5381 | return SQLITE_OK; |
||
5382 | } |
||
5383 | rc = moveToLeftmost( pCur ); |
||
5384 | return rc; |
||
5385 | } |
||
5386 | |||
5387 | |||
5388 | /* |
||
5389 | ** Step the cursor to the back to the previous entry in the database. If |
||
5390 | ** successful then set pRes=0. If the cursor |
||
5391 | ** was already pointing to the first entry in the database before |
||
5392 | ** this routine was called, then set pRes=1. |
||
5393 | */ |
||
5394 | static int sqlite3BtreePrevious( BtCursor pCur, ref int pRes ) |
||
5395 | { |
||
5396 | int rc; |
||
5397 | MemPage pPage; |
||
5398 | |||
5399 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
5400 | rc = restoreCursorPosition( pCur ); |
||
5401 | if ( rc != SQLITE_OK ) |
||
5402 | { |
||
5403 | return rc; |
||
5404 | } |
||
5405 | pCur.atLast = 0; |
||
5406 | if ( CURSOR_INVALID == pCur.eState ) |
||
5407 | { |
||
5408 | pRes = 1; |
||
5409 | return SQLITE_OK; |
||
5410 | } |
||
5411 | if ( pCur.skipNext < 0 ) |
||
5412 | { |
||
5413 | pCur.skipNext = 0; |
||
5414 | pRes = 0; |
||
5415 | return SQLITE_OK; |
||
5416 | } |
||
5417 | pCur.skipNext = 0; |
||
5418 | |||
5419 | pPage = pCur.apPage[pCur.iPage]; |
||
5420 | Debug.Assert( pPage.isInit != 0 ); |
||
5421 | if ( 0 == pPage.leaf ) |
||
5422 | { |
||
5423 | int idx = pCur.aiIdx[pCur.iPage]; |
||
5424 | rc = moveToChild( pCur, sqlite3Get4byte( pPage.aData, findCell( pPage, idx ) ) ); |
||
5425 | if ( rc != 0 ) |
||
5426 | { |
||
5427 | return rc; |
||
5428 | } |
||
5429 | rc = moveToRightmost( pCur ); |
||
5430 | } |
||
5431 | else |
||
5432 | { |
||
5433 | while ( pCur.aiIdx[pCur.iPage] == 0 ) |
||
5434 | { |
||
5435 | if ( pCur.iPage == 0 ) |
||
5436 | { |
||
5437 | pCur.eState = CURSOR_INVALID; |
||
5438 | pRes = 1; |
||
5439 | return SQLITE_OK; |
||
5440 | } |
||
5441 | moveToParent( pCur ); |
||
5442 | } |
||
5443 | pCur.info.nSize = 0; |
||
5444 | pCur.validNKey = false; |
||
5445 | |||
5446 | pCur.aiIdx[pCur.iPage]--; |
||
5447 | pPage = pCur.apPage[pCur.iPage]; |
||
5448 | if ( pPage.intKey != 0 && 0 == pPage.leaf ) |
||
5449 | { |
||
5450 | rc = sqlite3BtreePrevious( pCur, ref pRes ); |
||
5451 | } |
||
5452 | else |
||
5453 | { |
||
5454 | rc = SQLITE_OK; |
||
5455 | } |
||
5456 | } |
||
5457 | pRes = 0; |
||
5458 | return rc; |
||
5459 | } |
||
5460 | |||
5461 | /* |
||
5462 | ** Allocate a new page from the database file. |
||
5463 | ** |
||
5464 | ** The new page is marked as dirty. (In other words, sqlite3PagerWrite() |
||
5465 | ** has already been called on the new page.) The new page has also |
||
5466 | ** been referenced and the calling routine is responsible for calling |
||
5467 | ** sqlite3PagerUnref() on the new page when it is done. |
||
5468 | ** |
||
5469 | ** SQLITE_OK is returned on success. Any other return value indicates |
||
5470 | ** an error. ppPage and pPgno are undefined in the event of an error. |
||
5471 | ** Do not invoke sqlite3PagerUnref() on ppPage if an error is returned. |
||
5472 | ** |
||
5473 | ** If the "nearby" parameter is not 0, then a (feeble) effort is made to |
||
5474 | ** locate a page close to the page number "nearby". This can be used in an |
||
5475 | ** attempt to keep related pages close to each other in the database file, |
||
5476 | ** which in turn can make database access faster. |
||
5477 | ** |
||
5478 | ** If the "exact" parameter is not 0, and the page-number nearby exists |
||
5479 | ** anywhere on the free-list, then it is guarenteed to be returned. This |
||
5480 | ** is only used by auto-vacuum databases when allocating a new table. |
||
5481 | */ |
||
5482 | static int allocateBtreePage( |
||
5483 | BtShared pBt, |
||
5484 | ref MemPage ppPage, |
||
5485 | ref Pgno pPgno, |
||
5486 | Pgno nearby, |
||
5487 | u8 exact |
||
5488 | ) |
||
5489 | { |
||
5490 | MemPage pPage1; |
||
5491 | int rc; |
||
5492 | u32 n; /* Number of pages on the freelist */ |
||
5493 | u32 k; /* Number of leaves on the trunk of the freelist */ |
||
5494 | MemPage pTrunk = null; |
||
5495 | MemPage pPrevTrunk = null; |
||
5496 | Pgno mxPage; /* Total size of the database file */ |
||
5497 | |||
5498 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
5499 | pPage1 = pBt.pPage1; |
||
5500 | mxPage = btreePagecount( pBt ); |
||
5501 | n = sqlite3Get4byte( pPage1.aData, 36 ); |
||
5502 | testcase( n == mxPage - 1 ); |
||
5503 | if ( n >= mxPage ) |
||
5504 | { |
||
5505 | return SQLITE_CORRUPT_BKPT(); |
||
5506 | } |
||
5507 | if ( n > 0 ) |
||
5508 | { |
||
5509 | /* There are pages on the freelist. Reuse one of those pages. */ |
||
5510 | Pgno iTrunk; |
||
5511 | u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ |
||
5512 | |||
5513 | /* If the 'exact' parameter was true and a query of the pointer-map |
||
5514 | ** shows that the page 'nearby' is somewhere on the free-list, then |
||
5515 | ** the entire-list will be searched for that page. |
||
5516 | */ |
||
5517 | #if !SQLITE_OMIT_AUTOVACUUM |
||
5518 | if ( exact != 0 && nearby <= mxPage ) |
||
5519 | { |
||
5520 | u8 eType = 0; |
||
5521 | Debug.Assert( nearby > 0 ); |
||
5522 | Debug.Assert( pBt.autoVacuum ); |
||
5523 | u32 Dummy0 = 0; |
||
5524 | rc = ptrmapGet( pBt, nearby, ref eType, ref Dummy0 ); |
||
5525 | if ( rc != 0 ) |
||
5526 | return rc; |
||
5527 | if ( eType == PTRMAP_FREEPAGE ) |
||
5528 | { |
||
5529 | searchList = 1; |
||
5530 | } |
||
5531 | pPgno = nearby; |
||
5532 | } |
||
5533 | #endif |
||
5534 | |||
5535 | /* Decrement the free-list count by 1. Set iTrunk to the index of the |
||
5536 | ** first free-list trunk page. iPrevTrunk is initially 1. |
||
5537 | */ |
||
5538 | rc = sqlite3PagerWrite( pPage1.pDbPage ); |
||
5539 | if ( rc != 0 ) |
||
5540 | return rc; |
||
5541 | sqlite3Put4byte( pPage1.aData, (u32)36, n - 1 ); |
||
5542 | |||
5543 | /* The code within this loop is run only once if the 'searchList' variable |
||
5544 | ** is not true. Otherwise, it runs once for each trunk-page on the |
||
5545 | ** free-list until the page 'nearby' is located. |
||
5546 | */ |
||
5547 | do |
||
5548 | { |
||
5549 | pPrevTrunk = pTrunk; |
||
5550 | if ( pPrevTrunk != null ) |
||
5551 | { |
||
5552 | iTrunk = sqlite3Get4byte( pPrevTrunk.aData, 0 ); |
||
5553 | } |
||
5554 | else |
||
5555 | { |
||
5556 | iTrunk = sqlite3Get4byte( pPage1.aData, 32 ); |
||
5557 | } |
||
5558 | testcase( iTrunk == mxPage ); |
||
5559 | if ( iTrunk > mxPage ) |
||
5560 | { |
||
5561 | rc = SQLITE_CORRUPT_BKPT(); |
||
5562 | } |
||
5563 | else |
||
5564 | { |
||
5565 | rc = btreeGetPage( pBt, iTrunk, ref pTrunk, 0 ); |
||
5566 | } |
||
5567 | if ( rc != 0 ) |
||
5568 | { |
||
5569 | pTrunk = null; |
||
5570 | goto end_allocate_page; |
||
5571 | } |
||
5572 | |||
5573 | k = sqlite3Get4byte( pTrunk.aData, 4 ); /* # of leaves on this trunk page */ |
||
5574 | if ( k == 0 && 0 == searchList ) |
||
5575 | { |
||
5576 | /* The trunk has no leaves and the list is not being searched. |
||
5577 | ** So extract the trunk page itself and use it as the newly |
||
5578 | ** allocated page */ |
||
5579 | Debug.Assert( pPrevTrunk == null ); |
||
5580 | rc = sqlite3PagerWrite( pTrunk.pDbPage ); |
||
5581 | if ( rc != 0 ) |
||
5582 | { |
||
5583 | goto end_allocate_page; |
||
5584 | } |
||
5585 | pPgno = iTrunk; |
||
5586 | Buffer.BlockCopy( pTrunk.aData, 0, pPage1.aData, 32, 4 );//memcpy( pPage1.aData[32], ref pTrunk.aData[0], 4 ); |
||
5587 | ppPage = pTrunk; |
||
5588 | pTrunk = null; |
||
5589 | TRACE( "ALLOCATE: %d trunk - %d free pages left\n", pPgno, n - 1 ); |
||
5590 | } |
||
5591 | else if ( k > (u32)( pBt.usableSize / 4 - 2 ) ) |
||
5592 | { |
||
5593 | /* Value of k is out of range. Database corruption */ |
||
5594 | rc = SQLITE_CORRUPT_BKPT(); |
||
5595 | goto end_allocate_page; |
||
5596 | #if !SQLITE_OMIT_AUTOVACUUM |
||
5597 | } |
||
5598 | else if ( searchList != 0 && nearby == iTrunk ) |
||
5599 | { |
||
5600 | /* The list is being searched and this trunk page is the page |
||
5601 | ** to allocate, regardless of whether it has leaves. |
||
5602 | */ |
||
5603 | Debug.Assert( pPgno == iTrunk ); |
||
5604 | ppPage = pTrunk; |
||
5605 | searchList = 0; |
||
5606 | rc = sqlite3PagerWrite( pTrunk.pDbPage ); |
||
5607 | if ( rc != 0 ) |
||
5608 | { |
||
5609 | goto end_allocate_page; |
||
5610 | } |
||
5611 | if ( k == 0 ) |
||
5612 | { |
||
5613 | if ( null == pPrevTrunk ) |
||
5614 | { |
||
5615 | //memcpy(pPage1.aData[32], pTrunk.aData[0], 4); |
||
5616 | pPage1.aData[32 + 0] = pTrunk.aData[0 + 0]; |
||
5617 | pPage1.aData[32 + 1] = pTrunk.aData[0 + 1]; |
||
5618 | pPage1.aData[32 + 2] = pTrunk.aData[0 + 2]; |
||
5619 | pPage1.aData[32 + 3] = pTrunk.aData[0 + 3]; |
||
5620 | } |
||
5621 | else |
||
5622 | { |
||
5623 | rc = sqlite3PagerWrite( pPrevTrunk.pDbPage ); |
||
5624 | if ( rc != SQLITE_OK ) |
||
5625 | { |
||
5626 | goto end_allocate_page; |
||
5627 | } |
||
5628 | //memcpy(pPrevTrunk.aData[0], pTrunk.aData[0], 4); |
||
5629 | pPrevTrunk.aData[0 + 0] = pTrunk.aData[0 + 0]; |
||
5630 | pPrevTrunk.aData[0 + 1] = pTrunk.aData[0 + 1]; |
||
5631 | pPrevTrunk.aData[0 + 2] = pTrunk.aData[0 + 2]; |
||
5632 | pPrevTrunk.aData[0 + 3] = pTrunk.aData[0 + 3]; |
||
5633 | } |
||
5634 | } |
||
5635 | else |
||
5636 | { |
||
5637 | /* The trunk page is required by the caller but it contains |
||
5638 | ** pointers to free-list leaves. The first leaf becomes a trunk |
||
5639 | ** page in this case. |
||
5640 | */ |
||
5641 | MemPage pNewTrunk = new MemPage(); |
||
5642 | Pgno iNewTrunk = sqlite3Get4byte( pTrunk.aData, 8 ); |
||
5643 | if ( iNewTrunk > mxPage ) |
||
5644 | { |
||
5645 | rc = SQLITE_CORRUPT_BKPT(); |
||
5646 | goto end_allocate_page; |
||
5647 | } |
||
5648 | testcase( iNewTrunk == mxPage ); |
||
5649 | rc = btreeGetPage( pBt, iNewTrunk, ref pNewTrunk, 0 ); |
||
5650 | if ( rc != SQLITE_OK ) |
||
5651 | { |
||
5652 | goto end_allocate_page; |
||
5653 | } |
||
5654 | rc = sqlite3PagerWrite( pNewTrunk.pDbPage ); |
||
5655 | if ( rc != SQLITE_OK ) |
||
5656 | { |
||
5657 | releasePage( pNewTrunk ); |
||
5658 | goto end_allocate_page; |
||
5659 | } |
||
5660 | //memcpy(pNewTrunk.aData[0], pTrunk.aData[0], 4); |
||
5661 | pNewTrunk.aData[0 + 0] = pTrunk.aData[0 + 0]; |
||
5662 | pNewTrunk.aData[0 + 1] = pTrunk.aData[0 + 1]; |
||
5663 | pNewTrunk.aData[0 + 2] = pTrunk.aData[0 + 2]; |
||
5664 | pNewTrunk.aData[0 + 3] = pTrunk.aData[0 + 3]; |
||
5665 | sqlite3Put4byte( pNewTrunk.aData, (u32)4, (u32)( k - 1 ) ); |
||
5666 | Buffer.BlockCopy( pTrunk.aData, 12, pNewTrunk.aData, 8, (int)( k - 1 ) * 4 );//memcpy( pNewTrunk.aData[8], ref pTrunk.aData[12], ( k - 1 ) * 4 ); |
||
5667 | releasePage( pNewTrunk ); |
||
5668 | if ( null == pPrevTrunk ) |
||
5669 | { |
||
5670 | Debug.Assert( sqlite3PagerIswriteable( pPage1.pDbPage ) ); |
||
5671 | sqlite3Put4byte( pPage1.aData, (u32)32, iNewTrunk ); |
||
5672 | } |
||
5673 | else |
||
5674 | { |
||
5675 | rc = sqlite3PagerWrite( pPrevTrunk.pDbPage ); |
||
5676 | if ( rc != 0 ) |
||
5677 | { |
||
5678 | goto end_allocate_page; |
||
5679 | } |
||
5680 | sqlite3Put4byte( pPrevTrunk.aData, (u32)0, iNewTrunk ); |
||
5681 | } |
||
5682 | } |
||
5683 | pTrunk = null; |
||
5684 | TRACE( "ALLOCATE: %d trunk - %d free pages left\n", pPgno, n - 1 ); |
||
5685 | #endif |
||
5686 | } |
||
5687 | else if ( k > 0 ) |
||
5688 | { |
||
5689 | /* Extract a leaf from the trunk */ |
||
5690 | u32 closest; |
||
5691 | Pgno iPage; |
||
5692 | byte[] aData = pTrunk.aData; |
||
5693 | if ( nearby > 0 ) |
||
5694 | { |
||
5695 | u32 i; |
||
5696 | int dist; |
||
5697 | closest = 0; |
||
5698 | dist = sqlite3AbsInt32( (int)(sqlite3Get4byte( aData, 8 ) - nearby )); |
||
5699 | for ( i = 1; i < k; i++ ) |
||
5700 | { |
||
5701 | int d2 = sqlite3AbsInt32( (int)(sqlite3Get4byte( aData, 8 + i * 4 ) - nearby )); |
||
5702 | if ( d2 < dist ) |
||
5703 | { |
||
5704 | closest = i; |
||
5705 | dist = d2; |
||
5706 | } |
||
5707 | } |
||
5708 | } |
||
5709 | else |
||
5710 | { |
||
5711 | closest = 0; |
||
5712 | } |
||
5713 | |||
5714 | iPage = sqlite3Get4byte( aData, 8 + closest * 4 ); |
||
5715 | testcase( iPage == mxPage ); |
||
5716 | if ( iPage > mxPage ) |
||
5717 | { |
||
5718 | rc = SQLITE_CORRUPT_BKPT(); |
||
5719 | goto end_allocate_page; |
||
5720 | } |
||
5721 | testcase( iPage == mxPage ); |
||
5722 | if ( 0 == searchList || iPage == nearby ) |
||
5723 | { |
||
5724 | int noContent; |
||
5725 | pPgno = iPage; |
||
5726 | TRACE( "ALLOCATE: %d was leaf %d of %d on trunk %d" + |
||
5727 | ": %d more free pages\n", |
||
5728 | pPgno, closest + 1, k, pTrunk.pgno, n - 1 ); |
||
5729 | rc = sqlite3PagerWrite( pTrunk.pDbPage ); |
||
5730 | if ( rc != 0) |
||
5731 | goto end_allocate_page; |
||
5732 | if ( closest < k - 1 ) |
||
5733 | { |
||
5734 | Buffer.BlockCopy( aData, (int)( 4 + k * 4 ), aData, 8 + (int)closest * 4, 4 );//memcpy( aData[8 + closest * 4], ref aData[4 + k * 4], 4 ); |
||
5735 | } |
||
5736 | sqlite3Put4byte( aData, (u32)4, ( k - 1 ) );// sqlite3Put4byte( aData, 4, k - 1 ); |
||
5737 | noContent = !btreeGetHasContent( pBt, pPgno ) ? 1 : 0; |
||
5738 | rc = btreeGetPage( pBt, pPgno, ref ppPage, noContent ); |
||
5739 | if ( rc == SQLITE_OK ) |
||
5740 | { |
||
5741 | rc = sqlite3PagerWrite( ( ppPage ).pDbPage ); |
||
5742 | if ( rc != SQLITE_OK ) |
||
5743 | { |
||
5744 | releasePage( ppPage ); |
||
5745 | } |
||
5746 | } |
||
5747 | searchList = 0; |
||
5748 | } |
||
5749 | } |
||
5750 | releasePage( pPrevTrunk ); |
||
5751 | pPrevTrunk = null; |
||
5752 | } while ( searchList != 0 ); |
||
5753 | } |
||
5754 | else |
||
5755 | { |
||
5756 | /* There are no pages on the freelist, so create a new page at the |
||
5757 | ** end of the file */ |
||
5758 | rc = sqlite3PagerWrite( pBt.pPage1.pDbPage ); |
||
5759 | if ( rc != 0 ) |
||
5760 | return rc; |
||
5761 | pBt.nPage++; |
||
5762 | if ( pBt.nPage == PENDING_BYTE_PAGE( pBt ) ) |
||
5763 | pBt.nPage++; |
||
5764 | |||
5765 | #if !SQLITE_OMIT_AUTOVACUUM |
||
5766 | if ( pBt.autoVacuum && PTRMAP_ISPAGE( pBt, pBt.nPage ) ) |
||
5767 | { |
||
5768 | /* If pPgno refers to a pointer-map page, allocate two new pages |
||
5769 | ** at the end of the file instead of one. The first allocated page |
||
5770 | ** becomes a new pointer-map page, the second is used by the caller. |
||
5771 | */ |
||
5772 | MemPage pPg = null; |
||
5773 | TRACE( "ALLOCATE: %d from end of file (pointer-map page)\n", pPgno ); |
||
5774 | Debug.Assert( pBt.nPage != PENDING_BYTE_PAGE( pBt ) ); |
||
5775 | rc = btreeGetPage( pBt, pBt.nPage, ref pPg, 1 ); |
||
5776 | if ( rc == SQLITE_OK ) |
||
5777 | { |
||
5778 | rc = sqlite3PagerWrite( pPg.pDbPage ); |
||
5779 | releasePage( pPg ); |
||
5780 | } |
||
5781 | if ( rc != 0 ) |
||
5782 | return rc; |
||
5783 | pBt.nPage++; |
||
5784 | if ( pBt.nPage == PENDING_BYTE_PAGE( pBt ) ) |
||
5785 | { |
||
5786 | pBt.nPage++; |
||
5787 | } |
||
5788 | } |
||
5789 | #endif |
||
5790 | sqlite3Put4byte( pBt.pPage1.aData, (u32)28, pBt.nPage ); |
||
5791 | pPgno = pBt.nPage; |
||
5792 | |||
5793 | Debug.Assert( pPgno != PENDING_BYTE_PAGE( pBt ) ); |
||
5794 | rc = btreeGetPage( pBt, pPgno, ref ppPage, 1 ); |
||
5795 | if ( rc != 0 ) |
||
5796 | return rc; |
||
5797 | rc = sqlite3PagerWrite( ( ppPage ).pDbPage ); |
||
5798 | if ( rc != SQLITE_OK ) |
||
5799 | { |
||
5800 | releasePage( ppPage ); |
||
5801 | } |
||
5802 | TRACE( "ALLOCATE: %d from end of file\n", pPgno ); |
||
5803 | } |
||
5804 | |||
5805 | Debug.Assert( pPgno != PENDING_BYTE_PAGE( pBt ) ); |
||
5806 | |||
5807 | end_allocate_page: |
||
5808 | releasePage( pTrunk ); |
||
5809 | releasePage( pPrevTrunk ); |
||
5810 | if ( rc == SQLITE_OK ) |
||
5811 | { |
||
5812 | if ( sqlite3PagerPageRefcount( ( ppPage ).pDbPage ) > 1 ) |
||
5813 | { |
||
5814 | releasePage( ppPage ); |
||
5815 | return SQLITE_CORRUPT_BKPT(); |
||
5816 | } |
||
5817 | ( ppPage ).isInit = 0; |
||
5818 | } |
||
5819 | else |
||
5820 | { |
||
5821 | ppPage = null; |
||
5822 | } |
||
5823 | Debug.Assert( rc != SQLITE_OK || sqlite3PagerIswriteable( ( ppPage ).pDbPage ) ); |
||
5824 | return rc; |
||
5825 | } |
||
5826 | |||
5827 | /* |
||
5828 | ** This function is used to add page iPage to the database file free-list. |
||
5829 | ** It is assumed that the page is not already a part of the free-list. |
||
5830 | ** |
||
5831 | ** The value passed as the second argument to this function is optional. |
||
5832 | ** If the caller happens to have a pointer to the MemPage object |
||
5833 | ** corresponding to page iPage handy, it may pass it as the second value. |
||
5834 | ** Otherwise, it may pass NULL. |
||
5835 | ** |
||
5836 | ** If a pointer to a MemPage object is passed as the second argument, |
||
5837 | ** its reference count is not altered by this function. |
||
5838 | */ |
||
5839 | static int freePage2( BtShared pBt, MemPage pMemPage, Pgno iPage ) |
||
5840 | { |
||
5841 | MemPage pTrunk = null; /* Free-list trunk page */ |
||
5842 | Pgno iTrunk = 0; /* Page number of free-list trunk page */ |
||
5843 | MemPage pPage1 = pBt.pPage1; /* Local reference to page 1 */ |
||
5844 | MemPage pPage; /* Page being freed. May be NULL. */ |
||
5845 | int rc; /* Return Code */ |
||
5846 | int nFree; /* Initial number of pages on free-list */ |
||
5847 | |||
5848 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
5849 | Debug.Assert( iPage > 1 ); |
||
5850 | Debug.Assert( null == pMemPage || pMemPage.pgno == iPage ); |
||
5851 | |||
5852 | if ( pMemPage != null ) |
||
5853 | { |
||
5854 | pPage = pMemPage; |
||
5855 | sqlite3PagerRef( pPage.pDbPage ); |
||
5856 | } |
||
5857 | else |
||
5858 | { |
||
5859 | pPage = btreePageLookup( pBt, iPage ); |
||
5860 | } |
||
5861 | |||
5862 | /* Increment the free page count on pPage1 */ |
||
5863 | rc = sqlite3PagerWrite( pPage1.pDbPage ); |
||
5864 | if ( rc != 0 ) |
||
5865 | goto freepage_out; |
||
5866 | nFree = (int)sqlite3Get4byte( pPage1.aData, 36 ); |
||
5867 | sqlite3Put4byte( pPage1.aData, 36, nFree + 1 ); |
||
5868 | |||
5869 | if ( pBt.secureDelete ) |
||
5870 | { |
||
5871 | /* If the secure_delete option is enabled, then |
||
5872 | ** always fully overwrite deleted information with zeros. |
||
5873 | */ |
||
5874 | if ( ( null == pPage && ( ( rc = btreeGetPage( pBt, iPage, ref pPage, 0 ) ) != 0 ) ) |
||
5875 | || ( ( rc = sqlite3PagerWrite( pPage.pDbPage ) ) != 0 ) |
||
5876 | ) |
||
5877 | { |
||
5878 | goto freepage_out; |
||
5879 | } |
||
5880 | Array.Clear( pPage.aData, 0, (int)pPage.pBt.pageSize );//memset(pPage->aData, 0, pPage->pBt->pageSize); |
||
5881 | } |
||
5882 | |||
5883 | /* If the database supports auto-vacuum, write an entry in the pointer-map |
||
5884 | ** to indicate that the page is free. |
||
5885 | */ |
||
5886 | #if !SQLITE_OMIT_AUTOVACUUM // if ( ISAUTOVACUUM ) |
||
5887 | if ( pBt.autoVacuum ) |
||
5888 | #else |
||
5889 | if (false) |
||
5890 | #endif |
||
5891 | { |
||
5892 | ptrmapPut( pBt, iPage, PTRMAP_FREEPAGE, 0, ref rc ); |
||
5893 | if ( rc != 0 ) |
||
5894 | goto freepage_out; |
||
5895 | } |
||
5896 | |||
5897 | /* Now manipulate the actual database free-list structure. There are two |
||
5898 | ** possibilities. If the free-list is currently empty, or if the first |
||
5899 | ** trunk page in the free-list is full, then this page will become a |
||
5900 | ** new free-list trunk page. Otherwise, it will become a leaf of the |
||
5901 | ** first trunk page in the current free-list. This block tests if it |
||
5902 | ** is possible to add the page as a new free-list leaf. |
||
5903 | */ |
||
5904 | if ( nFree != 0 ) |
||
5905 | { |
||
5906 | u32 nLeaf; /* Initial number of leaf cells on trunk page */ |
||
5907 | |||
5908 | iTrunk = sqlite3Get4byte( pPage1.aData, 32 ); |
||
5909 | rc = btreeGetPage( pBt, iTrunk, ref pTrunk, 0 ); |
||
5910 | if ( rc != SQLITE_OK ) |
||
5911 | { |
||
5912 | goto freepage_out; |
||
5913 | } |
||
5914 | |||
5915 | nLeaf = sqlite3Get4byte( pTrunk.aData, 4 ); |
||
5916 | Debug.Assert( pBt.usableSize > 32 ); |
||
5917 | if ( nLeaf > (u32)pBt.usableSize / 4 - 2 ) |
||
5918 | { |
||
5919 | rc = SQLITE_CORRUPT_BKPT(); |
||
5920 | goto freepage_out; |
||
5921 | } |
||
5922 | if ( nLeaf < (u32)pBt.usableSize / 4 - 8 ) |
||
5923 | { |
||
5924 | /* In this case there is room on the trunk page to insert the page |
||
5925 | ** being freed as a new leaf. |
||
5926 | ** |
||
5927 | ** Note that the trunk page is not really full until it contains |
||
5928 | ** usableSize/4 - 2 entries, not usableSize/4 - 8 entries as we have |
||
5929 | ** coded. But due to a coding error in versions of SQLite prior to |
||
5930 | ** 3.6.0, databases with freelist trunk pages holding more than |
||
5931 | ** usableSize/4 - 8 entries will be reported as corrupt. In order |
||
5932 | ** to maintain backwards compatibility with older versions of SQLite, |
||
5933 | ** we will continue to restrict the number of entries to usableSize/4 - 8 |
||
5934 | ** for now. At some point in the future (once everyone has upgraded |
||
5935 | ** to 3.6.0 or later) we should consider fixing the conditional above |
||
5936 | ** to read "usableSize/4-2" instead of "usableSize/4-8". |
||
5937 | */ |
||
5938 | rc = sqlite3PagerWrite( pTrunk.pDbPage ); |
||
5939 | if ( rc == SQLITE_OK ) |
||
5940 | { |
||
5941 | sqlite3Put4byte( pTrunk.aData, (u32)4, nLeaf + 1 ); |
||
5942 | sqlite3Put4byte( pTrunk.aData, (u32)8 + nLeaf * 4, iPage ); |
||
5943 | if ( pPage != null && !pBt.secureDelete ) |
||
5944 | { |
||
5945 | sqlite3PagerDontWrite( pPage.pDbPage ); |
||
5946 | } |
||
5947 | rc = btreeSetHasContent( pBt, iPage ); |
||
5948 | } |
||
5949 | TRACE( "FREE-PAGE: %d leaf on trunk page %d\n", iPage, pTrunk.pgno ); |
||
5950 | goto freepage_out; |
||
5951 | } |
||
5952 | } |
||
5953 | |||
5954 | /* If control flows to this point, then it was not possible to add the |
||
5955 | ** the page being freed as a leaf page of the first trunk in the free-list. |
||
5956 | ** Possibly because the free-list is empty, or possibly because the |
||
5957 | ** first trunk in the free-list is full. Either way, the page being freed |
||
5958 | ** will become the new first trunk page in the free-list. |
||
5959 | */ |
||
5960 | if ( pPage == null && SQLITE_OK != ( rc = btreeGetPage( pBt, iPage, ref pPage, 0 ) ) ) |
||
5961 | { |
||
5962 | goto freepage_out; |
||
5963 | } |
||
5964 | rc = sqlite3PagerWrite( pPage.pDbPage ); |
||
5965 | if ( rc != SQLITE_OK ) |
||
5966 | { |
||
5967 | goto freepage_out; |
||
5968 | } |
||
5969 | sqlite3Put4byte( pPage.aData, iTrunk ); |
||
5970 | sqlite3Put4byte( pPage.aData, 4, 0 ); |
||
5971 | sqlite3Put4byte( pPage1.aData, (u32)32, iPage ); |
||
5972 | TRACE( "FREE-PAGE: %d new trunk page replacing %d\n", pPage.pgno, iTrunk ); |
||
5973 | |||
5974 | freepage_out: |
||
5975 | if ( pPage != null ) |
||
5976 | { |
||
5977 | pPage.isInit = 0; |
||
5978 | } |
||
5979 | releasePage( pPage ); |
||
5980 | releasePage( pTrunk ); |
||
5981 | return rc; |
||
5982 | } |
||
5983 | static void freePage( MemPage pPage, ref int pRC ) |
||
5984 | { |
||
5985 | if ( ( pRC ) == SQLITE_OK ) |
||
5986 | { |
||
5987 | pRC = freePage2( pPage.pBt, pPage, pPage.pgno ); |
||
5988 | } |
||
5989 | } |
||
5990 | |||
5991 | /* |
||
5992 | ** Free any overflow pages associated with the given Cell. |
||
5993 | */ |
||
5994 | static int clearCell( MemPage pPage, int pCell ) |
||
5995 | { |
||
5996 | BtShared pBt = pPage.pBt; |
||
5997 | CellInfo info = new CellInfo(); |
||
5998 | Pgno ovflPgno; |
||
5999 | int rc; |
||
6000 | int nOvfl; |
||
6001 | u32 ovflPageSize; |
||
6002 | |||
6003 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6004 | btreeParseCellPtr( pPage, pCell, ref info ); |
||
6005 | if ( info.iOverflow == 0 ) |
||
6006 | { |
||
6007 | return SQLITE_OK; /* No overflow pages. Return without doing anything */ |
||
6008 | } |
||
6009 | ovflPgno = sqlite3Get4byte( pPage.aData, pCell, info.iOverflow ); |
||
6010 | Debug.Assert( pBt.usableSize > 4 ); |
||
6011 | ovflPageSize = (u16)( pBt.usableSize - 4 ); |
||
6012 | nOvfl = (int)( ( info.nPayload - info.nLocal + ovflPageSize - 1 ) / ovflPageSize ); |
||
6013 | Debug.Assert( ovflPgno == 0 || nOvfl > 0 ); |
||
6014 | while ( nOvfl-- != 0 ) |
||
6015 | { |
||
6016 | Pgno iNext = 0; |
||
6017 | MemPage pOvfl = null; |
||
6018 | if ( ovflPgno < 2 || ovflPgno > btreePagecount( pBt ) ) |
||
6019 | { |
||
6020 | /* 0 is not a legal page number and page 1 cannot be an |
||
6021 | ** overflow page. Therefore if ovflPgno<2 or past the end of the |
||
6022 | ** file the database must be corrupt. */ |
||
6023 | return SQLITE_CORRUPT_BKPT(); |
||
6024 | } |
||
6025 | if ( nOvfl != 0 ) |
||
6026 | { |
||
6027 | rc = getOverflowPage( pBt, ovflPgno, out pOvfl, out iNext ); |
||
6028 | if ( rc != 0 ) |
||
6029 | return rc; |
||
6030 | } |
||
6031 | |||
6032 | if ( ( pOvfl != null || ( ( pOvfl = btreePageLookup( pBt, ovflPgno ) ) != null ) ) |
||
6033 | && sqlite3PagerPageRefcount( pOvfl.pDbPage ) != 1 |
||
6034 | ) |
||
6035 | { |
||
6036 | /* There is no reason any cursor should have an outstanding reference |
||
6037 | ** to an overflow page belonging to a cell that is being deleted/updated. |
||
6038 | ** So if there exists more than one reference to this page, then it |
||
6039 | ** must not really be an overflow page and the database must be corrupt. |
||
6040 | ** It is helpful to detect this before calling freePage2(), as |
||
6041 | ** freePage2() may zero the page contents if secure-delete mode is |
||
6042 | ** enabled. If this 'overflow' page happens to be a page that the |
||
6043 | ** caller is iterating through or using in some other way, this |
||
6044 | ** can be problematic. |
||
6045 | */ |
||
6046 | rc = SQLITE_CORRUPT_BKPT(); |
||
6047 | } |
||
6048 | else |
||
6049 | { |
||
6050 | rc = freePage2( pBt, pOvfl, ovflPgno ); |
||
6051 | } |
||
6052 | if ( pOvfl != null ) |
||
6053 | { |
||
6054 | sqlite3PagerUnref( pOvfl.pDbPage ); |
||
6055 | } |
||
6056 | if ( rc != 0 ) |
||
6057 | return rc; |
||
6058 | ovflPgno = iNext; |
||
6059 | } |
||
6060 | return SQLITE_OK; |
||
6061 | } |
||
6062 | |||
6063 | /* |
||
6064 | ** Create the byte sequence used to represent a cell on page pPage |
||
6065 | ** and write that byte sequence into pCell[]. Overflow pages are |
||
6066 | ** allocated and filled in as necessary. The calling procedure |
||
6067 | ** is responsible for making sure sufficient space has been allocated |
||
6068 | ** for pCell[]. |
||
6069 | ** |
||
6070 | ** Note that pCell does not necessary need to point to the pPage.aData |
||
6071 | ** area. pCell might point to some temporary storage. The cell will |
||
6072 | ** be constructed in this temporary area then copied into pPage.aData |
||
6073 | ** later. |
||
6074 | */ |
||
6075 | static int fillInCell( |
||
6076 | MemPage pPage, /* The page that contains the cell */ |
||
6077 | byte[] pCell, /* Complete text of the cell */ |
||
6078 | byte[] pKey, i64 nKey, /* The key */ |
||
6079 | byte[] pData, int nData, /* The data */ |
||
6080 | int nZero, /* Extra zero bytes to append to pData */ |
||
6081 | ref int pnSize /* Write cell size here */ |
||
6082 | ) |
||
6083 | { |
||
6084 | int nPayload; |
||
6085 | u8[] pSrc; |
||
6086 | int pSrcIndex = 0; |
||
6087 | int nSrc, n, rc; |
||
6088 | int spaceLeft; |
||
6089 | MemPage pOvfl = null; |
||
6090 | MemPage pToRelease = null; |
||
6091 | byte[] pPrior; |
||
6092 | int pPriorIndex = 0; |
||
6093 | byte[] pPayload; |
||
6094 | int pPayloadIndex = 0; |
||
6095 | BtShared pBt = pPage.pBt; |
||
6096 | Pgno pgnoOvfl = 0; |
||
6097 | int nHeader; |
||
6098 | CellInfo info = new CellInfo(); |
||
6099 | |||
6100 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6101 | |||
6102 | /* pPage is not necessarily writeable since pCell might be auxiliary |
||
6103 | ** buffer space that is separate from the pPage buffer area */ |
||
6104 | // TODO -- Determine if the following Assert is needed under c# |
||
6105 | //Debug.Assert( pCell < pPage.aData || pCell >= &pPage.aData[pBt.pageSize] |
||
6106 | // || sqlite3PagerIswriteable(pPage.pDbPage) ); |
||
6107 | |||
6108 | /* Fill in the header. */ |
||
6109 | nHeader = 0; |
||
6110 | if ( 0 == pPage.leaf ) |
||
6111 | { |
||
6112 | nHeader += 4; |
||
6113 | } |
||
6114 | if ( pPage.hasData != 0 ) |
||
6115 | { |
||
6116 | nHeader += (int)putVarint( pCell, nHeader, (int)( nData + nZero ) ); //putVarint( pCell[nHeader], nData + nZero ); |
||
6117 | } |
||
6118 | else |
||
6119 | { |
||
6120 | nData = nZero = 0; |
||
6121 | } |
||
6122 | nHeader += putVarint( pCell, nHeader, (u64)nKey ); //putVarint( pCell[nHeader], *(u64*)&nKey ); |
||
6123 | btreeParseCellPtr( pPage, pCell, ref info ); |
||
6124 | Debug.Assert( info.nHeader == nHeader ); |
||
6125 | Debug.Assert( info.nKey == nKey ); |
||
6126 | Debug.Assert( info.nData == (u32)( nData + nZero ) ); |
||
6127 | |||
6128 | /* Fill in the payload */ |
||
6129 | nPayload = nData + nZero; |
||
6130 | if ( pPage.intKey != 0 ) |
||
6131 | { |
||
6132 | pSrc = pData; |
||
6133 | nSrc = nData; |
||
6134 | nData = 0; |
||
6135 | } |
||
6136 | else |
||
6137 | { |
||
6138 | if ( NEVER( nKey > 0x7fffffff || pKey == null ) ) |
||
6139 | { |
||
6140 | return SQLITE_CORRUPT_BKPT(); |
||
6141 | } |
||
6142 | nPayload += (int)nKey; |
||
6143 | pSrc = pKey; |
||
6144 | nSrc = (int)nKey; |
||
6145 | } |
||
6146 | pnSize = info.nSize; |
||
6147 | spaceLeft = info.nLocal; |
||
6148 | // pPayload = &pCell[nHeader]; |
||
6149 | pPayload = pCell; |
||
6150 | pPayloadIndex = nHeader; |
||
6151 | // pPrior = &pCell[info.iOverflow]; |
||
6152 | pPrior = pCell; |
||
6153 | pPriorIndex = info.iOverflow; |
||
6154 | |||
6155 | while ( nPayload > 0 ) |
||
6156 | { |
||
6157 | if ( spaceLeft == 0 ) |
||
6158 | { |
||
6159 | #if !SQLITE_OMIT_AUTOVACUUM |
||
6160 | Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ |
||
6161 | if ( pBt.autoVacuum ) |
||
6162 | { |
||
6163 | do |
||
6164 | { |
||
6165 | pgnoOvfl++; |
||
6166 | } while ( |
||
6167 | PTRMAP_ISPAGE( pBt, pgnoOvfl ) || pgnoOvfl == PENDING_BYTE_PAGE( pBt ) |
||
6168 | ); |
||
6169 | } |
||
6170 | #endif |
||
6171 | rc = allocateBtreePage( pBt, ref pOvfl, ref pgnoOvfl, pgnoOvfl, 0 ); |
||
6172 | #if !SQLITE_OMIT_AUTOVACUUM |
||
6173 | /* If the database supports auto-vacuum, and the second or subsequent |
||
6174 | ** overflow page is being allocated, add an entry to the pointer-map |
||
6175 | ** for that page now. |
||
6176 | ** |
||
6177 | ** If this is the first overflow page, then write a partial entry |
||
6178 | ** to the pointer-map. If we write nothing to this pointer-map slot, |
||
6179 | ** then the optimistic overflow chain processing in clearCell() |
||
6180 | ** may misinterpret the uninitialised values and delete the |
||
6181 | ** wrong pages from the database. |
||
6182 | */ |
||
6183 | if ( pBt.autoVacuum && rc == SQLITE_OK ) |
||
6184 | { |
||
6185 | u8 eType = (u8)( pgnoPtrmap != 0 ? PTRMAP_OVERFLOW2 : PTRMAP_OVERFLOW1 ); |
||
6186 | ptrmapPut( pBt, pgnoOvfl, eType, pgnoPtrmap, ref rc ); |
||
6187 | if ( rc != 0 ) |
||
6188 | { |
||
6189 | releasePage( pOvfl ); |
||
6190 | } |
||
6191 | } |
||
6192 | #endif |
||
6193 | if ( rc != 0 ) |
||
6194 | { |
||
6195 | releasePage( pToRelease ); |
||
6196 | return rc; |
||
6197 | } |
||
6198 | |||
6199 | /* If pToRelease is not zero than pPrior points into the data area |
||
6200 | ** of pToRelease. Make sure pToRelease is still writeable. */ |
||
6201 | Debug.Assert( pToRelease == null || sqlite3PagerIswriteable( pToRelease.pDbPage ) ); |
||
6202 | |||
6203 | /* If pPrior is part of the data area of pPage, then make sure pPage |
||
6204 | ** is still writeable */ |
||
6205 | // TODO -- Determine if the following Assert is needed under c# |
||
6206 | //Debug.Assert( pPrior < pPage.aData || pPrior >= &pPage.aData[pBt.pageSize] |
||
6207 | // || sqlite3PagerIswriteable(pPage.pDbPage) ); |
||
6208 | |||
6209 | sqlite3Put4byte( pPrior, pPriorIndex, pgnoOvfl ); |
||
6210 | releasePage( pToRelease ); |
||
6211 | pToRelease = pOvfl; |
||
6212 | pPrior = pOvfl.aData; |
||
6213 | pPriorIndex = 0; |
||
6214 | sqlite3Put4byte( pPrior, 0 ); |
||
6215 | pPayload = pOvfl.aData; |
||
6216 | pPayloadIndex = 4; //&pOvfl.aData[4]; |
||
6217 | spaceLeft = (int)pBt.usableSize - 4; |
||
6218 | } |
||
6219 | n = nPayload; |
||
6220 | if ( n > spaceLeft ) |
||
6221 | n = spaceLeft; |
||
6222 | |||
6223 | /* If pToRelease is not zero than pPayload points into the data area |
||
6224 | ** of pToRelease. Make sure pToRelease is still writeable. */ |
||
6225 | Debug.Assert( pToRelease == null || sqlite3PagerIswriteable( pToRelease.pDbPage ) ); |
||
6226 | |||
6227 | /* If pPayload is part of the data area of pPage, then make sure pPage |
||
6228 | ** is still writeable */ |
||
6229 | // TODO -- Determine if the following Assert is needed under c# |
||
6230 | //Debug.Assert( pPayload < pPage.aData || pPayload >= &pPage.aData[pBt.pageSize] |
||
6231 | // || sqlite3PagerIswriteable(pPage.pDbPage) ); |
||
6232 | |||
6233 | if ( nSrc > 0 ) |
||
6234 | { |
||
6235 | if ( n > nSrc ) |
||
6236 | n = nSrc; |
||
6237 | Debug.Assert( pSrc != null ); |
||
6238 | Buffer.BlockCopy( pSrc, pSrcIndex, pPayload, pPayloadIndex, n );//memcpy(pPayload, pSrc, n); |
||
6239 | } |
||
6240 | else |
||
6241 | { |
||
6242 | byte[] pZeroBlob = sqlite3Malloc( n ); // memset(pPayload, 0, n); |
||
6243 | Buffer.BlockCopy( pZeroBlob, 0, pPayload, pPayloadIndex, n ); |
||
6244 | } |
||
6245 | nPayload -= n; |
||
6246 | pPayloadIndex += n;// pPayload += n; |
||
6247 | pSrcIndex += n;// pSrc += n; |
||
6248 | nSrc -= n; |
||
6249 | spaceLeft -= n; |
||
6250 | if ( nSrc == 0 ) |
||
6251 | { |
||
6252 | nSrc = nData; |
||
6253 | pSrc = pData; |
||
6254 | } |
||
6255 | } |
||
6256 | releasePage( pToRelease ); |
||
6257 | return SQLITE_OK; |
||
6258 | } |
||
6259 | |||
6260 | /* |
||
6261 | ** Remove the i-th cell from pPage. This routine effects pPage only. |
||
6262 | ** The cell content is not freed or deallocated. It is assumed that |
||
6263 | ** the cell content has been copied someplace else. This routine just |
||
6264 | ** removes the reference to the cell from pPage. |
||
6265 | ** |
||
6266 | ** "sz" must be the number of bytes in the cell. |
||
6267 | */ |
||
6268 | static void dropCell( MemPage pPage, int idx, int sz, ref int pRC ) |
||
6269 | { |
||
6270 | u32 pc; /* Offset to cell content of cell being deleted */ |
||
6271 | u8[] data; /* pPage.aData */ |
||
6272 | int ptr; /* Used to move bytes around within data[] */ |
||
6273 | int endPtr; /* End of loop */ |
||
6274 | int rc; /* The return code */ |
||
6275 | int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ |
||
6276 | |||
6277 | if ( pRC != 0 ) |
||
6278 | return; |
||
6279 | |||
6280 | Debug.Assert( idx >= 0 && idx < pPage.nCell ); |
||
6281 | #if SQLITE_DEBUG |
||
6282 | Debug.Assert( sz == cellSize( pPage, idx ) ); |
||
6283 | #endif |
||
6284 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
6285 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6286 | data = pPage.aData; |
||
6287 | ptr = pPage.cellOffset + 2 * idx; //ptr = &data[pPage.cellOffset + 2 * idx]; |
||
6288 | pc = (u32)get2byte( data, ptr ); |
||
6289 | hdr = pPage.hdrOffset; |
||
6290 | testcase( pc == get2byte( data, hdr + 5 ) ); |
||
6291 | testcase( pc + sz == pPage.pBt.usableSize ); |
||
6292 | if ( pc < (u32)get2byte( data, hdr + 5 ) || pc + sz > pPage.pBt.usableSize ) |
||
6293 | { |
||
6294 | pRC = SQLITE_CORRUPT_BKPT(); |
||
6295 | return; |
||
6296 | } |
||
6297 | rc = freeSpace( pPage, pc, sz ); |
||
6298 | if ( rc != 0 ) |
||
6299 | { |
||
6300 | pRC = rc; |
||
6301 | return; |
||
6302 | } |
||
6303 | //endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2]; |
||
6304 | //assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */ |
||
6305 | //while( ptr<endPtr ){ |
||
6306 | // *(u16*)ptr = *(u16*)&ptr[2]; |
||
6307 | // ptr += 2; |
||
6308 | Buffer.BlockCopy( data, ptr + 2, data, ptr, ( pPage.nCell - 1 - idx ) * 2 ); |
||
6309 | pPage.nCell--; |
||
6310 | data[pPage.hdrOffset + 3] = (byte)( pPage.nCell >> 8 ); |
||
6311 | data[pPage.hdrOffset + 4] = (byte)( pPage.nCell ); //put2byte( data, hdr + 3, pPage.nCell ); |
||
6312 | pPage.nFree += 2; |
||
6313 | } |
||
6314 | |||
6315 | /* |
||
6316 | ** Insert a new cell on pPage at cell index "i". pCell points to the |
||
6317 | ** content of the cell. |
||
6318 | ** |
||
6319 | ** If the cell content will fit on the page, then put it there. If it |
||
6320 | ** will not fit, then make a copy of the cell content into pTemp if |
||
6321 | ** pTemp is not null. Regardless of pTemp, allocate a new entry |
||
6322 | ** in pPage.aOvfl[] and make it point to the cell content (either |
||
6323 | ** in pTemp or the original pCell) and also record its index. |
||
6324 | ** Allocating a new entry in pPage.aCell[] implies that |
||
6325 | ** pPage.nOverflow is incremented. |
||
6326 | ** |
||
6327 | ** If nSkip is non-zero, then do not copy the first nSkip bytes of the |
||
6328 | ** cell. The caller will overwrite them after this function returns. If |
||
6329 | ** nSkip is non-zero, then pCell may not point to an invalid memory location |
||
6330 | ** (but pCell+nSkip is always valid). |
||
6331 | */ |
||
6332 | static void insertCell( |
||
6333 | MemPage pPage, /* Page into which we are copying */ |
||
6334 | int i, /* New cell becomes the i-th cell of the page */ |
||
6335 | u8[] pCell, /* Content of the new cell */ |
||
6336 | int sz, /* Bytes of content in pCell */ |
||
6337 | u8[] pTemp, /* Temp storage space for pCell, if needed */ |
||
6338 | Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ |
||
6339 | ref int pRC /* Read and write return code from here */ |
||
6340 | ) |
||
6341 | { |
||
6342 | int idx = 0; /* Where to write new cell content in data[] */ |
||
6343 | int j; /* Loop counter */ |
||
6344 | int end; /* First byte past the last cell pointer in data[] */ |
||
6345 | int ins; /* Index in data[] where new cell pointer is inserted */ |
||
6346 | int cellOffset; /* Address of first cell pointer in data[] */ |
||
6347 | u8[] data; /* The content of the whole page */ |
||
6348 | u8 ptr; /* Used for moving information around in data[] */ |
||
6349 | u8 endPtr; /* End of the loop */ |
||
6350 | |||
6351 | int nSkip = ( iChild != 0 ? 4 : 0 ); |
||
6352 | |||
6353 | if ( pRC != 0 ) |
||
6354 | return; |
||
6355 | |||
6356 | Debug.Assert( i >= 0 && i <= pPage.nCell + pPage.nOverflow ); |
||
6357 | Debug.Assert( pPage.nCell <= MX_CELL( pPage.pBt ) && MX_CELL( pPage.pBt ) <= 10921 ); |
||
6358 | Debug.Assert( pPage.nOverflow <= ArraySize( pPage.aOvfl ) ); |
||
6359 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6360 | /* The cell should normally be sized correctly. However, when moving a |
||
6361 | ** malformed cell from a leaf page to an interior page, if the cell size |
||
6362 | ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size |
||
6363 | ** might be less than 8 (leaf-size + pointer) on the interior node. Hence |
||
6364 | ** the term after the || in the following assert(). */ |
||
6365 | Debug.Assert( sz == cellSizePtr( pPage, pCell ) || ( sz == 8 && iChild > 0 ) ); |
||
6366 | if ( pPage.nOverflow != 0 || sz + 2 > pPage.nFree ) |
||
6367 | { |
||
6368 | if ( pTemp != null ) |
||
6369 | { |
||
6370 | Buffer.BlockCopy( pCell, nSkip, pTemp, nSkip, sz - nSkip );//memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip); |
||
6371 | pCell = pTemp; |
||
6372 | } |
||
6373 | if ( iChild != 0 ) |
||
6374 | { |
||
6375 | sqlite3Put4byte( pCell, iChild ); |
||
6376 | } |
||
6377 | j = pPage.nOverflow++; |
||
6378 | Debug.Assert( j < pPage.aOvfl.Length );//(int)(sizeof(pPage.aOvfl)/sizeof(pPage.aOvfl[0])) ); |
||
6379 | pPage.aOvfl[j].pCell = pCell; |
||
6380 | pPage.aOvfl[j].idx = (u16)i; |
||
6381 | } |
||
6382 | else |
||
6383 | { |
||
6384 | int rc = sqlite3PagerWrite( pPage.pDbPage ); |
||
6385 | if ( rc != SQLITE_OK ) |
||
6386 | { |
||
6387 | pRC = rc; |
||
6388 | return; |
||
6389 | } |
||
6390 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
6391 | data = pPage.aData; |
||
6392 | cellOffset = pPage.cellOffset; |
||
6393 | end = cellOffset + 2 * pPage.nCell; |
||
6394 | ins = cellOffset + 2 * i; |
||
6395 | rc = allocateSpace( pPage, sz, ref idx ); |
||
6396 | if ( rc != 0 ) |
||
6397 | { |
||
6398 | pRC = rc; |
||
6399 | return; |
||
6400 | } |
||
6401 | /* The allocateSpace() routine guarantees the following two properties |
||
6402 | ** if it returns success */ |
||
6403 | Debug.Assert( idx >= end + 2 ); |
||
6404 | Debug.Assert( idx + sz <= (int)pPage.pBt.usableSize ); |
||
6405 | pPage.nCell++; |
||
6406 | pPage.nFree -= (u16)( 2 + sz ); |
||
6407 | Buffer.BlockCopy( pCell, nSkip, data, idx + nSkip, sz - nSkip ); //memcpy( data[idx + nSkip], pCell + nSkip, sz - nSkip ); |
||
6408 | if ( iChild != 0 ) |
||
6409 | { |
||
6410 | sqlite3Put4byte( data, idx, iChild ); |
||
6411 | } |
||
6412 | //ptr = &data[end]; |
||
6413 | //endPtr = &data[ins]; |
||
6414 | //assert( ( SQLITE_PTR_TO_INT( ptr ) & 1 ) == 0 ); /* ptr is always 2-byte aligned */ |
||
6415 | //while ( ptr > endPtr ) |
||
6416 | //{ |
||
6417 | // *(u16*)ptr = *(u16*)&ptr[-2]; |
||
6418 | // ptr -= 2; |
||
6419 | //} |
||
6420 | for ( j = end; j > ins; j -= 2 ) |
||
6421 | { |
||
6422 | data[j + 0] = data[j - 2]; |
||
6423 | data[j + 1] = data[j - 1]; |
||
6424 | } |
||
6425 | put2byte( data, ins, idx ); |
||
6426 | put2byte( data, pPage.hdrOffset + 3, pPage.nCell ); |
||
6427 | #if !SQLITE_OMIT_AUTOVACUUM |
||
6428 | if ( pPage.pBt.autoVacuum ) |
||
6429 | { |
||
6430 | /* The cell may contain a pointer to an overflow page. If so, write |
||
6431 | ** the entry for the overflow page into the pointer map. |
||
6432 | */ |
||
6433 | ptrmapPutOvflPtr( pPage, pCell, ref pRC ); |
||
6434 | } |
||
6435 | #endif |
||
6436 | } |
||
6437 | } |
||
6438 | |||
6439 | /* |
||
6440 | ** Add a list of cells to a page. The page should be initially empty. |
||
6441 | ** The cells are guaranteed to fit on the page. |
||
6442 | */ |
||
6443 | static void assemblePage( |
||
6444 | MemPage pPage, /* The page to be assemblied */ |
||
6445 | int nCell, /* The number of cells to add to this page */ |
||
6446 | u8[] apCell, /* Pointer to a single the cell bodies */ |
||
6447 | int[] aSize /* Sizes of the cells bodie*/ |
||
6448 | ) |
||
6449 | { |
||
6450 | int i; /* Loop counter */ |
||
6451 | int pCellptr; /* Address of next cell pointer */ |
||
6452 | int cellbody; /* Address of next cell body */ |
||
6453 | byte[] data = pPage.aData; /* Pointer to data for pPage */ |
||
6454 | int hdr = pPage.hdrOffset; /* Offset of header on pPage */ |
||
6455 | int nUsable = (int)pPage.pBt.usableSize; /* Usable size of page */ |
||
6456 | |||
6457 | Debug.Assert( pPage.nOverflow == 0 ); |
||
6458 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6459 | Debug.Assert( nCell >= 0 && nCell <= (int)MX_CELL( pPage.pBt ) |
||
6460 | && (int)MX_CELL( pPage.pBt ) <= 10921 ); |
||
6461 | |||
6462 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
6463 | |||
6464 | /* Check that the page has just been zeroed by zeroPage() */ |
||
6465 | Debug.Assert( pPage.nCell == 0 ); |
||
6466 | Debug.Assert( get2byteNotZero( data, hdr + 5 ) == nUsable ); |
||
6467 | |||
6468 | pCellptr = pPage.cellOffset + nCell * 2; //data[pPage.cellOffset + nCell * 2]; |
||
6469 | cellbody = nUsable; |
||
6470 | for ( i = nCell - 1; i >= 0; i-- ) |
||
6471 | { |
||
6472 | u16 sz = (u16)aSize[i]; |
||
6473 | pCellptr -= 2; |
||
6474 | cellbody -= sz; |
||
6475 | put2byte( data, pCellptr, cellbody ); |
||
6476 | Buffer.BlockCopy( apCell, 0, data, cellbody, sz );// memcpy(&data[cellbody], apCell[i], sz); |
||
6477 | } |
||
6478 | put2byte( data, hdr + 3, nCell ); |
||
6479 | put2byte( data, hdr + 5, cellbody ); |
||
6480 | pPage.nFree -= (u16)( nCell * 2 + nUsable - cellbody ); |
||
6481 | pPage.nCell = (u16)nCell; |
||
6482 | } |
||
6483 | static void assemblePage( |
||
6484 | MemPage pPage, /* The page to be assemblied */ |
||
6485 | int nCell, /* The number of cells to add to this page */ |
||
6486 | u8[][] apCell, /* Pointers to cell bodies */ |
||
6487 | u16[] aSize, /* Sizes of the cells */ |
||
6488 | int offset /* Offset into the cell bodies, for c# */ |
||
6489 | ) |
||
6490 | { |
||
6491 | int i; /* Loop counter */ |
||
6492 | int pCellptr; /* Address of next cell pointer */ |
||
6493 | int cellbody; /* Address of next cell body */ |
||
6494 | byte[] data = pPage.aData; /* Pointer to data for pPage */ |
||
6495 | int hdr = pPage.hdrOffset; /* Offset of header on pPage */ |
||
6496 | int nUsable = (int)pPage.pBt.usableSize; /* Usable size of page */ |
||
6497 | |||
6498 | Debug.Assert( pPage.nOverflow == 0 ); |
||
6499 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6500 | Debug.Assert( nCell >= 0 && nCell <= MX_CELL( pPage.pBt ) && MX_CELL( pPage.pBt ) <= 5460 ); |
||
6501 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
6502 | |||
6503 | /* Check that the page has just been zeroed by zeroPage() */ |
||
6504 | Debug.Assert( pPage.nCell == 0 ); |
||
6505 | Debug.Assert( get2byte( data, hdr + 5 ) == nUsable ); |
||
6506 | |||
6507 | pCellptr = pPage.cellOffset + nCell * 2; //data[pPage.cellOffset + nCell * 2]; |
||
6508 | cellbody = nUsable; |
||
6509 | for ( i = nCell - 1; i >= 0; i-- ) |
||
6510 | { |
||
6511 | pCellptr -= 2; |
||
6512 | cellbody -= aSize[i + offset]; |
||
6513 | put2byte( data, pCellptr, cellbody ); |
||
6514 | Buffer.BlockCopy( apCell[offset + i], 0, data, cellbody, aSize[i + offset] );// memcpy(&data[cellbody], apCell[i], aSize[i]); |
||
6515 | } |
||
6516 | put2byte( data, hdr + 3, nCell ); |
||
6517 | put2byte( data, hdr + 5, cellbody ); |
||
6518 | pPage.nFree -= (u16)( nCell * 2 + nUsable - cellbody ); |
||
6519 | pPage.nCell = (u16)nCell; |
||
6520 | } |
||
6521 | |||
6522 | static void assemblePage( |
||
6523 | MemPage pPage, /* The page to be assemblied */ |
||
6524 | int nCell, /* The number of cells to add to this page */ |
||
6525 | u8[] apCell, /* Pointers to cell bodies */ |
||
6526 | u16[] aSize /* Sizes of the cells */ |
||
6527 | ) |
||
6528 | { |
||
6529 | int i; /* Loop counter */ |
||
6530 | int pCellptr; /* Address of next cell pointer */ |
||
6531 | int cellbody; /* Address of next cell body */ |
||
6532 | u8[] data = pPage.aData; /* Pointer to data for pPage */ |
||
6533 | int hdr = pPage.hdrOffset; /* Offset of header on pPage */ |
||
6534 | int nUsable = (int)pPage.pBt.usableSize; /* Usable size of page */ |
||
6535 | |||
6536 | Debug.Assert( pPage.nOverflow == 0 ); |
||
6537 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6538 | Debug.Assert( nCell >= 0 && nCell <= MX_CELL( pPage.pBt ) && MX_CELL( pPage.pBt ) <= 5460 ); |
||
6539 | Debug.Assert( sqlite3PagerIswriteable( pPage.pDbPage ) ); |
||
6540 | |||
6541 | /* Check that the page has just been zeroed by zeroPage() */ |
||
6542 | Debug.Assert( pPage.nCell == 0 ); |
||
6543 | Debug.Assert( get2byte( data, hdr + 5 ) == nUsable ); |
||
6544 | |||
6545 | pCellptr = pPage.cellOffset + nCell * 2; //&data[pPage.cellOffset + nCell * 2]; |
||
6546 | cellbody = nUsable; |
||
6547 | for ( i = nCell - 1; i >= 0; i-- ) |
||
6548 | { |
||
6549 | pCellptr -= 2; |
||
6550 | cellbody -= aSize[i]; |
||
6551 | put2byte( data, pCellptr, cellbody ); |
||
6552 | Buffer.BlockCopy( apCell, 0, data, cellbody, aSize[i] );//memcpy( data[cellbody], apCell[i], aSize[i] ); |
||
6553 | } |
||
6554 | put2byte( data, hdr + 3, nCell ); |
||
6555 | put2byte( data, hdr + 5, cellbody ); |
||
6556 | pPage.nFree -= (u16)( nCell * 2 + nUsable - cellbody ); |
||
6557 | pPage.nCell = (u16)nCell; |
||
6558 | } |
||
6559 | |||
6560 | /* |
||
6561 | ** The following parameters determine how many adjacent pages get involved |
||
6562 | ** in a balancing operation. NN is the number of neighbors on either side |
||
6563 | ** of the page that participate in the balancing operation. NB is the |
||
6564 | ** total number of pages that participate, including the target page and |
||
6565 | ** NN neighbors on either side. |
||
6566 | ** |
||
6567 | ** The minimum value of NN is 1 (of course). Increasing NN above 1 |
||
6568 | ** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance |
||
6569 | ** in exchange for a larger degradation in INSERT and UPDATE performance. |
||
6570 | ** The value of NN appears to give the best results overall. |
||
6571 | */ |
||
6572 | static int NN = 1; /* Number of neighbors on either side of pPage */ |
||
6573 | static int NB = ( NN * 2 + 1 ); /* Total pages involved in the balance */ |
||
6574 | |||
6575 | #if !SQLITE_OMIT_QUICKBALANCE |
||
6576 | /* |
||
6577 | ** This version of balance() handles the common special case where |
||
6578 | ** a new entry is being inserted on the extreme right-end of the |
||
6579 | ** tree, in other words, when the new entry will become the largest |
||
6580 | ** entry in the tree. |
||
6581 | ** |
||
6582 | ** Instead of trying to balance the 3 right-most leaf pages, just add |
||
6583 | ** a new page to the right-hand side and put the one new entry in |
||
6584 | ** that page. This leaves the right side of the tree somewhat |
||
6585 | ** unbalanced. But odds are that we will be inserting new entries |
||
6586 | ** at the end soon afterwards so the nearly empty page will quickly |
||
6587 | ** fill up. On average. |
||
6588 | ** |
||
6589 | ** pPage is the leaf page which is the right-most page in the tree. |
||
6590 | ** pParent is its parent. pPage must have a single overflow entry |
||
6591 | ** which is also the right-most entry on the page. |
||
6592 | ** |
||
6593 | ** The pSpace buffer is used to store a temporary copy of the divider |
||
6594 | ** cell that will be inserted into pParent. Such a cell consists of a 4 |
||
6595 | ** byte page number followed by a variable length integer. In other |
||
6596 | ** words, at most 13 bytes. Hence the pSpace buffer must be at |
||
6597 | ** least 13 bytes in size. |
||
6598 | */ |
||
6599 | static int balance_quick( MemPage pParent, MemPage pPage, u8[] pSpace ) |
||
6600 | { |
||
6601 | BtShared pBt = pPage.pBt; /* B-Tree Database */ |
||
6602 | MemPage pNew = new MemPage();/* Newly allocated page */ |
||
6603 | int rc; /* Return Code */ |
||
6604 | Pgno pgnoNew = 0; /* Page number of pNew */ |
||
6605 | |||
6606 | Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) ); |
||
6607 | Debug.Assert( sqlite3PagerIswriteable( pParent.pDbPage ) ); |
||
6608 | Debug.Assert( pPage.nOverflow == 1 ); |
||
6609 | |||
6610 | /* This error condition is now caught prior to reaching this function */ |
||
6611 | if ( pPage.nCell <= 0 ) |
||
6612 | return SQLITE_CORRUPT_BKPT(); |
||
6613 | |||
6614 | /* Allocate a new page. This page will become the right-sibling of |
||
6615 | ** pPage. Make the parent page writable, so that the new divider cell |
||
6616 | ** may be inserted. If both these operations are successful, proceed. |
||
6617 | */ |
||
6618 | rc = allocateBtreePage( pBt, ref pNew, ref pgnoNew, 0, 0 ); |
||
6619 | |||
6620 | if ( rc == SQLITE_OK ) |
||
6621 | { |
||
6622 | |||
6623 | int pOut = 4;//u8 pOut = &pSpace[4]; |
||
6624 | u8[] pCell = pPage.aOvfl[0].pCell; |
||
6625 | int[] szCell = new int[1]; |
||
6626 | szCell[0] = cellSizePtr( pPage, pCell ); |
||
6627 | int pStop; |
||
6628 | |||
6629 | Debug.Assert( sqlite3PagerIswriteable( pNew.pDbPage ) ); |
||
6630 | Debug.Assert( pPage.aData[0] == ( PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF ) ); |
||
6631 | zeroPage( pNew, PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF ); |
||
6632 | assemblePage( pNew, 1, pCell, szCell ); |
||
6633 | |||
6634 | /* If this is an auto-vacuum database, update the pointer map |
||
6635 | ** with entries for the new page, and any pointer from the |
||
6636 | ** cell on the page to an overflow page. If either of these |
||
6637 | ** operations fails, the return code is set, but the contents |
||
6638 | ** of the parent page are still manipulated by thh code below. |
||
6639 | ** That is Ok, at this point the parent page is guaranteed to |
||
6640 | ** be marked as dirty. Returning an error code will cause a |
||
6641 | ** rollback, undoing any changes made to the parent page. |
||
6642 | */ |
||
6643 | #if !SQLITE_OMIT_AUTOVACUUM // if ( ISAUTOVACUUM ) |
||
6644 | if ( pBt.autoVacuum ) |
||
6645 | #else |
||
6646 | if (false) |
||
6647 | #endif |
||
6648 | { |
||
6649 | ptrmapPut( pBt, pgnoNew, PTRMAP_BTREE, pParent.pgno, ref rc ); |
||
6650 | if ( szCell[0] > pNew.minLocal ) |
||
6651 | { |
||
6652 | ptrmapPutOvflPtr( pNew, pCell, ref rc ); |
||
6653 | } |
||
6654 | } |
||
6655 | |||
6656 | /* Create a divider cell to insert into pParent. The divider cell |
||
6657 | ** consists of a 4-byte page number (the page number of pPage) and |
||
6658 | ** a variable length key value (which must be the same value as the |
||
6659 | ** largest key on pPage). |
||
6660 | ** |
||
6661 | ** To find the largest key value on pPage, first find the right-most |
||
6662 | ** cell on pPage. The first two fields of this cell are the |
||
6663 | ** record-length (a variable length integer at most 32-bits in size) |
||
6664 | ** and the key value (a variable length integer, may have any value). |
||
6665 | ** The first of the while(...) loops below skips over the record-length |
||
6666 | ** field. The second while(...) loop copies the key value from the |
||
6667 | ** cell on pPage into the pSpace buffer. |
||
6668 | */ |
||
6669 | int iCell = findCell( pPage, pPage.nCell - 1 ); //pCell = findCell( pPage, pPage.nCell - 1 ); |
||
6670 | pCell = pPage.aData; |
||
6671 | int _pCell = iCell; |
||
6672 | pStop = _pCell + 9; //pStop = &pCell[9]; |
||
6673 | while ( ( ( pCell[_pCell++] ) & 0x80 ) != 0 && _pCell < pStop ) |
||
6674 | ; //while ( ( *( pCell++ ) & 0x80 ) && pCell < pStop ) ; |
||
6675 | pStop = _pCell + 9;//pStop = &pCell[9]; |
||
6676 | while ( ( ( pSpace[pOut++] = pCell[_pCell++] ) & 0x80 ) != 0 && _pCell < pStop ) |
||
6677 | ; //while ( ( ( *( pOut++ ) = *( pCell++ ) ) & 0x80 ) && pCell < pStop ) ; |
||
6678 | |||
6679 | /* Insert the new divider cell into pParent. */ |
||
6680 | insertCell( pParent, pParent.nCell, pSpace, pOut, //(int)(pOut-pSpace), |
||
6681 | null, pPage.pgno, ref rc ); |
||
6682 | |||
6683 | /* Set the right-child pointer of pParent to point to the new page. */ |
||
6684 | sqlite3Put4byte( pParent.aData, pParent.hdrOffset + 8, pgnoNew ); |
||
6685 | |||
6686 | /* Release the reference to the new page. */ |
||
6687 | releasePage( pNew ); |
||
6688 | } |
||
6689 | |||
6690 | return rc; |
||
6691 | } |
||
6692 | #endif //* SQLITE_OMIT_QUICKBALANCE */ |
||
6693 | |||
6694 | #if FALSE |
||
6695 | /* |
||
6696 | ** This function does not contribute anything to the operation of SQLite. |
||
6697 | ** it is sometimes activated temporarily while debugging code responsible |
||
6698 | ** for setting pointer-map entries. |
||
6699 | */ |
||
6700 | static int ptrmapCheckPages(MemPage **apPage, int nPage){ |
||
6701 | int i, j; |
||
6702 | for(i=0; i<nPage; i++){ |
||
6703 | Pgno n; |
||
6704 | u8 e; |
||
6705 | MemPage pPage = apPage[i]; |
||
6706 | BtShared pBt = pPage.pBt; |
||
6707 | Debug.Assert( pPage.isInit!=0 ); |
||
6708 | |||
6709 | for(j=0; j<pPage.nCell; j++){ |
||
6710 | CellInfo info; |
||
6711 | u8 *z; |
||
6712 | |||
6713 | z = findCell(pPage, j); |
||
6714 | btreeParseCellPtr(pPage, z, info); |
||
6715 | if( info.iOverflow ){ |
||
6716 | Pgno ovfl = sqlite3Get4byte(z[info.iOverflow]); |
||
6717 | ptrmapGet(pBt, ovfl, ref e, ref n); |
||
6718 | Debug.Assert( n==pPage.pgno && e==PTRMAP_OVERFLOW1 ); |
||
6719 | } |
||
6720 | if( 0==pPage.leaf ){ |
||
6721 | Pgno child = sqlite3Get4byte(z); |
||
6722 | ptrmapGet(pBt, child, ref e, ref n); |
||
6723 | Debug.Assert( n==pPage.pgno && e==PTRMAP_BTREE ); |
||
6724 | } |
||
6725 | } |
||
6726 | if( 0==pPage.leaf ){ |
||
6727 | Pgno child = sqlite3Get4byte(pPage.aData,pPage.hdrOffset+8]); |
||
6728 | ptrmapGet(pBt, child, ref e, ref n); |
||
6729 | Debug.Assert( n==pPage.pgno && e==PTRMAP_BTREE ); |
||
6730 | } |
||
6731 | } |
||
6732 | return 1; |
||
6733 | } |
||
6734 | #endif |
||
6735 | |||
6736 | /* |
||
6737 | ** This function is used to copy the contents of the b-tree node stored |
||
6738 | ** on page pFrom to page pTo. If page pFrom was not a leaf page, then |
||
6739 | ** the pointer-map entries for each child page are updated so that the |
||
6740 | ** parent page stored in the pointer map is page pTo. If pFrom contained |
||
6741 | ** any cells with overflow page pointers, then the corresponding pointer |
||
6742 | ** map entries are also updated so that the parent page is page pTo. |
||
6743 | ** |
||
6744 | ** If pFrom is currently carrying any overflow cells (entries in the |
||
6745 | ** MemPage.aOvfl[] array), they are not copied to pTo. |
||
6746 | ** |
||
6747 | ** Before returning, page pTo is reinitialized using btreeInitPage(). |
||
6748 | ** |
||
6749 | ** The performance of this function is not critical. It is only used by |
||
6750 | ** the balance_shallower() and balance_deeper() procedures, neither of |
||
6751 | ** which are called often under normal circumstances. |
||
6752 | */ |
||
6753 | static void copyNodeContent( MemPage pFrom, MemPage pTo, ref int pRC ) |
||
6754 | { |
||
6755 | if ( ( pRC ) == SQLITE_OK ) |
||
6756 | { |
||
6757 | BtShared pBt = pFrom.pBt; |
||
6758 | u8[] aFrom = pFrom.aData; |
||
6759 | u8[] aTo = pTo.aData; |
||
6760 | int iFromHdr = pFrom.hdrOffset; |
||
6761 | int iToHdr = ( ( pTo.pgno == 1 ) ? 100 : 0 ); |
||
6762 | int rc; |
||
6763 | int iData; |
||
6764 | |||
6765 | |||
6766 | Debug.Assert( pFrom.isInit != 0 ); |
||
6767 | Debug.Assert( pFrom.nFree >= iToHdr ); |
||
6768 | Debug.Assert( get2byte( aFrom, iFromHdr + 5 ) <= (int)pBt.usableSize ); |
||
6769 | |||
6770 | /* Copy the b-tree node content from page pFrom to page pTo. */ |
||
6771 | iData = get2byte( aFrom, iFromHdr + 5 ); |
||
6772 | Buffer.BlockCopy( aFrom, iData, aTo, iData, (int)pBt.usableSize - iData );//memcpy(aTo[iData], ref aFrom[iData], pBt.usableSize-iData); |
||
6773 | Buffer.BlockCopy( aFrom, iFromHdr, aTo, iToHdr, pFrom.cellOffset + 2 * pFrom.nCell );//memcpy(aTo[iToHdr], ref aFrom[iFromHdr], pFrom.cellOffset + 2*pFrom.nCell); |
||
6774 | |||
6775 | /* Reinitialize page pTo so that the contents of the MemPage structure |
||
6776 | ** match the new data. The initialization of pTo can actually fail under |
||
6777 | ** fairly obscure circumstances, even though it is a copy of initialized |
||
6778 | ** page pFrom. |
||
6779 | */ |
||
6780 | pTo.isInit = 0; |
||
6781 | rc = btreeInitPage( pTo ); |
||
6782 | if ( rc != SQLITE_OK ) |
||
6783 | { |
||
6784 | pRC = rc; |
||
6785 | return; |
||
6786 | } |
||
6787 | |||
6788 | /* If this is an auto-vacuum database, update the pointer-map entries |
||
6789 | ** for any b-tree or overflow pages that pTo now contains the pointers to. |
||
6790 | */ |
||
6791 | #if !SQLITE_OMIT_AUTOVACUUM // if ( ISAUTOVACUUM ) |
||
6792 | if ( pBt.autoVacuum ) |
||
6793 | #else |
||
6794 | if (false) |
||
6795 | #endif |
||
6796 | { |
||
6797 | pRC = setChildPtrmaps( pTo ); |
||
6798 | } |
||
6799 | } |
||
6800 | } |
||
6801 | |||
6802 | /* |
||
6803 | ** This routine redistributes cells on the iParentIdx'th child of pParent |
||
6804 | ** (hereafter "the page") and up to 2 siblings so that all pages have about the |
||
6805 | ** same amount of free space. Usually a single sibling on either side of the |
||
6806 | ** page are used in the balancing, though both siblings might come from one |
||
6807 | ** side if the page is the first or last child of its parent. If the page |
||
6808 | ** has fewer than 2 siblings (something which can only happen if the page |
||
6809 | ** is a root page or a child of a root page) then all available siblings |
||
6810 | ** participate in the balancing. |
||
6811 | ** |
||
6812 | ** The number of siblings of the page might be increased or decreased by |
||
6813 | ** one or two in an effort to keep pages nearly full but not over full. |
||
6814 | ** |
||
6815 | ** Note that when this routine is called, some of the cells on the page |
||
6816 | ** might not actually be stored in MemPage.aData[]. This can happen |
||
6817 | ** if the page is overfull. This routine ensures that all cells allocated |
||
6818 | ** to the page and its siblings fit into MemPage.aData[] before returning. |
||
6819 | ** |
||
6820 | ** In the course of balancing the page and its siblings, cells may be |
||
6821 | ** inserted into or removed from the parent page (pParent). Doing so |
||
6822 | ** may cause the parent page to become overfull or underfull. If this |
||
6823 | ** happens, it is the responsibility of the caller to invoke the correct |
||
6824 | ** balancing routine to fix this problem (see the balance() routine). |
||
6825 | ** |
||
6826 | ** If this routine fails for any reason, it might leave the database |
||
6827 | ** in a corrupted state. So if this routine fails, the database should |
||
6828 | ** be rolled back. |
||
6829 | ** |
||
6830 | ** The third argument to this function, aOvflSpace, is a pointer to a |
||
6831 | ** buffer big enough to hold one page. If while inserting cells into the parent |
||
6832 | ** page (pParent) the parent page becomes overfull, this buffer is |
||
6833 | ** used to store the parent's overflow cells. Because this function inserts |
||
6834 | ** a maximum of four divider cells into the parent page, and the maximum |
||
6835 | ** size of a cell stored within an internal node is always less than 1/4 |
||
6836 | ** of the page-size, the aOvflSpace[] buffer is guaranteed to be large |
||
6837 | ** enough for all overflow cells. |
||
6838 | ** |
||
6839 | ** If aOvflSpace is set to a null pointer, this function returns |
||
6840 | ** SQLITE_NOMEM. |
||
6841 | */ |
||
6842 | |||
6843 | // under C#; Try to reuse Memory |
||
6844 | |||
6845 | static int balance_nonroot( |
||
6846 | MemPage pParent, /* Parent page of siblings being balanced */ |
||
6847 | int iParentIdx, /* Index of "the page" in pParent */ |
||
6848 | u8[] aOvflSpace, /* page-size bytes of space for parent ovfl */ |
||
6849 | int isRoot /* True if pParent is a root-page */ |
||
6850 | ) |
||
6851 | { |
||
6852 | MemPage[] apOld = new MemPage[NB]; /* pPage and up to two siblings */ |
||
6853 | MemPage[] apCopy = new MemPage[NB]; /* Private copies of apOld[] pages */ |
||
6854 | MemPage[] apNew = new MemPage[NB + 2];/* pPage and up to NB siblings after balancing */ |
||
6855 | int[] apDiv = new int[NB - 1]; /* Divider cells in pParent */ |
||
6856 | int[] cntNew = new int[NB + 2]; /* Index in aCell[] of cell after i-th page */ |
||
6857 | int[] szNew = new int[NB + 2]; /* Combined size of cells place on i-th page */ |
||
6858 | u16[] szCell = new u16[1]; /* Local size of all cells in apCell[] */ |
||
6859 | BtShared pBt; /* The whole database */ |
||
6860 | int nCell = 0; /* Number of cells in apCell[] */ |
||
6861 | int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ |
||
6862 | int nNew = 0; /* Number of pages in apNew[] */ |
||
6863 | int nOld; /* Number of pages in apOld[] */ |
||
6864 | int i, j, k; /* Loop counters */ |
||
6865 | int nxDiv; /* Next divider slot in pParent.aCell[] */ |
||
6866 | int rc = SQLITE_OK; /* The return code */ |
||
6867 | u16 leafCorrection; /* 4 if pPage is a leaf. 0 if not */ |
||
6868 | int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ |
||
6869 | int usableSpace; /* Bytes in pPage beyond the header */ |
||
6870 | int pageFlags; /* Value of pPage.aData[0] */ |
||
6871 | int subtotal; /* Subtotal of bytes in cells on one page */ |
||
6872 | //int iSpace1 = 0; /* First unused byte of aSpace1[] */ |
||
6873 | int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ |
||
6874 | int szScratch; /* Size of scratch memory requested */ |
||
6875 | int pRight; /* Location in parent of right-sibling pointer */ |
||
6876 | u8[][] apCell = null; /* All cells begin balanced */ |
||
6877 | //u16[] szCell; /* Local size of all cells in apCell[] */ |
||
6878 | //u8[] aSpace1; /* Space for copies of dividers cells */ |
||
6879 | Pgno pgno; /* Temp var to store a page number in */ |
||
6880 | |||
6881 | pBt = pParent.pBt; |
||
6882 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
6883 | Debug.Assert( sqlite3PagerIswriteable( pParent.pDbPage ) ); |
||
6884 | |||
6885 | #if FALSE |
||
6886 | TRACE("BALANCE: begin page %d child of %d\n", pPage.pgno, pParent.pgno); |
||
6887 | #endif |
||
6888 | |||
6889 | /* At this point pParent may have at most one overflow cell. And if |
||
6890 | ** this overflow cell is present, it must be the cell with |
||
6891 | ** index iParentIdx. This scenario comes about when this function |
||
6892 | ** is called (indirectly) from sqlite3BtreeDelete(). |
||
6893 | */ |
||
6894 | Debug.Assert( pParent.nOverflow == 0 || pParent.nOverflow == 1 ); |
||
6895 | Debug.Assert( pParent.nOverflow == 0 || pParent.aOvfl[0].idx == iParentIdx ); |
||
6896 | |||
6897 | //if( !aOvflSpace ){ |
||
6898 | // return SQLITE_NOMEM; |
||
6899 | //} |
||
6900 | |||
6901 | /* Find the sibling pages to balance. Also locate the cells in pParent |
||
6902 | ** that divide the siblings. An attempt is made to find NN siblings on |
||
6903 | ** either side of pPage. More siblings are taken from one side, however, |
||
6904 | ** if there are fewer than NN siblings on the other side. If pParent |
||
6905 | ** has NB or fewer children then all children of pParent are taken. |
||
6906 | ** |
||
6907 | ** This loop also drops the divider cells from the parent page. This |
||
6908 | ** way, the remainder of the function does not have to deal with any |
||
6909 | ** overflow cells in the parent page, since if any existed they will |
||
6910 | ** have already been removed. |
||
6911 | */ |
||
6912 | i = pParent.nOverflow + pParent.nCell; |
||
6913 | if ( i < 2 ) |
||
6914 | { |
||
6915 | nxDiv = 0; |
||
6916 | nOld = i + 1; |
||
6917 | } |
||
6918 | else |
||
6919 | { |
||
6920 | nOld = 3; |
||
6921 | if ( iParentIdx == 0 ) |
||
6922 | { |
||
6923 | nxDiv = 0; |
||
6924 | } |
||
6925 | else if ( iParentIdx == i ) |
||
6926 | { |
||
6927 | nxDiv = i - 2; |
||
6928 | } |
||
6929 | else |
||
6930 | { |
||
6931 | nxDiv = iParentIdx - 1; |
||
6932 | } |
||
6933 | i = 2; |
||
6934 | } |
||
6935 | if ( ( i + nxDiv - pParent.nOverflow ) == pParent.nCell ) |
||
6936 | { |
||
6937 | pRight = pParent.hdrOffset + 8; //&pParent.aData[pParent.hdrOffset + 8]; |
||
6938 | } |
||
6939 | else |
||
6940 | { |
||
6941 | pRight = findCell( pParent, i + nxDiv - pParent.nOverflow ); |
||
6942 | } |
||
6943 | pgno = sqlite3Get4byte( pParent.aData, pRight ); |
||
6944 | while ( true ) |
||
6945 | { |
||
6946 | rc = getAndInitPage( pBt, pgno, ref apOld[i] ); |
||
6947 | if ( rc != 0 ) |
||
6948 | { |
||
6949 | //memset(apOld, 0, (i+1)*sizeof(MemPage*)); |
||
6950 | goto balance_cleanup; |
||
6951 | } |
||
6952 | nMaxCells += 1 + apOld[i].nCell + apOld[i].nOverflow; |
||
6953 | if ( ( i-- ) == 0 ) |
||
6954 | break; |
||
6955 | |||
6956 | if ( i + nxDiv == pParent.aOvfl[0].idx && pParent.nOverflow != 0 ) |
||
6957 | { |
||
6958 | apDiv[i] = 0;// = pParent.aOvfl[0].pCell; |
||
6959 | pgno = sqlite3Get4byte( pParent.aOvfl[0].pCell, apDiv[i] ); |
||
6960 | szNew[i] = cellSizePtr( pParent, apDiv[i] ); |
||
6961 | pParent.nOverflow = 0; |
||
6962 | } |
||
6963 | else |
||
6964 | { |
||
6965 | apDiv[i] = findCell( pParent, i + nxDiv - pParent.nOverflow ); |
||
6966 | pgno = sqlite3Get4byte( pParent.aData, apDiv[i] ); |
||
6967 | szNew[i] = cellSizePtr( pParent, apDiv[i] ); |
||
6968 | |||
6969 | /* Drop the cell from the parent page. apDiv[i] still points to |
||
6970 | ** the cell within the parent, even though it has been dropped. |
||
6971 | ** This is safe because dropping a cell only overwrites the first |
||
6972 | ** four bytes of it, and this function does not need the first |
||
6973 | ** four bytes of the divider cell. So the pointer is safe to use |
||
6974 | ** later on. |
||
6975 | ** |
||
6976 | ** Unless SQLite is compiled in secure-delete mode. In this case, |
||
6977 | ** the dropCell() routine will overwrite the entire cell with zeroes. |
||
6978 | ** In this case, temporarily copy the cell into the aOvflSpace[] |
||
6979 | ** buffer. It will be copied out again as soon as the aSpace[] buffer |
||
6980 | ** is allocated. */ |
||
6981 | //if (pBt.secureDelete) |
||
6982 | //{ |
||
6983 | // int iOff = (int)(apDiv[i]) - (int)(pParent.aData); //SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent.aData); |
||
6984 | // if( (iOff+szNew[i])>(int)pBt->usableSize ) |
||
6985 | // { |
||
6986 | // rc = SQLITE_CORRUPT_BKPT(); |
||
6987 | // Array.Clear(apOld[0].aData,0,apOld[0].aData.Length); //memset(apOld, 0, (i + 1) * sizeof(MemPage*)); |
||
6988 | // goto balance_cleanup; |
||
6989 | // } |
||
6990 | // else |
||
6991 | // { |
||
6992 | // memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]); |
||
6993 | // apDiv[i] = &aOvflSpace[apDiv[i] - pParent.aData]; |
||
6994 | // } |
||
6995 | //} |
||
6996 | dropCell( pParent, i + nxDiv - pParent.nOverflow, szNew[i], ref rc ); |
||
6997 | } |
||
6998 | } |
||
6999 | |||
7000 | /* Make nMaxCells a multiple of 4 in order to preserve 8-byte |
||
7001 | ** alignment */ |
||
7002 | nMaxCells = ( nMaxCells + 3 ) & ~3; |
||
7003 | |||
7004 | /* |
||
7005 | ** Allocate space for memory structures |
||
7006 | */ |
||
7007 | //k = pBt.pageSize + ROUND8(sizeof(MemPage)); |
||
7008 | //szScratch = |
||
7009 | // nMaxCells*sizeof(u8*) /* apCell */ |
||
7010 | // + nMaxCells*sizeof(u16) /* szCell */ |
||
7011 | // + pBt.pageSize /* aSpace1 */ |
||
7012 | // + k*nOld; /* Page copies (apCopy) */ |
||
7013 | apCell = sqlite3ScratchMalloc( apCell, nMaxCells ); |
||
7014 | //if( apCell==null ){ |
||
7015 | // rc = SQLITE_NOMEM; |
||
7016 | // goto balance_cleanup; |
||
7017 | //} |
||
7018 | if ( szCell.Length < nMaxCells ) |
||
7019 | Array.Resize( ref szCell, nMaxCells ); //(u16*)&apCell[nMaxCells]; |
||
7020 | //aSpace1 = new byte[pBt.pageSize * (nMaxCells)];// aSpace1 = (u8*)&szCell[nMaxCells]; |
||
7021 | //Debug.Assert( EIGHT_BYTE_ALIGNMENT(aSpace1) ); |
||
7022 | |||
7023 | /* |
||
7024 | ** Load pointers to all cells on sibling pages and the divider cells |
||
7025 | ** into the local apCell[] array. Make copies of the divider cells |
||
7026 | ** into space obtained from aSpace1[] and remove the the divider Cells |
||
7027 | ** from pParent. |
||
7028 | ** |
||
7029 | ** If the siblings are on leaf pages, then the child pointers of the |
||
7030 | ** divider cells are stripped from the cells before they are copied |
||
7031 | ** into aSpace1[]. In this way, all cells in apCell[] are without |
||
7032 | ** child pointers. If siblings are not leaves, then all cell in |
||
7033 | ** apCell[] include child pointers. Either way, all cells in apCell[] |
||
7034 | ** are alike. |
||
7035 | ** |
||
7036 | ** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf. |
||
7037 | ** leafData: 1 if pPage holds key+data and pParent holds only keys. |
||
7038 | */ |
||
7039 | leafCorrection = (u16)( apOld[0].leaf * 4 ); |
||
7040 | leafData = apOld[0].hasData; |
||
7041 | for ( i = 0; i < nOld; i++ ) |
||
7042 | { |
||
7043 | int limit; |
||
7044 | |||
7045 | /* Before doing anything else, take a copy of the i'th original sibling |
||
7046 | ** The rest of this function will use data from the copies rather |
||
7047 | ** that the original pages since the original pages will be in the |
||
7048 | ** process of being overwritten. */ |
||
7049 | //MemPage pOld = apCopy[i] = (MemPage*)&aSpace1[pBt.pageSize + k*i]; |
||
7050 | //memcpy(pOld, apOld[i], sizeof(MemPage)); |
||
7051 | //pOld.aData = (void*)&pOld[1]; |
||
7052 | //memcpy(pOld.aData, apOld[i].aData, pBt.pageSize); |
||
7053 | MemPage pOld = apCopy[i] = apOld[i].Copy(); |
||
7054 | |||
7055 | limit = pOld.nCell + pOld.nOverflow; |
||
7056 | if( pOld.nOverflow>0 || true){ |
||
7057 | for ( j = 0; j < limit; j++ ) |
||
7058 | { |
||
7059 | Debug.Assert( nCell < nMaxCells ); |
||
7060 | //apCell[nCell] = findOverflowCell( pOld, j ); |
||
7061 | //szCell[nCell] = cellSizePtr( pOld, apCell, nCell ); |
||
7062 | int iFOFC = findOverflowCell( pOld, j ); |
||
7063 | szCell[nCell] = cellSizePtr( pOld, iFOFC ); |
||
7064 | // Copy the Data Locally |
||
7065 | if ( apCell[nCell] == null ) |
||
7066 | apCell[nCell] = new u8[szCell[nCell]]; |
||
7067 | else if ( apCell[nCell].Length < szCell[nCell] ) |
||
7068 | Array.Resize( ref apCell[nCell], szCell[nCell] ); |
||
7069 | if ( iFOFC < 0 ) // Overflow Cell |
||
7070 | Buffer.BlockCopy( pOld.aOvfl[-( iFOFC + 1 )].pCell, 0, apCell[nCell], 0, szCell[nCell] ); |
||
7071 | else |
||
7072 | Buffer.BlockCopy( pOld.aData, iFOFC, apCell[nCell], 0, szCell[nCell] ); |
||
7073 | nCell++; |
||
7074 | } |
||
7075 | } |
||
7076 | else |
||
7077 | { |
||
7078 | u8[] aData = pOld.aData; |
||
7079 | u16 maskPage = pOld.maskPage; |
||
7080 | u16 cellOffset = pOld.cellOffset; |
||
7081 | for ( j = 0; j < limit; j++ ) |
||
7082 | { |
||
7083 | Debugger.Break(); |
||
7084 | Debug.Assert( nCell < nMaxCells ); |
||
7085 | apCell[nCell] = findCellv2( aData, maskPage, cellOffset, j ); |
||
7086 | szCell[nCell] = cellSizePtr( pOld, apCell[nCell] ); |
||
7087 | nCell++; |
||
7088 | } |
||
7089 | } |
||
7090 | if ( i < nOld - 1 && 0 == leafData ) |
||
7091 | { |
||
7092 | u16 sz = (u16)szNew[i]; |
||
7093 | byte[] pTemp = sqlite3Malloc( sz + leafCorrection ); |
||
7094 | Debug.Assert( nCell < nMaxCells ); |
||
7095 | szCell[nCell] = sz; |
||
7096 | //pTemp = &aSpace1[iSpace1]; |
||
7097 | //iSpace1 += sz; |
||
7098 | Debug.Assert( sz <= pBt.maxLocal + 23 ); |
||
7099 | //Debug.Assert(iSpace1 <= (int)pBt.pageSize); |
||
7100 | Buffer.BlockCopy( pParent.aData, apDiv[i], pTemp, 0, sz );//memcpy( pTemp, apDiv[i], sz ); |
||
7101 | if ( apCell[nCell] == null || apCell[nCell].Length < sz ) |
||
7102 | Array.Resize( ref apCell[nCell], sz ); |
||
7103 | Buffer.BlockCopy( pTemp, leafCorrection, apCell[nCell], 0, sz );//apCell[nCell] = pTemp + leafCorrection; |
||
7104 | Debug.Assert( leafCorrection == 0 || leafCorrection == 4 ); |
||
7105 | szCell[nCell] = (u16)( szCell[nCell] - leafCorrection ); |
||
7106 | if ( 0 == pOld.leaf ) |
||
7107 | { |
||
7108 | Debug.Assert( leafCorrection == 0 ); |
||
7109 | Debug.Assert( pOld.hdrOffset == 0 ); |
||
7110 | /* The right pointer of the child page pOld becomes the left |
||
7111 | ** pointer of the divider cell */ |
||
7112 | Buffer.BlockCopy( pOld.aData, 8, apCell[nCell], 0, 4 );//memcpy( apCell[nCell], ref pOld.aData[8], 4 ); |
||
7113 | } |
||
7114 | else |
||
7115 | { |
||
7116 | Debug.Assert( leafCorrection == 4 ); |
||
7117 | if ( szCell[nCell] < 4 ) |
||
7118 | { |
||
7119 | /* Do not allow any cells smaller than 4 bytes. */ |
||
7120 | szCell[nCell] = 4; |
||
7121 | } |
||
7122 | } |
||
7123 | nCell++; |
||
7124 | } |
||
7125 | } |
||
7126 | |||
7127 | /* |
||
7128 | ** Figure out the number of pages needed to hold all nCell cells. |
||
7129 | ** Store this number in "k". Also compute szNew[] which is the total |
||
7130 | ** size of all cells on the i-th page and cntNew[] which is the index |
||
7131 | ** in apCell[] of the cell that divides page i from page i+1. |
||
7132 | ** cntNew[k] should equal nCell. |
||
7133 | ** |
||
7134 | ** Values computed by this block: |
||
7135 | ** |
||
7136 | ** k: The total number of sibling pages |
||
7137 | ** szNew[i]: Spaced used on the i-th sibling page. |
||
7138 | ** cntNew[i]: Index in apCell[] and szCell[] for the first cell to |
||
7139 | ** the right of the i-th sibling page. |
||
7140 | ** usableSpace: Number of bytes of space available on each sibling. |
||
7141 | ** |
||
7142 | */ |
||
7143 | usableSpace = (int)pBt.usableSize - 12 + leafCorrection; |
||
7144 | for ( subtotal = k = i = 0; i < nCell; i++ ) |
||
7145 | { |
||
7146 | Debug.Assert( i < nMaxCells ); |
||
7147 | subtotal += szCell[i] + 2; |
||
7148 | if ( subtotal > usableSpace ) |
||
7149 | { |
||
7150 | szNew[k] = subtotal - szCell[i]; |
||
7151 | cntNew[k] = i; |
||
7152 | if ( leafData != 0 ) |
||
7153 | { |
||
7154 | i--; |
||
7155 | } |
||
7156 | subtotal = 0; |
||
7157 | k++; |
||
7158 | if ( k > NB + 1 ) |
||
7159 | { |
||
7160 | rc = SQLITE_CORRUPT_BKPT(); |
||
7161 | goto balance_cleanup; |
||
7162 | } |
||
7163 | } |
||
7164 | } |
||
7165 | szNew[k] = subtotal; |
||
7166 | cntNew[k] = nCell; |
||
7167 | k++; |
||
7168 | |||
7169 | /* |
||
7170 | ** The packing computed by the previous block is biased toward the siblings |
||
7171 | ** on the left side. The left siblings are always nearly full, while the |
||
7172 | ** right-most sibling might be nearly empty. This block of code attempts |
||
7173 | ** to adjust the packing of siblings to get a better balance. |
||
7174 | ** |
||
7175 | ** This adjustment is more than an optimization. The packing above might |
||
7176 | ** be so out of balance as to be illegal. For example, the right-most |
||
7177 | ** sibling might be completely empty. This adjustment is not optional. |
||
7178 | */ |
||
7179 | for ( i = k - 1; i > 0; i-- ) |
||
7180 | { |
||
7181 | int szRight = szNew[i]; /* Size of sibling on the right */ |
||
7182 | int szLeft = szNew[i - 1]; /* Size of sibling on the left */ |
||
7183 | int r; /* Index of right-most cell in left sibling */ |
||
7184 | int d; /* Index of first cell to the left of right sibling */ |
||
7185 | |||
7186 | r = cntNew[i - 1] - 1; |
||
7187 | d = r + 1 - leafData; |
||
7188 | Debug.Assert( d < nMaxCells ); |
||
7189 | Debug.Assert( r < nMaxCells ); |
||
7190 | while ( szRight == 0 || szRight + szCell[d] + 2 <= szLeft - ( szCell[r] + 2 ) ) |
||
7191 | { |
||
7192 | szRight += szCell[d] + 2; |
||
7193 | szLeft -= szCell[r] + 2; |
||
7194 | cntNew[i - 1]--; |
||
7195 | r = cntNew[i - 1] - 1; |
||
7196 | d = r + 1 - leafData; |
||
7197 | } |
||
7198 | szNew[i] = szRight; |
||
7199 | szNew[i - 1] = szLeft; |
||
7200 | } |
||
7201 | |||
7202 | /* Either we found one or more cells (cntnew[0])>0) or pPage is |
||
7203 | ** a virtual root page. A virtual root page is when the real root |
||
7204 | ** page is page 1 and we are the only child of that page. |
||
7205 | */ |
||
7206 | Debug.Assert( cntNew[0] > 0 || ( pParent.pgno == 1 && pParent.nCell == 0 ) ); |
||
7207 | |||
7208 | TRACE( "BALANCE: old: %d %d %d ", |
||
7209 | apOld[0].pgno, |
||
7210 | nOld >= 2 ? apOld[1].pgno : 0, |
||
7211 | nOld >= 3 ? apOld[2].pgno : 0 |
||
7212 | ); |
||
7213 | |||
7214 | /* |
||
7215 | ** Allocate k new pages. Reuse old pages where possible. |
||
7216 | */ |
||
7217 | if ( apOld[0].pgno <= 1 ) |
||
7218 | { |
||
7219 | rc = SQLITE_CORRUPT_BKPT(); |
||
7220 | goto balance_cleanup; |
||
7221 | } |
||
7222 | pageFlags = apOld[0].aData[0]; |
||
7223 | for ( i = 0; i < k; i++ ) |
||
7224 | { |
||
7225 | MemPage pNew = new MemPage(); |
||
7226 | if ( i < nOld ) |
||
7227 | { |
||
7228 | pNew = apNew[i] = apOld[i]; |
||
7229 | apOld[i] = null; |
||
7230 | rc = sqlite3PagerWrite( pNew.pDbPage ); |
||
7231 | nNew++; |
||
7232 | if ( rc != 0 ) |
||
7233 | goto balance_cleanup; |
||
7234 | } |
||
7235 | else |
||
7236 | { |
||
7237 | Debug.Assert( i > 0 ); |
||
7238 | rc = allocateBtreePage( pBt, ref pNew, ref pgno, pgno, 0 ); |
||
7239 | if ( rc != 0 ) |
||
7240 | goto balance_cleanup; |
||
7241 | apNew[i] = pNew; |
||
7242 | nNew++; |
||
7243 | |||
7244 | /* Set the pointer-map entry for the new sibling page. */ |
||
7245 | #if !SQLITE_OMIT_AUTOVACUUM // if ( ISAUTOVACUUM ) |
||
7246 | if ( pBt.autoVacuum ) |
||
7247 | #else |
||
7248 | if (false) |
||
7249 | #endif |
||
7250 | { |
||
7251 | ptrmapPut( pBt, pNew.pgno, PTRMAP_BTREE, pParent.pgno, ref rc ); |
||
7252 | if ( rc != SQLITE_OK ) |
||
7253 | { |
||
7254 | goto balance_cleanup; |
||
7255 | } |
||
7256 | } |
||
7257 | } |
||
7258 | } |
||
7259 | |||
7260 | /* Free any old pages that were not reused as new pages. |
||
7261 | */ |
||
7262 | while ( i < nOld ) |
||
7263 | { |
||
7264 | freePage( apOld[i], ref rc ); |
||
7265 | if ( rc != 0 ) |
||
7266 | goto balance_cleanup; |
||
7267 | releasePage( apOld[i] ); |
||
7268 | apOld[i] = null; |
||
7269 | i++; |
||
7270 | } |
||
7271 | |||
7272 | /* |
||
7273 | ** Put the new pages in accending order. This helps to |
||
7274 | ** keep entries in the disk file in order so that a scan |
||
7275 | ** of the table is a linear scan through the file. That |
||
7276 | ** in turn helps the operating system to deliver pages |
||
7277 | ** from the disk more rapidly. |
||
7278 | ** |
||
7279 | ** An O(n^2) insertion sort algorithm is used, but since |
||
7280 | ** n is never more than NB (a small constant), that should |
||
7281 | ** not be a problem. |
||
7282 | ** |
||
7283 | ** When NB==3, this one optimization makes the database |
||
7284 | ** about 25% faster for large insertions and deletions. |
||
7285 | */ |
||
7286 | for ( i = 0; i < k - 1; i++ ) |
||
7287 | { |
||
7288 | int minV = (int)apNew[i].pgno; |
||
7289 | int minI = i; |
||
7290 | for ( j = i + 1; j < k; j++ ) |
||
7291 | { |
||
7292 | if ( apNew[j].pgno < (u32)minV ) |
||
7293 | { |
||
7294 | minI = j; |
||
7295 | minV = (int)apNew[j].pgno; |
||
7296 | } |
||
7297 | } |
||
7298 | if ( minI > i ) |
||
7299 | { |
||
7300 | MemPage pT; |
||
7301 | pT = apNew[i]; |
||
7302 | apNew[i] = apNew[minI]; |
||
7303 | apNew[minI] = pT; |
||
7304 | } |
||
7305 | } |
||
7306 | TRACE( "new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n", |
||
7307 | apNew[0].pgno, szNew[0], |
||
7308 | nNew >= 2 ? apNew[1].pgno : 0, nNew >= 2 ? szNew[1] : 0, |
||
7309 | nNew >= 3 ? apNew[2].pgno : 0, nNew >= 3 ? szNew[2] : 0, |
||
7310 | nNew >= 4 ? apNew[3].pgno : 0, nNew >= 4 ? szNew[3] : 0, |
||
7311 | nNew >= 5 ? apNew[4].pgno : 0, nNew >= 5 ? szNew[4] : 0 ); |
||
7312 | |||
7313 | Debug.Assert( sqlite3PagerIswriteable( pParent.pDbPage ) ); |
||
7314 | sqlite3Put4byte( pParent.aData, pRight, apNew[nNew - 1].pgno ); |
||
7315 | |||
7316 | /* |
||
7317 | ** Evenly distribute the data in apCell[] across the new pages. |
||
7318 | ** Insert divider cells into pParent as necessary. |
||
7319 | */ |
||
7320 | j = 0; |
||
7321 | for ( i = 0; i < nNew; i++ ) |
||
7322 | { |
||
7323 | /* Assemble the new sibling page. */ |
||
7324 | MemPage pNew = apNew[i]; |
||
7325 | Debug.Assert( j < nMaxCells ); |
||
7326 | zeroPage( pNew, pageFlags ); |
||
7327 | assemblePage( pNew, cntNew[i] - j, apCell, szCell, j ); |
||
7328 | Debug.Assert( pNew.nCell > 0 || ( nNew == 1 && cntNew[0] == 0 ) ); |
||
7329 | Debug.Assert( pNew.nOverflow == 0 ); |
||
7330 | |||
7331 | j = cntNew[i]; |
||
7332 | |||
7333 | /* If the sibling page assembled above was not the right-most sibling, |
||
7334 | ** insert a divider cell into the parent page. |
||
7335 | */ |
||
7336 | Debug.Assert( i < nNew - 1 || j == nCell ); |
||
7337 | if ( j < nCell ) |
||
7338 | { |
||
7339 | u8[] pCell; |
||
7340 | u8[] pTemp; |
||
7341 | int sz; |
||
7342 | |||
7343 | Debug.Assert( j < nMaxCells ); |
||
7344 | pCell = apCell[j]; |
||
7345 | sz = szCell[j] + leafCorrection; |
||
7346 | pTemp = sqlite3Malloc( sz );//&aOvflSpace[iOvflSpace]; |
||
7347 | if ( 0 == pNew.leaf ) |
||
7348 | { |
||
7349 | Buffer.BlockCopy( pCell, 0, pNew.aData, 8, 4 );//memcpy( pNew.aData[8], pCell, 4 ); |
||
7350 | } |
||
7351 | else if ( leafData != 0 ) |
||
7352 | { |
||
7353 | /* If the tree is a leaf-data tree, and the siblings are leaves, |
||
7354 | ** then there is no divider cell in apCell[]. Instead, the divider |
||
7355 | ** cell consists of the integer key for the right-most cell of |
||
7356 | ** the sibling-page assembled above only. |
||
7357 | */ |
||
7358 | CellInfo info = new CellInfo(); |
||
7359 | j--; |
||
7360 | btreeParseCellPtr( pNew, apCell[j], ref info ); |
||
7361 | pCell = pTemp; |
||
7362 | sz = 4 + putVarint( pCell, 4, (u64)info.nKey ); |
||
7363 | pTemp = null; |
||
7364 | } |
||
7365 | else |
||
7366 | { |
||
7367 | //------------ pCell -= 4; |
||
7368 | byte[] _pCell_4 = sqlite3Malloc( pCell.Length + 4 ); |
||
7369 | Buffer.BlockCopy( pCell, 0, _pCell_4, 4, pCell.Length ); |
||
7370 | pCell = _pCell_4; |
||
7371 | // |
||
7372 | /* Obscure case for non-leaf-data trees: If the cell at pCell was |
||
7373 | ** previously stored on a leaf node, and its reported size was 4 |
||
7374 | ** bytes, then it may actually be smaller than this |
||
7375 | ** (see btreeParseCellPtr(), 4 bytes is the minimum size of |
||
7376 | ** any cell). But it is important to pass the correct size to |
||
7377 | ** insertCell(), so reparse the cell now. |
||
7378 | ** |
||
7379 | ** Note that this can never happen in an SQLite data file, as all |
||
7380 | ** cells are at least 4 bytes. It only happens in b-trees used |
||
7381 | ** to evaluate "IN (SELECT ...)" and similar clauses. |
||
7382 | */ |
||
7383 | if ( szCell[j] == 4 ) |
||
7384 | { |
||
7385 | Debug.Assert( leafCorrection == 4 ); |
||
7386 | sz = cellSizePtr( pParent, pCell ); |
||
7387 | } |
||
7388 | } |
||
7389 | iOvflSpace += sz; |
||
7390 | Debug.Assert( sz <= pBt.maxLocal + 23 ); |
||
7391 | Debug.Assert( iOvflSpace <= (int)pBt.pageSize ); |
||
7392 | insertCell( pParent, nxDiv, pCell, sz, pTemp, pNew.pgno, ref rc ); |
||
7393 | if ( rc != SQLITE_OK ) |
||
7394 | goto balance_cleanup; |
||
7395 | Debug.Assert( sqlite3PagerIswriteable( pParent.pDbPage ) ); |
||
7396 | |||
7397 | j++; |
||
7398 | nxDiv++; |
||
7399 | } |
||
7400 | } |
||
7401 | Debug.Assert( j == nCell ); |
||
7402 | Debug.Assert( nOld > 0 ); |
||
7403 | Debug.Assert( nNew > 0 ); |
||
7404 | if ( ( pageFlags & PTF_LEAF ) == 0 ) |
||
7405 | { |
||
7406 | Buffer.BlockCopy( apCopy[nOld - 1].aData, 8, apNew[nNew - 1].aData, 8, 4 ); //u8* zChild = &apCopy[nOld - 1].aData[8]; |
||
7407 | //memcpy( apNew[nNew - 1].aData[8], zChild, 4 ); |
||
7408 | } |
||
7409 | |||
7410 | if ( isRoot != 0 && pParent.nCell == 0 && pParent.hdrOffset <= apNew[0].nFree ) |
||
7411 | { |
||
7412 | /* The root page of the b-tree now contains no cells. The only sibling |
||
7413 | ** page is the right-child of the parent. Copy the contents of the |
||
7414 | ** child page into the parent, decreasing the overall height of the |
||
7415 | ** b-tree structure by one. This is described as the "balance-shallower" |
||
7416 | ** sub-algorithm in some documentation. |
||
7417 | ** |
||
7418 | ** If this is an auto-vacuum database, the call to copyNodeContent() |
||
7419 | ** sets all pointer-map entries corresponding to database image pages |
||
7420 | ** for which the pointer is stored within the content being copied. |
||
7421 | ** |
||
7422 | ** The second Debug.Assert below verifies that the child page is defragmented |
||
7423 | ** (it must be, as it was just reconstructed using assemblePage()). This |
||
7424 | ** is important if the parent page happens to be page 1 of the database |
||
7425 | ** image. */ |
||
7426 | Debug.Assert( nNew == 1 ); |
||
7427 | Debug.Assert( apNew[0].nFree == |
||
7428 | ( get2byte( apNew[0].aData, 5 ) - apNew[0].cellOffset - apNew[0].nCell * 2 ) |
||
7429 | ); |
||
7430 | copyNodeContent( apNew[0], pParent, ref rc ); |
||
7431 | freePage( apNew[0], ref rc ); |
||
7432 | } |
||
7433 | else |
||
7434 | #if !SQLITE_OMIT_AUTOVACUUM // if ( ISAUTOVACUUM ) |
||
7435 | if ( pBt.autoVacuum ) |
||
7436 | #else |
||
7437 | if (false) |
||
7438 | #endif |
||
7439 | { |
||
7440 | /* Fix the pointer-map entries for all the cells that were shifted around. |
||
7441 | ** There are several different types of pointer-map entries that need to |
||
7442 | ** be dealt with by this routine. Some of these have been set already, but |
||
7443 | ** many have not. The following is a summary: |
||
7444 | ** |
||
7445 | ** 1) The entries associated with new sibling pages that were not |
||
7446 | ** siblings when this function was called. These have already |
||
7447 | ** been set. We don't need to worry about old siblings that were |
||
7448 | ** moved to the free-list - the freePage() code has taken care |
||
7449 | ** of those. |
||
7450 | ** |
||
7451 | ** 2) The pointer-map entries associated with the first overflow |
||
7452 | ** page in any overflow chains used by new divider cells. These |
||
7453 | ** have also already been taken care of by the insertCell() code. |
||
7454 | ** |
||
7455 | ** 3) If the sibling pages are not leaves, then the child pages of |
||
7456 | ** cells stored on the sibling pages may need to be updated. |
||
7457 | ** |
||
7458 | ** 4) If the sibling pages are not internal intkey nodes, then any |
||
7459 | ** overflow pages used by these cells may need to be updated |
||
7460 | ** (internal intkey nodes never contain pointers to overflow pages). |
||
7461 | ** |
||
7462 | ** 5) If the sibling pages are not leaves, then the pointer-map |
||
7463 | ** entries for the right-child pages of each sibling may need |
||
7464 | ** to be updated. |
||
7465 | ** |
||
7466 | ** Cases 1 and 2 are dealt with above by other code. The next |
||
7467 | ** block deals with cases 3 and 4 and the one after that, case 5. Since |
||
7468 | ** setting a pointer map entry is a relatively expensive operation, this |
||
7469 | ** code only sets pointer map entries for child or overflow pages that have |
||
7470 | ** actually moved between pages. */ |
||
7471 | MemPage pNew = apNew[0]; |
||
7472 | MemPage pOld = apCopy[0]; |
||
7473 | int nOverflow = pOld.nOverflow; |
||
7474 | int iNextOld = pOld.nCell + nOverflow; |
||
7475 | int iOverflow = ( nOverflow != 0 ? pOld.aOvfl[0].idx : -1 ); |
||
7476 | j = 0; /* Current 'old' sibling page */ |
||
7477 | k = 0; /* Current 'new' sibling page */ |
||
7478 | for ( i = 0; i < nCell; i++ ) |
||
7479 | { |
||
7480 | int isDivider = 0; |
||
7481 | while ( i == iNextOld ) |
||
7482 | { |
||
7483 | /* Cell i is the cell immediately following the last cell on old |
||
7484 | ** sibling page j. If the siblings are not leaf pages of an |
||
7485 | ** intkey b-tree, then cell i was a divider cell. */ |
||
7486 | pOld = apCopy[++j]; |
||
7487 | iNextOld = i + ( 0 == leafData ? 1 : 0 ) + pOld.nCell + pOld.nOverflow; |
||
7488 | if ( pOld.nOverflow != 0 ) |
||
7489 | { |
||
7490 | nOverflow = pOld.nOverflow; |
||
7491 | iOverflow = i + ( 0 == leafData ? 1 : 0 ) + pOld.aOvfl[0].idx; |
||
7492 | } |
||
7493 | isDivider = 0 == leafData ? 1 : 0; |
||
7494 | } |
||
7495 | |||
7496 | Debug.Assert( nOverflow > 0 || iOverflow < i ); |
||
7497 | Debug.Assert( nOverflow < 2 || pOld.aOvfl[0].idx == pOld.aOvfl[1].idx - 1 ); |
||
7498 | Debug.Assert( nOverflow < 3 || pOld.aOvfl[1].idx == pOld.aOvfl[2].idx - 1 ); |
||
7499 | if ( i == iOverflow ) |
||
7500 | { |
||
7501 | isDivider = 1; |
||
7502 | if ( ( --nOverflow ) > 0 ) |
||
7503 | { |
||
7504 | iOverflow++; |
||
7505 | } |
||
7506 | } |
||
7507 | |||
7508 | if ( i == cntNew[k] ) |
||
7509 | { |
||
7510 | /* Cell i is the cell immediately following the last cell on new |
||
7511 | ** sibling page k. If the siblings are not leaf pages of an |
||
7512 | ** intkey b-tree, then cell i is a divider cell. */ |
||
7513 | pNew = apNew[++k]; |
||
7514 | if ( 0 == leafData ) |
||
7515 | continue; |
||
7516 | } |
||
7517 | Debug.Assert( j < nOld ); |
||
7518 | Debug.Assert( k < nNew ); |
||
7519 | |||
7520 | /* If the cell was originally divider cell (and is not now) or |
||
7521 | ** an overflow cell, or if the cell was located on a different sibling |
||
7522 | ** page before the balancing, then the pointer map entries associated |
||
7523 | ** with any child or overflow pages need to be updated. */ |
||
7524 | if ( isDivider != 0 || pOld.pgno != pNew.pgno ) |
||
7525 | { |
||
7526 | if ( 0 == leafCorrection ) |
||
7527 | { |
||
7528 | ptrmapPut( pBt, sqlite3Get4byte( apCell[i] ), PTRMAP_BTREE, pNew.pgno, ref rc ); |
||
7529 | } |
||
7530 | if ( szCell[i] > pNew.minLocal ) |
||
7531 | { |
||
7532 | ptrmapPutOvflPtr( pNew, apCell[i], ref rc ); |
||
7533 | } |
||
7534 | } |
||
7535 | } |
||
7536 | |||
7537 | if ( 0 == leafCorrection ) |
||
7538 | { |
||
7539 | for ( i = 0; i < nNew; i++ ) |
||
7540 | { |
||
7541 | u32 key = sqlite3Get4byte( apNew[i].aData, 8 ); |
||
7542 | ptrmapPut( pBt, key, PTRMAP_BTREE, apNew[i].pgno, ref rc ); |
||
7543 | } |
||
7544 | } |
||
7545 | |||
7546 | #if FALSE |
||
7547 | /* The ptrmapCheckPages() contains Debug.Assert() statements that verify that |
||
7548 | ** all pointer map pages are set correctly. This is helpful while |
||
7549 | ** debugging. This is usually disabled because a corrupt database may |
||
7550 | ** cause an Debug.Assert() statement to fail. */ |
||
7551 | ptrmapCheckPages(apNew, nNew); |
||
7552 | ptrmapCheckPages(pParent, 1); |
||
7553 | #endif |
||
7554 | } |
||
7555 | |||
7556 | Debug.Assert( pParent.isInit != 0 ); |
||
7557 | TRACE( "BALANCE: finished: old=%d new=%d cells=%d\n", |
||
7558 | nOld, nNew, nCell ); |
||
7559 | |||
7560 | /* |
||
7561 | ** Cleanup before returning. |
||
7562 | */ |
||
7563 | balance_cleanup: |
||
7564 | sqlite3ScratchFree( apCell ); |
||
7565 | for ( i = 0; i < nOld; i++ ) |
||
7566 | { |
||
7567 | releasePage( apOld[i] ); |
||
7568 | } |
||
7569 | for ( i = 0; i < nNew; i++ ) |
||
7570 | { |
||
7571 | releasePage( apNew[i] ); |
||
7572 | } |
||
7573 | |||
7574 | return rc; |
||
7575 | } |
||
7576 | |||
7577 | |||
7578 | /* |
||
7579 | ** This function is called when the root page of a b-tree structure is |
||
7580 | ** overfull (has one or more overflow pages). |
||
7581 | ** |
||
7582 | ** A new child page is allocated and the contents of the current root |
||
7583 | ** page, including overflow cells, are copied into the child. The root |
||
7584 | ** page is then overwritten to make it an empty page with the right-child |
||
7585 | ** pointer pointing to the new page. |
||
7586 | ** |
||
7587 | ** Before returning, all pointer-map entries corresponding to pages |
||
7588 | ** that the new child-page now contains pointers to are updated. The |
||
7589 | ** entry corresponding to the new right-child pointer of the root |
||
7590 | ** page is also updated. |
||
7591 | ** |
||
7592 | ** If successful, ppChild is set to contain a reference to the child |
||
7593 | ** page and SQLITE_OK is returned. In this case the caller is required |
||
7594 | ** to call releasePage() on ppChild exactly once. If an error occurs, |
||
7595 | ** an error code is returned and ppChild is set to 0. |
||
7596 | */ |
||
7597 | static int balance_deeper( MemPage pRoot, ref MemPage ppChild ) |
||
7598 | { |
||
7599 | int rc; /* Return value from subprocedures */ |
||
7600 | MemPage pChild = null; /* Pointer to a new child page */ |
||
7601 | Pgno pgnoChild = 0; /* Page number of the new child page */ |
||
7602 | BtShared pBt = pRoot.pBt; /* The BTree */ |
||
7603 | |||
7604 | Debug.Assert( pRoot.nOverflow > 0 ); |
||
7605 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
7606 | |||
7607 | /* Make pRoot, the root page of the b-tree, writable. Allocate a new |
||
7608 | ** page that will become the new right-child of pPage. Copy the contents |
||
7609 | ** of the node stored on pRoot into the new child page. |
||
7610 | */ |
||
7611 | rc = sqlite3PagerWrite( pRoot.pDbPage ); |
||
7612 | if ( rc == SQLITE_OK ) |
||
7613 | { |
||
7614 | rc = allocateBtreePage( pBt, ref pChild, ref pgnoChild, pRoot.pgno, 0 ); |
||
7615 | copyNodeContent( pRoot, pChild, ref rc ); |
||
7616 | #if !SQLITE_OMIT_AUTOVACUUM // if ( ISAUTOVACUUM ) |
||
7617 | if ( pBt.autoVacuum ) |
||
7618 | #else |
||
7619 | if (false) |
||
7620 | #endif |
||
7621 | { |
||
7622 | ptrmapPut( pBt, pgnoChild, PTRMAP_BTREE, pRoot.pgno, ref rc ); |
||
7623 | } |
||
7624 | } |
||
7625 | if ( rc != 0 ) |
||
7626 | { |
||
7627 | ppChild = null; |
||
7628 | releasePage( pChild ); |
||
7629 | return rc; |
||
7630 | } |
||
7631 | Debug.Assert( sqlite3PagerIswriteable( pChild.pDbPage ) ); |
||
7632 | Debug.Assert( sqlite3PagerIswriteable( pRoot.pDbPage ) ); |
||
7633 | Debug.Assert( pChild.nCell == pRoot.nCell ); |
||
7634 | |||
7635 | TRACE( "BALANCE: copy root %d into %d\n", pRoot.pgno, pChild.pgno ); |
||
7636 | |||
7637 | /* Copy the overflow cells from pRoot to pChild */ |
||
7638 | Array.Copy( pRoot.aOvfl, pChild.aOvfl, pRoot.nOverflow );//memcpy(pChild.aOvfl, pRoot.aOvfl, pRoot.nOverflow*sizeof(pRoot.aOvfl[0])); |
||
7639 | pChild.nOverflow = pRoot.nOverflow; |
||
7640 | |||
7641 | /* Zero the contents of pRoot. Then install pChild as the right-child. */ |
||
7642 | zeroPage( pRoot, pChild.aData[0] & ~PTF_LEAF ); |
||
7643 | sqlite3Put4byte( pRoot.aData, pRoot.hdrOffset + 8, pgnoChild ); |
||
7644 | |||
7645 | ppChild = pChild; |
||
7646 | return SQLITE_OK; |
||
7647 | } |
||
7648 | |||
7649 | /* |
||
7650 | ** The page that pCur currently points to has just been modified in |
||
7651 | ** some way. This function figures out if this modification means the |
||
7652 | ** tree needs to be balanced, and if so calls the appropriate balancing |
||
7653 | ** routine. Balancing routines are: |
||
7654 | ** |
||
7655 | ** balance_quick() |
||
7656 | ** balance_deeper() |
||
7657 | ** balance_nonroot() |
||
7658 | */ |
||
7659 | static u8[] aBalanceQuickSpace = new u8[13]; |
||
7660 | static int balance( BtCursor pCur ) |
||
7661 | { |
||
7662 | int rc = SQLITE_OK; |
||
7663 | int nMin = (int)pCur.pBt.usableSize * 2 / 3; |
||
7664 | |||
7665 | //u8[] pFree = null; |
||
7666 | |||
7667 | #if !NDEBUG || SQLITE_COVERAGE_TEST || DEBUG |
||
7668 | int balance_quick_called = 0;//TESTONLY( int balance_quick_called = 0 ); |
||
7669 | int balance_deeper_called = 0;//TESTONLY( int balance_deeper_called = 0 ); |
||
7670 | #else |
||
7671 | int balance_quick_called = 0; |
||
7672 | int balance_deeper_called = 0; |
||
7673 | #endif |
||
7674 | |||
7675 | do |
||
7676 | { |
||
7677 | int iPage = pCur.iPage; |
||
7678 | MemPage pPage = pCur.apPage[iPage]; |
||
7679 | |||
7680 | if ( iPage == 0 ) |
||
7681 | { |
||
7682 | if ( pPage.nOverflow != 0 ) |
||
7683 | { |
||
7684 | /* The root page of the b-tree is overfull. In this case call the |
||
7685 | ** balance_deeper() function to create a new child for the root-page |
||
7686 | ** and copy the current contents of the root-page to it. The |
||
7687 | ** next iteration of the do-loop will balance the child page. |
||
7688 | */ |
||
7689 | Debug.Assert( ( balance_deeper_called++ ) == 0 ); |
||
7690 | rc = balance_deeper( pPage, ref pCur.apPage[1] ); |
||
7691 | if ( rc == SQLITE_OK ) |
||
7692 | { |
||
7693 | pCur.iPage = 1; |
||
7694 | pCur.aiIdx[0] = 0; |
||
7695 | pCur.aiIdx[1] = 0; |
||
7696 | Debug.Assert( pCur.apPage[1].nOverflow != 0 ); |
||
7697 | } |
||
7698 | } |
||
7699 | else |
||
7700 | { |
||
7701 | break; |
||
7702 | } |
||
7703 | } |
||
7704 | else if ( pPage.nOverflow == 0 && pPage.nFree <= nMin ) |
||
7705 | { |
||
7706 | break; |
||
7707 | } |
||
7708 | else |
||
7709 | { |
||
7710 | MemPage pParent = pCur.apPage[iPage - 1]; |
||
7711 | int iIdx = pCur.aiIdx[iPage - 1]; |
||
7712 | |||
7713 | rc = sqlite3PagerWrite( pParent.pDbPage ); |
||
7714 | if ( rc == SQLITE_OK ) |
||
7715 | { |
||
7716 | #if !SQLITE_OMIT_QUICKBALANCE |
||
7717 | if ( pPage.hasData != 0 |
||
7718 | && pPage.nOverflow == 1 |
||
7719 | && pPage.aOvfl[0].idx == pPage.nCell |
||
7720 | && pParent.pgno != 1 |
||
7721 | && pParent.nCell == iIdx |
||
7722 | ) |
||
7723 | { |
||
7724 | /* Call balance_quick() to create a new sibling of pPage on which |
||
7725 | ** to store the overflow cell. balance_quick() inserts a new cell |
||
7726 | ** into pParent, which may cause pParent overflow. If this |
||
7727 | ** happens, the next interation of the do-loop will balance pParent |
||
7728 | ** use either balance_nonroot() or balance_deeper(). Until this |
||
7729 | ** happens, the overflow cell is stored in the aBalanceQuickSpace[] |
||
7730 | ** buffer. |
||
7731 | ** |
||
7732 | ** The purpose of the following Debug.Assert() is to check that only a |
||
7733 | ** single call to balance_quick() is made for each call to this |
||
7734 | ** function. If this were not verified, a subtle bug involving reuse |
||
7735 | ** of the aBalanceQuickSpace[] might sneak in. |
||
7736 | */ |
||
7737 | Debug.Assert( ( balance_quick_called++ ) == 0 ); |
||
7738 | rc = balance_quick( pParent, pPage, aBalanceQuickSpace ); |
||
7739 | } |
||
7740 | else |
||
7741 | #endif |
||
7742 | { |
||
7743 | /* In this case, call balance_nonroot() to redistribute cells |
||
7744 | ** between pPage and up to 2 of its sibling pages. This involves |
||
7745 | ** modifying the contents of pParent, which may cause pParent to |
||
7746 | ** become overfull or underfull. The next iteration of the do-loop |
||
7747 | ** will balance the parent page to correct this. |
||
7748 | ** |
||
7749 | ** If the parent page becomes overfull, the overflow cell or cells |
||
7750 | ** are stored in the pSpace buffer allocated immediately below. |
||
7751 | ** A subsequent iteration of the do-loop will deal with this by |
||
7752 | ** calling balance_nonroot() (balance_deeper() may be called first, |
||
7753 | ** but it doesn't deal with overflow cells - just moves them to a |
||
7754 | ** different page). Once this subsequent call to balance_nonroot() |
||
7755 | ** has completed, it is safe to release the pSpace buffer used by |
||
7756 | ** the previous call, as the overflow cell data will have been |
||
7757 | ** copied either into the body of a database page or into the new |
||
7758 | ** pSpace buffer passed to the latter call to balance_nonroot(). |
||
7759 | */ |
||
7760 | ////u8[] pSpace = new u8[pCur.pBt.pageSize];// u8 pSpace = sqlite3PageMalloc( pCur.pBt.pageSize ); |
||
7761 | rc = balance_nonroot( pParent, iIdx, null, iPage == 1 ? 1 : 0 ); |
||
7762 | //if (pFree != null) |
||
7763 | //{ |
||
7764 | // /* If pFree is not NULL, it points to the pSpace buffer used |
||
7765 | // ** by a previous call to balance_nonroot(). Its contents are |
||
7766 | // ** now stored either on real database pages or within the |
||
7767 | // ** new pSpace buffer, so it may be safely freed here. */ |
||
7768 | // sqlite3PageFree(ref pFree); |
||
7769 | //} |
||
7770 | |||
7771 | /* The pSpace buffer will be freed after the next call to |
||
7772 | ** balance_nonroot(), or just before this function returns, whichever |
||
7773 | ** comes first. */ |
||
7774 | //pFree = pSpace; |
||
7775 | } |
||
7776 | } |
||
7777 | |||
7778 | pPage.nOverflow = 0; |
||
7779 | |||
7780 | /* The next iteration of the do-loop balances the parent page. */ |
||
7781 | releasePage( pPage ); |
||
7782 | pCur.iPage--; |
||
7783 | } |
||
7784 | } while ( rc == SQLITE_OK ); |
||
7785 | |||
7786 | //if (pFree != null) |
||
7787 | //{ |
||
7788 | // sqlite3PageFree(ref pFree); |
||
7789 | //} |
||
7790 | return rc; |
||
7791 | } |
||
7792 | |||
7793 | |||
7794 | /* |
||
7795 | ** Insert a new record into the BTree. The key is given by (pKey,nKey) |
||
7796 | ** and the data is given by (pData,nData). The cursor is used only to |
||
7797 | ** define what table the record should be inserted into. The cursor |
||
7798 | ** is left pointing at a random location. |
||
7799 | ** |
||
7800 | ** For an INTKEY table, only the nKey value of the key is used. pKey is |
||
7801 | ** ignored. For a ZERODATA table, the pData and nData are both ignored. |
||
7802 | ** |
||
7803 | ** If the seekResult parameter is non-zero, then a successful call to |
||
7804 | ** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already |
||
7805 | ** been performed. seekResult is the search result returned (a negative |
||
7806 | ** number if pCur points at an entry that is smaller than (pKey, nKey), or |
||
7807 | ** a positive value if pCur points at an etry that is larger than |
||
7808 | ** (pKey, nKey)). |
||
7809 | ** |
||
7810 | ** If the seekResult parameter is non-zero, then the caller guarantees that |
||
7811 | ** cursor pCur is pointing at the existing copy of a row that is to be |
||
7812 | ** overwritten. If the seekResult parameter is 0, then cursor pCur may |
||
7813 | ** point to any entry or to no entry at all and so this function has to seek |
||
7814 | ** the cursor before the new key can be inserted. |
||
7815 | */ |
||
7816 | static int sqlite3BtreeInsert( |
||
7817 | BtCursor pCur, /* Insert data into the table of this cursor */ |
||
7818 | byte[] pKey, i64 nKey, /* The key of the new record */ |
||
7819 | byte[] pData, int nData, /* The data of the new record */ |
||
7820 | int nZero, /* Number of extra 0 bytes to append to data */ |
||
7821 | int appendBias, /* True if this is likely an append */ |
||
7822 | int seekResult /* Result of prior MovetoUnpacked() call */ |
||
7823 | ) |
||
7824 | { |
||
7825 | int rc; |
||
7826 | int loc = seekResult; /* -1: before desired location +1: after */ |
||
7827 | int szNew = 0; |
||
7828 | int idx; |
||
7829 | MemPage pPage; |
||
7830 | Btree p = pCur.pBtree; |
||
7831 | BtShared pBt = p.pBt; |
||
7832 | int oldCell; |
||
7833 | byte[] newCell = null; |
||
7834 | |||
7835 | if ( pCur.eState == CURSOR_FAULT ) |
||
7836 | { |
||
7837 | Debug.Assert( pCur.skipNext != SQLITE_OK ); |
||
7838 | return pCur.skipNext; |
||
7839 | } |
||
7840 | |||
7841 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
7842 | Debug.Assert( pCur.wrFlag != 0 && pBt.inTransaction == TRANS_WRITE && !pBt.readOnly ); |
||
7843 | Debug.Assert( hasSharedCacheTableLock( p, pCur.pgnoRoot, pCur.pKeyInfo != null ? 1 : 0, 2 ) ); |
||
7844 | |||
7845 | /* Assert that the caller has been consistent. If this cursor was opened |
||
7846 | ** expecting an index b-tree, then the caller should be inserting blob |
||
7847 | ** keys with no associated data. If the cursor was opened expecting an |
||
7848 | ** intkey table, the caller should be inserting integer keys with a |
||
7849 | ** blob of associated data. */ |
||
7850 | Debug.Assert( ( pKey == null ) == ( pCur.pKeyInfo == null ) ); |
||
7851 | |||
7852 | /* If this is an insert into a table b-tree, invalidate any incrblob |
||
7853 | ** cursors open on the row being replaced (assuming this is a replace |
||
7854 | ** operation - if it is not, the following is a no-op). */ |
||
7855 | if ( pCur.pKeyInfo == null ) |
||
7856 | { |
||
7857 | invalidateIncrblobCursors( p, nKey, 0 ); |
||
7858 | } |
||
7859 | |||
7860 | /* Save the positions of any other cursors open on this table. |
||
7861 | ** |
||
7862 | ** In some cases, the call to btreeMoveto() below is a no-op. For |
||
7863 | ** example, when inserting data into a table with auto-generated integer |
||
7864 | ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the |
||
7865 | ** integer key to use. It then calls this function to actually insert the |
||
7866 | ** data into the intkey B-Tree. In this case btreeMoveto() recognizes |
||
7867 | ** that the cursor is already where it needs to be and returns without |
||
7868 | ** doing any work. To avoid thwarting these optimizations, it is important |
||
7869 | ** not to clear the cursor here. |
||
7870 | */ |
||
7871 | rc = saveAllCursors( pBt, pCur.pgnoRoot, pCur ); |
||
7872 | if ( rc != 0 ) |
||
7873 | return rc; |
||
7874 | if ( 0 == loc ) |
||
7875 | { |
||
7876 | rc = btreeMoveto( pCur, pKey, nKey, appendBias, ref loc ); |
||
7877 | if ( rc != 0 ) |
||
7878 | return rc; |
||
7879 | } |
||
7880 | Debug.Assert( pCur.eState == CURSOR_VALID || ( pCur.eState == CURSOR_INVALID && loc != 0 ) ); |
||
7881 | |||
7882 | pPage = pCur.apPage[pCur.iPage]; |
||
7883 | Debug.Assert( pPage.intKey != 0 || nKey >= 0 ); |
||
7884 | Debug.Assert( pPage.leaf != 0 || 0 == pPage.intKey ); |
||
7885 | |||
7886 | TRACE( "INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", |
||
7887 | pCur.pgnoRoot, nKey, nData, pPage.pgno, |
||
7888 | loc == 0 ? "overwrite" : "new entry" ); |
||
7889 | Debug.Assert( pPage.isInit != 0 ); |
||
7890 | allocateTempSpace( pBt ); |
||
7891 | newCell = pBt.pTmpSpace; |
||
7892 | //if (newCell == null) return SQLITE_NOMEM; |
||
7893 | rc = fillInCell( pPage, newCell, pKey, nKey, pData, nData, nZero, ref szNew ); |
||
7894 | if ( rc != 0 ) |
||
7895 | goto end_insert; |
||
7896 | Debug.Assert( szNew == cellSizePtr( pPage, newCell ) ); |
||
7897 | Debug.Assert( szNew <= MX_CELL_SIZE( pBt ) ); |
||
7898 | idx = pCur.aiIdx[pCur.iPage]; |
||
7899 | if ( loc == 0 ) |
||
7900 | { |
||
7901 | u16 szOld; |
||
7902 | Debug.Assert( idx < pPage.nCell ); |
||
7903 | rc = sqlite3PagerWrite( pPage.pDbPage ); |
||
7904 | if ( rc != 0 ) |
||
7905 | { |
||
7906 | goto end_insert; |
||
7907 | } |
||
7908 | oldCell = findCell( pPage, idx ); |
||
7909 | if ( 0 == pPage.leaf ) |
||
7910 | { |
||
7911 | //memcpy(newCell, oldCell, 4); |
||
7912 | newCell[0] = pPage.aData[oldCell + 0]; |
||
7913 | newCell[1] = pPage.aData[oldCell + 1]; |
||
7914 | newCell[2] = pPage.aData[oldCell + 2]; |
||
7915 | newCell[3] = pPage.aData[oldCell + 3]; |
||
7916 | } |
||
7917 | szOld = cellSizePtr( pPage, oldCell ); |
||
7918 | rc = clearCell( pPage, oldCell ); |
||
7919 | dropCell( pPage, idx, szOld, ref rc ); |
||
7920 | if ( rc != 0 ) |
||
7921 | goto end_insert; |
||
7922 | } |
||
7923 | else if ( loc < 0 && pPage.nCell > 0 ) |
||
7924 | { |
||
7925 | Debug.Assert( pPage.leaf != 0 ); |
||
7926 | idx = ++pCur.aiIdx[pCur.iPage]; |
||
7927 | } |
||
7928 | else |
||
7929 | { |
||
7930 | Debug.Assert( pPage.leaf != 0 ); |
||
7931 | } |
||
7932 | insertCell( pPage, idx, newCell, szNew, null, 0, ref rc ); |
||
7933 | Debug.Assert( rc != SQLITE_OK || pPage.nCell > 0 || pPage.nOverflow > 0 ); |
||
7934 | |||
7935 | /* If no error has occured and pPage has an overflow cell, call balance() |
||
7936 | ** to redistribute the cells within the tree. Since balance() may move |
||
7937 | ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey |
||
7938 | ** variables. |
||
7939 | ** |
||
7940 | ** Previous versions of SQLite called moveToRoot() to move the cursor |
||
7941 | ** back to the root page as balance() used to invalidate the contents |
||
7942 | ** of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that, |
||
7943 | ** set the cursor state to "invalid". This makes common insert operations |
||
7944 | ** slightly faster. |
||
7945 | ** |
||
7946 | ** There is a subtle but important optimization here too. When inserting |
||
7947 | ** multiple records into an intkey b-tree using a single cursor (as can |
||
7948 | ** happen while processing an "INSERT INTO ... SELECT" statement), it |
||
7949 | ** is advantageous to leave the cursor pointing to the last entry in |
||
7950 | ** the b-tree if possible. If the cursor is left pointing to the last |
||
7951 | ** entry in the table, and the next row inserted has an integer key |
||
7952 | ** larger than the largest existing key, it is possible to insert the |
||
7953 | ** row without seeking the cursor. This can be a big performance boost. |
||
7954 | */ |
||
7955 | pCur.info.nSize = 0; |
||
7956 | pCur.validNKey = false; |
||
7957 | if ( rc == SQLITE_OK && pPage.nOverflow != 0 ) |
||
7958 | { |
||
7959 | rc = balance( pCur ); |
||
7960 | |||
7961 | /* Must make sure nOverflow is reset to zero even if the balance() |
||
7962 | ** fails. Internal data structure corruption will result otherwise. |
||
7963 | ** Also, set the cursor state to invalid. This stops saveCursorPosition() |
||
7964 | ** from trying to save the current position of the cursor. */ |
||
7965 | pCur.apPage[pCur.iPage].nOverflow = 0; |
||
7966 | pCur.eState = CURSOR_INVALID; |
||
7967 | } |
||
7968 | Debug.Assert( pCur.apPage[pCur.iPage].nOverflow == 0 ); |
||
7969 | |||
7970 | end_insert: |
||
7971 | return rc; |
||
7972 | } |
||
7973 | |||
7974 | /* |
||
7975 | ** Delete the entry that the cursor is pointing to. The cursor |
||
7976 | ** is left pointing at a arbitrary location. |
||
7977 | */ |
||
7978 | static int sqlite3BtreeDelete( BtCursor pCur ) |
||
7979 | { |
||
7980 | Btree p = pCur.pBtree; |
||
7981 | BtShared pBt = p.pBt; |
||
7982 | int rc; /* Return code */ |
||
7983 | MemPage pPage; /* Page to delete cell from */ |
||
7984 | int pCell; /* Pointer to cell to delete */ |
||
7985 | int iCellIdx; /* Index of cell to delete */ |
||
7986 | int iCellDepth; /* Depth of node containing pCell */ |
||
7987 | |||
7988 | Debug.Assert( cursorHoldsMutex( pCur ) ); |
||
7989 | Debug.Assert( pBt.inTransaction == TRANS_WRITE ); |
||
7990 | Debug.Assert( !pBt.readOnly ); |
||
7991 | Debug.Assert( pCur.wrFlag != 0 ); |
||
7992 | Debug.Assert( hasSharedCacheTableLock( p, pCur.pgnoRoot, pCur.pKeyInfo != null ? 1 : 0, 2 ) ); |
||
7993 | Debug.Assert( !hasReadConflicts( p, pCur.pgnoRoot ) ); |
||
7994 | |||
7995 | if ( NEVER( pCur.aiIdx[pCur.iPage] >= pCur.apPage[pCur.iPage].nCell ) |
||
7996 | || NEVER( pCur.eState != CURSOR_VALID ) |
||
7997 | ) |
||
7998 | { |
||
7999 | return SQLITE_ERROR; /* Something has gone awry. */ |
||
8000 | } |
||
8001 | |||
8002 | /* If this is a delete operation to remove a row from a table b-tree, |
||
8003 | ** invalidate any incrblob cursors open on the row being deleted. */ |
||
8004 | if ( pCur.pKeyInfo == null ) |
||
8005 | { |
||
8006 | invalidateIncrblobCursors( p, pCur.info.nKey, 0 ); |
||
8007 | } |
||
8008 | |||
8009 | iCellDepth = pCur.iPage; |
||
8010 | iCellIdx = pCur.aiIdx[iCellDepth]; |
||
8011 | pPage = pCur.apPage[iCellDepth]; |
||
8012 | pCell = findCell( pPage, iCellIdx ); |
||
8013 | |||
8014 | /* If the page containing the entry to delete is not a leaf page, move |
||
8015 | ** the cursor to the largest entry in the tree that is smaller than |
||
8016 | ** the entry being deleted. This cell will replace the cell being deleted |
||
8017 | ** from the internal node. The 'previous' entry is used for this instead |
||
8018 | ** of the 'next' entry, as the previous entry is always a part of the |
||
8019 | ** sub-tree headed by the child page of the cell being deleted. This makes |
||
8020 | ** balancing the tree following the delete operation easier. */ |
||
8021 | if ( 0 == pPage.leaf ) |
||
8022 | { |
||
8023 | int notUsed = 0; |
||
8024 | rc = sqlite3BtreePrevious( pCur, ref notUsed ); |
||
8025 | if ( rc != 0 ) |
||
8026 | return rc; |
||
8027 | } |
||
8028 | |||
8029 | /* Save the positions of any other cursors open on this table before |
||
8030 | ** making any modifications. Make the page containing the entry to be |
||
8031 | ** deleted writable. Then free any overflow pages associated with the |
||
8032 | ** entry and finally remove the cell itself from within the page. |
||
8033 | */ |
||
8034 | rc = saveAllCursors( pBt, pCur.pgnoRoot, pCur ); |
||
8035 | if ( rc != 0 ) |
||
8036 | return rc; |
||
8037 | rc = sqlite3PagerWrite( pPage.pDbPage ); |
||
8038 | if ( rc != 0 ) |
||
8039 | return rc; |
||
8040 | rc = clearCell( pPage, pCell ); |
||
8041 | dropCell( pPage, iCellIdx, cellSizePtr( pPage, pCell ), ref rc ); |
||
8042 | if ( rc != 0 ) |
||
8043 | return rc; |
||
8044 | |||
8045 | /* If the cell deleted was not located on a leaf page, then the cursor |
||
8046 | ** is currently pointing to the largest entry in the sub-tree headed |
||
8047 | ** by the child-page of the cell that was just deleted from an internal |
||
8048 | ** node. The cell from the leaf node needs to be moved to the internal |
||
8049 | ** node to replace the deleted cell. */ |
||
8050 | if ( 0 == pPage.leaf ) |
||
8051 | { |
||
8052 | MemPage pLeaf = pCur.apPage[pCur.iPage]; |
||
8053 | int nCell; |
||
8054 | Pgno n = pCur.apPage[iCellDepth + 1].pgno; |
||
8055 | //byte[] pTmp; |
||
8056 | |||
8057 | pCell = findCell( pLeaf, pLeaf.nCell - 1 ); |
||
8058 | nCell = cellSizePtr( pLeaf, pCell ); |
||
8059 | Debug.Assert( MX_CELL_SIZE( pBt ) >= nCell ); |
||
8060 | |||
8061 | //allocateTempSpace(pBt); |
||
8062 | //pTmp = pBt.pTmpSpace; |
||
8063 | |||
8064 | rc = sqlite3PagerWrite( pLeaf.pDbPage ); |
||
8065 | byte[] pNext_4 = sqlite3Malloc( nCell + 4 ); |
||
8066 | Buffer.BlockCopy( pLeaf.aData, pCell - 4, pNext_4, 0, nCell + 4 ); |
||
8067 | insertCell( pPage, iCellIdx, pNext_4, nCell + 4, null, n, ref rc ); //insertCell( pPage, iCellIdx, pCell - 4, nCell + 4, pTmp, n, ref rc ); |
||
8068 | dropCell( pLeaf, pLeaf.nCell - 1, nCell, ref rc ); |
||
8069 | if ( rc != 0 ) |
||
8070 | return rc; |
||
8071 | } |
||
8072 | |||
8073 | /* Balance the tree. If the entry deleted was located on a leaf page, |
||
8074 | ** then the cursor still points to that page. In this case the first |
||
8075 | ** call to balance() repairs the tree, and the if(...) condition is |
||
8076 | ** never true. |
||
8077 | ** |
||
8078 | ** Otherwise, if the entry deleted was on an internal node page, then |
||
8079 | ** pCur is pointing to the leaf page from which a cell was removed to |
||
8080 | ** replace the cell deleted from the internal node. This is slightly |
||
8081 | ** tricky as the leaf node may be underfull, and the internal node may |
||
8082 | ** be either under or overfull. In this case run the balancing algorithm |
||
8083 | ** on the leaf node first. If the balance proceeds far enough up the |
||
8084 | ** tree that we can be sure that any problem in the internal node has |
||
8085 | ** been corrected, so be it. Otherwise, after balancing the leaf node, |
||
8086 | ** walk the cursor up the tree to the internal node and balance it as |
||
8087 | ** well. */ |
||
8088 | rc = balance( pCur ); |
||
8089 | if ( rc == SQLITE_OK && pCur.iPage > iCellDepth ) |
||
8090 | { |
||
8091 | while ( pCur.iPage > iCellDepth ) |
||
8092 | { |
||
8093 | releasePage( pCur.apPage[pCur.iPage--] ); |
||
8094 | } |
||
8095 | rc = balance( pCur ); |
||
8096 | } |
||
8097 | |||
8098 | if ( rc == SQLITE_OK ) |
||
8099 | { |
||
8100 | moveToRoot( pCur ); |
||
8101 | } |
||
8102 | return rc; |
||
8103 | } |
||
8104 | |||
8105 | /* |
||
8106 | ** Create a new BTree table. Write into piTable the page |
||
8107 | ** number for the root page of the new table. |
||
8108 | ** |
||
8109 | ** The type of type is determined by the flags parameter. Only the |
||
8110 | ** following values of flags are currently in use. Other values for |
||
8111 | ** flags might not work: |
||
8112 | ** |
||
8113 | ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys |
||
8114 | ** BTREE_ZERODATA Used for SQL indices |
||
8115 | */ |
||
8116 | static int btreeCreateTable( Btree p, ref int piTable, int createTabFlags ) |
||
8117 | { |
||
8118 | BtShared pBt = p.pBt; |
||
8119 | MemPage pRoot = new MemPage(); |
||
8120 | Pgno pgnoRoot = 0; |
||
8121 | int rc; |
||
8122 | int ptfFlags; /* Page-type flage for the root page of new table */ |
||
8123 | |||
8124 | Debug.Assert( sqlite3BtreeHoldsMutex( p ) ); |
||
8125 | Debug.Assert( pBt.inTransaction == TRANS_WRITE ); |
||
8126 | Debug.Assert( !pBt.readOnly ); |
||
8127 | |||
8128 | #if SQLITE_OMIT_AUTOVACUUM |
||
8129 | rc = allocateBtreePage(pBt, ref pRoot, ref pgnoRoot, 1, 0); |
||
8130 | if( rc !=0){ |
||
8131 | return rc; |
||
8132 | } |
||
8133 | #else |
||
8134 | if ( pBt.autoVacuum ) |
||
8135 | { |
||
8136 | Pgno pgnoMove = 0; /* Move a page here to make room for the root-page */ |
||
8137 | MemPage pPageMove = new MemPage(); /* The page to move to. */ |
||
8138 | |||
8139 | /* Creating a new table may probably require moving an existing database |
||
8140 | ** to make room for the new tables root page. In case this page turns |
||
8141 | ** out to be an overflow page, delete all overflow page-map caches |
||
8142 | ** held by open cursors. |
||
8143 | */ |
||
8144 | invalidateAllOverflowCache( pBt ); |
||
8145 | |||
8146 | /* Read the value of meta[3] from the database to determine where the |
||
8147 | ** root page of the new table should go. meta[3] is the largest root-page |
||
8148 | ** created so far, so the new root-page is (meta[3]+1). |
||
8149 | */ |
||
8150 | sqlite3BtreeGetMeta( p, BTREE_LARGEST_ROOT_PAGE, ref pgnoRoot ); |
||
8151 | pgnoRoot++; |
||
8152 | |||
8153 | /* The new root-page may not be allocated on a pointer-map page, or the |
||
8154 | ** PENDING_BYTE page. |
||
8155 | */ |
||
8156 | while ( pgnoRoot == PTRMAP_PAGENO( pBt, pgnoRoot ) || |
||
8157 | pgnoRoot == PENDING_BYTE_PAGE( pBt ) ) |
||
8158 | { |
||
8159 | pgnoRoot++; |
||
8160 | } |
||
8161 | Debug.Assert( pgnoRoot >= 3 ); |
||
8162 | |||
8163 | /* Allocate a page. The page that currently resides at pgnoRoot will |
||
8164 | ** be moved to the allocated page (unless the allocated page happens |
||
8165 | ** to reside at pgnoRoot). |
||
8166 | */ |
||
8167 | rc = allocateBtreePage( pBt, ref pPageMove, ref pgnoMove, pgnoRoot, 1 ); |
||
8168 | if ( rc != SQLITE_OK ) |
||
8169 | { |
||
8170 | return rc; |
||
8171 | } |
||
8172 | |||
8173 | if ( pgnoMove != pgnoRoot ) |
||
8174 | { |
||
8175 | /* pgnoRoot is the page that will be used for the root-page of |
||
8176 | ** the new table (assuming an error did not occur). But we were |
||
8177 | ** allocated pgnoMove. If required (i.e. if it was not allocated |
||
8178 | ** by extending the file), the current page at position pgnoMove |
||
8179 | ** is already journaled. |
||
8180 | */ |
||
8181 | u8 eType = 0; |
||
8182 | Pgno iPtrPage = 0; |
||
8183 | |||
8184 | releasePage( pPageMove ); |
||
8185 | |||
8186 | /* Move the page currently at pgnoRoot to pgnoMove. */ |
||
8187 | rc = btreeGetPage( pBt, pgnoRoot, ref pRoot, 0 ); |
||
8188 | if ( rc != SQLITE_OK ) |
||
8189 | { |
||
8190 | return rc; |
||
8191 | } |
||
8192 | rc = ptrmapGet( pBt, pgnoRoot, ref eType, ref iPtrPage ); |
||
8193 | if ( eType == PTRMAP_ROOTPAGE || eType == PTRMAP_FREEPAGE ) |
||
8194 | { |
||
8195 | rc = SQLITE_CORRUPT_BKPT(); |
||
8196 | } |
||
8197 | if ( rc != SQLITE_OK ) |
||
8198 | { |
||
8199 | releasePage( pRoot ); |
||
8200 | return rc; |
||
8201 | } |
||
8202 | Debug.Assert( eType != PTRMAP_ROOTPAGE ); |
||
8203 | Debug.Assert( eType != PTRMAP_FREEPAGE ); |
||
8204 | rc = relocatePage( pBt, pRoot, eType, iPtrPage, pgnoMove, 0 ); |
||
8205 | releasePage( pRoot ); |
||
8206 | |||
8207 | /* Obtain the page at pgnoRoot */ |
||
8208 | if ( rc != SQLITE_OK ) |
||
8209 | { |
||
8210 | return rc; |
||
8211 | } |
||
8212 | rc = btreeGetPage( pBt, pgnoRoot, ref pRoot, 0 ); |
||
8213 | if ( rc != SQLITE_OK ) |
||
8214 | { |
||
8215 | return rc; |
||
8216 | } |
||
8217 | rc = sqlite3PagerWrite( pRoot.pDbPage ); |
||
8218 | if ( rc != SQLITE_OK ) |
||
8219 | { |
||
8220 | releasePage( pRoot ); |
||
8221 | return rc; |
||
8222 | } |
||
8223 | } |
||
8224 | else |
||
8225 | { |
||
8226 | pRoot = pPageMove; |
||
8227 | } |
||
8228 | |||
8229 | /* Update the pointer-map and meta-data with the new root-page number. */ |
||
8230 | ptrmapPut( pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, ref rc ); |
||
8231 | if ( rc != 0 ) |
||
8232 | { |
||
8233 | releasePage( pRoot ); |
||
8234 | return rc; |
||
8235 | } |
||
8236 | |||
8237 | /* When the new root page was allocated, page 1 was made writable in |
||
8238 | ** order either to increase the database filesize, or to decrement the |
||
8239 | ** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail. |
||
8240 | */ |
||
8241 | Debug.Assert( sqlite3PagerIswriteable( pBt.pPage1.pDbPage ) ); |
||
8242 | rc = sqlite3BtreeUpdateMeta( p, 4, pgnoRoot ); |
||
8243 | if ( NEVER( rc != 0 ) ) |
||
8244 | { |
||
8245 | releasePage( pRoot ); |
||
8246 | return rc; |
||
8247 | } |
||
8248 | |||
8249 | } |
||
8250 | else |
||
8251 | { |
||
8252 | rc = allocateBtreePage( pBt, ref pRoot, ref pgnoRoot, 1, 0 ); |
||
8253 | if ( rc != 0 ) |
||
8254 | return rc; |
||
8255 | } |
||
8256 | #endif |
||
8257 | Debug.Assert( sqlite3PagerIswriteable( pRoot.pDbPage ) ); |
||
8258 | if ( ( createTabFlags & BTREE_INTKEY ) != 0 ) |
||
8259 | { |
||
8260 | ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF; |
||
8261 | } |
||
8262 | else |
||
8263 | { |
||
8264 | ptfFlags = PTF_ZERODATA | PTF_LEAF; |
||
8265 | } |
||
8266 | zeroPage( pRoot, ptfFlags ); |
||
8267 | sqlite3PagerUnref( pRoot.pDbPage ); |
||
8268 | Debug.Assert( ( pBt.openFlags & BTREE_SINGLE ) == 0 || pgnoRoot == 2 ); |
||
8269 | piTable = (int)pgnoRoot; |
||
8270 | return SQLITE_OK; |
||
8271 | } |
||
8272 | static int sqlite3BtreeCreateTable( Btree p, ref int piTable, int flags ) |
||
8273 | { |
||
8274 | int rc; |
||
8275 | sqlite3BtreeEnter( p ); |
||
8276 | rc = btreeCreateTable( p, ref piTable, flags ); |
||
8277 | sqlite3BtreeLeave( p ); |
||
8278 | return rc; |
||
8279 | } |
||
8280 | |||
8281 | /* |
||
8282 | ** Erase the given database page and all its children. Return |
||
8283 | ** the page to the freelist. |
||
8284 | */ |
||
8285 | static int clearDatabasePage( |
||
8286 | BtShared pBt, /* The BTree that contains the table */ |
||
8287 | Pgno pgno, /* Page number to clear */ |
||
8288 | int freePageFlag, /* Deallocate page if true */ |
||
8289 | ref int pnChange /* Add number of Cells freed to this counter */ |
||
8290 | ) |
||
8291 | { |
||
8292 | MemPage pPage = new MemPage(); |
||
8293 | int rc; |
||
8294 | byte[] pCell; |
||
8295 | int i; |
||
8296 | |||
8297 | Debug.Assert( sqlite3_mutex_held( pBt.mutex ) ); |
||
8298 | if ( pgno > btreePagecount( pBt ) ) |
||
8299 | { |
||
8300 | return SQLITE_CORRUPT_BKPT(); |
||
8301 | } |
||
8302 | |||
8303 | rc = getAndInitPage( pBt, pgno, ref pPage ); |
||
8304 | if ( rc != 0 ) |
||
8305 | return rc; |
||
8306 | for ( i = 0; i < pPage.nCell; i++ ) |
||
8307 | { |
||
8308 | int iCell = findCell( pPage, i ); |
||
8309 | pCell = pPage.aData; // pCell = findCell( pPage, i ); |
||
8310 | if ( 0 == pPage.leaf ) |
||
8311 | { |
||
8312 | rc = clearDatabasePage( pBt, sqlite3Get4byte( pCell, iCell ), 1, ref pnChange ); |
||
8313 | if ( rc != 0 ) |
||
8314 | goto cleardatabasepage_out; |
||
8315 | } |
||
8316 | rc = clearCell( pPage, iCell ); |
||
8317 | if ( rc != 0 ) |
||
8318 | goto cleardatabasepage_out; |
||
8319 | } |
||
8320 | if ( 0 == pPage.leaf ) |
||
8321 | { |
||
8322 | rc = clearDatabasePage( pBt, sqlite3Get4byte( pPage.aData, 8 ), 1, ref pnChange ); |
||
8323 | if ( rc != 0 ) |
||
8324 | goto cleardatabasepage_out; |
||
8325 | } |
||
8326 | else //if (pnChange != 0) |
||
8327 | { |
||
8328 | //Debug.Assert(pPage.intKey != 0); |
||
8329 | pnChange += pPage.nCell; |
||
8330 | } |
||
8331 | if ( freePageFlag != 0 ) |
||
8332 | { |
||
8333 | freePage( pPage, ref rc ); |
||
8334 | } |
||
8335 | else if ( ( rc = sqlite3PagerWrite( pPage.pDbPage ) ) == 0 ) |
||
8336 | { |
||
8337 | zeroPage( pPage, pPage.aData[0] | PTF_LEAF ); |
||
8338 | } |
||
8339 | |||
8340 | cleardatabasepage_out: |
||
8341 | releasePage( pPage ); |
||
8342 | return rc; |
||
8343 | } |
||
8344 | |||
8345 | /* |
||
8346 | ** Delete all information from a single table in the database. iTable is |
||
8347 | ** the page number of the root of the table. After this routine returns, |
||
8348 | ** the root page is empty, but still exists. |
||
8349 | ** |
||
8350 | ** This routine will fail with SQLITE_LOCKED if there are any open |
||
8351 | ** read cursors on the table. Open write cursors are moved to the |
||
8352 | ** root of the table. |
||
8353 | ** |
||
8354 | ** If pnChange is not NULL, then table iTable must be an intkey table. The |
||
8355 | ** integer value pointed to by pnChange is incremented by the number of |
||
8356 | ** entries in the table. |
||
8357 | */ |
||
8358 | static int sqlite3BtreeClearTable( Btree p, int iTable, ref int pnChange ) |
||
8359 | { |
||
8360 | int rc; |
||
8361 | BtShared pBt = p.pBt; |
||
8362 | sqlite3BtreeEnter( p ); |
||
8363 | Debug.Assert( p.inTrans == TRANS_WRITE ); |
||
8364 | |||
8365 | /* Invalidate all incrblob cursors open on table iTable (assuming iTable |
||
8366 | ** is the root of a table b-tree - if it is not, the following call is |
||
8367 | ** a no-op). */ |
||
8368 | invalidateIncrblobCursors( p, 0, 1 ); |
||
8369 | |||
8370 | rc = saveAllCursors( pBt, (Pgno)iTable, null ); |
||
8371 | if ( SQLITE_OK == rc ) |
||
8372 | { |
||
8373 | rc = clearDatabasePage( pBt, (Pgno)iTable, 0, ref pnChange ); |
||
8374 | } |
||
8375 | sqlite3BtreeLeave( p ); |
||
8376 | return rc; |
||
8377 | } |
||
8378 | |||
8379 | /* |
||
8380 | ** Erase all information in a table and add the root of the table to |
||
8381 | ** the freelist. Except, the root of the principle table (the one on |
||
8382 | ** page 1) is never added to the freelist. |
||
8383 | ** |
||
8384 | ** This routine will fail with SQLITE_LOCKED if there are any open |
||
8385 | ** cursors on the table. |
||
8386 | ** |
||
8387 | ** If AUTOVACUUM is enabled and the page at iTable is not the last |
||
8388 | ** root page in the database file, then the last root page |
||
8389 | ** in the database file is moved into the slot formerly occupied by |
||
8390 | ** iTable and that last slot formerly occupied by the last root page |
||
8391 | ** is added to the freelist instead of iTable. In this say, all |
||
8392 | ** root pages are kept at the beginning of the database file, which |
||
8393 | ** is necessary for AUTOVACUUM to work right. piMoved is set to the |
||
8394 | ** page number that used to be the last root page in the file before |
||
8395 | ** the move. If no page gets moved, piMoved is set to 0. |
||
8396 | ** The last root page is recorded in meta[3] and the value of |
||
8397 | ** meta[3] is updated by this procedure. |
||
8398 | */ |
||
8399 | static int btreeDropTable( Btree p, Pgno iTable, ref int piMoved ) |
||
8400 | { |
||
8401 | int rc; |
||
8402 | MemPage pPage = null; |
||
8403 | BtShared pBt = p.pBt; |
||
8404 | |||
8405 | Debug.Assert( sqlite3BtreeHoldsMutex( p ) ); |
||
8406 | Debug.Assert( p.inTrans == TRANS_WRITE ); |
||
8407 | |||
8408 | /* It is illegal to drop a table if any cursors are open on the |
||
8409 | ** database. This is because in auto-vacuum mode the backend may |
||
8410 | ** need to move another root-page to fill a gap left by the deleted |
||
8411 | ** root page. If an open cursor was using this page a problem would |
||
8412 | ** occur. |
||
8413 | ** |
||
8414 | ** This error is caught long before control reaches this point. |
||
8415 | */ |
||
8416 | if ( NEVER( pBt.pCursor ) ) |
||
8417 | { |
||
8418 | sqlite3ConnectionBlocked( p.db, pBt.pCursor.pBtree.db ); |
||
8419 | return SQLITE_LOCKED_SHAREDCACHE; |
||
8420 | } |
||
8421 | |||
8422 | rc = btreeGetPage( pBt, (Pgno)iTable, ref pPage, 0 ); |
||
8423 | if ( rc != 0 ) |
||
8424 | return rc; |
||
8425 | int Dummy0 = 0; |
||
8426 | rc = sqlite3BtreeClearTable( p, (int)iTable, ref Dummy0 ); |
||
8427 | if ( rc != 0 ) |
||
8428 | { |
||
8429 | releasePage( pPage ); |
||
8430 | return rc; |
||
8431 | } |
||
8432 | |||
8433 | piMoved = 0; |
||
8434 | |||
8435 | if ( iTable > 1 ) |
||
8436 | { |
||
8437 | #if SQLITE_OMIT_AUTOVACUUM |
||
8438 | freePage(pPage, ref rc); |
||
8439 | releasePage(pPage); |
||
8440 | #else |
||
8441 | if ( pBt.autoVacuum ) |
||
8442 | { |
||
8443 | Pgno maxRootPgno = 0; |
||
8444 | sqlite3BtreeGetMeta( p, BTREE_LARGEST_ROOT_PAGE, ref maxRootPgno ); |
||
8445 | |||
8446 | if ( iTable == maxRootPgno ) |
||
8447 | { |
||
8448 | /* If the table being dropped is the table with the largest root-page |
||
8449 | ** number in the database, put the root page on the free list. |
||
8450 | */ |
||
8451 | freePage( pPage, ref rc ); |
||
8452 | releasePage( pPage ); |
||
8453 | if ( rc != SQLITE_OK ) |
||
8454 | { |
||
8455 | return rc; |
||
8456 | } |
||
8457 | } |
||
8458 | else |
||
8459 | { |
||
8460 | /* The table being dropped does not have the largest root-page |
||
8461 | ** number in the database. So move the page that does into the |
||
8462 | ** gap left by the deleted root-page. |
||
8463 | */ |
||
8464 | MemPage pMove = new MemPage(); |
||
8465 | releasePage( pPage ); |
||
8466 | rc = btreeGetPage( pBt, maxRootPgno, ref pMove, 0 ); |
||
8467 | if ( rc != SQLITE_OK ) |
||
8468 | { |
||
8469 | return rc; |
||
8470 | } |
||
8471 | rc = relocatePage( pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0 ); |
||
8472 | releasePage( pMove ); |
||
8473 | if ( rc != SQLITE_OK ) |
||
8474 | { |
||
8475 | return rc; |
||
8476 | } |
||
8477 | pMove = null; |
||
8478 | rc = btreeGetPage( pBt, maxRootPgno, ref pMove, 0 ); |
||
8479 | freePage( pMove, ref rc ); |
||
8480 | releasePage( pMove ); |
||
8481 | if ( rc != SQLITE_OK ) |
||
8482 | { |
||
8483 | return rc; |
||
8484 | } |
||
8485 | piMoved = (int)maxRootPgno; |
||
8486 | } |
||
8487 | |||
8488 | /* Set the new 'max-root-page' value in the database header. This |
||
8489 | ** is the old value less one, less one more if that happens to |
||
8490 | ** be a root-page number, less one again if that is the |
||
8491 | ** PENDING_BYTE_PAGE. |
||
8492 | */ |
||
8493 | maxRootPgno--; |
||
8494 | while ( maxRootPgno == PENDING_BYTE_PAGE( pBt ) |
||
8495 | || PTRMAP_ISPAGE( pBt, maxRootPgno ) ) |
||
8496 | { |
||
8497 | maxRootPgno--; |
||
8498 | } |
||
8499 | Debug.Assert( maxRootPgno != PENDING_BYTE_PAGE( pBt ) ); |
||
8500 | |||
8501 | rc = sqlite3BtreeUpdateMeta( p, 4, maxRootPgno ); |
||
8502 | } |
||
8503 | else |
||
8504 | { |
||
8505 | freePage( pPage, ref rc ); |
||
8506 | releasePage( pPage ); |
||
8507 | } |
||
8508 | #endif |
||
8509 | } |
||
8510 | else |
||
8511 | { |
||
8512 | /* If sqlite3BtreeDropTable was called on page 1. |
||
8513 | ** This really never should happen except in a corrupt |
||
8514 | ** database. |
||
8515 | */ |
||
8516 | zeroPage( pPage, PTF_INTKEY | PTF_LEAF ); |
||
8517 | releasePage( pPage ); |
||
8518 | } |
||
8519 | return rc; |
||
8520 | } |
||
8521 | static int sqlite3BtreeDropTable( Btree p, int iTable, ref int piMoved ) |
||
8522 | { |
||
8523 | int rc; |
||
8524 | sqlite3BtreeEnter( p ); |
||
8525 | rc = btreeDropTable( p, (u32)iTable, ref piMoved ); |
||
8526 | sqlite3BtreeLeave( p ); |
||
8527 | return rc; |
||
8528 | } |
||
8529 | |||
8530 | |||
8531 | /* |
||
8532 | ** This function may only be called if the b-tree connection already |
||
8533 | ** has a read or write transaction open on the database. |
||
8534 | ** |
||
8535 | ** Read the meta-information out of a database file. Meta[0] |
||
8536 | ** is the number of free pages currently in the database. Meta[1] |
||
8537 | ** through meta[15] are available for use by higher layers. Meta[0] |
||
8538 | ** is read-only, the others are read/write. |
||
8539 | ** |
||
8540 | ** The schema layer numbers meta values differently. At the schema |
||
8541 | ** layer (and the SetCookie and ReadCookie opcodes) the number of |
||
8542 | ** free pages is not visible. So Cookie[0] is the same as Meta[1]. |
||
8543 | */ |
||
8544 | static void sqlite3BtreeGetMeta( Btree p, int idx, ref u32 pMeta ) |
||
8545 | { |
||
8546 | BtShared pBt = p.pBt; |
||
8547 | |||
8548 | sqlite3BtreeEnter( p ); |
||
8549 | Debug.Assert( p.inTrans > TRANS_NONE ); |
||
8550 | Debug.Assert( SQLITE_OK == querySharedCacheTableLock( p, MASTER_ROOT, READ_LOCK ) ); |
||
8551 | Debug.Assert( pBt.pPage1 != null ); |
||
8552 | Debug.Assert( idx >= 0 && idx <= 15 ); |
||
8553 | |||
8554 | pMeta = sqlite3Get4byte( pBt.pPage1.aData, 36 + idx * 4 ); |
||
8555 | |||
8556 | /* If auto-vacuum is disabled in this build and this is an auto-vacuum |
||
8557 | ** database, mark the database as read-only. */ |
||
8558 | #if SQLITE_OMIT_AUTOVACUUM |
||
8559 | if( idx==BTREE_LARGEST_ROOT_PAGE && pMeta>0 ) pBt.readOnly = 1; |
||
8560 | #endif |
||
8561 | |||
8562 | sqlite3BtreeLeave( p ); |
||
8563 | } |
||
8564 | |||
8565 | /* |
||
8566 | ** Write meta-information back into the database. Meta[0] is |
||
8567 | ** read-only and may not be written. |
||
8568 | */ |
||
8569 | static int sqlite3BtreeUpdateMeta( Btree p, int idx, u32 iMeta ) |
||
8570 | { |
||
8571 | BtShared pBt = p.pBt; |
||
8572 | byte[] pP1; |
||
8573 | int rc; |
||
8574 | Debug.Assert( idx >= 1 && idx <= 15 ); |
||
8575 | sqlite3BtreeEnter( p ); |
||
8576 | Debug.Assert( p.inTrans == TRANS_WRITE ); |
||
8577 | Debug.Assert( pBt.pPage1 != null ); |
||
8578 | pP1 = pBt.pPage1.aData; |
||
8579 | rc = sqlite3PagerWrite( pBt.pPage1.pDbPage ); |
||
8580 | if ( rc == SQLITE_OK ) |
||
8581 | { |
||
8582 | sqlite3Put4byte( pP1, 36 + idx * 4, iMeta ); |
||
8583 | #if !SQLITE_OMIT_AUTOVACUUM |
||
8584 | if ( idx == BTREE_INCR_VACUUM ) |
||
8585 | { |
||
8586 | Debug.Assert( pBt.autoVacuum || iMeta == 0 ); |
||
8587 | Debug.Assert( iMeta == 0 || iMeta == 1 ); |
||
8588 | pBt.incrVacuum = iMeta != 0; |
||
8589 | } |
||
8590 | #endif |
||
8591 | } |
||
8592 | sqlite3BtreeLeave( p ); |
||
8593 | return rc; |
||
8594 | } |
||
8595 | |||
8596 | #if !SQLITE_OMIT_BTREECOUNT |
||
8597 | /* |
||
8598 | ** The first argument, pCur, is a cursor opened on some b-tree. Count the |
||
8599 | ** number of entries in the b-tree and write the result to pnEntry. |
||
8600 | ** |
||
8601 | ** SQLITE_OK is returned if the operation is successfully executed. |
||
8602 | ** Otherwise, if an error is encountered (i.e. an IO error or database |
||
8603 | ** corruption) an SQLite error code is returned. |
||
8604 | */ |
||
8605 | static int sqlite3BtreeCount( BtCursor pCur, ref i64 pnEntry ) |
||
8606 | { |
||
8607 | i64 nEntry = 0; /* Value to return in pnEntry */ |
||
8608 | int rc; /* Return code */ |
||
8609 | rc = moveToRoot( pCur ); |
||
8610 | |||
8611 | /* Unless an error occurs, the following loop runs one iteration for each |
||
8612 | ** page in the B-Tree structure (not including overflow pages). |
||
8613 | */ |
||
8614 | while ( rc == SQLITE_OK ) |
||
8615 | { |
||
8616 | int iIdx; /* Index of child node in parent */ |
||
8617 | MemPage pPage; /* Current page of the b-tree */ |
||
8618 | |||
8619 | /* If this is a leaf page or the tree is not an int-key tree, then |
||
8620 | ** this page contains countable entries. Increment the entry counter |
||
8621 | ** accordingly. |
||
8622 | */ |
||
8623 | pPage = pCur.apPage[pCur.iPage]; |
||
8624 | if ( pPage.leaf != 0 || 0 == pPage.intKey ) |
||
8625 | { |
||
8626 | nEntry += pPage.nCell; |
||
8627 | } |
||
8628 | |||
8629 | /* pPage is a leaf node. This loop navigates the cursor so that it |
||
8630 | ** points to the first interior cell that it points to the parent of |
||
8631 | ** the next page in the tree that has not yet been visited. The |
||
8632 | ** pCur.aiIdx[pCur.iPage] value is set to the index of the parent cell |
||
8633 | ** of the page, or to the number of cells in the page if the next page |
||
8634 | ** to visit is the right-child of its parent. |
||
8635 | ** |
||
8636 | ** If all pages in the tree have been visited, return SQLITE_OK to the |
||
8637 | ** caller. |
||
8638 | */ |
||
8639 | if ( pPage.leaf != 0 ) |
||
8640 | { |
||
8641 | do |
||
8642 | { |
||
8643 | if ( pCur.iPage == 0 ) |
||
8644 | { |
||
8645 | /* All pages of the b-tree have been visited. Return successfully. */ |
||
8646 | pnEntry = nEntry; |
||
8647 | return SQLITE_OK; |
||
8648 | } |
||
8649 | moveToParent( pCur ); |
||
8650 | } while ( pCur.aiIdx[pCur.iPage] >= pCur.apPage[pCur.iPage].nCell ); |
||
8651 | |||
8652 | pCur.aiIdx[pCur.iPage]++; |
||
8653 | pPage = pCur.apPage[pCur.iPage]; |
||
8654 | } |
||
8655 | |||
8656 | /* Descend to the child node of the cell that the cursor currently |
||
8657 | ** points at. This is the right-child if (iIdx==pPage.nCell). |
||
8658 | */ |
||
8659 | iIdx = pCur.aiIdx[pCur.iPage]; |
||
8660 | if ( iIdx == pPage.nCell ) |
||
8661 | { |
||
8662 | rc = moveToChild( pCur, sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ) ); |
||
8663 | } |
||
8664 | else |
||
8665 | { |
||
8666 | rc = moveToChild( pCur, sqlite3Get4byte( pPage.aData, findCell( pPage, iIdx ) ) ); |
||
8667 | } |
||
8668 | } |
||
8669 | |||
8670 | /* An error has occurred. Return an error code. */ |
||
8671 | return rc; |
||
8672 | } |
||
8673 | #endif |
||
8674 | |||
8675 | /* |
||
8676 | ** Return the pager associated with a BTree. This routine is used for |
||
8677 | ** testing and debugging only. |
||
8678 | */ |
||
8679 | static Pager sqlite3BtreePager( Btree p ) |
||
8680 | { |
||
8681 | return p.pBt.pPager; |
||
8682 | } |
||
8683 | |||
8684 | #if !SQLITE_OMIT_INTEGRITY_CHECK |
||
8685 | /* |
||
8686 | ** Append a message to the error message string. |
||
8687 | */ |
||
8688 | static void checkAppendMsg( |
||
8689 | IntegrityCk pCheck, |
||
8690 | string zMsg1, |
||
8691 | string zFormat, |
||
8692 | params object[] ap |
||
8693 | ) |
||
8694 | { |
||
8695 | if ( 0 == pCheck.mxErr ) |
||
8696 | return; |
||
8697 | //va_list ap; |
||
8698 | lock ( lock_va_list ) |
||
8699 | { |
||
8700 | pCheck.mxErr--; |
||
8701 | pCheck.nErr++; |
||
8702 | va_start( ap, zFormat ); |
||
8703 | if ( pCheck.errMsg.zText.Length != 0 ) |
||
8704 | { |
||
8705 | sqlite3StrAccumAppend( pCheck.errMsg, "\n", 1 ); |
||
8706 | } |
||
8707 | if ( zMsg1.Length > 0 ) |
||
8708 | { |
||
8709 | sqlite3StrAccumAppend( pCheck.errMsg, zMsg1.ToString(), -1 ); |
||
8710 | } |
||
8711 | sqlite3VXPrintf( pCheck.errMsg, 1, zFormat, ap ); |
||
8712 | va_end( ref ap ); |
||
8713 | } |
||
8714 | } |
||
8715 | |||
8716 | static void checkAppendMsg( |
||
8717 | IntegrityCk pCheck, |
||
8718 | StringBuilder zMsg1, |
||
8719 | string zFormat, |
||
8720 | params object[] ap |
||
8721 | ) |
||
8722 | { |
||
8723 | if ( 0 == pCheck.mxErr ) |
||
8724 | return; |
||
8725 | //va_list ap; |
||
8726 | lock ( lock_va_list ) |
||
8727 | { |
||
8728 | pCheck.mxErr--; |
||
8729 | pCheck.nErr++; |
||
8730 | va_start( ap, zFormat ); |
||
8731 | if ( pCheck.errMsg.zText.Length != 0 ) |
||
8732 | { |
||
8733 | sqlite3StrAccumAppend( pCheck.errMsg, "\n", 1 ); |
||
8734 | } |
||
8735 | if ( zMsg1.Length > 0 ) |
||
8736 | { |
||
8737 | sqlite3StrAccumAppend( pCheck.errMsg, zMsg1.ToString(), -1 ); |
||
8738 | } |
||
8739 | sqlite3VXPrintf( pCheck.errMsg, 1, zFormat, ap ); |
||
8740 | va_end( ref ap ); |
||
8741 | } |
||
8742 | //if( pCheck.errMsg.mallocFailed ){ |
||
8743 | // pCheck.mallocFailed = 1; |
||
8744 | //} |
||
8745 | } |
||
8746 | #endif //* SQLITE_OMIT_INTEGRITY_CHECK */ |
||
8747 | |||
8748 | #if !SQLITE_OMIT_INTEGRITY_CHECK |
||
8749 | /* |
||
8750 | ** Add 1 to the reference count for page iPage. If this is the second |
||
8751 | ** reference to the page, add an error message to pCheck.zErrMsg. |
||
8752 | ** Return 1 if there are 2 ore more references to the page and 0 if |
||
8753 | ** if this is the first reference to the page. |
||
8754 | ** |
||
8755 | ** Also check that the page number is in bounds. |
||
8756 | */ |
||
8757 | static int checkRef( IntegrityCk pCheck, Pgno iPage, string zContext ) |
||
8758 | { |
||
8759 | if ( iPage == 0 ) |
||
8760 | return 1; |
||
8761 | if ( iPage > pCheck.nPage ) |
||
8762 | { |
||
8763 | checkAppendMsg( pCheck, zContext, "invalid page number %d", iPage ); |
||
8764 | return 1; |
||
8765 | } |
||
8766 | if ( pCheck.anRef[iPage] == 1 ) |
||
8767 | { |
||
8768 | checkAppendMsg( pCheck, zContext, "2nd reference to page %d", iPage ); |
||
8769 | return 1; |
||
8770 | } |
||
8771 | return ( ( pCheck.anRef[iPage]++ ) > 1 ) ? 1 : 0; |
||
8772 | } |
||
8773 | |||
8774 | #if !SQLITE_OMIT_AUTOVACUUM |
||
8775 | /* |
||
8776 | ** Check that the entry in the pointer-map for page iChild maps to |
||
8777 | ** page iParent, pointer type ptrType. If not, append an error message |
||
8778 | ** to pCheck. |
||
8779 | */ |
||
8780 | static void checkPtrmap( |
||
8781 | IntegrityCk pCheck, /* Integrity check context */ |
||
8782 | Pgno iChild, /* Child page number */ |
||
8783 | u8 eType, /* Expected pointer map type */ |
||
8784 | Pgno iParent, /* Expected pointer map parent page number */ |
||
8785 | string zContext /* Context description (used for error msg) */ |
||
8786 | ) |
||
8787 | { |
||
8788 | int rc; |
||
8789 | u8 ePtrmapType = 0; |
||
8790 | Pgno iPtrmapParent = 0; |
||
8791 | |||
8792 | rc = ptrmapGet( pCheck.pBt, iChild, ref ePtrmapType, ref iPtrmapParent ); |
||
8793 | if ( rc != SQLITE_OK ) |
||
8794 | { |
||
8795 | //if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck.mallocFailed = 1; |
||
8796 | checkAppendMsg( pCheck, zContext, "Failed to read ptrmap key=%d", iChild ); |
||
8797 | return; |
||
8798 | } |
||
8799 | |||
8800 | if ( ePtrmapType != eType || iPtrmapParent != iParent ) |
||
8801 | { |
||
8802 | checkAppendMsg( pCheck, zContext, |
||
8803 | "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", |
||
8804 | iChild, eType, iParent, ePtrmapType, iPtrmapParent ); |
||
8805 | } |
||
8806 | } |
||
8807 | #endif |
||
8808 | |||
8809 | /* |
||
8810 | ** Check the integrity of the freelist or of an overflow page list. |
||
8811 | ** Verify that the number of pages on the list is N. |
||
8812 | */ |
||
8813 | static void checkList( |
||
8814 | IntegrityCk pCheck, /* Integrity checking context */ |
||
8815 | int isFreeList, /* True for a freelist. False for overflow page list */ |
||
8816 | int iPage, /* Page number for first page in the list */ |
||
8817 | int N, /* Expected number of pages in the list */ |
||
8818 | string zContext /* Context for error messages */ |
||
8819 | ) |
||
8820 | { |
||
8821 | int i; |
||
8822 | int expected = N; |
||
8823 | int iFirst = iPage; |
||
8824 | while ( N-- > 0 && pCheck.mxErr != 0 ) |
||
8825 | { |
||
8826 | PgHdr pOvflPage = new PgHdr(); |
||
8827 | byte[] pOvflData; |
||
8828 | if ( iPage < 1 ) |
||
8829 | { |
||
8830 | checkAppendMsg( pCheck, zContext, |
||
8831 | "%d of %d pages missing from overflow list starting at %d", |
||
8832 | N + 1, expected, iFirst ); |
||
8833 | break; |
||
8834 | } |
||
8835 | if ( checkRef( pCheck, (u32)iPage, zContext ) != 0 ) |
||
8836 | break; |
||
8837 | if ( sqlite3PagerGet( pCheck.pPager, (Pgno)iPage, ref pOvflPage ) != 0 ) |
||
8838 | { |
||
8839 | checkAppendMsg( pCheck, zContext, "failed to get page %d", iPage ); |
||
8840 | break; |
||
8841 | } |
||
8842 | pOvflData = sqlite3PagerGetData( pOvflPage ); |
||
8843 | if ( isFreeList != 0 ) |
||
8844 | { |
||
8845 | int n = (int)sqlite3Get4byte( pOvflData, 4 ); |
||
8846 | #if !SQLITE_OMIT_AUTOVACUUM |
||
8847 | if ( pCheck.pBt.autoVacuum ) |
||
8848 | { |
||
8849 | checkPtrmap( pCheck, (u32)iPage, PTRMAP_FREEPAGE, 0, zContext ); |
||
8850 | } |
||
8851 | #endif |
||
8852 | if ( n > (int)pCheck.pBt.usableSize / 4 - 2 ) |
||
8853 | { |
||
8854 | checkAppendMsg( pCheck, zContext, |
||
8855 | "freelist leaf count too big on page %d", iPage ); |
||
8856 | N--; |
||
8857 | } |
||
8858 | else |
||
8859 | { |
||
8860 | for ( i = 0; i < n; i++ ) |
||
8861 | { |
||
8862 | Pgno iFreePage = sqlite3Get4byte( pOvflData, 8 + i * 4 ); |
||
8863 | #if !SQLITE_OMIT_AUTOVACUUM |
||
8864 | if ( pCheck.pBt.autoVacuum ) |
||
8865 | { |
||
8866 | checkPtrmap( pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext ); |
||
8867 | } |
||
8868 | #endif |
||
8869 | checkRef( pCheck, iFreePage, zContext ); |
||
8870 | } |
||
8871 | N -= n; |
||
8872 | } |
||
8873 | } |
||
8874 | #if !SQLITE_OMIT_AUTOVACUUM |
||
8875 | else |
||
8876 | { |
||
8877 | /* If this database supports auto-vacuum and iPage is not the last |
||
8878 | ** page in this overflow list, check that the pointer-map entry for |
||
8879 | ** the following page matches iPage. |
||
8880 | */ |
||
8881 | if ( pCheck.pBt.autoVacuum && N > 0 ) |
||
8882 | { |
||
8883 | i = (int)sqlite3Get4byte( pOvflData ); |
||
8884 | checkPtrmap( pCheck, (u32)i, PTRMAP_OVERFLOW2, (u32)iPage, zContext ); |
||
8885 | } |
||
8886 | } |
||
8887 | #endif |
||
8888 | iPage = (int)sqlite3Get4byte( pOvflData ); |
||
8889 | sqlite3PagerUnref( pOvflPage ); |
||
8890 | } |
||
8891 | } |
||
8892 | #endif //* SQLITE_OMIT_INTEGRITY_CHECK */ |
||
8893 | |||
8894 | #if !SQLITE_OMIT_INTEGRITY_CHECK |
||
8895 | /* |
||
8896 | ** Do various sanity checks on a single page of a tree. Return |
||
8897 | ** the tree depth. Root pages return 0. Parents of root pages |
||
8898 | ** return 1, and so forth. |
||
8899 | ** |
||
8900 | ** These checks are done: |
||
8901 | ** |
||
8902 | ** 1. Make sure that cells and freeblocks do not overlap |
||
8903 | ** but combine to completely cover the page. |
||
8904 | ** NO 2. Make sure cell keys are in order. |
||
8905 | ** NO 3. Make sure no key is less than or equal to zLowerBound. |
||
8906 | ** NO 4. Make sure no key is greater than or equal to zUpperBound. |
||
8907 | ** 5. Check the integrity of overflow pages. |
||
8908 | ** 6. Recursively call checkTreePage on all children. |
||
8909 | ** 7. Verify that the depth of all children is the same. |
||
8910 | ** 8. Make sure this page is at least 33% full or else it is |
||
8911 | ** the root of the tree. |
||
8912 | */ |
||
8913 | |||
8914 | static i64 refNULL = 0; //Dummy for C# ref NULL |
||
8915 | |||
8916 | static int checkTreePage( |
||
8917 | IntegrityCk pCheck, /* Context for the sanity check */ |
||
8918 | int iPage, /* Page number of the page to check */ |
||
8919 | string zParentContext, /* Parent context */ |
||
8920 | ref i64 pnParentMinKey, |
||
8921 | ref i64 pnParentMaxKey, |
||
8922 | object _pnParentMinKey, /* C# Needed to determine if content passed*/ |
||
8923 | object _pnParentMaxKey /* C# Needed to determine if content passed*/ |
||
8924 | ) |
||
8925 | { |
||
8926 | MemPage pPage = new MemPage(); |
||
8927 | int i, rc, depth, d2, pgno, cnt; |
||
8928 | int hdr, cellStart; |
||
8929 | int nCell; |
||
8930 | u8[] data; |
||
8931 | BtShared pBt; |
||
8932 | int usableSize; |
||
8933 | StringBuilder zContext = new StringBuilder( 100 ); |
||
8934 | byte[] hit = null; |
||
8935 | i64 nMinKey = 0; |
||
8936 | i64 nMaxKey = 0; |
||
8937 | |||
8938 | |||
8939 | sqlite3_snprintf( 200, zContext, "Page %d: ", iPage ); |
||
8940 | |||
8941 | /* Check that the page exists |
||
8942 | */ |
||
8943 | pBt = pCheck.pBt; |
||
8944 | usableSize = (int)pBt.usableSize; |
||
8945 | if ( iPage == 0 ) |
||
8946 | return 0; |
||
8947 | if ( checkRef( pCheck, (u32)iPage, zParentContext ) != 0 ) |
||
8948 | return 0; |
||
8949 | if ( ( rc = btreeGetPage( pBt, (Pgno)iPage, ref pPage, 0 ) ) != 0 ) |
||
8950 | { |
||
8951 | checkAppendMsg( pCheck, zContext.ToString(), |
||
8952 | "unable to get the page. error code=%d", rc ); |
||
8953 | return 0; |
||
8954 | } |
||
8955 | |||
8956 | /* Clear MemPage.isInit to make sure the corruption detection code in |
||
8957 | ** btreeInitPage() is executed. */ |
||
8958 | pPage.isInit = 0; |
||
8959 | if ( ( rc = btreeInitPage( pPage ) ) != 0 ) |
||
8960 | { |
||
8961 | Debug.Assert( rc == SQLITE_CORRUPT ); /* The only possible error from InitPage */ |
||
8962 | checkAppendMsg( pCheck, zContext.ToString(), |
||
8963 | "btreeInitPage() returns error code %d", rc ); |
||
8964 | releasePage( pPage ); |
||
8965 | return 0; |
||
8966 | } |
||
8967 | |||
8968 | /* Check out all the cells. |
||
8969 | */ |
||
8970 | depth = 0; |
||
8971 | for ( i = 0; i < pPage.nCell && pCheck.mxErr != 0; i++ ) |
||
8972 | { |
||
8973 | u8[] pCell; |
||
8974 | u32 sz; |
||
8975 | CellInfo info = new CellInfo(); |
||
8976 | |||
8977 | /* Check payload overflow pages |
||
8978 | */ |
||
8979 | sqlite3_snprintf( 200, zContext, |
||
8980 | "On tree page %d cell %d: ", iPage, i ); |
||
8981 | int iCell = findCell( pPage, i ); //pCell = findCell( pPage, i ); |
||
8982 | pCell = pPage.aData; |
||
8983 | btreeParseCellPtr( pPage, iCell, ref info ); //btreeParseCellPtr( pPage, pCell, info ); |
||
8984 | sz = info.nData; |
||
8985 | if ( 0 == pPage.intKey ) |
||
8986 | sz += (u32)info.nKey; |
||
8987 | /* For intKey pages, check that the keys are in order. |
||
8988 | */ |
||
8989 | else if ( i == 0 ) |
||
8990 | nMinKey = nMaxKey = info.nKey; |
||
8991 | else |
||
8992 | { |
||
8993 | if ( info.nKey <= nMaxKey ) |
||
8994 | { |
||
8995 | checkAppendMsg( pCheck, zContext.ToString(), |
||
8996 | "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey ); |
||
8997 | } |
||
8998 | nMaxKey = info.nKey; |
||
8999 | } |
||
9000 | Debug.Assert( sz == info.nPayload ); |
||
9001 | if ( ( sz > info.nLocal ) |
||
9002 | //&& (pCell[info.iOverflow]<=&pPage.aData[pBt.usableSize]) |
||
9003 | ) |
||
9004 | { |
||
9005 | int nPage = (int)( sz - info.nLocal + usableSize - 5 ) / ( usableSize - 4 ); |
||
9006 | Pgno pgnoOvfl = sqlite3Get4byte( pCell, iCell, info.iOverflow ); |
||
9007 | #if !SQLITE_OMIT_AUTOVACUUM |
||
9008 | if ( pBt.autoVacuum ) |
||
9009 | { |
||
9010 | checkPtrmap( pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, (u32)iPage, zContext.ToString() ); |
||
9011 | } |
||
9012 | #endif |
||
9013 | checkList( pCheck, 0, (int)pgnoOvfl, nPage, zContext.ToString() ); |
||
9014 | } |
||
9015 | |||
9016 | /* Check sanity of left child page. |
||
9017 | */ |
||
9018 | if ( 0 == pPage.leaf ) |
||
9019 | { |
||
9020 | pgno = (int)sqlite3Get4byte( pCell, iCell ); //sqlite3Get4byte( pCell ); |
||
9021 | #if !SQLITE_OMIT_AUTOVACUUM |
||
9022 | if ( pBt.autoVacuum ) |
||
9023 | { |
||
9024 | checkPtrmap( pCheck, (u32)pgno, PTRMAP_BTREE, (u32)iPage, zContext.ToString() ); |
||
9025 | } |
||
9026 | #endif |
||
9027 | if ( i == 0 ) |
||
9028 | d2 = checkTreePage( pCheck, pgno, zContext.ToString(), ref nMinKey, ref refNULL, pCheck, null ); |
||
9029 | else |
||
9030 | d2 = checkTreePage( pCheck, pgno, zContext.ToString(), ref nMinKey, ref nMaxKey, pCheck, pCheck ); |
||
9031 | |||
9032 | if ( i > 0 && d2 != depth ) |
||
9033 | { |
||
9034 | checkAppendMsg( pCheck, zContext, "Child page depth differs" ); |
||
9035 | } |
||
9036 | depth = d2; |
||
9037 | } |
||
9038 | } |
||
9039 | if ( 0 == pPage.leaf ) |
||
9040 | { |
||
9041 | pgno = (int)sqlite3Get4byte( pPage.aData, pPage.hdrOffset + 8 ); |
||
9042 | sqlite3_snprintf( 200, zContext, |
||
9043 | "On page %d at right child: ", iPage ); |
||
9044 | #if !SQLITE_OMIT_AUTOVACUUM |
||
9045 | if ( pBt.autoVacuum ) |
||
9046 | { |
||
9047 | checkPtrmap( pCheck, (u32)pgno, PTRMAP_BTREE, (u32)iPage, zContext.ToString() ); |
||
9048 | } |
||
9049 | #endif |
||
9050 | // checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey); |
||
9051 | if ( 0 == pPage.nCell ) |
||
9052 | checkTreePage( pCheck, pgno, zContext.ToString(), ref refNULL, ref refNULL, null, null ); |
||
9053 | else |
||
9054 | checkTreePage( pCheck, pgno, zContext.ToString(), ref refNULL, ref nMaxKey, null, pCheck ); |
||
9055 | } |
||
9056 | |||
9057 | /* For intKey leaf pages, check that the min/max keys are in order |
||
9058 | ** with any left/parent/right pages. |
||
9059 | */ |
||
9060 | if ( pPage.leaf != 0 && pPage.intKey != 0 ) |
||
9061 | { |
||
9062 | /* if we are a left child page */ |
||
9063 | if ( _pnParentMinKey != null ) |
||
9064 | { |
||
9065 | /* if we are the left most child page */ |
||
9066 | if ( _pnParentMaxKey == null ) |
||
9067 | { |
||
9068 | if ( nMaxKey > pnParentMinKey ) |
||
9069 | { |
||
9070 | checkAppendMsg( pCheck, zContext, |
||
9071 | "Rowid %lld out of order (max larger than parent min of %lld)", |
||
9072 | nMaxKey, pnParentMinKey ); |
||
9073 | } |
||
9074 | } |
||
9075 | else |
||
9076 | { |
||
9077 | if ( nMinKey <= pnParentMinKey ) |
||
9078 | { |
||
9079 | checkAppendMsg( pCheck, zContext, |
||
9080 | "Rowid %lld out of order (min less than parent min of %lld)", |
||
9081 | nMinKey, pnParentMinKey ); |
||
9082 | } |
||
9083 | if ( nMaxKey > pnParentMaxKey ) |
||
9084 | { |
||
9085 | checkAppendMsg( pCheck, zContext, |
||
9086 | "Rowid %lld out of order (max larger than parent max of %lld)", |
||
9087 | nMaxKey, pnParentMaxKey ); |
||
9088 | } |
||
9089 | pnParentMinKey = nMaxKey; |
||
9090 | } |
||
9091 | /* else if we're a right child page */ |
||
9092 | } |
||
9093 | else if ( _pnParentMaxKey != null ) |
||
9094 | { |
||
9095 | if ( nMinKey <= pnParentMaxKey ) |
||
9096 | { |
||
9097 | checkAppendMsg( pCheck, zContext, |
||
9098 | "Rowid %lld out of order (min less than parent max of %lld)", |
||
9099 | nMinKey, pnParentMaxKey ); |
||
9100 | } |
||
9101 | } |
||
9102 | } |
||
9103 | |||
9104 | /* Check for complete coverage of the page |
||
9105 | */ |
||
9106 | data = pPage.aData; |
||
9107 | hdr = pPage.hdrOffset; |
||
9108 | hit = sqlite3Malloc( pBt.pageSize ); |
||
9109 | //if( hit==null ){ |
||
9110 | // pCheck.mallocFailed = 1; |
||
9111 | //}else |
||
9112 | { |
||
9113 | int contentOffset = get2byteNotZero( data, hdr + 5 ); |
||
9114 | Debug.Assert( contentOffset <= usableSize ); /* Enforced by btreeInitPage() */ |
||
9115 | Array.Clear( hit, contentOffset, usableSize - contentOffset );//memset(hit+contentOffset, 0, usableSize-contentOffset); |
||
9116 | for ( int iLoop = contentOffset - 1; iLoop >= 0; iLoop-- ) |
||
9117 | hit[iLoop] = 1;//memset(hit, 1, contentOffset); |
||
9118 | nCell = get2byte( data, hdr + 3 ); |
||
9119 | cellStart = hdr + 12 - 4 * pPage.leaf; |
||
9120 | for ( i = 0; i < nCell; i++ ) |
||
9121 | { |
||
9122 | int pc = get2byte( data, cellStart + i * 2 ); |
||
9123 | u32 size = 65536; |
||
9124 | int j; |
||
9125 | if ( pc <= usableSize - 4 ) |
||
9126 | { |
||
9127 | size = cellSizePtr( pPage, data, pc ); |
||
9128 | } |
||
9129 | if ( (int)( pc + size - 1 ) >= usableSize ) |
||
9130 | { |
||
9131 | checkAppendMsg( pCheck, string.Empty, |
||
9132 | "Corruption detected in cell %d on page %d", i, iPage ); |
||
9133 | } |
||
9134 | else |
||
9135 | { |
||
9136 | for ( j = (int)( pc + size - 1 ); j >= pc; j-- ) |
||
9137 | hit[j]++; |
||
9138 | } |
||
9139 | } |
||
9140 | i = get2byte( data, hdr + 1 ); |
||
9141 | while ( i > 0 ) |
||
9142 | { |
||
9143 | int size, j; |
||
9144 | Debug.Assert( i <= usableSize - 4 ); /* Enforced by btreeInitPage() */ |
||
9145 | size = get2byte( data, i + 2 ); |
||
9146 | Debug.Assert( i + size <= usableSize ); /* Enforced by btreeInitPage() */ |
||
9147 | for ( j = i + size - 1; j >= i; j-- ) |
||
9148 | hit[j]++; |
||
9149 | j = get2byte( data, i ); |
||
9150 | Debug.Assert( j == 0 || j > i + size ); /* Enforced by btreeInitPage() */ |
||
9151 | Debug.Assert( j <= usableSize - 4 ); /* Enforced by btreeInitPage() */ |
||
9152 | i = j; |
||
9153 | } |
||
9154 | for ( i = cnt = 0; i < usableSize; i++ ) |
||
9155 | { |
||
9156 | if ( hit[i] == 0 ) |
||
9157 | { |
||
9158 | cnt++; |
||
9159 | } |
||
9160 | else if ( hit[i] > 1 ) |
||
9161 | { |
||
9162 | checkAppendMsg( pCheck, string.Empty, |
||
9163 | "Multiple uses for byte %d of page %d", i, iPage ); |
||
9164 | break; |
||
9165 | } |
||
9166 | } |
||
9167 | if ( cnt != data[hdr + 7] ) |
||
9168 | { |
||
9169 | checkAppendMsg( pCheck, string.Empty, |
||
9170 | "Fragmentation of %d bytes reported as %d on page %d", |
||
9171 | cnt, data[hdr + 7], iPage ); |
||
9172 | } |
||
9173 | } |
||
9174 | sqlite3PageFree( ref hit ); |
||
9175 | releasePage( pPage ); |
||
9176 | return depth + 1; |
||
9177 | } |
||
9178 | #endif //* SQLITE_OMIT_INTEGRITY_CHECK */ |
||
9179 | |||
9180 | #if !SQLITE_OMIT_INTEGRITY_CHECK |
||
9181 | /* |
||
9182 | ** This routine does a complete check of the given BTree file. aRoot[] is |
||
9183 | ** an array of pages numbers were each page number is the root page of |
||
9184 | ** a table. nRoot is the number of entries in aRoot. |
||
9185 | ** |
||
9186 | ** A read-only or read-write transaction must be opened before calling |
||
9187 | ** this function. |
||
9188 | ** |
||
9189 | ** Write the number of error seen in pnErr. Except for some memory |
||
9190 | ** allocation errors, an error message held in memory obtained from |
||
9191 | ** malloc is returned if pnErr is non-zero. If pnErr==null then NULL is |
||
9192 | ** returned. If a memory allocation error occurs, NULL is returned. |
||
9193 | */ |
||
9194 | static string sqlite3BtreeIntegrityCheck( |
||
9195 | Btree p, /* The btree to be checked */ |
||
9196 | int[] aRoot, /* An array of root pages numbers for individual trees */ |
||
9197 | int nRoot, /* Number of entries in aRoot[] */ |
||
9198 | int mxErr, /* Stop reporting errors after this many */ |
||
9199 | ref int pnErr /* Write number of errors seen to this variable */ |
||
9200 | ) |
||
9201 | { |
||
9202 | Pgno i; |
||
9203 | int nRef; |
||
9204 | IntegrityCk sCheck = new IntegrityCk(); |
||
9205 | BtShared pBt = p.pBt; |
||
9206 | |||
9207 | sqlite3BtreeEnter( p ); |
||
9208 | Debug.Assert( p.inTrans > TRANS_NONE && pBt.inTransaction > TRANS_NONE ); |
||
9209 | nRef = sqlite3PagerRefcount( pBt.pPager ); |
||
9210 | sCheck.pBt = pBt; |
||
9211 | sCheck.pPager = pBt.pPager; |
||
9212 | sCheck.nPage = btreePagecount( sCheck.pBt ); |
||
9213 | sCheck.mxErr = mxErr; |
||
9214 | sCheck.nErr = 0; |
||
9215 | //sCheck.mallocFailed = 0; |
||
9216 | pnErr = 0; |
||
9217 | if ( sCheck.nPage == 0 ) |
||
9218 | { |
||
9219 | sqlite3BtreeLeave( p ); |
||
9220 | return string.Empty; |
||
9221 | } |
||
9222 | sCheck.anRef = sqlite3Malloc( sCheck.anRef, (int)sCheck.nPage + 1 ); |
||
9223 | //if( !sCheck.anRef ){ |
||
9224 | // pnErr = 1; |
||
9225 | // sqlite3BtreeLeave(p); |
||
9226 | // return 0; |
||
9227 | //} |
||
9228 | // for (i = 0; i <= sCheck.nPage; i++) { sCheck.anRef[i] = 0; } |
||
9229 | i = PENDING_BYTE_PAGE( pBt ); |
||
9230 | if ( i <= sCheck.nPage ) |
||
9231 | { |
||
9232 | sCheck.anRef[i] = 1; |
||
9233 | } |
||
9234 | sqlite3StrAccumInit( sCheck.errMsg, null, 1000, 20000 ); |
||
9235 | //sCheck.errMsg.useMalloc = 2; |
||
9236 | |||
9237 | /* Check the integrity of the freelist |
||
9238 | */ |
||
9239 | checkList( sCheck, 1, (int)sqlite3Get4byte( pBt.pPage1.aData, 32 ), |
||
9240 | (int)sqlite3Get4byte( pBt.pPage1.aData, 36 ), "Main freelist: " ); |
||
9241 | |||
9242 | /* Check all the tables. |
||
9243 | */ |
||
9244 | for ( i = 0; (int)i < nRoot && sCheck.mxErr != 0; i++ ) |
||
9245 | { |
||
9246 | if ( aRoot[i] == 0 ) |
||
9247 | continue; |
||
9248 | #if !SQLITE_OMIT_AUTOVACUUM |
||
9249 | if ( pBt.autoVacuum && aRoot[i] > 1 ) |
||
9250 | { |
||
9251 | checkPtrmap( sCheck, (u32)aRoot[i], PTRMAP_ROOTPAGE, 0, string.Empty ); |
||
9252 | } |
||
9253 | #endif |
||
9254 | checkTreePage( sCheck, aRoot[i], "List of tree roots: ", ref refNULL, ref refNULL, null, null ); |
||
9255 | } |
||
9256 | |||
9257 | /* Make sure every page in the file is referenced |
||
9258 | */ |
||
9259 | for ( i = 1; i <= sCheck.nPage && sCheck.mxErr != 0; i++ ) |
||
9260 | { |
||
9261 | #if SQLITE_OMIT_AUTOVACUUM |
||
9262 | if( sCheck.anRef[i]==null ){ |
||
9263 | checkAppendMsg(sCheck, 0, "Page %d is never used", i); |
||
9264 | } |
||
9265 | #else |
||
9266 | /* If the database supports auto-vacuum, make sure no tables contain |
||
9267 | ** references to pointer-map pages. |
||
9268 | */ |
||
9269 | if ( sCheck.anRef[i] == 0 && |
||
9270 | ( PTRMAP_PAGENO( pBt, i ) != i || !pBt.autoVacuum ) ) |
||
9271 | { |
||
9272 | checkAppendMsg( sCheck, string.Empty, "Page %d is never used", i ); |
||
9273 | } |
||
9274 | if ( sCheck.anRef[i] != 0 && |
||
9275 | ( PTRMAP_PAGENO( pBt, i ) == i && pBt.autoVacuum ) ) |
||
9276 | { |
||
9277 | checkAppendMsg( sCheck, string.Empty, "Pointer map page %d is referenced", i ); |
||
9278 | } |
||
9279 | #endif |
||
9280 | } |
||
9281 | |||
9282 | /* Make sure this analysis did not leave any unref() pages. |
||
9283 | ** This is an internal consistency check; an integrity check |
||
9284 | ** of the integrity check. |
||
9285 | */ |
||
9286 | if ( NEVER( nRef != sqlite3PagerRefcount( pBt.pPager ) ) ) |
||
9287 | { |
||
9288 | checkAppendMsg( sCheck, string.Empty, |
||
9289 | "Outstanding page count goes from %d to %d during this analysis", |
||
9290 | nRef, sqlite3PagerRefcount( pBt.pPager ) |
||
9291 | ); |
||
9292 | } |
||
9293 | |||
9294 | /* Clean up and report errors. |
||
9295 | */ |
||
9296 | sqlite3BtreeLeave( p ); |
||
9297 | sCheck.anRef = null;// sqlite3_free( ref sCheck.anRef ); |
||
9298 | //if( sCheck.mallocFailed ){ |
||
9299 | // sqlite3StrAccumReset(sCheck.errMsg); |
||
9300 | // pnErr = sCheck.nErr+1; |
||
9301 | // return 0; |
||
9302 | //} |
||
9303 | pnErr = sCheck.nErr; |
||
9304 | if ( sCheck.nErr == 0 ) |
||
9305 | sqlite3StrAccumReset( sCheck.errMsg ); |
||
9306 | return sqlite3StrAccumFinish( sCheck.errMsg ); |
||
9307 | } |
||
9308 | #endif //* SQLITE_OMIT_INTEGRITY_CHECK */ |
||
9309 | |||
9310 | /* |
||
9311 | ** Return the full pathname of the underlying database file. |
||
9312 | ** |
||
9313 | ** The pager filename is invariant as long as the pager is |
||
9314 | ** open so it is safe to access without the BtShared mutex. |
||
9315 | */ |
||
9316 | static string sqlite3BtreeGetFilename( Btree p ) |
||
9317 | { |
||
9318 | Debug.Assert( p.pBt.pPager != null ); |
||
9319 | return sqlite3PagerFilename( p.pBt.pPager ); |
||
9320 | } |
||
9321 | |||
9322 | /* |
||
9323 | ** Return the pathname of the journal file for this database. The return |
||
9324 | ** value of this routine is the same regardless of whether the journal file |
||
9325 | ** has been created or not. |
||
9326 | ** |
||
9327 | ** The pager journal filename is invariant as long as the pager is |
||
9328 | ** open so it is safe to access without the BtShared mutex. |
||
9329 | */ |
||
9330 | static string sqlite3BtreeGetJournalname( Btree p ) |
||
9331 | { |
||
9332 | Debug.Assert( p.pBt.pPager != null ); |
||
9333 | return sqlite3PagerJournalname( p.pBt.pPager ); |
||
9334 | } |
||
9335 | |||
9336 | /* |
||
9337 | ** Return non-zero if a transaction is active. |
||
9338 | */ |
||
9339 | static bool sqlite3BtreeIsInTrans( Btree p ) |
||
9340 | { |
||
9341 | Debug.Assert( p == null || sqlite3_mutex_held( p.db.mutex ) ); |
||
9342 | return ( p != null && ( p.inTrans == TRANS_WRITE ) ); |
||
9343 | } |
||
9344 | |||
9345 | #if !SQLITE_OMIT_WAL |
||
9346 | /* |
||
9347 | ** Run a checkpoint on the Btree passed as the first argument. |
||
9348 | ** |
||
9349 | ** Return SQLITE_LOCKED if this or any other connection has an open |
||
9350 | ** transaction on the shared-cache the argument Btree is connected to. |
||
9351 | ** |
||
9352 | ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. |
||
9353 | */ |
||
9354 | static int sqlite3BtreeCheckpointBtree *p, int eMode, int *pnLog, int *pnCkpt){ |
||
9355 | int rc = SQLITE_OK; |
||
9356 | if( p != null){ |
||
9357 | BtShared pBt = p.pBt; |
||
9358 | sqlite3BtreeEnter(p); |
||
9359 | if( pBt.inTransaction!=TRANS_NONE ){ |
||
9360 | rc = SQLITE_LOCKED; |
||
9361 | }else{ |
||
9362 | rc = sqlite3PagerCheckpoint(pBt.pPager, eMode, pnLog, pnCkpt); |
||
9363 | } |
||
9364 | sqlite3BtreeLeave(p); |
||
9365 | } |
||
9366 | return rc; |
||
9367 | } |
||
9368 | #endif |
||
9369 | |||
9370 | /* |
||
9371 | ** Return non-zero if a read (or write) transaction is active. |
||
9372 | */ |
||
9373 | static bool sqlite3BtreeIsInReadTrans( Btree p ) |
||
9374 | { |
||
9375 | Debug.Assert( p != null ); |
||
9376 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
9377 | return p.inTrans != TRANS_NONE; |
||
9378 | } |
||
9379 | |||
9380 | static bool sqlite3BtreeIsInBackup( Btree p ) |
||
9381 | { |
||
9382 | Debug.Assert( p != null ); |
||
9383 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
9384 | return p.nBackup != 0; |
||
9385 | } |
||
9386 | |||
9387 | /* |
||
9388 | ** This function returns a pointer to a blob of memory associated with |
||
9389 | ** a single shared-btree. The memory is used by client code for its own |
||
9390 | ** purposes (for example, to store a high-level schema associated with |
||
9391 | ** the shared-btree). The btree layer manages reference counting issues. |
||
9392 | ** |
||
9393 | ** The first time this is called on a shared-btree, nBytes bytes of memory |
||
9394 | ** are allocated, zeroed, and returned to the caller. For each subsequent |
||
9395 | ** call the nBytes parameter is ignored and a pointer to the same blob |
||
9396 | ** of memory returned. |
||
9397 | ** |
||
9398 | ** If the nBytes parameter is 0 and the blob of memory has not yet been |
||
9399 | ** allocated, a null pointer is returned. If the blob has already been |
||
9400 | ** allocated, it is returned as normal. |
||
9401 | ** |
||
9402 | ** Just before the shared-btree is closed, the function passed as the |
||
9403 | ** xFree argument when the memory allocation was made is invoked on the |
||
9404 | ** blob of allocated memory. The xFree function should not call sqlite3_free() |
||
9405 | ** on the memory, the btree layer does that. |
||
9406 | */ |
||
9407 | static Schema sqlite3BtreeSchema( Btree p, int nBytes, dxFreeSchema xFree ) |
||
9408 | { |
||
9409 | BtShared pBt = p.pBt; |
||
9410 | sqlite3BtreeEnter( p ); |
||
9411 | if ( null == pBt.pSchema && nBytes != 0 ) |
||
9412 | { |
||
9413 | pBt.pSchema = new Schema();//sqlite3DbMallocZero(0, nBytes); |
||
9414 | pBt.xFreeSchema = xFree; |
||
9415 | } |
||
9416 | sqlite3BtreeLeave( p ); |
||
9417 | return pBt.pSchema; |
||
9418 | } |
||
9419 | |||
9420 | /* |
||
9421 | ** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared |
||
9422 | ** btree as the argument handle holds an exclusive lock on the |
||
9423 | ** sqlite_master table. Otherwise SQLITE_OK. |
||
9424 | */ |
||
9425 | static int sqlite3BtreeSchemaLocked( Btree p ) |
||
9426 | { |
||
9427 | int rc; |
||
9428 | Debug.Assert( sqlite3_mutex_held( p.db.mutex ) ); |
||
9429 | sqlite3BtreeEnter( p ); |
||
9430 | rc = querySharedCacheTableLock( p, MASTER_ROOT, READ_LOCK ); |
||
9431 | Debug.Assert( rc == SQLITE_OK || rc == SQLITE_LOCKED_SHAREDCACHE ); |
||
9432 | sqlite3BtreeLeave( p ); |
||
9433 | return rc; |
||
9434 | } |
||
9435 | |||
9436 | |||
9437 | #if !SQLITE_OMIT_SHARED_CACHE |
||
9438 | /* |
||
9439 | ** Obtain a lock on the table whose root page is iTab. The |
||
9440 | ** lock is a write lock if isWritelock is true or a read lock |
||
9441 | ** if it is false. |
||
9442 | */ |
||
9443 | int sqlite3BtreeLockTable(Btree p, int iTab, u8 isWriteLock){ |
||
9444 | int rc = SQLITE_OK; |
||
9445 | Debug.Assert( p.inTrans!=TRANS_NONE ); |
||
9446 | if( p.sharable ){ |
||
9447 | u8 lockType = READ_LOCK + isWriteLock; |
||
9448 | Debug.Assert( READ_LOCK+1==WRITE_LOCK ); |
||
9449 | Debug.Assert( isWriteLock==null || isWriteLock==1 ); |
||
9450 | |||
9451 | sqlite3BtreeEnter(p); |
||
9452 | rc = querySharedCacheTableLock(p, iTab, lockType); |
||
9453 | if( rc==SQLITE_OK ){ |
||
9454 | rc = setSharedCacheTableLock(p, iTab, lockType); |
||
9455 | } |
||
9456 | sqlite3BtreeLeave(p); |
||
9457 | } |
||
9458 | return rc; |
||
9459 | } |
||
9460 | #endif |
||
9461 | |||
9462 | #if !SQLITE_OMIT_INCRBLOB |
||
9463 | /* |
||
9464 | ** Argument pCsr must be a cursor opened for writing on an |
||
9465 | ** INTKEY table currently pointing at a valid table entry. |
||
9466 | ** This function modifies the data stored as part of that entry. |
||
9467 | ** |
||
9468 | ** Only the data content may only be modified, it is not possible to |
||
9469 | ** change the length of the data stored. If this function is called with |
||
9470 | ** parameters that attempt to write past the end of the existing data, |
||
9471 | ** no modifications are made and SQLITE_CORRUPT is returned. |
||
9472 | */ |
||
9473 | int sqlite3BtreePutData(BtCursor pCsr, u32 offset, u32 amt, void *z){ |
||
9474 | int rc; |
||
9475 | Debug.Assert( cursorHoldsMutex(pCsr) ); |
||
9476 | Debug.Assert( sqlite3_mutex_held(pCsr.pBtree.db.mutex) ); |
||
9477 | Debug.Assert( pCsr.isIncrblobHandle ); |
||
9478 | |||
9479 | rc = restoreCursorPosition(pCsr); |
||
9480 | if( rc!=SQLITE_OK ){ |
||
9481 | return rc; |
||
9482 | } |
||
9483 | Debug.Assert( pCsr.eState!=CURSOR_REQUIRESEEK ); |
||
9484 | if( pCsr.eState!=CURSOR_VALID ){ |
||
9485 | return SQLITE_ABORT; |
||
9486 | } |
||
9487 | |||
9488 | /* Check some assumptions: |
||
9489 | ** (a) the cursor is open for writing, |
||
9490 | ** (b) there is a read/write transaction open, |
||
9491 | ** (c) the connection holds a write-lock on the table (if required), |
||
9492 | ** (d) there are no conflicting read-locks, and |
||
9493 | ** (e) the cursor points at a valid row of an intKey table. |
||
9494 | */ |
||
9495 | if( !pCsr.wrFlag ){ |
||
9496 | return SQLITE_READONLY; |
||
9497 | } |
||
9498 | Debug.Assert( !pCsr.pBt.readOnly && pCsr.pBt.inTransaction==TRANS_WRITE ); |
||
9499 | Debug.Assert( hasSharedCacheTableLock(pCsr.pBtree, pCsr.pgnoRoot, 0, 2) ); |
||
9500 | Debug.Assert( !hasReadConflicts(pCsr.pBtree, pCsr.pgnoRoot) ); |
||
9501 | Debug.Assert( pCsr.apPage[pCsr.iPage].intKey ); |
||
9502 | |||
9503 | return accessPayload(pCsr, offset, amt, (byte[] *)z, 1); |
||
9504 | } |
||
9505 | |||
9506 | /* |
||
9507 | ** Set a flag on this cursor to cache the locations of pages from the |
||
9508 | ** overflow list for the current row. This is used by cursors opened |
||
9509 | ** for incremental blob IO only. |
||
9510 | ** |
||
9511 | ** This function sets a flag only. The actual page location cache |
||
9512 | ** (stored in BtCursor.aOverflow[]) is allocated and used by function |
||
9513 | ** accessPayload() (the worker function for sqlite3BtreeData() and |
||
9514 | ** sqlite3BtreePutData()). |
||
9515 | */ |
||
9516 | static void sqlite3BtreeCacheOverflow(BtCursor pCur){ |
||
9517 | Debug.Assert( cursorHoldsMutex(pCur) ); |
||
9518 | Debug.Assert( sqlite3_mutex_held(pCur.pBtree.db.mutex) ); |
||
9519 | invalidateOverflowCache(pCur) |
||
9520 | pCur.isIncrblobHandle = 1; |
||
9521 | } |
||
9522 | #endif |
||
9523 | |||
9524 | /* |
||
9525 | ** Set both the "read version" (single byte at byte offset 18) and |
||
9526 | ** "write version" (single byte at byte offset 19) fields in the database |
||
9527 | ** header to iVersion. |
||
9528 | */ |
||
9529 | static int sqlite3BtreeSetVersion( Btree pBtree, int iVersion ) |
||
9530 | { |
||
9531 | BtShared pBt = pBtree.pBt; |
||
9532 | int rc; /* Return code */ |
||
9533 | |||
9534 | Debug.Assert( pBtree.inTrans == TRANS_NONE ); |
||
9535 | Debug.Assert( iVersion == 1 || iVersion == 2 ); |
||
9536 | |||
9537 | /* If setting the version fields to 1, do not automatically open the |
||
9538 | ** WAL connection, even if the version fields are currently set to 2. |
||
9539 | */ |
||
9540 | pBt.doNotUseWAL = iVersion == 1; |
||
9541 | |||
9542 | rc = sqlite3BtreeBeginTrans( pBtree, 0 ); |
||
9543 | if ( rc == SQLITE_OK ) |
||
9544 | { |
||
9545 | u8[] aData = pBt.pPage1.aData; |
||
9546 | if ( aData[18] != (u8)iVersion || aData[19] != (u8)iVersion ) |
||
9547 | { |
||
9548 | rc = sqlite3BtreeBeginTrans( pBtree, 2 ); |
||
9549 | if ( rc == SQLITE_OK ) |
||
9550 | { |
||
9551 | rc = sqlite3PagerWrite( pBt.pPage1.pDbPage ); |
||
9552 | if ( rc == SQLITE_OK ) |
||
9553 | { |
||
9554 | aData[18] = (u8)iVersion; |
||
9555 | aData[19] = (u8)iVersion; |
||
9556 | } |
||
9557 | } |
||
9558 | } |
||
9559 | } |
||
9560 | |||
9561 | pBt.doNotUseWAL = false; |
||
9562 | return rc; |
||
9563 | } |
||
9564 | } |
||
9565 | } |