Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c8606e4

Browse files
author
drh
committed
Further performance tweaks to OP_Column.
FossilOrigin-Name: 0e3f5df695216a27602a53eed5d25231b055adc8
1 parent 399af1d commit c8606e4

File tree

4 files changed

+141
-132
lines changed

4 files changed

+141
-132
lines changed

manifest

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
C Refactoring\sthe\sOP_Column\sopcode\sfor\simproved\sperformance\sand\nmaintainability.
2-
D 2013-11-20T17:25:55.912
1+
C Further\sperformance\stweaks\sto\sOP_Column.
2+
D 2013-11-20T19:28:03.982
33
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
44
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
55
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -280,7 +280,7 @@ F src/update.c c05a0ee658f1a149e0960dfd110f3b8bd846bcb0
280280
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
281281
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
282282
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
283-
F src/vdbe.c d4b8a9067a163f18535324c76bafdddff6b93491
283+
F src/vdbe.c 1a6e2c9413fca3b2d00c49e85a861e0adc8b6c6a
284284
F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644
285285
F src/vdbeInt.h fbae1c449049a1a26ebbdf44e1beb08344072b72
286286
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
@@ -313,7 +313,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
313313
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
314314
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
315315
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
316-
F test/analyze9.test 1b9b7e9a096d1536f03d9ad7b72f638ef5669347
316+
F test/analyze9.test 339e87723cd4dc158dc5e9095acd8df9e87faf79
317317
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
318318
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
319319
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
@@ -1140,10 +1140,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
11401140
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
11411141
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
11421142
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
1143-
P 5562cd343d8f69242e06a51a7f1aef7ee7d78eec
1144-
R 71521f10a62f5e2d15e34378a9a872cf
1145-
T *branch * OP_Column-refactor
1146-
T *sym-OP_Column-refactor *
1147-
T -sym-trunk *
1143+
P 7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
1144+
R 72749b37eba95a49879e9308fdcd90bb
11481145
U drh
1149-
Z 41c0df82986aff89d8eb065b326b79ba
1146+
Z 441207295dddfadd80f4cc85b77f0a53

manifest.uuid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
1+
0e3f5df695216a27602a53eed5d25231b055adc8

src/vdbe.c

