SQLite

Check-in [1e037eb303]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Code for user-defined aggregates added. Legacy tests all pass but there has been no testing of the new user-defined aggregate code. (CVS 392)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1e037eb303d8508cb2ea3418e71b03315d895fbd
User & Date: drh 2002-02-24 03:25:15.000
Context
2002-02-24
17:12
Added a "stddev()" aggregate function for testing the new user aggregate function interface. (CVS 393) (check-in: 2198109712 user: drh tags: trunk)
03:25
Code for user-defined aggregates added. Legacy tests all pass but there has been no testing of the new user-defined aggregate code. (CVS 392) (check-in: 1e037eb303 user: drh tags: trunk)
01:55
Move the build-in function definitions into a new source file "func.c". (CVS 391) (check-in: 530b0f4f2d user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
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 routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.43 2002/02/23 23:45:45 drh Exp $
*/
#include "sqliteInt.h"


/*
** Construct a new expression node and return a pointer to it.  Memory
** for this node is obtained from sqliteMalloc().  The calling function







|







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 routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.44 2002/02/24 03:25:15 drh Exp $
*/
#include "sqliteInt.h"


/*
** Construct a new expression node and return a pointer to it.  Memory
** for this node is obtained from sqliteMalloc().  The calling function
1253
1254
1255
1256
1257
1258
1259






1260
1261
1262
1263
1264
1265
1266
        }
      }
      if( i>=pParse->nAgg ){
        i = appendAggInfo(pParse);
        if( i<0 ) return 1;
        pParse->aAgg[i].isAgg = 1;
        pParse->aAgg[i].pExpr = pExpr;






      }
      pExpr->iAgg = i;
      break;
    }
    default: {
      if( pExpr->pLeft ){
        nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pLeft);







>
>
>
>
>
>







1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
        }
      }
      if( i>=pParse->nAgg ){
        i = appendAggInfo(pParse);
        if( i<0 ) return 1;
        pParse->aAgg[i].isAgg = 1;
        pParse->aAgg[i].pExpr = pExpr;
        if( pExpr->iColumn==FN_Unknown ){
          pParse->aAgg[i].pUser = sqliteFindUserFunction(pParse->db,
             pExpr->token.z, pExpr->token.n, pExpr->pList->nExpr, 0);
        }else{
          pParse->aAgg[i].pUser = 0;
        }
      }
      pExpr->iAgg = i;
      break;
    }
    default: {
      if( pExpr->pLeft ){
        nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pLeft);
Changes to src/select.c.
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.65 2002/02/23 02:32:10 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/







|







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.66 2002/02/24 03:25:16 drh Exp $
*/
#include "sqliteInt.h"

/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
1097
1098
1099
1100
1101
1102
1103







1104
1105
1106
1107
1108
1109
1110
    generateColumnNames(pParse, pTabList, pEList);
  }

  /* Reset the aggregator
  */
  if( isAgg ){
    sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);







    if( pGroupBy==0 ){
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      sqliteVdbeAddOp(v, OP_AggFocus, 0, 0);
      for(i=0; i<pParse->nAgg; i++){
        Expr *pE;
        if( !pParse->aAgg[i].isAgg ) continue;
        pE = pParse->aAgg[i].pExpr;







>
>
>
>
>
>
>







1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
    generateColumnNames(pParse, pTabList, pEList);
  }

  /* Reset the aggregator
  */
  if( isAgg ){
    sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg);
    for(i=0; i<pParse->nAgg; i++){
      UserFunc *pUser;
      if( (pUser = pParse->aAgg[i].pUser)!=0 && pUser->xFinalize!=0 ){
        sqliteVdbeAddOp(v, OP_AggFinalizer, 0, i);
        sqliteVdbeChangeP3(v, -1, (char*)pUser->xFinalize, P3_POINTER);
      }
    }
    if( pGroupBy==0 ){
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      sqliteVdbeAddOp(v, OP_AggFocus, 0, 0);
      for(i=0; i<pParse->nAgg; i++){
        Expr *pE;
        if( !pParse->aAgg[i].isAgg ) continue;
        pE = pParse->aAgg[i].pExpr;
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176

1177

1178
1179
1180
1181
1182
1183

1184

1185






1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
        sqliteExprCode(pParse, pParse->aAgg[i].pExpr);
        sqliteVdbeAddOp(v, OP_AggSet, 0, i);
      }
      sqliteVdbeResolveLabel(v, lbl1);
    }
    for(i=0; i<pParse->nAgg; i++){
      Expr *pE;
      int op;
      if( !pParse->aAgg[i].isAgg ) continue;
      pE = pParse->aAgg[i].pExpr;
      if( pE==0 ){
        sqliteVdbeAddOp(v, OP_AggIncr, 1, i);
        continue;
      }
      assert( pE->op==TK_AGG_FUNCTION );
      assert( pE->pList!=0 && pE->pList->nExpr==1 );

      sqliteExprCode(pParse, pE->pList->a[0].pExpr);

      sqliteVdbeAddOp(v, OP_AggGet, 0, i);
      switch( pE->iColumn ){
        case FN_Min:  op = OP_Min;   break;
        case FN_Max:  op = OP_Max;   break;
        case FN_Avg:  op = OP_Add;   break;
        case FN_Sum:  op = OP_Add;   break;

      }

      sqliteVdbeAddOp(v, op, 0, 0);






      sqliteVdbeAddOp(v, OP_AggSet, 0, i);
    }
  }


  /* End the database scan loop.
  */
  sqliteWhereEnd(pWInfo);

  /* If we are processing aggregates, we need to set up a second loop
  ** over all of the aggregate values and process them.







|







|
>
|
>


|
|
|
|
>

>
|
>
>
>
>
>
>



<







1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205

1206
1207
1208
1209
1210
1211
1212
        sqliteExprCode(pParse, pParse->aAgg[i].pExpr);
        sqliteVdbeAddOp(v, OP_AggSet, 0, i);
      }
      sqliteVdbeResolveLabel(v, lbl1);
    }
    for(i=0; i<pParse->nAgg; i++){
      Expr *pE;
      int op, j;
      if( !pParse->aAgg[i].isAgg ) continue;
      pE = pParse->aAgg[i].pExpr;
      if( pE==0 ){
        sqliteVdbeAddOp(v, OP_AggIncr, 1, i);
        continue;
      }
      assert( pE->op==TK_AGG_FUNCTION );
      assert( pE->pList!=0 );
      for(j=0; j<pE->pList->nExpr; j++){
        sqliteExprCode(pParse, pE->pList->a[j].pExpr);
      }
      sqliteVdbeAddOp(v, OP_AggGet, 0, i);
      switch( pE->iColumn ){
        case FN_Min:      op = OP_Min;     break;
        case FN_Max:      op = OP_Max;     break;
        case FN_Avg:      op = OP_Add;     break;
        case FN_Sum:      op = OP_Add;     break;
        case FN_Unknown:  op = OP_AggFunc; break;
      }
      if( op!=OP_AggFunc ){
        sqliteVdbeAddOp(v, op, 0, 0);
      }else{
        sqliteVdbeAddOp(v, OP_AggFunc, 0, pE->pList->nExpr);
        assert( pParse->aAgg[i].pUser!=0 );
        assert( pParse->aAgg[i].pUser->xStep!=0 );
        sqliteVdbeChangeP3(v,-1,(char*)pParse->aAgg[i].pUser->xStep,P3_POINTER);
      }
      sqliteVdbeAddOp(v, OP_AggSet, 0, i);
    }
  }


  /* End the database scan loop.
  */
  sqliteWhereEnd(pWInfo);

  /* If we are processing aggregates, we need to set up a second loop
  ** over all of the aggregate values and process them.
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.92 2002/02/24 01:55:17 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.93 2002/02/24 03:25:16 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
505
506
507
508
509
510
511

512
513
514
515
516
517
518
** up.  Do not try to delete the expression attached to AggExpr.pExpr.
**
** If AggExpr.pExpr==0, that means the expression is "count(*)".
*/
struct AggExpr {
  int isAgg;        /* if TRUE contains an aggregate function */
  Expr *pExpr;      /* The expression */

};

