aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2013-11-20 19:28:03 +0000
committerdrh <drh@noemail.net>2013-11-20 19:28:03 +0000
commitc8606e416a6cab18e24a33d730a1a43376b0003c (patch)
tree491c7712a7b829bc73cb50f35d7baae53055be6b
parent399af1d2c26f383c6069b30e2ca966de31689aba (diff)
downloadsqlite-c8606e416a6cab18e24a33d730a1a43376b0003c.tar.gz
sqlite-c8606e416a6cab18e24a33d730a1a43376b0003c.zip
Further performance tweaks to OP_Column.
FossilOrigin-Name: 0e3f5df695216a27602a53eed5d25231b055adc8
-rw-r--r--manifest17
-rw-r--r--manifest.uuid2
-rw-r--r--src/vdbe.c251
-rw-r--r--test/analyze9.test3
4 files changed, 141 insertions, 132 deletions
diff --git a/manifest b/manifest
index 91be839db..a7de779af 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 6e355397d..458e461e6 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 874645f18..f3832ab34 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( p1<p->nCursor );
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->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- nField = pC->nField;
- assert( p2<nField );
+ assert( p2<pC->nField );
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->iHdrOffset<aOffset[0] ){
- /* Make sure zData points to enough of the record to cover the header. */
- if( pC->aRow==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 && zHdr<zEndHdr; i++){
- if( zHdr[0]<0x80 ){
- t = zHdr[0];
- zHdr++;
+ if( pC->nHdrParsed<=p2 ){
+ /* If there is more header available for parsing, try to extract
+ ** additional fields up through the p2-th field
+ */
+ if( pC->iHdrOffset<aOffset[0] ){
+ /* Make sure zData points to enough of the record to cover the header. */
+ if( pC->aRow==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( offset<szField ){ /* True if offset overflows */
- zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
- break;
+
+ /* 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 + aOffset[0];
+ assert( i<=p2 && zHdr<zEndHdr );
+ do{
+ if( zHdr[0]<0x80 ){
+ t = zHdr[0];
+ zHdr++;
+ }else{
+ zHdr += sqlite3GetVarint32(zHdr, &t);
+ }
+ aType[i] = t;
+ szField = sqlite3VdbeSerialTypeLen(t);
+ offset += szField;
+ if( offset<szField ){ /* True if offset overflows */
+ zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
+ break;
+ }
+ i++;
+ aOffset[i] = offset;
+ }while( i<=p2 && zHdr<zEndHdr );
+ 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;
+ 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( p2<pC->nHdrParsed ){
- 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( p2<pC->nHdrParsed );
+ 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 aaf0ba3bb..0fce55ac4 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}
#-------------------------------------------------------------------------