Add the OPFLAG_MULTICOLUMN flat to the OP_Column opcode. Rearrange OP_Column
instrunctions to take advantage of the new flag for a small performance
increase
FossilOrigin-Name: 5e5d6e8680b253b4de5c04df155c27f15fedc0c1
diff --git a/manifest b/manifest
index c39ace7..1c59731 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sthe\sheader\scomment\sin\ssqlite3VdbeDeletePriorOpcode().\s\sNo\schanges\sto\ncode.
-D 2014-09-29T15:42:01.115
+C Add\sthe\sOPFLAG_MULTICOLUMN\sflat\sto\sthe\sOP_Column\sopcode.\s\sRearrange\sOP_Column\ninstrunctions\sto\stake\sadvantage\sof\sthe\snew\sflag\sfor\sa\ssmall\sperformance\s\nincrease
+D 2014-09-29T18:47:20.017
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -181,7 +181,7 @@
F src/ctime.c bb434068b5308a857b181c2d204a320ff0d6c638
F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036
F src/delete.c fae81cc2eb14b75267d4f47d3cfc9ae02aae726f
-F src/expr.c f32119248996680aa73c5c37bfdd42820804dc17
+F src/expr.c 622ca88bb258292690a550ca0c290ec7b071bed4
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee
@@ -227,12 +227,12 @@
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c a3466128b52a86c466e47ac1a19e2174f7b5cf89
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
-F src/select.c a83ed8bc2a31c131e3addb6f0488b68334085e7b
+F src/select.c 6e7d7a277307ebee1a284d8811a8a3351ffc39b2
F src/shell.c dad23987c34faddb061a339da3e92e05ccc6935e
F src/sqlite.h.in 8b018219ce988913e5977d5de9ab4beb33be23b6
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
-F src/sqliteInt.h 5e09fe04f999223680801ddf8fbae6b60751d613
+F src/sqliteInt.h ba443d9af2cef399e2ec641d44d005212b1476ef
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2e99ef7ef16187e17033d9398dc962ce22dab5cb
@@ -285,15 +285,15 @@
F src/threads.c 22dded4283dc4b25422f6444cdcb8d6b1ea0b5ff
F src/tokenize.c cc9016e5007fc5e76789079616d2f26741bcc689
F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
-F src/update.c 729f6f18fc27740591d085e1172cebe311144bf0
+F src/update.c dcc1733c8f9d455a3127e2b151a211fa7f9ef053
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c 4006c01772bd8d8ac4306d523bbcee41d3e392d8
F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
-F src/vdbe.c 93eeb6f9c3a3084133225a196f220454d71cca10
-F src/vdbe.h 09f5b4e3719fa454f252322b1cdab5cf1f361327
+F src/vdbe.c 89636b004debc955452f6e0f26dfcc13cc96676b
+F src/vdbe.h d5825ae515ab108331739bd4910eb66dd0eb33f0
F src/vdbeInt.h bb7f7ecfdead1a2ae0251b59f86f5724838d975c
F src/vdbeapi.c e9e33b59834e3edc8790209765e069874c269d9d
-F src/vdbeaux.c 8e016c6051c013a394f8e8679be1ca60723707bd
+F src/vdbeaux.c f8df1050cb0e5f7d537bda4dc6caa44d44ab87bc
F src/vdbeblob.c 848238dc73e93e48432991bb5651bf87d865eca4
F src/vdbemem.c 1e105dacf5190fc85a8ec2107c0dcc1884e75099
F src/vdbesort.c 5c1bacf90578d22b630fbf6ed98ccf60d83435ef
@@ -1200,7 +1200,10 @@
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 414f0d6a647a4d040b5463c73c5e15e699d85b4c
-R f6298f1a1c0cd9e9dc9c3dc07f24407e
+P 7fb1626866c2f8dad84c7e6184824be3efd71ca2
+R 58d61b9e8ed6b972c827aa4b2de6a9d8
+T *branch * faster-OP_Column
+T *sym-faster-OP_Column *
+T -sym-trunk *
U drh
-Z 0f82639c06e932d5523a9215bf58cd9c
+Z bc7d4115a8f75585e68aa7b7bc067fe4
diff --git a/manifest.uuid b/manifest.uuid
index b5ea57e..59185e9 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7fb1626866c2f8dad84c7e6184824be3efd71ca2
\ No newline at end of file
+5e5d6e8680b253b4de5c04df155c27f15fedc0c1
\ No newline at end of file
diff --git a/src/expr.c b/src/expr.c
index 57e462e..64dcbae 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2381,6 +2381,7 @@
}
if( iCol>=0 ){
sqlite3ColumnDefault(v, pTab, iCol, regOut);
+ sqlite3VdbeOptimizeColumnOpcodes(v);
}
}
diff --git a/src/select.c b/src/select.c
index 7820833..5e0c03b 100644
--- a/src/select.c
+++ b/src/select.c
@@ -706,7 +706,7 @@
pDest->nSdst = nResultCol;
regResult = pDest->iSdst;
if( srcTab>=0 ){
- for(i=0; i<nResultCol; i++){
+ for(i=nResultCol-1; i>=0; i--){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
VdbeComment((v, "%s", pEList->a[i].zName));
}
@@ -1225,10 +1225,11 @@
p5 = 0;
bSeq = 1;
}
- for(i=0; i<nSortData; i++){
+ for(i=nSortData-1; i>=0; i--){
sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
- if( i==0 ) sqlite3VdbeChangeP5(v, p5);
+ sqlite3VdbeChangeP5(v, p5);
VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
+ p5 = 0;
}
switch( eDest ){
case SRT_Table:
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b7e4d07..7ec6336 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2665,6 +2665,7 @@
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
+#define OPFLAG_MULTICOLUMN 0x10 /* OP_Column followed by another */
/*
* Each trigger present in the database schema is stored as an instance of
diff --git a/src/update.c b/src/update.c
index f781a60..8a7774c 100644
--- a/src/update.c
+++ b/src/update.c
@@ -73,6 +73,7 @@
}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeOptimizeColumnOpcodes(v);
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
diff --git a/src/vdbe.c b/src/vdbe.c
index 34eb1d4..5e2ca39 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2266,9 +2266,11 @@
u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
u16 fx; /* pDest->flags value */
+ u8 p5;
Mem *pReg; /* PseudoTable input register */
p2 = pOp->p2;
+ p5 = 0;
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
@@ -2436,22 +2438,32 @@
}
}
- /* Extract the content for the p2+1-th column. Control can only
- ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are
- ** all valid.
+ /* At this point, all of the following values are set:
+ **
+ ** p2 Index of column to extract. pOp->p2.
+ ** pDest Memory register into which to write result
+ ** pC->aRow Binary row content from the btree. Might be incomplete
+ ** pC->szRow Number of bytes in pC->szRow
+ ** aOffset[p2] Offset into the binary row where P2-th column starts
+ ** aOffste[p2+1] Offset into binary row of first byte past P2-th column
+ ** pC->aType[p2] Datatype of the P2-th column (as stored on disk)
+ **
+ ** Extract the content for column number p2.
*/
+op_column_decode:
assert( p2<pC->nHdrParsed );
assert( rc==SQLITE_OK );
assert( sqlite3VdbeCheckMemInvariants(pDest) );
if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
t = pC->aType[p2];
+ p5 = pOp->p5;
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
}else{
/* This branch happens only when content is on overflow pages */
- if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
+ if( ((p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
|| (len = sqlite3VdbeSerialTypeLen(t))==0
){
@@ -2495,6 +2507,23 @@
op_column_error:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
+
+ /* If the OPFLAG_MULTICOLUMN bit is set on P5, that means that this
+ ** OP_Column is immediately followed by another OP_Column with the same
+ ** P1 and a P2 that is no larger than the current P2. In that case,
+ ** process the following OP_Column as part of this instruction, without
+ ** returning to the main instruction dispatch loop.
+ */
+ if( (p5 & OPFLAG_MULTICOLUMN)!=0 && rc==0 ){
+ pc++;
+ assert( pOp[1].opcode==OP_Column );
+ assert( pOp[1].p1==pOp[0].p1 );
+ assert( pOp[1].p2<=pOp[0].p2 );
+ pOp++;
+ p2 = pOp->p2;
+ pDest = &aMem[pOp->p3];
+ goto op_column_decode;
+ }
break;
}
diff --git a/src/vdbe.h b/src/vdbe.h
index f975f95..b977d3c 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -179,6 +179,7 @@
void sqlite3VdbeJumpHere(Vdbe*, int addr);
void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
+void sqlite3VdbeOptimizeColumnOpcodes(Vdbe*);
void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
void sqlite3VdbeUsesBtree(Vdbe*, int);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 2562c63..3f3f8d0 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -502,6 +502,15 @@
pOp->p4type = P4_ADVANCE;
break;
}
+ case OP_Column: {
+ if( pOp[1].opcode==OP_Column
+ && pOp[1].p1==pOp->p1
+ && pOp[1].p2<=pOp->p2
+ ){
+ pOp->p5 |= OPFLAG_MULTICOLUMN;
+ }
+ break;
+ }
}
pOp->opflags = sqlite3OpcodeProperty[opcode];
@@ -765,6 +774,30 @@
}
/*
+** When running multiple OP_Column opcodes in a row, it is advantagous
+** to run the one with the largest P2 value (the largest column number)
+** first. This routine checks the last few OP_Column opcodes and
+** might reorder them so that a larger P2 value opertion occurs at
+** the start of the list.
+*/
+void sqlite3VdbeOptimizeColumnOpcodes(Vdbe *p){
+ VdbeOp *aOp, tempOp;
+ int i;
+ aOp = p->aOp;
+ i = p->nOp-2;
+ while( i>p->pParse->iFixedOp
+ && aOp[i+1].opcode==OP_Column
+ && aOp[i].opcode==OP_Column
+ && aOp[i].p1==aOp[i+1].p1
+ && aOp[i].p2<aOp[i+1].p2 ){
+ tempOp = aOp[i];
+ aOp[i] = aOp[i+1];
+ aOp[i+1] = tempOp;
+ i--;
+ }
+}
+
+/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
** static array using sqlite3VdbeAddOpList but we want to make a