Split the sqlite3BtreeMovetoUnpacked() routine into two separate routines
sqlite3BtreeTableMoveto() and sqlite3BtreeIndexMoveto(), since we usually know the type of btree in advance. This results in less branching and better performance. FossilOrigin-Name: 3b0d34e5e5f9a16c3397e4551f3b534729b1b375770f05f6ed5847818b1f4c0b
This commit is contained in:
parent
6d72858e79
commit
42a410dcad
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
||||
C Version\s3.36.0
|
||||
D 2021-06-18T18:36:39.378
|
||||
C Split\sthe\ssqlite3BtreeMovetoUnpacked()\sroutine\sinto\stwo\sseparate\sroutines\nsqlite3BtreeTableMoveto()\sand\ssqlite3BtreeIndexMoveto(),\ssince\swe\susually\nknow\sthe\stype\sof\sbtree\sin\sadvance.\s\sThis\sresults\sin\sless\sbranching\sand\nbetter\sperformance.
|
||||
D 2021-06-19T18:32:20.087
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -485,8 +485,8 @@ F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 399e1ebcd6c4f9ad47f5457bfe3623441db287f0923433cf6539497791557be8
|
||||
F src/btree.h 096cc53baa58be22b02c896d1cf933c38cfc6d65f9253c1367ece8cc88a24de5
|
||||
F src/btree.c 6079ee9dc399a7a6f0727f2c6ba2f43c18600c71827a76ddcdedde54a58b646e
|
||||
F src/btree.h ace9c1c243612bb95c32d848e3f9e159340c2caefcb68412b441569f56328f65
|
||||
F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0
|
||||
F src/build.c ea28944f65b04f771e7aa5d614d406faa1bde5fe4ce882e2ead73049f03ed568
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
@ -616,11 +616,11 @@ F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
|
||||
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
|
||||
F src/vdbe.c 6ece0ee94fa3a95601372efdc4ec6d068cd6cc58e28af8852f3407b90be4b7f8
|
||||
F src/vdbe.c 226deb5bc5d88c4feb215cccaecdbe36924078737f27629fa06123d4da10f609
|
||||
F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
|
||||
F src/vdbeInt.h 465fcb494db4ca6630fb9c19b2f3dfed597fbe885b0d4204193a5093b0dd7dc6
|
||||
F src/vdbeapi.c aa5aaf2c37676b83af5724c6cd8207a3064ed46a217fd180957f75ac84f7a2a5
|
||||
F src/vdbeaux.c 065a10392378109f08435bd50d03dff315e384cde2831d6b8dbaec05f33b10af
|
||||
F src/vdbeaux.c 17e5f6a491d439396296dd20427829fad14c78a6be8f84415d253ff94c31ce9a
|
||||
F src/vdbeblob.c c6b8db50b227f66fb404215732068df76485b5b433e5f9d4d9ac27410b218193
|
||||
F src/vdbemem.c 53881aa0a7845922a075b3f375695588618098871a7a4120af4c297b80fa3e64
|
||||
F src/vdbesort.c cd5130f683706c1a43e165a74187745fb3351cb56052cf9dc91de820634bbde2
|
||||
@ -1918,9 +1918,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 7bd55eee1ac63cf6d5699ce85bc5a29bf51afdf7a80bce44937fa833947a40f4
|
||||
R 6b8a0a7cf847af9edb1fb9387491b821
|
||||
T +sym-release *
|
||||
T +sym-version-3.36.0 *
|
||||
P 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5
|
||||
R cc13a86c593d747f18b1766f1996fa8f
|
||||
U drh
|
||||
Z 05ee2bbc3eef4148ab2800c954a168c4
|
||||
Z 15ce4941abcea77bc0d9552f8406032e
|
||||
|
@ -1 +1 @@
|
||||
5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5
|
||||
3b0d34e5e5f9a16c3397e4551f3b534729b1b375770f05f6ed5847818b1f4c0b
|
403
src/btree.c
403
src/btree.c
@ -827,15 +827,13 @@ static int btreeMoveto(
|
||||
sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
|
||||
if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto moveto_done;
|
||||
}else{
|
||||
rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes);
|
||||
}
|
||||
sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
|
||||
}else{
|
||||
pIdxKey = 0;
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
|
||||
moveto_done:
|
||||
if( pIdxKey ){
|
||||
sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
|
||||
rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -5421,12 +5419,8 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Move the cursor so that it points to an entry near the key
|
||||
** specified by pIdxKey or intKey. Return a success code.
|
||||
**
|
||||
** For INTKEY tables, the intKey parameter is used. pIdxKey
|
||||
** must be NULL. For index tables, pIdxKey is used and intKey
|
||||
** is ignored.
|
||||
/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)
|
||||
** table near the key intKey. Return a success code.
|
||||
**
|
||||
** If an exact match is not found, then the cursor is always
|
||||
** left pointing at a leaf page which would hold the entry if it
|
||||
@ -5439,39 +5433,32 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
** *pRes is as follows:
|
||||
**
|
||||
** *pRes<0 The cursor is left pointing at an entry that
|
||||
** is smaller than intKey/pIdxKey or if the table is empty
|
||||
** is smaller than intKey or if the table is empty
|
||||
** and the cursor is therefore left point to nothing.
|
||||
**
|
||||
** *pRes==0 The cursor is left pointing at an entry that
|
||||
** exactly matches intKey/pIdxKey.
|
||||
** exactly matches intKey.
|
||||
**
|
||||
** *pRes>0 The cursor is left pointing at an entry that
|
||||
** is larger than intKey/pIdxKey.
|
||||
**
|
||||
** For index tables, the pIdxKey->eqSeen field is set to 1 if there
|
||||
** exists an entry in the table that exactly matches pIdxKey.
|
||||
** is larger than intKey.
|
||||
*/
|
||||
int sqlite3BtreeMovetoUnpacked(
|
||||
int sqlite3BtreeTableMoveto(
|
||||
BtCursor *pCur, /* The cursor to be moved */
|
||||
UnpackedRecord *pIdxKey, /* Unpacked index key */
|
||||
i64 intKey, /* The table key */
|
||||
int biasRight, /* If true, bias the search to the high end */
|
||||
int *pRes /* Write search results here */
|
||||
){
|
||||
int rc;
|
||||
RecordCompare xRecordCompare;
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( pRes );
|
||||
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
|
||||
assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
|
||||
assert( pCur->pKeyInfo==0 );
|
||||
assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 );
|
||||
|
||||
/* If the cursor is already positioned at the point we are trying
|
||||
** to move to, then just return without doing any work */
|
||||
if( pIdxKey==0
|
||||
&& pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
|
||||
){
|
||||
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){
|
||||
if( pCur->info.nKey==intKey ){
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
@ -5506,16 +5493,149 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
pCur->pBtree->nSeek++; /* Performance measurement during testing */
|
||||
#endif
|
||||
|
||||
if( pIdxKey ){
|
||||
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
||||
pIdxKey->errCode = 0;
|
||||
assert( pIdxKey->default_rc==1
|
||||
|| pIdxKey->default_rc==0
|
||||
|| pIdxKey->default_rc==-1
|
||||
);
|
||||
}else{
|
||||
xRecordCompare = 0; /* All keys are integers */
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ){
|
||||
if( rc==SQLITE_EMPTY ){
|
||||
assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
|
||||
*pRes = -1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
assert( pCur->pPage );
|
||||
assert( pCur->pPage->isInit );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->pPage->nCell > 0 );
|
||||
assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
|
||||
assert( pCur->curIntKey );
|
||||
|
||||
for(;;){
|
||||
int lwr, upr, idx, c;
|
||||
Pgno chldPg;
|
||||
MemPage *pPage = pCur->pPage;
|
||||
u8 *pCell; /* Pointer to current cell in pPage */
|
||||
|
||||
/* pPage->nCell must be greater than zero. If this is the root-page
|
||||
** the cursor would have been INVALID above and this for(;;) loop
|
||||
** not run. If this is not the root-page, then the moveToChild() routine
|
||||
** would have already detected db corruption. Similarly, pPage must
|
||||
** be the right kind (index or table) of b-tree page. Otherwise
|
||||
** a moveToChild() or moveToRoot() call would have detected corruption. */
|
||||
assert( pPage->nCell>0 );
|
||||
assert( pPage->intKey );
|
||||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
assert( biasRight==0 || biasRight==1 );
|
||||
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
||||
pCur->ix = (u16)idx;
|
||||
for(;;){
|
||||
i64 nCellKey;
|
||||
pCell = findCellPastPtr(pPage, idx);
|
||||
if( pPage->intKeyLeaf ){
|
||||
while( 0x80 <= *(pCell++) ){
|
||||
if( pCell>=pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
getVarint(pCell, (u64*)&nCellKey);
|
||||
if( nCellKey<intKey ){
|
||||
lwr = idx+1;
|
||||
if( lwr>upr ){ c = -1; break; }
|
||||
}else if( nCellKey>intKey ){
|
||||
upr = idx-1;
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->ix = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
lwr = idx;
|
||||
goto moveto_table_next_layer;
|
||||
}else{
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->info.nSize = 0;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
assert( lwr+upr>=0 );
|
||||
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */
|
||||
}
|
||||
assert( lwr==upr+1 || !pPage->leaf );
|
||||
assert( pPage->isInit );
|
||||
if( pPage->leaf ){
|
||||
assert( pCur->ix<pCur->pPage->nCell );
|
||||
pCur->ix = (u16)idx;
|
||||
*pRes = c;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_table_finish;
|
||||
}
|
||||
moveto_table_next_layer:
|
||||
if( lwr>=pPage->nCell ){
|
||||
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage, lwr));
|
||||
}
|
||||
pCur->ix = (u16)lwr;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) break;
|
||||
}
|
||||
moveto_table_finish:
|
||||
pCur->info.nSize = 0;
|
||||
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Move the cursor so that it points to an entry in an index table
|
||||
** near the key pIdxKey. Return a success code.
|
||||
**
|
||||
** If an exact match is not found, then the cursor is always
|
||||
** left pointing at a leaf page which would hold the entry if it
|
||||
** were present. The cursor might point to an entry that comes
|
||||
** before or after the key.
|
||||
**
|
||||
** An integer is written into *pRes which is the result of
|
||||
** comparing the key with the entry to which the cursor is
|
||||
** pointing. The meaning of the integer written into
|
||||
** *pRes is as follows:
|
||||
**
|
||||
** *pRes<0 The cursor is left pointing at an entry that
|
||||
** is smaller than pIdxKey or if the table is empty
|
||||
** and the cursor is therefore left point to nothing.
|
||||
**
|
||||
** *pRes==0 The cursor is left pointing at an entry that
|
||||
** exactly matches pIdxKey.
|
||||
**
|
||||
** *pRes>0 The cursor is left pointing at an entry that
|
||||
** is larger than pIdxKey.
|
||||
**
|
||||
** The pIdxKey->eqSeen field is set to 1 if there
|
||||
** exists an entry in the table that exactly matches pIdxKey.
|
||||
*/
|
||||
int sqlite3BtreeIndexMoveto(
|
||||
BtCursor *pCur, /* The cursor to be moved */
|
||||
UnpackedRecord *pIdxKey, /* Unpacked index key */
|
||||
int *pRes /* Write search results here */
|
||||
){
|
||||
int rc;
|
||||
RecordCompare xRecordCompare;
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( pRes );
|
||||
assert( pCur->pKeyInfo!=0 );
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
pCur->pBtree->nSeek++; /* Performance measurement during testing */
|
||||
#endif
|
||||
|
||||
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
||||
pIdxKey->errCode = 0;
|
||||
assert( pIdxKey->default_rc==1
|
||||
|| pIdxKey->default_rc==0
|
||||
|| pIdxKey->default_rc==-1
|
||||
);
|
||||
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ){
|
||||
@ -5548,130 +5668,92 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( pPage->intKey==(pIdxKey==0) );
|
||||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
assert( biasRight==0 || biasRight==1 );
|
||||
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
||||
idx = upr>>1; /* idx = (lwr+upr)/2; */
|
||||
pCur->ix = (u16)idx;
|
||||
if( xRecordCompare==0 ){
|
||||
for(;;){
|
||||
i64 nCellKey;
|
||||
pCell = findCellPastPtr(pPage, idx);
|
||||
if( pPage->intKeyLeaf ){
|
||||
while( 0x80 <= *(pCell++) ){
|
||||
if( pCell>=pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
getVarint(pCell, (u64*)&nCellKey);
|
||||
if( nCellKey<intKey ){
|
||||
lwr = idx+1;
|
||||
if( lwr>upr ){ c = -1; break; }
|
||||
}else if( nCellKey>intKey ){
|
||||
upr = idx-1;
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->ix = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
lwr = idx;
|
||||
goto moveto_next_layer;
|
||||
}else{
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->info.nSize = 0;
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
assert( lwr+upr>=0 );
|
||||
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */
|
||||
}
|
||||
}else{
|
||||
for(;;){
|
||||
int nCell; /* Size of the pCell cell in bytes */
|
||||
pCell = findCellPastPtr(pPage, idx);
|
||||
for(;;){
|
||||
int nCell; /* Size of the pCell cell in bytes */
|
||||
pCell = findCellPastPtr(pPage, idx);
|
||||
|
||||
/* The maximum supported page-size is 65536 bytes. This means that
|
||||
** the maximum number of record bytes stored on an index B-Tree
|
||||
** page is less than 16384 bytes and may be stored as a 2-byte
|
||||
** varint. This information is used to attempt to avoid parsing
|
||||
** the entire cell by checking for the cases where the record is
|
||||
** stored entirely within the b-tree page by inspecting the first
|
||||
** 2 bytes of the cell.
|
||||
*/
|
||||
nCell = pCell[0];
|
||||
if( nCell<=pPage->max1bytePayload ){
|
||||
/* This branch runs if the record-size field of the cell is a
|
||||
** single byte varint and the record fits entirely on the main
|
||||
** b-tree page. */
|
||||
testcase( pCell+nCell+1==pPage->aDataEnd );
|
||||
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
||||
}else if( !(pCell[1] & 0x80)
|
||||
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
||||
){
|
||||
/* The record-size field is a 2 byte varint and the record
|
||||
** fits entirely on the main b-tree page. */
|
||||
testcase( pCell+nCell+2==pPage->aDataEnd );
|
||||
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
||||
}else{
|
||||
/* The record flows over onto one or more overflow pages. In
|
||||
** this case the whole cell needs to be parsed, a buffer allocated
|
||||
** and accessPayload() used to retrieve the record into the
|
||||
** buffer before VdbeRecordCompare() can be called.
|
||||
**
|
||||
** If the record is corrupt, the xRecordCompare routine may read
|
||||
** up to two varints past the end of the buffer. An extra 18
|
||||
** bytes of padding is allocated at the end of the buffer in
|
||||
** case this happens. */
|
||||
void *pCellKey;
|
||||
u8 * const pCellBody = pCell - pPage->childPtrSize;
|
||||
const int nOverrun = 18; /* Size of the overrun padding */
|
||||
pPage->xParseCell(pPage, pCellBody, &pCur->info);
|
||||
nCell = (int)pCur->info.nKey;
|
||||
testcase( nCell<0 ); /* True if key size is 2^32 or more */
|
||||
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
||||
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
||||
testcase( nCell==2 ); /* Minimum legal index key size */
|
||||
if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
|
||||
rc = SQLITE_CORRUPT_PAGE(pPage);
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCellKey = sqlite3Malloc( nCell+nOverrun );
|
||||
if( pCellKey==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->ix = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
|
||||
pCur->curFlags &= ~BTCF_ValidOvfl;
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
}
|
||||
c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
|
||||
/* The maximum supported page-size is 65536 bytes. This means that
|
||||
** the maximum number of record bytes stored on an index B-Tree
|
||||
** page is less than 16384 bytes and may be stored as a 2-byte
|
||||
** varint. This information is used to attempt to avoid parsing
|
||||
** the entire cell by checking for the cases where the record is
|
||||
** stored entirely within the b-tree page by inspecting the first
|
||||
** 2 bytes of the cell.
|
||||
*/
|
||||
nCell = pCell[0];
|
||||
if( nCell<=pPage->max1bytePayload ){
|
||||
/* This branch runs if the record-size field of the cell is a
|
||||
** single byte varint and the record fits entirely on the main
|
||||
** b-tree page. */
|
||||
testcase( pCell+nCell+1==pPage->aDataEnd );
|
||||
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
||||
}else if( !(pCell[1] & 0x80)
|
||||
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
||||
){
|
||||
/* The record-size field is a 2 byte varint and the record
|
||||
** fits entirely on the main b-tree page. */
|
||||
testcase( pCell+nCell+2==pPage->aDataEnd );
|
||||
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
||||
}else{
|
||||
/* The record flows over onto one or more overflow pages. In
|
||||
** this case the whole cell needs to be parsed, a buffer allocated
|
||||
** and accessPayload() used to retrieve the record into the
|
||||
** buffer before VdbeRecordCompare() can be called.
|
||||
**
|
||||
** If the record is corrupt, the xRecordCompare routine may read
|
||||
** up to two varints past the end of the buffer. An extra 18
|
||||
** bytes of padding is allocated at the end of the buffer in
|
||||
** case this happens. */
|
||||
void *pCellKey;
|
||||
u8 * const pCellBody = pCell - pPage->childPtrSize;
|
||||
const int nOverrun = 18; /* Size of the overrun padding */
|
||||
pPage->xParseCell(pPage, pCellBody, &pCur->info);
|
||||
nCell = (int)pCur->info.nKey;
|
||||
testcase( nCell<0 ); /* True if key size is 2^32 or more */
|
||||
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
||||
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
||||
testcase( nCell==2 ); /* Minimum legal index key size */
|
||||
if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
|
||||
rc = SQLITE_CORRUPT_PAGE(pPage);
|
||||
goto moveto_index_finish;
|
||||
}
|
||||
pCellKey = sqlite3Malloc( nCell+nOverrun );
|
||||
if( pCellKey==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto moveto_index_finish;
|
||||
}
|
||||
pCur->ix = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
|
||||
pCur->curFlags &= ~BTCF_ValidOvfl;
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_index_finish;
|
||||
}
|
||||
assert(
|
||||
(pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
|
||||
&& (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
|
||||
);
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else if( c>0 ){
|
||||
upr = idx-1;
|
||||
}else{
|
||||
assert( c==0 );
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->ix = (u16)idx;
|
||||
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
if( lwr>upr ) break;
|
||||
assert( lwr+upr>=0 );
|
||||
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
|
||||
c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
|
||||
sqlite3_free(pCellKey);
|
||||
}
|
||||
assert(
|
||||
(pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
|
||||
&& (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
|
||||
);
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else if( c>0 ){
|
||||
upr = idx-1;
|
||||
}else{
|
||||
assert( c==0 );
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->ix = (u16)idx;
|
||||
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
|
||||
goto moveto_index_finish;
|
||||
}
|
||||
if( lwr>upr ) break;
|
||||
assert( lwr+upr>=0 );
|
||||
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
|
||||
}
|
||||
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
||||
assert( pPage->isInit );
|
||||
@ -5680,9 +5762,8 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
pCur->ix = (u16)idx;
|
||||
*pRes = c;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
goto moveto_index_finish;
|
||||
}
|
||||
moveto_next_layer:
|
||||
if( lwr>=pPage->nCell ){
|
||||
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
}else{
|
||||
@ -5692,7 +5773,7 @@ moveto_next_layer:
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) break;
|
||||
}
|
||||
moveto_finish:
|
||||
moveto_index_finish:
|
||||
pCur->info.nSize = 0;
|
||||
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
||||
return rc;
|
||||
@ -8798,7 +8879,8 @@ int sqlite3BtreeInsert(
|
||||
** to an adjacent cell. Move the cursor so that it is pointing either
|
||||
** to the cell to be overwritten or an adjacent cell.
|
||||
*/
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
|
||||
rc = sqlite3BtreeTableMoveto(pCur, pX->nKey,
|
||||
(flags & BTREE_APPEND)!=0, &loc);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
}else{
|
||||
@ -8825,9 +8907,10 @@ int sqlite3BtreeInsert(
|
||||
r.r1 = 0;
|
||||
r.r2 = 0;
|
||||
r.eqSeen = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc);
|
||||
rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc);
|
||||
}else{
|
||||
rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc);
|
||||
rc = btreeMoveto(pCur, pX->pKey, pX->nKey,
|
||||
(flags & BTREE_APPEND)!=0, &loc);
|
||||
}
|
||||
if( rc ) return rc;
|
||||
}
|
||||
|
@ -247,13 +247,17 @@ void sqlite3BtreeCursorHint(BtCursor*, int, ...);
|
||||
#endif
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMovetoUnpacked(
|
||||
int sqlite3BtreeTableMoveto(
|
||||
BtCursor*,
|
||||
UnpackedRecord *pUnKey,
|
||||
i64 intKey,
|
||||
int bias,
|
||||
int *pRes
|
||||
);
|
||||
int sqlite3BtreeIndexMoveto(
|
||||
BtCursor*,
|
||||
UnpackedRecord *pUnKey,
|
||||
int *pRes
|
||||
);
|
||||
int sqlite3BtreeCursorHasMoved(BtCursor*);
|
||||
int sqlite3BtreeCursorRestore(BtCursor*, int*);
|
||||
int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
||||
|
12
src/vdbe.c
12
src/vdbe.c
@ -4307,7 +4307,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
||||
if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
|
||||
rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res);
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
@ -4354,7 +4354,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
||||
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
||||
#endif
|
||||
r.eqSeen = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
|
||||
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@ -4773,7 +4773,7 @@ case OP_Found: { /* jump, in3 */
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
|
||||
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res);
|
||||
if( pFree ) sqlite3DbFreeNN(db, pFree);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
@ -4882,7 +4882,7 @@ notExistsWithKey:
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr!=0 );
|
||||
res = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
|
||||
rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res);
|
||||
assert( rc==SQLITE_OK || res==0 );
|
||||
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
||||
pC->nullRow = 0;
|
||||
@ -5039,7 +5039,7 @@ case OP_NewRowid: { /* out2 */
|
||||
do{
|
||||
sqlite3_randomness(sizeof(v), &v);
|
||||
v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */
|
||||
}while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
|
||||
}while( ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v,
|
||||
0, &res))==SQLITE_OK)
|
||||
&& (res==0)
|
||||
&& (++cnt<100));
|
||||
@ -5937,7 +5937,7 @@ case OP_IdxDelete: {
|
||||
r.nField = (u16)pOp->p3;
|
||||
r.default_rc = 0;
|
||||
r.aMem = &aMem[pOp->p2];
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
|
||||
rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( res==0 ){
|
||||
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
|
||||
|
@ -3501,7 +3501,7 @@ int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
|
||||
assert( p->deferredMoveto );
|
||||
assert( p->isTable );
|
||||
assert( p->eCurType==CURTYPE_BTREE );
|
||||
rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
|
||||
rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res);
|
||||
if( rc ) return rc;
|
||||
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
|
||||
#ifdef SQLITE_TEST
|
||||
|
Loading…
Reference in New Issue
Block a user