UnQL

Check-in [5fad391dbc]
Login

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

Overview
Comment:Internal changes to aggregate queries.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5fad391dbcc5adc0c666a03d5670595af3395dd5
User & Date: dan 2011-07-21 18:24:20
Context
2011-07-21
18:56
Add fragments to the syntax diagram page: /doc/trunk/doc/syntax/all.wiki check-in: 33c3f4b80d user: drh tags: trunk
18:24
Internal changes to aggregate queries. check-in: 5fad391dbc user: dan tags: trunk
17:48
Fix the postscript generation to omit the creation date, so that we do not change the postscript on every rerun of the generator script. Change sql-stmt to unql-stmt. Add the all.wiki page. check-in: c6fdb1f6a7 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/func.c.

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
...
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
...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

  if( p ){
    static const int ARRAY_ALLOC_INCR = 8;

    if( (pAgg->nExpr % ARRAY_ALLOC_INCR)==0 ){
      int nByte;                    /* Size of new allocation in bytes */
      int nCopy;                    /* Size of old allocation in bytes */
      Expr **apNew;                 /* Pointer to new allocation */
     
      nByte = (pAgg->nExpr + ARRAY_ALLOC_INCR) * sizeof(Expr *);
      nCopy = pAgg->nExpr * sizeof(Expr *);
      apNew = (Expr **)xjd1PoolMallocZero(&pStmt->sPool, nByte);
  
      if( apNew==0 ) return XJD1_NOMEM;
      memcpy(apNew, pAgg->apExpr, nCopy);
      pAgg->apExpr = apNew;
    }
  

    pAgg->apExpr[pAgg->nExpr++] = p;
  }

  return XJD1_OK;
}

/*
** The expression passed as the first argument is of type TK_FUNCTION.
................................................................................
  if( !p->u.func.apArg ){
    return XJD1_NOMEM;
  }

  return XJD1_OK;
}

static int aggExprStep(Expr *p){

  Function *pFunc = p->u.func.pFunction;
  int i;
  int nItem = p->u.func.args->nEItem;

  assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC );
  assert( pFunc->xStep && pFunc->xFinal && pFunc->xFunc==0 );

  for(i=0; i<nItem; i++){
    p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr);
  }

  pFunc->xStep(nItem, p->u.func.apArg, &p->u.func.pAggCtx);
  for(i=0; i<nItem; i++){
    xjd1JsonFree(p->u.func.apArg[i]);
  }

  return XJD1_OK;
}

int xjd1AggregateStep(Aggregate *pAgg){
  int i;                /* Used to iterate through aggregate functions */
  for(i=0; i<pAgg->nExpr; i++){
    int rc = aggExprStep(pAgg->apExpr[i]);
    if( rc!=XJD1_OK ) return rc;
  }
  return XJD1_OK;;
}
















/*
** Call any outstanding xFinal() functions for aggregate functions in the
** query. This is required to reset the aggregate contexts when a query is 
** rewound following an error.
*/
void xjd1AggregateClear(Query *pQuery){
  Aggregate *pAgg = pQuery->pAgg;

  if( pAgg ){
    int i;
    for(i=0; i<pAgg->nExpr; i++){
      Expr *p = pAgg->apExpr[i];  /* Aggregate expression to finalize */


      xjd1JsonFree( p->u.func.pFunction->xFinal(p->u.func.pAggCtx) );

      p->u.func.pAggCtx = 0;

    }
  }
}

JsonNode *xjd1FunctionEval(Expr *p){
  JsonNode *pRet;
  Function *pFunc = p->u.func.pFunction;
................................................................................
    }

    pRet = pFunc->xFunc(nItem, p->u.func.apArg);
    for(i=0; i<nItem; i++){
      xjd1JsonFree(p->u.func.apArg[i]);
    }
  }else{
    /* This is the xFinal() call of an aggregate function. */
    assert( pFunc->xStep && pFunc->xFinal );
    pRet = pFunc->xFinal(p->u.func.pAggCtx);
    p->u.func.pAggCtx = 0;
  }

  return pRet;
}








|

|
|
|

|
|
|


>
|







 







|
>











|










|




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












|
>
>
|
>
|
>







 







|
|
<
<





81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
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
233
...
243
244
245
246
247
248
249
250
251


