UnQL

Check-in [514e16d7cb]
Login

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

Overview
Comment:Add support for simple aggregates. Fix a problem with joins.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 514e16d7cb18ebb37972548953fa511d12ed6a15
User & Date: dan 2011-07-20 19:50:22
Context
2011-07-21
17:08
Add support for GROUP BY and HAVING. check-in: 8c09ee47d8 user: dan tags: trunk
2011-07-20
19:50
Add support for simple aggregates. Fix a problem with joins. check-in: 514e16d7cb user: dan tags: trunk
14:13
Improve error handling. check-in: f19d31ea5d user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/datasrc.c.

54
55
56
57
58
59
60







61
62


63
64

65
66
67
68
69
70
71
...
133
134
135
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
...
176
177
178
179
180
181
182























































** the step results in a row of content being available.
*/
int xjd1DataSrcStep(DataSrc *p){
  int rc= XJD1_DONE;
  if( p==0 ) return XJD1_DONE;
  switch( p->eDSType ){
    case TK_COMMA: {







      rc = xjd1DataSrcStep(p->u.join.pRight);
      if( rc==XJD1_DONE ){


        xjd1DataSrcRewind(p->u.join.pRight);
        rc = xjd1DataSrcStep(p->u.join.pLeft);

      }
      break;
    }
    case TK_SELECT: {
      xjd1JsonFree(p->pValue);
      p->pValue = 0;
      rc = xjd1QueryStep(p->u.subq.q);
................................................................................
      break;
    }
  }
  return pRes;
}

/*
** Rewind a data source so that it is pointing at the first row.
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the rewind results in a row of content being available.
*/
int xjd1DataSrcRewind(DataSrc *p){
  if( p==0 ) return XJD1_DONE;
  xjd1JsonFree(p->pValue);  p->pValue = 0;
  switch( p->eDSType ){
    case TK_COMMA: {

      xjd1DataSrcRewind(p->u.join.pLeft);
      xjd1DataSrcRewind(p->u.join.pRight);
      break;
    }
    case TK_SELECT: {
      xjd1QueryRewind(p->u.subq.q);
      break;
    }
    case TK_ID: {
      sqlite3_reset(p->u.tab.pStmt);
      return xjd1DataSrcStep(p);
    }
    case TK_NULL: {
      p->u.null.isDone = 0;
      return xjd1DataSrcStep(p);
    }
  }
  return XJD1_DONE;
}

/*
** The destructor for a Query object.
................................................................................
    case TK_ID: {
      sqlite3_finalize(p->u.tab.pStmt);
      break;
    }
  }
  return XJD1_OK;
}






























































>
>
>
>
>
>
>


>
>
|
|
>







 







|
|
<






>










|



|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
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
...
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
235
236
237
238
239
240
241
242
243
244
245
246
247
** the step results in a row of content being available.
*/
int xjd1DataSrcStep(DataSrc *p){
  int rc= XJD1_DONE;
  if( p==0 ) return XJD1_DONE;
  switch( p->eDSType ){
    case TK_COMMA: {

      if( p->u.join.bStart==0 ){
        p->u.join.bStart = 1;
        rc = xjd1DataSrcStep(p->u.join.pLeft);
        if( rc!=XJD1_ROW ) break;
      }

      rc = xjd1DataSrcStep(p->u.join.pRight);
      if( rc==XJD1_DONE ){
        rc = xjd1DataSrcStep(p->u.join.pLeft);
        if( rc==XJD1_ROW ) {
          xjd1DataSrcRewind(p->u.join.pRight);
          rc = xjd1DataSrcStep(p->u.join.pRight);
        }
      }
      break;
    }
    case TK_SELECT: {
      xjd1JsonFree(p->pValue);
      p->pValue = 0;
      rc = xjd1QueryStep(p->u.subq.q);
................................................................................
      break;
    }
  }
  return pRes;
}