/*
** An SQL parser context.  A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
*/







>







505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
** up.  Do not try to delete the expression attached to AggExpr.pExpr.
**
** If AggExpr.pExpr==0, that means the expression is "count(*)".
*/
struct AggExpr {
  int isAgg;        /* if TRUE contains an aggregate function */
  Expr *pExpr;      /* The expression */
  UserFunc *pUser;  /* User-defined aggregate function */
};

/*
** An SQL parser context.  A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
*/
Changes to src/vdbe.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.122 2002/02/23 23:45:45 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.123 2002/02/24 03:25:16 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
134
135
136
137
138
139
140






141
142
143
144
145
146
147
#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 */







/*
** The "context" argument for a user-defined function.
*/
struct UserFuncContext {
  Stack s;       /* Small string, integer, and floating point values go here */
  char *z;       /* Space for holding dynamic string results */
  int isError;   /* Set to true for an error */







>
>
>
>
>
>







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#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 */

/* The following STK_ value appears only in AggElem.aMem.s.flag fields.
** It indicates that the corresponding AggElem.aMem.z points to a
** user-defined aggregate context that needs to be finalized.
*/
#define STK_AggCtx    0x0040   /* zStack[] points to an user function context */

/*
** The "context" argument for a user-defined function.
*/
struct UserFuncContext {
  Stack s;       /* Small string, integer, and floating point values go here */
  char *z;       /* Space for holding dynamic string results */
  int isError;   /* Set to true for an error */
158
159
160
161
162
163
164

165
166
167
168
169
170
171
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 */

};
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 */
};








