From: drh Date: Wed, 20 Nov 2013 19:28:03 +0000 (+0000) Subject: Further performance tweaks to OP_Column. X-Git-Tag: version-3.8.2~69^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c8606e416a6cab18e24a33d730a1a43376b0003c;p=thirdparty%2Fsqlite.git Further performance tweaks to OP_Column. FossilOrigin-Name: 0e3f5df695216a27602a53eed5d25231b055adc8 --- diff --git a/manifest b/manifest index 91be839db0..a7de779afd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactoring\sthe\sOP_Column\sopcode\sfor\simproved\sperformance\sand\nmaintainability. -D 2013-11-20T17:25:55.912 +C Further\sperformance\stweaks\sto\sOP_Column. +D 2013-11-20T19:28:03.982 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -280,7 +280,7 @@ F src/update.c c05a0ee658f1a149e0960dfd110f3b8bd846bcb0 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c d4b8a9067a163f18535324c76bafdddff6b93491 +F src/vdbe.c 1a6e2c9413fca3b2d00c49e85a861e0adc8b6c6a F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644 F src/vdbeInt.h fbae1c449049a1a26ebbdf44e1beb08344072b72 F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed @@ -313,7 +313,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88 -F test/analyze9.test 1b9b7e9a096d1536f03d9ad7b72f638ef5669347 +F test/analyze9.test 339e87723cd4dc158dc5e9095acd8df9e87faf79 F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944 F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b @@ -1140,10 +1140,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 5562cd343d8f69242e06a51a7f1aef7ee7d78eec -R 71521f10a62f5e2d15e34378a9a872cf -T *branch * OP_Column-refactor -T *sym-OP_Column-refactor * -T -sym-trunk * +P 7c914e3997d2b28164a2fa7eb4398262b6ddb4b2 +R 72749b37eba95a49879e9308fdcd90bb U drh -Z 41c0df82986aff89d8eb065b326b79ba +Z 441207295dddfadd80f4cc85b77f0a53 diff --git a/manifest.uuid b/manifest.uuid index 6e355397de..458e461e6b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c914e3997d2b28164a2fa7eb4398262b6ddb4b2 \ No newline at end of file +0e3f5df695216a27602a53eed5d25231b055adc8 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 874645f189..f3832ab34f 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2255,13 +2255,11 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ */ case OP_Column: { i64 payloadSize64; /* Number of bytes in the record */ - int p1; /* P1 value of the opcode */ int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aType; /* aType[i] holds the numeric type of the i-th column */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ - int nField; /* number of fields in the record */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ Mem *pDest; /* Where to write the extracted value */ @@ -2275,17 +2273,14 @@ case OP_Column: { u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ - p1 = pOp->p1; - assert( p1nCursor ); p2 = pOp->p2; - sMem.zMalloc = 0; assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); - pC = p->apCsr[p1]; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; assert( pC!=0 ); - nField = pC->nField; - assert( p2nField ); aType = pC->aType; aOffset = pC->aOffset; #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -2293,27 +2288,31 @@ case OP_Column: { #endif pCrsr = pC->pCursor; assert( pCrsr!=0 || pC->pseudoTableReg>0 ); + assert( pC->pseudoTableReg==0 || pC->nullRow ); /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){ - if( pCrsr==0 ){ - assert( pC->pseudoTableReg>0 ); - pReg = &aMem[pC->pseudoTableReg]; - if( pC->multiPseudo ){ - sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem); - Deephemeralize(pDest); + if( pC->nullRow ){ + if( pCrsr==0 ){ + assert( pC->pseudoTableReg>0 ); + pReg = &aMem[pC->pseudoTableReg]; + if( pC->multiPseudo ){ + sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem); + Deephemeralize(pDest); + goto op_column_out; + } + assert( pReg->flags & MEM_Blob ); + assert( memIsValid(pReg) ); + pC->payloadSize = pC->szRow = avail = pReg->n; + pC->aRow = (u8*)pReg->z; + }else{ + MemSetTypeFlag(pDest, MEM_Null); goto op_column_out; } - assert( pReg->flags & MEM_Blob ); - assert( memIsValid(pReg) ); - pC->payloadSize = pC->szRow = avail = pReg->n; - pC->aRow = (u8*)pReg->z; - }else if( pC->nullRow ){ - MemSetTypeFlag(pDest, MEM_Null); - goto op_column_out; }else{ + assert( pCrsr ); if( pC->isIndex ){ assert( sqlite3BtreeCursorIsValid(pCrsr) ); VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64); @@ -2361,65 +2360,85 @@ case OP_Column: { */ if( offset > 98307 || offset > pC->payloadSize ){ rc = SQLITE_CORRUPT_BKPT; - goto op_column_out; + goto op_column_error; } } /* Make sure at least the first p2+1 entries of the header have been ** parsed and valid information is in aOffset[] and aType[]. */ - if( pC->nHdrParsed<=p2 && pC->iHdrOffsetaRow==0 ){ - memset(&sMem, 0, sizeof(sMem)); - rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,&sMem); - if( rc!=SQLITE_OK ){ - goto op_column_out; - } - zData = (u8*)sMem.z; - }else{ - zData = pC->aRow; - } - - /* Fill in aType[i] and aOffset[i] values through the p2-th field. */ - i = pC->nHdrParsed; - offset = aOffset[i]; - zHdr = zData + pC->iHdrOffset; - zEndHdr = zData + pC->aOffset[0]; - for(; i<=p2 && zHdrnHdrParsed<=p2 ){ + /* If there is more header available for parsing, try to extract + ** additional fields up through the p2-th field + */ + if( pC->iHdrOffsetaRow==0 ){ + memset(&sMem, 0, sizeof(sMem)); + rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex, + &sMem); + if( rc!=SQLITE_OK ){ + goto op_column_error; + } + zData = (u8*)sMem.z; }else{ - zHdr += sqlite3GetVarint32(zHdr, &t); + zData = pC->aRow; } - aType[i] = t; - szField = sqlite3VdbeSerialTypeLen(t); - offset += szField; - if( offsetnHdrParsed; + offset = aOffset[i]; + zHdr = zData + pC->iHdrOffset; + zEndHdr = zData + aOffset[0]; + assert( i<=p2 && zHdrnHdrParsed = i; + pC->iHdrOffset = (u32)(zHdr - zData); + if( pC->aRow==0 ){ + sqlite3VdbeMemRelease(&sMem); + sMem.flags = MEM_Null; + } + + /* If we have read more header data than was contained in the header, + ** or if the end of the last field appears to be past the end of the + ** record, or if the end of the last field appears to be before the end + ** of the record (when all fields present), then we must be dealing + ** with a corrupt database. + */ + if( (zHdr > zEndHdr) + || (offset > pC->payloadSize) + || (zHdr==zEndHdr && offset!=pC->payloadSize) + ){ + rc = SQLITE_CORRUPT_BKPT; + goto op_column_error; } - aOffset[i+1] = offset; - } - pC->nHdrParsed = i; - pC->iHdrOffset = (u32)(zHdr - zData); - if( pC->aRow==0 ){ - sqlite3VdbeMemRelease(&sMem); - sMem.flags = MEM_Null; } - /* If we have read more header data than was contained in the header, - ** or if the end of the last field appears to be past the end of the - ** record, or if the end of the last field appears to be before the end - ** of the record (when all fields present), then we must be dealing - ** with a corrupt database. - */ - if( (zHdr > zEndHdr) - || (offset > pC->payloadSize) - || (zHdr==zEndHdr && offset!=pC->payloadSize) - ){ - rc = SQLITE_CORRUPT_BKPT; + /* If after nHdrParsed is still not up to p2, that means that the record + ** has fewer than p2 columns. So the result will be either the default + ** value or a NULL. */ + if( pC->nHdrParsed<=p2 ){ + if( pOp->p4type==P4_MEM ){ + sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); + }else{ + MemSetTypeFlag(pDest, MEM_Null); + } goto op_column_out; } } @@ -2430,64 +2449,56 @@ case OP_Column: { ** request. In this case, set the value NULL or to P4 if P4 is ** a pointer to a Mem object. */ - if( p2nHdrParsed ){ - assert( rc==SQLITE_OK ); - if( pC->szRow>=aOffset[p2+1] ){ - /* This is the common case where the whole row fits on a single page */ - VdbeMemRelease(pDest); - sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest); + assert( p2nHdrParsed ); + assert( rc==SQLITE_OK ); + if( pC->szRow>=aOffset[p2+1] ){ + /* This is the common case where the whole row fits on a single page */ + VdbeMemRelease(pDest); + sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest); + }else{ + /* This branch happens only when the row overflows onto multiple pages */ + t = aType[p2]; + if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 + && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0) + ){ + /* Content is irrelevant for the typeof() function and for + ** the length(X) function if X is a blob. So we might as well use + ** bogus content rather than reading content from disk. NULL works + ** for text and blob and whatever is in the payloadSize64 variable + ** will work for everything else. */ + zData = t<12 ? (u8*)&payloadSize64 : 0; + sMem.zMalloc = 0; }else{ - /* This branch happens only when the row overflows onto multiple pages */ - t = aType[p2]; - if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 - && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0) - ){ - /* Content is irrelevant for the typeof() function and for - ** the length(X) function if X is a blob. So we might as well use - ** bogus content rather than reading content from disk. NULL works - ** for text and blob and whatever is in the payloadSize64 variable - ** will work for everything else. */ - zData = t<12 ? (u8*)&payloadSize64 : 0; - }else{ - len = sqlite3VdbeSerialTypeLen(t); - memset(&sMem, 0, sizeof(sMem)); - sqlite3VdbeMemMove(&sMem, pDest); - rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, - &sMem); - if( rc!=SQLITE_OK ){ - goto op_column_out; - } - zData = (u8*)sMem.z; + len = sqlite3VdbeSerialTypeLen(t); + memset(&sMem, 0, sizeof(sMem)); + sqlite3VdbeMemMove(&sMem, pDest); + rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, + &sMem); + if( rc!=SQLITE_OK ){ + goto op_column_error; } - sqlite3VdbeSerialGet(zData, t, pDest); + zData = (u8*)sMem.z; } - pDest->enc = encoding; - }else{ - if( pOp->p4type==P4_MEM ){ - sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); - }else{ - MemSetTypeFlag(pDest, MEM_Null); + sqlite3VdbeSerialGet(zData, t, pDest); + /* If we dynamically allocated space to hold the data (in the + ** sqlite3VdbeMemFromBtree() call above) then transfer control of that + ** dynamically allocated space over to the pDest structure. + ** This prevents a memory copy. */ + if( sMem.zMalloc ){ + assert( sMem.z==sMem.zMalloc ); + assert( !(pDest->flags & MEM_Dyn) ); + assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); + pDest->flags &= ~(MEM_Ephem|MEM_Static); + pDest->flags |= MEM_Term; + pDest->z = sMem.z; + pDest->zMalloc = sMem.zMalloc; } } - - /* If we dynamically allocated space to hold the data (in the - ** sqlite3VdbeMemFromBtree() call above) then transfer control of that - ** dynamically allocated space over to the pDest structure. - ** This prevents a memory copy. - */ - if( sMem.zMalloc ){ - assert( sMem.z==sMem.zMalloc ); - assert( !(pDest->flags & MEM_Dyn) ); - assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); - pDest->flags &= ~(MEM_Ephem|MEM_Static); - pDest->flags |= MEM_Term; - pDest->z = sMem.z; - pDest->zMalloc = sMem.zMalloc; - } - - rc = sqlite3VdbeMemMakeWriteable(pDest); + pDest->enc = encoding; op_column_out: + rc = sqlite3VdbeMemMakeWriteable(pDest); +op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; diff --git a/test/analyze9.test b/test/analyze9.test index aaf0ba3bb0..0fce55ac4b 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -805,8 +805,9 @@ do_test 16.1 { ANALYZE; } set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] + puts -nonewline " (nByte=$nByte nByte2=$nByte2)" - expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1050} + expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1100} } {1} #-------------------------------------------------------------------------