/*
** Rewind a data source so that the next call to DataSrcStep() will cause
** it to point to the first row.

*/
int xjd1DataSrcRewind(DataSrc *p){
  if( p==0 ) return XJD1_DONE;
  xjd1JsonFree(p->pValue);  p->pValue = 0;
  switch( p->eDSType ){
    case TK_COMMA: {
      p->u.join.bStart = 0;
      xjd1DataSrcRewind(p->u.join.pLeft);
      xjd1DataSrcRewind(p->u.join.pRight);
      break;
    }
    case TK_SELECT: {
      xjd1QueryRewind(p->u.subq.q);
      break;
    }
    case TK_ID: {
      sqlite3_reset(p->u.tab.pStmt);
      break;
    }
    case TK_NULL: {
      p->u.null.isDone = 0;
      break;
    }
  }
  return XJD1_DONE;
}

/*
** The destructor for a Query object.
................................................................................
    case TK_ID: {
      sqlite3_finalize(p->u.tab.pStmt);
      break;
    }
  }
  return XJD1_OK;
}

int xjd1DataSrcCount(DataSrc *p){
  int n = 1;
  if( p->eDSType==TK_COMMA ){
    n = xjd1DataSrcCount(p->u.join.pLeft) + xjd1DataSrcCount(p->u.join.pRight); 
  }
  return n;
}

static void cacheSaveRecursive(DataSrc *p, JsonNode ***papNode){
  if( p->eDSType==TK_COMMA ){
    cacheSaveRecursive(p->u.join.pLeft, papNode);
    cacheSaveRecursive(p->u.join.pRight, papNode);
  }else{
    xjd1JsonFree(**papNode);
    **papNode = xjd1JsonRef(p->pValue);
    (*papNode)++;
  }
}

void xjd1DataSrcCacheSave(DataSrc *p, JsonNode **apNode){
  JsonNode **pp = apNode;
  cacheSaveRecursive(p, &pp);
}

static JsonNode *cacheReadRecursive(
  DataSrc *p, 
  JsonNode ***papNode, 
  const char *zDocname
){
  JsonNode *pRet = 0;
  if( p->eDSType==TK_COMMA ){
    pRet = cacheReadRecursive(p->u.join.pLeft, papNode, zDocname);
    if( !pRet ) pRet = cacheReadRecursive(p->u.join.pRight, papNode, zDocname);
  }else{
    if( zDocname==0 
     || (p->zAs && 0==strcmp(zDocname, p->zAs))
     || (p->zAs==0 && p->eDSType==TK_ID && strcmp(p->u.tab.zName, zDocname)==0)
    ){
      pRet = xjd1JsonRef(**papNode);
    }
    (*papNode)++;
  }
  return pRet;
}

JsonNode *xjd1DataSrcCacheRead(
  DataSrc *p,                     /* The data-source */
  JsonNode **apNode,              /* Array of cached values */
  const char *zDocname            /* The document name to search for */
){
  JsonNode **pp = apNode;
  return cacheReadRecursive(p, &pp, zDocname);
}

Changes to src/expr.c.

112
113
114
115
116
117
118
119

120
121

122
123
124
125
126
127
128
129
130
131
132
133
134
135





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
  p->pStmt = pAction->pStmt;
  p->pQuery = pAction->pQuery;
  switch( p->eClass ){
    case XJD1_EXPR_Q:
      rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery);
      break;

    case XJD1_EXPR_FUNC:

      rc = xjd1FunctionInit(p, pAction->pStmt);
      break;


    default:
      break;
  }
  
  return rc;
}


/*
** Initialize an expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery){





  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;

  return walkExpr(p, &sAction);
}

/*
** Initialize a list of expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprListInit(ExprList *p, xjd1_stmt *pStmt, Query *pQuery){
  WalkAction sAction;

  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;

  return walkExprList(p, &sAction);
}


/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
  assert( p );







|
>
|

>













|
>
>
>
>
>





>







|

>




>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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
  p->pStmt = pAction->pStmt;
  p->pQuery = pAction->pQuery;
  switch( p->eClass ){
    case XJD1_EXPR_Q:
      rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery);
      break;

    case XJD1_EXPR_FUNC: {
      int bAggOk = *(int *)pAction->pArg;
      rc = xjd1FunctionInit(p, pAction->pStmt, pAction->pQuery, bAggOk);
      break;
    }

    default:
      break;
  }
  
  return rc;
}


/*
** Initialize an expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprInit(
  Expr *p,                        /* Expression to initialize */
  xjd1_stmt *pStmt,               /* Statement expression belongs to */
  Query *pQuery,                  /* Query expression belongs to (or NULL) */
  int bAggOk                      /* True if an aggregate function is Ok */
){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  sAction.pArg = (void *)&bAggOk;
  return walkExpr(p, &sAction);
}

