Rewrite the aggregate handling logic so that it runs in O(1) space.

This is the first cut at the code.  Many regression tests fail. (CVS 2662)

FossilOrigin-Name: 17039ec3ff4396862beedf4a8af89654b2140f58
This commit is contained in:
drh 2005-09-07 21:22:45 +00:00
parent 79158e1865
commit 13449892ef
14 changed files with 701 additions and 806 deletions

View File

@ -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

View File

@ -1 +1 @@
b86bd70f301205d6ca66475a425e157b976107e2
17039ec3ff4396862beedf4a8af89654b2140f58

View File

@ -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 <ctype.h>
@ -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;
}

View File

@ -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 <ctype.h>
@ -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; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
p2 |= (1<<i);
constMask |= (1<<i);
}
if( pDef->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 && i<pSrcList->nSrc; i++){
if( pExpr->iTable==pSrcList->a[i].iCursor ){
pAgg = pParse->aAgg;
for(i=0; i<pParse->nAgg; 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; i<pSrcList->nSrc; 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; i<pAggInfo->nColumn; 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; j<n; j++, pTerm++){
Expr *pE = pTerm->pExpr;
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; i<pParse->nAgg; 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; i<pAggInfo->nFunc; 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);

View File

@ -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;
}

View File

@ -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.

View File

@ -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; 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 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; i<pAggInfo->nColumn; i++){
addr = sqlite3VdbeAddOp(v, OP_MemStore, pAggInfo->aCol[i].iMem, 0);
}
for(i=0; i<pAggInfo->nFunc; 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; i<pAggInfo->nFunc; 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; i<pAggInfo->nFunc; 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 && 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);
}
memset(&fauxExpr, 0, sizeof(fauxExpr));
fauxExpr.op = TK_AGG_COLUMN;
fauxExpr.pAggInfo = pAggInfo;
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; 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; 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_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; 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 ){
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; 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);
}
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; i<sAggInfo.nFunc; i++){
if( sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList) ){
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; 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++;
}
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; 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, 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; j<pGroupBy->nExpr; 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;
}

View File

