diff --git a/manifest b/manifest index a5ff70bff9..cf457f8a60 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\sto\sreduce\sthe\samount\sof\sstack\sspace\srequired.\s(CVS\s2661) -D 2005-09-06T21:40:45 +C Rewrite\sthe\saggregate\shandling\slogic\sso\sthat\sit\sruns\sin\sO(1)\sspace.\nThis\sis\sthe\sfirst\scut\sat\sthe\scode.\s\sMany\sregression\stests\sfail.\s(CVS\s2662) +D 2005-09-07T21:22:46 F Makefile.in 12784cdce5ffc8dfb707300c34e4f1eb3b8a14f1 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -34,19 +34,19 @@ F src/attach.c 4b21689700a72ae281fa85dbaff06b2a62bd49ee F src/auth.c 31e2304bef67f44d635655f44234387ea7d21454 F src/btree.c 5b3bc015c49a41c025cfdf8ad36051f3007e2cb0 F src/btree.h 1ed561263ca0e335bc3e81d761c9d5ff8c22f61e -F src/build.c d61682e8d0368fbc6ff230cd4b9bd41659d5634b +F src/build.c d9f3c0e65ada1087da21b524f6ef685e4d1a1725 F src/callback.c 9a1162c8f9dae9fad6d548339669aacb5f6cf76b F src/complete.c 4de937dfdd4c79a501772ab2035b26082f337a79 F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940 F src/delete.c be1fc25c9e109cd8cbab42a43ee696263da7c04b F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d -F src/expr.c 8a72157fa6842e84819a8c80521be02ec471180c +F src/expr.c e0a3f275586bb076cc5995885a328b531b5aecf2 F src/func.c 713cf33a0ab8685d44ed31a9c753983a7ff9fd6e F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c 484c73bc1309f283a31baa0e114f3ee980536397 F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b -F src/main.c 8bcd1d2ed92dcb24bafb770eae6e4afce8ddcbde +F src/main.c bf88855445d365b497070d85e3faa0579a9edb91 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/os.h c4b34bd4d6fea51a420f337468b907f4edecb161 F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73 @@ -58,15 +58,15 @@ F src/os_win.c 4aad6cd49a2a546f945491a9e6a0b7d061cf47c5 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c cd9896287a8fd33cc267bd0c2b69c421a4808169 F src/pager.h 17b13225abd93c1e9f470060f40a21b9edb5a164 -F src/parse.y d57cdd2adc0923762b40314f08683c836a2e0c90 +F src/parse.y 4c0cf6b0646166b232693249b89e32a75c6f87d7 F src/pragma.c 69413fbdc0c6aaa493a776ea52c1b3e6cf35dfb2 F src/prepare.c 86f0d8e744b8d956eff6bc40e29049efee017610 F src/printf.c c01e9ad473d79463fb1f483b1eca5c3cbed2a4e5 F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4 -F src/select.c 79bd7f97345ee4291e7f4d469307b185eb2cba8f +F src/select.c 2f965220652f5417a70720ea3bf7703bf432fb6b F src/shell.c b21daba017b8feef2fdc65ecde57f70209494217 F src/sqlite.h.in d6561d51025d08de4f455607f3f9f9aa76e855d5 -F src/sqliteInt.h 845ff6f8019f80baafb1bdbb8ef80fcd04d9d0f9 +F src/sqliteInt.h 97d7d13bfcccd67974b0db9c19fce4428ae9d236 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c ac94682f9e601dd373912c46414a5a842db2089a F src/test1.c b569b60e35f0e3ea20e5ebfaf6e522a01c08d481 @@ -80,13 +80,13 @@ F src/update.c a9d2c5f504212d62da1b094476f1389c0e02f83f F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c F src/util.c 5650f6fe5ee30e0678985ad7b94da91e3f85752b F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c -F src/vdbe.c 5f0ed87252912fa1d4c989b0c6d7e3d4d2bb337a -F src/vdbe.h 3b29a9af6c7a64ed692bef1fc5f61338f40d2f67 -F src/vdbeInt.h 7a6b3c1adfa7b23c1f4f15ce0549b5b52a85a635 +F src/vdbe.c e774761b4566540e0007ec3d6ff24ed7a89f51c9 +F src/vdbe.h c8e105979fc7aaf5b8004e9621904e3bd096dfa2 +F src/vdbeInt.h 15a32128a8173c724a90829b90af495b370c09cc F src/vdbeapi.c 46e2fd47e2ce3c1aea9bb48bbbac31a1dc75a6ff -F src/vdbeaux.c 2cfc66b30be5e293bd72db8084f8cb5c865e8b01 +F src/vdbeaux.c 11db0de973c850bb5d92c67af1c8f3c189f08741 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 -F src/vdbemem.c b6ae3ac842a6759bd8ec4eb1cd428520b5eafc57 +F src/vdbemem.c 3cb63f021ac5ed102d80ec888d6f76fc0dcac153 F src/where.c 92ab208abe6bec15e81616b8c1a619be23ece506 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 @@ -178,7 +178,7 @@ F test/minmax.test 9429a06f1f93acf76fcacafd17160a4392e88526 F test/misc1.test 4ca69ca2e2ef33c7a0b0fc8b324111e37a522d29 F test/misc2.test 5c699af2fede2694736a9f45aea7e2f052686e15 F test/misc3.test 7bd937e2c62bcc6be71939faf068d506467b1e03 -F test/misc4.test edd3e3adf5b6e3b995b29843565ca58dd602f9a7 +F test/misc4.test 8a28f046bac8121dc2fe623ccb75578cd51b9db0 F test/misc5.test 24bd03404039ec727028ac9cf7fd9066fd209ec9 F test/misuse.test 1c7fee3c4c0cb4008717ecccf5c72281fac0008e F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0 @@ -306,7 +306,7 @@ F www/tclsqlite.tcl 3df553505b6efcad08f91e9b975deb2e6c9bb955 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 7ecf3654aa9a275a4cf0c3ec5f63a8c1e0a11fc9 -R a30f5538e6a4b7f1c84ee615fff6a374 +P b86bd70f301205d6ca66475a425e157b976107e2 +R 47d4cda0a17a577f38d2fea59c44e4f5 U drh -Z 6a9878dbd0fbab628ba267b019a75820 +Z e6ce677b69437ad913acfe1b1ebf26c2 diff --git a/manifest.uuid b/manifest.uuid index ad534eb1d1..f90b49b398 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b86bd70f301205d6ca66475a425e157b976107e2 \ No newline at end of file +17039ec3ff4396862beedf4a8af89654b2140f58 \ No newline at end of file diff --git a/src/build.c b/src/build.c index fc4a0311f5..b2be37aab5 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.344 2005/08/31 13:13:31 drh Exp $ +** $Id: build.c,v 1.345 2005/09/07 21:22:46 drh Exp $ */ #include "sqliteInt.h" #include @@ -103,7 +103,7 @@ void sqlite3FinishCoding(Parse *pParse){ FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace); sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3, - pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain); + pParse->nTab+3, pParse->explain); pParse->rc = SQLITE_DONE; pParse->colNamesSet = 0; }else if( pParse->rc==SQLITE_OK ){ @@ -2469,6 +2469,45 @@ exit_drop_index: sqlite3SrcListDelete(pName); } +/* +** ppArray points into a structure where there is an array pointer +** followed by two integers. The first integer is the +** number of elements in the structure array. The second integer +** is the number of allocated slots in the array. +** +** In other words, the structure looks something like this: +** +** struct Example1 { +** struct subElem *aEntry; +** int nEntry; +** int nAlloc; +** } +** +** The pnEntry parameter points to the equivalent of Example1.nEntry. +** +** This routine allocates a new slot in the array, zeros it out, +** and returns its index. If malloc fails a negative number is returned. +** +** szEntry is the sizeof of a single array entry. initSize is the +** number of array entries allocated on the initial allocation. +*/ +int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){ + char *p; + int *an = (int*)&ppArray[1]; + if( an[0]>=an[1] ){ + void *pNew; + an[1] = an[1]*2 + initSize; + pNew = sqliteRealloc(*ppArray, an[1]*szEntry); + if( pNew==0 ){ + return -1; + } + *ppArray = pNew; + } + p = *ppArray; + memset(&p[an[0]*szEntry], 0, szEntry); + return an[0]++; +} + /* ** Append a new element to the given IdList. Create a new IdList if ** need be. @@ -2476,24 +2515,18 @@ exit_drop_index: ** A new IdList is returned, or NULL if malloc() fails. */ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){ + int i; if( pList==0 ){ pList = sqliteMalloc( sizeof(IdList) ); if( pList==0 ) return 0; pList->nAlloc = 0; } - if( pList->nId>=pList->nAlloc ){ - struct IdList_item *a; - pList->nAlloc = pList->nAlloc*2 + 5; - a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) ); - if( a==0 ){ - sqlite3IdListDelete(pList); - return 0; - } - pList->a = a; + i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5); + if( i<0 ){ + sqlite3IdListDelete(pList); + return 0; } - memset(&pList->a[pList->nId], 0, sizeof(pList->a[0])); - pList->a[pList->nId].zName = sqlite3NameFromToken(pToken); - pList->nId++; + pList->a[i].zName = sqlite3NameFromToken(pToken); return pList; } diff --git a/src/expr.c b/src/expr.c index 7ac7a7ae46..ac37e507fc 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.224 2005/09/05 20:06:49 drh Exp $ +** $Id: expr.c,v 1.225 2005/09/07 21:22:46 drh Exp $ */ #include "sqliteInt.h" #include @@ -695,6 +695,7 @@ static int exprNodeIsConstant(void *pArg, Expr *pExpr){ case TK_COLUMN: case TK_DOT: case TK_AGG_FUNCTION: + case TK_AGG_COLUMN: #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS: @@ -1230,11 +1231,19 @@ int sqlite3ExprResolveNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ + int savedHasAgg; if( pExpr==0 ) return 0; + savedHasAgg = pNC->hasAgg; + pNC->hasAgg = 0; walkExprTree(pExpr, nameResolverStep, pNC); if( pNC->nErr>0 ){ ExprSetProperty(pExpr, EP_Error); } + if( pNC->hasAgg ){ + ExprSetProperty(pExpr, EP_Agg); + }else if( savedHasAgg ){ + pNC->hasAgg = 1; + } return ExprHasProperty(pExpr, EP_Error); } @@ -1287,10 +1296,6 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ sqlite3VdbeAddOp(v, OP_MemStore, mem, 1); } - if( pExpr->pSelect ){ - sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0); - } - switch( pExpr->op ){ case TK_IN: { char affinity; @@ -1403,9 +1408,6 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } } - if( pExpr->pSelect ){ - sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0); - } if( testAddr ){ sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v)); } @@ -1448,10 +1450,21 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ } op = pExpr->op; switch( op ){ + case TK_AGG_COLUMN: { + AggInfo *pAggInfo = pExpr->pAggInfo; + struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; + if( !pAggInfo->directMode ){ + sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0); + break; + }else if( pAggInfo->useSortingIdx ){ + sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx, + pCol->iSorterColumn); + break; + } + /* Otherwise, fall thru into the TK_COLUMN case */ + } case TK_COLUMN: { - if( !pParse->fillAgg && pExpr->iAgg>=0 ){ - sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg); - }else if( pExpr->iColumn>=0 ){ + if( pExpr->iColumn>=0 ){ sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn); sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn); }else{ @@ -1600,7 +1613,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ break; } case TK_AGG_FUNCTION: { - sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); + AggInfo *pInfo = pExpr->pAggInfo; + sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0); break; } case TK_CONST_FUNC: @@ -1610,7 +1624,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ FuncDef *pDef; int nId; const char *zId; - int p2 = 0; + int constMask = 0; int i; u8 enc = pParse->db->enc; CollSeq *pColl = 0; @@ -1621,7 +1635,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ nExpr = sqlite3ExprCodeExprList(pParse, pList); for(i=0; ia[i].pExpr) ){ - p2 |= (1<needCollSeq && !pColl ){ pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); @@ -1631,7 +1645,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ if( !pColl ) pColl = pParse->db->pDfltColl; sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); } - sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF); + sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF); break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -2047,23 +2061,32 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){ return 1; } + /* -** Add a new element to the pParse->aAgg[] array and return its index. -** The new element is initialized to zero. The calling function is -** expected to fill it in. +** Add a new element to the pAggInfo->aCol[] array. Return the index of +** the new element. Return a negative number if malloc fails. */ -static int appendAggInfo(Parse *pParse){ - if( (pParse->nAgg & 0x7)==0 ){ - int amt = pParse->nAgg + 8; - AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); - if( aAgg==0 ){ - return -1; - } - pParse->aAgg = aAgg; +static int addAggInfoColumn(AggInfo *pInfo){ + int i; + i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3); + if( i<0 ){ + return -1; } - memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0])); - return pParse->nAgg++; -} + return i; +} + +/* +** Add a new element to the pAggInfo->aFunc[] array. Return the index of +** the new element. Return a negative number if malloc fails. +*/ +static int addAggInfoFunc(AggInfo *pInfo){ + int i; + i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2); + if( i<0 ){ + return -1; + } + return i; +} /* ** This is an xFunc for walkExprTree() used to implement @@ -2074,63 +2097,112 @@ static int appendAggInfo(Parse *pParse){ */ static int analyzeAggregate(void *pArg, Expr *pExpr){ int i; - AggExpr *pAgg; NameContext *pNC = (NameContext *)pArg; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; + AggInfo *pAggInfo = pNC->pAggInfo; + switch( pExpr->op ){ case TK_COLUMN: { - for(i=0; pSrcList && inSrc; i++){ - if( pExpr->iTable==pSrcList->a[i].iCursor ){ - pAgg = pParse->aAgg; - for(i=0; inAgg; i++, pAgg++){ - Expr *pE; - if( pAgg->isAgg ) continue; - pE = pAgg->pExpr; - if( pE->iTable==pExpr->iTable && pE->iColumn==pExpr->iColumn ){ - break; + /* Check to see if the column is in one of the tables in the FROM + ** clause of the aggregate query */ + if( pSrcList ){ + struct SrcList_item *pItem = pSrcList->a; + for(i=0; inSrc; i++, pItem++){ + struct AggInfo_col *pCol; + if( pExpr->iTable==pItem->iCursor ){ + /* If we reach this point, it means that pExpr refers to a table + ** that is in the FROM clause of the aggregate query. + ** + ** Make an entry for the column in pAggInfo->aCol[] if there + ** is not an entry there already. + */ + pCol = pAggInfo->aCol; + for(i=0; inColumn; i++, pCol++){ + if( pCol->iTable==pExpr->iTable && + pCol->iColumn==pExpr->iColumn ){ + break; + } } - } - if( i>=pParse->nAgg ){ - i = appendAggInfo(pParse); - if( i<0 ) return 1; - pAgg = &pParse->aAgg[i]; - pAgg->isAgg = 0; - pAgg->pExpr = pExpr; - } - pExpr->iAgg = i; - pExpr->iAggCtx = pNC->nDepth; - return 1; - } + if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){ + pCol = &pAggInfo->aCol[i]; + pCol->iTable = pExpr->iTable; + pCol->iColumn = pExpr->iColumn; + pCol->iMem = pParse->nMem++; + pCol->iSorterColumn = -1; + if( pAggInfo->pGroupBy ){ + int j, n; + ExprList *pGB = pAggInfo->pGroupBy; + struct ExprList_item *pTerm = pGB->a; + n = pGB->nExpr; + for(j=0; jpExpr; + if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable && + pE->iColumn==pExpr->iColumn ){ + pCol->iSorterColumn = j; + break; + } + } + } + if( pCol->iSorterColumn<0 ){ + pCol->iSorterColumn = pAggInfo->nSortingColumn++; + } + } + /* There is now an entry for pExpr in pAggInfo->aCol[] (either + ** because it was there before or because we just created it). + ** Convert the pExpr to be a TK_AGG_COLUMN referring to that + ** pAggInfo->aCol[] entry. + */ + pExpr->pAggInfo = pAggInfo; + pExpr->op = TK_AGG_COLUMN; + pExpr->iAgg = i; + break; + } /* endif pExpr->iTable==pItem->iCursor */ + } /* end loop over pSrcList */ } return 1; } case TK_AGG_FUNCTION: { + /* The pNC->nDepth==0 test causes aggregate functions in subqueries + ** to be ignored */ if( pNC->nDepth==0 ){ - pAgg = pParse->aAgg; - for(i=0; inAgg; i++, pAgg++){ - if( !pAgg->isAgg ) continue; - if( sqlite3ExprCompare(pAgg->pExpr, pExpr) ){ + /* Check to see if pExpr is a duplicate of another aggregate + ** function that is already in the pAggInfo structure + */ + struct AggInfo_func *pItem = pAggInfo->aFunc; + for(i=0; inFunc; i++, pItem++){ + if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){ break; } } - if( i>=pParse->nAgg ){ + if( i>=pAggInfo->nFunc ){ + /* pExpr is original. Make a new entry in pAggInfo->aFunc[] + */ u8 enc = pParse->db->enc; - i = appendAggInfo(pParse); - if( i<0 ) return 1; - pAgg = &pParse->aAgg[i]; - pAgg->isAgg = 1; - pAgg->pExpr = pExpr; - pAgg->pFunc = sqlite3FindFunction(pParse->db, - pExpr->token.z, pExpr->token.n, - pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); + i = addAggInfoFunc(pAggInfo); + if( i>=0 ){ + pItem = &pAggInfo->aFunc[i]; + pItem->pExpr = pExpr; + pItem->iMem = pParse->nMem++; + pItem->pFunc = sqlite3FindFunction(pParse->db, + pExpr->token.z, pExpr->token.n, + pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); + } } + /* Make pExpr point to the appropriate pAggInfo->aFunc[] entry + */ pExpr->iAgg = i; + pExpr->pAggInfo = pAggInfo; return 1; } } } + + /* Recursively walk subqueries looking for TK_COLUMN nodes that need + ** to be changed to TK_AGG_COLUMN. But increment nDepth so that + ** TK_AGG_FUNCTION nodes in subqueries will be unchanged. + */ if( pExpr->pSelect ){ pNC->nDepth++; walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC); diff --git a/src/main.c b/src/main.c index bfc2bd597a..0169111678 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.300 2005/08/29 23:00:04 drh Exp $ +** $Id: main.c,v 1.301 2005/09/07 21:22:46 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -875,7 +875,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){ rc = SQLITE_OK; }else{ rc = sqlite3VdbeReset((Vdbe*)pStmt); - sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0); + sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0); } return rc; } diff --git a/src/parse.y b/src/parse.y index 750f8a4418..b008a01dd8 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.175 2005/07/08 12:13:05 drh Exp $ +** @(#) $Id: parse.y,v 1.176 2005/09/07 21:22:46 drh Exp $ */ // All token codes are small integers with #defines that begin with "TK_" @@ -93,7 +93,7 @@ struct AttachKey { int type; Token key; }; // add them to the parse.h output file. // %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION - COLUMN AGG_FUNCTION CONST_FUNC. + COLUMN AGG_FUNCTION AGG_COLUMN CONST_FUNC. // Input is a single SQL command input ::= cmdlist. diff --git a/src/select.c b/src/select.c index 94943a5414..dc1a57890b 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.260 2005/09/05 20:06:49 drh Exp $ +** $Id: select.c,v 1.261 2005/09/07 21:22:47 drh Exp $ */ #include "sqliteInt.h" @@ -346,7 +346,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); @@ -357,7 +357,7 @@ 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")); } @@ -435,13 +435,15 @@ static int selectInnerLoop( } 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; } @@ -1350,6 +1352,20 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){ } } +/* +** 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 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; +} + #ifndef SQLITE_OMIT_COMPOUND_SELECT /* ** Return the appropriate collating sequence for the iCol-th column of @@ -2276,6 +2292,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 ){ @@ -2319,18 +2336,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; @@ -2345,7 +2350,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; @@ -2353,7 +2359,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; } @@ -2370,49 +2376,112 @@ 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; inExpr; 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 saveAggregateInfo(Parse *pParse, AggregateInfo *pInfo){ - pInfo->aAgg = pParse->aAgg; - pInfo->nAgg = pParse->nAgg; - pParse->aAgg = 0; - pParse->nAgg = 0; +static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ + Vdbe *v = pParse->pVdbe; + int i; + int addr; + if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){ + return; + } + sqlite3VdbeAddOp(v, OP_Null, 0, 0); + for(i=0; inColumn; i++){ + addr = sqlite3VdbeAddOp(v, OP_MemStore, pAggInfo->aCol[i].iMem, 0); + } + for(i=0; inFunc; i++){ + addr = sqlite3VdbeAddOp(v, OP_MemStore, pAggInfo->aFunc[i].iMem, 0); + } + sqlite3VdbeChangeP2(v, addr, 1); } /* -** 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. +** Invoke the OP_AggFinalize opcode for every aggregate function +** in the AggInfo structure. */ -static void restoreAggregateInfo(Parse *pParse, AggregateInfo *pInfo){ - sqliteFree(pParse->aAgg); - pParse->aAgg = pInfo->aAgg; - pParse->nAgg = pInfo->nAgg; +static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ + Vdbe *v = pParse->pVdbe; + int i; + struct AggInfo_func *pF; + for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ + sqlite3VdbeAddOp(v, OP_AggFinal, pF->iMem, 0); + } } - + +/* +** Update the accumulator memory cells for an aggregate based on +** the current cursor position. +*/ +static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ + Vdbe *v = pParse->pVdbe; + int i; + struct AggInfo_func *pF; + struct AggInfo_col *pC; + Expr fauxExpr; + + pAggInfo->directMode = 1; + for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ + int nArg; + ExprList *pList = pF->pExpr->pList; + if( pList ){ + nArg = pList->nExpr; + sqlite3ExprCodeExprList(pParse, pList); + }else{ + nArg = 0; + } + if( pF->pFunc->needCollSeq ){ + CollSeq *pColl = 0; + struct ExprList_item *pItem; + int j; + for(j=0, pItem=pList->a; !pColl && jnExpr; 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); + } + memset(&fauxExpr, 0, sizeof(fauxExpr)); + fauxExpr.op = TK_AGG_COLUMN; + fauxExpr.pAggInfo = pAggInfo; + for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ + fauxExpr.iAgg = i; + sqlite3ExprCode(pParse, &fauxExpr); + sqlite3VdbeAddOp(v, OP_MemStore, pC->iMem, 1); + } + pAggInfo->directMode = 0; +} + + /* ** Generate code for the given SELECT statement. ** @@ -2475,9 +2544,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 */ @@ -2488,10 +2557,11 @@ 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; + 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. @@ -2507,9 +2577,8 @@ int sqlite3Select( } #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) ){ @@ -2548,14 +2617,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. @@ -2576,23 +2639,24 @@ int sqlite3Select( for(i=0; inSrc; 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_TempTable, + 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; @@ -2652,55 +2716,6 @@ int sqlite3Select( 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; - if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){ - goto select_end; - } - if( sqlite3ExprAnalyzeAggList(&sNC, pGroupBy) ){ - goto select_end; - } - if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){ - goto select_end; - } - if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){ - goto select_end; - } - } - - /* Reset the aggregator - */ - if( isAgg ){ - int addr = sqlite3VdbeAddOp(v, OP_AggReset, (pGroupBy?0:1), pParse->nAgg); - for(i=0; inAgg; 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 ){ - KeyInfo *pKey = keyInfoFromExprList(pParse, pGroupBy); - if( 0==pKey ){ - goto select_end; - } - sqlite3VdbeChangeP3(v, addr, (char *)pKey, P3_KEYINFO_HANDOFF); - } - } /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists */ @@ -2721,94 +2736,264 @@ int sqlite3Select( 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 ){ + /* 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; - 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; inAgg; 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; inAgg; 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 && jpList->a[j].pExpr); - } - if( !pColl ) pColl = pParse->db->pDfltColl; - sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); - } - sqlite3VdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_FUNCDEF); - } - } + /* 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 */ - /* End the database scan loop. - */ - sqlite3WhereEnd(pWInfo); - /* 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) ){ + /* 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 */ + + 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; + if( sqlite3ExprAnalyzeAggList(&sNC, pEList) ){ goto select_end; } - sqlite3VdbeAddOp(v, OP_Goto, 0, startagg); - sqlite3VdbeResolveLabel(v, endagg); - sqlite3VdbeAddOp(v, OP_Noop, 0, 0); - } + if( sqlite3ExprAnalyzeAggList(&sNC, pOrderBy) ){ + goto select_end; + } + if( pHaving && sqlite3ExprAnalyzeAggregates(&sNC, pHaving) ){ + goto select_end; + } + sAggInfo.nAccumulator = sAggInfo.nColumn; + for(i=0; ipList) ){ + goto select_end; + } + } + + /* Processing for aggregates with GROUP BY is very different and + ** much more complex tha aggregates without a GROUP BY. + */ + if( pGroupBy ){ + 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_Integer, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iAbortFlag, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iUseFlag, 1); + sqlite3VdbeAddOp(v, OP_Null, 0, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iAMem, 1); + 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_MemIncr, iAbortFlag, 0); + sqlite3VdbeAddOp(v, OP_Return, 0, 0); + addrOutputRow = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp(v, OP_IfMemPos, iUseFlag, addrOutputRow+2); + 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); + + /* 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); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy); + 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; iiSorterColumniColumn<0 ){ + sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0); + }else{ + sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn); + } + j++; + } + sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0); + sqlite3VdbeAddOp(v, OP_IdxInsert, sAggInfo.sortingIdx, 0); + sqlite3WhereEnd(pWInfo); + sqlite3VdbeAddOp(v, OP_Sort, sAggInfo.sortingIdx, 0); + sAggInfo.useSortingIdx = 1; + } + + /* 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; jnExpr; 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, jnExpr-1); + } + for(j=pGroupBy->nExpr-1; j>=0; j--){ + if( jnExpr-1 ){ + sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0); + } + sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0); + if( j==0 ){ + sqlite3VdbeAddOp(v, OP_Eq, 0, addrProcessRow); + }else{ + sqlite3VdbeAddOp(v, OP_Ne, 0x100, addrGroupByChange); + } + sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ); + } + + /* 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; jnExpr; j++){ + sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0); + sqlite3VdbeAddOp(v, OP_MemStore, iAMem+j, 1); + } + sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow); + sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd); + resetAccumulator(pParse, &sAggInfo); + + /* Update the aggregate accumulators based on the content of + ** the current row + */ + sqlite3VdbeResolveLabel(v, addrProcessRow); + updateAccumulator(pParse, &sAggInfo); + sqlite3VdbeAddOp(v, OP_MemIncr, iUseFlag, 0); + + /* 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); + + } /* 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); + updateAccumulator(pParse, &sAggInfo); + sqlite3WhereEnd(pWInfo); + finalizeAggFunctions(pParse, &sAggInfo); + pOrderBy = 0; + selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1, + eDest, iParm, addrEnd, addrEnd, aff); + } + 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. @@ -2840,6 +3025,7 @@ int sqlite3Select( ** successful coding of the SELECT. */ select_end: - restoreAggregateInfo(pParse, &sAggInfo); + sqliteFree(sAggInfo.aCol); + sqliteFree(sAggInfo.aFunc); return rc; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4dc7ed0530..16ab6ae2fa 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.407 2005/09/01 03:07:44 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.408 2005/09/07 21:22:47 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -298,7 +298,7 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */ /* ** Forward references to structures */ -typedef struct AggExpr AggExpr; +typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct CollSeq CollSeq; typedef struct Column Column; @@ -788,6 +788,47 @@ struct Token { unsigned n : 31; /* Number of characters in this token */ }; +/* +** An instance of this structure contains information needed to generate +** code for a SELECT that contains aggregate functions. +** +** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a +** pointer to this structure. The Expr.iColumn field is the index in +** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate +** code for that node. +** +** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the +** original Select structure that describes the SELECT statement. These +** fields do not need to be freed when deallocating the AggInfo structure. +*/ +struct AggInfo { + u8 directMode; /* Direct rendering mode means take data directly + ** from source tables rather than from accumulators */ + u8 useSortingIdx; /* In direct mode, reference the sorting index rather + ** than the source table */ + int sortingIdx; /* Cursor number of the sorting index */ + ExprList *pGroupBy; /* The group by clause */ + int nSortingColumn; /* Number of columns in the sorting index */ + struct AggInfo_col { /* For each column used in source tables */ + int iTable; /* Cursor number of the source table */ + int iColumn; /* Column number within the source table */ + int iSorterColumn; /* Column number in the sorting index */ + int iMem; /* Memory location that acts as accumulator */ + } *aCol; + int nColumn; /* Number of used entries in aCol[] */ + int nColumnAlloc; /* Number of slots allocated for aCol[] */ + int nAccumulator; /* Number of columns that show through to the output. + ** Additional columns are used only as parameters to + ** aggregate functions */ + struct AggInfo_func { /* For each aggregate function */ + Expr *pExpr; /* Expression encoding the function */ + FuncDef *pFunc; /* The aggregate function implementation */ + int iMem; /* Memory location that acts as accumulator */ + } *aFunc; + int nFunc; /* Number of entries in aFunc[] */ + int nFuncAlloc; /* Number of slots allocated for aFunc[] */ +}; + /* ** Each node of an expression in the parse tree is an instance ** of this structure. @@ -847,9 +888,8 @@ struct Expr { Token span; /* Complete text of the expression */ int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the ** iColumn-th field of the iTable-th table. */ - int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull - ** result from the iAgg-th element of the aggregator */ - int iAggCtx; /* The value to pass as P1 of OP_AggGet. */ + AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ + int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ Select *pSelect; /* When the expression is a sub-select. Also the ** right side of " IN (