/*
** Initialize a list of expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprListInit(ExprList *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk){
  WalkAction sAction;
  assert( bAggOk==0 || pQuery );
  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  sAction.pArg = (int *)&bAggOk;
  return walkExprList(p, &sAction);
}


/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
  assert( p );

Changes to src/func.c.

16
17
18
19
20
21
22

23


24
25
26
27
28
29
30
31
32
33
34
35
36
..
48
49
50
51
52
53
54
55























































56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71
72

73
74
75
76
77
78

79












80
81
82
83
84
85
86
..
92
93
94
95
96
97
98
99
100
101
102
103
104


105
106
107
108
109












































110
111
112
113





114

115
116
117
*************************************************************************
*/
#include "xjd1Int.h"

struct Function {
  int nArg;
  const char *zName;

  JsonNode *(*xFunc)(int nArg, JsonNode **apArg);


};

#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))

/*
** Implementation of "length(x)".
*/
static JsonNode *xLength(int nArg, JsonNode **apArg){
  JsonNode *pRet;
  JsonNode *pStr;
  int nRet;
  assert( nArg==1 );

................................................................................

  pRet = xjd1JsonNew(0);
  pRet->eJType = XJD1_REAL;
  pRet->u.r = (double)nRet;

  return pRet;
}
























































/*
** The expression passed as the first argument is of type TK_FUNCTION.
** This function initializes the expression object. If successful, XJD1_OK
** is returned. Otherwise, an error code is returned and an error left in
** the pStmt statement handle.
*/
int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt){
  char *zName;
  int nArg;
  int nByte;
  int i;

  static Function aFunc[] = {
    { 1, "length", xLength },

  };

  assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC );


  zName = p->u.func.zFName;
  nArg = p->u.func.args->nEItem;

  for(i=0; i<ArraySize(aFunc); i++){
    Function *pFunc = &aFunc[i];

    if( strcmp(pFunc->zName, zName)==0 && nArg==pFunc->nArg ){












      p->u.func.pFunction = pFunc;
      break;
    }
  }

  if( !p->u.func.pFunction ){
    xjd1StmtError(pStmt, XJD1_ERROR, "no such function: %s", zName);
................................................................................
  if( !p->u.func.apArg ){
    return XJD1_NOMEM;
  }

  return XJD1_OK;
}


JsonNode *xjd1FunctionEval(Expr *p){
  Function *pFunc = p->u.func.pFunction;
  int i;
  int nItem = p->u.func.args->nEItem;
  JsonNode *pRet;



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













































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







  return pRet;
}








>

>
>





|







 








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






|






|
>



>






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







 







|
<



|
>
>





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



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
...
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
234
235
236
237
238
239
240
241
*************************************************************************
*/
#include "xjd1Int.h"

struct Function {
  int nArg;
  const char *zName;

  JsonNode *(*xFunc)(int nArg, JsonNode **apArg);
  int (*xStep)(int nArg, JsonNode **apArg, void **);
  JsonNode *(*xFinal)(void *);
};

#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))

/*
** Implementation of scalar function "length(x)".
*/
static JsonNode *xLength(int nArg, JsonNode **apArg){
  JsonNode *pRet;
  JsonNode *pStr;
  int nRet;
  assert( nArg==1 );

................................................................................

  pRet = xjd1JsonNew(0);
  pRet->eJType = XJD1_REAL;
  pRet->u.r = (double)nRet;

  return pRet;
}

static int xCountStep(int nArg, JsonNode **apArg, void **pp){
  int nCount = (int)*pp;
  nCount++;
  *pp = (void *)nCount;
  return XJD1_OK;
}

static JsonNode *xCountFinal(void *p){
  JsonNode *pRet;
  pRet = xjd1JsonNew(0);
  pRet->eJType = XJD1_REAL;
  pRet->u.r = (double)(int)p;
  return pRet;
}


