From 1b18a90d8d493e19582c9ff8cf9999692d6d5745 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 25 Feb 2022 18:15:09 +0000 Subject: [PATCH] Attempt to transform OP_Column to make use of eCurState instead of the other miscellaneous flags. FossilOrigin-Name: 09a47f32a44bfe8630157f09518e6467fac281bc70cf229c88efccac2028ea70 --- manifest | 12 ++-- manifest.uuid | 2 +- src/vdbe.c | 165 ++++++++++++++++++++++++++++---------------------- 3 files changed, 101 insertions(+), 78 deletions(-) diff --git a/manifest b/manifest index d506655738..87c0e550b0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sdo\sa\sdeferred\sseek\son\sa\scursor\sthat\sis\smarked\snullRow. -D 2022-02-25T16:21:00.933 +C Attempt\sto\stransform\sOP_Column\sto\smake\suse\sof\seCurState\sinstead\sof\sthe\sother\nmiscellaneous\sflags. +D 2022-02-25T18:15:09.709 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -624,7 +624,7 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23 F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 -F src/vdbe.c 588de992e0efc2cc167748888b90fc0910e93b3030a16b5685f0acd7cb5f1cb3 +F src/vdbe.c 7778e0f54e7ffe99edf44133e346915cb1ababb696186e6f566ff0053d39f28d F src/vdbe.h a1d0e3b934e835e73edd146f2e7c4eadb711b5c9875c18159a57483fd78e550e F src/vdbeInt.h 68756566247e190f22ea8f175a81f9d1b91b6258bcdd69832ea2eb3c78ecfb11 F src/vdbeapi.c 8863ffb5a7bac42fe9a68aaa3526ee29fc18fb02a9b27188b756de41e33856e9 @@ -1944,8 +1944,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7953716c12ca1deb50ee2c91d9b62a029e38f7cb61af418eeca438283c45f825 -R 85c483559243dc30f8f8dd48c45fb13f +P 1c026bcb3c9e1ae0f38ad8a3e6e3bda1a0cdff9dcc77a08b1820f2fdde2ee200 +R 6589fae24aaa3fb0ff9b2ab0fa20c61e U drh -Z 6cb6334f470796473908dc1f535cd43a +Z bb01b1e110beac42908286888d97e4bc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d9f3573134..95408aeeac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1c026bcb3c9e1ae0f38ad8a3e6e3bda1a0cdff9dcc77a08b1820f2fdde2ee200 \ No newline at end of file +09a47f32a44bfe8630157f09518e6467fac281bc70cf229c88efccac2028ea70 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 9d0a227e81..0deee95928 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2688,43 +2688,56 @@ case OP_Column: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); p2 = (u32)pOp->p2; - - /* If the cursor cache is stale (meaning it is not currently point at - ** the correct row) then bring it up-to-date by doing the necessary - ** B-Tree seek. */ - rc = sqlite3VdbeCursorMoveto(&pC, &p2); - if( rc ) goto abort_due_to_error; - - assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); + +op_column_restart: assert( pC!=0 ); assert( p2<(u32)pC->nField ); aOffset = pC->aOffset; assert( aOffset==pC->aType+pC->nField ); + assert( aOffset==pC->aType+pC->nField ); assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); - if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ - if( pC->nullRow ){ - if( pC->eCurType==CURTYPE_PSEUDO ){ - /* For the special case of as pseudo-cursor, the seekResult field - ** identifies the register that holds the record */ - assert( pC->seekResult>0 ); - assert( pC->eCurState==CURSTATE_PSEUDO_UNINIT - || pC->eCurState==CURSTATE_NULLROW ); - pReg = &aMem[pC->seekResult]; - assert( pReg->flags & MEM_Blob ); - assert( memIsValid(pReg) ); - pC->payloadSize = pC->szRow = pReg->n; - pC->aRow = (u8*)pReg->z; - }else{ - assert( pC->eCurState==CURSTATE_NULLROW ); - sqlite3VdbeMemSetNull(pDest); - goto op_column_out; + switch( pC->eCurState ){ + case CURSTATE_READY: { + rc = sqlite3VdbeCursorRestore(pC); + if( rc ) goto abort_due_to_error; + break; + } + case CURSTATE_PSEUDO: { + break; + } + case CURSTATE_DEFERRED: { + u32 iMap; + assert( !pC->isEphemeral ); + if( pC->ub.aAltMap && (iMap = pC->ub.aAltMap[1+p2])>0 ){ + pC = pC->pAltCursor; + p2 = iMap - 1; + goto op_column_restart; } - }else{ + rc = sqlite3VdbeFinishMoveto(pC); + if( rc ) goto abort_due_to_error; + goto op_column_btree_init; + } + case CURSTATE_PSEUDO_UNINIT: { + assert( pC->eCurType==CURTYPE_PSEUDO ); + /* For the special case of as pseudo-cursor, the seekResult field + ** identifies the register that holds the record */ + assert( pC->seekResult>0 ); + pReg = &aMem[pC->seekResult]; + assert( pReg->flags & MEM_Blob ); + assert( memIsValid(pReg) ); + pC->payloadSize = pC->szRow = pReg->n; + pC->aRow = (u8*)pReg->z; + goto op_column_init_cache; + } + case CURSTATE_UNINIT: { + rc = sqlite3VdbeCursorRestore(pC); + if( rc ) goto abort_due_to_error; + op_column_btree_init: pCrsr = pC->uc.pCursor; assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->eCurState==CURSTATE_UNINIT ); @@ -2737,51 +2750,57 @@ case OP_Column: { if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - } - pC->eCurState = pC->eCurType; - pC->cacheStatus = p->cacheCtr; - pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); - pC->nHdrParsed = 0; - - - if( pC->szRowaRow does not have to hold the entire row, but it does at least - ** need to cover the header of the record. If pC->aRow does not contain - ** the complete header, then set it to zero, forcing the header to be - ** dynamically allocated. */ - pC->aRow = 0; - pC->szRow = 0; - - /* Make sure a corrupt database has not given us an oversize header. - ** Do this now to avoid an oversize memory allocation. - ** - ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte - ** types use so much data space that there can only be 4096 and 32 of - ** them, respectively. So the maximum header length results from a - ** 3-byte type for each of the maximum of 32768 columns plus three - ** extra bytes for the header length itself. 32768*3 + 3 = 98307. - */ - if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){ - goto op_column_corrupt; + op_column_init_cache: + pC->eCurState = pC->eCurType; + pC->cacheStatus = p->cacheCtr; + pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); + pC->nHdrParsed = 0; + + if( pC->szRowaRow does not have to hold the entire row, but it does at least + ** need to cover the header of the record. If pC->aRow does not contain + ** the complete header, then set it to zero, forcing the header to be + ** dynamically allocated. */ + pC->aRow = 0; + pC->szRow = 0; + + /* Make sure a corrupt database has not given us an oversize header. + ** Do this now to avoid an oversize memory allocation. + ** + ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte + ** types use so much data space that there can only be 4096 and 32 of + ** them, respectively. So the maximum header length results from a + ** 3-byte type for each of the maximum of 32768 columns plus three + ** extra bytes for the header length itself. 32768*3 + 3 = 98307. + */ + if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){ + goto op_column_corrupt; + } + }else{ + /* This is an optimization. By skipping over the first few tests + ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a + ** measurable performance gain. + ** + ** This branch is taken even if aOffset[0]==0. Such a record is never + ** generated by SQLite, and could be considered corruption, but we + ** accept it for historical reasons. When aOffset[0]==0, the code this + ** branch jumps to reads past the end of the record, but never more + ** than a few bytes. Even if the record occurs at the end of the page + ** content area, the "page header" comes after the page content and so + ** this overread is harmless. Similar overreads can occur for a corrupt + ** database file. + */ + zData = pC->aRow; + assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + testcase( aOffset[0]==0 ); + goto op_column_read_header; } - }else{ - /* This is an optimization. By skipping over the first few tests - ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a - ** measurable performance gain. - ** - ** This branch is taken even if aOffset[0]==0. Such a record is never - ** generated by SQLite, and could be considered corruption, but we - ** accept it for historical reasons. When aOffset[0]==0, the code this - ** branch jumps to reads past the end of the record, but never more - ** than a few bytes. Even if the record occurs at the end of the page - ** content area, the "page header" comes after the page content and so - ** this overread is harmless. Similar overreads can occur for a corrupt - ** database file. - */ - zData = pC->aRow; - assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ - testcase( aOffset[0]==0 ); - goto op_column_read_header; + break; + } + default: { + assert( pC->eCurState==CURSTATE_NULLROW ); + sqlite3VdbeMemSetNull(pDest); + goto op_column_out; } } @@ -5752,10 +5771,14 @@ case OP_NullRow: { assert( pC!=0 ); pC->nullRow = 1; pC->cacheStatus = CACHE_STALE; - pC->eCurState = CURSTATE_NULLROW; if( pC->eCurType==CURTYPE_BTREE ){ assert( pC->uc.pCursor!=0 ); sqlite3BtreeClearCursor(pC->uc.pCursor); + pC->eCurState = CURSTATE_NULLROW; + }else if( pC->eCurType==CURTYPE_PSEUDO ){ + pC->eCurState = CURSTATE_PSEUDO_UNINIT; + }else{ + pC->eCurState = CURSTATE_NULLROW; } #ifdef SQLITE_DEBUG if( pC->seekOp==0 ) pC->seekOp = OP_NullRow; -- 2.39.5