Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.435 2008/06/24 12:46:31 drh Exp $ +** $Id: select.c,v 1.436 2008/06/25 00:12:41 drh Exp $ */ #include "sqliteInt.h" /* @@ -428,11 +428,11 @@ sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); if( pSelect->iLimit ){ int addr1, addr2; int iLimit; - if( pSelect->pOffset ){ + if( pSelect->iOffset ){ iLimit = pSelect->iOffset+1; }else{ iLimit = pSelect->iLimit; } addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit); @@ -559,12 +559,13 @@ nResultCol = nColumn; }else{ nResultCol = pEList->nExpr; } if( pDest->iMem==0 ){ - pDest->iMem = sqlite3GetTempRange(pParse, nResultCol); + pDest->iMem = pParse->nMem+1; pDest->nMem = nResultCol; + pParse->nMem += nResultCol; }else if( pDest->nMem!=nResultCol ){ /* This happens when two SELECTs of a compound SELECT have differing ** numbers of result columns. The error message will be generated by ** a higher-level routine. */ return; @@ -1785,10 +1786,11 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ Vdbe *v = 0; int iLimit = 0; int iOffset; int addr1; + if( p->iLimit ) return; /* ** "LIMIT -1" always shows all rows. There is some ** contraversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean @@ -1969,11 +1971,11 @@ " do not have the same number of result columns", selectOpName(p->op)); rc = 1; goto multi_select_end; } -#if 0 +#if 1 if( p->pOrderBy ){ return multiSelectOrderBy(pParse, p, pDest, aff); } #endif @@ -2310,26 +2312,61 @@ #endif /* SQLITE_OMIT_COMPOUND_SELECT */ /* ** Code an output subroutine for a coroutine implementation of a ** SELECT statment. +** +** The data to be output is contained in pIn->iMem. There are +** pIn->nMem columns to be output. pDest is where the output should +** be sent. +** +** regReturn is the number of the register holding the subroutine +** return address. +** +** If regPrev>0 then it is a the first register in a vector that +** records the previous output. mem[regPrev] is a flag that is false +** if there has been no previous output. If regPrev>0 then code is +** generated to suppress duplicates. pKeyInfo is used for comparing +** keys. +** +** If the LIMIT found in p->iLimit is reached, jump immediately to +** iBreak. */ -static int outputSubroutine( +static int generateOutputSubroutine( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ SelectDest *pIn, /* Coroutine supplying data */ SelectDest *pDest, /* Where to send the data */ int regReturn, /* The return address register */ + int regPrev, /* Previous result register. No uniqueness if 0 */ + KeyInfo *pKeyInfo, /* For comparing with previous entry */ + int p4type, /* The p4 type for pKeyInfo */ int iBreak /* Jump here if we hit the LIMIT */ ){ Vdbe *v = pParse->pVdbe; int iContinue; int addr; if( v==0 ) return 0; addr = sqlite3VdbeCurrentAddr(v); iContinue = sqlite3VdbeMakeLabel(v); + + /* Suppress duplicates for UNION, EXCEPT, and INTERSECT + */ + if( regPrev ){ + int j1, j2; + j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); + j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iMem, regPrev+1, pIn->nMem, + (char*)pKeyInfo, p4type); + sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); + sqlite3VdbeJumpHere(v, j1); + sqlite3ExprCodeCopy(pParse, pIn->iMem, regPrev+1, pIn->nMem); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev); + } + + /* Suppress the the first OFFSET entries if there is an OFFSET clause + */ codeOffset(v, p, iContinue); switch( pDest->eDest ){ /* Store the result as data using a unique key. */ @@ -2423,17 +2460,13 @@ if( p->iLimit ){ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1); sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak); } - /* Advance the coroutine to its next value. - */ - sqlite3VdbeResolveLabel(v, iContinue); - sqlite3VdbeAddOp1(v, OP_Yield, pIn->iParm); - /* Generate the subroutine return */ + sqlite3VdbeResolveLabel(v, iContinue); sqlite3VdbeAddOp1(v, OP_Return, regReturn); return addr; } @@ -2473,22 +2506,29 @@ ** is used: ** ** ** UNION ALL UNION EXCEPT INTERSECT ** ------------- ----------------- -------------- ----------------- -** AltB: outA, nextA outA, nextA outA, nextA nextA -** -** AeqB: outA, nextA nextA nextA outA -** nextA while A==B -** -** AgtB: outB, nextB outB, nextB nextB nextB -** -** EofA: outB, nextB A<-B, outB, halt halt -** nextB while A==B -** -** EofB: outA, nextA B<-A, outA outA, nextA halt -** nextA while A==B +** AltB: outA, nextA outA, nextA outA, nextA nextA +** +** AeqB: outA, nextA nextA nextA outA, nextA +** +** AgtB: outB, nextB outB, nextB nextB nextB +** +** EofA: outB, nextB outB, nextB halt halt +** +** EofB: outA, nextA outA, nextA outA, nextA halt +** +** In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA +** causes an immediate jump to EofA and an EOF on B following nextB causes +** an immediate jump to EofB. Within EofA and EofB, and EOF on entry or +** following nextX causes a jump to the end of the select processing. +** +** Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled +** within the output subroutine. The regPrev register set holds the previously +** output value. A comparison is made against this value and the output +** is skipped if the next results would be the same as the previous. ** ** The implementation plan is to implement the two coroutines and seven ** subroutines first, then put the control logic at the bottom. Like this: ** ** goto Init @@ -2519,10 +2559,11 @@ Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest, /* What to do with query results */ char *aff /* If eDest is SRT_Union, the affinity string */ ){ + int i, j; /* Loop counters */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ SelectDest destA; /* Destination for coroutine A */ SelectDest destB; /* Destination for coroutine B */ int regAddrA; /* Address register for select-A coroutine */ @@ -2540,53 +2581,163 @@ int addrAltB; /* Address of the AB subroutine */ int regLimitA; /* Limit register for select-A */ int regLimitB; /* Limit register for select-A */ + int regPrev; /* A range of registers to hold previous output */ int savedLimit; /* Saved value of p->iLimit */ int savedOffset; /* Saved value of p->iOffset */ int labelCmpr; /* Label for the start of the merge algorithm */ int labelEnd; /* Label for the end of the overall SELECT stmt */ - int j1, j2, j3; /* Jump instructions that get retargetted */ + int j1; /* Jump instructions that get retargetted */ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ - KeyInfo *pKeyInfo; /* Type data for comparisons */ - int p4type; /* P4 type used for pKeyInfo */ + KeyInfo *pKeyDup; /* Comparison information for duplicate removal */ + KeyInfo *pKeyMerge; /* Comparison information for merging rows */ + sqlite3 *db; /* Database connection */ + ExprList *pOrderBy; /* The ORDER BY clause */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + int *aPermute; /* Mapping from ORDER BY terms to result set columns */ + u8 NotUsed; /* Dummy variables */ assert( p->pOrderBy!=0 ); + db = pParse->db; v = pParse->pVdbe; if( v==0 ) return SQLITE_NOMEM; labelEnd = sqlite3VdbeMakeLabel(v); labelCmpr = sqlite3VdbeMakeLabel(v); - pKeyInfo = keyInfoFromExprList(pParse, p->pEList); - p4type = P4_KEYINFO_HANDOFF; + /* Patch up the ORDER BY clause */ op = p->op; pPrior = p->pPrior; assert( pPrior->pOrderBy==0 ); - if( processCompoundOrderBy(pParse, p, 0) ){ - return SQLITE_ERROR; + pOrderBy = p->pOrderBy; + if( pOrderBy ){ + if( processCompoundOrderBy(pParse, p, 0) ){ + return SQLITE_ERROR; + } + nOrderBy = pOrderBy->nExpr; + }else{ + nOrderBy = 0; } - pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy); + /* For operators other than UNION ALL we have to make sure that + ** the ORDER BY clause covers every term of the result set. Add + ** terms to the ORDER BY clause as necessary. + */ + if( op!=TK_ALL ){ + for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){ + for(j=0; ja[j].pExpr; + assert( pTerm->op==TK_INTEGER ); + assert( (pTerm->flags & EP_IntValue)!=0 ); + if( pTerm->iTable==i ) break; + } + if( j==nOrderBy ){ + Expr *pNew = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, 0); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->flags |= EP_IntValue; + pNew->iTable = i; + pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew, 0); + nOrderBy++; + } + } + } + + /* Compute the comparison permutation and keyinfo that is used with + ** the permutation in order to comparisons to determine if the next + ** row of results comes from selectA or selectB. Also add explicit + ** collations to the ORDER BY clause terms so that when the subqueries + ** to the right and the left are evaluated, they use the correct + ** collation. + */ + aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy); + if( aPermute ){ + for(i=0; ia[i].pExpr; + assert( pTerm->op==TK_INTEGER ); + assert( (pTerm->flags & EP_IntValue)!=0 ); + aPermute[i] = pTerm->iTable-1; + assert( aPermute[i]>=0 && aPermute[i]pEList->nExpr ); + } + pKeyMerge = + sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq*)+1)); + if( pKeyMerge ){ + pKeyMerge->aSortOrder = (u8*)&pKeyMerge->aColl[nOrderBy]; + pKeyMerge->nField = nOrderBy; + pKeyMerge->enc = ENC(db); + for(i=0; ia[i].pExpr; + if( pTerm->flags & EP_ExpCollate ){ + pColl = pTerm->pColl; + }else{ + pColl = multiSelectCollSeq(pParse, p, aPermute[i]); + pTerm->flags |= EP_ExpCollate; + pTerm->pColl = pColl; + } + pKeyMerge->aColl[i] = pColl; + pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder; + } + } + }else{ + pKeyMerge = 0; + } + + /* Reattach the ORDER BY clause to the query. + */ + p->pOrderBy = pOrderBy; + pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy); + + /* Allocate a range of temporary registers and the KeyInfo needed + ** for the logic that removes duplicate result rows when the + ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). + */ + if( op==TK_ALL ){ + regPrev = 0; + }else{ + int nExpr = p->pEList->nExpr; + assert( nOrderBy>=nExpr ); + regPrev = sqlite3GetTempRange(pParse, nExpr+1); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); + pKeyDup = sqlite3DbMallocZero(db, + sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) ); + if( pKeyDup ){ + pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr]; + pKeyDup->nField = nExpr; + pKeyDup->enc = ENC(db); + for(i=0; iaColl[i] = multiSelectCollSeq(pParse, p, i); + pKeyDup->aSortOrder[i] = 0; + } + } + } /* Separate the left and the right query from one another */ p->pPrior = 0; pPrior->pRightmost = 0; - + processOrderGroupBy(pParse, p, p->pOrderBy, 1, &NotUsed); + if( pPrior->pPrior==0 ){ + processOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, 1, &NotUsed); + } + /* Compute the limit registers */ computeLimitRegisters(pParse, p, labelEnd); - if( p->iLimit ){ + if( p->iLimit && op==TK_ALL ){ regLimitA = ++pParse->nMem; regLimitB = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit, regLimitA); sqlite3VdbeAddOp2(v, OP_Copy, regLimitA, regLimitB); }else{ regLimitA = regLimitB = 0; } + sqlite3ExprDelete(p->pLimit); + p->pLimit = 0; + sqlite3ExprDelete(p->pOffset); + p->pOffset = 0; regAddrA = ++pParse->nMem; regEofA = ++pParse->nMem; regAddrB = ++pParse->nMem; regEofB = ++pParse->nMem; @@ -2598,13 +2749,15 @@ /* Jump past the various subroutines and coroutines to the main ** merge loop */ j1 = sqlite3VdbeAddOp0(v, OP_Goto); addrSelectA = sqlite3VdbeCurrentAddr(v); + /* Generate a coroutine to evaluate the SELECT statement to the - ** left of the compound operator - the "A" select. */ + ** left of the compound operator - the "A" select. + */ VdbeNoopComment((v, "Begin coroutine for left SELECT")); pPrior->iLimit = regLimitA; sqlite3Select(pParse, pPrior, &destA, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA); sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); @@ -2625,160 +2778,126 @@ sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB); sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); VdbeNoopComment((v, "End coroutine for right SELECT")); /* Generate a subroutine that outputs the current row of the A - ** select as the next output row of the compound select and then - ** advances the A select to its next row + ** select as the next output row of the compound select. */ VdbeNoopComment((v, "Output routine for A")); - addrOutA = outputSubroutine(pParse, p, &destA, pDest, regOutA, labelEnd); + addrOutA = generateOutputSubroutine(pParse, + p, &destA, pDest, regOutA, + regPrev, pKeyDup, P4_KEYINFO_HANDOFF, labelEnd); /* Generate a subroutine that outputs the current row of the B - ** select as the next output row of the compound select and then - ** advances the B select to its next row + ** select as the next output row of the compound select. */ - VdbeNoopComment((v, "Output routine for B")); - addrOutB = outputSubroutine(pParse, p, &destB, pDest, regOutB, labelEnd); + if( op==TK_ALL || op==TK_UNION ){ + VdbeNoopComment((v, "Output routine for B")); + addrOutB = generateOutputSubroutine(pParse, + p, &destB, pDest, regOutB, + regPrev, pKeyDup, P4_KEYINFO_STATIC, labelEnd); + } /* Generate a subroutine to run when the results from select A ** are exhausted and only data in select B remains. */ VdbeNoopComment((v, "eof-A subroutine")); - addrEofA = sqlite3VdbeCurrentAddr(v); - if( op==TK_EXCEPT || op==TK_INTERSECT ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd); - }else{ - if( op==TK_ALL ){ - j2 = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); - sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); - sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); - }else{ - assert( op==TK_UNION ); - sqlite3ExprCodeCopy(pParse, destB.iMem, destA.iMem, destB.nMem); - j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); - sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); - sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem, - (char*)pKeyInfo, p4type); - p4type = P4_KEYINFO_STATIC; - sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+4, j2); - sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); - sqlite3VdbeAddOp2(v, OP_Goto, 0, j2+1); - } + if( op==TK_EXCEPT || op==TK_INTERSECT ){ + addrEofA = sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd); + }else{ + addrEofA = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA); } /* Generate a subroutine to run when the results from select B ** are exhausted and only data in select A remains. */ if( op==TK_INTERSECT ){ addrEofB = addrEofA; }else{ VdbeNoopComment((v, "eof-B subroutine")); - addrEofB = sqlite3VdbeCurrentAddr(v); - if( op==TK_ALL || op==TK_EXCEPT ){ - j2 = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); - sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); - sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); - }else{ - assert( op==TK_UNION ); - sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); - sqlite3ExprCodeCopy(pParse, destA.iMem, destB.iMem, destA.nMem); - j2 = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); - sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); - sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destB.nMem, - (char*)pKeyInfo, p4type); - p4type = P4_KEYINFO_STATIC; - sqlite3VdbeAddOp3(v, OP_Jump, j2, j2+4, j2); - sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); - sqlite3VdbeAddOp2(v, OP_Goto, 0, j2+1); - } + addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd); + sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + sqlite3VdbeAddOp1(v, OP_Yield, regAddrA); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB); } /* Generate code to handle the case of AB */ VdbeNoopComment((v, "A-gt-B subroutine")); addrAgtB = sqlite3VdbeCurrentAddr(v); if( op==TK_ALL || op==TK_UNION ){ sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); - }else{ - sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); } + sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB); sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr); /* This code runs once to initialize everything. */ sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA); sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB); - sqlite3VdbeAddOp2(v, OP_Integer, addrSelectB, regAddrB); sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA); + sqlite3VdbeAddOp2(v, OP_Gosub, regAddrB, addrSelectB); sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA); - sqlite3VdbeAddOp1(v, OP_Yield, regAddrB); sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB); /* Implement the main merge loop */ sqlite3VdbeResolveLabel(v, labelCmpr); - sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, destA.nMem, - (char*)pKeyInfo, p4type); - p4type = P4_KEYINFO_STATIC; + sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); + sqlite3VdbeAddOp4(v, OP_Compare, destA.iMem, destB.iMem, nOrderBy, + (char*)pKeyMerge, P4_KEYINFO_HANDOFF); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); + + /* Release temporary registers + */ + if( regPrev ){ + sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1); + } /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); /* Set the number of output columns */ if( pDest->eDest==SRT_Callback ){ - Select *pFirst = p; + Select *pFirst = pPrior; while( pFirst->pPrior ) pFirst = pFirst->pPrior; generateColumnNames(pParse, 0, pFirst->pEList); } - /* Free the KeyInfo if unused. - */ - if( p4type==P4_KEYINFO_HANDOFF ){ - sqlite3_free(pKeyInfo); - } + /* Reassembly the compound query so that it will be freed correctly + ** by the calling function */ + p->pPrior = pPrior; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ return SQLITE_OK; } Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -41,11 +41,11 @@ ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.754 2008/06/23 18:49:44 danielk1977 Exp $ +** $Id: vdbe.c,v 1.755 2008/06/25 00:12:41 drh Exp $ */ #include "sqliteInt.h" #include #include "vdbeInt.h" @@ -544,10 +544,12 @@ sqlite3 *db = p->db; /* The database */ u8 encoding = ENC(db); /* The database encoding */ Mem *pIn1, *pIn2, *pIn3; /* Input operands */ Mem *pOut; /* Output operand */ u8 opProperty; + int iCompare = 0; /* Result of last OP_Compare operation */ + int *aPermute = 0; /* Permuation of columns for OP_Compare */ #ifdef VDBE_PROFILE u64 start; /* CPU clock count at start of opcode */ int origPc; /* Program counter at start of opcode */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK @@ -995,11 +997,10 @@ assert( p2>0 ); assert( p2+nnMem ); pOut = &p->aMem[p2]; assert( p1+n<=p2 || p2+n<=p1 ); while( n-- ){ - REGISTER_TRACE(p1++, pIn1); zMalloc = pOut->zMalloc; pOut->zMalloc = 0; sqlite3VdbeMemMove(pOut, pIn1); pIn1->zMalloc = zMalloc; REGISTER_TRACE(p2++, pOut); @@ -1018,11 +1019,10 @@ */ case OP_Copy: { assert( pOp->p1>0 ); assert( pOp->p1<=p->nMem ); pIn1 = &p->aMem[pOp->p1]; - REGISTER_TRACE(pOp->p1, pIn1); assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; assert( pOut!=pIn1 ); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); @@ -1081,10 +1081,11 @@ */ pMem = p->pResultSet = &p->aMem[pOp->p1]; for(i=0; ip2; i++){ sqlite3VdbeMemNulTerminate(&pMem[i]); storeTypeInfo(&pMem[i], encoding); + REGISTER_TRACE(pOp->p1+i, &pMem[i]); } if( db->mallocFailed ) goto no_mem; /* Return SQLITE_ROW */ @@ -1737,20 +1738,39 @@ }else if( res ){ pc = pOp->p2-1; } break; } + +/* Opcode: Permutation * * * P4 * +** +** Set the permuation used by the OP_Compare operator to be the array +** of integers in P4. +** +** The permutation is only valid until the next OP_Permutation, OP_Compare, +** OP_Halt, or OP_ResultRow. Typically the OP_Permutation should occur +** immediately prior to the OP_Compare. +*/ +case OP_Permutation: { + assert( pOp->p4type==P4_INTARRAY ); + assert( pOp->p4.ai ); + aPermute = pOp->p4.ai; + break; +} /* Opcode: Compare P1 P2 P3 P4 * ** ** Compare to vectors of registers in reg(P1)..reg(P1+P3-1) (all this ** one "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of ** the comparison for use by the next OP_Jump instruct. ** -** P4 is a KeyInfo structure that defines collating sequences usedused for affinity purposes. The -** comparison is done for sorting purposes, so NULLs compare -** equal, NULLs are less than numbers, numbers are less than strings, +** P4 is a KeyInfo structure that defines collating sequences and sort +** orders for the comparison. The permutation applies to registers +** only. The KeyInfo elements are used sequentially. +** +** The comparison is a sort comparison, so NULLs compare equal, +** NULLs are less than numbers, numbers are less than strings, ** and strings are less than blobs. */ case OP_Compare: { int n = pOp->p3; int i, p1, p2; @@ -1758,30 +1778,45 @@ assert( n>0 ); p1 = pOp->p1; assert( p1>0 && p1+n-1nMem ); p2 = pOp->p2; assert( p2>0 && p2+n-1nMem ); - for(i=0; iaMem[p1]); - REGISTER_TRACE(p2, &p->aMem[p2]); - p->iCompare = sqlite3MemCompare(&p->aMem[p1], &p->aMem[p2], - pKeyInfo && inField ? pKeyInfo->aColl[i] : 0); - if( p->iCompare ) break; + for(i=0; inField ); + REGISTER_TRACE(p1+idx, &p->aMem[p1+idx]); + REGISTER_TRACE(p2+idx, &p->aMem[p2+idx]); + if( pKeyInfo ){ + assert( inField ); + pColl = pKeyInfo->aColl[i]; + bRev = pKeyInfo->aSortOrder[i]; + }else{ + pColl = 0; + bRev = 0; + } + iCompare = sqlite3MemCompare(&p->aMem[p1+idx], &p->aMem[p2+idx], pColl); + if( iCompare ){ + if( bRev ) iCompare = -iCompare; + break; + } } + aPermute = 0; break; } /* Opcode: Jump P1 P2 P3 * * ** ** Jump to the instruction at address P1, P2, or P3 depending on whether ** in the most recent OP_Compare instruction the P1 vector was less than ** equal to, or greater than the P2 vector, respectively. */ -case OP_Jump: { - if( p->iCompare<0 ){ +case OP_Jump: { /* jump */ + if( iCompare<0 ){ pc = pOp->p1 - 1; - }else if( p->iCompare==0 ){ + }else if( iCompare==0 ){ pc = pOp->p2 - 1; }else{ pc = pOp->p3 - 1; } break; Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -13,11 +13,11 @@ ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.133 2008/06/20 18:13:25 drh Exp $ +** $Id: vdbe.h,v 1.134 2008/06/25 00:12:41 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include @@ -59,10 +59,11 @@ VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ sqlite3_vtab *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ + int *ai; /* Used when p4type is P4_INTARRAY */ } p4; #ifdef SQLITE_DEBUG char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE @@ -99,20 +100,21 @@ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ +#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still ** gets freed when the Vdbe is finalized so it still should be obtained ** from a single sqliteMalloc(). But no copy is made and the calling ** function should *not* try to free the KeyInfo. */ -#define P4_KEYINFO_HANDOFF (-15) -#define P4_KEYINFO_STATIC (-16) +#define P4_KEYINFO_HANDOFF (-16) +#define P4_KEYINFO_STATIC (-17) /* ** The Vdbe.aColName array contains 5n Mem structures, where n is the ** number of columns of data returned by the statement. */ Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -13,11 +13,11 @@ ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. ** -** $Id: vdbeInt.h,v 1.148 2008/06/20 18:13:25 drh Exp $ +** $Id: vdbeInt.h,v 1.149 2008/06/25 00:12:41 drh Exp $ */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ /* @@ -319,11 +319,10 @@ u8 changeCntOn; /* True to update the change-counter */ u8 aborted; /* True if ROLLBACK in another VM causes an abort */ u8 expired; /* True if the VM needs to be recompiled */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 inVtabMethod; /* See comments above */ - int iCompare; /* Result of most recent OP_Compare comparison */ int nChange; /* Number of db changes made since last reset */ i64 startTime; /* Time when query started - used for profiling */ int btreeMask; /* Bitmask of db->aDb[] entries referenced */ BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */ int nSql; /* Number of bytes in zSql */ Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -12,11 +12,11 @@ ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** -** $Id: vdbeaux.c,v 1.392 2008/06/23 13:57:22 danielk1977 Exp $ +** $Id: vdbeaux.c,v 1.393 2008/06/25 00:12:42 drh Exp $ */ #include "sqliteInt.h" #include #include "vdbeInt.h" @@ -439,35 +439,36 @@ } /* ** Delete a P4 value if necessary. */ -static void freeP4(int p4type, void *p3){ - if( p3 ){ +static void freeP4(int p4type, void *p4){ + if( p4 ){ switch( p4type ){ case P4_REAL: case P4_INT64: case P4_MPRINTF: case P4_DYNAMIC: case P4_KEYINFO: + case P4_INTARRAY: case P4_KEYINFO_HANDOFF: { - sqlite3_free(p3); + sqlite3_free(p4); break; } case P4_VDBEFUNC: { - VdbeFunc *pVdbeFunc = (VdbeFunc *)p3; + VdbeFunc *pVdbeFunc = (VdbeFunc *)p4; freeEphemeralFunction(pVdbeFunc->pFunc); sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); sqlite3_free(pVdbeFunc); break; } case P4_FUNCDEF: { - freeEphemeralFunction((FuncDef*)p3); + freeEphemeralFunction((FuncDef*)p4); break; } case P4_MEM: { - sqlite3ValueFree((sqlite3_value*)p3); + sqlite3ValueFree((sqlite3_value*)p4); break; } } } } @@ -695,10 +696,14 @@ sqlite3_vtab *pVtab = pOp->p4.pVtab; sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule); break; } #endif + case P4_INTARRAY: { + sqlite3_snprintf(nTemp, zTemp, "intarray"); + break; + } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0;