>







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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 */
  void (**axFinalize)(void*,void*);  /* Array of nMem finalizers */
};
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 */
};

573
574
575
576
577
578
579

580
581
582


583
584
585
586
587


588
589
590
591
592
593
594
** Reset an Agg structure.  Delete all its contents.
*/
static void AggReset(Agg *pAgg){
  int i;
  HashElem *p;
  for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){
    AggElem *pElem = sqliteHashData(p);

    for(i=0; i<pAgg->nMem; i++){
      if( pElem->aMem[i].s.flags & STK_Dyn ){
        sqliteFree(pElem->aMem[i].z);


      }
    }
    sqliteFree(pElem);
  }
  sqliteHashClear(&pAgg->hash);


  pAgg->pCurrent = 0;
  pAgg->pSearch = 0;
  pAgg->nMem = 0;
}

/*
** Insert a new element and make it the current element.  







>



>
>





>
>







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
** Reset an Agg structure.  Delete all its contents.
*/
static void AggReset(Agg *pAgg){
  int i;
  HashElem *p;
  for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){
    AggElem *pElem = sqliteHashData(p);
    assert( pAgg->axFinalize!=0 );
    for(i=0; i<pAgg->nMem; i++){
      if( pElem->aMem[i].s.flags & STK_Dyn ){
        sqliteFree(pElem->aMem[i].z);
      }else if( pAgg->axFinalize[i] && (pElem->aMem[i].s.flags & STK_AggCtx) ){
        (pAgg->axFinalize[i])((void*)pElem->aMem[i].z, 0);
      }
    }
    sqliteFree(pElem);
  }
  sqliteHashClear(&pAgg->hash);
  sqliteFree(pAgg->axFinalize);
  pAgg->axFinalize = 0;
  pAgg->pCurrent = 0;
  pAgg->pSearch = 0;
  pAgg->nMem = 0;
}