252
253
254
255
256

  if( p ){
    static const int ARRAY_ALLOC_INCR = 8;

    if( (pAgg->nExpr % ARRAY_ALLOC_INCR)==0 ){
      int nByte;                    /* Size of new allocation in bytes */
      int nCopy;                    /* Size of old allocation in bytes */
      AggExpr *aNew;                /* Pointer to new allocation */
     
      nByte = (pAgg->nExpr + ARRAY_ALLOC_INCR) * sizeof(AggExpr);
      nCopy = pAgg->nExpr * sizeof(AggExpr);
      aNew = (AggExpr *)xjd1PoolMallocZero(&pStmt->sPool, nByte);
  
      if( aNew==0 ) return XJD1_NOMEM;
      memcpy(aNew, pAgg->aAggExpr, nCopy);
      pAgg->aAggExpr = aNew;
    }
  
    p->u.func.iAgg = pAgg->nExpr;
    pAgg->aAggExpr[pAgg->nExpr++].pExpr = p;
  }

  return XJD1_OK;
}

/*
** The expression passed as the first argument is of type TK_FUNCTION.
................................................................................
  if( !p->u.func.apArg ){
    return XJD1_NOMEM;
  }

  return XJD1_OK;
}

static int aggExprStep(AggExpr *pAggExpr){
  Expr *p = pAggExpr->pExpr;
  Function *pFunc = p->u.func.pFunction;
  int i;
  int nItem = p->u.func.args->nEItem;

  assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC );
  assert( pFunc->xStep && pFunc->xFinal && pFunc->xFunc==0 );

  for(i=0; i<nItem; i++){
    p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr);
  }

  pFunc->xStep(nItem, p->u.func.apArg, &pAggExpr->pAggCtx);
  for(i=0; i<nItem; i++){
    xjd1JsonFree(p->u.func.apArg[i]);
  }

  return XJD1_OK;
}

int xjd1AggregateStep(Aggregate *pAgg){
  int i;                /* Used to iterate through aggregate functions */
  for(i=0; i<pAgg->nExpr; i++){
    int rc = aggExprStep(&pAgg->aAggExpr[i]);
    if( rc!=XJD1_OK ) return rc;
  }
  return XJD1_OK;;
}

int xjd1AggregateFinalize(Aggregate *pAgg){
  int i;
  for(i=0; i<pAgg->nExpr; i++){
    AggExpr *pAggExpr = &pAgg->aAggExpr[i];
    Expr *p = pAggExpr->pExpr;

    assert( i==p->u.func.iAgg );
    xjd1JsonFree(pAggExpr->pValue);
    pAggExpr->pValue = p->u.func.pFunction->xFinal(pAggExpr->pAggCtx);
    pAggExpr->pAggCtx = 0;
  }

  return XJD1_OK;
}

/*
** Call any outstanding xFinal() functions for aggregate functions in the
** query. This is required to reset the aggregate contexts when a query is 
** rewound following an error.
*/
void xjd1AggregateClear(Query *pQuery){
  Aggregate *pAgg = pQuery->pAgg;

  if( pAgg ){
    int i;
    for(i=0; i<pAgg->nExpr; i++){
      AggExpr *pAggExpr = &pAgg->aAggExpr[i];
      Expr *p = pAggExpr->pExpr;

      xjd1JsonFree( p->u.func.pFunction->xFinal(pAggExpr->pAggCtx) );
      xjd1JsonFree( pAggExpr->pValue );
      pAggExpr->pAggCtx = 0;
      pAggExpr->pValue = 0;
    }
  }
}

JsonNode *xjd1FunctionEval(Expr *p){
  JsonNode *pRet;
  Function *pFunc = p->u.func.pFunction;
................................................................................
    }

    pRet = pFunc->xFunc(nItem, p->u.func.apArg);
    for(i=0; i<nItem; i++){
      xjd1JsonFree(p->u.func.apArg[i]);
    }
  }else{
    AggExpr *pAggExpr = &p->pQuery->pAgg->aAggExpr[p->u.func.iAgg];
    pRet = xjd1JsonRef(pAggExpr->pValue);


  }

  return pRet;
}

Changes to src/query.c.

239
240
241
242
243
244
245

246
247

248



249
250
251
252
253
254
255
256
257
258
259
...
307
308
309
310
311
312
313
314
315
316
317
318
319

320