@ -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 "<expr> IN (<select>)" */
Table *pTab; /* Table for OP_Column expressions. */
@ -912,12 +952,12 @@ struct ExprList {
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
*/
struct IdList {
int nId; /* Number of identifiers on the list */
int nAlloc; /* Number of entries allocated for a[] below */
struct IdList_item {
char *zName; /* Name of the identifier */
int idx; /* Index in some Table.aCol[] of a column named zName */
} *a;
int nId; /* Number of identifiers on the list */
int nAlloc; /* Number of entries allocated for a[] below */
};
/*
@ -1031,8 +1071,9 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nErr; /* Number of errors encountered while resolving names */
u8 allowAgg; /* Aggregate functions allowed here */
u8 hasAgg;
u8 hasAgg; /* True if aggregates are seen */
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
AggInfo *pAggInfo; /* Information about aggregates at this level */
NameContext *pNext; /* Next outer name context. NULL for outermost */
};
@ -1079,42 +1120,21 @@ struct Select {
/*
** The results of a select can be distributed in several ways.
*/
#define SRT_Callback 1 /* Invoke a callback with each row of result */
#define SRT_Mem 2 /* Store result in a memory cell */
#define SRT_Set 3 /* Store result as unique keys in a table */
#define SRT_Union 5 /* Store result as keys in a table */
#define SRT_Except 6 /* Remove result from a UNION table */
#define SRT_Table 7 /* Store result as data with a unique key */
#define SRT_TempTable 8 /* Store result in a trasient table */
#define SRT_Discard 9 /* Do not save the results anywhere */
#define SRT_Sorter 10 /* Store results in the sorter */
#define SRT_Subroutine 11 /* Call a subroutine to handle results */
#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */
#define SRT_Union 1 /* Store result as keys in an index */
#define SRT_Except 2 /* Remove result from a UNION index */
#define SRT_Discard 3 /* Do not save the results anywhere */
/*
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
** we have to do some additional analysis of expressions. An instance
** of the following structure holds information about a single subexpression
** somewhere in the SELECT statement. An array of these structures holds
** all the information we need to generate code for aggregate
** expressions.
**
** Note that when analyzing a SELECT containing aggregates, both
** non-aggregate field variables and aggregate functions are stored
** in the AggExpr array of the Parser structure.
**
** The pExpr field points to an expression that is part of either the
** field list, the GROUP BY clause, the HAVING clause or the ORDER BY
** clause. The expression will be freed when those clauses are cleaned
** up. Do not try to delete the expression attached to AggExpr.pExpr.
**
** If AggExpr.pExpr==0, that means the expression is "count(*)".
*/
struct AggExpr {
int isAgg; /* if TRUE contains an aggregate function */
Expr *pExpr; /* The expression */
FuncDef *pFunc; /* Information about the aggregate function */
};
/* The ORDER BY clause is ignored for all of the above */
#define IgnorableOrderby(X) (X<=SRT_Discard)
#define SRT_Callback 4 /* Invoke a callback with each row of result */
#define SRT_Mem 5 /* Store result in a memory cell */
#define SRT_Set 6 /* Store non-null results as keys in an index */
#define SRT_Table 7 /* Store result as data and add automatic rowid */
#define SRT_TempTable 8 /* Store result in a trasient table */
#define SRT_Sorter 9 /* Store results in the sorter NOT USED */
#define SRT_Subroutine 10 /* Call a subroutine to handle results */
#define SRT_Exists 11 /* Put 0 or 1 in a memory cell */
/*
** An SQL parser context. A copy of this structure is passed through
@ -1135,7 +1155,6 @@ struct Parse {
u8 nameClash; /* A permanent table name clashes with temp table name */
u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
@ -1162,9 +1181,6 @@ struct Parse {
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
int nAgg; /* Number of aggregate expressions */
AggExpr *aAgg; /* An array of aggregate expressions */
int nMaxDepth; /* Maximum depth of subquery recursion */
};
/*
@ -1421,6 +1437,7 @@ void sqlite3EndTable(Parse*,Token*,Token*,Select*);
void sqlite3DropTable(Parse*, SrcList*, int);
void sqlite3DeleteTable(sqlite3*, Table*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
int sqlite3ArrayAllocate(void**,int,int);
IdList *sqlite3IdListAppend(IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);

View File

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.481 2005/09/06 20:36:49 drh Exp $
** $Id: vdbe.c,v 1.482 2005/09/07 21:22:47 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -160,38 +160,6 @@ static void _storeTypeInfo(Mem *pMem){
}
}
/*
** Insert a new aggregate element and make it the element that
** has focus.
**
** Return 0 on success and 1 if memory is exhausted.
*/
static int AggInsert(Agg *p, char *zKey, int nKey){
AggElem *pElem;
int i;
int rc;
pElem = sqliteMalloc( sizeof(AggElem) + nKey +
(p->nMem-1)*sizeof(pElem->aMem[0]) );
if( pElem==0 ) return SQLITE_NOMEM;
pElem->zKey = (char*)&pElem->aMem[p->nMem];
memcpy(pElem->zKey, zKey, nKey);
pElem->nKey = nKey;
if( p->pCsr ){
rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
if( rc!=SQLITE_OK ){
sqliteFree(pElem);
return rc;
}
}
for(i=0; i<p->nMem; i++){
pElem->aMem[i].flags = MEM_Null;
}
p->pCurrent = pElem;
return 0;
}
/*
** Pop the stack N times.
*/
@ -1131,26 +1099,25 @@ case OP_CollSeq: { /* no-push */
/* Opcode: Function P1 P2 P3
**
** Invoke a user function (P3 is a pointer to a Function structure that
** defines the function) with P1 arguments taken from the stack. Pop all
** defines the function) with P2 arguments taken from the stack. Pop all
** arguments from the stack and push back the result.
**
** P2 is a 32-bit bitmask indicating whether or not each argument to the
** P1 is a 32-bit bitmask indicating whether or not each argument to the
** function was determined to be constant at compile time. If the first
** argument was constant then bit 0 of P2 is set. This is used to determine
** argument was constant then bit 0 of P1 is set. This is used to determine
** whether meta data associated with a user function argument using the
** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode.
**
** See also: AggFunc
** See also: AggStep and AggFinal
*/
case OP_Function: {
int i;
Mem *pArg;
sqlite3_context ctx;
sqlite3_value **apVal;
int n = pOp->p1;
int n = pOp->p2;
n = pOp->p1;
apVal = p->apArg;
assert( apVal || n==0 );
@ -1189,7 +1156,7 @@ case OP_Function: {
** immediately call the destructor for any non-static values.
*/
if( ctx.pVdbeFunc ){
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2);
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
pOp->p3 = (char *)ctx.pVdbeFunc;
pOp->p3type = P3_VDBEFUNC;
}
@ -4028,31 +3995,6 @@ case OP_FifoRead: {
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
/* Opcode: AggContextPush * * *
**
** Save the state of the current aggregator. It is restored an
** AggContextPop opcode.
**
*/
case OP_AggContextPush: { /* no-push */
p->pAgg++;
assert( p->pAgg<&p->apAgg[p->nAgg] );
break;
}
/* Opcode: AggContextPop * * *
**
** Restore the aggregator to the state it was in when AggContextPush
** was last called. Any data in the current aggregator is deleted.
*/
case OP_AggContextPop: { /* no-push */
p->pAgg--;
assert( p->pAgg>=p->apAgg );
break;
}
#endif
#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: ContextPush * * *
**
@ -4199,64 +4141,16 @@ case OP_IfMemPos: { /* no-push */
break;
}
/* Opcode: AggReset P1 P2 P3
**
** Reset the current aggregator context so that it no longer contains any
** data. Future aggregator elements will contain P2 values each and be sorted
** using the KeyInfo structure pointed to by P3.
**
** If P1 is non-zero, then only a single aggregator row is available (i.e.
** there is no GROUP BY expression). In this case it is illegal to invoke
** OP_AggFocus.
*/
case OP_AggReset: { /* no-push */
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
if( pOp->p1 ){
rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
p->pAgg->nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
rc = AggInsert(p->pAgg, 0, 0);
}else{
rc = sqlite3VdbeAggReset(db, p->pAgg, (KeyInfo *)pOp->p3);
p->pAgg->nMem = pOp->p2;
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
p->pAgg->apFunc = sqliteMalloc( p->pAgg->nMem*sizeof(p->pAgg->apFunc[0]) );
if( p->pAgg->apFunc==0 ) goto no_mem;
break;
}
/* Opcode: AggInit P1 P2 P3
**
** Initialize the function parameters for an aggregate function.
** The aggregate will operate out of aggregate column P2.
** P3 is a pointer to the FuncDef structure for the function.
**
** The P1 argument is not used by this opcode. However if the SSE
** extension is compiled in, P1 is set to the number of arguments that
** will be passed to the aggregate function, if any. This is used
** by SSE to select the correct function when (de)serializing statements.
*/
case OP_AggInit: { /* no-push */
int i = pOp->p2;
assert( i>=0 && i<p->pAgg->nMem );
p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
break;
}
/* Opcode: AggFunc * P2 P3
/* Opcode: AggStep P1 P2 P3
**
** Execute the step function for an aggregate. The
** function has P2 arguments. P3 is a pointer to the FuncDef
** structure that specifies the function.
** structure that specifies the function. Use memory location
** P1 as the accumulator.
**
** The top of the stack must be an integer which is the index of
** the aggregate column that corresponds to this aggregate function.
** Ideally, this index would be another parameter, but there are
** no free parameters left. The integer is popped from the stack.
** The P2 arguments are popped from the stack.
*/
case OP_AggFunc: { /* no-push */
case OP_AggStep: { /* no-push */
int n = pOp->p2;
int i;
Mem *pMem, *pRec;
@ -4264,21 +4158,17 @@ case OP_AggFunc: { /* no-push */
sqlite3_value **apVal;
assert( n>=0 );
assert( pTos->flags==MEM_Int );
pRec = &pTos[-n];
pRec = &pTos[1-n];
assert( pRec>=p->aStack );
apVal = p->apArg;
assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){
apVal[i] = pRec;
storeTypeInfo(pRec, db->enc);
}
i = pTos->i;
assert( i>=0 && i<p->pAgg->nMem );
ctx.pFunc = (FuncDef*)pOp->p3;
ctx.pMem = pMem = &p->pAgg->pCurrent->aMem[i];
assert( pOp->p1>=0 && pOp->p1<p->nMem );
ctx.pMem = pMem = &p->aMem[pOp->p1];
pMem->n++;
ctx.isError = 0;
ctx.pColl = 0;
@ -4289,165 +4179,26 @@ case OP_AggFunc: { /* no-push */
ctx.pColl = (CollSeq *)pOp[-1].p3;
}
(ctx.pFunc->xStep)(&ctx, n, apVal);
popStack(&pTos, n+1);
popStack(&pTos, n);
if( ctx.isError ){
rc = SQLITE_ERROR;
}
break;
}
/* Opcode: AggFocus * P2 *
/* Opcode: AggFinal P1 * *
**
** Pop the top of the stack and use that as an aggregator key. If
** an aggregator with that same key already exists, then make the
** aggregator the current aggregator and jump to P2. If no aggregator
** with the given key exists, create one and make it current but
** do not jump.
**
** The order of aggregator opcodes is important. The order is:
** AggReset AggFocus AggNext. In other words, you must execute
** AggReset first, then zero or more AggFocus operations, then
** zero or more AggNext operations. You must not execute an AggFocus
** in between an AggNext and an AggReset.
** Execute the finalizer function for an aggregate. P1 is
** the memory location that is the accumulator for the aggregate.
*/
case OP_AggFocus: { /* no-push */
char *zKey;
int nKey;
int res;
assert( pTos>=p->aStack );
Stringify(pTos, db->enc);
zKey = pTos->z;
nKey = pTos->n;
assert( p->pAgg->pBtree );
assert( p->pAgg->pCsr );
rc = sqlite3BtreeMoveto(p->pAgg->pCsr, zKey, nKey, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( res==0 ){
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
(char *)&p->pAgg->pCurrent);
pc = pOp->p2 - 1;
}else{
rc = AggInsert(p->pAgg, zKey, nKey);
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
Release(pTos);
pTos--;
break;
}
/* Opcode: AggSet * P2 *
**
** Move the top of the stack into the P2-th field of the current
** aggregate. String values are duplicated into new memory.
*/
case OP_AggSet: { /* no-push */
AggElem *pFocus;
int i = pOp->p2;
pFocus = p->pAgg->pCurrent;
assert( pTos>=p->aStack );
if( pFocus==0 ) goto no_mem;
assert( i>=0 && i<p->pAgg->nMem );
rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
pTos--;
case OP_AggFinal: { /* no-push */
Mem *pMem;
assert( pOp->p1>=0 && pOp->p1<p->nMem );
pMem = &p->aMem[pOp->p1];
sqlite3VdbeMemFinalize(pMem);
break;
}
/* Opcode: AggGet P1 P2 *
**
** Push a new entry onto the stack which is a copy of the P2-th field
** of the current aggregate. Strings are not duplicated so
** string values will be ephemeral.
**
** If P1 is zero, then the value is pulled out of the current aggregate
** in the current aggregate context. If P1 is greater than zero, then
** the value is taken from the P1th outer aggregate context. (i.e. if
** P1==1 then read from the aggregate context that will be restored
** by the next OP_AggContextPop opcode).
*/
case OP_AggGet: {
AggElem *pFocus;
int i = pOp->p2;
Agg *pAgg = &p->pAgg[-pOp->p1];
assert( pAgg>=p->apAgg );
pFocus = pAgg->pCurrent;
if( pFocus==0 ){
int res;
if( sqlite3_malloc_failed ) goto no_mem;
rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
if( rc!=SQLITE_OK ){
return rc;
}
if( res!=0 ){
rc = AggInsert(pAgg, "", 1);
pFocus = pAgg->pCurrent;
}else{
rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
}
}
assert( i>=0 && i<pAgg->nMem );
pTos++;
sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
if( pTos->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pTos, db->enc);
}
break;
}
/* Opcode: AggNext * P2 *
**
** Make the next aggregate value the current aggregate. The prior
** aggregate is deleted. If all aggregate values have been consumed,
** jump to P2.
**
** The order of aggregator opcodes is important. The order is:
** AggReset AggFocus AggNext. In other words, you must execute
** AggReset first, then zero or more AggFocus operations, then
** zero or more AggNext operations. You must not execute an AggFocus
** in between an AggNext and an AggReset.
*/
case OP_AggNext: { /* no-push */
int res;
assert( rc==SQLITE_OK );
CHECK_FOR_INTERRUPT;
if( p->pAgg->searching==0 ){
p->pAgg->searching = 1;
if( p->pAgg->pCsr ){
rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
}else{
res = 0;
}
}else{
if( p->pAgg->pCsr ){
rc = sqlite3BtreeNext(p->pAgg->pCsr, &res);
}else{
res = 1;
}
}
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( res!=0 ){
pc = pOp->p2 - 1;
}else{
int i;
Mem *aMem;
if( p->pAgg->pCsr ){
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
(char *)&p->pAgg->pCurrent);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
aMem = p->pAgg->pCurrent->aMem;
for(i=0; i<p->pAgg->nMem; i++){
FuncDef *pFunc = p->pAgg->apFunc[i];
Mem *pMem = &aMem[i];
sqlite3VdbeMemFinalize(pMem, pFunc);
}
}
break;
}
/* Opcode: Vacuum * * *
**

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.97 2005/08/19 01:07:16 drh Exp $
** $Id: vdbe.h,v 1.98 2005/09/07 21:22:47 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -108,7 +108,7 @@ void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);

View File

@ -201,30 +201,6 @@ struct sqlite3_context {
CollSeq *pColl; /* Collating sequence */
};
/*
** An Agg structure describes an Aggregator. Each Agg consists of
** zero or more Aggregator elements (AggElem). Each AggElem contains
** a key and one or more values. The values are used in processing
** aggregate functions in a SELECT. The key is used to implement
** the GROUP BY clause of a select.
*/
typedef struct Agg Agg;
typedef struct AggElem AggElem;
struct Agg {
int nMem; /* Number of values stored in each AggElem */
AggElem *pCurrent; /* The AggElem currently in focus */
FuncDef **apFunc; /* Information about aggregate functions */
Btree *pBtree; /* The tmp. btree used to group elements, if required. */
BtCursor *pCsr; /* Read/write cursor to the table in pBtree */
int nTab; /* Root page of the table in pBtree */
u8 searching; /* True between the first AggNext and AggReset */
};
struct AggElem {
char *zKey; /* The key to this AggElem */
int nKey; /* Number of bytes in the key, including '\0' at end */
Mem aMem[1]; /* The values for this AggElem */
};
/*
** A Set structure is used for quick testing to see if a value
** is part of a small set. Sets are used to implement code like
@ -309,9 +285,6 @@ struct Vdbe {
int magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
int nAgg; /* Number of elements in apAgg */
Agg *apAgg; /* Array of aggregate contexts */
Agg *pAgg; /* Current aggregate context */
int nCallback; /* Number of callbacks invoked so far */
Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
@ -349,7 +322,6 @@ struct Vdbe {
** Function prototypes
*/
void sqlite3VdbeFreeCursor(Cursor*);
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@ -391,7 +363,7 @@ double sqlite3VdbeRealValue(Mem*);
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
void sqlite3VdbeMemFinalize(Mem*);
#ifndef NDEBUG
void sqlite3VdbeMemSanity(Mem*, u8);
int sqlite3VdbeOpcodeNoPush(u8);

View File

@ -215,8 +215,8 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
**
** This routine is called once after all opcodes have been inserted.
**
** Variable *pMaxFuncArgs is set to the maximum value of any P1 argument
** to an OP_Function or P2 to an OP_AggFunc opcode. This is used by
** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
** to an OP_Function or OP_AggStep opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
**
** The integer *pMaxStack is set to the maximum number of vdbe stack
@ -239,12 +239,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
u8 opcode = pOp->opcode;
/* Todo: Maybe OP_AggFunc should change to use P1 in the same
* way as OP_Function.
*/
if( opcode==OP_Function ){
if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;
}else if( opcode==OP_AggFunc ){
if( opcode==OP_Function || opcode==OP_AggStep ){
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
}else if( opcode==OP_Halt ){
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
@ -663,7 +658,6 @@ void sqlite3VdbeMakeReady(
int nVar, /* Number of '?' see in the SQL statement */
int nMem, /* Number of memory cells to allocate */
int nCursor, /* Number of cursors to allocate */
int nAgg, /* Number of aggregate contexts required */
int isExplain /* True if the EXPLAIN keywords is present */
){
int n;
@ -706,7 +700,6 @@ void sqlite3VdbeMakeReady(
+ nVar*sizeof(char*) /* azVar */
+ nMem*sizeof(Mem) /* aMem */
+ nCursor*sizeof(Cursor*) /* apCsr */
+ nAgg*sizeof(Agg) /* Aggregate contexts */
);
if( !sqlite3_malloc_failed ){
p->aMem = &p->aStack[nStack];
@ -717,17 +710,12 @@ void sqlite3VdbeMakeReady(
p->apArg = (Mem**)&p->aVar[nVar];
p->azVar = (char**)&p->apArg[nArg];
p->apCsr = (Cursor**)&p->azVar[nVar];
if( nAgg>0 ){
p->nAgg = nAgg;
p->apAgg = (Agg*)&p->apCsr[nCursor];
}
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
}
}
}
p->pAgg = p->apAgg;
for(n=0; n<p->nMem; n++){
p->aMem[n].flags = MEM_Null;
}
@ -768,129 +756,6 @@ void sqlite3VdbeMakeReady(
#endif
}
/*
** Free all resources allociated with AggElem pElem, an element of
** aggregate pAgg.
*/
static void freeAggElem(AggElem *pElem, Agg *pAgg){
int i;
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_Agg)!=0 ){
sqlite3VdbeMemFinalize(pMem, pAgg->apFunc[i]);
}
sqlite3VdbeMemRelease(pMem);
}
sqliteFree(pElem);
}
/*
** Reset an Agg structure. Delete all its contents.
**
** For installable aggregate functions, if the step function has been
** called, make sure the finalizer function has also been called. The
** finalizer might need to free memory that was allocated as part of its
** private context. If the finalizer has not been called yet, call it
** now.
**
** If db is NULL, then this is being called from sqliteVdbeReset(). In
** this case clean up all references to the temp-table used for
** aggregates (if it was ever opened).
**
** If db is not NULL, then this is being called from with an OP_AggReset
** opcode. Open the temp-table, if it has not already been opened and
** delete the contents of the table used for aggregate information, ready
** for the next round of aggregate processing.
*/
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
int rc = 0;
BtCursor *pCsr;
if( !pAgg ) return SQLITE_OK;
pCsr = pAgg->pCsr;
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|| sqlite3_malloc_failed );
/* If pCsr is not NULL, then the table used for aggregate information
** is open. Loop through it and free the AggElem* structure pointed at
** by each entry. If the finalizer has not been called for an AggElem,
** do that too. Finally, clear the btree table itself.
*/
if( pCsr ){
int res;
assert( pAgg->pBtree );
assert( pAgg->nTab>0 );
rc=sqlite3BtreeFirst(pCsr, &res);
while( res==0 && rc==SQLITE_OK ){
AggElem *pElem;
rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pAgg->apFunc!=0 );
freeAggElem(pElem, pAgg);
rc=sqlite3BtreeNext(pCsr, &res);
}
if( rc!=SQLITE_OK ){
return rc;
}
sqlite3BtreeCloseCursor(pCsr);
sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
}else{
/* The cursor may not be open because the aggregator was never used,
** or it could be that it was used but there was no GROUP BY clause.
*/
if( pAgg->pCurrent ){
freeAggElem(pAgg->pCurrent, pAgg);
}
}
/* If db is not NULL and we have not yet and we have not yet opened
** the temporary btree then do so and create the table to store aggregate
** information.
**
** If db is NULL, then close the temporary btree if it is open.
*/
if( db ){
if( !pAgg->pBtree ){
assert( pAgg->nTab==0 );
#ifndef SQLITE_OMIT_MEMORYDB
rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
#else
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
#endif
if( rc!=SQLITE_OK ) return rc;
sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
if( rc!=SQLITE_OK ) return rc;
}
assert( pAgg->nTab!=0 );
rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1,
sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr);
if( rc!=SQLITE_OK ) return rc;
}else{
if( pAgg->pBtree ){
sqlite3BtreeClose(pAgg->pBtree);
pAgg->pBtree = 0;
pAgg->nTab = 0;
}
pAgg->pCsr = 0;
}
if( pAgg->apFunc ){
sqliteFree(pAgg->apFunc);
pAgg->apFunc = 0;
}
pAgg->pCurrent = 0;
pAgg->nMem = 0;
pAgg->searching = 0;
return SQLITE_OK;
}
/*
** Close a cursor and release all the resources that cursor happens
** to hold.
@ -944,9 +809,6 @@ static void Cleanup(Vdbe *p){
}
sqliteFree(p->contextStack);
}
for(i=0; i<p->nAgg; i++){
sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
}
p->contextStack = 0;
p->contextStackDepth = 0;
p->contextStackTop = 0;

View File

@ -192,20 +192,23 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
** This routine calls the finalize method for that function. The
** result of the aggregate is stored back into pMem.
*/
void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
}
*pMem = ctx.s;
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
void sqlite3VdbeMemFinalize(Mem *pMem){
if( pMem->flags & MEM_Agg ){
FuncDef *pFunc = *(FuncDef**)&pMem->i;
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx);
if( pMem->z && pMem->z!=pMem->zShort ){
sqliteFree( pMem->z );
}
*pMem = ctx.s;
if( pMem->flags & MEM_Short ){
pMem->z = pMem->zShort;
}
}
}
}
@ -219,7 +222,7 @@ void sqlite3VdbeMemRelease(Mem *p){
if( p->flags & (MEM_Dyn|MEM_Agg) ){
if( p->xDel ){
if( p->flags & MEM_Agg ){
sqlite3VdbeMemFinalize(p, (FuncDef*)&p->i);
sqlite3VdbeMemFinalize(p);
assert( (p->flags & MEM_Agg)==0 );
sqlite3VdbeMemRelease(p);
}else{

View File

@ -13,7 +13,7 @@
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc4.test,v 1.16 2005/03/29 03:11:00 danielk1977 Exp $
# $Id: misc4.test,v 1.17 2005/09/07 21:22:47 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -96,7 +96,7 @@ do_test misc4-3.1 {
INSERT INTO Table2 VALUES(1, 'z');
INSERT INTO Table2 VALUES (1, 'a');
SELECT ID, Value FROM Table1
UNION SELECT ID, max(Value) FROM Table2 GROUP BY 1,2
UNION SELECT ID, max(Value) FROM Table2 GROUP BY 1
ORDER BY 1, 2;
}
} {{} {} 1 x 1 z}
@ -177,4 +177,3 @@ do_test misc4-6.2 {
} {1}
finish_test