/*
** Insert a new element and make it the current element.  
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971

972
973
974
975
976
977
978
  "Clear",             "CreateIndex",       "CreateTable",       "IntegrityCk",
  "IdxPut",            "IdxDelete",         "IdxRecno",          "IdxGT",
  "IdxGE",             "MemLoad",           "MemStore",          "ListWrite",
  "ListRewind",        "ListRead",          "ListReset",         "SortPut",
  "SortMakeRec",       "SortMakeKey",       "Sort",              "SortNext",
  "SortCallback",      "SortReset",         "FileOpen",          "FileRead",
  "FileColumn",        "AggReset",          "AggFocus",          "AggIncr",
  "AggNext",           "AggSet",            "AggGet",            "SetInsert",
  "SetFound",          "SetNotFound",       "MakeRecord",        "MakeKey",
  "MakeIdxKey",        "IncrKey",           "Goto",              "If",
  "Halt",              "ColumnCount",       "ColumnName",        "Callback",
  "NullCallback",      "Integer",           "String",            "Pop",
  "Dup",               "Pull",              "Push",              "MustBeInt",
  "Add",               "AddImm",            "Subtract",          "Multiply",
  "Divide",            "Remainder",         "BitAnd",            "BitOr",
  "BitNot",            "ShiftLeft",         "ShiftRight",        "AbsValue",
  "Precision",         "Min",               "Max",               "Like",
  "Glob",              "Eq",                "Ne",                "Lt",
  "Le",                "Gt",                "Ge",                "IsNull",
  "NotNull",           "Negative",          "And",               "Or",
  "Not",               "Concat",            "Noop",              "Strlen",
  "Substr",            "UserFunc",          "UserAgg",           "Limit",

};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
  "Clear",             "CreateIndex",       "CreateTable",       "IntegrityCk",
  "IdxPut",            "IdxDelete",         "IdxRecno",          "IdxGT",
  "IdxGE",             "MemLoad",           "MemStore",          "ListWrite",
  "ListRewind",        "ListRead",          "ListReset",         "SortPut",
  "SortMakeRec",       "SortMakeKey",       "Sort",              "SortNext",
  "SortCallback",      "SortReset",         "FileOpen",          "FileRead",
  "FileColumn",        "AggReset",          "AggFocus",          "AggIncr",
  "AggNext",           "AggSet",            "AggGet",            "AggFinalizer",
  "AggFunc",           "SetInsert",         "SetFound",          "SetNotFound",
  "MakeRecord",        "MakeKey",           "MakeIdxKey",        "IncrKey",
  "Goto",              "If",                "Halt",              "ColumnCount",
  "ColumnName",        "Callback",          "NullCallback",      "Integer",
  "String",            "Pop",               "Dup",               "Pull",
  "Push",              "MustBeInt",         "Add",               "AddImm",
  "Subtract",          "Multiply",          "Divide",            "Remainder",
  "BitAnd",            "BitOr",             "BitNot",            "ShiftLeft",
  "ShiftRight",        "AbsValue",          "Precision",         "Min",
  "Max",               "Like",              "Glob",              "Eq",
  "Ne",                "Lt",                "Le",                "Gt",
  "Ge",                "IsNull",            "NotNull",           "Negative",
  "And",               "Or",                "Not",               "Concat",
  "Noop",              "Strlen",            "Substr",            "UserFunc",
  "Limit",           
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
4296
4297
4298
4299
4300
4301
4302

























































4303
4304
4305
4306
4307
4308
4309
**
** Reset the aggregator so that it no longer contains any data.
** Future aggregator elements will contain P2 values each.
*/
case OP_AggReset: {
  AggReset(&p->agg);
  p->agg.nMem = pOp->p2;

























































  break;
}

/* Opcode: AggFocus * P2 *
**
** Pop the top of the stack and use that as an aggregator key.  If
** an aggregator with that same key already exists, then make the







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
**
** Reset the aggregator so that it no longer contains any data.
** Future aggregator elements will contain P2 values each.
*/
case OP_AggReset: {
  AggReset(&p->agg);
  p->agg.nMem = pOp->p2;
  p->agg.axFinalize = sqliteMalloc( p->agg.nMem*sizeof(p->agg.axFinalize[0]) );
  break;
}

/* Opcode: AggFinalizer * P2 P3
**
** Register a finializer function for the P2-th column of the aggregate.
** The P3 parameter is a pointer to the finalizer.
** There should be one instance of this opcode immediately following
** each AggReset for each user defined aggregate function that is used
** in a SELECT.
**
** All finalizers must be registered so that user-defined aggregate
** function contexts can be deallocated if the VDBE aborts.
*/
case OP_AggFinalizer: {
  int i = pOp->p2;
  VERIFY( if( p->agg.nMem<=i ) goto bad_instruction; );
  p->agg.axFinalize[i] = (void(*)(void*,void*))pOp->p3;
  break;
}

