summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/select.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/select.c1086
1 files changed, 677 insertions, 409 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/select.c b/ext/pdo_sqlite/sqlite/src/select.c
index a4eb3fca4a..8a51208d79 100644
--- a/ext/pdo_sqlite/sqlite/src/select.c
+++ b/ext/pdo_sqlite/sqlite/src/select.c
@@ -60,6 +60,9 @@ Select *sqlite3SelectNew(
pNew->pOffset = pOffset;
pNew->iLimit = -1;
pNew->iOffset = -1;
+ pNew->addrOpenVirt[0] = -1;
+ pNew->addrOpenVirt[1] = -1;
+ pNew->addrOpenVirt[2] = -1;
}
return pNew;
}
@@ -70,6 +73,7 @@ Select *sqlite3SelectNew(
** in terms of the following bit values:
**
** JT_INNER
+** JT_CROSS
** JT_OUTER
** JT_NATURAL
** JT_LEFT
@@ -95,7 +99,7 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
{ "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER },
{ "outer", 5, JT_OUTER },
{ "inner", 5, JT_INNER },
- { "cross", 5, JT_INNER },
+ { "cross", 5, JT_INNER|JT_CROSS },
};
int i, j;
apAll[0] = pA;
@@ -175,6 +179,7 @@ static void addWhereTerm(
const char *zAlias1, /* Alias for first table. May be NULL */
const Table *pTab2, /* Second table */
const char *zAlias2, /* Alias for second table. May be NULL */
+ int iRightJoinTable, /* VDBE cursor for the right table */
Expr **ppExpr /* Add the equality term to this expression */
){
Expr *pE1a, *pE1b, *pE1c;
@@ -195,11 +200,14 @@ static void addWhereTerm(
pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
ExprSetProperty(pE, EP_FromJoin);
+ pE->iRightJoinTable = iRightJoinTable;
*ppExpr = sqlite3ExprAnd(*ppExpr, pE);
}
/*
** Set the EP_FromJoin property on all terms of the given expression.
+** And set the Expr.iRightJoinTable to iTable for every term in the
+** expression.
**
** The EP_FromJoin property is used on terms of an expression to tell
** the LEFT OUTER JOIN processing logic that this term is part of the
@@ -207,11 +215,26 @@ static void addWhereTerm(
** of the more general WHERE clause. These terms are moved over to the
** WHERE clause during join processing but we need to remember that they
** originated in the ON or USING clause.
+**
+** The Expr.iRightJoinTable tells the WHERE clause processing that the
+** expression depends on table iRightJoinTable even if that table is not
+** explicitly mentioned in the expression. That information is needed
+** for cases like this:
+**
+** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5
+**
+** The where clause needs to defer the handling of the t1.x=5
+** term until after the t2 loop of the join. In that way, a
+** NULL t2 row will be inserted whenever t1.x!=5. If we do not
+** defer the handling of t1.x=5, it will be processed immediately
+** after the t1 loop and rows with t1.x!=5 will never appear in
+** the output, which is incorrect.
*/
-static void setJoinExpr(Expr *p){
+static void setJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
- setJoinExpr(p->pLeft);
+ p->iRightJoinTable = iTable;
+ setJoinExpr(p->pLeft, iTable);
p = p->pRight;
}
}
@@ -258,7 +281,9 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
char *zName = pLeftTab->aCol[j].zName;
if( columnIndex(pRightTab, zName)>=0 ){
addWhereTerm(zName, pLeftTab, pLeft->zAlias,
- pRightTab, pRight->zAlias, &p->pWhere);
+ pRightTab, pRight->zAlias,
+ pRight->iCursor, &p->pWhere);
+
}
}
}
@@ -275,7 +300,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** an AND operator.
*/
if( pLeft->pOn ){
- setJoinExpr(pLeft->pOn);
+ setJoinExpr(pLeft->pOn, pRight->iCursor);
p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
pLeft->pOn = 0;
}
@@ -297,7 +322,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
return 1;
}
addWhereTerm(zName, pLeftTab, pLeft->zAlias,
- pRightTab, pRight->zAlias, &p->pWhere);
+ pRightTab, pRight->zAlias,
+ pRight->iCursor, &p->pWhere);
}
}
}
@@ -327,8 +353,10 @@ void sqlite3SelectDelete(Select *p){
*/
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_Sequence, pOrderBy->iECursor, 0);
+ sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0);
+ sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0);
+ sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0);
}
/*
@@ -341,7 +369,7 @@ static void codeLimiter(
int iBreak, /* Jump here to end the loop */
int nPop /* Number of times to pop stack when jumping */
){
- if( p->iOffset>=0 ){
+ if( p->iOffset>=0 && iContinue!=0 ){
int addr = sqlite3VdbeCurrentAddr(v) + 3;
if( nPop>0 ) addr++;
sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0);
@@ -352,13 +380,41 @@ static void codeLimiter(
sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
VdbeComment((v, "# skip OFFSET records"));
}
- if( p->iLimit>=0 ){
+ if( p->iLimit>=0 && iBreak!=0 ){
sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak);
VdbeComment((v, "# exit when LIMIT reached"));
}
}
/*
+** Add code that will check to make sure the top N elements of the
+** stack are distinct. iTab is a sorting index that holds previously
+** seen combinations of the N values. A new entry is made in iTab
+** if the current N values are new.
+**
+** A jump to addrRepeat is made and the K values are popped from the
+** stack if the top N elements are not distinct.
+*/
+static void codeDistinct(
+ Vdbe *v, /* Generate code into this VM */
+ int iTab, /* A sorting index used to test for distinctness */
+ int addrRepeat, /* Jump to here if not distinct */
+ int N, /* The top N elements of the stack must be distinct */
+ int K /* Pop K elements from the stack if indistinct */
+){
+#if NULL_ALWAYS_DISTINCT
+ sqlite3VdbeAddOp(v, OP_IsNull, -N, sqlite3VdbeCurrentAddr(v)+6);
+#endif
+ sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0);
+ sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
+ sqlite3VdbeAddOp(v, OP_Pop, K, 0);
+ sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat);
+ VdbeComment((v, "# skip indistinct records"));
+ sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0);
+}
+
+
+/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
@@ -413,30 +469,22 @@ static int selectInnerLoop(
*/
if( hasDistinct ){
int n = pEList->nExpr;
-#if NULL_ALWAYS_DISTINCT
- sqlite3VdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqlite3VdbeCurrentAddr(v)+7);
-#endif
- /* Deliberately leave the affinity string off of the following
- ** OP_MakeRecord */
- sqlite3VdbeAddOp(v, OP_MakeRecord, -n, 0);
- sqlite3VdbeAddOp(v, OP_Distinct, distinct, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, n+1, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
- VdbeComment((v, "# skip indistinct records"));
- sqlite3VdbeAddOp(v, OP_IdxInsert, distinct, 0);
+ codeDistinct(v, distinct, iContinue, n, n+1);
if( pOrderBy==0 ){
codeLimiter(v, p, iContinue, iBreak, nColumn);
}
}
switch( eDest ){
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* In this mode, write each query result to the key of the temporary
** table iParm.
*/
+#ifndef SQLITE_OMIT_COMPOUND_SELECT
case SRT_Union: {
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
- sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
+ if( aff ){
+ sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
+ }
sqlite3VdbeAddOp(v, OP_IdxInsert, iParm, 0);
break;
}
@@ -458,7 +506,7 @@ static int selectInnerLoop(
/* Store the result as data using a unique key.
*/
case SRT_Table:
- case SRT_TempTable: {
+ case SRT_VirtualTab: {
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
if( pOrderBy ){
pushOntoSorter(pParse, v, pOrderBy);
@@ -484,6 +532,10 @@ static int selectInnerLoop(
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
if( pOrderBy ){
+ /* At first glance you would think we could optimize out the
+ ** ORDER BY in this case since the order of entries in the set
+ ** does not matter. But there might be a LIMIT clause, in which
+ ** case the order does matter */
pushOntoSorter(pParse, v, pOrderBy);
}else{
char aff = (iParm>>16)&0xFF;
@@ -491,7 +543,7 @@ static int selectInnerLoop(
sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1);
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
}
- sqlite3VdbeChangeP2(v, addr2, sqlite3VdbeCurrentAddr(v));
+ sqlite3VdbeJumpHere(v, addr2);
break;
}
@@ -517,15 +569,13 @@ static int selectInnerLoop(
** popping the data from the stack.
*/
case SRT_Subroutine:
- case SRT_Callback:
- case SRT_Sorter: {
+ case SRT_Callback: {
if( pOrderBy ){
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
pushOntoSorter(pParse, v, pOrderBy);
}else if( eDest==SRT_Subroutine ){
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
}else{
- assert( eDest!=SRT_Sorter );
sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
}
break;
@@ -548,6 +598,48 @@ static int selectInnerLoop(
}
/*
+** 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
+** P3_KEYINFO_HANDOFF is the usual way of dealing with this.
+*/
+static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
+ sqlite3 *db = pParse->db;
+ int nExpr;
+ KeyInfo *pInfo;
+ struct ExprList_item *pItem;
+ int i;
+
+ nExpr = pList->nExpr;
+ pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
+ if( pInfo ){
+ pInfo->aSortOrder = (char*)&pInfo->aColl[nExpr];
+ pInfo->nField = nExpr;
+ pInfo->enc = db->enc;
+ for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
+ CollSeq *pColl;
+ pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
+ if( !pColl ){
+ pColl = db->pDfltColl;
+ }
+ pInfo->aColl[i] = pColl;
+ pInfo->aSortOrder[i] = pItem->sortOrder;
+ }
+ }
+ return pInfo;
+}
+
+
+/*
** If the inner loop was generated using a non-null pOrderBy argument,
** then the results were placed in a sorter. After the loop is terminated
** we need to run the sorter and output the results. The following
@@ -561,38 +653,19 @@ static void generateSortTail(
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;
- ExprList *pOrderBy;
- int nCol, i;
- sqlite3 *db = pParse->db;
+ int iTab;
+ ExprList *pOrderBy = p->pOrderBy;
- if( eDest==SRT_Sorter ) return;
- pOrderBy = p->pOrderBy;
- nCol = pOrderBy->nExpr;
- pInfo = sqliteMalloc( sizeof(*pInfo) + nCol*(sizeof(CollSeq*)+1) );
- if( pInfo==0 ) return;
- pInfo->aSortOrder = (char*)&pInfo->aColl[nCol];
- pInfo->nField = nCol;
- for(i=0; i<nCol; i++){
- /* If a collation sequence was specified explicity, then it
- ** is stored in pOrderBy->a[i].zName. Otherwise, use the default
- ** collation type for the expression.
- */
- pInfo->aColl[i] = sqlite3ExprCollSeq(pParse, pOrderBy->a[i].pExpr);
- if( !pInfo->aColl[i] ){
- pInfo->aColl[i] = db->pDfltColl;
- }
- pInfo->aSortOrder[i] = pOrderBy->a[i].sortOrder;
- }
- 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->iECursor;
+ addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
+ codeLimiter(v, p, cont, brk, 0);
+ sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
switch( eDest ){
case SRT_Table:
- case SRT_TempTable: {
+ case SRT_VirtualTab: {
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
@@ -612,7 +685,7 @@ static void generateSortTail(
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
@@ -637,11 +710,9 @@ static void generateSortTail(
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);
}
/*
@@ -1305,59 +1376,33 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
}
/*
-** 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.
+** Allocate a virtual index to use for sorting.
*/
-static int openVirtualIndex(Parse *pParse, Select *p, int iTab){
- KeyInfo *pKeyInfo;
- int nColumn;
- sqlite3 *db = pParse->db;
- int i;
- Vdbe *v = pParse->pVdbe;
- int addr;
-
- if( prepSelectStmt(pParse, p) ){
- return 0;
- }
- nColumn = p->pEList->nExpr;
- pKeyInfo = sqliteMalloc( sizeof(*pKeyInfo)+nColumn*sizeof(CollSeq*) );
- if( pKeyInfo==0 ) return 0;
- pKeyInfo->enc = db->enc;
- pKeyInfo->nField = nColumn;
- for(i=0; i<nColumn; i++){
- pKeyInfo->aColl[i] = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
- if( !pKeyInfo->aColl[i] ){
- pKeyInfo->aColl[i] = db->pDfltColl;
- }
+static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
+ if( pOrderBy ){
+ int addr;
+ assert( pOrderBy->iECursor==0 );
+ pOrderBy->iECursor = pParse->nTab++;
+ addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual,
+ pOrderBy->iECursor, pOrderBy->nExpr+1);
+ assert( p->addrOpenVirt[2] == -1 );
+ p->addrOpenVirt[2] = addr;
}
- 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.
+** The opcode at addr is an OP_OpenVirtual that created a sorting
+** index tha we ended up not needing. This routine changes that
+** opcode to OP_Noop.
*/
-static int multiSelectOpenVirtualAddr(Select *p, int addr){
- IdList *pList = *p->ppOpenVirtual = sqlite3IdListAppend(*p->ppOpenVirtual, 0);
- if( pList==0 ){
- return SQLITE_NOMEM;
- }
- pList->a[pList->nId-1].idx = addr;
- return SQLITE_OK;
+static void uncreateSortingIndex(Parse *pParse, int addr){
+ Vdbe *v = pParse->pVdbe;
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, addr);
+ sqlite3VdbeChangeP3(v, addr, 0, 0);
+ pOp->opcode = OP_Noop;
+ pOp->p1 = 0;
+ pOp->p2 = 0;
}
-#endif /* SQLITE_OMIT_COMPOUND_SELECT */
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
@@ -1423,10 +1468,10 @@ static int multiSelect(
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.
@@ -1436,6 +1481,8 @@ static int multiSelect(
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));
@@ -1457,32 +1504,21 @@ static int multiSelect(
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 ){
+ if( eDest==SRT_VirtualTab ){
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;
@@ -1510,11 +1546,10 @@ static int multiSelect(
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.
*/
@@ -1524,20 +1559,20 @@ static int multiSelect(
** 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 );
}
@@ -1557,8 +1592,8 @@ static int multiSelect(
case TK_ALL: op = SRT_Table; break;
}
p->pPrior = 0;
- pOrderBy = p->pOrderBy;
p->pOrderBy = 0;
+ p->disallowOrderBy = pOrderBy!=0;
pLimit = p->pLimit;
p->pLimit = 0;
pOffset = p->pOffset;
@@ -1591,7 +1626,7 @@ static int multiSelect(
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;
@@ -1616,18 +1651,16 @@ static int multiSelect(
*/
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".
@@ -1640,12 +1673,8 @@ static int multiSelect(
/* 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;
@@ -1674,7 +1703,7 @@ static int multiSelect(
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;
@@ -1703,9 +1732,8 @@ static int multiSelect(
/* 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
@@ -1718,12 +1746,15 @@ static int multiSelect(
** 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*) + nCol);
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
@@ -1732,46 +1763,62 @@ static int multiSelect(
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;
+ u8 *pSortOrder;
+
+ aCopy = (CollSeq**)&pKeyInfo[1];
+ pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nExpr];
+ memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
+ apColl = pKeyInfo->aColl;
+ for(i=0; i<pOrderBy->nExpr; i++, pOTerm++, apColl++, pSortOrder++){
+ 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];
}
+ *pSortOrder = pOTerm->sortOrder;
}
+ assert( p->pRightmost==p );
+ assert( p->addrOpenVirt[2]>=0 );
+ addr = p->addrOpenVirt[2];
+ sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
+ pKeyInfo->nField = pOrderBy->nExpr;
+ sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ pKeyInfo = 0;
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 */
@@ -1947,7 +1994,7 @@ static int flattenSubquery(
return 0;
}
if( p->isDistinct && subqueryIsAgg ) return 0;
- if( p->pOrderBy && pSub->pOrderBy ) return 0;
+ if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ) return 0;
/* Restriction 3: If the subquery is a join, make sure the subquery is
** not used as the right operand of an outer join. Examples of why this
@@ -2175,9 +2222,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
/* 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, 1);
+ if( eDest==SRT_VirtualTab ){
+ sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1);
}
/* Generating code to find the min or the max. Basically all we have
@@ -2286,6 +2332,7 @@ int sqlite3SelectResolve(
ExprList *pEList; /* Result set. */
int i; /* For-loop variable used in multiple places */
NameContext sNC; /* Local name-context */
+ ExprList *pGroupBy; /* The group by clause */
/* If this routine has run before, return immediately. */
if( p->isResolved ){
@@ -2329,18 +2376,6 @@ int sqlite3SelectResolve(
sNC.pSrcList = p->pSrc;
sNC.pNext = pOuterNC;
- /* NameContext.nDepth stores the depth of recursion for this query. For
- ** an outer query (e.g. SELECT * FROM sqlite_master) this is 1. For
- ** a subquery it is 2. For a subquery of a subquery, 3. And so on.
- ** Parse.nMaxDepth is the maximum depth for any subquery resolved so
- ** far. This is used to determine the number of aggregate contexts
- ** required at runtime.
- */
- sNC.nDepth = (pOuterNC?pOuterNC->nDepth+1:1);
- if( sNC.nDepth>pParse->nMaxDepth ){
- pParse->nMaxDepth = sNC.nDepth;
- }
-
/* Resolve names in the result set. */
pEList = p->pEList;
if( !pEList ) return SQLITE_ERROR;
@@ -2355,7 +2390,8 @@ int sqlite3SelectResolve(
** expression, do not allow aggregates in any of the other expressions.
*/
assert( !p->isAgg );
- if( p->pGroupBy || sNC.hasAgg ){
+ pGroupBy = p->pGroupBy;
+ if( pGroupBy || sNC.hasAgg ){
p->isAgg = 1;
}else{
sNC.allowAgg = 0;
@@ -2363,7 +2399,7 @@ int sqlite3SelectResolve(
/* If a HAVING clause is present, then there must be a GROUP BY clause.
*/
- if( p->pHaving && !p->pGroupBy ){
+ if( p->pHaving && !pGroupBy ){
sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
return SQLITE_ERROR;
}
@@ -2380,49 +2416,128 @@ int sqlite3SelectResolve(
if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
sqlite3ExprResolveNames(&sNC, p->pHaving) ||
processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
- processOrderGroupBy(&sNC, p->pGroupBy, "GROUP")
+ processOrderGroupBy(&sNC, pGroupBy, "GROUP")
){
return SQLITE_ERROR;
}
+ /* Make sure the GROUP BY clause does not contain aggregate functions.
+ */
+ if( pGroupBy ){
+ struct ExprList_item *pItem;
+
+ for(i=0, pItem=pGroupBy->a; i<pGroupBy->nExpr; i++, pItem++){
+ if( ExprHasProperty(pItem->pExpr, EP_Agg) ){
+ sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in "
+ "the GROUP BY clause");
+ return SQLITE_ERROR;
+ }
+ }
+ }
+
return SQLITE_OK;
}
/*
-** An instance of the following struct is used by sqlite3Select()
-** to save aggregate related information from the Parse object
-** at the start of each call and to restore it at the end. See
-** saveAggregateInfo() and restoreAggregateInfo().
-*/
-struct AggregateInfo {
- int nAgg;
- AggExpr *aAgg;
-};
-typedef struct AggregateInfo AggregateInfo;
-
-/*
-** Copy aggregate related information from the Parse structure
-** into the AggregateInfo structure. Zero the aggregate related
-** values in the Parse struct.
+** Reset the aggregate accumulator.
+**
+** The aggregate accumulator is a set of memory cells that hold
+** intermediate results while calculating an aggregate. This
+** routine simply stores NULLs in all of those memory cells.
+*/
+static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
+ Vdbe *v = pParse->pVdbe;
+ int i;
+ struct AggInfo_func *pFunc;
+ if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
+ return;
+ }
+ for(i=0; i<pAggInfo->nColumn; i++){
+ sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0);
+ }
+ for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
+ sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0);
+ if( pFunc->iDistinct>=0 ){
+ Expr *pE = pFunc->pExpr;
+ if( pE->pList==0 || pE->pList->nExpr!=1 ){
+ sqlite3ErrorMsg(pParse, "DISTINCT in aggregate must be followed "
+ "by an expression");
+ pFunc->iDistinct = -1;
+ }else{
+ KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
+ sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0,
+ (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ }
+ }
+ }
+}
+
+/*
+** Invoke the OP_AggFinalize opcode for every aggregate function
+** in the AggInfo structure.
*/
-static void saveAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
- pInfo->aAgg = pParse->aAgg;
- pInfo->nAgg = pParse->nAgg;
- pParse->aAgg = 0;
- pParse->nAgg = 0;
+static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
+ Vdbe *v = pParse->pVdbe;
+ int i;
+ struct AggInfo_func *pF;
+ for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
+ ExprList *pList = pF->pExpr->pList;
+ sqlite3VdbeOp3(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0,
+ (void*)pF->pFunc, P3_FUNCDEF);
+ }
}
/*
-** Copy aggregate related information from the AggregateInfo struct
-** back into the Parse structure. The aggregate related information
-** currently stored in the Parse structure is deleted.
+** Update the accumulator memory cells for an aggregate based on
+** the current cursor position.
*/
-static void restoreAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
- sqliteFree(pParse->aAgg);
- pParse->aAgg = pInfo->aAgg;
- pParse->nAgg = pInfo->nAgg;
+static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
+ Vdbe *v = pParse->pVdbe;
+ int i;
+ struct AggInfo_func *pF;
+ struct AggInfo_col *pC;
+
+ pAggInfo->directMode = 1;
+ for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
+ int nArg;
+ int addrNext = 0;
+ ExprList *pList = pF->pExpr->pList;
+ if( pList ){
+ nArg = pList->nExpr;
+ sqlite3ExprCodeExprList(pParse, pList);
+ }else{
+ nArg = 0;
+ }
+ if( pF->iDistinct>=0 ){
+ addrNext = sqlite3VdbeMakeLabel(v);
+ assert( nArg==1 );
+ codeDistinct(v, pF->iDistinct, addrNext, 1, 2);
+ }
+ if( pF->pFunc->needCollSeq ){
+ CollSeq *pColl = 0;
+ struct ExprList_item *pItem;
+ int j;
+ for(j=0, pItem=pList->a; !pColl && j<pList->nExpr; j++, pItem++){
+ pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
+ }
+ if( !pColl ){
+ pColl = pParse->db->pDfltColl;
+ }
+ sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
+ }
+ sqlite3VdbeOp3(v, OP_AggStep, pF->iMem, nArg, (void*)pF->pFunc, P3_FUNCDEF);
+ if( addrNext ){
+ sqlite3VdbeResolveLabel(v, addrNext);
+ }
+ }
+ for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
+ sqlite3ExprCode(pParse, pC->pExpr);
+ sqlite3VdbeAddOp(v, OP_MemStore, pC->iMem, 1);
+ }
+ pAggInfo->directMode = 0;
}
-
+
+
/*
** Generate code for the given SELECT statement.
**
@@ -2485,9 +2600,9 @@ int sqlite3Select(
int *pParentAgg, /* True if pParent uses aggregate functions */
char *aff /* If eDest is SRT_Union, the affinity string */
){
- int i;
- WhereInfo *pWInfo;
- Vdbe *v;
+ int i, j; /* Loop counters */
+ WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */
+ Vdbe *v; /* The virtual machine under construction */
int isAgg; /* True for select lists like "count(*)" */
ExprList *pEList; /* List of columns to extract. */
SrcList *pTabList; /* List of tables to select from */
@@ -2498,22 +2613,29 @@ int sqlite3Select(
int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */
- AggregateInfo sAggInfo;
+ int addrSortIndex; /* Address of an OP_OpenVirtual instruction */
+ AggInfo sAggInfo; /* Information used by aggregate queries */
if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1;
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
+ memset(&sAggInfo, 0, sizeof(sAggInfo));
#ifndef 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
- saveAggregateInfo(pParse, &sAggInfo);
pOrderBy = p->pOrderBy;
- if( eDest==SRT_Union || eDest==SRT_Except || eDest==SRT_Discard ){
+ if( IgnorableOrderby(eDest) ){
p->pOrderBy = 0;
}
if( sqlite3SelectResolve(pParse, p, 0) ){
@@ -2552,14 +2674,8 @@ int sqlite3Select(
/* ORDER BY is ignored for some destinations.
*/
- switch( eDest ){
- case SRT_Union:
- case SRT_Except:
- case SRT_Discard:
- pOrderBy = 0;
- break;
- default:
- break;
+ if( IgnorableOrderby(eDest) ){
+ pOrderBy = 0;
}
/* Begin generating code.
@@ -2580,23 +2696,24 @@ int sqlite3Select(
for(i=0; i<pTabList->nSrc; i++){
const char *zSavedAuthContext = 0;
int needRestoreContext;
+ struct SrcList_item *pItem = &pTabList->a[i];
- if( pTabList->a[i].pSelect==0 ) continue;
- if( pTabList->a[i].zName!=0 ){
+ if( pItem->pSelect==0 ) continue;
+ if( pItem->zName!=0 ){
zSavedAuthContext = pParse->zAuthContext;
- pParse->zAuthContext = pTabList->a[i].zName;
+ pParse->zAuthContext = pItem->zName;
needRestoreContext = 1;
}else{
needRestoreContext = 0;
}
- sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable,
- pTabList->a[i].iCursor, p, i, &isAgg, 0);
+ sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab,
+ pItem->iCursor, p, i, &isAgg, 0);
if( needRestoreContext ){
pParse->zAuthContext = zSavedAuthContext;
}
pTabList = p->pSrc;
pWhere = p->pWhere;
- if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){
+ if( !IgnorableOrderby(eDest) ){
pOrderBy = p->pOrderBy;
}
pGroupBy = p->pGroupBy;
@@ -2625,18 +2742,32 @@ int sqlite3Select(
#endif
/* If there is an ORDER BY clause, resolve any collation sequences
- ** names that have been explicitly specified.
+ ** names that have been explicitly specified and create a sorting index.
+ **
+ ** This sorting index might end up being unused if the data can be
+ ** extracted in pre-sorted order. If that is the case, then the
+ ** OP_OpenVirtual instruction will be changed to an OP_Noop once
+ ** we figure out that the sorting index is not needed. The addrSortIndex
+ ** variable is used to facilitate that change.
*/
if( pOrderBy ){
- for(i=0; i<pOrderBy->nExpr; i++){
- if( pOrderBy->a[i].zName ){
- pOrderBy->a[i].pExpr->pColl =
- sqlite3LocateCollSeq(pParse, pOrderBy->a[i].zName, -1);
+ struct ExprList_item *pTerm;
+ KeyInfo *pKeyInfo;
+ 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->iECursor = pParse->nTab++;
+ p->addrOpenVirt[2] = addrSortIndex =
+ sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2,
+ (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+ }else{
+ addrSortIndex = -1;
}
/* Set the limiter.
@@ -2645,184 +2776,320 @@ int sqlite3Select(
/* 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);
+ if( eDest==SRT_VirtualTab ){
+ sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
}
- /* Do an analysis of aggregate expressions.
- */
- if( isAgg || pGroupBy ){
- NameContext sNC;
- memset(&sNC, 0, sizeof(sNC));
- sNC.pParse = pParse;
- sNC.pSrcList = pTabList;
-
- assert( pParse->nAgg==0 );
- isAgg = 1;
- for(i=0; i<pEList->nExpr; i++){
- if( sqlite3ExprAnalyzeAggregates(&sNC, pEList->a[i].pExpr) ){
- goto select_end;
- }
- }
- if( pGroupBy ){
- for(i=0; i<pGroupBy->nExpr; i++){
- if( sqlite3ExprAnalyzeAggregates(&sNC, pGroupBy->a[i].pExpr) ){
- goto select_end;
- }
- }
- }
- if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
- goto select_end;
- }
- if( pOrderBy ){
- for(i=0; i<pOrderBy->nExpr; i++){
- if( sqlite3ExprAnalyzeAggregates(&sNC, pOrderBy->a[i].pExpr) ){
- goto select_end;
- }
- }
- }
- }
-
- /* Reset the aggregator
- */
- if( isAgg ){
- int addr = sqlite3VdbeAddOp(v, OP_AggReset, (pGroupBy?0:1), pParse->nAgg);
- for(i=0; i<pParse->nAgg; i++){
- FuncDef *pFunc;
- if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
- int nExpr = 0;
-#ifdef SQLITE_SSE
- Expr *pAggExpr = pParse->aAgg[i].pExpr;
- if( pAggExpr && pAggExpr->pList ){
- nExpr = pAggExpr->pList->nExpr;
- }
-#endif
- sqlite3VdbeOp3(v, OP_AggInit, nExpr, i, (char*)pFunc, P3_FUNCDEF);
- }
- }
- if( pGroupBy ){
- int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*);
- KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz);
- if( 0==pKey ){
- goto select_end;
- }
- pKey->enc = pParse->db->enc;
- pKey->nField = pGroupBy->nExpr;
- for(i=0; i<pGroupBy->nExpr; i++){
- pKey->aColl[i] = sqlite3ExprCollSeq(pParse, pGroupBy->a[i].pExpr);
- if( !pKey->aColl[i] ){
- pKey->aColl[i] = pParse->db->pDfltColl;
- }
- }
- sqlite3VdbeChangeP3(v, addr, (char *)pKey, P3_KEYINFO_HANDOFF);
- }
- }
/* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists
*/
- if( eDest==SRT_Mem || eDest==SRT_Exists ){
- sqlite3VdbeAddOp(v, eDest==SRT_Mem ? OP_Null : OP_Integer, 0, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
+ if( eDest==SRT_Mem ){
+ sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0);
+ }else if( eDest==SRT_Exists ){
+ sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm);
}
- /* Open a temporary table to use for the distinct set.
+ /* 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;
}
- /* Begin the database scan
- */
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,
- pGroupBy ? 0 : &pOrderBy);
- if( pWInfo==0 ) goto select_end;
+ /* Aggregate and non-aggregate queries are handled differently */
+ if( !isAgg && pGroupBy==0 ){
+ /* This case is for non-aggregate queries
+ ** Begin the database scan
+ */
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy);
+ if( pWInfo==0 ) goto select_end;
- /* Use the standard inner loop if we are not dealing with
- ** aggregates
- */
- if( !isAgg ){
+ /* If sorting index that was created by a prior OP_OpenVirtual
+ ** instruction ended up not being needed, then change the OP_OpenVirtual
+ ** into an OP_Noop.
+ */
+ if( addrSortIndex>=0 && pOrderBy==0 ){
+ uncreateSortingIndex(pParse, addrSortIndex);
+ p->addrOpenVirt[2] = -1;
+ }
+
+ /* Use the standard inner loop
+ */
if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
iParm, pWInfo->iContinue, pWInfo->iBreak, aff) ){
goto select_end;
}
- }
- /* If we are dealing with aggregates, then do the special aggregate
- ** processing.
- */
- else{
- AggExpr *pAgg;
- int lbl1 = 0;
- pParse->fillAgg = 1;
+ /* End the database scan loop.
+ */
+ sqlite3WhereEnd(pWInfo);
+ }else{
+ /* This is the processing for aggregate queries */
+ NameContext sNC; /* Name context for processing aggregate information */
+ int iAMem; /* First Mem address for storing current GROUP BY */
+ int iBMem; /* First Mem address for previous GROUP BY */
+ int iUseFlag; /* Mem address holding flag indicating that at least
+ ** one row of the input to the aggregator has been
+ ** processed */
+ int iAbortFlag; /* Mem address which causes query abort if positive */
+ int groupBySort; /* Rows come from source in GROUP BY order */
+
+
+ /* The following variables hold addresses or labels for parts of the
+ ** virtual machine program we are putting together */
+ int addrOutputRow; /* Start of subroutine that outputs a result row */
+ int addrSetAbort; /* Set the abort flag and return */
+ int addrInitializeLoop; /* Start of code that initializes the input loop */
+ int addrTopOfLoop; /* Top of the input loop */
+ int addrGroupByChange; /* Code that runs when any GROUP BY term changes */
+ int addrProcessRow; /* Code to process a single input row */
+ int addrEnd; /* End of all processing */
+ int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */
+ int addrReset; /* Subroutine for resetting the accumulator */
+
+ addrEnd = sqlite3VdbeMakeLabel(v);
+
+ /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
+ ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
+ ** SELECT statement.
+ */
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
+ sNC.pSrcList = pTabList;
+ sNC.pAggInfo = &sAggInfo;
+ sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
+ sAggInfo.pGroupBy = pGroupBy;
+ if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){
+ goto select_end;
+ }
+ if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){
+ goto select_end;
+ }
+ if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){
+ goto select_end;
+ }
+ sAggInfo.nAccumulator = sAggInfo.nColumn;
+ for(i=0; i<sAggInfo.nFunc; i++){
+ if( sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList) ){
+ goto select_end;
+ }
+ }
+ if( sqlite3_malloc_failed ) goto select_end;
+
+ /* Processing for aggregates with GROUP BY is very different and
+ ** much more complex tha aggregates without a GROUP BY.
+ */
if( pGroupBy ){
- sqlite3ExprCodeExprList(pParse, pGroupBy);
- /* No affinity string is attached to the following OP_MakeRecord
- ** because we do not need to do any coercion of datatypes. */
- sqlite3VdbeAddOp(v, OP_MakeRecord, pGroupBy->nExpr, 0);
- lbl1 = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1);
- }
- for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
- if( pAgg->isAgg ) continue;
- sqlite3ExprCode(pParse, pAgg->pExpr);
- sqlite3VdbeAddOp(v, OP_AggSet, 0, i);
- }
- pParse->fillAgg = 0;
- if( lbl1<0 ){
- sqlite3VdbeResolveLabel(v, lbl1);
- }
- for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
- Expr *pE;
- int nExpr;
- FuncDef *pDef;
- if( !pAgg->isAgg ) continue;
- assert( pAgg->pFunc!=0 );
- assert( pAgg->pFunc->xStep!=0 );
- pDef = pAgg->pFunc;
- pE = pAgg->pExpr;
- assert( pE!=0 );
- assert( pE->op==TK_AGG_FUNCTION );
- nExpr = sqlite3ExprCodeExprList(pParse, pE->pList);
- sqlite3VdbeAddOp(v, OP_Integer, i, 0);
- if( pDef->needCollSeq ){
- CollSeq *pColl = 0;
- int j;
- for(j=0; !pColl && j<nExpr; j++){
- pColl = sqlite3ExprCollSeq(pParse, pE->pList->a[j].pExpr);
+ KeyInfo *pKeyInfo; /* Keying information for the group by clause */
+
+ /* Create labels that we will be needing
+ */
+
+ addrInitializeLoop = sqlite3VdbeMakeLabel(v);
+ addrGroupByChange = sqlite3VdbeMakeLabel(v);
+ addrProcessRow = sqlite3VdbeMakeLabel(v);
+
+ /* If there is a GROUP BY clause we might need a sorting index to
+ ** implement it. Allocate that sorting index now. If it turns out
+ ** that we do not need it after all, the OpenVirtual instruction
+ ** will be converted into a Noop.
+ */
+ sAggInfo.sortingIdx = pParse->nTab++;
+ pKeyInfo = keyInfoFromExprList(pParse, pGroupBy);
+ addrSortingIdx =
+ sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx,
+ sAggInfo.nSortingColumn,
+ (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+
+ /* Initialize memory locations used by GROUP BY aggregate processing
+ */
+ iUseFlag = pParse->nMem++;
+ iAbortFlag = pParse->nMem++;
+ iAMem = pParse->nMem;
+ pParse->nMem += pGroupBy->nExpr;
+ iBMem = pParse->nMem;
+ pParse->nMem += pGroupBy->nExpr;
+ sqlite3VdbeAddOp(v, OP_MemInt, 0, iAbortFlag);
+ VdbeComment((v, "# clear abort flag"));
+ sqlite3VdbeAddOp(v, OP_MemInt, 0, iUseFlag);
+ VdbeComment((v, "# indicate accumulator empty"));
+ sqlite3VdbeAddOp(v, OP_Goto, 0, addrInitializeLoop);
+
+ /* Generate a subroutine that outputs a single row of the result
+ ** set. This subroutine first looks at the iUseFlag. If iUseFlag
+ ** is less than or equal to zero, the subroutine is a no-op. If
+ ** the processing calls for the query to abort, this subroutine
+ ** increments the iAbortFlag memory location before returning in
+ ** order to signal the caller to abort.
+ */
+ addrSetAbort = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp(v, OP_MemInt, 1, iAbortFlag);
+ VdbeComment((v, "# set abort flag"));
+ sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ addrOutputRow = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp(v, OP_IfMemPos, iUseFlag, addrOutputRow+2);
+ VdbeComment((v, "# Groupby result generator entry point"));
+ sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ finalizeAggFunctions(pParse, &sAggInfo);
+ if( pHaving ){
+ sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, 1);
+ }
+ rc = selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
+ distinct, eDest, iParm,
+ addrOutputRow+1, addrSetAbort, aff);
+ if( rc ){
+ goto select_end;
+ }
+ sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+ VdbeComment((v, "# end groupby result generator"));
+
+ /* Generate a subroutine that will reset the group-by accumulator
+ */
+ addrReset = sqlite3VdbeCurrentAddr(v);
+ resetAccumulator(pParse, &sAggInfo);
+ sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+
+ /* Begin a loop that will extract all source rows in GROUP BY order.
+ ** This might involve two separate loops with an OP_Sort in between, or
+ ** it might be a single loop that uses an index to extract information
+ ** in the right order to begin with.
+ */
+ sqlite3VdbeResolveLabel(v, addrInitializeLoop);
+ sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy);
+ if( pWInfo==0 ) goto select_end;
+ if( pGroupBy==0 ){
+ /* The optimizer is able to deliver rows in group by order so
+ ** we do not have to sort. The OP_OpenVirtual table will be
+ ** cancelled later because we still need to use the pKeyInfo
+ */
+ pGroupBy = p->pGroupBy;
+ groupBySort = 0;
+ }else{
+ /* Rows are coming out in undetermined order. We have to push
+ ** each row into a sorting index, terminate the first loop,
+ ** then loop over the sorting index in order to get the output
+ ** in sorted order
+ */
+ groupBySort = 1;
+ sqlite3ExprCodeExprList(pParse, pGroupBy);
+ sqlite3VdbeAddOp(v, OP_Sequence, sAggInfo.sortingIdx, 0);
+ j = pGroupBy->nExpr+1;
+ for(i=0; i<sAggInfo.nColumn; i++){
+ struct AggInfo_col *pCol = &sAggInfo.aCol[i];
+ if( pCol->iSorterColumn<j ) continue;
+ if( pCol->iColumn<0 ){
+ sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0);
+ }else{
+ sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn);
+ }
+ j++;
}
- if( !pColl ) pColl = pParse->db->pDfltColl;
- sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
+ sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0);
+ sqlite3VdbeAddOp(v, OP_IdxInsert, sAggInfo.sortingIdx, 0);
+ sqlite3WhereEnd(pWInfo);
+ sqlite3VdbeAddOp(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
+ VdbeComment((v, "# GROUP BY sort"));
+ sAggInfo.useSortingIdx = 1;
}
- sqlite3VdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_FUNCDEF);
- }
- }
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
+ /* Evaluate the current GROUP BY terms and store in b0, b1, b2...
+ ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
+ ** Then compare the current GROUP BY terms against the GROUP BY terms
+ ** from the previous row currently stored in a0, a1, a2...
+ */
+ addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
+ for(j=0; j<pGroupBy->nExpr; j++){
+ if( groupBySort ){
+ sqlite3VdbeAddOp(v, OP_Column, sAggInfo.sortingIdx, j);
+ }else{
+ sAggInfo.directMode = 1;
+ sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr);
+ }
+ sqlite3VdbeAddOp(v, OP_MemStore, iBMem+j, j<pGroupBy->nExpr-1);
+ }
+ for(j=pGroupBy->nExpr-1; j>=0; j--){
+ if( j<pGroupBy->nExpr-1 ){
+ sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0);
+ }
+ sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0);
+ if( j==0 ){
+ sqlite3VdbeAddOp(v, OP_Eq, 0x200, addrProcessRow);
+ }else{
+ sqlite3VdbeAddOp(v, OP_Ne, 0x200, addrGroupByChange);
+ }
+ sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ);
+ }
- /* If we are processing aggregates, we need to set up a second loop
- ** over all of the aggregate values and process them.
- */
- if( isAgg ){
- int endagg = sqlite3VdbeMakeLabel(v);
- int startagg;
- startagg = sqlite3VdbeAddOp(v, OP_AggNext, 0, endagg);
- if( pHaving ){
- sqlite3ExprIfFalse(pParse, pHaving, startagg, 1);
- }
- if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest,
- iParm, startagg, endagg, aff) ){
- goto select_end;
+ /* Generate code that runs whenever the GROUP BY changes.
+ ** Change in the GROUP BY are detected by the previous code
+ ** block. If there were no changes, this block is skipped.
+ **
+ ** This code copies current group by terms in b0,b1,b2,...
+ ** over to a0,a1,a2. It then calls the output subroutine
+ ** and resets the aggregate accumulator registers in preparation
+ ** for the next GROUP BY batch.
+ */
+ sqlite3VdbeResolveLabel(v, addrGroupByChange);
+ for(j=0; j<pGroupBy->nExpr; j++){
+ sqlite3VdbeAddOp(v, OP_MemMove, iAMem+j, iBMem+j);
+ }
+ sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
+ VdbeComment((v, "# output one row"));
+ sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd);
+ VdbeComment((v, "# check abort flag"));
+ sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
+ VdbeComment((v, "# reset accumulator"));
+
+ /* Update the aggregate accumulators based on the content of
+ ** the current row
+ */
+ sqlite3VdbeResolveLabel(v, addrProcessRow);
+ updateAccumulator(pParse, &sAggInfo);
+ sqlite3VdbeAddOp(v, OP_MemInt, 1, iUseFlag);
+ VdbeComment((v, "# indicate data in accumulator"));
+
+ /* End of the loop
+ */
+ if( groupBySort ){
+ sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop);
+ }else{
+ sqlite3WhereEnd(pWInfo);
+ uncreateSortingIndex(pParse, addrSortingIdx);
+ }
+
+ /* Output the final row of result
+ */
+ sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
+ VdbeComment((v, "# output final row"));
+
+ } /* endif pGroupBy */
+ else {
+ /* This case runs if the aggregate has no GROUP BY clause. The
+ ** processing is much simpler since there is only a single row
+ ** of output.
+ */
+ resetAccumulator(pParse, &sAggInfo);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
+ if( pWInfo==0 ) goto select_end;
+ updateAccumulator(pParse, &sAggInfo);
+ sqlite3WhereEnd(pWInfo);
+ finalizeAggFunctions(pParse, &sAggInfo);
+ pOrderBy = 0;
+ if( pHaving ){
+ sqlite3ExprIfFalse(pParse, pHaving, addrEnd, 1);
+ }
+ selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
+ eDest, iParm, addrEnd, addrEnd, aff);
}
- sqlite3VdbeAddOp(v, OP_Goto, 0, startagg);
- sqlite3VdbeResolveLabel(v, endagg);
- sqlite3VdbeAddOp(v, OP_Noop, 0, 0);
- }
+ sqlite3VdbeResolveLabel(v, addrEnd);
+
+ } /* endif aggregate query */
/* If there is an ORDER BY clause, then we need to sort the results
** and send them to the callback one by one.
@@ -2854,6 +3121,7 @@ int sqlite3Select(
** successful coding of the SELECT.
*/
select_end:
- restoreAggregateInfo(pParse, &sAggInfo);
+ sqliteFree(sAggInfo.aCol);
+ sqliteFree(sAggInfo.aFunc);
return rc;
}