Rework the VDBE data structures to combine string representations into the
same structure with integer and floating point. This opens the door to significant optimizations. (CVS 1202) FossilOrigin-Name: c0faa1c67a967f028cd018e58988fb08bc814d3d
This commit is contained in:
+12
-8
@@ -16,7 +16,7 @@
|
||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.37 2004/01/19 04:53:25 jplyon Exp $
|
||||
** $Id: func.c,v 1.38 2004/01/30 14:49:17 drh Exp $
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
@@ -495,14 +495,16 @@ static void minStep(sqlite_func *context, int argc, const char **argv){
|
||||
if( p==0 || argc<1 || argv[0]==0 ) return;
|
||||
if( p->z==0 || sqliteCompare(argv[0],p->z)<0 ){
|
||||
int len;
|
||||
if( p->z && p->z!=p->zBuf ){
|
||||
if( !p->zBuf[0] ){
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
len = strlen(argv[0]);
|
||||
if( len < sizeof(p->zBuf) ){
|
||||
p->z = p->zBuf;
|
||||
if( len < sizeof(p->zBuf)-1 ){
|
||||
p->z = &p->zBuf[1];
|
||||
p->zBuf[0] = 1;
|
||||
}else{
|
||||
p->z = sqliteMalloc( len+1 );
|
||||
p->zBuf[0] = 0;
|
||||
if( p->z==0 ) return;
|
||||
}
|
||||
strcpy(p->z, argv[0]);
|
||||
@@ -514,14 +516,16 @@ static void maxStep(sqlite_func *context, int argc, const char **argv){
|
||||
if( p==0 || argc<1 || argv[0]==0 ) return;
|
||||
if( p->z==0 || sqliteCompare(argv[0],p->z)>0 ){
|
||||
int len;
|
||||
if( p->z && p->z!=p->zBuf ){
|
||||
if( !p->zBuf[0] ){
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
len = strlen(argv[0]);
|
||||
if( len < sizeof(p->zBuf) ){
|
||||
p->z = p->zBuf;
|
||||
if( len < sizeof(p->zBuf)-1 ){
|
||||
p->z = &p->zBuf[1];
|
||||
p->zBuf[0] = 1;
|
||||
}else{
|
||||
p->z = sqliteMalloc( len+1 );
|
||||
p->zBuf[0] = 0;
|
||||
if( p->z==0 ) return;
|
||||
}
|
||||
strcpy(p->z, argv[0]);
|
||||
@@ -533,7 +537,7 @@ static void minMaxFinalize(sqlite_func *context){
|
||||
if( p && p->z ){
|
||||
sqlite_set_result_string(context, p->z, strlen(p->z));
|
||||
}
|
||||
if( p && p->z && p->z!=p->zBuf ){
|
||||
if( p && !p->zBuf[0] ){
|
||||
sqliteFree(p->z);
|
||||
}
|
||||
}
|
||||
|
||||
+339
-344
File diff suppressed because it is too large
Load Diff
+23
-36
@@ -106,47 +106,35 @@ struct Sorter {
|
||||
#define NBFS 32
|
||||
|
||||
/*
|
||||
** A single level of the stack is an instance of the following
|
||||
** structure. Except, string values are stored on a separate
|
||||
** list of of pointers to character. The reason for storing
|
||||
** strings separately is so that they can be easily passed
|
||||
** to the callback function.
|
||||
*/
|
||||
struct Stack {
|
||||
int i; /* Integer value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
int flags; /* Some combination of STK_Null, STK_Str, STK_Dyn, etc. */
|
||||
double r; /* Real value */
|
||||
char z[NBFS]; /* Space for short strings */
|
||||
};
|
||||
typedef struct Stack Stack;
|
||||
|
||||
/*
|
||||
** Memory cells use the same structure as the stack except that space
|
||||
** for an arbitrary string is added.
|
||||
** A single level of the stack or a single memory cell
|
||||
** is an instance of the following structure.
|
||||
*/
|
||||
struct Mem {
|
||||
Stack s; /* All values of the memory cell besides string */
|
||||
char *z; /* String value for this memory cell */
|
||||
int i; /* Integer value */
|
||||
int n; /* Number of characters in string value, including '\0' */
|
||||
int flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
double r; /* Real value */
|
||||
char *z; /* String value */
|
||||
char zShort[NBFS]; /* Space for short strings */
|
||||
};
|
||||
typedef struct Mem Mem;
|
||||
|
||||
/*
|
||||
** Allowed values for Stack.flags
|
||||
** Allowed values for Mem.flags
|
||||
*/
|
||||
#define STK_Null 0x0001 /* Value is NULL */
|
||||
#define STK_Str 0x0002 /* Value is a string */
|
||||
#define STK_Int 0x0004 /* Value is an integer */
|
||||
#define STK_Real 0x0008 /* Value is a real number */
|
||||
#define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[] */
|
||||
#define STK_Static 0x0020 /* zStack[] points to a static string */
|
||||
#define STK_Ephem 0x0040 /* zStack[] points to an ephemeral string */
|
||||
#define MEM_Null 0x0001 /* Value is NULL */
|
||||
#define MEM_Str 0x0002 /* Value is a string */
|
||||
#define MEM_Int 0x0004 /* Value is an integer */
|
||||
#define MEM_Real 0x0008 /* Value is a real number */
|
||||
#define MEM_Dyn 0x0010 /* Need to call sqliteFree() on Mem.z */
|
||||
#define MEM_Static 0x0020 /* Mem.z points to a static string */
|
||||
#define MEM_Ephem 0x0040 /* Mem.z points to an ephemeral string */
|
||||
|
||||
/* The following STK_ value appears only in AggElem.aMem.s.flag fields.
|
||||
/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
|
||||
** It indicates that the corresponding AggElem.aMem.z points to a
|
||||
** aggregate function context that needs to be finalized.
|
||||
*/
|
||||
#define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */
|
||||
#define MEM_AggCtx 0x0040 /* Mem.z points to an agg function context */
|
||||
|
||||
/*
|
||||
** The "context" argument for a installable function. A pointer to an
|
||||
@@ -159,12 +147,11 @@ typedef struct Mem Mem;
|
||||
** structure are known.
|
||||
**
|
||||
** This structure is defined inside of vdbe.c because it uses substructures
|
||||
** (Stack) which are only defined there.
|
||||
** (Mem) which are only defined there.
|
||||
*/
|
||||
struct sqlite_func {
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
Stack s; /* Small strings, ints, and double values go here */
|
||||
char *z; /* Space for holding dynamic string results */
|
||||
Mem s; /* The return value is stored here */
|
||||
void *pAgg; /* Aggregate context */
|
||||
u8 isError; /* Set to true for an error */
|
||||
u8 isStep; /* Current in the step function */
|
||||
@@ -237,8 +224,8 @@ struct Vdbe {
|
||||
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
int tos; /* Index of top of stack */
|
||||
Stack *aStack; /* The operand stack, except string values */
|
||||
char **zStack; /* Text or binary values of the stack */
|
||||
Mem *aStack; /* The operand stack, except string values */
|
||||
char **zArgv; /* Text values used by the callback */
|
||||
char **azColName; /* Becomes the 4th parameter to callbacks */
|
||||
int nCursor; /* Number of slots in aCsr[] */
|
||||
Cursor *aCsr; /* One element of this array for each open cursor */
|
||||
@@ -294,7 +281,7 @@ struct Vdbe {
|
||||
*/
|
||||
#define POPSTACK \
|
||||
assert(p->tos>=0); \
|
||||
if( aStack[p->tos].flags & STK_Dyn ) sqliteFree(zStack[p->tos]); \
|
||||
if( aStack[p->tos].flags & MEM_Dyn ) sqliteFree(aStack[p->tos].z); \
|
||||
p->tos--;
|
||||
|
||||
/*
|
||||
|
||||
+44
-47
@@ -375,48 +375,48 @@ VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){
|
||||
*/
|
||||
char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){
|
||||
assert( !p->isStep );
|
||||
if( p->s.flags & STK_Dyn ){
|
||||
sqliteFree(p->z);
|
||||
if( p->s.flags & MEM_Dyn ){
|
||||
sqliteFree(p->s.z);
|
||||
}
|
||||
if( zResult==0 ){
|
||||
p->s.flags = STK_Null;
|
||||
p->s.flags = MEM_Null;
|
||||
n = 0;
|
||||
p->z = 0;
|
||||
p->s.z = 0;
|
||||
p->s.n = 0;
|
||||
}else{
|
||||
if( n<0 ) n = strlen(zResult);
|
||||
if( n<NBFS-1 ){
|
||||
memcpy(p->s.z, zResult, n);
|
||||
p->s.z[n] = 0;
|
||||
p->s.flags = STK_Str;
|
||||
p->z = p->s.z;
|
||||
memcpy(p->s.zShort, zResult, n);
|
||||
p->s.zShort[n] = 0;
|
||||
p->s.flags = MEM_Str;
|
||||
p->s.z = p->s.zShort;
|
||||
}else{
|
||||
p->z = sqliteMallocRaw( n+1 );
|
||||
if( p->z ){
|
||||
memcpy(p->z, zResult, n);
|
||||
p->z[n] = 0;
|
||||
p->s.z = sqliteMallocRaw( n+1 );
|
||||
if( p->s.z ){
|
||||
memcpy(p->s.z, zResult, n);
|
||||
p->s.z[n] = 0;
|
||||
}
|
||||
p->s.flags = STK_Str | STK_Dyn;
|
||||
p->s.flags = MEM_Str | MEM_Dyn;
|
||||
}
|
||||
p->s.n = n+1;
|
||||
}
|
||||
return p->z;
|
||||
return p->s.z;
|
||||
}
|
||||
void sqlite_set_result_int(sqlite_func *p, int iResult){
|
||||
assert( !p->isStep );
|
||||
if( p->s.flags & STK_Dyn ){
|
||||
sqliteFree(p->z);
|
||||
if( p->s.flags & MEM_Dyn ){
|
||||
sqliteFree(p->s.z);
|
||||
}
|
||||
p->s.i = iResult;
|
||||
p->s.flags = STK_Int;
|
||||
p->s.flags = MEM_Int;
|
||||
}
|
||||
void sqlite_set_result_double(sqlite_func *p, double rResult){
|
||||
assert( !p->isStep );
|
||||
if( p->s.flags & STK_Dyn ){
|
||||
sqliteFree(p->z);
|
||||
if( p->s.flags & MEM_Dyn ){
|
||||
sqliteFree(p->s.z);
|
||||
}
|
||||
p->s.r = rResult;
|
||||
p->s.flags = STK_Real;
|
||||
p->s.flags = MEM_Real;
|
||||
}
|
||||
void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){
|
||||
assert( !p->isStep );
|
||||
@@ -446,7 +446,8 @@ void *sqlite_aggregate_context(sqlite_func *p, int nByte){
|
||||
assert( p && p->pFunc && p->pFunc->xStep );
|
||||
if( p->pAgg==0 ){
|
||||
if( nByte<=NBFS ){
|
||||
p->pAgg = (void*)p->z;
|
||||
p->pAgg = (void*)p->s.z;
|
||||
memset(p->pAgg, 0, nByte);
|
||||
}else{
|
||||
p->pAgg = sqliteMalloc( nByte );
|
||||
}
|
||||
@@ -508,8 +509,8 @@ int sqliteVdbeList(
|
||||
assert( p->popStack==0 );
|
||||
assert( p->explain );
|
||||
p->azColName = azColumnNames;
|
||||
p->azResColumn = p->zStack;
|
||||
for(i=0; i<5; i++) p->zStack[i] = p->aStack[i].z;
|
||||
p->azResColumn = p->zArgv;
|
||||
for(i=0; i<5; i++) p->zArgv[i] = p->aStack[i].zShort;
|
||||
p->rc = SQLITE_OK;
|
||||
for(i=p->pc; p->rc==SQLITE_OK && i<p->nOp; i++){
|
||||
if( db->flags & SQLITE_Interrupt ){
|
||||
@@ -522,19 +523,19 @@ int sqliteVdbeList(
|
||||
sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), (char*)0);
|
||||
break;
|
||||
}
|
||||
sprintf(p->zStack[0],"%d",i);
|
||||
sprintf(p->zStack[2],"%d", p->aOp[i].p1);
|
||||
sprintf(p->zStack[3],"%d", p->aOp[i].p2);
|
||||
sprintf(p->zArgv[0],"%d",i);
|
||||
sprintf(p->zArgv[2],"%d", p->aOp[i].p1);
|
||||
sprintf(p->zArgv[3],"%d", p->aOp[i].p2);
|
||||
if( p->aOp[i].p3type==P3_POINTER ){
|
||||
sprintf(p->aStack[4].z, "ptr(%#x)", (int)p->aOp[i].p3);
|
||||
p->zStack[4] = p->aStack[4].z;
|
||||
sprintf(p->aStack[4].zShort, "ptr(%#x)", (int)p->aOp[i].p3);
|
||||
p->zArgv[4] = p->aStack[4].zShort;
|
||||
}else{
|
||||
p->zStack[4] = p->aOp[i].p3;
|
||||
p->zArgv[4] = p->aOp[i].p3;
|
||||
}
|
||||
p->zStack[1] = sqliteOpcodeNames[p->aOp[i].opcode];
|
||||
p->zArgv[1] = sqliteOpcodeNames[p->aOp[i].opcode];
|
||||
if( p->xCallback==0 ){
|
||||
p->pc = i+1;
|
||||
p->azResColumn = p->zStack;
|
||||
p->azResColumn = p->zArgv;
|
||||
p->nResColumn = 5;
|
||||
return SQLITE_ROW;
|
||||
}
|
||||
@@ -542,7 +543,7 @@ int sqliteVdbeList(
|
||||
p->rc = SQLITE_MISUSE;
|
||||
break;
|
||||
}
|
||||
if( p->xCallback(p->pCbArg, 5, p->zStack, p->azColName) ){
|
||||
if( p->xCallback(p->pCbArg, 5, p->zArgv, p->azColName) ){
|
||||
p->rc = SQLITE_ABORT;
|
||||
}
|
||||
if( sqliteSafetyOn(db) ){
|
||||
@@ -596,11 +597,11 @@ void sqliteVdbeMakeReady(
|
||||
assert( nVar>=0 );
|
||||
n = isExplain ? 10 : p->nOp;
|
||||
p->aStack = sqliteMalloc(
|
||||
n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) /* aStack and zStack */
|
||||
n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) /* aStack and zArgv */
|
||||
+ p->nVar*(sizeof(char*)+sizeof(int)+1) /* azVar, anVar, abVar */
|
||||
);
|
||||
p->zStack = (char**)&p->aStack[n];
|
||||
p->azColName = (char**)&p->zStack[n];
|
||||
p->zArgv = (char**)&p->aStack[n];
|
||||
p->azColName = (char**)&p->zArgv[n];
|
||||
p->azVar = (char**)&p->azColName[n];
|
||||
p->anVar = (int*)&p->azVar[p->nVar];
|
||||
p->abVar = (u8*)&p->anVar[p->nVar];
|
||||
@@ -656,15 +657,12 @@ void sqliteVdbeSorterReset(Vdbe *p){
|
||||
*/
|
||||
void sqliteVdbePopStack(Vdbe *p, int N){
|
||||
assert( N>=0 );
|
||||
if( p->zStack==0 ) return;
|
||||
assert( p->aStack || sqlite_malloc_failed );
|
||||
if( p->aStack==0 ) return;
|
||||
while( N-- > 0 ){
|
||||
if( p->aStack[p->tos].flags & STK_Dyn ){
|
||||
sqliteFree(p->zStack[p->tos]);
|
||||
if( p->aStack[p->tos].flags & MEM_Dyn ){
|
||||
sqliteFree(p->aStack[p->tos].z);
|
||||
}
|
||||
p->aStack[p->tos].flags = 0;
|
||||
p->zStack[p->tos] = 0;
|
||||
p->tos--;
|
||||
}
|
||||
}
|
||||
@@ -686,20 +684,19 @@ void sqliteVdbeAggReset(Agg *pAgg){
|
||||
assert( pAgg->apFunc!=0 );
|
||||
for(i=0; i<pAgg->nMem; i++){
|
||||
Mem *pMem = &pElem->aMem[i];
|
||||
if( pAgg->apFunc[i] && (pMem->s.flags & STK_AggCtx)!=0 ){
|
||||
if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
|
||||
sqlite_func ctx;
|
||||
ctx.pFunc = pAgg->apFunc[i];
|
||||
ctx.s.flags = STK_Null;
|
||||
ctx.z = 0;
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.pAgg = pMem->z;
|
||||
ctx.cnt = pMem->s.i;
|
||||
ctx.cnt = pMem->i;
|
||||
ctx.isStep = 0;
|
||||
ctx.isError = 0;
|
||||
(*pAgg->apFunc[i]->xFinalize)(&ctx);
|
||||
if( pMem->z!=0 && pMem->z!=pMem->s.z ){
|
||||
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
|
||||
sqliteFree(pMem->z);
|
||||
}
|
||||
}else if( pMem->s.flags & STK_Dyn ){
|
||||
}else if( pMem->flags & MEM_Dyn ){
|
||||
sqliteFree(pMem->z);
|
||||
}
|
||||
}
|
||||
@@ -765,7 +762,7 @@ static void Cleanup(Vdbe *p){
|
||||
closeAllCursors(p);
|
||||
if( p->aMem ){
|
||||
for(i=0; i<p->nMem; i++){
|
||||
if( p->aMem[i].s.flags & STK_Dyn ){
|
||||
if( p->aMem[i].flags & MEM_Dyn ){
|
||||
sqliteFree(p->aMem[i].z);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user