/* Opcode: AggFunc * P2 P3
**
** Execute the step function for a user-defined aggregate.  The
** function has P2 arguments.  P3 is a pointer to the step function.
**
** The top of the stack should be the function context.  The P2
** parameters occur below the function context on the stack.  The
** revised function context remains on the stack after this op-code
** finishes.
*/
case OP_AggFunc: {
  int n = pOp->p2;
  int i;
  void *pCtx;
  void *(*xStep)(void*,int,const char**);

  if( aStack[p->tos].flags & STK_AggCtx ){
    pCtx = zStack[p->tos];
  }else{
    pCtx = 0;
  }
  VERIFY( if( n<=0 ) goto bad_instruction; )
  VERIFY( if( p->tos+1<n ) goto not_enough_stack; )
  for(i=p->tos-n; i<p->tos; i++){
    if( (aStack[i].flags & STK_Null)==0 ){
      if( Stringify(p, i) ) goto no_mem;
    }
  }
  xStep = (void*(*)(void*,int,const char**))pOp->p3;
  pCtx = xStep(pCtx, n, (const char**)&zStack[p->tos-n]);
  PopStack(p, n+1);
  VERIFY( NeedStack(p, p->tos+1); )
  p->tos++;
  aStack[p->tos].flags = STK_AggCtx;
  zStack[p->tos] = (char*)pCtx;
  break;
}

