** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.257 2005/08/31 18:20:00 drh Exp $
+** $Id: select.c,v 1.258 2005/09/01 03:07:44 drh Exp $
*/
#include "sqliteInt.h"
pNew->pOffset = pOffset;
pNew->iLimit = -1;
pNew->iOffset = -1;
+ pNew->addrOpenVirt[0] = -1;
+ pNew->addrOpenVirt[1] = -1;
+ pNew->addrOpenVirt[2] = -1;
}
return pNew;
}
*/
static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
sqlite3ExprCodeExprList(pParse, pOrderBy);
- sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr, 0);
- sqlite3VdbeAddOp(v, OP_SortInsert, 0, 0);
+ sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr, 0);
+ sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 1, 0);
+ sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iTab, 0);
}
/*
** Given an expression list, generate a KeyInfo structure that records
** the collating sequence for each expression in that expression list.
**
+** If the ExprList is an ORDER BY or GROUP BY clause then the resulting
+** KeyInfo structure is appropriate for initializing a virtual index to
+** implement that clause. If the ExprList is the result set of a SELECT
+** then the KeyInfo structure is appropriate for initializing a virtual
+** index to implement a DISTINCT test.
+**
** Space to hold the KeyInfo structure is obtain from malloc. The calling
** function is responsible for seeing that this structure is eventually
** freed. Add the KeyInfo structure to the P3 field of an opcode using
int eDest, /* Write the sorted results here */
int iParm /* Optional parameter associated with eDest */
){
- int end1 = sqlite3VdbeMakeLabel(v);
- int end2 = sqlite3VdbeMakeLabel(v);
+ int brk = sqlite3VdbeMakeLabel(v);
+ int cont = sqlite3VdbeMakeLabel(v);
int addr;
- KeyInfo *pInfo;
+ int iTab;
+ ExprList *pOrderBy = p->pOrderBy;
if( eDest==SRT_Sorter ) return;
- pInfo = keyInfoFromExprList(pParse, p->pOrderBy);
- if( pInfo==0 ) return;
- sqlite3VdbeOp3(v, OP_Sort, 0, 0, (char*)pInfo, P3_KEYINFO_HANDOFF);
- addr = sqlite3VdbeAddOp(v, OP_SortNext, 0, end1);
- codeLimiter(v, p, addr, end2, 1);
+ iTab = pOrderBy->iTab;
+ addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
+ codeLimiter(v, p, cont, brk, 0);
+ sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr);
switch( eDest ){
case SRT_Table:
case SRT_TempTable: {
case SRT_Mem: {
assert( nColumn==1 );
sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
- sqlite3VdbeAddOp(v, OP_Goto, 0, end1);
+ sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
break;
}
#endif
break;
}
}
- sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
- sqlite3VdbeResolveLabel(v, end2);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeResolveLabel(v, end1);
- sqlite3VdbeAddOp(v, OP_SortReset, 0, 0);
+ sqlite3VdbeResolveLabel(v, cont);
+ sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
+ sqlite3VdbeResolveLabel(v, brk);
}
/*
}
/*
-** Generate VDBE instructions that will open a transient table that
-** will be used for an index or to store keyed results for a compound
-** select. In other words, open a transient table that needs a
-** KeyInfo structure. The number of columns in the KeyInfo is determined
-** by the result set of the SELECT statement in the second argument.
-**
-** Specifically, this routine is called to open an index table for
-** DISTINCT, UNION, INTERSECT and EXCEPT select statements (but not
-** UNION ALL).
-**
-** The value returned is the address of the OP_OpenVirtual instruction.
-*/
-static int openVirtualIndex(Parse *pParse, Select *p, int iTab){
- KeyInfo *pKeyInfo;
- Vdbe *v = pParse->pVdbe;
- int addr;
-
- if( prepSelectStmt(pParse, p) ){
- return 0;
- }
- pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
- if( pKeyInfo==0 ) return 0;
- addr = sqlite3VdbeOp3(v, OP_OpenVirtual, iTab, 0,
- (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
- return addr;
-}
-
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
-/*
-** Add the address "addr" to the set of all OpenVirtual opcode addresses
-** that are being accumulated in p->ppOpenVirtual.
+** Allocate a virtual index to use for sorting.
*/
-static int multiSelectOpenVirtualAddr(Select *p, int addr){
- IdList *pList = *p->ppOpenVirtual = sqlite3IdListAppend(*p->ppOpenVirtual, 0);
- if( pList==0 ){
- return SQLITE_NOMEM;
+static createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
+ if( pOrderBy ){
+ int addr;
+ assert( pOrderBy->iTab==0 );
+ pOrderBy->iTab = pParse->nTab++;
+ addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual,
+ pOrderBy->iTab, pOrderBy->nExpr+1);
+ assert( p->addrOpenVirt[2] == -1 );
+ p->addrOpenVirt[2] = addr;
}
- pList->a[pList->nId-1].idx = addr;
- return SQLITE_OK;
}
-#endif /* SQLITE_OMIT_COMPOUND_SELECT */
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
int rc = SQLITE_OK; /* Success code from a subroutine */
Select *pPrior; /* Another SELECT immediately to our left */
Vdbe *v; /* Generate code to this VDBE */
- IdList *pOpenVirtual = 0;/* OP_OpenVirtual opcodes that need a KeyInfo */
- int aAddr[5]; /* Addresses of SetNumColumns operators */
- int nAddr = 0; /* Number used */
int nCol; /* Number of columns in the result set */
+ ExprList *pOrderBy; /* The ORDER BY clause on p */
+ int aSetP2[2]; /* Set P2 value of these op to number of columns */
+ int nSetP2 = 0; /* Number of slots in aSetP2[] used */
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
goto multi_select_end;
}
pPrior = p->pPrior;
+ assert( pPrior->pRightmost!=pPrior );
+ assert( pPrior->pRightmost==p->pRightmost );
if( pPrior->pOrderBy ){
sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
selectOpName(p->op));
goto multi_select_end;
}
- /* If *p this is the right-most select statement, then initialize
- ** p->ppOpenVirtual to point to pOpenVirtual. If *p is not the right most
- ** statement then p->ppOpenVirtual will have already been initialized
- ** by a prior call to this same procedure. Pass along the pOpenVirtual
- ** pointer to pPrior, the next statement to our left.
- */
- if( p->ppOpenVirtual==0 ){
- p->ppOpenVirtual = &pOpenVirtual;
- }
- pPrior->ppOpenVirtual = p->ppOpenVirtual;
-
/* Create the destination temporary table if necessary
*/
if( eDest==SRT_TempTable ){
assert( p->pEList );
- sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
- assert( nAddr==0 );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 0);
+ assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
+ aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
eDest = SRT_Table;
}
/* Generate code for the left and right SELECT statements.
*/
+ pOrderBy = p->pOrderBy;
switch( p->op ){
case TK_ALL: {
- if( p->pOrderBy==0 ){
+ if( pOrderBy==0 ){
assert( !pPrior->pLimit );
pPrior->pLimit = p->pLimit;
pPrior->pOffset = p->pOffset;
int op = 0; /* One of the SRT_ operations to apply to self */
int priorOp; /* The SRT_ operation to apply to prior selects */
Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
- ExprList *pOrderBy; /* The ORDER BY clause for the right SELECT */
int addr;
priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union;
- if( eDest==priorOp && p->pOrderBy==0 && !p->pLimit && !p->pOffset ){
+ if( eDest==priorOp && pOrderBy==0 && !p->pLimit && !p->pOffset ){
/* We can reuse a temporary table generated by a SELECT to our
** right.
*/
** intermediate results.
*/
unionTab = pParse->nTab++;
- if( p->pOrderBy
- && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){
+ if( pOrderBy && matchOrderbyToColumn(pParse, p, pOrderBy, unionTab,1) ){
rc = 1;
goto multi_select_end;
}
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0);
- if( p->op!=TK_ALL ){
- rc = multiSelectOpenVirtualAddr(p, addr);
- if( rc!=SQLITE_OK ){
- goto multi_select_end;
- }
+ if( priorOp==SRT_Table ){
+ assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) );
+ aSetP2[nSetP2++] = addr;
+ }else{
+ assert( p->addrOpenVirt[0] == -1 );
+ p->addrOpenVirt[0] = addr;
+ p->pRightmost->usesVirt = 1;
}
- assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, unionTab, 0);
+ createSortingIndex(pParse, p, pOrderBy);
assert( p->pEList );
}
case TK_ALL: op = SRT_Table; break;
}
p->pPrior = 0;
- pOrderBy = p->pOrderBy;
p->pOrderBy = 0;
pLimit = p->pLimit;
p->pLimit = 0;
computeLimitRegisters(pParse, p);
iStart = sqlite3VdbeCurrentAddr(v);
rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
- p->pOrderBy, -1, eDest, iParm,
+ pOrderBy, -1, eDest, iParm,
iCont, iBreak, 0);
if( rc ){
rc = 1;
*/
tab1 = pParse->nTab++;
tab2 = pParse->nTab++;
- if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
+ if( pOrderBy && matchOrderbyToColumn(pParse,p,pOrderBy,tab1,1) ){
rc = 1;
goto multi_select_end;
}
+ createSortingIndex(pParse, p, pOrderBy);
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0);
- rc = multiSelectOpenVirtualAddr(p, addr);
- if( rc!=SQLITE_OK ){
- goto multi_select_end;
- }
- assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab1, 0);
+ assert( p->addrOpenVirt[0] == -1 );
+ p->addrOpenVirt[0] = addr;
+ p->pRightmost->usesVirt = 1;
assert( p->pEList );
/* Code the SELECTs to our left into temporary table "tab1".
/* Code the current SELECT into temporary table "tab2"
*/
addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0);
- rc = multiSelectOpenVirtualAddr(p, addr);
- if( rc!=SQLITE_OK ){
- goto multi_select_end;
- }
- assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );
- aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab2, 0);
+ assert( p->addrOpenVirt[1] == -1 );
+ p->addrOpenVirt[1] = addr;
p->pPrior = 0;
pLimit = p->pLimit;
p->pLimit = 0;
iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);
sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
- p->pOrderBy, -1, eDest, iParm,
+ pOrderBy, -1, eDest, iParm,
iCont, iBreak, 0);
if( rc ){
rc = 1;
/* Set the number of columns in temporary tables
*/
nCol = p->pEList->nExpr;
- while( nAddr>0 ){
- nAddr--;
- sqlite3VdbeChangeP2(v, aAddr[nAddr], nCol);
+ while( nSetP2 ){
+ sqlite3VdbeChangeP2(v, aSetP2[--nSetP2], nCol);
}
/* Compute collating sequences used by either the ORDER BY clause or
** SELECT might also skip this part if it has no ORDER BY clause and
** no temp tables are required.
*/
- if( p->pOrderBy || (pOpenVirtual && pOpenVirtual->nId>0) ){
+ if( pOrderBy || p->usesVirt ){
int i; /* Loop counter */
KeyInfo *pKeyInfo; /* Collating sequence for the result set */
+ Select *pLoop; /* For looping through SELECT statements */
+ CollSeq **apColl;
+ CollSeq **aCopy;
- assert( p->ppOpenVirtual == &pOpenVirtual );
- pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*sizeof(CollSeq*));
+ assert( p->pRightmost==p );
+ pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*2*sizeof(CollSeq*));
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
pKeyInfo->enc = pParse->db->enc;
pKeyInfo->nField = nCol;
- for(i=0; i<nCol; i++){
- pKeyInfo->aColl[i] = multiSelectCollSeq(pParse, p, i);
- if( !pKeyInfo->aColl[i] ){
- pKeyInfo->aColl[i] = pParse->db->pDfltColl;
+ for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
+ *apColl = multiSelectCollSeq(pParse, p, i);
+ if( 0==*apColl ){
+ *apColl = pParse->db->pDfltColl;
}
}
- for(i=0; pOpenVirtual && i<pOpenVirtual->nId; i++){
- int p3type = (i==0?P3_KEYINFO_HANDOFF:P3_KEYINFO);
- int addr = pOpenVirtual->a[i].idx;
- sqlite3VdbeChangeP3(v, addr, (char *)pKeyInfo, p3type);
+ for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
+ for(i=0; i<2; i++){
+ int addr = pLoop->addrOpenVirt[i];
+ if( addr<0 ){
+ /* If [0] is unused then [1] is also unused. So we can
+ ** always safely abort as soon as the first unused slot is found */
+ assert( pLoop->addrOpenVirt[1]<0 );
+ break;
+ }
+ sqlite3VdbeChangeP2(v, addr, nCol);
+ sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
+ }
}
- if( p->pOrderBy ){
- struct ExprList_item *pOrderByTerm = p->pOrderBy->a;
- for(i=0; i<p->pOrderBy->nExpr; i++, pOrderByTerm++){
- Expr *pExpr = pOrderByTerm->pExpr;
- char *zName = pOrderByTerm->zName;
+ if( pOrderBy ){
+ struct ExprList_item *pOTerm = pOrderBy->a;
+ int nExpr = pOrderBy->nExpr;
+ int addr;
+
+ aCopy = (CollSeq**)&pKeyInfo[1];
+ memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
+ apColl = pKeyInfo->aColl;
+ for(i=0; i<pOrderBy->nExpr; i++, pOTerm++, apColl++){
+ Expr *pExpr = pOTerm->pExpr;
+ char *zName = pOTerm->zName;
assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
- /* assert( !pExpr->pColl ); */
if( zName ){
- pExpr->pColl = sqlite3LocateCollSeq(pParse, zName, -1);
+ *apColl = sqlite3LocateCollSeq(pParse, zName, -1);
}else{
- pExpr->pColl = pKeyInfo->aColl[pExpr->iColumn];
+ *apColl = aCopy[pExpr->iColumn];
}
}
+ assert( p->pRightmost==p );
+ assert( p->addrOpenVirt[2]>=0 );
+ addr = p->addrOpenVirt[2];
+ sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+1);
+ sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
}
- if( !pOpenVirtual ){
- /* This happens for UNION ALL ... ORDER BY */
- sqliteFree(pKeyInfo);
- }
+ sqliteFree(pKeyInfo);
}
multi_select_end:
- if( pOpenVirtual ){
- sqlite3IdListDelete(pOpenVirtual);
- }
- p->ppOpenVirtual = 0;
return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
/* If there is are a sequence of queries, do the earlier ones first.
*/
if( p->pPrior ){
+ if( p->pRightmost==0 ){
+ Select *pLoop;
+ for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
+ pLoop->pRightmost = p;
+ }
+ }
return multiSelect(pParse, p, eDest, iParm, aff);
}
#endif
*/
if( pOrderBy ){
struct ExprList_item *pTerm;
+ KeyInfo *pKeyInfo;
+ int addr;
for(i=0, pTerm=pOrderBy->a; i<pOrderBy->nExpr; i++, pTerm++){
if( pTerm->zName ){
pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1);
if( pParse->nErr ){
goto select_end;
}
+ pKeyInfo = keyInfoFromExprList(pParse, pOrderBy);
+ pOrderBy->iTab = pParse->nTab++;
+ addr = sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iTab, pOrderBy->nExpr+1,
+ (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ p->addrOpenVirt[2] = addr;
}
/* Set the limiter.
/* If the output is destined for a temporary table, open that table.
*/
if( eDest==SRT_TempTable ){
- sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
+ sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
}
/* Do an analysis of aggregate expressions.
/* Open a virtual index to use for the distinct set.
*/
if( isDistinct ){
+ KeyInfo *pKeyInfo;
distinct = pParse->nTab++;
- openVirtualIndex(pParse, p, distinct);
+ pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
+ sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0,
+ (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
}else{
distinct = -1;
}
** 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.478 2005/07/28 20:51:19 drh Exp $
+** $Id: vdbe.c,v 1.479 2005/09/01 03:07:44 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
*ppTos = pTos;
}
-/*
-** The parameters are pointers to the head of two sorted lists
-** of Sorter structures. Merge these two lists together and return
-** a single sorted list. This routine forms the core of the merge-sort
-** algorithm.
-**
-** In the case of a tie, left sorts in front of right.
-*/
-static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){
- Sorter sHead;
- Sorter *pTail;
- pTail = &sHead;
- pTail->pNext = 0;
- while( pLeft && pRight ){
- int c = sqlite3VdbeRecordCompare(pKeyInfo, pLeft->nKey, pLeft->zKey,
- pRight->nKey, pRight->zKey);
- if( c<=0 ){
- pTail->pNext = pLeft;
- pLeft = pLeft->pNext;
- }else{
- pTail->pNext = pRight;
- pRight = pRight->pNext;
- }
- pTail = pTail->pNext;
- }
- if( pLeft ){
- pTail->pNext = pLeft;
- }else if( pRight ){
- pTail->pNext = pRight;
- }
- return sHead.pNext;
-}
-
/*
** Allocate cursor number iCur. Return a pointer to it. Return NULL
** if we run out of memory.
/* Opcode: Halt P1 P2 P3
**
-** Exit immediately. All open cursors, Lists, Sorts, etc are closed
+** Exit immediately. All open cursors, Fifos, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
break;
}
-/* Opcode: OpenVirtual P1 * P3
+/* Opcode: OpenVirtual P1 P2 P3
**
-** Open a new cursor to a transient or virtual table.
+** Open a new cursor P1 to a transient or virtual table.
** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual
** table is deleted automatically when the cursor is closed.
**
+** P2 is the number of columns in the virtual table.
** The cursor points to a BTree table if P3==0 and to a BTree index
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
pCx->pIncrKey = &pCx->bogusIncrKey;
}
}
+ pCx->nField = pOp->p2;
pCx->isIndex = !pCx->isTable;
break;
}
break;
}
+
+/* Opcode: Sort P1 P2 *
+**
+** This opcode does exactly the same thing as OP_Rewind except that
+** it increments an undocumented global variable used for testing.
+**
+** Sorting is accomplished by writing records into a sorting index,
+** then rewinding that index and playing it back from beginning to
+** end. We use the OP_Sort opcode instead of OP_Rewind to do the
+** rewinding so that the global variable will be incremented and
+** regression tests can determine whether or not the optimizer is
+** correctly optimizing out sorts.
+*/
+case OP_Sort: { /* no-push */
+ sqlite3_sort_count++;
+ /* Fall through into OP_Rewind */
+}
/* Opcode: Rewind P1 P2 *
**
** The next use of the Rowid or Column or Next instruction for P1
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
-/* Opcode: SortInsert * * *
-**
-** The TOS is the key and the NOS is the data. Pop both from the stack
-** and put them on the sorter. The key and data should have been
-** made using the MakeRecord opcode.
-*/
-case OP_SortInsert: { /* no-push */
- Mem *pNos = &pTos[-1];
- Sorter *pSorter;
- assert( pNos>=p->aStack );
- if( Dynamicify(pTos, db->enc) ) goto no_mem;
- pSorter = sqliteMallocRaw( sizeof(Sorter) );
- if( pSorter==0 ) goto no_mem;
- pSorter->pNext = 0;
- if( p->pSortTail ){
- p->pSortTail->pNext = pSorter;
- }else{
- p->pSort = pSorter;
- }
- p->pSortTail = pSorter;
- assert( pTos->flags & MEM_Dyn );
- pSorter->nKey = pTos->n;
- pSorter->zKey = pTos->z;
- pSorter->data.flags = MEM_Null;
- rc = sqlite3VdbeMemMove(&pSorter->data, pNos);
- pTos -= 2;
- break;
-}
-
-/* Opcode: Sort * * P3
-**
-** Sort all elements on the sorter. The algorithm is a
-** mergesort. The P3 argument is a pointer to a KeyInfo structure
-** that describes the keys to be sorted.
-*/
-case OP_Sort: { /* no-push */
- int i;
- KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
- Sorter *pElem;
- Sorter *apSorter[NSORT];
- sqlite3_sort_count++;
- pKeyInfo->enc = p->db->enc;
- for(i=0; i<NSORT; i++){
- apSorter[i] = 0;
- }
- while( p->pSort ){
- pElem = p->pSort;
- p->pSort = pElem->pNext;
- pElem->pNext = 0;
- for(i=0; i<NSORT-1; i++){
- if( apSorter[i]==0 ){
- apSorter[i] = pElem;
- break;
- }else{
- pElem = Merge(apSorter[i], pElem, pKeyInfo);
- apSorter[i] = 0;
- }
- }
- if( i>=NSORT-1 ){
- apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem, pKeyInfo);
- }
- }
- pElem = 0;
- for(i=0; i<NSORT; i++){
- pElem = Merge(apSorter[i], pElem, pKeyInfo);
- }
- p->pSort = pElem;
- break;
-}
-
-/* Opcode: SortNext * P2 *
-**
-** Push the data for the topmost element in the sorter onto the
-** stack, then remove the element from the sorter. If the sorter
-** is empty, push nothing on the stack and instead jump immediately
-** to instruction P2.
-*/
-case OP_SortNext: {
- Sorter *pSorter = p->pSort;
- CHECK_FOR_INTERRUPT;
- if( pSorter!=0 ){
- p->pSort = pSorter->pNext;
- pTos++;
- pTos->flags = MEM_Null;
- rc = sqlite3VdbeMemMove(pTos, &pSorter->data);
- sqliteFree(pSorter->zKey);
- sqliteFree(pSorter);
- }else{
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: SortReset * * *
-**
-** Remove any elements that remain on the sorter.
-*/
-case OP_SortReset: { /* no-push */
- sqlite3VdbeSorterReset(p);
- break;
-}
-
/* Opcode: MemStore P1 P2 *
**
** Write the top of the stack into memory location P1.