Lines changed: 131 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,13 +2255,11 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
22552255
*/
22562256
case OP_Column: {
22572257
i64 payloadSize64; /* Number of bytes in the record */
2258-
int p1; /* P1 value of the opcode */
22592258
int p2; /* column number to retrieve */
22602259
VdbeCursor *pC; /* The VDBE cursor */
22612260
BtCursor *pCrsr; /* The BTree cursor */
22622261
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
22632262
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
2264-
int nField; /* number of fields in the record */
22652263
int len; /* The length of the serialized data for the column */
22662264
int i; /* Loop counter */
22672265
Mem *pDest; /* Where to write the extracted value */
@@ -2275,45 +2273,46 @@ case OP_Column: {
22752273
u32 t; /* A type code from the record header */
22762274
Mem *pReg; /* PseudoTable input register */
22772275

2278-
p1 = pOp->p1;
2279-
assert( p1<p->nCursor );
22802276
p2 = pOp->p2;
2281-
sMem.zMalloc = 0;
22822277
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
22832278
pDest = &aMem[pOp->p3];
22842279
memAboutToChange(p, pDest);
2285-
pC = p->apCsr[p1];
2280+
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
2281+
pC = p->apCsr[pOp->p1];
22862282
assert( pC!=0 );
2287-
nField = pC->nField;
2288-
assert( p2<nField );
2283+
assert( p2<pC->nField );
22892284
aType = pC->aType;
22902285
aOffset = pC->aOffset;
22912286
#ifndef SQLITE_OMIT_VIRTUALTABLE
22922287
assert( pC->pVtabCursor==0 );
22932288
#endif
22942289
pCrsr = pC->pCursor;
22952290
assert( pCrsr!=0 || pC->pseudoTableReg>0 );
2291+
assert( pC->pseudoTableReg==0 || pC->nullRow );
22962292

22972293
/* If the cursor cache is stale, bring it up-to-date */
22982294
rc = sqlite3VdbeCursorMoveto(pC);
22992295
if( rc ) goto abort_due_to_error;
23002296
if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
2301-
if( pCrsr==0 ){
2302-
assert( pC->pseudoTableReg>0 );
2303-
pReg = &aMem[pC->pseudoTableReg];
2304-
if( pC->multiPseudo ){
2305-
sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
2306-
Deephemeralize(pDest);
2297+
if( pC->nullRow ){
2298+
if( pCrsr==0 ){
2299+
assert( pC->pseudoTableReg>0 );
2300+
pReg = &aMem[pC->pseudoTableReg];
2301+
if( pC->multiPseudo ){
2302+
sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
2303+
Deephemeralize(pDest);
2304+
goto op_column_out;
2305+
}
2306+
assert( pReg->flags & MEM_Blob );
2307+
assert( memIsValid(pReg) );
2308+
pC->payloadSize = pC->szRow = avail = pReg->n;
2309+
pC->aRow = (u8*)pReg->z;
2310+
}else{
2311+
MemSetTypeFlag(pDest, MEM_Null);
23072312
goto op_column_out;
23082313
}
2309-
assert( pReg->flags & MEM_Blob );
2310-
assert( memIsValid(pReg) );
2311-
pC->payloadSize = pC->szRow = avail = pReg->n;
2312-
pC->aRow = (u8*)pReg->z;
2313-
}else if( pC->nullRow ){
2314-
MemSetTypeFlag(pDest, MEM_Null);
2315-
goto op_column_out;
23162314
}else{
2315+
assert( pCrsr );
23172316
if( pC->isIndex ){
23182317
assert( sqlite3BtreeCursorIsValid(pCrsr) );
23192318
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
@@ -2361,65 +2360,85 @@ case OP_Column: {
23612360
*/
23622361
if( offset > 98307 || offset > pC->payloadSize ){
23632362
rc = SQLITE_CORRUPT_BKPT;
2364-
goto op_column_out;
2363+
goto op_column_error;
23652364
}
23662365
}
23672366

23682367
/* Make sure at least the first p2+1 entries of the header have been
23692368
** parsed and valid information is in aOffset[] and aType[].
23702369
*/
2371-
if( pC->nHdrParsed<=p2 && pC->iHdrOffset<aOffset[0] ){
2372-
/* Make sure zData points to enough of the record to cover the header. */
2373-
if( pC->aRow==0 ){
2374-
memset(&sMem, 0, sizeof(sMem));
2375-
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,&sMem);
2376-
if( rc!=SQLITE_OK ){
2377-
goto op_column_out;
2378-
}
2379-
zData = (u8*)sMem.z;
2380-
}else{
2381-
zData = pC->aRow;
2382-
}
2383-
2384-
/* Fill in aType[i] and aOffset[i] values through the p2-th field. */
2385-
i = pC->nHdrParsed;
2386-
offset = aOffset[i];
2387-
zHdr = zData + pC->iHdrOffset;
2388-
zEndHdr = zData + pC->aOffset[0];
2389-
for(; i<=p2 && zHdr<zEndHdr; i++){
2390-
if( zHdr[0]<0x80 ){
2391-
t = zHdr[0];
2392-
zHdr++;
2370+
if( pC->nHdrParsed<=p2 ){
2371+
/* If there is more header available for parsing, try to extract
2372+
** additional fields up through the p2-th field
2373+
*/
2374+
if( pC->iHdrOffset<aOffset[0] ){
2375+
/* Make sure zData points to enough of the record to cover the header. */
2376+
if( pC->aRow==0 ){
2377+
memset(&sMem, 0, sizeof(sMem));
2378+
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,
2379+
&sMem);
2380+
if( rc!=SQLITE_OK ){
2381+
goto op_column_error;
2382+
}
2383+
zData = (u8*)sMem.z;
23932384
}else{
2394-
zHdr += sqlite3GetVarint32(zHdr, &t);
2385+
zData = pC->aRow;
23952386
}
2396-
aType[i] = t;
2397-
szField = sqlite3VdbeSerialTypeLen(t);
2398-
offset += szField;
2399-
if( offset<szField ){ /* True if offset overflows */
2400-
zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
2401-
break;
2387+
2388+
/* Fill in aType[i] and aOffset[i] values through the p2-th field. */
2389+
i = pC->nHdrParsed;
2390+
offset = aOffset[i];
2391+
zHdr = zData + pC->iHdrOffset;
2392+
zEndHdr = zData + aOffset[0];
2393+
assert( i<=p2 && zHdr<zEndHdr );
2394+
do{
2395+
if( zHdr[0]<0x80 ){
2396+
t = zHdr[0];
2397+
zHdr++;
2398+
}else{
2399+
zHdr += sqlite3GetVarint32(zHdr, &t);
2400+
}
2401+
aType[i] = t;
2402+
szField = sqlite3VdbeSerialTypeLen(t);
2403+
offset += szField;
2404+
if( offset<szField ){ /* True if offset overflows */
2405+
zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
2406+
break;
2407+
}
2408+
i++;
2409+
aOffset[i] = offset;
2410+
}while( i<=p2 && zHdr<zEndHdr );
2411+
pC->nHdrParsed = i;
2412+
pC->iHdrOffset = (u32)(zHdr - zData);
2413+
if( pC->aRow==0 ){
2414+
sqlite3VdbeMemRelease(&sMem);
2415+
sMem.flags = MEM_Null;
2416+
}
2417+
2418+
/* If we have read more header data than was contained in the header,
2419+
** or if the end of the last field appears to be past the end of the
2420+
** record, or if the end of the last field appears to be before the end
2421+
** of the record (when all fields present), then we must be dealing
2422+
** with a corrupt database.
2423+
*/
2424+
if( (zHdr > zEndHdr)
2425+
|| (offset > pC->payloadSize)
2426+
|| (zHdr==zEndHdr && offset!=pC->payloadSize)
2427+
){
2428+
rc = SQLITE_CORRUPT_BKPT;
2429+
goto op_column_error;
24022430
}
2403-
aOffset[i+1] = offset;
2404-
}
2405-
pC->nHdrParsed = i;
2406-
pC->iHdrOffset = (u32)(zHdr - zData);
2407-
if( pC->aRow==0 ){
2408-
sqlite3VdbeMemRelease(&sMem);
2409-
sMem.flags = MEM_Null;
24102431
}
24112432

2412-
/* If we have read more header data than was contained in the header,
2413-
** or if the end of the last field appears to be past the end of the
2414-
** record, or if the end of the last field appears to be before the end
2415-
** of the record (when all fields present), then we must be dealing
2416-
** with a corrupt database.
2417-
*/
2418-
if( (zHdr > zEndHdr)
2419-
|| (offset > pC->payloadSize)
2420-
|| (zHdr==zEndHdr && offset!=pC->payloadSize)
2421-
){
2422-
rc = SQLITE_CORRUPT_BKPT;
2433+
/* If after nHdrParsed is still not up to p2, that means that the record
2434+
** has fewer than p2 columns. So the result will be either the default
2435+
** value or a NULL. */
2436+
if( pC->nHdrParsed<=p2 ){
2437+
if( pOp->p4type==P4_MEM ){
2438+
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
2439+
}else{
2440+
MemSetTypeFlag(pDest, MEM_Null);
2441+
}
24232442
goto op_column_out;
24242443
}
24252444
}
@@ -2430,64 +2449,56 @@ case OP_Column: {
24302449
** request. In this case, set the value NULL or to P4 if P4 is
24312450
** a pointer to a Mem object.
24322451
*/
2433-
if( p2<pC->nHdrParsed ){
2434-
assert( rc==SQLITE_OK );
2435-
if( pC->szRow>=aOffset[p2+1] ){
2436-
/* This is the common case where the whole row fits on a single page */
2437-
VdbeMemRelease(pDest);
2438-
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
2452+
assert( p2<pC->nHdrParsed );
2453+
assert( rc==SQLITE_OK );
2454+
if( pC->szRow>=aOffset[p2+1] ){
2455+
/* This is the common case where the whole row fits on a single page */
2456+
VdbeMemRelease(pDest);
2457+
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
2458+
}else{
2459+
/* This branch happens only when the row overflows onto multiple pages */
2460+
t = aType[p2];
2461+
if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
2462+
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
2463+
){
2464+
/* Content is irrelevant for the typeof() function and for
2465+
** the length(X) function if X is a blob. So we might as well use
2466+
** bogus content rather than reading content from disk. NULL works
2467+
** for text and blob and whatever is in the payloadSize64 variable
2468+
** will work for everything else. */
2469+
zData = t<12 ? (u8*)&payloadSize64 : 0;
2470+
sMem.zMalloc = 0;
24392471
}else{
2440-
/* This branch happens only when the row overflows onto multiple pages */
2441-
t = aType[p2];
2442-
if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
2443-
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
2444-
){
2445-
/* Content is irrelevant for the typeof() function and for
2446-
** the length(X) function if X is a blob. So we might as well use
2447-
** bogus content rather than reading content from disk. NULL works
2448-
** for text and blob and whatever is in the payloadSize64 variable
2449-
** will work for everything else. */
2450-
zData = t<12 ? (u8*)&payloadSize64 : 0;
2451-
}else{
2452-
len = sqlite3VdbeSerialTypeLen(t);
2453-
memset(&sMem, 0, sizeof(sMem));
2454-
sqlite3VdbeMemMove(&sMem, pDest);
2455-
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,
2456-
&sMem);
2457-
if( rc!=SQLITE_OK ){
2458-
goto op_column_out;
2459-
}
2460-
zData = (u8*)sMem.z;
2472+
len = sqlite3VdbeSerialTypeLen(t);
2473+
memset(&sMem, 0, sizeof(sMem));
2474+
sqlite3VdbeMemMove(&sMem, pDest);
2475+
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,
2476+
&sMem);
2477+
if( rc!=SQLITE_OK ){
2478+
goto op_column_error;
24612479
}
2462-
sqlite3VdbeSerialGet(zData, t, pDest);
2480+
zData = (u8*)sMem.z;
24632481
}
2464-
pDest->enc = encoding;
2465-
}else{
2466-
if( pOp->p4type==P4_MEM ){
2467-
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
2468-
}else{
2469-
MemSetTypeFlag(pDest, MEM_Null);
2482+
sqlite3VdbeSerialGet(zData, t, pDest);
2483+
/* If we dynamically allocated space to hold the data (in the
2484+
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
2485+
** dynamically allocated space over to the pDest structure.
2486+
** This prevents a memory copy. */
2487+
if( sMem.zMalloc ){
2488+
assert( sMem.z==sMem.zMalloc );
2489+
assert( !(pDest->flags & MEM_Dyn) );
2490+
assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
2491+
pDest->flags &= ~(MEM_Ephem|MEM_Static);
2492+
pDest->flags |= MEM_Term;
2493+
pDest->z = sMem.z;
2494+
pDest->zMalloc = sMem.zMalloc;
24702495
}
24712496
}
2472-
2473-
/* If we dynamically allocated space to hold the data (in the
2474-
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
2475-
** dynamically allocated space over to the pDest structure.
2476-
** This prevents a memory copy.
2477-
*/
2478-
if( sMem.zMalloc ){
2479-
assert( sMem.z==sMem.zMalloc );
2480-
assert( !(pDest->flags & MEM_Dyn) );
2481-
assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
2482-
pDest->flags &= ~(MEM_Ephem|MEM_Static);
2483-
pDest->flags |= MEM_Term;
2484-
pDest->z = sMem.z;
2485-
pDest->zMalloc = sMem.zMalloc;
2486-
}
2487-
2488-
rc = sqlite3VdbeMemMakeWriteable(pDest);
2497+
pDest->enc = encoding;
24892498

24902499
op_column_out:
2500+
rc = sqlite3VdbeMemMakeWriteable(pDest);
2501+
op_column_error:
24912502
UPDATE_MAX_BLOBSIZE(pDest);
24922503
REGISTER_TRACE(pOp->p3, pDest);
24932504
break;

test/analyze9.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,8 +805,9 @@ do_test 16.1 {
805805
ANALYZE;
806806
}
807807
set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
808+
puts -nonewline " (nByte=$nByte nByte2=$nByte2)"
808809

809-
expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1050}
810+
expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1100}
810811
} {1}
811812

812813
#-------------------------------------------------------------------------

0 commit comments

Comments
 (0)