321
322
323
324
325
326
327

        /* Call the xStep() of each aggregate in the query for each row 
        ** matched by the query WHERE clause. */
        while( rc==XJD1_OK && XJD1_ROW==(rc = selectStepWhered(p) ) ){
          rc = xjd1AggregateStep(pAgg);
          xjd1DataSrcCacheSave(p->u.simple.pFrom, apSrc);
        }

        if( rc==XJD1_DONE ){
          rc = addToResultList(&p->grouped, apSrc);

          if( rc==XJD1_OK ){



            rc = XJD1_ROW;
            p->eDocFrom = XJD1_FROM_GROUPED;
          }
        }
      }else{
        rc = XJD1_DONE;
      }
      
      /* TODO: If this is a top-level query, then xQueryDoc(p, 0) will be
      ** called exactly once to retrieve the query result. When any 
      ** aggregate expressions within the query result are evaluated, the 
................................................................................
        pItem = p->grouped.pItem;
        if( pItem==0 ){
          rc = XJD1_DONE;
        }else{
          while( 1 ){
            ResultItem *pNext = pItem->pNext;
            rc = xjd1AggregateStep(pAgg);
            if( !pNext || cmpResultItem(pItem, pNext, pGroupBy) ){
              break;
            }
            popResultList(&p->grouped);
            pItem = p->grouped.pItem;
          }

          rc = XJD1_ROW;

        }

      }while( rc==XJD1_ROW 
           && p->u.simple.pHaving && !xjd1ExprTrue(p->u.simple.pHaving)
      );
    }








>


>
|
>
>
>
|
|
|
|







 







|





>
|
>







239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

        /* Call the xStep() of each aggregate in the query for each row 
        ** matched by the query WHERE clause. */
        while( rc==XJD1_OK && XJD1_ROW==(rc = selectStepWhered(p) ) ){
          rc = xjd1AggregateStep(pAgg);
          xjd1DataSrcCacheSave(p->u.simple.pFrom, apSrc);
        }
        assert( rc!=XJD1_OK );
        if( rc==XJD1_DONE ){
          rc = addToResultList(&p->grouped, apSrc);
        }
        if( rc==XJD1_OK ){
          rc = xjd1AggregateFinalize(pAgg);
        }
        if( rc==XJD1_OK ){
          rc = XJD1_ROW;
          p->eDocFrom = XJD1_FROM_GROUPED;
        }

      }else{
        rc = XJD1_DONE;
      }
      
      /* TODO: If this is a top-level query, then xQueryDoc(p, 0) will be
      ** called exactly once to retrieve the query result. When any 
      ** aggregate expressions within the query result are evaluated, the 
................................................................................
        pItem = p->grouped.pItem;
        if( pItem==0 ){
          rc = XJD1_DONE;
        }else{
          while( 1 ){
            ResultItem *pNext = pItem->pNext;
            rc = xjd1AggregateStep(pAgg);
            if( rc || !pNext || cmpResultItem(pItem, pNext, pGroupBy) ){
              break;
            }
            popResultList(&p->grouped);
            pItem = p->grouped.pItem;
          }
          if( XJD1_OK==rc && XJD1_OK==(rc = xjd1AggregateFinalize(pAgg)) ){
            rc = XJD1_ROW;
          }
        }

      }while( rc==XJD1_ROW 
           && p->u.simple.pHaving && !xjd1ExprTrue(p->u.simple.pHaving)
      );
    }

Changes to src/xjd1Int.h.

50
51
52
53
54
55
56

57
58
59
60
61
62
63
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
...
249
250
251
252
253
254
255

256



257
258
259
260
261
262
263
...
277
278
279
280
281
282
283

284
285
286
287
288
289
290
...
466
467
468
469
470
471
472

473
474
475
**     DataType var[N];
**     assert( ArraySize(var)==N );
*/
#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))

typedef unsigned char u8;
typedef unsigned short int u16;

typedef struct Aggregate Aggregate;
typedef struct Command Command;
typedef struct DataSrc DataSrc;
typedef struct Expr Expr;
typedef struct ExprItem ExprItem;
typedef struct ExprList ExprList;
typedef struct Function Function;
................................................................................
      char *zId;               /* token value.  eClass=EXPR_TK */
    } id;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* Name of the function */
      ExprList *args;          /* List of arguments */
      Function *pFunction;     /* Function object */
      JsonNode **apArg;        /* Array to martial function arguments in */
      void *pAggCtx;           /* Context for aggregate functions */
    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
    struct {                /* Literal value.  eClass=EXPR_JSON */
      JsonNode *p;             /* The value */
    } json;
