Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Have the vdbe aggregator use a btree table instead of a hash table. (CVS 1569) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8d56118f64dbaf8c8006266fa7026f90 |
User & Date: | danielk1977 2004-06-11 13:19:21.000 |
Context
2004-06-11
| ||
17:48 | Documentation of the new pager locking mechanism. (CVS 1570) (check-in: 13cf1ba825 user: drh tags: trunk) | |
13:19 | Have the vdbe aggregator use a btree table instead of a hash table. (CVS 1569) (check-in: 8d56118f64 user: danielk1977 tags: trunk) | |
10:51 | Fix various collation sequence issues. (CVS 1568) (check-in: 66835ee670 user: danielk1977 tags: trunk) | |
Changes
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.188 2004/06/11 13:19:21 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. |
︙ | ︙ | |||
2437 2438 2439 2440 2441 2442 2443 | } } } /* Reset the aggregator */ if( isAgg ){ | | > > > > > > > > > > > > > > > | 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 | } } } /* Reset the aggregator */ if( isAgg ){ 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 ){ 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{ int sz = sizeof(KeyInfo) + pGroupBy->nExpr*sizeof(CollSeq*); KeyInfo *pKey = (KeyInfo *)sqliteMalloc(sz); if( 0==pKey ){ goto select_end; } pKey->enc = pParse->db->enc; pKey->nField = pGroupBy->nExpr; for(i=0; i<pGroupBy->nExpr; i++){ pKey->aColl[i] = sqlite3ExprCollSeq(pParse, pGroupBy->a[i].pExpr); if( !pKey->aColl[i] ){ pKey->aColl[i] = pParse->db->pDfltColl; } } sqlite3VdbeChangeP3(v, addr, (char *)pKey, P3_KEYINFO_HANDOFF); } } /* Initialize the memory cell to NULL */ if( eDest==SRT_Mem ){ sqlite3VdbeAddOp(v, OP_String8, 0, 0); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.365 2004/06/11 13:19:21 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
156 157 158 159 160 161 162 | /* ** 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){ | | | | | | | > | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | /* ** 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; assert( 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; } /* ** 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); if( pElem==0 ){ AggInsert(p,"",1); pElem = sqliteHashFirst(&p->hash); } 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. */ static void popStack(Mem **ppTos, int N){ Mem *pTos = *ppTos; while( N>0 ){ |
︙ | ︙ | |||
1294 1295 1296 1297 1298 1299 1300 | ** immediately call the destructor for any non-static values. */ if( ctx.pVdbeFunc ){ int mask = pOp->p2; for(i=0; i<ctx.pVdbeFunc->nAux; i++){ struct AuxData *pAux = &ctx.pVdbeFunc->apAux[i]; if( (i>31 || !(mask&(1<<i))) && pAux->pAux ){ | > | > | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 | ** immediately call the destructor for any non-static values. */ if( ctx.pVdbeFunc ){ int mask = pOp->p2; for(i=0; i<ctx.pVdbeFunc->nAux; i++){ struct AuxData *pAux = &ctx.pVdbeFunc->apAux[i]; if( (i>31 || !(mask&(1<<i))) && pAux->pAux ){ if( pAux->xDelete ){ pAux->xDelete(pAux->pAux); } pAux->pAux = 0; } } pOp->p3 = (char *)ctx.pVdbeFunc; pOp->p3type = P3_VDBEFUNC; } |
︙ | ︙ | |||
4255 4256 4257 4258 4259 4260 4261 | pMem->i++; if( pOp->p2>0 && pMem->i>0 ){ pc = pOp->p2 - 1; } break; } | | | > > | > > > | 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 | pMem->i++; if( pOp->p2>0 && pMem->i>0 ){ pc = pOp->p2 - 1; } break; } /* Opcode: AggReset * 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. */ case OP_AggReset: { 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; break; } /* Opcode: AggInit * P2 P3 |
︙ | ︙ | |||
4352 4353 4354 4355 4356 4357 4358 | ** 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_AggFocus: { | < | | > > > | > | > > > | > | > | > | > | 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 | ** 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_AggFocus: { char *zKey; int nKey; int res; assert( pTos>=p->aStack ); Stringify(pTos, db->enc); zKey = pTos->z; nKey = pTos->n; 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{ rc = AggInsert(&p->agg, 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: { 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 ); Deephemeralize(pTos); pMem = &pFocus->aMem[i]; Release(pMem); *pMem = *pTos; |
︙ | ︙ | |||
4405 4406 4407 4408 4409 4410 4411 | /* Opcode: AggGet * 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. */ case OP_AggGet: { | | > > | 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 | /* Opcode: AggGet * 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. */ case OP_AggGet: { 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++; pMem = &pFocus->aMem[i]; *pTos = *pMem; if( pTos->flags & (MEM_Str|MEM_Blob) ){ pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); |
︙ | ︙ | |||
4436 4437 4438 4439 4440 4441 4442 4443 | ** 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: { CHECK_FOR_INTERRUPT; | > | | > > | > | | > > | > > > | 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 | ** 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: { int res; 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; }else{ rc = sqlite3BtreeNext(p->agg.pCsr, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; } if( res!=0 ){ pc = pOp->p2 - 1; }else{ int i; 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; } aMem = p->agg.pCurrent->aMem; for(i=0; i<p->agg.nMem; i++){ int freeCtx; if( p->agg.apFunc[i]==0 ) continue; if( p->agg.apFunc[i]->xFinalize==0 ) continue; ctx.s.flags = MEM_Null; ctx.s.z = aMem[i].zShort; |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
219 220 221 222 223 224 225 226 227 | ** 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 */ HashElem *pSearch; /* The hash element for pCurrent */ Hash hash; /* Hash table of all aggregate elements */ | > > < > > > > > | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | ** 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 */ #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 */ 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 */ }; |
︙ | ︙ | |||
340 341 342 343 344 345 346 | #define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ /* ** Function prototypes */ void sqlite3VdbeCleanupCursor(Cursor*); void sqlite3VdbeSorterReset(Vdbe*); | | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | #define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ /* ** Function prototypes */ void sqlite3VdbeCleanupCursor(Cursor*); void sqlite3VdbeSorterReset(Vdbe*); int sqlite3VdbeAggReset(sqlite *, Agg *, KeyInfo *); void sqlite3VdbeKeylistFree(Keylist*); void sqliteVdbePopStack(Vdbe*,int); int sqlite3VdbeCursorMoveto(Cursor*); #if !defined(NDEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, Op*); #endif int sqlite3VdbeSerialTypeLen(u32); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
647 648 649 650 651 652 653 | p->azColName = (char**)&p->apArg[n]; p->apVar = (Mem *)&p->azColName[n]; for(n=0; n<p->nVar; n++){ p->apVar[n].flags = MEM_Null; } } | < < | 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | p->azColName = (char**)&p->apArg[n]; p->apVar = (Mem *)&p->azColName[n]; for(n=0; n<p->nVar; n++){ p->apVar[n].flags = MEM_Null; } } #ifdef SQLITE_DEBUG if( (p->db->flags & SQLITE_VdbeListing)!=0 || sqlite3OsFileExists("vdbe_explain") ){ int i; printf("VDBE Program Listing:\n"); for(i=0; i<p->nOp; i++){ |
︙ | ︙ | |||
707 708 709 710 711 712 713 714 715 716 717 718 719 720 | ** ** 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. */ void sqlite3VdbeAggReset(Agg *pAgg){ int i; HashElem *p; for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){ AggElem *pElem = sqliteHashData(p); assert( pAgg->apFunc!=0 ); for(i=0; i<pAgg->nMem; i++){ | > | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | ** ** 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 0 void sqlite3VdbeAggReset(Agg *pAgg){ int i; HashElem *p; for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){ AggElem *pElem = sqliteHashData(p); assert( pAgg->apFunc!=0 ); for(i=0; i<pAgg->nMem; i++){ |
︙ | ︙ | |||
743 744 745 746 747 748 749 750 751 752 753 754 755 756 | sqlite3HashClear(&pAgg->hash); sqliteFree(pAgg->apFunc); pAgg->apFunc = 0; pAgg->pCurrent = 0; pAgg->pSearch = 0; pAgg->nMem = 0; } /* ** Delete a keylist */ void sqlite3VdbeKeylistFree(Keylist *p){ while( p ){ Keylist *pNext = p->pNext; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | sqlite3HashClear(&pAgg->hash); sqliteFree(pAgg->apFunc); pAgg->apFunc = 0; pAgg->pCurrent = 0; 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 */ void sqlite3VdbeKeylistFree(Keylist *p){ while( p ){ Keylist *pNext = p->pNext; |
︙ | ︙ | |||
835 836 837 838 839 840 841 | } p->nField = 0; if( p->zLine ){ sqliteFree(p->zLine); p->zLine = 0; } p->nLineAlloc = 0; | | | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 | } p->nField = 0; if( p->zLine ){ sqliteFree(p->zLine); p->zLine = 0; } p->nLineAlloc = 0; sqlite3VdbeAggReset(0, &p->agg, 0); if( p->keylistStack ){ int ii; for(ii = 0; ii < p->keylistStackDepth; ii++){ sqlite3VdbeKeylistFree(p->keylistStack[ii]); } sqliteFree(p->keylistStack); p->keylistStackDepth = 0; |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | /* If the current encoding does not match the desired encoding, then ** we will need to do some translation between encodings. */ char *z; int n; int rc; | | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | /* If the current encoding does not match the desired encoding, then ** we will need to do some translation between encodings. */ char *z; int n; int rc; rc = sqlite3utfTranslate(pMem->z, pMem->n, pMem->enc, (void **)&z, &n, desiredEnc); if( rc!=SQLITE_OK ){ return rc; } if( pMem->flags&MEM_Dyn ){ sqliteFree(pMem->z); } /* Result of sqlite3utfTranslate is currently always dynamically |
︙ | ︙ |
Changes to test/select3.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing aggregate functions and the # GROUP BY and HAVING clauses of SELECT statements. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing aggregate functions and the # GROUP BY and HAVING clauses of SELECT statements. # # $Id: select3.test,v 1.11 2004/06/11 13:19:22 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # do_test select3-1.0 { |
︙ | ︙ | |||
74 75 76 77 78 79 80 | SELECT log*2+1 as x, count(*) FROM t1 GROUP BY x ORDER BY x } } {1 1 3 1 5 2 7 4 9 8 11 15} do_test select3-2.7 { execsql { SELECT log*2+1 AS x, count(*) AS y FROM t1 GROUP BY x ORDER BY y } | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | SELECT log*2+1 as x, count(*) FROM t1 GROUP BY x ORDER BY x } } {1 1 3 1 5 2 7 4 9 8 11 15} do_test select3-2.7 { execsql { SELECT log*2+1 AS x, count(*) AS y FROM t1 GROUP BY x ORDER BY y } } {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) } } {11 15 9 8 7 4 5 2 3 1 1 1} do_test select3-2.9 { catchsql { |
︙ | ︙ |