int xjd1AggregateInit(xjd1_stmt *pStmt, Query *pQuery, Expr *p){
  Aggregate *pAgg = pQuery->pAgg;

  if( pAgg==0 ){
    int nDatasrc;

    pAgg = (Aggregate *)xjd1PoolMallocZero(&pStmt->sPool, sizeof(Aggregate));
    if( pAgg==0 ) return XJD1_NOMEM;
    pQuery->pAgg = pAgg;

    pAgg->nNode = xjd1DataSrcCount(pQuery->u.simple.pFrom);
    nDatasrc = pAgg->nNode * sizeof(JsonNode *);
    pAgg->apNode = (JsonNode **)xjd1PoolMallocZero(&pStmt->sPool, nDatasrc);
    if( pAgg->apNode==0 ) return XJD1_NOMEM;
  }

  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.
** This function initializes the expression object. If successful, XJD1_OK
** is returned. Otherwise, an error code is returned and an error left in
** the pStmt statement handle.
*/
int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk){
  char *zName;
  int nArg;
  int nByte;
  int i;

  static Function aFunc[] = {
    {  1, "length", xLength, 0, 0 },
    { -1, "count", 0, xCountStep, xCountFinal },
  };

  assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC );
  assert( pQuery || bAggOk==0 );

  zName = p->u.func.zFName;
  nArg = p->u.func.args->nEItem;

  for(i=0; i<ArraySize(aFunc); i++){
    Function *pFunc = &aFunc[i];
    assert( (pFunc->xFunc==0)==(pFunc->xStep && pFunc->xFinal) );
    if( !strcmp(pFunc->zName, zName) && (nArg==pFunc->nArg || 0>pFunc->nArg) ){
      if( pFunc->xStep ){
        int rc;
        if( bAggOk==0 ){
          const char *zErrMsg = "illegal use of aggregate function: %s";
          xjd1StmtError(pStmt, XJD1_ERROR, zErrMsg, zName);
          return XJD1_ERROR;
        }

        /* Add this aggregate function to the Query.pAgg->apExpr[] array. */
        rc = xjd1AggregateInit(pStmt, pQuery, p);
        if( rc!=XJD1_OK ) return rc;
      }
      p->u.func.pFunction = pFunc;
      break;
    }
  }

  if( !p->u.func.pFunction ){
    xjd1StmtError(pStmt, XJD1_ERROR, "no such function: %s", zName);
................................................................................
  if( !p->u.func.apArg ){
    return XJD1_NOMEM;
  }

  return XJD1_OK;
}

int xjd1AggregateStep(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;
}

/*
** 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->nNode; i++){
      xjd1JsonFree(pAgg->apNode[i]);
      pAgg->apNode[i] = 0;
    }
    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;

  assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC );

  if( pFunc->xFunc ){
    /* A scalar function. */
    int i;
    int nItem = p->u.func.args->nEItem;
    for(i=0; i<nItem; i++){
      p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr);
    }

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

Changes to src/query.c.

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161



162
163
164
165
166
167
168
...
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
...
209
210
211
212
213
214
215





























216
217
218
219
220
221
222
223
...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
...
328
329
330
331
332
333
334


335
336
337

338
339
340
341
342
343
344
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){
  int rc;
  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    rc = xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery);
    if( !rc ) rc = xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery);



  }else{
    rc = xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter);
    if( !rc ) rc = xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter);
  }
  return rc;
}

................................................................................
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;
  if( p->eQType==TK_SELECT ){
    xjd1DataSrcRewind(p->u.simple.pFrom);
    p->bUseResultList = 0;
    p->bStarted = 0;

    clearResultList(&p->result);

  }else{
    xjd1QueryRewind(p->u.compound.pLeft);
    p->u.compound.doneLeft = 0;
    xjd1QueryRewind(p->u.compound.pRight);
  }
  return XJD1_OK;
}