................................................................................
  Pool *pPool;
  int nKey;
  ResultItem *pItem;
};

struct Aggregate {
  int nExpr;                      /* Number of aggregate functions */

  Expr **apExpr;                  /* Array of aggregate functions */



};

/* A query statement */
struct Query {
  int eQType;                   /* Query type */
  xjd1_stmt *pStmt;             /* Statement this query is part of */
  Query *pOuter;                /* Next outer query for a subquery */
................................................................................
      Expr *pLimit;               /* The LIMIT clause */
      Expr *pOffset;              /* The OFFSET clause */
    } simple;
  } u;

  Aggregate *pAgg;                /* Aggregation info. 0 for non-aggregates */
  ResultList grouped;             /* Grouped results, for GROUP BY queries */

  ResultList ordered;             /* Query results in sorted order */
  int eDocFrom;                   /* XJD1_FROM_* - configures xjd1QueryDoc() */

  int bStarted;                   /* Set to true after first Step() */
  int nLimit;                     /* Stop after returning this many more rows */
};

................................................................................
/******************************** func.c *************************************/
int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk);
JsonNode *xjd1FunctionEval(Expr *p);
void xjd1FunctionClose(Expr *p);

int xjd1AggregateInit(xjd1_stmt *, Query *, Expr *);
int xjd1AggregateStep(Aggregate *);

void xjd1AggregateClear(Query *);

#endif /* _XJD1INT_H */







>







 







|







 







>
|
>
>
>







 







>







 







>



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
...
472
473
474
475
476
477
478
479
480
481
482
**     DataType var[N];
**     assert( ArraySize(var)==N );
*/
#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))

typedef unsigned char u8;
typedef unsigned short int u16;
typedef struct AggExpr AggExpr;
typedef struct Aggregate Aggregate;
typedef struct Command Command;
typedef struct DataSrc DataSrc;
typedef struct Expr Expr;
typedef struct ExprItem ExprItem;
typedef struct ExprList ExprList;
typedef struct Function Function;
................................................................................
      char *zId;               /* token value.  eClass=EXPR_TK */
    } id;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* Name of the function */
      ExprList *args;          /* List of arguments */
      Function *pFunction;     /* Function object */
      JsonNode **apArg;        /* Array to martial function arguments in */
      int iAgg;
    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
    struct {                /* Literal value.  eClass=EXPR_JSON */
      JsonNode *p;             /* The value */
    } json;
................................................................................
  Pool *pPool;
  int nKey;
  ResultItem *pItem;
};

struct Aggregate {
  int nExpr;                      /* Number of aggregate functions */
  struct AggExpr {
    Expr *pExpr;                  /* Array of aggregate functions */
    JsonNode *pValue;             /* Value returned by xFinal() */
    void *pAggCtx;                /* Context pointer used by implementation */
  } *aAggExpr;
};

/* A query statement */
struct Query {
  int eQType;                   /* Query type */
  xjd1_stmt *pStmt;             /* Statement this query is part of */
  Query *pOuter;                /* Next outer query for a subquery */
................................................................................
      Expr *pLimit;               /* The LIMIT clause */
      Expr *pOffset;              /* The OFFSET clause */
    } simple;
  } u;

  Aggregate *pAgg;                /* Aggregation info. 0 for non-aggregates */
  ResultList grouped;             /* Grouped results, for GROUP BY queries */
  ResultList distincted;          /* Distinct results */
  ResultList ordered;             /* Query results in sorted order */
  int eDocFrom;                   /* XJD1_FROM_* - configures xjd1QueryDoc() */

  int bStarted;                   /* Set to true after first Step() */
  int nLimit;                     /* Stop after returning this many more rows */
};

................................................................................
/******************************** func.c *************************************/
int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk);
JsonNode *xjd1FunctionEval(Expr *p);
void xjd1FunctionClose(Expr *p);

int xjd1AggregateInit(xjd1_stmt *, Query *, Expr *);
int xjd1AggregateStep(Aggregate *);
int xjd1AggregateFinalize(Aggregate *);
void xjd1AggregateClear(Query *);

#endif /* _XJD1INT_H */