Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -4149,10 +4149,108 @@ sqlite3ExprCode(pParse, pExpr, target); iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); exprToRegister(pExpr, iMem); } + +/* +** Return the value of (*p1) - (*p2), as defined by the sort order described +** in the comment above reorderColumnFetch(). +*/ +static int compareOpCode(VdbeOp *p1, VdbeOp *p2){ + int res; + + assert( p1->opcode==OP_Column || p1->opcode==OP_VColumn + || p1->opcode==OP_Copy || p1->opcode==OP_SCopy + || p1->opcode==OP_Rowid || p1->opcode==OP_RealAffinity + ); + assert( p2->opcode==OP_Column || p2->opcode==OP_VColumn + || p2->opcode==OP_Copy || p2->opcode==OP_SCopy + || p2->opcode==OP_Rowid || p2->opcode==OP_RealAffinity + ); + + assert( OP_VColumn>OP_Column && OP_Rowid>OP_Column ); + assert( OP_Column>OP_RealAffinity ); + assert( OP_RealAffinity>OP_Copy && OP_RealAffinity>OP_SCopy ); + + res = (int)(p2->opcode) - (int)(p1->opcode); + if( res==0 ){ + res = p1->p1 - p2->p1; + if( res==0 ){ + res = p2->p2 - p1->p2; + } + } + return res; +} + +/* +** The VM instructions from iFirst to the current address were generated +** in order to populate an array of registers with the results of a series +** of TK_COLUMN expressions. This guarantees that the specified range +** contains opcodes of the following types only: +** +** Rowid +** Column +** VColumn +** RealAffinity +** Copy +** SCopy +** +** This function sorts the opcodes so all of the OP_Column appear in a +** contiguous block, sorted by (p1, p2 DESC). The VDBE layer processes +** OP_Column instructions in this order more efficiently. +** +** In practice, the array is sorted so that all instructions of each type +** of opcode are arranged into a contiguous group. Given the following, +** this is a safe re-ordering: +** +** * All Rowid, VColumn and Column instructions appear before all +** RealAffinity instructions (that might operate on the result of +** a VColumn or Column), and +** +** * All RealAffinity instructions occur before all Copy and SCopy +** instructions (which might read a column-cache entry populated +** by a prior Column+RealAffinity). +*/ +static void reorderColumnFetch(sqlite3 *db, Vdbe *v, int iFirst){ + int iEnd = sqlite3VdbeCurrentAddr(v); + int nOp = iEnd-iFirst; + if( nOp>1 ){ + VdbeOp *aSpace = (VdbeOp*)sqlite3StackAllocRaw(db, sizeof(VdbeOp) * nOp); + if( aSpace ){ + int sz; + VdbeOp *aOp = sqlite3VdbeGetOp(v, iFirst); + VdbeOp *a1 = aOp; + VdbeOp *a2 = aSpace; + for(sz=1; sz=e1 || (i2pVdbe; assert( pList!=0 ); assert( target>0 ); assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */ n = pList->nExpr; if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; ipExpr; + if( iFirst>0 ){ + if( pExpr->op!=TK_COLUMN ){ + reorderColumnFetch(pParse->db, v, iFirst); + iFirst = -1; + } + }else{ + if( pExpr->op==TK_COLUMN ) iFirst = sqlite3VdbeCurrentAddr(v); + } if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; n--; }else{ @@ -4209,10 +4316,11 @@ sqlite3VdbeAddOp2(v, copyOp, inReg, target+i); } } } } + if( iFirst>0 ) reorderColumnFetch(pParse->db, v, iFirst); return n; } /* ** Generate code for a BETWEEN operator. Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -1272,19 +1272,26 @@ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; bSeq = 1; } - for(i=0, iCol=nKey+bSeq; i=0; i--){ + if( aOutEx[i].u.x.iOrderByCol==0 ){ + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, --iCol, regRow+i); + VdbeComment((v, "%s", aOutEx[i].zName?aOutEx[i].zName:aOutEx[i].zSpan)); + } + } + for(i=nSortData-1; i>=0; i--){ if( aOutEx[i].u.x.iOrderByCol ){ - iRead = aOutEx[i].u.x.iOrderByCol-1; - }else{ - iRead = iCol++; + int iRead = aOutEx[i].u.x.iOrderByCol-1; + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); + VdbeComment((v, "%s", aOutEx[i].zName?aOutEx[i].zName:aOutEx[i].zSpan)); } - sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); - VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3078,10 +3078,12 @@ #define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */ #define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ #define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ #define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ + +#define OPFLAG_CONTINUE 0x01 /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. * Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -545,11 +545,15 @@ ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); +#if 1 + for(i=pTab->nCol-1; i>=0; i--){ +#else for(i=0; inCol; i++){ +#endif if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); }else{ j = aXRef[i]; if( j>=0 ){ Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -551,11 +551,10 @@ pOut->flags = MEM_Int; return pOut; } } - /* ** Execute as much of a VDBE program as we can. ** This is the core of sqlite3_step(). */ int sqlite3VdbeExec( @@ -2625,31 +2624,46 @@ } assert( t==pC->aType[p2] ); 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 */ - zData = pC->aRow + aOffset[p2]; - if( t<12 ){ - sqlite3VdbeSerialGet(zData, t, pDest); - }else{ - /* If the column value is a string, we need a persistent value, not - ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent - ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). - */ - static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; - pDest->n = len = (t-12)/2; - pDest->enc = encoding; - if( pDest->szMalloc < len+2 ){ - pDest->flags = MEM_Null; - if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; - }else{ - pDest->z = pDest->zMalloc; - } - memcpy(pDest->z, zData, len); - pDest->z[len] = 0; - pDest->z[len+1] = 0; - pDest->flags = aFlag[t&1]; + while( 1 ){ + zData = pC->aRow + aOffset[p2]; + if( t<12 ){ + sqlite3VdbeSerialGet(zData, t, pDest); + }else{ + /* If the column value is a string, we need a persistent value, not + ** a MEM_Ephem value. This branch is a fast short-cut that is + ** equivalent to calling sqlite3VdbeSerialGet() and + ** sqlite3VdbeDeephemeralize(). + */ + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; + pDest->n = len = (t-12)/2; + pDest->enc = encoding; + if( pDest->szMalloc < len+2 ){ + pDest->flags = MEM_Null; + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + }else{ + pDest->z = pDest->zMalloc; + } + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = aFlag[t&1]; + } + + if( (pOp->p5 & OPFLAG_CONTINUE)==0 ) break; + UPDATE_MAX_BLOBSIZE(pDest); + REGISTER_TRACE(pOp->p3, pDest); + pOp++; + p2 = pOp->p2; + t = pC->aType[p2]; + pDest = &aMem[pOp->p3]; + memAboutToChange(p, pDest); + if( VdbeMemDynamic(pDest) ){ + sqlite3VdbeMemSetNull(pDest); + } } }else{ pDest->enc = encoding; /* This branch happens only when content is on overflow pages */ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -224,10 +224,11 @@ void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); void sqlite3VdbeSwap(Vdbe*,Vdbe*); VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); void sqlite3VdbeSetVarmask(Vdbe*, int); +void sqlite3VdbeUsesAltMap(Vdbe*); #ifndef SQLITE_OMIT_TRACE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -388,10 +388,11 @@ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ bft isPrepareV2:1; /* True if prepared with prepare_v2() */ + bft usesAltMap:1; /* True if uses VdbeCursor.aAltMap[] */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -616,10 +616,17 @@ pOp->p2 = aLabel[ADDR(pOp->p2)]; } } if( pOp==p->aOp ) break; pOp--; + + if( p->usesAltMap==0 + && pOp[0].opcode==OP_Column && pOp[1].opcode==OP_Column + && pOp[0].p1==pOp[1].p1 && pOp[0].p2>=pOp[1].p2 + ){ + pOp->p5 |= OPFLAG_CONTINUE; + } } sqlite3DbFree(p->db, pParse->aLabel); pParse->aLabel = 0; pParse->nLabel = 0; *pMaxFuncArgs = nMaxArgs; @@ -4555,10 +4562,16 @@ }else{ v->expmask |= ((u32)1 << (iVar-1)); } } +/* +** Set the "uses-alt-map" flag. +*/ +void sqlite3VdbeUsesAltMap(Vdbe *v){ + v->usesAltMap = 1; +} #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored ** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored ** in memory obtained from sqlite3DbMalloc). Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -1001,10 +1001,11 @@ assert( pIdx->aiColumn[i]nCol ); if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1; } sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); } + sqlite3VdbeUsesAltMap(v); } } /* ** If the expression passed as the second argument is a vector, generate