Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -4497,11 +4497,13 @@ for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){ /* If required, populate the overflow page-list cache. */ if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){ - assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage); + assert( pCur->aOverflow[iIdx]==0 + || pCur->aOverflow[iIdx]==nextPage + || CORRUPT_DB ); pCur->aOverflow[iIdx] = nextPage; } if( offset>=ovflSize ){ /* The only reason to read this page is to obtain the page Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1308,10 +1308,11 @@ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ +#define SQLITE_RowCache 0x1000 /* Reorder OP_Column opcodes */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -654,11 +654,11 @@ } #endif /* Sanity checking on other operands */ #ifdef SQLITE_DEBUG - assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] ); + assert( (pOp->opflags&~OPFLG_JMPDEST)==sqlite3OpcodeProperty[pOp->opcode] ); if( (pOp->opflags & OPFLG_IN1)!=0 ){ assert( pOp->p1>0 ); assert( pOp->p1<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p1]) ); assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -516,25 +516,71 @@ ** indicate what the prepared statement actually does. ** ** (4) Initialize the p4.xAdvance pointer on opcodes that use it. ** ** (5) Reclaim the memory allocated for storing labels. +** +** (6) Set the Op.opflags field on all opcodes, and especially the +** OPFLG_JMPDEST bit. +** +** (7) Reorders OP_Column opcodes against the same cursor so that the +** last column is extracted first. This is a performance optimization. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ - int i; + int i, m; int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; p->readOnly = 1; p->bIsReader = 0; + + /* First cut at the Op.opcode flags */ + for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ + pOp->opflags = sqlite3OpcodeProperty[pOp->opcode]; + } + + /* Resolve goto labels. And add OPFLG_JMPDEST flags to the + ** destinations of jumps. */ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ - u8 opcode = pOp->opcode; + if( (pOp->opflags & OPFLG_JUMP)!=0 ){ + if( pOp->p2<0 ){ + assert( -1-pOp->p2nLabel ); + pOp->p2 = aLabel[-1-pOp->p2]; + } + if( pOp->p2>0 && pOp->p2nOp ){ + p->aOp[pOp->p2].opflags |= OPFLG_JMPDEST; + } + } + } + sqlite3DbFree(p->db, pParse->aLabel); + pParse->aLabel = 0; + pParse->nLabel = 0; + /* Third pass: fix up opcodes */ + for(pOp=p->aOp, i=m=0; inOp; i++, pOp++){ /* NOTE: Be sure to update mkopcodeh.awk when adding or removing ** cases from this switch! */ - switch( opcode ){ + switch( pOp->opcode ){ + case OP_Column: { + if( OptimizationEnabled(p->db, SQLITE_RowCache) && i>=m ){ + /* Reorder OP_Column opcodes so that the right-most column is + ** extracted first. This warms up the row cache and helps the + ** subsequent OP_Column opcodes to run faster */ + int j; + int b = 0; + int p2 = pOp->p2; + for(j=1; pOp[j].opcode==OP_Column; j++){ + if( pOp[j].p1!=pOp->p1 ) break; + if( pOp[j].opflags & OPFLG_JMPDEST ) break; + if( pOp[j].p2>p2 ){ b = j; p2 = pOp[j].p2; } + } + if( b ) SWAP(Op, pOp[0], pOp[b]); + m = i+j; + } + break; + } case OP_Transaction: { if( pOp->p2!=0 ) p->readOnly = 0; /* fall thru */ } case OP_AutoCommit: @@ -577,20 +623,11 @@ pOp->p4.xAdvance = sqlite3BtreePrevious; pOp->p4type = P4_ADVANCE; break; } } - - pOp->opflags = sqlite3OpcodeProperty[opcode]; - if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ - assert( -1-pOp->p2nLabel ); - pOp->p2 = aLabel[-1-pOp->p2]; - } - } - sqlite3DbFree(p->db, pParse->aLabel); - pParse->aLabel = 0; - pParse->nLabel = 0; + } *pMaxFuncArgs = nMaxArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } /* Index: tool/mkopcodeh.tcl ================================================================== --- tool/mkopcodeh.tcl +++ tool/mkopcodeh.tcl @@ -124,10 +124,11 @@ incr nOp # The following are the opcodes that are processed by resolveP2Values() # set rp2v_ops { + OP_Column OP_Transaction OP_AutoCommit OP_Savepoint OP_Checkpoint OP_Vacuum @@ -209,16 +210,17 @@ puts "" puts "/* Properties such as \"out2\" or \"jump\" that are specified in" puts "** comments following the \"case\" for each opcode in the vdbe.c" puts "** are encoded into bitvectors as follows:" puts "*/" -puts "#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */" -puts "#define OPFLG_IN1 0x0002 /* in1: P1 is an input */" -puts "#define OPFLG_IN2 0x0004 /* in2: P2 is an input */" -puts "#define OPFLG_IN3 0x0008 /* in3: P3 is an input */" -puts "#define OPFLG_OUT2 0x0010 /* out2: P2 is an output */" -puts "#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */" +puts "#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */" +puts "#define OPFLG_IN1 0x02 /* in1: P1 is an input */" +puts "#define OPFLG_IN2 0x04 /* in2: P2 is an input */" +puts "#define OPFLG_IN3 0x08 /* in3: P3 is an input */" +puts "#define OPFLG_OUT2 0x10 /* out2: P2 is an output */" +puts "#define OPFLG_OUT3 0x20 /* out3: P3 is an output */" +puts "#define OPFLG_JMPDEST 0x40 /* A jump destination */" puts "#define OPFLG_INITIALIZER \173\\" for {set i 0} {$i<=$max} {incr i} { if {$i%8==0} { puts -nonewline [format "/* %3d */" $i] }