/*
** Advance to the next row of the TK_SELECT query passed as the first 
** argument, disregarding any ORDER BY, OFFSET or LIMIT clause.
**
** Return XJD1_ROW if there is such a row, or XJD1_EOF if there is not. Or 
** return an error code if an error occurs.
*/
static int selectStepUnordered(Query *p){
  int rc;                         /* Return code */
  assert( p->eQType==TK_SELECT );
  do{
    rc = xjd1DataSrcStep(p->u.simple.pFrom);
  }while(
................................................................................
**
** Return XJD1_ROW if there is such a row, or XJD1_EOF if there is not. Or 
** return an error code if an error occurs.
*/
static int selectStepOrdered(Query *p){
  int rc;






























  if( p->u.simple.pOrderBy ){
    /* There is an ORDER BY clause. */
    if( p->bUseResultList==0 ){
      int nKey = p->u.simple.pOrderBy->nEItem + 1;
      ExprList *pOrderBy = p->u.simple.pOrderBy;
      Pool *pPool;
      JsonNode **apKey;

................................................................................

/*
** Advance a query to the next row.  Return XDJ1_DONE if there is no
** next row, or XJD1_ROW if the step was successful.
*/
int xjd1QueryStep(Query *p){
  int rc = XJD1_ROW;
  if( p==0 ) return XJD1_DONE;
  if( p->eQType==TK_SELECT ){

    /* Calculate the values, if any, of the LIMIT and OFFSET clauses.
    **
    ** TBD: Should this throw an exception if the result of evaluating
    ** either of these clauses cannot be converted to a number?
    */
................................................................................
  if( p ){
    if( p->eQType==TK_SELECT ){
      if( p->bUseResultList ){
        assert( zDocName==0 && p->result.pItem );
        pOut = xjd1JsonRef(p->result.pItem->apKey[p->result.nKey-1]);
      }else if( zDocName==0 && p->u.simple.pRes ){
        pOut = xjd1ExprEval(p->u.simple.pRes);


      }else{
        pOut = xjd1DataSrcDoc(p->u.simple.pFrom, zDocName);
      }

    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryDoc(p->u.compound.pLeft, zDocName);
    }else{
      pOut = xjd1QueryDoc(p->u.compound.pRight, zDocName);
    }
    if( pOut==0 && zDocName ){
      pOut = xjd1QueryDoc(p->pOuter, zDocName);







|

|
|
|
|
|
|
>
>
>







 







>

>












|
|







 







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







 







|







 







>
>



>







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
...
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
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){
  int rc;
  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    rc = xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery, 1);
    if( !rc ) rc = xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery, 0);
    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery,0);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery, 1);
    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery,1);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery, 0);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery, 0);
    if( !rc && pQuery->u.simple.pGroupBy ){ 
      rc = xjd1AggregateInit(pStmt, pQuery, 0);
    }
  }else{
    rc = xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter);
    if( !rc ) rc = xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter);
  }
  return rc;
}

................................................................................
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;
  if( p->eQType==TK_SELECT ){
    xjd1DataSrcRewind(p->u.simple.pFrom);
    p->bUseResultList = 0;
    p->bStarted = 0;
    p->bDone = 0;
    clearResultList(&p->result);
    xjd1AggregateClear(p);
  }else{
    xjd1QueryRewind(p->u.compound.pLeft);
    p->u.compound.doneLeft = 0;
    xjd1QueryRewind(p->u.compound.pRight);
  }
  return XJD1_OK;
}

