diff --git a/manifest b/manifest index affa485fbb..ce103c06a2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sOP_Concat8\sopcode,\ssimilar\sin\sconcept\sto\sOP_String8.\s(CVS\s1648) -D 2004-06-21T09:06:42 +C Avoid\sopening\sa\stemp\stable\sfor\saggregate\squeries\swith\sno\sGROUP\sBY\sclause.\s(CVS\s1649) +D 2004-06-21T10:45:07 F Makefile.in d69d53c543518c1572ee0a8e8723d7e00bdb2266 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -28,7 +28,7 @@ F src/attach.c 05102e2e8ac43ce639d07b47a99c7772a62420e6 F src/auth.c 60db23b98bb94c8b0178180faaf49dc116674217 F src/btree.c 0cf8a52a57a7eb13d50719114ee1fa353e89d7d3 F src/btree.h 32f96abef464cf8765b23ca669acfe90d191fcc5 -F src/build.c b1180cfc82b29fae42f9eac84aa869f3f7e207a8 +F src/build.c ffcd0cd8cd8aac1a45d852c6364c6b5b07cd9dc4 F src/date.c b3e8b2bef1e3f2ce24e5b057203036defb18c3f1 F src/delete.c 19287dd204569519636a04eca2b66c49c26e9266 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 @@ -54,7 +54,7 @@ F src/parse.y 097438674976355a10cf177bd97326c548820b86 F src/pragma.c 0750e1c360647dbe0a991f16133b0fe5e42e5039 F src/printf.c 823b6a5cbedb6971a9e62f5d83204fe9b0be7c1b F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c 7305795965f7702c6d95fc023dee138b40e90d41 +F src/select.c f02a65af34231031896e8442161cb5251e191e75 F src/shell.c 24b641700c9d90f361fcfa4f432c5b4aff704e6d F src/sqlite.h.in a3d593016d1a1a514d7a26c8a353b58caf62e798 F src/sqliteInt.h b379bc549c9d812090d6c33ff5f229b34346ac0c @@ -71,11 +71,11 @@ F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a F src/utf.c 3a2596013e4b9582d075ca742de7f067ff7dee95 F src/util.c e31e35d3d76cab7a02045095064897eca49cbce3 F src/vacuum.c fcb930215a3f6c50087300782555f61ad11dd80c -F src/vdbe.c 78d675c104d917a3061218775dddc5283cfff49d +F src/vdbe.c 206ac8aa50978ff2870c3e53dc3564dff5ae8d33 F src/vdbe.h 2d87155e31e84bb00cdc48cc1ce6987a3a484250 -F src/vdbeInt.h 4d56da610923efa8d4c9db89dff17cb721e69a9b +F src/vdbeInt.h c0740932621a8d4aac20e0c4235ce44eb5e8dce6 F src/vdbeapi.c 8a9421341e09b506a934132c9015f26362ae8c0e -F src/vdbeaux.c 4e0d90a74e315194449e42e097d04028b521887b +F src/vdbeaux.c b89e05d8a1be4a27ba98c0ae369642c12a2cb44f F src/vdbemem.c 9359c53386e070fea9f5403cab0c6f0cfe36496b F src/where.c 6507074d8ce3f78e7a4cd33f667f11e62020553e F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 @@ -225,7 +225,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl af528563442e3039928f9018327a18157e53a44f F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 7a33daef5b49b1f2d89f27e0063372fe4f1702c8 -R 7ca92734bb4802e7f5046704b052bee6 +P bbd3e93348bc3a1178f5278c6cf0b82e75bbf642 +R 721de3571b9dffe04fab1715f24d4561 U danielk1977 -Z f888e07c9fa8c25fdc20925aefd11399 +Z c3a890995f7791045ca127dcbcc39544 diff --git a/manifest.uuid b/manifest.uuid index af75d5edab..a5fef3c17c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bbd3e93348bc3a1178f5278c6cf0b82e75bbf642 \ No newline at end of file +4d02df63496091a1e643601f84313f42130d6282 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 04b60a0a1e..8b43092869 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.228 2004/06/21 09:06:42 danielk1977 Exp $ +** $Id: build.c,v 1.229 2004/06/21 10:45:07 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -959,17 +959,20 @@ CollSeq *sqlite3FindCollSeq( return pColl; } +/* +** Invoke the 'collation needed' callback to request a collation sequence +** in the database text encoding of name zName, length nName. +** If the collation sequence +*/ static void callCollNeeded(sqlite *db, const char *zName, int nName){ - /* No collation sequence of this type for this encoding is registered. - ** Call the collation factory to see if it can supply us with one. - */ char const *zExternal = 0; assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( nName<0 ) nName = strlen(zName); if( db->xCollNeeded ){ zExternal = sqliteStrNDup(zName, nName); if( !zExternal ) return; - db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal); + db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal); + sqliteFree(zExternal); } if( db->xCollNeeded16 ){ sqlite3_value *pTmp = sqlite3GetTransientValue(db); @@ -980,12 +983,14 @@ static void callCollNeeded(sqlite *db, const char *zName, int nName){ } } +/* +** This routine is called if the collation factory fails to deliver a +** collation function in the best encoding but there may be other versions +** of this collation function (for other text encodings) available. Use one +** of these instead if they exist. Avoid a UTF-8 <-> UTF-16 conversion if +** possible. +*/ static int synthCollSeq(Parse *pParse, CollSeq *pColl){ - /* The collation factory failed to deliver a function but there may be - ** other versions of this collation function (for other text encodings) - ** available. Use one of these instead. Avoid a UTF-8 <-> UTF-16 - ** conversion if possible. - */ CollSeq *pColl2 = 0; char *z = pColl->zName; int n = strlen(z); @@ -1040,6 +1045,9 @@ static int synthCollSeq(Parse *pParse, CollSeq *pColl){ */ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ if( pColl && !pColl->xCmp ){ + /* No collation sequence of this type for this encoding is registered. + ** Call the collation factory to see if it can supply us with one. + */ callCollNeeded(pParse->db, pColl->zName, strlen(pColl->zName)); if( !pColl->xCmp && synthCollSeq(pParse, pColl) ){ return SQLITE_ERROR; diff --git a/src/select.c b/src/select.c index 1811f12491..9a7f762d8e 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.194 2004/06/21 07:36:32 danielk1977 Exp $ +** $Id: select.c,v 1.195 2004/06/21 10:45:09 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -2452,17 +2452,14 @@ int sqlite3Select( /* Reset the aggregator */ if( isAgg ){ - int addr = sqlite3VdbeAddOp(v, OP_AggReset, 0, pParse->nAgg); + 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 ){ sqlite3VdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_FUNCDEF); } } - if( pGroupBy==0 ){ - sqlite3VdbeAddOp(v, OP_String8, 0, 0); - sqlite3VdbeAddOp(v, OP_AggFocus, 0, 0); - }else{ + if( pGroupBy ){ int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*); KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz); if( 0==pKey ){ diff --git a/src/vdbe.c b/src/vdbe.c index df1303fcec..b8cd8507c9 100644 --- a/src/vdbe.c +++ b/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.383 2004/06/21 09:06:42 danielk1977 Exp $ +** $Id: vdbe.c,v 1.384 2004/06/21 10:45:09 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -170,11 +170,12 @@ static int AggInsert(Agg *p, char *zKey, int nKey){ memcpy(pElem->zKey, zKey, nKey); pElem->nKey = nKey; - assert( p->pCsr ); - rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*)); - if( rc!=SQLITE_OK ){ - sqliteFree(pElem); - return rc; + if( p->pCsr ){ + rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*)); + if( rc!=SQLITE_OK ){ + sqliteFree(pElem); + return rc; + } } for(i=0; inMem; i++){ @@ -4259,19 +4260,29 @@ case OP_MemIncr: { break; } -/* Opcode: AggReset * P2 P3 +/* Opcode: AggReset P1 P2 P3 ** ** Reset the aggregator 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: { assert( !pOp->p3 || pOp->p3type==P3_KEYINFO ); - rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3); + if( pOp->p1 ){ + rc = sqlite3VdbeAggReset(0, &p->agg, (KeyInfo *)pOp->p3); + p->agg.nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */ + AggInsert(&p->agg, 0, 0); + }else{ + rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3); + p->agg.nMem = pOp->p2; + } 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; break; @@ -4368,6 +4379,8 @@ case OP_AggFocus: { Stringify(pTos, db->enc); zKey = pTos->z; nKey = pTos->n; + assert( p->agg.pBtree ); + assert( p->agg.pCsr ); rc = sqlite3BtreeMoveto(p->agg.pCsr, zKey, nKey, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; @@ -4462,11 +4475,19 @@ case OP_AggNext: { CHECK_FOR_INTERRUPT; if( p->agg.searching==0 ){ p->agg.searching = 1; - rc = sqlite3BtreeFirst(p->agg.pCsr, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + if( p->agg.pCsr ){ + rc = sqlite3BtreeFirst(p->agg.pCsr, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + }else{ + res = 0; + } }else{ - rc = sqlite3BtreeNext(p->agg.pCsr, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + if( p->agg.pCsr ){ + rc = sqlite3BtreeNext(p->agg.pCsr, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + }else{ + res = 1; + } } if( res!=0 ){ pc = pOp->p2 - 1; @@ -4475,10 +4496,10 @@ case OP_AggNext: { sqlite3_context ctx; Mem *aMem; - rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*), - (char *)&p->agg.pCurrent); - if( rc!=SQLITE_OK ){ - goto abort_due_to_error; + if( p->agg.pCsr ){ + 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; iagg.nMem; i++){ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 5e71fdf778..f5b3673b64 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -238,11 +238,7 @@ 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 */ -#endif - Btree *pBtree; /* The temporary btree used to group elements */ + 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 */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 088f0d2eeb..823c0972f1 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -671,6 +671,35 @@ void sqlite3VdbeSorterReset(Vdbe *p){ } } +/* +** Free all resources allociated with AggElem pElem, an element of +** aggregate pAgg. +*/ +int freeAggElem(AggElem *pElem, Agg *pAgg){ + int i; + for(i=0; inMem; 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); + pMem->z = ctx.pAgg; + if( pMem->z!=0 && pMem->z!=pMem->zShort ){ + sqliteFree(pMem->z); + } + sqlite3VdbeMemRelease(&ctx.s); + }else{ + sqlite3VdbeMemRelease(pMem); + } + } + sqliteFree(pElem); +} + /* ** Reset an Agg structure. Delete all its contents. ** @@ -715,27 +744,7 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){ return rc; } assert( pAgg->apFunc!=0 ); - for(i=0; inMem; 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); - pMem->z = ctx.pAgg; - if( pMem->z!=0 && pMem->z!=pMem->zShort ){ - sqliteFree(pMem->z); - } - sqlite3VdbeMemRelease(&ctx.s); - }else{ - sqlite3VdbeMemRelease(pMem); - } - } - sqliteFree(pElem); + freeAggElem(pElem, pAgg); rc=sqlite3BtreeNext(pCsr, &res); } if( rc!=SQLITE_OK ){ @@ -744,6 +753,13 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){ 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 @@ -1313,9 +1329,9 @@ int sqlite3VdbeFinalize(Vdbe *p){ /* ** Call the destructor for each auxdata entry in pVdbeFunc for which -** the corresponding bit in mask is set. Auxdata entries beyond 31 +** the corresponding bit in mask is clear. Auxdata entries beyond 31 ** are always destroyed. To destroy all auxdata entries, call this -** routine with mask==-1. +** routine with mask==0. */ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){ int i; @@ -1358,7 +1374,7 @@ void sqlite3VdbeDelete(Vdbe *p){ } if( pOp->p3type==P3_VDBEFUNC ){ VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3; - sqlite3VdbeDeleteAuxData(pVdbeFunc, -1); + sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); sqliteFree(pVdbeFunc); } #ifndef NDEBUG