Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Cleanup the processing of MEM_Agg elements. (CVS 2660) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
7ecf3654aa9a275a4cf0c3ec5f63a8c1 |
User & Date: | drh 2005-09-06 20:36:49.000 |
Context
2005-09-06
| ||
21:40 | Changes to reduce the amount of stack space required. (CVS 2661) (check-in: b86bd70f30 user: drh tags: trunk) | |
20:36 | Cleanup the processing of MEM_Agg elements. (CVS 2660) (check-in: 7ecf3654aa user: drh tags: trunk) | |
10:26 | Fix ANALYZE so that it works even if the empty_result_callbacks pragma is enabled. Ticket #1409. (CVS 2659) (check-in: bfdaef1224 user: drh tags: trunk) | |
Changes
Changes to src/func.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** ** $Id: func.c,v 1.107 2005/09/06 20:36:49 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include <math.h> #include <stdlib.h> #include <assert.h> #include "vdbeInt.h" |
︙ | ︙ | |||
831 832 833 834 835 836 837 | if( p && SQLITE_NULL!=sqlite3_value_type(argv[0]) ){ p->sum += sqlite3_value_double(argv[0]); p->cnt++; } } static void sumFinalize(sqlite3_context *context){ SumCtx *p; | | | | 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | if( p && SQLITE_NULL!=sqlite3_value_type(argv[0]) ){ p->sum += sqlite3_value_double(argv[0]); p->cnt++; } } static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); sqlite3_result_double(context, p ? p->sum : 0.0); } static void avgFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ sqlite3_result_double(context, p->sum/(double)p->cnt); } } /* ** An instance of the following structure holds the context of a |
︙ | ︙ | |||
874 875 876 877 878 879 880 | p = sqlite3_aggregate_context(context, sizeof(*p)); if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ p->n++; } } static void countFinalize(sqlite3_context *context){ CountCtx *p; | | | 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | p = sqlite3_aggregate_context(context, sizeof(*p)); if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ p->n++; } } static void countFinalize(sqlite3_context *context){ CountCtx *p; p = sqlite3_aggregate_context(context, 0); sqlite3_result_int(context, p ? p->n : 0); } /* ** Routines to implement min() and max() aggregate functions. */ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv){ |
︙ | ︙ | |||
912 913 914 915 916 917 918 | } }else{ sqlite3VdbeMemCopy(pBest, pArg); } } static void minMaxFinalize(sqlite3_context *context){ sqlite3_value *pRes; | | > | | | | > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | } }else{ sqlite3VdbeMemCopy(pBest, pArg); } } static void minMaxFinalize(sqlite3_context *context){ sqlite3_value *pRes; pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); if( pRes ){ if( pRes->flags ){ sqlite3_result_value(context, pRes); } sqlite3VdbeMemRelease(pRes); } } /* ** This function registered all of the above C functions as SQL ** functions. This should be the only routine in this file with ** external linkage. |
︙ | ︙ |
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.481 2005/09/06 20:36:49 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
4274 4275 4276 4277 4278 4279 4280 | 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; | | < | < < < | 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 | 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]; pMem->n++; ctx.isError = 0; ctx.pColl = 0; if( ctx.pFunc->needCollSeq ){ assert( pOp>p->aOp ); assert( pOp[-1].p3type==P3_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); ctx.pColl = (CollSeq *)pOp[-1].p3; } (ctx.pFunc->xStep)(&ctx, n, apVal); popStack(&pTos, n+1); if( ctx.isError ){ rc = SQLITE_ERROR; } break; } |
︙ | ︙ | |||
4432 4433 4434 4435 4436 4437 4438 | } } if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res!=0 ){ pc = pOp->p2 - 1; }else{ int i; | < < < < < < < | < < < < < < < < | 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 | } } 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 * * * ** |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
110 111 112 113 114 115 116 | ** ** Each value has a manifest type. The manifest type of the value stored ** in a Mem struct is returned by the MemType(Mem*) macro. The type is ** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or ** SQLITE_BLOB. */ struct Mem { | | > > < < | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | ** ** Each value has a manifest type. The manifest type of the value stored ** in a Mem struct is returned by the MemType(Mem*) macro. The type is ** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or ** SQLITE_BLOB. */ struct Mem { i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */ double r; /* Real value */ char *z; /* String or BLOB value */ int n; /* Number of characters in string value, including '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 type; /* One of MEM_Null, MEM_Str, etc. */ u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ char zShort[NBFS]; /* Space for short strings */ }; typedef struct Mem Mem; /* One or more of the following flags are set to indicate the validOK ** representations of the value stored in the Mem struct. |
︙ | ︙ | |||
153 154 155 156 157 158 159 | ** string is \000 or \u0000 terminated */ #define MEM_Term 0x0020 /* String rep is nul terminated */ #define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ #define MEM_Static 0x0080 /* Mem.z points to a static string */ #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ #define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ | < < < < < | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ** string is \000 or \u0000 terminated */ #define MEM_Term 0x0020 /* String rep is nul terminated */ #define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ #define MEM_Static 0x0080 /* Mem.z points to a static string */ #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ #define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ #define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains ** additional information about auxiliary information bound to arguments ** of the function. This is used to implement the sqlite3_get_auxdata() ** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data ** that can be associated with a constant argument to a function. This |
︙ | ︙ | |||
190 191 192 193 194 195 196 | ** implement the SQL functions. ** ** There is a typedef for this structure in sqlite.h. So all routines, ** even the public interface to SQLite, can use a pointer to this structure. ** But this file is the only place where the internal details of this ** structure are known. ** | | | | | | < | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | ** implement the SQL functions. ** ** There is a typedef for this structure in sqlite.h. So all routines, ** even the public interface to SQLite, can use a pointer to this structure. ** But this file is the only place where the internal details of this ** structure are known. ** ** This structure is defined inside of vdbeInt.h because it uses substructures ** (Mem) which are only defined there. */ struct sqlite3_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ u8 isError; /* Set to true for an error */ 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 |
︙ | ︙ | |||
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | int sqlite3VdbeMemStringify(Mem*, int); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*, u8); int sqlite3VdbeOpcodeNoPush(u8); #endif int sqlite3VdbeMemTranslate(Mem*, u8); void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf); int sqlite3VdbeMemHandleBom(Mem *pMem); void sqlite3VdbeFifoInit(Fifo*); int sqlite3VdbeFifoPush(Fifo*, i64); int sqlite3VdbeFifoPop(Fifo*, i64*); void sqlite3VdbeFifoClear(Fifo*); | > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | int sqlite3VdbeMemStringify(Mem*, int); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*, u8); int sqlite3VdbeOpcodeNoPush(u8); #endif int sqlite3VdbeMemTranslate(Mem*, u8); void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf); int sqlite3VdbeMemHandleBom(Mem *pMem); void sqlite3VdbeFifoInit(Fifo*); int sqlite3VdbeFifoPush(Fifo*, i64); int sqlite3VdbeFifoPop(Fifo*, i64*); void sqlite3VdbeFifoClear(Fifo*); |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
254 255 256 257 258 259 260 | /* ** Allocate or return the aggregate context for a user function. A new ** context is allocated on the first call. Subsequent calls return the ** same context that was returned on prior calls. */ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ assert( p && p->pFunc && p->pFunc->xStep ); | | > > > | | | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | /* ** Allocate or return the aggregate context for a user function. A new ** context is allocated on the first call. Subsequent calls return the ** same context that was returned on prior calls. */ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ assert( p && p->pFunc && p->pFunc->xStep ); Mem *pMem = p->pMem; if( (pMem->flags & MEM_Agg)==0 && nByte>0 ){ pMem->flags = MEM_Agg; *(FuncDef**)&pMem->i = p->pFunc; if( nByte<=NBFS ){ pMem->z = pMem->zShort; memset(pMem->z, 0, nByte); }else{ pMem->z = sqliteMalloc( nByte ); } } return (void*)pMem->z; } /* ** Return the auxilary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ |
︙ | ︙ | |||
321 322 323 324 325 326 327 | ** ** This routine is defined here in vdbe.c because it depends on knowing ** the internals of the sqlite3_context structure which is only defined in ** this source file. */ int sqlite3_aggregate_count(sqlite3_context *p){ assert( p && p->pFunc && p->pFunc->xStep ); | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | ** ** This routine is defined here in vdbe.c because it depends on knowing ** the internals of the sqlite3_context structure which is only defined in ** this source file. */ int sqlite3_aggregate_count(sqlite3_context *p){ assert( p && p->pFunc && p->pFunc->xStep ); return p->pMem->n; } /* ** Return the number of columns in the result set for the statement pStmt. */ int sqlite3_column_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
772 773 774 775 776 777 778 | ** 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]; | | < | < < < < < < < < | < < | | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | ** 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. ** |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
182 183 184 185 186 187 188 189 190 191 192 193 194 195 | pMem->n = strlen(z); pMem->z = z; pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str | MEM_Short | MEM_Term; sqlite3VdbeChangeEncoding(pMem, enc); return rc; } /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and ** (Mem.type==SQLITE_TEXT). */ void sqlite3VdbeMemRelease(Mem *p){ | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > | 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 233 234 | pMem->n = strlen(z); pMem->z = z; pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str | MEM_Short | MEM_Term; sqlite3VdbeChangeEncoding(pMem, enc); return rc; } /* ** Memory cell pMem contains the context of an aggregate function. ** 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; } } } /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and ** (Mem.type==SQLITE_TEXT). */ void sqlite3VdbeMemRelease(Mem *p){ if( p->flags & (MEM_Dyn|MEM_Agg) ){ if( p->xDel ){ if( p->flags & MEM_Agg ){ sqlite3VdbeMemFinalize(p, (FuncDef*)&p->i); assert( (p->flags & MEM_Agg)==0 ); sqlite3VdbeMemRelease(p); }else{ p->xDel((void *)p->z); } }else{ sqliteFree(p->z); } p->z = 0; p->xDel = 0; } } |
︙ | ︙ |