Have the vdbe aggregator use a btree table instead of a hash table. (CVS 1569)
FossilOrigin-Name: 8d56118f64dbaf8c8006266fa7026f900a4a16bd
This commit is contained in:
parent
dc1bdc4f9d
commit
ce2663ccc8
22
manifest
22
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\svarious\scollation\ssequence\sissues.\s(CVS\s1568)
|
||||
D 2004-06-11T10:51:27
|
||||
C Have\sthe\svdbe\saggregator\suse\sa\sbtree\stable\sinstead\sof\sa\shash\stable.\s(CVS\s1569)
|
||||
D 2004-06-11T13:19:21
|
||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@ -54,7 +54,7 @@ F src/parse.y 097438674976355a10cf177bd97326c548820b86
|
||||
F src/pragma.c 0bc3adea28df802074996bec067d506d55d28f84
|
||||
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
|
||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||
F src/select.c 3559dcd25b3e86150fb991b866b00b5152f15cac
|
||||
F src/select.c d29488f86e61e0d45dff318e1f04ba6a7e5782d0
|
||||
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
|
||||
F src/sqlite.h.in 2b6afe1de6935d3dfbd6042f46a62f1b7c3b3992
|
||||
F src/sqliteInt.h 625faf4c9ce2f99b9c85a2bca5c4e73736c30262
|
||||
@ -71,12 +71,12 @@ F src/update.c 168b6d523087ca4545b74ec9f3102b1f3c6b1e38
|
||||
F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab
|
||||
F src/util.c e8629f04d920ae968fced709dc7a3a2c62b65ac4
|
||||
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
|
||||
F src/vdbe.c 688ae431918ee4aefe53d395d7c43bb1aa32e458
|
||||
F src/vdbe.c 56a97efecedecff984599763552a96cacce86319
|
||||
F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde
|
||||
F src/vdbeInt.h e27e29ffe5b8b3998032e394631944dacafe5c54
|
||||
F src/vdbeInt.h 57b7001bc18de348f2180c5fa8a85b687592a19b
|
||||
F src/vdbeapi.c bcf5821ed09070d586898374b905861c4dd73d0b
|
||||
F src/vdbeaux.c 73764dadcdbf79aa2d948f863eae07b18589e663
|
||||
F src/vdbemem.c b1599f5d24131107a21a54e618e372e1252de958
|
||||
F src/vdbeaux.c 117d0d0a3178c203a0093d6fd7c26b69c34e9ed5
|
||||
F src/vdbemem.c 6407b5dcd6cae43ee1342d49bcd574f0f23f5beb
|
||||
F src/where.c dda77afaa593cd54e5955ec433076de18faf62f6
|
||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||
F test/attach.test aed659e52635662bcd5069599aaca823533edf5a
|
||||
@ -145,7 +145,7 @@ F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
|
||||
F test/rowid.test 863e6e75878cccf03d166fe52023f20e09508683
|
||||
F test/select1.test 2f161f9cdf9fb577336bc8c930edade538567123
|
||||
F test/select2.test 91a2225926039b0d1687840735c284dbbf89f0bc
|
||||
F test/select3.test f8ff60d98c7b4898f5e7326f0c5929ba56f5d047
|
||||
F test/select3.test ab2e583154ee230fa4b46b06512775a38cd9d8b0
|
||||
F test/select4.test 86e72fc3b07de4fe11439aa419e37db3c49467e2
|
||||
F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081
|
||||
F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
|
||||
@ -222,7 +222,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248
|
||||
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
|
||||
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
|
||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||
P 0e420f72cd5885e32914b4d958bad811fdd9fb77
|
||||
R 51b6a0eb20d4bdd91945614e74564613
|
||||
P 66835ee67051027456a536e33b2f88a741654525
|
||||
R 17851c4c7a9d880622be1c17f4d88abf
|
||||
U danielk1977
|
||||
Z a2401ce0227bab41442da327e235dd95
|
||||
Z 37fd25919977ced5eda4bf17b983a171
|
||||
|
@ -1 +1 @@
|
||||
66835ee67051027456a536e33b2f88a741654525
|
||||
8d56118f64dbaf8c8006266fa7026f900a4a16bd
|
19
src/select.c
19
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.187 2004/06/11 10:51:35 danielk1977 Exp $
|
||||
** $Id: select.c,v 1.188 2004/06/11 13:19:21 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -2441,7 +2441,7 @@ int sqlite3Select(
|
||||
/* Reset the aggregator
|
||||
*/
|
||||
if( isAgg ){
|
||||
sqlite3VdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
|
||||
int addr = sqlite3VdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
|
||||
for(i=0; i<pParse->nAgg; i++){
|
||||
FuncDef *pFunc;
|
||||
if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
|
||||
@ -2451,6 +2451,21 @@ int sqlite3Select(
|
||||
if( pGroupBy==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||
sqlite3VdbeAddOp(v, OP_AggFocus, 0, 0);
|
||||
}else{
|
||||
int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*);
|
||||
KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz);
|
||||
if( 0==pKey ){
|
||||
goto select_end;
|
||||
}
|
||||
pKey->enc = pParse->db->enc;
|
||||
pKey->nField = pGroupBy->nExpr;
|
||||
for(i=0; i<pGroupBy->nExpr; i++){
|
||||
pKey->aColl[i] = sqlite3ExprCollSeq(pParse, pGroupBy->a[i].pExpr);
|
||||
if( !pKey->aColl[i] ){
|
||||
pKey->aColl[i] = pParse->db->pDfltColl;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeChangeP3(v, addr, (char *)pKey, P3_KEYINFO_HANDOFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
119
src/vdbe.c
119
src/vdbe.c
@ -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.364 2004/06/11 10:51:37 danielk1977 Exp $
|
||||
** $Id: vdbe.c,v 1.365 2004/06/11 13:19:21 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -160,23 +160,25 @@ static void _storeTypeInfo(Mem *pMem){
|
||||
** Return 0 on success and 1 if memory is exhausted.
|
||||
*/
|
||||
static int AggInsert(Agg *p, char *zKey, int nKey){
|
||||
AggElem *pElem, *pOld;
|
||||
AggElem *pElem;
|
||||
int i;
|
||||
Mem *pMem;
|
||||
int rc;
|
||||
pElem = sqliteMalloc( sizeof(AggElem) + nKey +
|
||||
(p->nMem-1)*sizeof(pElem->aMem[0]) );
|
||||
if( pElem==0 ) return 1;
|
||||
if( pElem==0 ) return SQLITE_NOMEM;
|
||||
pElem->zKey = (char*)&pElem->aMem[p->nMem];
|
||||
memcpy(pElem->zKey, zKey, nKey);
|
||||
pElem->nKey = nKey;
|
||||
pOld = sqlite3HashInsert(&p->hash, pElem->zKey, pElem->nKey, pElem);
|
||||
if( pOld!=0 ){
|
||||
assert( pOld==pElem ); /* Malloc failed on insert */
|
||||
sqliteFree(pOld);
|
||||
return 0;
|
||||
|
||||
assert( p->pCsr );
|
||||
rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteFree(pElem);
|
||||
return rc;
|
||||
}
|
||||
for(i=0, pMem=pElem->aMem; i<p->nMem; i++, pMem++){
|
||||
pMem->flags = MEM_Null;
|
||||
|
||||
for(i=0; i<p->nMem; i++){
|
||||
pElem->aMem[i].flags = MEM_Null;
|
||||
}
|
||||
p->pCurrent = pElem;
|
||||
return 0;
|
||||
@ -185,6 +187,7 @@ static int AggInsert(Agg *p, char *zKey, int nKey){
|
||||
/*
|
||||
** Get the AggElem currently in focus
|
||||
*/
|
||||
#if 0
|
||||
#define AggInFocus(P) ((P).pCurrent ? (P).pCurrent : _AggInFocus(&(P)))
|
||||
static AggElem *_AggInFocus(Agg *p){
|
||||
HashElem *pElem = sqliteHashFirst(&p->hash);
|
||||
@ -194,6 +197,32 @@ static AggElem *_AggInFocus(Agg *p){
|
||||
}
|
||||
return pElem ? sqliteHashData(pElem) : 0;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
** Store a pointer to the AggElem currently in focus in *ppElem. Return
|
||||
** SQLITE_OK if successful, otherwise an error-code.
|
||||
*/
|
||||
static int AggInFocus(Agg *p, AggElem **ppElem){
|
||||
int rc;
|
||||
int res;
|
||||
|
||||
if( p->pCurrent ){
|
||||
*ppElem = p->pCurrent;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeFirst(p->pCsr, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
if( res!=0 ){
|
||||
rc = AggInsert(p,"",1);
|
||||
*ppElem = p->pCurrent;
|
||||
}else{
|
||||
rc = sqlite3BtreeData(p->pCsr, 0, 4, (char *)ppElem);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop the stack N times.
|
||||
@ -1298,7 +1327,9 @@ case OP_Function: {
|
||||
for(i=0; i<ctx.pVdbeFunc->nAux; i++){
|
||||
struct AuxData *pAux = &ctx.pVdbeFunc->apAux[i];
|
||||
if( (i>31 || !(mask&(1<<i))) && pAux->pAux ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
if( pAux->xDelete ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
}
|
||||
pAux->pAux = 0;
|
||||
}
|
||||
}
|
||||
@ -4259,13 +4290,18 @@ case OP_MemIncr: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: AggReset * P2 *
|
||||
/* Opcode: AggReset * P2 P3
|
||||
**
|
||||
** Reset the aggregator so that it no longer contains any data.
|
||||
** Future aggregator elements will contain P2 values each.
|
||||
** Future aggregator elements will contain P2 values each and be sorted
|
||||
** using the KeyInfo structure pointed to by P3.
|
||||
*/
|
||||
case OP_AggReset: {
|
||||
sqlite3VdbeAggReset(&p->agg);
|
||||
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
|
||||
rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
p->agg.nMem = pOp->p2;
|
||||
p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
|
||||
if( p->agg.apFunc==0 ) goto no_mem;
|
||||
@ -4356,21 +4392,29 @@ case OP_AggFunc: {
|
||||
** in between an AggNext and an AggReset.
|
||||
*/
|
||||
case OP_AggFocus: {
|
||||
AggElem *pElem;
|
||||
char *zKey;
|
||||
int nKey;
|
||||
|
||||
int res;
|
||||
assert( pTos>=p->aStack );
|
||||
Stringify(pTos, db->enc);
|
||||
zKey = pTos->z;
|
||||
nKey = pTos->n;
|
||||
pElem = sqlite3HashFind(&p->agg.hash, zKey, nKey);
|
||||
if( pElem ){
|
||||
p->agg.pCurrent = pElem;
|
||||
rc = sqlite3BtreeMoveto(p->agg.pCsr, zKey, nKey, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
if( res==0 ){
|
||||
rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
|
||||
(char *)&p->agg.pCurrent);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
AggInsert(&p->agg, zKey, nKey);
|
||||
if( sqlite3_malloc_failed ) goto no_mem;
|
||||
rc = AggInsert(&p->agg, zKey, nKey);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
Release(pTos);
|
||||
pTos--;
|
||||
@ -4383,9 +4427,11 @@ case OP_AggFocus: {
|
||||
** aggregate. String values are duplicated into new memory.
|
||||
*/
|
||||
case OP_AggSet: {
|
||||
AggElem *pFocus = AggInFocus(p->agg);
|
||||
Mem *pMem;
|
||||
AggElem *pFocus;
|
||||
int i = pOp->p2;
|
||||
Mem *pMem;
|
||||
rc = AggInFocus(&p->agg, &pFocus);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
assert( pTos>=p->aStack );
|
||||
if( pFocus==0 ) goto no_mem;
|
||||
assert( i>=0 && i<p->agg.nMem );
|
||||
@ -4409,9 +4455,11 @@ case OP_AggSet: {
|
||||
** string values will be ephemeral.
|
||||
*/
|
||||
case OP_AggGet: {
|
||||
AggElem *pFocus = AggInFocus(p->agg);
|
||||
AggElem *pFocus;
|
||||
Mem *pMem;
|
||||
int i = pOp->p2;
|
||||
rc = AggInFocus(&p->agg, &pFocus);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
if( pFocus==0 ) goto no_mem;
|
||||
assert( i>=0 && i<p->agg.nMem );
|
||||
pTos++;
|
||||
@ -4440,19 +4488,28 @@ case OP_AggGet: {
|
||||
** in between an AggNext and an AggReset.
|
||||
*/
|
||||
case OP_AggNext: {
|
||||
int res;
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( p->agg.pSearch==0 ){
|
||||
p->agg.pSearch = sqliteHashFirst(&p->agg.hash);
|
||||
if( p->agg.searching==0 ){
|
||||
p->agg.searching = 1;
|
||||
rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}else{
|
||||
p->agg.pSearch = sqliteHashNext(p->agg.pSearch);
|
||||
rc = sqlite3BtreeNext(p->agg.pCsr, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
if( p->agg.pSearch==0 ){
|
||||
if( res!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
} else {
|
||||
}else{
|
||||
int i;
|
||||
sqlite3_context ctx;
|
||||
Mem *aMem;
|
||||
p->agg.pCurrent = sqliteHashData(p->agg.pSearch);
|
||||
|
||||
rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
|
||||
(char *)&p->agg.pCurrent);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
aMem = p->agg.pCurrent->aMem;
|
||||
for(i=0; i<p->agg.nMem; i++){
|
||||
int freeCtx;
|
||||
|
@ -223,9 +223,15 @@ 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 */
|
||||
#if 0
|
||||
HashElem *pSearch; /* The hash element for pCurrent */
|
||||
Hash hash; /* Hash table of all aggregate elements */
|
||||
FuncDef **apFunc; /* Information about aggregate functions */
|
||||
#endif
|
||||
Btree *pBtree; /* The temporary btree used to group elements */
|
||||
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 */
|
||||
@ -344,7 +350,7 @@ struct Vdbe {
|
||||
*/
|
||||
void sqlite3VdbeCleanupCursor(Cursor*);
|
||||
void sqlite3VdbeSorterReset(Vdbe*);
|
||||
void sqlite3VdbeAggReset(Agg*);
|
||||
int sqlite3VdbeAggReset(sqlite *, Agg *, KeyInfo *);
|
||||
void sqlite3VdbeKeylistFree(Keylist*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqlite3VdbeCursorMoveto(Cursor*);
|
||||
|
119
src/vdbeaux.c
119
src/vdbeaux.c
@ -651,8 +651,6 @@ void sqlite3VdbeMakeReady(
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3HashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
|
||||
p->agg.pSearch = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (p->db->flags & SQLITE_VdbeListing)!=0
|
||||
|| sqlite3OsFileExists("vdbe_explain")
|
||||
@ -711,6 +709,7 @@ void sqlite3VdbeSorterReset(Vdbe *p){
|
||||
** private context. If the finalizer has not been called yet, call it
|
||||
** now.
|
||||
*/
|
||||
#if 0
|
||||
void sqlite3VdbeAggReset(Agg *pAgg){
|
||||
int i;
|
||||
HashElem *p;
|
||||
@ -747,6 +746,120 @@ void sqlite3VdbeAggReset(Agg *pAgg){
|
||||
pAgg->pSearch = 0;
|
||||
pAgg->nMem = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){
|
||||
int i;
|
||||
int rc = 0;
|
||||
BtCursor *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( res!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pAgg->apFunc!=0 );
|
||||
for(i=0; i<pAgg->nMem; i++){
|
||||
Mem *pMem = &pElem->aMem[i];
|
||||
if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
|
||||
sqlite3_context ctx;
|
||||
ctx.pFunc = pAgg->apFunc[i];
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.pAgg = pMem->z;
|
||||
ctx.cnt = pMem->i;
|
||||
ctx.isStep = 0;
|
||||
ctx.isError = 0;
|
||||
(*pAgg->apFunc[i]->xFinalize)(&ctx);
|
||||
if( pMem->z!=0 && pMem->z!=pMem->z ){
|
||||
sqliteFree(pMem->z);
|
||||
}
|
||||
}else if( pMem->flags&MEM_Dyn ){
|
||||
sqliteFree(pMem->z);
|
||||
}
|
||||
}
|
||||
sqliteFree(pElem);
|
||||
rc=sqlite3BtreeNext(pCsr, &res);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
sqlite3BtreeCloseCursor(pCsr);
|
||||
sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3BtreeBeginTrans(pAgg->pBtree, 1, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Delete a keylist
|
||||
@ -839,7 +952,7 @@ static void Cleanup(Vdbe *p){
|
||||
p->zLine = 0;
|
||||
}
|
||||
p->nLineAlloc = 0;
|
||||
sqlite3VdbeAggReset(&p->agg);
|
||||
sqlite3VdbeAggReset(0, &p->agg, 0);
|
||||
if( p->keylistStack ){
|
||||
int ii;
|
||||
for(ii = 0; ii < p->keylistStackDepth; ii++){
|
||||
|
@ -49,7 +49,8 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
||||
int n;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3utfTranslate(pMem->z, pMem->n, pMem->enc, &z, &n, desiredEnc);
|
||||
rc = sqlite3utfTranslate(pMem->z, pMem->n, pMem->enc, (void **)&z,
|
||||
&n, desiredEnc);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
# focus of this file is testing aggregate functions and the
|
||||
# GROUP BY and HAVING clauses of SELECT statements.
|
||||
#
|
||||
# $Id: select3.test,v 1.10 2004/05/27 17:22:56 drh Exp $
|
||||
# $Id: select3.test,v 1.11 2004/06/11 13:19:22 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -78,7 +78,7 @@ do_test select3-2.7 {
|
||||
execsql {
|
||||
SELECT log*2+1 AS x, count(*) AS y FROM t1 GROUP BY x ORDER BY y
|
||||
}
|
||||
} {1 1 3 1 5 2 7 4 9 8 11 15}
|
||||
} {3 1 1 1 5 2 7 4 9 8 11 15}
|
||||
do_test select3-2.8 {
|
||||
execsql {
|
||||
SELECT log*2+1 AS x, count(*) AS y FROM t1 GROUP BY x ORDER BY 10-(x+y)
|
||||
|
Loading…
Reference in New Issue
Block a user