Compare commits

..

1 Commits

Author SHA1 Message Date
drh e3bf194c0e Add the BtCursor.pPage field which is the current page to which the cursor
points, for a very small performance gain.

FossilOrigin-Name: a200e1eae9a1350ed2aed9bfe70042fec05dd98b
2015-04-15 19:13:26 +00:00
11 changed files with 114 additions and 251 deletions
+18 -15
View File
@@ -1,5 +1,5 @@
C Merge\supdates\sfrom\strunk.
D 2015-04-16T04:20:10.533
C Add\sthe\sBtCursor.pPage\sfield\swhich\sis\sthe\scurrent\spage\sto\swhich\sthe\scursor\npoints,\sfor\sa\svery\ssmall\sperformance\sgain.
D 2015-04-15T19:13:26.759
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5f78b1ab81b64e7c57a75d170832443e66c0880a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -173,9 +173,9 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
F src/btree.c c6e32d84442f79d5b96965265d65b3baa231dffc
F src/btree.c 485e357f2409b1d23f21e542190764ea707d567f
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4
F src/btreeInt.h 3c791196f75a737b234aee7ba36b37160373fc18
F src/build.c 01b969b20a44a3d9620e597d9af8242348123540
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575
@@ -225,13 +225,13 @@ F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9
F src/pragma.c 3965ae4e82bed39fb97ce04c5fe18c9bc3ee6a88
F src/pragma.h 09c89bca58e9a44de2116cc8272b8d454657129f
F src/prepare.c 1fffbdcd6f8a0173a8f70d71f22528f4c0e1e3d3
F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9
F src/printf.c 08fa675c200aac29e561c6153f91f909ed17612f
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 66cfe49a9c3b449ef13b89a8c47036a4ed167eab
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c 93260bc9e7e0e6dfe1b7cb8815b0ed4cad8be9e3
F src/shell.c 04706b14b737229cfba359cc1f46dd03b53a59be
F src/shell.c 84a1593bd86aaa14f4da8a8f9b16fbc239d262aa
F src/sqlite.h.in ca27603a36fcacdaac5a19d8ee35aaff8ce8516f
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
@@ -320,7 +320,7 @@ F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 3eb35a4af972f98422e5dc0586501b17d103d321
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
F test/analyze3.test 75b9e42ea1e4edc919250450dc5762186965d4e6
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
@@ -655,7 +655,7 @@ F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b
F test/index3.test 55a90cff99834305e8141df7afaef39674b57062
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e
F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481
@@ -865,7 +865,7 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test ce5e744870387164703bf2dee2cc9753e4a71513
F test/shell1.test ca88b14a8fc8b1f3543a24e519d019585ac9c903
F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
F test/shell4.test ddf0a99044e2245a87fc17423e3aaa1445b3243b
@@ -915,7 +915,7 @@ F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
F test/tester.tcl 51211254f2ee2340d3e4fa0a83bd5381b9e1a227
F test/tester.tcl ed77454e6c7b40eb501db7e79d1c6fbfd3eebbff
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1082,7 +1082,7 @@ F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
F test/trigger7.test 200dd51e728c9cdc20c72d99d9e9d45c667248f8
F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41
F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
@@ -1250,7 +1250,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P c458db41bbb6bd13d47531685e25a09f512c7f5f d3c00d61581c8ba6dce5618391432d3af8d324d4
R 2c042385d701fe541a26946cba425218
U mistachkin
Z e84ee44408bcf2cec5bcea635dbd30f2
P f71053cf658b3260a32ac06f8ba5c2cde0ea54dd
R a88b52422fda2f2ea905aaa2e3a17ff4
T *branch * btree-current-page-cache
T *sym-btree-current-page-cache *
T -sym-trunk *
U drh
Z 4cafb2843490ebe751738bc5633d8f3a
+1 -1
View File
@@ -1 +1 @@
22827542a5c7aeac4385ba647f45bd500e787fe6
a200e1eae9a1350ed2aed9bfe70042fec05dd98b
+82 -49
View File
@@ -587,6 +587,7 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
pCur->apPage[i] = 0;
}
pCur->iPage = -1;
pCur->pPage = 0;
}
@@ -3651,6 +3652,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
releasePage(p->apPage[i]);
p->apPage[i] = 0;
}
p->pPage = 0;
}
sqlite3BtreeLeave(pBtree);
}
@@ -3865,6 +3867,7 @@ static int btreeCursor(
** variables and link the cursor into the BtShared list. */
pCur->pgnoRoot = (Pgno)iTable;
pCur->iPage = -1;
pCur->pPage = 0;
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
pCur->pBt = pBt;
@@ -3966,7 +3969,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
CellInfo info;
int iPage = pCur->iPage;
memset(&info, 0, sizeof(info));
btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
assert( pCur->pPage==pCur->apPage[iPage] );
btreeParseCell(pCur->pPage, pCur->aiIdx[iPage], &info);
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
}
#else
@@ -3977,7 +3981,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
static void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
int iPage = pCur->iPage;
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
assert( pCur->pPage==pCur->apPage[iPage] );
btreeParseCell(pCur->pPage,pCur->aiIdx[iPage],&pCur->info);
pCur->curFlags |= BTCF_ValidNKey;
}else{
assertCellInfo(pCur);
@@ -3988,7 +3993,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#define getCellInfo(pCur) \
if( pCur->info.nSize==0 ){ \
int iPage = pCur->iPage; \
btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
assert( pCur->pPage==pCur->apPage[iPage] ); \
btreeParseCell(pCur->pPage,pCur->aiIdx[iPage],&pCur->info); \
pCur->curFlags |= BTCF_ValidNKey; \
}else{ \
assertCellInfo(pCur); \
@@ -4043,7 +4049,8 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
assert( pCur->pPage->intKeyLeaf==1 );
getCellInfo(pCur);
*pSize = pCur->info.nPayload;
return SQLITE_OK;
@@ -4197,14 +4204,15 @@ static int accessPayload(
unsigned char *aPayload;
int rc = SQLITE_OK;
int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
MemPage *pPage = pCur->pPage; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
unsigned char * const pBufStart = pBuf;
int bEnd; /* True if reading to end of data */
#endif
assert( pPage );
assert( pPage==pCur->apPage[pCur->iPage] );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
assert( cursorHoldsMutex(pCur) );
@@ -4394,8 +4402,10 @@ static int accessPayload(
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->iPage>=0 );
assert( pCur->apPage[pCur->iPage]==pCur->pPage );
assert( pCur->pPage!=0 );
assert( pCur->aiIdx[pCur->iPage]<pCur->pPage->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
@@ -4421,8 +4431,10 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->iPage>=0 );
assert( pCur->apPage[pCur->iPage]==pCur->pPage );
assert( pCur->pPage!=0 );
assert( pCur->aiIdx[pCur->iPage]<pCur->pPage->nCell );
rc = accessPayload(pCur, offset, amt, pBuf, 0);
}
return rc;
@@ -4452,15 +4464,18 @@ static const void *fetchPayload(
u32 *pAmt /* Write the number of available bytes here */
){
u32 amt;
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur!=0 );
assert( pCur->iPage>=0 );
assert( pCur->apPage[pCur->iPage]==pCur->pPage );
assert( pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->aiIdx[pCur->iPage]<pCur->pPage->nCell );
assert( pCur->info.nSize>0 );
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
assert( pCur->info.pPayload<pCur->pPage->aDataEnd || CORRUPT_DB );
amt = (int)(pCur->pPage->aDataEnd - pCur->info.pPayload);
if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
*pAmt = amt;
return (void*)pCur->info.pPayload;
@@ -4514,7 +4529,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
rc = getAndInitPage(pBt, newPgno, &pNewPage,
(pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc ) return rc;
pCur->apPage[i+1] = pNewPage;
pCur->apPage[i+1] = pCur->pPage = pNewPage;
pCur->aiIdx[i+1] = 0;
pCur->iPage++;
@@ -4560,16 +4575,18 @@ static void moveToParent(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
assert( pCur->pPage!=0 );
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
pCur->pPage->pgno
);
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
releasePage(pCur->apPage[pCur->iPage]);
releasePage(pCur->pPage);
pCur->iPage--;
pCur->pPage = pCur->apPage[pCur->iPage];
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
}
@@ -4625,7 +4642,8 @@ static int moveToRoot(BtCursor *pCur){
}
pCur->iPage = 0;
}
pRoot = pCur->apPage[0];
assert( pCur->iPage==0 );
pRoot = pCur->pPage = pCur->apPage[0];
assert( pRoot->pgno==pCur->pgnoRoot );
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
@@ -4675,7 +4693,7 @@ static int moveToLeftmost(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
rc = moveToChild(pCur, pgno);
@@ -4700,7 +4718,7 @@ static int moveToRightmost(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
while( !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->aiIdx[pCur->iPage] = pPage->nCell;
rc = moveToChild(pCur, pgno);
@@ -4723,11 +4741,12 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
if( pCur->eState==CURSOR_INVALID ){
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
*pRes = 1;
}else{
assert( pCur->apPage[pCur->iPage]->nCell>0 );
assert( pCur->pPage->nCell>0 );
*pRes = 0;
rc = moveToLeftmost(pCur);
}
@@ -4754,8 +4773,9 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
for(ii=0; ii<pCur->iPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
assert( pCur->apPage[pCur->iPage]->leaf );
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
assert( pCur->aiIdx[pCur->iPage]==pCur->pPage->nCell-1 );
assert( pCur->pPage->leaf );
#endif
return SQLITE_OK;
}
@@ -4853,19 +4873,20 @@ int sqlite3BtreeMovetoUnpacked(
if( rc ){
return rc;
}
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]==pCur->pPage );
assert( pCur->pgnoRoot==0 || pCur->pPage!=0 );
assert( pCur->pgnoRoot==0 || pCur->pPage->isInit );
assert( pCur->eState==CURSOR_INVALID || pCur->pPage->nCell>0 );
if( pCur->eState==CURSOR_INVALID ){
*pRes = -1;
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
return SQLITE_OK;
}
assert( pCur->apPage[0]->intKey || pIdxKey );
assert( pCur->pPage->intKey || pIdxKey );
for(;;){
int lwr, upr, idx, c;
Pgno chldPg;
MemPage *pPage = pCur->apPage[pCur->iPage];
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
@@ -4988,7 +5009,7 @@ int sqlite3BtreeMovetoUnpacked(
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->aiIdx[pCur->iPage]<pCur->pPage->nCell );
pCur->aiIdx[pCur->iPage] = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
@@ -5076,7 +5097,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
}
}
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
idx = ++pCur->aiIdx[pCur->iPage];
assert( pPage->isInit );
@@ -5100,7 +5121,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
return SQLITE_OK;
}
moveToParent(pCur);
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
}while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
if( pPage->intKey ){
return sqlite3BtreeNext(pCur, pRes);
@@ -5124,7 +5145,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
*pRes = 0;
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
pCur->aiIdx[pCur->iPage]--;
return btreeNext(pCur, pRes);
@@ -5187,7 +5208,8 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
}
}
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
assert( pPage==pCur->apPage[pCur->iPage] );
assert( pPage->isInit );
if( !pPage->leaf ){
int idx = pCur->aiIdx[pCur->iPage];
@@ -5207,7 +5229,8 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
pCur->aiIdx[pCur->iPage]--;
pPage = pCur->apPage[pCur->iPage];
assert( pCur->apPage[pCur->iPage]==pCur->pPage );
pPage = pCur->pPage;
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, pRes);
}else{
@@ -5226,7 +5249,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
|| pCur->aiIdx[pCur->iPage]==0
|| pCur->apPage[pCur->iPage]->leaf==0
|| pCur->pPage->leaf==0
){
return btreePrevious(pCur, pRes);
}
@@ -7419,7 +7442,8 @@ static int balance(BtCursor *pCur){
do {
int iPage = pCur->iPage;
MemPage *pPage = pCur->apPage[iPage];
MemPage *pPage = pCur->pPage;
assert( pPage==pCur->apPage[iPage] );
if( iPage==0 ){
if( pPage->nOverflow ){
@@ -7434,7 +7458,8 @@ static int balance(BtCursor *pCur){
pCur->iPage = 1;
pCur->aiIdx[0] = 0;
pCur->aiIdx[1] = 0;
assert( pCur->apPage[1]->nOverflow );
pCur->pPage = pCur->apPage[1];
assert( pCur->pPage->nOverflow );
}
}else{
break;
@@ -7513,6 +7538,7 @@ static int balance(BtCursor *pCur){
releasePage(pPage);
pCur->iPage--;
assert( pCur->iPage>=0 );
pCur->pPage = pCur->apPage[pCur->iPage];
}
}while( rc==SQLITE_OK );
@@ -7615,7 +7641,8 @@ int sqlite3BtreeInsert(
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
pPage = pCur->apPage[pCur->iPage];
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
pPage = pCur->pPage;
assert( pPage->intKey || nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
@@ -7682,10 +7709,11 @@ int sqlite3BtreeInsert(
** fails. Internal data structure corruption will result otherwise.
** Also, set the cursor state to invalid. This stops saveCursorPosition()
** from trying to save the current position of the cursor. */
pCur->apPage[pCur->iPage]->nOverflow = 0;
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
pCur->pPage->nOverflow = 0;
pCur->eState = CURSOR_INVALID;
}
assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
assert( pCur->pPage->nOverflow==0 );
end_insert:
return rc;
@@ -7711,8 +7739,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->pPage->nCell)
|| NEVER(pCur->eState!=CURSOR_VALID)
){
return SQLITE_ERROR; /* Something has gone awry. */
@@ -7762,7 +7791,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
** node. The cell from the leaf node needs to be moved to the internal
** node to replace the deleted cell. */
if( !pPage->leaf ){
MemPage *pLeaf = pCur->apPage[pCur->iPage];
MemPage *pLeaf = pCur->pPage;
int nCell;
Pgno n = pCur->apPage[iCellDepth+1]->pgno;
unsigned char *pTmp;
@@ -7798,6 +7827,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
while( pCur->iPage>iCellDepth ){
releasePage(pCur->apPage[pCur->iPage--]);
}
pCur->pPage = pCur->apPage[pCur->iPage];
rc = balance(pCur);
}
@@ -8302,7 +8332,8 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
pPage = pCur->apPage[pCur->iPage];
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
pPage = pCur->pPage;
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
}
@@ -8325,10 +8356,11 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
return moveToRoot(pCur);
}
moveToParent(pCur);
}while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
}while ( pCur->aiIdx[pCur->iPage]>=pCur->pPage->nCell );
pCur->aiIdx[pCur->iPage]++;
pPage = pCur->apPage[pCur->iPage];
assert( pCur->pPage==pCur->apPage[pCur->iPage] );
pPage = pCur->pPage;
}
/* Descend to the child node of the cell that the cursor currently
@@ -9111,6 +9143,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
assert( pCsr->apPage[pCsr->iPage]->intKey );
assert( pCsr->pPage==pCsr->apPage[pCsr->iPage] );
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}
+1
View File
@@ -518,6 +518,7 @@ struct BtCursor {
u8 hints; /* As configured by CursorSetHints() */
i16 iPage; /* Index of current page in apPage */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
MemPage *pPage; /* Current page */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
};
+3 -3
View File
@@ -67,7 +67,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[1]==0 ){
corruptSchema(pData, argv[0], 0);
}else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
}else if( argv[2] && argv[2][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data
@@ -98,8 +98,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
}
}
sqlite3_finalize(pStmt);
}else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
corruptSchema(pData, argv[0], 0);
}else if( argv[0]==0 ){
corruptSchema(pData, 0, 0);
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
+5 -46
View File
@@ -989,16 +989,7 @@ static int shell_callback(
case MODE_Insert: {
p->cnt++;
if( azArg==0 ) break;
fprintf(p->out,"INSERT INTO %s",p->zDestTable);
if( p->showHeader ){
fprintf(p->out,"(");
for(i=0; i<nArg; i++){
char *zSep = i>0 ? ",": "";
fprintf(p->out, "%s%s", zSep, azCol[i]);
}
fprintf(p->out,")");
}
fprintf(p->out," VALUES(");
fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
for(i=0; i<nArg; i++){
char *zSep = i>0 ? ",": "";
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
@@ -1780,7 +1771,6 @@ static int run_schema_dump_query(
static char zHelp[] =
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
".bail on|off Stop after hitting an error. Default OFF\n"
".binary on|off Turn binary output on or off. Default OFF\n"
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
".dbinfo ?DB? Show status information about the database\n"
@@ -1942,44 +1932,26 @@ static void open_db(ShellState *p, int keepAlive){
/*
** Do C-language style dequoting.
**
** \a -> alarm
** \b -> backspace
** \t -> tab
** \n -> newline
** \v -> vertical tab
** \f -> form feed
** \r -> carriage return
** \s -> space
** \" -> "
** \' -> '
** \\ -> backslash
** \NNN -> ascii character NNN in octal
** \\ -> backslash
*/
static void resolve_backslashes(char *z){
int i, j;
char c;
while( *z && *z!='\\' ) z++;
for(i=j=0; (c = z[i])!=0; i++, j++){
if( c=='\\' && z[i+1]!=0 ){
if( c=='\\' ){
c = z[++i];
if( c=='a' ){
c = '\a';
}else if( c=='b' ){
c = '\b';
if( c=='n' ){
c = '\n';
}else if( c=='t' ){
c = '\t';
}else if( c=='n' ){
c = '\n';
}else if( c=='v' ){
c = '\v';
}else if( c=='f' ){
c = '\f';
}else if( c=='r' ){
c = '\r';
}else if( c=='"' ){
c = '"';
}else if( c=='\'' ){
c = '\'';
}else if( c=='\\' ){
c = '\\';
}else if( c>='0' && c<='7' ){
@@ -2713,19 +2685,6 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
if( nArg==2 ){
if( booleanValue(azArg[1]) ){
setBinaryMode(p->out);
}else{
setTextMode(p->out);
}
}else{
fprintf(stderr, "Usage: .binary on|off\n");
rc = 1;
}
}else
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
+1 -1
View File
@@ -359,6 +359,6 @@ do_test analyze-99.1 {
catchsql {
ANALYZE
}
} {1 {malformed database schema (sqlite_stat1)}}
} {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}}
finish_test
+1 -1
View File
@@ -51,6 +51,6 @@ do_test index3-99.1 {
db close
catch { sqlite3 db test.db }
catchsql { DROP INDEX i1 }
} {1 {malformed database schema (t1)}}
} {1 {malformed database schema (t1) - near "nonsense": syntax error}}
finish_test
+1 -101
View File
@@ -738,9 +738,6 @@ do_test shell1-4.1 {
PRAGMA encoding=UTF16;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
CREATE TABLE t3(x,y);
INSERT INTO t3 VALUES(1,null), (2,''), (3,1),
(4,2.25), (5,'hello'), (6,x'807f');
}
catchcmd test.db {.dump}
} {0 {PRAGMA foreign_keys=OFF;
@@ -752,18 +749,11 @@ INSERT INTO "t1" VALUES(1);
INSERT INTO "t1" VALUES(2.25);
INSERT INTO "t1" VALUES('hello');
INSERT INTO "t1" VALUES(X'807F');
CREATE TABLE t3(x,y);
INSERT INTO "t3" VALUES(1,NULL);
INSERT INTO "t3" VALUES(2,'');
INSERT INTO "t3" VALUES(3,1);
INSERT INTO "t3" VALUES(4,2.25);
INSERT INTO "t3" VALUES(5,'hello');
INSERT INTO "t3" VALUES(6,X'807F');
COMMIT;}}
# Test the output of ".mode insert"
#
do_test shell1-4.2.1 {
do_test shell1-4.2 {
catchcmd test.db ".mode insert t1\nselect * from t1;"
} {0 {INSERT INTO t1 VALUES(NULL);
INSERT INTO t1 VALUES('');
@@ -772,39 +762,6 @@ INSERT INTO t1 VALUES(2.25);
INSERT INTO t1 VALUES('hello');
INSERT INTO t1 VALUES(X'807f');}}
# Test the output of ".mode insert" with headers
#
do_test shell1-4.2.2 {
catchcmd test.db ".mode insert t1\n.headers on\nselect * from t1;"
} {0 {INSERT INTO t1(x) VALUES(NULL);
INSERT INTO t1(x) VALUES('');
INSERT INTO t1(x) VALUES(1);
INSERT INTO t1(x) VALUES(2.25);
INSERT INTO t1(x) VALUES('hello');
INSERT INTO t1(x) VALUES(X'807f');}}
# Test the output of ".mode insert"
#
do_test shell1-4.2.3 {
catchcmd test.db ".mode insert t3\nselect * from t3;"
} {0 {INSERT INTO t3 VALUES(1,NULL);
INSERT INTO t3 VALUES(2,'');
INSERT INTO t3 VALUES(3,1);
INSERT INTO t3 VALUES(4,2.25);
INSERT INTO t3 VALUES(5,'hello');
INSERT INTO t3 VALUES(6,X'807f');}}
# Test the output of ".mode insert" with headers
#
do_test shell1-4.2.4 {
catchcmd test.db ".mode insert t3\n.headers on\nselect * from t3;"
} {0 {INSERT INTO t3(x,y) VALUES(1,NULL);
INSERT INTO t3(x,y) VALUES(2,'');
INSERT INTO t3(x,y) VALUES(3,1);
INSERT INTO t3(x,y) VALUES(4,2.25);
INSERT INTO t3(x,y) VALUES(5,'hello');
INSERT INTO t3(x,y) VALUES(6,X'807f');}}
# Test the output of ".mode tcl"
#
do_test shell1-4.3 {
@@ -861,61 +818,4 @@ do_test shell1-4.6 {
";"
"$"} 7}
# Test using arbitrary byte data with the shell via standard input/output.
#
do_test shell1-5.0 {
#
# NOTE: Skip NUL byte because it appears to be incompatible with command
# shell argument parsing.
#
for {set i 1} {$i < 256} {incr i} {
#
# NOTE: Due to how the Tcl [exec] command works (i.e. where it treats
# command channels opened for it as textual ones), the carriage
# return character (and on Windows, the end-of-file character)
# cannot be used here.
#
if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} {
continue
}
set hex [format %02X $i]
set char [subst \\x$hex]; set oldChar $char
set escapes [list]
if {$tcl_platform(platform)=="windows"} {
#
# NOTE: On Windows, we need to escape all the whitespace characters,
# the alarm (\a) character, and those with special meaning to
# the SQLite shell itself.
#
set escapes [list \
\a \\a \b \\b \t \\t \n \\n \v \\v \f \\f \r \\r \
" " "\" \"" \" \\\" ' \"'\" \\ \\\\]
} else {
#
# NOTE: On Unix, we need to escape most of the whitespace characters
# and those with special meaning to the SQLite shell itself.
# The alarm (\a), backspace (\b), and carriage-return (\r)
# characters do not appear to require escaping on Unix. For
# the alarm and backspace characters, this is probably due to
# differences in the command shell. For the carriage-return,
# it is probably due to differences in how Tcl handles command
# channel end-of-line translations.
#
set escapes [list \
\t \\t \n \\n \v \\v \f \\f \
" " "\" \"" \" \\\" ' \"'\" \\ \\\\]
}
set char [string map $escapes $char]
set x [catchcmdex test.db ".print $char\n"]
set code [lindex $x 0]
set res [lindex $x 1]
if {$code ne "0"} {
error "failed with error: $res"
}
if {$res ne "$oldChar\n"} {
error "failed with byte $hex mismatch"
}
}
} {}
finish_test
-33
View File
@@ -666,15 +666,6 @@ proc do_test {name cmd expected} {
flush stdout
}
proc dumpbytes {s} {
set r ""
for {set i 0} {$i < [string length $s]} {incr i} {
if {$i > 0} {append r " "}
append r [format %02X [scan [string index $s $i] %c]]
}
return $r
}
proc catchcmd {db {cmd ""}} {
global CLI
set out [open cmds.txt w]
@@ -685,30 +676,6 @@ proc catchcmd {db {cmd ""}} {
list $rc $msg
}
proc catchcmdex {db {cmd ""}} {
global CLI
set out [open cmds.txt w]
fconfigure $out -encoding binary -translation binary
puts -nonewline $out $cmd
close $out
set line "exec -keepnewline -- $CLI $db < cmds.txt"
set chans [list stdin stdout stderr]
foreach chan $chans {
catch {
set modes($chan) [fconfigure $chan]
fconfigure $chan -encoding binary -translation binary -buffering none
}
}
set rc [catch { eval $line } msg]
foreach chan $chans {
catch {
eval fconfigure [list $chan] $modes($chan)
}
}
# puts [dumpbytes $msg]
list $rc $msg
}
proc filepath_normalize {p} {
# test cases should be written to assume "unix"-like file paths
if {$::tcl_platform(platform)!="unix"} {
+1 -1
View File
@@ -114,6 +114,6 @@ do_test trigger7-99.1 {
db close
catch { sqlite3 db test.db }
catchsql { DROP TRIGGER t2r5 }
} {1 {malformed database schema (t2r12)}}
} {1 {malformed database schema (t2r12) - near "nonsense": syntax error}}
finish_test