/*
** Advance to the next row of the TK_SELECT query passed as the first 
** argument, disregarding any ORDER BY, OFFSET or LIMIT clause.
**
** Return XJD1_ROW if there is such a row, or XJD1_DONE at EOF. Or return 
** an error code if an error occurs.
*/
static int selectStepUnordered(Query *p){
  int rc;                         /* Return code */
  assert( p->eQType==TK_SELECT );
  do{
    rc = xjd1DataSrcStep(p->u.simple.pFrom);
  }while(
................................................................................
**
** Return XJD1_ROW if there is such a row, or XJD1_EOF if there is not. Or 
** return an error code if an error occurs.
*/
static int selectStepOrdered(Query *p){
  int rc;

  if( p->pAgg ){
    Aggregate *pAgg = p->pAgg;

    if( p->u.simple.pGroupBy==0 ){

      /* An aggregate query with no GROUP BY clause. If there is no GROUP BY,
      ** then exactly one row is returned, which makes ORDER BY and DISTINCT 
      ** no-ops. And it is not possible to have a HAVING clause without a
      ** GROUP BY, so no need to worry about that either. 
      */
      assert( p->u.simple.pHaving==0 );
      
      pAgg->eAction = XJD1_AGG_STEP;
      while( XJD1_ROW==(rc = selectStepUnordered(p) ) ){
        int i;
        for(i=0; i<pAgg->nExpr; i++){
          rc = xjd1AggregateStep(pAgg->apExpr[i]);
          if( rc!=XJD1_OK ) return rc;
        }
        xjd1DataSrcCacheSave(p->u.simple.pFrom, pAgg->apNode);
      }
      if( rc!=XJD1_DONE ) return rc;
      pAgg->eAction = XJD1_AGG_FINAL;
      p->bDone = 1;
      rc = XJD1_ROW;

    }else{
      assert(0);
    }
  }else if( p->u.simple.pOrderBy ){
    /* There is an ORDER BY clause. */
    if( p->bUseResultList==0 ){
      int nKey = p->u.simple.pOrderBy->nEItem + 1;
      ExprList *pOrderBy = p->u.simple.pOrderBy;
      Pool *pPool;
      JsonNode **apKey;

................................................................................

/*
** Advance a query to the next row.  Return XDJ1_DONE if there is no
** next row, or XJD1_ROW if the step was successful.
*/
int xjd1QueryStep(Query *p){
  int rc = XJD1_ROW;
  if( p==0 || p->bDone ) return XJD1_DONE;
  if( p->eQType==TK_SELECT ){

    /* Calculate the values, if any, of the LIMIT and OFFSET clauses.
    **
    ** TBD: Should this throw an exception if the result of evaluating
    ** either of these clauses cannot be converted to a number?
    */
................................................................................
  if( p ){
    if( p->eQType==TK_SELECT ){
      if( p->bUseResultList ){
        assert( zDocName==0 && p->result.pItem );
        pOut = xjd1JsonRef(p->result.pItem->apKey[p->result.nKey-1]);
      }else if( zDocName==0 && p->u.simple.pRes ){
        pOut = xjd1ExprEval(p->u.simple.pRes);
      }else if( p->pAgg && p->pAgg->eAction==XJD1_AGG_FINAL ){
        pOut = xjd1DataSrcCacheRead(p->u.simple.pFrom,p->pAgg->apNode,zDocName);
      }else{
        pOut = xjd1DataSrcDoc(p->u.simple.pFrom, zDocName);
      }

    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryDoc(p->u.compound.pLeft, zDocName);
    }else{
      pOut = xjd1QueryDoc(p->u.compound.pRight, zDocName);
    }
    if( pOut==0 && zDocName ){
      pOut = xjd1QueryDoc(p->pOuter, zDocName);

Changes to src/stmt.c.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
        break;
      }
      case TK_INSERT: {
        xjd1QueryInit(pCmd->u.ins.pQuery, p, 0);
        break;
      }
      case TK_DELETE: {
        xjd1ExprInit(pCmd->u.del.pWhere, p, 0);
        break;
      }
      case TK_UPDATE: {
        xjd1ExprInit(pCmd->u.update.pWhere, p, 0);
        xjd1ExprListInit(pCmd->u.update.pChng, p, 0);
        xjd1ExprInit(pCmd->u.update.pUpsert, p, 0);
        break;
      }
    }

    if( p->errCode ){
      xjd1Error(pConn, p->errCode, "%s", p->errMsg.zBuf);
      rc = p->errCode;







|



|
|
|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
        break;
      }
      case TK_INSERT: {
        xjd1QueryInit(pCmd->u.ins.pQuery, p, 0);
        break;
      }
      case TK_DELETE: {
        xjd1ExprInit(pCmd->u.del.pWhere, p, 0, 0);
        break;
      }
      case TK_UPDATE: {
        xjd1ExprInit(pCmd->u.update.pWhere, p, 0, 0);
        xjd1ExprListInit(pCmd->u.update.pChng, p, 0, 0);
        xjd1ExprInit(pCmd->u.update.pUpsert, p, 0, 0);
        break;
      }
    }

    if( p->errCode ){
      xjd1Error(pConn, p->errCode, "%s", p->errMsg.zBuf);
      rc = p->errCode;

Changes to src/xjd1Int.h.

41
42
43
44
45
46
47

48
49
50
51
52
53
54
...
158
159
160
161
162
163
164

165
166
167
168
169
170
171
...
236
237
238
239
240
241
242










243
244
245
246
247
248
249
...
259
260
261
262
263
264
265



266
267
268
269
270
271
272
...
274
275
276
277
278
279
280

281
282
283
284
285
286
287
...
344
345
346
347
348
349
350

351



352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
431
432
433
434
435
436
437
438
439
440

441




442
#define TK_DROPCOLLECTION    104
#define TK_ARRAY             105
#define TK_STRUCT            106
#define TK_JVALUE            107

typedef unsigned char u8;
typedef unsigned short int u16;

typedef struct Command Command;
typedef struct DataSrc DataSrc;
typedef struct Expr Expr;
typedef struct ExprItem ExprItem;
typedef struct ExprList ExprList;
typedef struct Function Function;
typedef struct JsonNode JsonNode;
................................................................................
      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 */

    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
    struct {                /* Literal value.  eClass=EXPR_JSON */
      JsonNode *p;             /* The value */
    } json;
................................................................................
/* A list of sorted results. */
struct ResultList {
  Pool *pPool;
  int nKey;
  ResultItem *pItem;
};











/* 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 */
  union {
    struct {                    /* For compound queries */
................................................................................
      Expr *pHaving;              /* The HAVING clause */
      ExprList *pOrderBy;         /* The ORDER BY clause */
      Expr *pLimit;               /* The LIMIT clause */
      Expr *pOffset;              /* The OFFSET clause */
    } simple;
  } u;




  int bStarted;                   /* Set to true after first Step() */
  int nLimit;                     /* Stop after returning this many more rows */
  int bUseResultList;             /* True to read results from Query.result */
  ResultList result;              /* List of query results in sorted order */
};

/* A Data Source is a representation of a term out of the FROM clause. */
................................................................................
  int eDSType;              /* Source type */
  char *zAs;                /* The identifier after the AS keyword */
  Query *pQuery;            /* Query this data source services */
  JsonNode *pValue;         /* Current value for this data source */
  int isOwner;              /* True if this DataSrc owns the pOut line */
  union {
    struct {                /* For a join.  eDSType==TK_COMMA */

      DataSrc *pLeft;          /* Data source on the left */
      DataSrc *pRight;         /* Data source on the right */
    } join;
    struct {                /* For a named collection.  eDSType==TK_ID */
      char *zName;             /* The collection name */
      sqlite3_stmt *pStmt;     /* Cursor for reading content */
      int eofSeen;             /* True if at EOF */
................................................................................
void xjd1Error(xjd1*,int,const char*,...);

/******************************** datasrc.c **********************************/
int xjd1DataSrcInit(DataSrc*,Query*);
int xjd1DataSrcRewind(DataSrc*);
int xjd1DataSrcStep(DataSrc*);
int xjd1DataSrcClose(DataSrc*);

JsonNode *xjd1DataSrcDoc(DataSrc*, const char*);




/******************************** delete.c ***********************************/
int xjd1DeleteStep(xjd1_stmt*);

/******************************** expr.c *************************************/
int xjd1ExprInit(Expr*, xjd1_stmt*, Query*);
int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*);
JsonNode *xjd1ExprEval(Expr*);
int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
int xjd1ExprListClose(ExprList*);

/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn);
................................................................................
void xjd1TraceExpr(String*,const Expr*);
void xjd1TraceExprList(String*,int, const ExprList*);

/******************************** update.c ***********************************/
int xjd1UpdateStep(xjd1_stmt*);

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






#endif /* _XJD1INT_H */







>







 







>







 







>
>
>
>
>
>
>
>
>
>







 







>
>
>







 







>







 







>

>
>
>





|
|







 







|
<

>

>
>
>
>

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
451
452
453
454
455
456
457
458

459
460
461
462
463
464
465
466
#define TK_DROPCOLLECTION    104
#define TK_ARRAY             105
#define TK_STRUCT            106
#define TK_JVALUE            107

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;
typedef struct JsonNode JsonNode;
................................................................................
      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;
................................................................................
/* A list of sorted results. */
struct ResultList {
  Pool *pPool;
  int nKey;
  ResultItem *pItem;
};

struct Aggregate {
  int eAction;                    /* One of XJD1_AGG_STEP or XJD1_AGG_FINAL */
  int nNode;                      /* Size of apNode array */
  JsonNode **apNode;              /* Cache of datasource values */
  int nExpr;                      /* Number of aggregate functions */
  Expr **apExpr;                  /* Array of aggregate functions */
};
#define XJD1_AGG_STEP  0
#define XJD1_AGG_FINAL 1

/* 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 */
  union {
    struct {                    /* For compound queries */
................................................................................
      Expr *pHaving;              /* The HAVING clause */
      ExprList *pOrderBy;         /* The ORDER BY clause */
      Expr *pLimit;               /* The LIMIT clause */
      Expr *pOffset;              /* The OFFSET clause */
    } simple;
  } u;

  Aggregate *pAgg;              /* Aggregation info. NULL for non-aggregates */

  int bDone;                      /* Set to true after query is finished */
  int bStarted;                   /* Set to true after first Step() */
  int nLimit;                     /* Stop after returning this many more rows */
  int bUseResultList;             /* True to read results from Query.result */
  ResultList result;              /* List of query results in sorted order */
};

/* A Data Source is a representation of a term out of the FROM clause. */
................................................................................
  int eDSType;              /* Source type */
  char *zAs;                /* The identifier after the AS keyword */
  Query *pQuery;            /* Query this data source services */
  JsonNode *pValue;         /* Current value for this data source */
  int isOwner;              /* True if this DataSrc owns the pOut line */
  union {
    struct {                /* For a join.  eDSType==TK_COMMA */
      int bStart;              /* True if has already started */
      DataSrc *pLeft;          /* Data source on the left */
      DataSrc *pRight;         /* Data source on the right */
    } join;
    struct {                /* For a named collection.  eDSType==TK_ID */
      char *zName;             /* The collection name */
      sqlite3_stmt *pStmt;     /* Cursor for reading content */
      int eofSeen;             /* True if at EOF */
................................................................................
void xjd1Error(xjd1*,int,const char*,...);

/******************************** datasrc.c **********************************/
int xjd1DataSrcInit(DataSrc*,Query*);
int xjd1DataSrcRewind(DataSrc*);
int xjd1DataSrcStep(DataSrc*);
int xjd1DataSrcClose(DataSrc*);
int xjd1DataSrcCount(DataSrc*);
JsonNode *xjd1DataSrcDoc(DataSrc*, const char*);
int xjd1DataSrcCount(DataSrc *);
JsonNode *xjd1DataSrcCacheRead(DataSrc *, JsonNode **, const char *zDocname);
void xjd1DataSrcCacheSave(DataSrc *, JsonNode **);

/******************************** delete.c ***********************************/
int xjd1DeleteStep(xjd1_stmt*);

/******************************** expr.c *************************************/
int xjd1ExprInit(Expr*, xjd1_stmt*, Query*, int);
int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*, int);
JsonNode *xjd1ExprEval(Expr*);
int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
int xjd1ExprListClose(ExprList*);

/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn);
................................................................................
void xjd1TraceExpr(String*,const Expr*);
void xjd1TraceExprList(String*,int, const ExprList*);

/******************************** update.c ***********************************/
int xjd1UpdateStep(xjd1_stmt*);

/******************************** 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(Expr *p);
void xjd1AggregateClear(Query *);

#endif /* _XJD1INT_H */

Changes to test/base05.test.

61
62
63
64
65
66
67



















68
69
70
SELECT length(null);
.result 11 2 4 5 4

.testcase 10
SELECT xyz("hello world");
.error ERROR no such function: xyz






























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



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
SELECT length(null);
.result 11 2 4 5 4

.testcase 10
SELECT xyz("hello world");
.error ERROR no such function: xyz

.testcase 11
SELECT FROM c1 WHERE count(c1);
.error ERROR illegal use of aggregate function: count

.testcase 12
SELECT count(c1) FROM c1;
SELECT count(c1) FROM c1 WHERE c1.i < 10;
.result 17 9

.testcase 13
SELECT {a: count(c1), b : c1} FROM c1;
.result {"a":17,"b":{"i":11,"z":"Fig"}}

.testcase 14
SELECT count(x) FROM c1, c1 AS b;
SELECT count(x) FROM c1, c1 AS b WHERE c1.i<3 && b.i<3;
SELECT count(x) FROM c1, c1 AS b WHERE c1.i==1;
.result 289 4 17