/* Opcode: AggFocus * P2 *
**
** Pop the top of the stack and use that as an aggregator key.  If
** an aggregator with that same key already exists, then make the
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
      zOld = 0;
    }
    pMem->s = aStack[tos];
    if( pMem->s.flags & STK_Dyn ){
      pMem->z = zStack[tos];
      zStack[tos] = 0;
      aStack[tos].flags = 0;
    }else if( pMem->s.flags & STK_Static ){
      pMem->z = zStack[tos];
    }else if( pMem->s.flags & STK_Str ){
      pMem->z = pMem->s.z;
    }
    if( zOld ) sqliteFree(zOld);
  }
  POPSTACK;







|







4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
      zOld = 0;
    }
    pMem->s = aStack[tos];
    if( pMem->s.flags & STK_Dyn ){
      pMem->z = zStack[tos];
      zStack[tos] = 0;
      aStack[tos].flags = 0;
    }else if( pMem->s.flags & (STK_Static|STK_AggCtx) ){
      pMem->z = zStack[tos];
    }else if( pMem->s.flags & STK_Str ){
      pMem->z = pMem->s.z;
    }
    if( zOld ) sqliteFree(zOld);
  }
  POPSTACK;
4442
4443
4444
4445
4446
4447
4448





4449
















4450
4451
4452
4453
4454
4455
4456
    p->agg.pSearch = sqliteHashFirst(&p->agg.hash);
  }else{
    p->agg.pSearch = sqliteHashNext(p->agg.pSearch);
  }
  if( p->agg.pSearch==0 ){
    pc = pOp->p2 - 1;
  } else {





    p->agg.pCurrent = sqliteHashData(p->agg.pSearch);
















  }
  break;
}

/* Opcode: SetInsert P1 * P3
**
** If Set P1 does not exist then create it.  Then insert value







>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
    p->agg.pSearch = sqliteHashFirst(&p->agg.hash);
  }else{
    p->agg.pSearch = sqliteHashNext(p->agg.pSearch);
  }
  if( p->agg.pSearch==0 ){
    pc = pOp->p2 - 1;
  } else {
    int i;
    UserFuncContext ctx;
    void *pCtx;
    Mem *aMem;
    int nErr = 0;
    p->agg.pCurrent = sqliteHashData(p->agg.pSearch);
    aMem = p->agg.pCurrent->aMem;
    for(i=0; i<p->agg.nMem; i++){
      if( p->agg.axFinalize[i]==0 ) continue;
      if( (aMem[i].s.flags & STK_AggCtx)==0 ) continue;
      ctx.s.flags = STK_Null;
      ctx.z = 0;
      pCtx = (void*)aMem[i].z;
      (*p->agg.axFinalize[i])(pCtx, &ctx);
      aMem[i].s = ctx.s;
      aMem[i].z = ctx.z;
      if( (aMem[i].s.flags & STK_Str) &&
              (aMem[i].s.flags & (STK_Dyn|STK_Static))==0 ){
        aMem[i].z = aMem[i].s.z;
      }
      nErr += ctx.isError;
    }
  }
  break;
}

/* Opcode: SetInsert P1 * P3
**
** If Set P1 does not exist then create it.  Then insert value
Changes to src/vdbe.h.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.45 2002/02/23 23:45:46 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.46 2002/02/24 03:25:16 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
136
137
138
139
140
141
142


143
144
145
146
147
148
149
150
151
152
153
154
155
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

#define OP_AggReset           58
#define OP_AggFocus           59
#define OP_AggIncr            60
#define OP_AggNext            61
#define OP_AggSet             62
#define OP_AggGet             63



#define OP_SetInsert          64
#define OP_SetFound           65
#define OP_SetNotFound        66

#define OP_MakeRecord         67
#define OP_MakeKey            68
#define OP_MakeIdxKey         69
#define OP_IncrKey            70

#define OP_Goto               71
#define OP_If                 72
#define OP_Halt               73

#define OP_ColumnCount        74
#define OP_ColumnName         75
#define OP_Callback           76
#define OP_NullCallback       77

#define OP_Integer            78
#define OP_String             79
#define OP_Pop                80
#define OP_Dup                81
#define OP_Pull               82
#define OP_Push               83
#define OP_MustBeInt          84

#define OP_Add                85
#define OP_AddImm             86
#define OP_Subtract           87
#define OP_Multiply           88
#define OP_Divide             89
#define OP_Remainder          90
#define OP_BitAnd             91
#define OP_BitOr              92
#define OP_BitNot             93
#define OP_ShiftLeft          94
#define OP_ShiftRight         95
#define OP_AbsValue           96
#define OP_Precision          97
#define OP_Min                98
#define OP_Max                99
#define OP_Like              100
#define OP_Glob              101
#define OP_Eq                102
#define OP_Ne                103
#define OP_Lt                104
#define OP_Le                105
#define OP_Gt                106
#define OP_Ge                107
#define OP_IsNull            108
#define OP_NotNull           109
#define OP_Negative          110
#define OP_And               111
#define OP_Or                112
#define OP_Not               113
#define OP_Concat            114
#define OP_Noop              115
#define OP_Strlen            116
#define OP_Substr            117
#define OP_UserFunc          118
#define OP_UserAgg           119

#define OP_Limit             120

#define OP_MAX               120

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
void sqliteVdbeCreateCallback(Vdbe*, int*);







>
>

|
|
|

|
|
|
|

|
|
|

|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<

|

|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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

#define OP_AggReset           58
#define OP_AggFocus           59
#define OP_AggIncr            60
#define OP_AggNext            61
#define OP_AggSet             62
#define OP_AggGet             63
#define OP_AggFinalizer       64
#define OP_AggFunc            65

#define OP_SetInsert          66
#define OP_SetFound           67
#define OP_SetNotFound        68

#define OP_MakeRecord         69
#define OP_MakeKey            70
#define OP_MakeIdxKey         71
#define OP_IncrKey            72

#define OP_Goto               73
#define OP_If                 74
#define OP_Halt               75

#define OP_ColumnCount        76
#define OP_ColumnName         77
#define OP_Callback           78
#define OP_NullCallback       79

#define OP_Integer            80
#define OP_String             81
#define OP_Pop                82
#define OP_Dup                83
#define OP_Pull               84
#define OP_Push               85
#define OP_MustBeInt          86

#define OP_Add                87
#define OP_AddImm             88
#define OP_Subtract           89
#define OP_Multiply           90
#define OP_Divide             91
#define OP_Remainder          92
#define OP_BitAnd             93
#define OP_BitOr              94
#define OP_BitNot             95
#define OP_ShiftLeft          96
#define OP_ShiftRight         97
#define OP_AbsValue           98
#define OP_Precision          99
#define OP_Min               100
#define OP_Max               101
#define OP_Like              102
#define OP_Glob              103
#define OP_Eq                104
#define OP_Ne                105
#define OP_Lt                106
#define OP_Le                107
#define OP_Gt                108
#define OP_Ge                109
#define OP_IsNull            110
#define OP_NotNull           111
#define OP_Negative          112
#define OP_And               113
#define OP_Or                114
#define OP_Not               115
#define OP_Concat            116
#define OP_Noop              117
#define OP_Strlen            118
#define OP_Substr            119
#define OP_UserFunc          120


#define OP_Limit             121

#define OP_MAX               121

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(sqlite*);
void sqliteVdbeCreateCallback(Vdbe*, int*);