UnQL

Check-in [56a739ec3b]
Login

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

Overview
Comment:Change the syntax so that the result specified in between SELECT and FROM keywords is a single JSON structure (actually any expression) rather than a SQL-style list. This check-in compiles and runs, but there are bugs so that the tests fail.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 56a739ec3b606922fe9b8e708d3b9e9713c74096
User & Date: drh 2011-06-28 13:46:18
Context
2011-06-28
15:15
Got all test cases passing again. check-in: 423cc63722 user: drh tags: trunk
13:46
Change the syntax so that the result specified in between SELECT and FROM keywords is a single JSON structure (actually any expression) rather than a SQL-style list. This check-in compiles and runs, but there are bugs so that the tests fail. check-in: 56a739ec3b user: drh tags: trunk
2011-06-27
17:56
Allow JSON strings in the column list. check-in: 51c49e25e9 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

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
...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
static int walkExpr(Expr *p, WalkAction *pAction){
  int rc = XJD1_OK;
  if( p==0 ) return XJD1_OK;
  if( pAction->xNodeAction ){
    rc = pAction->xNodeAction(p, pAction);
  }
  switch( p->eClass ){
    case XJD1_EXPR_Q: {
      if( pAction->xQueryAction ){
        rc = pAction->xQueryAction(p, pAction);
      }
      break;
    }
    case XJD1_EXPR_FUNC: {
      walkExprList(p->u.func.args, pAction);
      break;
    }
    case XJD1_EXPR_BI: {
      walkExpr(p->u.bi.pLeft, pAction);
      walkExpr(p->u.bi.pRight, pAction);
      break;
    }
    case XJD1_EXPR_TK: {
      /* Nothing to do */
      break;






















    }
  }
  return rc;
}


/*
................................................................................
** Callback for query expressions
*/
static int walkInitCallback(Expr *p, WalkAction *pAction){
  int rc = XJD1_OK;
  assert( p );
  p->pStmt = pAction->pStmt;
  if( p->eClass==XJD1_EXPR_Q ){
    rc = xjd1QueryInit(p->u.q, pAction->pStmt, pAction->pQuery);
  }
  return rc;
}


/*
** Initialize an expression in preparation for evaluation of a
................................................................................
}


/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
  assert( p );
  assert( p->eType==TK_SELECT );
  return xjd1QueryClose(p->u.q);
}

/*
** Close all subqueries in an expression.
*/
int xjd1ExprClose(Expr *p){
  WalkAction sAction;
................................................................................
}

/*
** Compute a real value from an expression
*/
static double realFromExpr(Expr *p){
  double r = 0.0;

  if( p==0 ) return 0.0;
  switch( p->eType ){
    case TK_STRING:
    case TK_INTEGER:
    case TK_FLOAT: {
      r = atof(p->u.tk.z);
      break;
    }
    case TK_TRUE: {
      r = 1.0;
      break;
    }
    case TK_FALSE:
    case TK_NULL: {
      break;
    }
    default: {
      JsonNode *pNode = xjd1ExprEval(p);
      r = realFromJson(pNode);

      xjd1JsonFree(pNode);
      break;
    }
  }
  return r;
}

/*
** Evaluate an expression.  Return the result as a JSON object.
**
** The caller must free the returned JSON by a call xjdJsonFree().
*/
JsonNode *xjd1ExprEval(Expr *p){
  JsonNode *pRes;
  double rLeft, rRight;
  if( p==0 ){
    pRes = xjd1JsonNew();
    if( pRes ) pRes->eJType = XJD1_NULL;
    return pRes;
  }
  if( p->eType==TK_JVALUE ){
    return xjd1JsonParse(p->u.tk.z, p->u.tk.n);
  }
  pRes = xjd1JsonNew();
  if( pRes==0 ) return 0;
  switch( p->eType ){
    case TK_INTEGER:
    case TK_FLOAT: {
      pRes->u.r = atof(p->u.tk.z);
      pRes->eJType = XJD1_REAL;
      break;
    }
    case TK_NULL: {
      pRes->eJType = XJD1_NULL;
      break;
    }
    case TK_TRUE: {
      pRes->eJType = XJD1_TRUE;
      break;
    }
    case TK_FALSE: {
      pRes->eJType = XJD1_FALSE;
      break;
    }
    case TK_STRING: {
      pRes->u.z = malloc( p->u.tk.n );
      if( pRes->u.z ){
        int i, j;
        for(i=1, j=0; i<p->u.tk.n-1; i++){
          char c = p->u.tk.z[i];
          if( c=='\\' ){
            c = p->u.tk.z[++i];
            if( c=='n' ){
              c = '\n';
            }else if( c=='t' ){
              c = '\t';
            }
          }
          pRes->u.z[++j] = c;
        }
        pRes->u.z[j] = 0;
      }
      pRes->eJType = XJD1_STRING;
      break;
    }
    case TK_PLUS: {
      rLeft = realFromExpr(p->u.bi.pLeft);
      rRight = realFromExpr(p->u.bi.pRight);
      pRes->eJType = XJD1_REAL;
      pRes->u.r = rLeft+rRight;  break;
      break;
    }
................................................................................
      rc = atof(pValue->u.z)!=0.0;
      break;
    }
  }
  xjd1JsonFree(pValue);
  return rc;
}

/*
** Convert an ExprList into a JSON structure.
*/
JsonNode *xjd1ExprListEval(ExprList *pList){
  JsonNode *pRes;
  JsonStructElem *pElem, **ppLast;
  int i;
  ExprItem *pItem;

  pRes = xjd1JsonNew();
  if( pRes==0 ) return 0;
  pRes->eJType = XJD1_STRUCT;
  ppLast = &pRes->u.pStruct;
  if( pList==0 ) return pRes;
  for(i=0; i<pList->nEItem; i++){
    pItem = &pList->apEItem[i];
    pElem = malloc( sizeof(*pElem) );
    if( pElem==0 ) break;
    memset(pElem, 0, sizeof(*pElem));
    pElem->zLabel = malloc( pItem->tkAs.n+1 );
    if( pElem->zLabel ){
      memcpy(pElem->zLabel, pItem->tkAs.z, pItem->tkAs.n);
      pElem->zLabel[pItem->tkAs.n] = 0;
    }
    pElem->pValue = xjd1ExprEval(pItem->pExpr);
    *ppLast = pElem;
    ppLast = &pElem->pNext;
  }
  return pRes;  
}







<
<
<
<
<
<
<
<
<
<








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







 







|







 







|







 







>

|
<
|
|
|
<
|
<
<
<
<
<
<
<
<
<
<
|
>
|
<
<













|




|

|


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
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
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
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
...
261
262
263
264
265
266
267































static int walkExpr(Expr *p, WalkAction *pAction){
  int rc = XJD1_OK;
  if( p==0 ) return XJD1_OK;
  if( pAction->xNodeAction ){
    rc = pAction->xNodeAction(p, pAction);
  }
  switch( p->eClass ){










    case XJD1_EXPR_BI: {
      walkExpr(p->u.bi.pLeft, pAction);
      walkExpr(p->u.bi.pRight, pAction);
      break;
    }
    case XJD1_EXPR_TK: {
      /* Nothing to do */
      break;
    }
    case XJD1_EXPR_FUNC: {
      walkExprList(p->u.func.args, pAction);
      break;
    }
    case XJD1_EXPR_Q: {
      if( pAction->xQueryAction ){
        rc = pAction->xQueryAction(p, pAction);
      }
      break;
    }
    case XJD1_EXPR_JSON: {
      /* Nothing to do */
      break;
    }
    case XJD1_EXPR_ARRAY: {
      walkExprList(p->u.ar, pAction);
      break;
    }
    case XJD1_EXPR_STRUCT: {
      walkExprList(p->u.st, pAction);
      break;
    }
  }
  return rc;
}


/*
................................................................................
** Callback for query expressions
*/
static int walkInitCallback(Expr *p, WalkAction *pAction){
  int rc = XJD1_OK;
  assert( p );
  p->pStmt = pAction->pStmt;
  if( p->eClass==XJD1_EXPR_Q ){
    rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery);
  }
  return rc;
}


/*
** Initialize an expression in preparation for evaluation of a
................................................................................
}


/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
  assert( p );
  assert( p->eType==TK_SELECT );
  return xjd1QueryClose(p->u.subq.p);
}

/*
** Close all subqueries in an expression.
*/
int xjd1ExprClose(Expr *p){
  WalkAction sAction;
................................................................................
}

/*
** Compute a real value from an expression
*/
static double realFromExpr(Expr *p){
  double r = 0.0;
  JsonNode *pNode;
  if( p==0 ) return 0.0;
  if( p->eType==TK_JVALUE ){

    pNode = p->u.json.p;
  }else{
    pNode = xjd1ExprEval(p);

  }










  r = realFromJson(pNode);
  if( p->eType!=TK_JVALUE ){
    xjd1JsonFree(pNode);


  }
  return r;
}

/*
** Evaluate an expression.  Return the result as a JSON object.
**
** The caller must free the returned JSON by a call xjdJsonFree().
*/
JsonNode *xjd1ExprEval(Expr *p){
  JsonNode *pRes;
  double rLeft, rRight;
  if( p==0 ){
    pRes = xjd1JsonNew(0);
    if( pRes ) pRes->eJType = XJD1_NULL;
    return pRes;
  }
  if( p->eType==TK_JVALUE ){
    return xjd1JsonRef(p->u.json.p);
  }
  pRes = xjd1JsonNew(0);
  if( pRes==0 ) return 0;
  switch( p->eType ){







































    case TK_PLUS: {
      rLeft = realFromExpr(p->u.bi.pLeft);
      rRight = realFromExpr(p->u.bi.pRight);
      pRes->eJType = XJD1_REAL;
      pRes->u.r = rLeft+rRight;  break;
      break;
    }
................................................................................
      rc = atof(pValue->u.z)!=0.0;
      break;
    }
  }
  xjd1JsonFree(pValue);
  return rc;
}































Changes to src/json.c.

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
51
52
53
54
55
56
57
58





59
60
61
62

63
64
65
66
67
68
69
..
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
...
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
...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

456
457
458
459
460
461
462
...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
    switch( p->eJType ){
      case XJD1_STRING: {
        free(p->u.z);
        break;
      }
      case XJD1_ARRAY: {
        int i;
        for(i=0; i<p->u.array.nElem; i++){
          xjd1JsonFree(p->u.array.apElem[i]);
        }
        free(p->u.array.apElem);
        break;
      }
      case XJD1_STRUCT: {
        JsonStructElem *pElem, *pNext;
        for(pElem=p->u.pStruct; pElem; pElem=pNext){
          pNext = pElem->pNext;
          free(pElem->zLabel);
          xjd1JsonFree(pElem->pValue);
          free(pElem);
        }
        break;
      }
................................................................................
    free(p);
  }
}

/*
** Allocate a new Json node.
*/
JsonNode *xjd1JsonNew(void){





  JsonNode *p = malloc( sizeof(*p) );
  if( p ){
    memset(p, 0, sizeof(*p));
    p->nRef = 1;

  }
  return p;
}

/*
** Increase the reference count on a JSON object.  
**
................................................................................
** reference count is exactly 1.  If the input JSON object has a reference
** count greater than 1, then make a copy and return the copy.
*/
JsonNode *xjd1JsonEdit(JsonNode *p){
  JsonNode *pNew;
  if( p==0 ) return 0;
  if( p->nRef==1 ) return p;
  pNew = xjd1JsonNew();
  if( pNew==0 ) return 0;
  pNew->eJType = p->eJType;
  switch( pNew->eJType ){
    case XJD1_STRING: {
      pNew->u.z = xjd1PoolDup(0, p->u.z, -1);
      break;
    }
    case XJD1_ARRAY: {
      JsonNode **ap;
      pNew->u.array.apElem = ap = malloc( sizeof(JsonNode*)*p->u.array.nElem );
      if( ap==0 ){
        pNew->eJType = XJD1_NULL;
      }else{
        int i;
        pNew->u.array.nElem = p->u.array.nElem;
        for(i=0; i<p->u.array.nElem; i++){
          ap[i] = xjd1JsonEdit(p->u.array.apElem[i]);
        }
      }
      break;
    }
    case XJD1_STRUCT: {
      JsonStructElem *pSrc, *pDest, **ppPrev;
      ppPrev = &pNew->u.pStruct;
      for(pSrc=p->u.pStruct; pSrc; pSrc=pSrc->pNext){
        pDest = malloc( sizeof(*pDest) );
        if( pDest==0 ) break;
        memset(pDest, 0, sizeof(*pDest));
        *ppPrev = pDest;
        ppPrev = &pDest->pNext;
        pDest->zLabel = xjd1PoolDup(0, pSrc->zLabel, -1);
        pDest->pValue = xjd1JsonEdit(pSrc->pValue);
      }
................................................................................
      case XJD1_STRING: {
        renderString(pOut, p->u.z);
        break;
      }
      case XJD1_ARRAY: {
        char cSep = '[';
        int i;
        for(i=0; i<p->u.array.nElem; i++){
          xjd1StringAppend(pOut, &cSep, 1);
          cSep = ',';
          xjd1JsonRender(pOut, p->u.array.apElem[i]);
        }
        xjd1StringAppend(pOut, "]", 1);
        break;
      }
      case XJD1_STRUCT: {
        char cSep = '{';
        JsonStructElem *pElem;
        for(pElem=p->u.pStruct; pElem; pElem=pElem->pNext){
          xjd1StringAppend(pOut, &cSep, 1);
          cSep = ',';
          renderString(pOut, pElem->zLabel);
          xjd1StringAppend(pOut, ":", 1);
          xjd1JsonRender(pOut, pElem->pValue);
        }
        xjd1StringAppend(pOut, "}", 1);
................................................................................

/* Enter point to the first token of the JSON object.
** Exit pointing to the first token past end end of the
** JSON object.
*/
static JsonNode *parseJson(JsonStr *pIn){
  JsonNode *pNew;
  pNew = xjd1JsonNew();
  if( pNew==0 ) return 0;
  pNew->eJType = tokenType(pIn);
  switch( pNew->eJType ){
    case JSON_BEGIN_STRUCT: {
      JsonStructElem **ppTail;
      tokenNext(pIn);
      if( tokenType(pIn)==JSON_END_STRUCT ) break;
      ppTail = &pNew->u.pStruct;
      while( 1 ){
        JsonStructElem *pElem;
        if( tokenType(pIn)!=JSON_STRING ){
          goto json_error; 
        }
        pElem = malloc( sizeof(*pElem) );
        if( pElem==0 ) goto json_error;
        memset(pElem, 0, sizeof(*pElem));
        *ppTail = pElem;

        ppTail = &pElem->pNext;
        pElem->zLabel = tokenDequoteString(pIn);
        tokenNext(pIn);
        if( tokenType(pIn)!=JSON_COLON ){
          goto json_error;
        }
        tokenNext(pIn);
................................................................................
      break;
    }
    case JSON_BEGIN_ARRAY: {
      int nAlloc = 0;
      tokenNext(pIn);
      if( tokenType(pIn)==JSON_END_ARRAY ) break;
      while( 1 ){
        if( pNew->u.array.nElem>=nAlloc ){
          JsonNode **pNewArray;
          nAlloc = nAlloc*2 + 5;
          pNewArray = realloc(pNew->u.array.apElem,
                              sizeof(JsonNode*)*nAlloc);
          if( pNewArray==0 ) goto json_error;
          pNew->u.array.apElem = pNewArray;
        }
        pNew->u.array.apElem[pNew->u.array.nElem++] = parseJson(pIn);
        if( tokenType(pIn)==JSON_COMMA ){
          tokenNext(pIn);
        }else if( tokenType(pIn)==JSON_END_ARRAY ){
          tokenNext(pIn);
          break;
        }else{
          goto json_error;







|
|

|




|







 







|
>
>
>
>
>
|
|
|
|
>







 







|









|




|
|
|






|
|
|







 







|


|







|







 







|







|









>







 







|


|


|

|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
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
..
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
...
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
...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
    switch( p->eJType ){
      case XJD1_STRING: {
        free(p->u.z);
        break;
      }
      case XJD1_ARRAY: {
        int i;
        for(i=0; i<p->u.ar.nElem; i++){
          xjd1JsonFree(p->u.ar.apElem[i]);
        }
        free(p->u.ar.apElem);
        break;
      }
      case XJD1_STRUCT: {
        JsonStructElem *pElem, *pNext;
        for(pElem=p->u.st.pFirst; pElem; pElem=pNext){
          pNext = pElem->pNext;
          free(pElem->zLabel);
          xjd1JsonFree(pElem->pValue);
          free(pElem);
        }
        break;
      }
................................................................................
    free(p);
  }
}

/*
** Allocate a new Json node.
*/
JsonNode *xjd1JsonNew(Pool *pPool){
  JsonNode *p;
  if( pPool ){
    p = xjd1PoolMalloc(pPool, sizeof(*p));
    if( p ) p->nRef = 10000;
  }else{
    p = malloc( sizeof(*p) );
    if( p ){
      memset(p, 0, sizeof(*p));
      p->nRef = 1;
    }
  }
  return p;
}

/*
** Increase the reference count on a JSON object.  
**
................................................................................
** reference count is exactly 1.  If the input JSON object has a reference
** count greater than 1, then make a copy and return the copy.
*/
JsonNode *xjd1JsonEdit(JsonNode *p){
  JsonNode *pNew;
  if( p==0 ) return 0;
  if( p->nRef==1 ) return p;
  pNew = xjd1JsonNew(0);
  if( pNew==0 ) return 0;
  pNew->eJType = p->eJType;
  switch( pNew->eJType ){
    case XJD1_STRING: {
      pNew->u.z = xjd1PoolDup(0, p->u.z, -1);
      break;
    }
    case XJD1_ARRAY: {
      JsonNode **ap;
      pNew->u.ar.apElem = ap = malloc( sizeof(JsonNode*)*p->u.ar.nElem );
      if( ap==0 ){
        pNew->eJType = XJD1_NULL;
      }else{
        int i;
        pNew->u.ar.nElem = p->u.ar.nElem;
        for(i=0; i<p->u.ar.nElem; i++){
          ap[i] = xjd1JsonEdit(p->u.ar.apElem[i]);
        }
      }
      break;
    }
    case XJD1_STRUCT: {
      JsonStructElem *pSrc, *pDest, **ppPrev;
      ppPrev = &pNew->u.st.pFirst;
      for(pSrc=p->u.st.pFirst; pSrc; pSrc=pSrc->pNext){
        pNew->u.st.pLast = pDest = malloc( sizeof(*pDest) );
        if( pDest==0 ) break;
        memset(pDest, 0, sizeof(*pDest));
        *ppPrev = pDest;
        ppPrev = &pDest->pNext;
        pDest->zLabel = xjd1PoolDup(0, pSrc->zLabel, -1);
        pDest->pValue = xjd1JsonEdit(pSrc->pValue);
      }
................................................................................
      case XJD1_STRING: {
        renderString(pOut, p->u.z);
        break;
      }
      case XJD1_ARRAY: {
        char cSep = '[';
        int i;
        for(i=0; i<p->u.ar.nElem; i++){
          xjd1StringAppend(pOut, &cSep, 1);
          cSep = ',';
          xjd1JsonRender(pOut, p->u.ar.apElem[i]);
        }
        xjd1StringAppend(pOut, "]", 1);
        break;
      }
      case XJD1_STRUCT: {
        char cSep = '{';
        JsonStructElem *pElem;
        for(pElem=p->u.st.pFirst; pElem; pElem=pElem->pNext){
          xjd1StringAppend(pOut, &cSep, 1);
          cSep = ',';
          renderString(pOut, pElem->zLabel);
          xjd1StringAppend(pOut, ":", 1);
          xjd1JsonRender(pOut, pElem->pValue);
        }
        xjd1StringAppend(pOut, "}", 1);
................................................................................

/* Enter point to the first token of the JSON object.
** Exit pointing to the first token past end end of the
** JSON object.
*/
static JsonNode *parseJson(JsonStr *pIn){
  JsonNode *pNew;
  pNew = xjd1JsonNew(0);
  if( pNew==0 ) return 0;
  pNew->eJType = tokenType(pIn);
  switch( pNew->eJType ){
    case JSON_BEGIN_STRUCT: {
      JsonStructElem **ppTail;
      tokenNext(pIn);
      if( tokenType(pIn)==JSON_END_STRUCT ) break;
      ppTail = &pNew->u.st.pFirst;
      while( 1 ){
        JsonStructElem *pElem;
        if( tokenType(pIn)!=JSON_STRING ){
          goto json_error; 
        }
        pElem = malloc( sizeof(*pElem) );
        if( pElem==0 ) goto json_error;
        memset(pElem, 0, sizeof(*pElem));
        *ppTail = pElem;
        pNew->u.st.pLast = pElem;
        ppTail = &pElem->pNext;
        pElem->zLabel = tokenDequoteString(pIn);
        tokenNext(pIn);
        if( tokenType(pIn)!=JSON_COLON ){
          goto json_error;
        }
        tokenNext(pIn);
................................................................................
      break;
    }
    case JSON_BEGIN_ARRAY: {
      int nAlloc = 0;
      tokenNext(pIn);
      if( tokenType(pIn)==JSON_END_ARRAY ) break;
      while( 1 ){
        if( pNew->u.ar.nElem>=nAlloc ){
          JsonNode **pNewArray;
          nAlloc = nAlloc*2 + 5;
          pNewArray = realloc(pNew->u.ar.apElem,
                              sizeof(JsonNode*)*nAlloc);
          if( pNewArray==0 ) goto json_error;
          pNew->u.ar.apElem = pNewArray;
        }
        pNew->u.ar.apElem[pNew->u.ar.nElem++] = parseJson(pIn);
        if( tokenType(pIn)==JSON_COMMA ){
          tokenNext(pIn);
        }else if( tokenType(pIn)==JSON_END_ARRAY ){
          tokenNext(pIn);
          break;
        }else{
          goto json_error;

Changes to src/parse.y.

62
63
64
65
66
67
68







































69
70
71
72
73
74
75
..
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
119
120
121
122
123
124
125
126

































127
128
129
130
131
132
133
...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
...
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
...
201
202
203
204
205
206
207

208
209
210
211
212
213
214
...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
// Input is a single XJD1 command
%type cmd {Command*}
%destructor cmd {(void)p;}
input ::= cmd(X) SEMI.   {p->pCmd = X;}

/////////////////////////// Expression Processing /////////////////////////////
//








































%left OR.
%left AND.
%right NOT.
%left IS LIKEOP BETWEEN IN NE EQ.
%left GT LE LT GE.
%right ESCAPE.
................................................................................
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%left COLLATE.
%right BITNOT.

%include {
  /* Generate an Expr object from a token */
  static Expr *tokExpr(Parse *p, int eType, Token *pTok){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = eType; 
      pNew->eClass = XJD1_EXPR_TK;
      pNew->u.tk = *pTok;
    }
    return pNew;
  }

  /* Generate an Expr object that is a binary operator on two
  ** other Expr objects. */
  static Expr *biExpr(Parse *p, Expr *pLeft, int eOp, Expr *pRight){
................................................................................

  /* Generate an Expr object that is a subquery. */
  static Expr *subqExpr(Parse *p, Query *pQuery){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_SELECT;
      pNew->eClass = XJD1_EXPR_Q;
      pNew->u.q = pQuery;

































    }
    return pNew;
  }

  /* Append a new expression to an expression list.  Allocate the
  ** expression list object if necessary. */
  static ExprList *apndExpr(Parse *p, ExprList *pList, Expr *pExpr, Token *pT){
................................................................................
    if( pList==0 ){
      pList = xjd1PoolMallocZero(p->pPool, sizeof(*pList)+4*sizeof(ExprItem));
      if( pList==0 ) return 0;
      pList->nEAlloc = 0;
    }
    if( pList->nEAlloc<=pList->nEItem ){
      ExprItem *pNew;
      int n = pList->nEAlloc*2;
      if( n==0 ) n = 4;
      pNew = xjd1PoolMalloc(p->pPool, sizeof(ExprItem)*n);
      if( pNew==0 ) return pList;
      memcpy(pNew, pList->apEItem, pList->nEItem*sizeof(ExprItem));
      pList->nEAlloc = n;
      pList->apEItem = pNew;
    }
    pItem = &pList->apEItem[pList->nEItem++];
................................................................................
      memset(&pItem->tkAs, 0, sizeof(pItem->tkAs));
    }
    pItem->pExpr = pExpr;
    return pList;
  }
}

jvalue(A) ::= INTEGER(X).  {A = X;}
jvalue(A) ::= FLOAT(X).    {A = X;}
jvalue(A) ::= STRING(X).   {A = X;}
jvalue(A) ::= TRUE(X).     {A = X;}
jvalue(A) ::= FALSE(X).    {A = X;}
jvalue(A) ::= NULL(X).     {A = X;}
jvalue(A) ::= JVALUE(X).   {A = X;}

%type jexpr {Expr*}
jexpr(A) ::= expr(X).      {A = X;}
jexpr(A) ::= JVALUE(X).    {A = tokExpr(p,@X,&X);}

%type lvalue {Expr*}
lvalue(A) ::= ID(X).                  {A = tokExpr(p,@X,&X);}
lvalue(A) ::= lvalue(X) DOT ID(Y).    {A = biExpr(p,X,TK_DOT,tokExpr(p,@Y,&Y));}
lvalue(A) ::= lvalue(X) LB expr(Y) RB.{A = biExpr(p,X,TK_LB,Y);}

%type expr {Expr*}
expr(A) ::= lvalue(X).    {A = X;}
expr(A) ::= INTEGER(X).   {A = tokExpr(p,@X,&X);}
expr(A) ::= FLOAT(X).     {A = tokExpr(p,@X,&X);}
expr(A) ::= STRING(X).    {A = tokExpr(p,@X,&X);}
expr(A) ::= TRUE(X).      {A = tokExpr(p,@X,&X);}
expr(A) ::= FALSE(X).     {A = tokExpr(p,@X,&X);}
expr(A) ::= NULL(X).      {A = tokExpr(p,@X,&X);}
expr(A) ::= ID(X) LP exprlist(Y) RP.  {A = funcExpr(p,&X,Y);}
expr(A) ::= expr(X) AND(OP) expr(Y).  {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) OR(OP) expr(Y).              {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).     {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y).           {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
                                                 {A = biExpr(p,X,@OP,Y);}
................................................................................
expr(A) ::= expr(X) IS NOT expr(Y).              {A = biExpr(p,X,TK_NOT_IS,Y);}
expr(A) ::= NOT(OP) expr(X).                     {A = biExpr(p,X,@OP,0);}
expr(A) ::= BITNOT(OP) expr(X).                  {A = biExpr(p,X,@OP,0);}
expr(A) ::= MINUS(OP) expr(X). [BITNOT]          {A = biExpr(p,X,@OP,0);}
expr(A) ::= PLUS(OP) expr(X). [BITNOT]           {A = biExpr(p,X,@OP,0);}
expr(A) ::= LP select(X) RP.                     {A = subqExpr(p,X);}
expr(A) ::= LP expr(X) RP.                       {A = X;}


%type exprlist {ExprList*}
%type nexprlist {ExprList*}
exprlist(A) ::= nexprlist(X).     {A = X;}
exprlist(A) ::= .                 {A = 0;}
nexprlist(A) ::= expr(X).                     {A = apndExpr(p,0,X,0);}
nexprlist(A) ::= nexprlist(X) COMMA expr(Y).  {A = apndExpr(p,X,Y,0);}
................................................................................
    ExprList *pGroupBy;
    Expr *pHaving;
  } GroupByHaving;

  /* Construct a simple query object */
  static Query *simpleQuery(
    Parse *p,
    ExprList *pCol,
    DataSrc *pFrom,
    Expr *pWhere,
    GroupByHaving *pGroupBy,
    ExprList *pOrderBy,
    LimitOffset *pLimit
  ){
    Query *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eQType = TK_SELECT;
      pNew->u.simple.pCol = pCol;
      pNew->u.simple.pFrom = pFrom;
      pNew->u.simple.pWhere = pWhere;
      pNew->u.simple.pGroupBy = pGroupBy ? pGroupBy->pGroupBy : 0;
      pNew->u.simple.pHaving = pGroupBy ? pGroupBy->pHaving : 0;
      pNew->u.simple.pOrderBy = pOrderBy;
      pNew->u.simple.pLimit = pLimit ? pLimit->pLimit : 0;
      pNew->u.simple.pOffset = pLimit ? pLimit->pOffset : 0;
................................................................................
select(A) ::= oneselect(X).                        {A = X;}
select(A) ::= eselect(X) UNION(OP) eselect(Y).     {A=compoundQuery(p,X,@OP,Y);}
select(A) ::= eselect(X) UNION ALL(OP) eselect(Y). {A=compoundQuery(p,X,@OP,Y);}
select(A) ::= eselect(X) EXCEPT(OP) eselect(Y).    {A=compoundQuery(p,X,@OP,Y);}
select(A) ::= eselect(X) INTERSECT(OP) eselect(Y). {A=compoundQuery(p,X,@OP,Y);}
eselect(A) ::= select(X).                          {A = X;}
eselect(A) ::= expr(X).       // must be (SELECT...)
  {A = X->u.q;}

oneselect(A) ::= SELECT selcollist_opt(S) from(F) where_opt(W)
                    groupby_opt(G) orderby_opt(O) limit_opt(L).
  {A = simpleQuery(p,S,F,W,&G,O,&L);}


// selcollist is a list of expressions that are to become the return
// values of the SELECT statement.
//
%type selcollist_opt {ExprList*}
%type selcollist {ExprList*}
selcollist_opt(A) ::= .                             {A = 0;}
selcollist_opt(A) ::= selcollist(X).                {A = X;}
selcollist(A) ::= jexpr(Y).                         {A = apndExpr(p,0,Y,0);}
selcollist(A) ::= jexpr(Y) AS ID(Z).                {A = apndExpr(p,0,Y,&Z);}
selcollist(A) ::= selcollist(X) COMMA jexpr(Y).     {A = apndExpr(p,X,Y,0);}
selcollist(A) ::= selcollist(X) COMMA jexpr(Y) AS ID(Z).
                                                    {A = apndExpr(p,X,Y,&Z);}


// A complete FROM clause.
//
%type from {DataSrc*}
%type fromlist {DataSrc*}
%type fromitem {DataSrc*}
%include {
................................................................................
    pNew->u.update.pWhere = W;
    pNew->u.update.pChng = L;
  }
  A = pNew;
}

%type setlist {ExprList*}
setlist(A) ::= setlist(X) COMMA lvalue(Y) EQ jexpr(Z). {
   A = apndExpr(p,X,Y,0);
   A = apndExpr(p,A,Z,0);
}
setlist(A) ::= lvalue(Y) EQ jexpr(Z). {
   A = apndExpr(p,0,Y,0);
   A = apndExpr(p,A,Z,0);
}



////////////////////////// The INSERT command /////////////////////////////////
//
cmd(A) ::= INSERT INTO tabname(N) VALUE jvalue(V). {
  Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_INSERT;
    pNew->u.ins.name = N;
    pNew->u.ins.jvalue = V;
  }
  A = pNew;
}
cmd(A) ::= INSERT INTO tabname(N) select(Q). {
  Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_INSERT;
................................................................................
  }
  A = pNew;
}

////////////////////////// The PRAGMA command /////////////////////////////////
//
%include {
  static Command *makePrag(Parse *p, Token *pName, Token *pValue){
    Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eCmdType = TK_PRAGMA;
      pNew->u.prag.name = *pName;
      if( pValue ){
        pNew->u.prag.jvalue = *pValue;
      }else{
        pNew->u.prag.jvalue.n = 0;
      }
    }
    return pNew;
  }
}
cmd(A) ::= PRAGMA ID(N).                  {A = makePrag(p,&N,0);}
cmd(A) ::= PRAGMA ID(N) EQ jvalue(V).     {A = makePrag(p,&N,&V);}
cmd(A) ::= PRAGMA ID(N) LP jvalue(V) RP.  {A = makePrag(p,&N,&V);}







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







 







|
|


|

|







 







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







 







|
|







 







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







 







>







 







|









|







 







|

|




|
|

|
<
|
|
<
<
<
<
<
>







 







|



|








|




|







 







|





<
<
|





|
|
|
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
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
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
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
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
258
259
260
261
262
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
...
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
386
387
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
...
573
574
575
576
577
578
579
580
581
582
583
584
585


586
587
588
589
590
591
592
593
594
// Input is a single XJD1 command
%type cmd {Command*}
%destructor cmd {(void)p;}
input ::= cmd(X) SEMI.   {p->pCmd = X;}

/////////////////////////// Expression Processing /////////////////////////////
//

%include {
  /* A JSON literal for a real number */
  static JsonNode *jsonReal(Parse *p, Token *pTok){
    JsonNode *pNew = xjd1JsonNew(p->pPool);
    if( pNew ){
      pNew->eJType = XJD1_REAL;
      pNew->u.r = atof(pTok->z);
    }
    return pNew;
  }

  /* A JSON literal for a string */
  static JsonNode *jsonString(Parse *p, Token *pTok){
    JsonNode *pNew = xjd1JsonNew(p->pPool);
    if( pNew ){
      pNew->eJType = XJD1_STRING;
      pNew->u.z = xjd1PoolDup(p->pPool, pTok->z, pTok->n);
    }
    return pNew;
  }

  /* A JSON literal for a boolean or NULL */
  static JsonNode *jsonType(Parse *p, int eJType){
    JsonNode *pNew = xjd1JsonNew(p->pPool);
    if( pNew ){
      pNew->eJType = eJType;
    }
    return pNew;
  }
}
%type jvalue {JsonNode*}
jvalue(A) ::= INTEGER(X).              {A = jsonReal(p,&X);}
jvalue(A) ::= FLOAT(X).                {A = jsonReal(p,&X);}
jvalue(A) ::= STRING(X).               {A = jsonString(p,&X);}
jvalue(A) ::= TRUE.                    {A = jsonType(p,XJD1_TRUE);}
jvalue(A) ::= FALSE.                   {A = jsonType(p,XJD1_FALSE);}
jvalue(A) ::= NULL.                    {A = jsonType(p,XJD1_NULL);}


%left OR.
%left AND.
%right NOT.
%left IS LIKEOP BETWEEN IN NE EQ.
%left GT LE LT GE.
%right ESCAPE.
................................................................................
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%left COLLATE.
%right BITNOT.

%include {
  /* Generate an Expr object from an identifer token */
  static Expr *idExpr(Parse *p, Token *pTok){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_ID;
      pNew->eClass = XJD1_EXPR_TK;
      pNew->u.tk.t = *pTok;
    }
    return pNew;
  }

  /* Generate an Expr object that is a binary operator on two
  ** other Expr objects. */
  static Expr *biExpr(Parse *p, Expr *pLeft, int eOp, Expr *pRight){
................................................................................

  /* Generate an Expr object that is a subquery. */
  static Expr *subqExpr(Parse *p, Query *pQuery){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_SELECT;
      pNew->eClass = XJD1_EXPR_Q;
      pNew->u.subq.p = pQuery;
    }
    return pNew;
  }

  /* Generate an Expr object that is a structure */
  static Expr *stExpr(Parse *p, ExprList *pList){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_STRUCT;
      pNew->eClass = XJD1_EXPR_STRUCT;
      pNew->u.st = pList;
    }
    return pNew;
  }

  /* Generate an Expr object that is an array7 */
  static Expr *arExpr(Parse *p, ExprList *pList){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_ARRAY;
      pNew->eClass = XJD1_EXPR_ARRAY;
      pNew->u.ar = pList;
    }
    return pNew;
  }

  /* Generate an Expr object that is JSON value literal */
  static Expr *jsonExpr(Parse *p, JsonNode *pNode){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_JVALUE;
      pNew->eClass = XJD1_EXPR_JSON;
      pNew->u.json.p = pNode;
    }
    return pNew;
  }

  /* Append a new expression to an expression list.  Allocate the
  ** expression list object if necessary. */
  static ExprList *apndExpr(Parse *p, ExprList *pList, Expr *pExpr, Token *pT){
................................................................................
    if( pList==0 ){
      pList = xjd1PoolMallocZero(p->pPool, sizeof(*pList)+4*sizeof(ExprItem));
      if( pList==0 ) return 0;
      pList->nEAlloc = 0;
    }
    if( pList->nEAlloc<=pList->nEItem ){
      ExprItem *pNew;
      int n = pList->nEAlloc*4;
      if( n==0 ) n = 10;
      pNew = xjd1PoolMalloc(p->pPool, sizeof(ExprItem)*n);
      if( pNew==0 ) return pList;
      memcpy(pNew, pList->apEItem, pList->nEItem*sizeof(ExprItem));
      pList->nEAlloc = n;
      pList->apEItem = pNew;
    }
    pItem = &pList->apEItem[pList->nEItem++];
................................................................................
      memset(&pItem->tkAs, 0, sizeof(pItem->tkAs));
    }
    pItem->pExpr = pExpr;
    return pList;
  }
}

%type lvalue {Expr*}
lvalue(A) ::= ID(X).                   {A = idExpr(p,&X);}
lvalue(A) ::= lvalue(X) DOT ID(Y).     {A = biExpr(p,X,TK_DOT,idExpr(p,&Y));}
lvalue(A) ::= lvalue(X) LB expr(Y) RB. {A = biExpr(p,X,TK_LB,Y);}

%type expr {Expr*}
expr(A) ::= lvalue(X).               {A = X;}
expr(A) ::= jvalue(X).               {A = jsonExpr(p,X);}
expr(A) ::= LC structlist(X) RC.     {A = stExpr(p,X);}
expr(A) ::= LC RC.                   {A = stExpr(p,0);}
expr(A) ::= LB arraylist(X) RB.      {A = arExpr(p,X);}
expr(A) ::= LB RB.                   {A = arExpr(p,0);}

%type structlist {ExprList*}
structlist(A) ::= ID|STRING(Y) COLON expr(Z).    {A = apndExpr(p,0,Z,&Y);}
structlist(A) ::= structlist(X) COMMA ID|STRING(Y) COLON expr(Z).
                                                 {A = apndExpr(p,X,Z,&Y);}
%type arraylist {ExprList*}
arraylist(A) ::= expr(Y).                        {A = apndExpr(p,0,Y,0);}
arraylist(A) ::= arraylist(X) COMMA expr(Y).     {A = apndExpr(p,X,Y,0);}





expr(A) ::= ID(X) LP exprlist(Y) RP.  {A = funcExpr(p,&X,Y);}
expr(A) ::= expr(X) AND(OP) expr(Y).  {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) OR(OP) expr(Y).              {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).     {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y).           {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
                                                 {A = biExpr(p,X,@OP,Y);}
................................................................................
expr(A) ::= expr(X) IS NOT expr(Y).              {A = biExpr(p,X,TK_NOT_IS,Y);}
expr(A) ::= NOT(OP) expr(X).                     {A = biExpr(p,X,@OP,0);}
expr(A) ::= BITNOT(OP) expr(X).                  {A = biExpr(p,X,@OP,0);}
expr(A) ::= MINUS(OP) expr(X). [BITNOT]          {A = biExpr(p,X,@OP,0);}
expr(A) ::= PLUS(OP) expr(X). [BITNOT]           {A = biExpr(p,X,@OP,0);}
expr(A) ::= LP select(X) RP.                     {A = subqExpr(p,X);}
expr(A) ::= LP expr(X) RP.                       {A = X;}


%type exprlist {ExprList*}
%type nexprlist {ExprList*}
exprlist(A) ::= nexprlist(X).     {A = X;}
exprlist(A) ::= .                 {A = 0;}
nexprlist(A) ::= expr(X).                     {A = apndExpr(p,0,X,0);}
nexprlist(A) ::= nexprlist(X) COMMA expr(Y).  {A = apndExpr(p,X,Y,0);}
................................................................................
    ExprList *pGroupBy;
    Expr *pHaving;
  } GroupByHaving;

  /* Construct a simple query object */
  static Query *simpleQuery(
    Parse *p,
    Expr *pRes,
    DataSrc *pFrom,
    Expr *pWhere,
    GroupByHaving *pGroupBy,
    ExprList *pOrderBy,
    LimitOffset *pLimit
  ){
    Query *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eQType = TK_SELECT;
      pNew->u.simple.pRes = pRes;
      pNew->u.simple.pFrom = pFrom;
      pNew->u.simple.pWhere = pWhere;
      pNew->u.simple.pGroupBy = pGroupBy ? pGroupBy->pGroupBy : 0;
      pNew->u.simple.pHaving = pGroupBy ? pGroupBy->pHaving : 0;
      pNew->u.simple.pOrderBy = pOrderBy;
      pNew->u.simple.pLimit = pLimit ? pLimit->pLimit : 0;
      pNew->u.simple.pOffset = pLimit ? pLimit->pOffset : 0;
................................................................................
select(A) ::= oneselect(X).                        {A = X;}
select(A) ::= eselect(X) UNION(OP) eselect(Y).     {A=compoundQuery(p,X,@OP,Y);}
select(A) ::= eselect(X) UNION ALL(OP) eselect(Y). {A=compoundQuery(p,X,@OP,Y);}
select(A) ::= eselect(X) EXCEPT(OP) eselect(Y).    {A=compoundQuery(p,X,@OP,Y);}
select(A) ::= eselect(X) INTERSECT(OP) eselect(Y). {A=compoundQuery(p,X,@OP,Y);}
eselect(A) ::= select(X).                          {A = X;}
eselect(A) ::= expr(X).       // must be (SELECT...)
  {A = X->u.subq.p;}

oneselect(A) ::= SELECT expr_opt(S) from(F) where_opt(W)
                    groupby_opt(G) orderby_opt(O) limit_opt(L).
  {A = simpleQuery(p,S,F,W,&G,O,&L);}


// The result set of an expression can be either an JSON expression
// or nothing.
//
%type expr_opt {Expr*}

expr_opt(A) ::= .                       {A = 0;}
expr_opt(A) ::= expr(X).                {A = X;}







// A complete FROM clause.
//
%type from {DataSrc*}
%type fromlist {DataSrc*}
%type fromitem {DataSrc*}
%include {
................................................................................
    pNew->u.update.pWhere = W;
    pNew->u.update.pChng = L;
  }
  A = pNew;
}

%type setlist {ExprList*}
setlist(A) ::= setlist(X) COMMA lvalue(Y) EQ expr(Z). {
   A = apndExpr(p,X,Y,0);
   A = apndExpr(p,A,Z,0);
}
setlist(A) ::= lvalue(Y) EQ expr(Z). {
   A = apndExpr(p,0,Y,0);
   A = apndExpr(p,A,Z,0);
}



////////////////////////// The INSERT command /////////////////////////////////
//
cmd(A) ::= INSERT INTO tabname(N) VALUE expr(V). {
  Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_INSERT;
    pNew->u.ins.name = N;
    pNew->u.ins.pValue = V;
  }
  A = pNew;
}
cmd(A) ::= INSERT INTO tabname(N) select(Q). {
  Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_INSERT;
................................................................................
  }
  A = pNew;
}

////////////////////////// The PRAGMA command /////////////////////////////////
//
%include {
  static Command *makePrag(Parse *p, Token *pName, Expr *pValue){
    Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eCmdType = TK_PRAGMA;
      pNew->u.prag.name = *pName;
      if( pValue ){


        pNew->u.prag.pValue = pValue;
      }
    }
    return pNew;
  }
}
cmd(A) ::= PRAGMA ID(N).                {A = makePrag(p,&N,0);}
cmd(A) ::= PRAGMA ID(N) EQ expr(V).     {A = makePrag(p,&N,V);}
cmd(A) ::= PRAGMA ID(N) LP expr(V) RP.  {A = makePrag(p,&N,V);}

Changes to src/query.c.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
** within the statement.
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){
  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprListInit(pQuery->u.simple.pCol, pStmt, pQuery);
    xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);
    xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery);
    xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery);
    xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery);
................................................................................
** by the next call to QueryStep(), QueryReset(), or QueryClose().
*/
JsonNode *xjd1QueryValue(Query *p){
  JsonNode *pOut = 0;
  if( p ){
    if( p->pOut ){ xjd1JsonFree(p->pOut); p->pOut = 0; }
    if( p->eQType==TK_SELECT ){
      if(  p->u.simple.pCol && p->u.simple.pCol->nEItem>0 ){
        pOut = p->pOut = xjd1ExprListEval(p->u.simple.pCol);
      }else{
        pOut = xjd1DataSrcValue(p->u.simple.pFrom);
      }
    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryValue(p->u.compound.pLeft);
    }else{
      pOut = xjd1QueryValue(p->u.compound.pRight);
................................................................................
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;
  if( pQuery->pOut ){
    xjd1JsonFree(pQuery->pOut);
    pQuery->pOut = 0;
  }
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprListClose(pQuery->u.simple.pCol);
    xjd1DataSrcClose(pQuery->u.simple.pFrom);
    xjd1ExprClose(pQuery->u.simple.pWhere);
    xjd1ExprListClose(pQuery->u.simple.pGroupBy);
    xjd1ExprClose(pQuery->u.simple.pHaving);
    xjd1ExprListClose(pQuery->u.simple.pOrderBy);
    xjd1ExprClose(pQuery->u.simple.pLimit);
    xjd1ExprClose(pQuery->u.simple.pOffset);
  }else{
    xjd1QueryClose(pQuery->u.compound.pLeft);
    xjd1QueryClose(pQuery->u.compound.pRight);
  }
  return rc;
}







|







 







|
|







 







|













23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
** within the statement.
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){
  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery);
    xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);
    xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery);
    xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery);
    xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery);
................................................................................
** by the next call to QueryStep(), QueryReset(), or QueryClose().
*/
JsonNode *xjd1QueryValue(Query *p){
  JsonNode *pOut = 0;
  if( p ){
    if( p->pOut ){ xjd1JsonFree(p->pOut); p->pOut = 0; }
    if( p->eQType==TK_SELECT ){
      if(  p->u.simple.pRes ){
        pOut = p->pOut = xjd1ExprEval(p->u.simple.pRes);
      }else{
        pOut = xjd1DataSrcValue(p->u.simple.pFrom);
      }
    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryValue(p->u.compound.pLeft);
    }else{
      pOut = xjd1QueryValue(p->u.compound.pRight);
................................................................................
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;
  if( pQuery->pOut ){
    xjd1JsonFree(pQuery->pOut);
    pQuery->pOut = 0;
  }
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprClose(pQuery->u.simple.pRes);
    xjd1DataSrcClose(pQuery->u.simple.pFrom);
    xjd1ExprClose(pQuery->u.simple.pWhere);
    xjd1ExprListClose(pQuery->u.simple.pGroupBy);
    xjd1ExprClose(pQuery->u.simple.pHaving);
    xjd1ExprListClose(pQuery->u.simple.pOrderBy);
    xjd1ExprClose(pQuery->u.simple.pLimit);
    xjd1ExprClose(pQuery->u.simple.pOffset);
  }else{
    xjd1QueryClose(pQuery->u.compound.pLeft);
    xjd1QueryClose(pQuery->u.compound.pRight);
  }
  return rc;
}

Changes to src/stmt.c.

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
      char *zErr;
      char *zSql;
      if( pCmd->u.ins.pQuery ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, 
                 "INSERT INTO ... SELECT not yet implemented");
        break;
      }
      pNode = xjd1JsonParse(pCmd->u.ins.jvalue.z, pCmd->u.ins.jvalue.n);
      if( pNode==0 ){
        xjd1Error(pStmt->pConn, XJD1_ERROR,
                  "malformed JSON");
        break;
      }
      xjd1StringInit(&json,0,0);
      xjd1JsonRender(&json, pNode);
      xjd1JsonFree(pNode);
      zSql = sqlite3_mprintf("INSERT INTO \"%.*w\" VALUES('%q')",
                  pCmd->u.ins.name.n, pCmd->u.ins.name.z,
                  xjd1StringText(&json));
      xjd1StringClear(&json);







|
|
<
<
<
<







151
152
153
154
155
156
157
158
159




160
161
162
163
164
165
166
      char *zErr;
      char *zSql;
      if( pCmd->u.ins.pQuery ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, 
                 "INSERT INTO ... SELECT not yet implemented");
        break;
      }
      pNode = xjd1ExprEval(pCmd->u.ins.pValue);
      if( pNode==0 ) break;




      xjd1StringInit(&json,0,0);
      xjd1JsonRender(&json, pNode);
      xjd1JsonFree(pNode);
      zSql = sqlite3_mprintf("INSERT INTO \"%.*w\" VALUES('%q')",
                  pCmd->u.ins.name.n, pCmd->u.ins.name.z,
                  xjd1StringText(&json));
      xjd1StringClear(&json);

Changes to src/tokenize.c.

185
186
187
188
189
190
191
















192
193
194
195
196
197
198
...
264
265
266
267
268
269
270




271
272
273
274
275
276
277
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
      *tokenType = TK_LP;
      return 1;
    }
    case ')': {
      *tokenType = TK_RP;
      return 1;
    }
















    case ';': {
      *tokenType = TK_SEMI;
      return 1;
    }
    case '+': {
      *tokenType = TK_PLUS;
      return 1;
................................................................................
        return 2;
      }
    }
    case ',': {
      *tokenType = TK_COMMA;
      return 1;
    }




    case '&': {
      *tokenType = TK_BITAND;
      return 1;
    }
    case '~': {
      *tokenType = TK_BITNOT;
      return 1;
................................................................................
        while( xjd1Isdigit(z[i]) ){ i++; }
        *tokenType = TK_FLOAT;
      }
      while( xjd1Isident(z[i]) ){
        *tokenType = TK_ILLEGAL;
        i++;
      }
      return i;
    }
    case '[': {
      int depth = 1;
      *tokenType = TK_ILLEGAL;
      for(i=1; (c=z[i])!=0; i++){
        if( c=='"' ){
          for(i++; (c=z[i])!=0 && c!='"'; i++){
            if( c=='\\' && z[i+1] ) i++;
          }
          if( c==0 ) return i;
        }else if( c=='[' ){
          depth++;
        }else if( c==']' ){
          depth--;
          if( depth==0 ){
            *tokenType = TK_JVALUE;
            return i+1;
          }
        }
      }
      return i;
    }
    case '{': {
      int depth = 1;
      *tokenType = TK_ILLEGAL;
      for(i=1; (c=z[i])!=0; i++){
        if( c=='"' ){
          for(i++; (c=z[i])!=0 && c!='"'; i++){
            if( c=='\\' && z[i+1] ) i++;
          }
          if( c==0 ) return i;
        }else if( c=='{' ){
          depth++;
        }else if( c=='}' ){
          depth--;
          if( depth==0 ){
            *tokenType = TK_JVALUE;
            return i+1;
          }
        }
      }
      return i;
    }
    default: {
      if( !xjd1Isident(*z) ){
        break;
      }
      for(i=1; xjd1Isident(z[i]); i++){}







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







 







>
>
>
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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
...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
...
336
337
338
339
340
341
342










































343
344
345
346
347
348
349
      *tokenType = TK_LP;
      return 1;
    }
    case ')': {
      *tokenType = TK_RP;
      return 1;
    }
    case '[': {
      *tokenType = TK_LB;
      return 1;
    }
    case ']': {
      *tokenType = TK_RB;
      return 1;
    }
    case '{': {
      *tokenType = TK_LC;
      return 1;
    }
    case '}': {
      *tokenType = TK_RC;
      return 1;
    }
    case ';': {
      *tokenType = TK_SEMI;
      return 1;
    }
    case '+': {
      *tokenType = TK_PLUS;
      return 1;
................................................................................
        return 2;
      }
    }
    case ',': {
      *tokenType = TK_COMMA;
      return 1;
    }
    case ':': {
      *tokenType = TK_COLON;
      return 1;
    }
    case '&': {
      *tokenType = TK_BITAND;
      return 1;
    }
    case '~': {
      *tokenType = TK_BITNOT;
      return 1;
................................................................................
        while( xjd1Isdigit(z[i]) ){ i++; }
        *tokenType = TK_FLOAT;
      }
      while( xjd1Isident(z[i]) ){
        *tokenType = TK_ILLEGAL;
        i++;
      }










































      return i;
    }
    default: {
      if( !xjd1Isident(*z) ){
        break;
      }
      for(i=1; xjd1Isident(z[i]); i++){}

Changes to src/trace.c.

141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
...
173
174
175
176
177
178
179
180
181
182

183
184
185
186
187
188
189
...
199
200
201
202
203
204
205
206
207
208

209
210
211
212
213
214
215
...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
         indent, "", pCmd->u.crtab.name.n, pCmd->u.crtab.name.z,
         pCmd->u.crtab.ifExists);
      break;
    }
    case TK_INSERT: {
      xjd1StringAppendF(pOut, "%*sInsert: %.*s\n",
         indent, "", pCmd->u.ins.name.n, pCmd->u.ins.name.z);
      if( pCmd->u.ins.jvalue.n ){
         xjd1StringAppendF(pOut, "%*s value=%.*s\n",
             indent, "", pCmd->u.ins.jvalue.n, pCmd->u.ins.jvalue.z);

      }else{
         xjd1TraceQuery(pOut, indent+3, pCmd->u.ins.pQuery);
      }
      break; 
    }
    case TK_DELETE: {
      xjd1StringAppendF(pOut, "%*sDELETE: %.*s\n",
................................................................................
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    case TK_PRAGMA: {
      xjd1StringAppendF(pOut, "%*sPRAGMA: %.*s",
         indent, "", pCmd->u.prag.name.n, pCmd->u.prag.name.z);
      if( pCmd->u.prag.jvalue.n>0 ){
        xjd1StringAppendF(pOut,"(%.*s)\n",
           pCmd->u.prag.jvalue.n, pCmd->u.prag.jvalue.z);

      }else{
        xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    default: {
      xjd1StringAppendF(pOut, "%*seCmdType = %s (%d)\n",
................................................................................
*/
void xjd1TraceQuery(String *pOut, int indent, const Query *p){
  if( p==0 ) return;
  xjd1StringAppendF(pOut, "%*seQType = %s\n",
          indent, "", xjd1TokenName(p->eQType));
  switch( p->eQType ){
    case TK_SELECT: {
      if( p->u.simple.pCol ){
        xjd1StringAppendF(pOut, "%*sColumn-List:\n", indent, "");
        xjd1TraceExprList(pOut, indent+3, p->u.simple.pCol);

      }
      if( p->u.simple.pFrom ){
        xjd1StringAppendF(pOut, "%*sFROM:\n", indent, "");
        xjd1TraceDataSrc(pOut, indent+3, p->u.simple.pFrom);
      }
      if( p->u.simple.pWhere ){
        xjd1StringAppendF(pOut, "%*sWHERE: ", indent, "");
................................................................................

/*
** Output the content of an expression.
*/
void xjd1TraceExpr(String *pOut, const Expr *p){
  if( p==0 ) return;
  switch( p->eType ){
    case TK_INTEGER:
    case TK_FLOAT:
    case TK_STRING:
    case TK_ID:
    case TK_TRUE:
    case TK_FALSE:
    case TK_NULL: {
      xjd1StringAppendF(pOut, "%s.%.*s",
          xjd1TokenName(p->eType),
          p->u.tk.n, p->u.tk.z);
      return;
    }
    case TK_DOT:
    case TK_AND:
    case TK_OR:
    case TK_LT:
    case TK_LE:
    case TK_GT:







|
|
|
>







 







|
|
|
>







 







|
|
|
>







 







|
|
|
<
<
<
<
<
<
<
<







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
297
298
299
300
301
302
303
304
305
306








307
308
309
310
311
312
313
         indent, "", pCmd->u.crtab.name.n, pCmd->u.crtab.name.z,
         pCmd->u.crtab.ifExists);
      break;
    }
    case TK_INSERT: {
      xjd1StringAppendF(pOut, "%*sInsert: %.*s\n",
         indent, "", pCmd->u.ins.name.n, pCmd->u.ins.name.z);
      if( pCmd->u.ins.pValue ){
         xjd1StringAppendF(pOut, "%*s value: ");
         xjd1TraceExpr(pOut, pCmd->u.ins.pValue);
         xjd1StringAppend(pOut, "\n", 1);
      }else{
         xjd1TraceQuery(pOut, indent+3, pCmd->u.ins.pQuery);
      }
      break; 
    }
    case TK_DELETE: {
      xjd1StringAppendF(pOut, "%*sDELETE: %.*s\n",
................................................................................
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    case TK_PRAGMA: {
      xjd1StringAppendF(pOut, "%*sPRAGMA: %.*s",
         indent, "", pCmd->u.prag.name.n, pCmd->u.prag.name.z);
      if( pCmd->u.prag.pValue ){
        xjd1StringAppend(pOut, "(", 1);
        xjd1TraceExpr(pOut, pCmd->u.ins.pValue);
        xjd1StringAppend(pOut, ")\n", 2);
      }else{
        xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    default: {
      xjd1StringAppendF(pOut, "%*seCmdType = %s (%d)\n",
................................................................................
*/
void xjd1TraceQuery(String *pOut, int indent, const Query *p){
  if( p==0 ) return;
  xjd1StringAppendF(pOut, "%*seQType = %s\n",
          indent, "", xjd1TokenName(p->eQType));
  switch( p->eQType ){
    case TK_SELECT: {
      if( p->u.simple.pRes ){
        xjd1StringAppendF(pOut, "%*sResult: ", indent, "");
        xjd1TraceExpr(pOut, p->u.simple.pRes);
        xjd1StringAppend(pOut, "\n", 1);
      }
      if( p->u.simple.pFrom ){
        xjd1StringAppendF(pOut, "%*sFROM:\n", indent, "");
        xjd1TraceDataSrc(pOut, indent+3, p->u.simple.pFrom);
      }
      if( p->u.simple.pWhere ){
        xjd1StringAppendF(pOut, "%*sWHERE: ", indent, "");
................................................................................

/*
** Output the content of an expression.
*/
void xjd1TraceExpr(String *pOut, const Expr *p){
  if( p==0 ) return;
  switch( p->eType ){
    case TK_JVALUE: {
      xjd1JsonRender(pOut, p->u.json.p);
      break;








    }
    case TK_DOT:
    case TK_AND:
    case TK_OR:
    case TK_LT:
    case TK_LE:
    case TK_GT:

Changes to src/xjd1Int.h.

36
37
38
39
40
41
42



43
44
45
46
47
48
49
...
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
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
...
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#define TK_NOT_LIKEOP     (TK_LIKEOP+128)
#define TK_NOT_IS         (TK_IS+128)
#define TK_FUNCTION       100
#define TK_SPACE          101
#define TK_ILLEGAL        102
#define TK_CREATEDATASET  103
#define TK_DROPDATASET    104




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;
................................................................................
  u16 eClass;               /* Expression class */
  xjd1_stmt *pStmt;         /* Statement this expression belongs to */
  union {
    struct {                /* Binary or unary operator. eClass==XJD1_EXPR_BI */
      Expr *pLeft;             /* Left operand.  Only operand for unary ops */
      Expr *pRight;            /* Right operand.  NULL for unary ops */
    } bi;
    Token tk;               /* Token values. eClass=EXPR_TK */


    struct {                /* Function calls.  eClass=EXPR_FUNC */
      Token name;              /* Name of the function */
      ExprList *args;          /* List of argumnts */
    } func;
    Query *q;               /* Subqueries. eClass=EXPR_Q */







  } u;
};
#define XJD1_EXPR_BI      1
#define XJD1_EXPR_TK      2
#define XJD1_EXPR_FUNC    3
#define XJD1_EXPR_Q       4







































/* Parsing context */
struct Parse {
  xjd1 *pConn;                    /* Connect for recording errors */
  Pool *pPool;                    /* Memory allocation pool */
  Command *pCmd;                  /* Results */
  Token sTok;                     /* Last token seen */
................................................................................
  union {
    struct {                    /* For compound queries */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
      int doneLeft;               /* True if left is run to completion */
    } compound;
    struct {                    /* For simple queries */
      ExprList *pCol;             /* List of result columns */
      DataSrc *pFrom;             /* The FROM clause */
      Expr *pWhere;               /* The WHERE clause */
      ExprList *pGroupBy;         /* The GROUP BY clause */
      Expr *pHaving;              /* The HAVING clause */
      ExprList *pOrderBy;         /* The ORDER BY clause */
      Expr *pLimit;               /* The LIMIT clause */
      Expr *pOffset;              /* The OFFSET clause */
................................................................................
      Token name;              /* Name of table */
    } crtab;
    struct {                /* Query statement */
      Query *pQuery;           /* The query */
    } q;
    struct {                /* Insert */
      Token name;              /* Table to insert into */
      Token jvalue;            /* Value to be inserted */
      Query *pQuery;           /* Query to insert from */
    } ins;
    struct {                /* Delete */
      Token name;              /* Table to delete */
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      Token name;              /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */
    } update;
    struct {                /* Pragma */
      Token name;              /* Pragma name */
      Token jvalue;            /* Argument or empty string */
    } prag;
  } u;
};

/* A single element of a JSON structure */
struct JsonStructElem {
  char *zLabel;             /* Label on this element */
  JsonStructElem *pNext;    /* Next element of the structure */
  JsonNode *pValue;         /* Value of this element */
};

/* A single element of a JSON value */
struct JsonNode {
  int eJType;               /* Element type */
  int nRef;                 /* Number of references */
  union {
    double r;               /* Real value */
    char *z;                /* String value */
    struct {                /* Array value */
      int nElem;               /* Number of elements */
      JsonNode **apElem;       /* Value of each element */
    } array;
    JsonStructElem *pStruct;   /* List of structure elements */
  } u;
};

/* Values for eJType */
#define XJD1_FALSE     0
#define XJD1_TRUE      1
#define XJD1_REAL      2
#define XJD1_NULL      3
#define XJD1_STRING    4
#define XJD1_ARRAY     5
#define XJD1_STRUCT    6

/******************************** context.c **********************************/
void xjd1ContextUnref(xjd1_context*);

/******************************** conn.c *************************************/
void xjd1Unref(xjd1*);
void xjd1Error(xjd1*,int,const char*,...);

................................................................................
int xjd1DataSrcClose(DataSrc*);
JsonNode *xjd1DataSrcValue(DataSrc*);

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

/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn);
JsonNode *xjd1JsonRef(JsonNode*);
void xjd1JsonRender(String*, JsonNode*);
JsonNode *xjd1JsonNew(void);
JsonNode *xjd1JsonEdit(JsonNode*);
void xjd1JsonFree(JsonNode*);

/******************************** malloc.c ***********************************/
Pool *xjd1PoolNew(void);
void xjd1PoolClear(Pool*);
void xjd1PoolDelete(Pool*);







>
>
>







 







|
>
>




|
>
>
>
>
>
>
>






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







 







|







 







|













|




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<








|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
...
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
...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304































305
306
307
308
309
310
311
...
317
318
319
320
321
322
323

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#define TK_NOT_LIKEOP     (TK_LIKEOP+128)
#define TK_NOT_IS         (TK_IS+128)
#define TK_FUNCTION       100
#define TK_SPACE          101
#define TK_ILLEGAL        102
#define TK_CREATEDATASET  103
#define TK_DROPDATASET    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;
................................................................................
  u16 eClass;               /* Expression class */
  xjd1_stmt *pStmt;         /* Statement this expression belongs to */
  union {
    struct {                /* Binary or unary operator. eClass==XJD1_EXPR_BI */
      Expr *pLeft;             /* Left operand.  Only operand for unary ops */
      Expr *pRight;            /* Right operand.  NULL for unary ops */
    } bi;
    struct {                /* Identifiers */
      Token t;                 /* token value.  eClass=EXPR_TK */
    } tk;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      Token name;              /* Name of the function */
      ExprList *args;          /* List of argumnts */
    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
    struct {                /* Literal value.  eClass=EXPR_JSON */
      JsonNode *p;             /* The value */
    } json;
    ExprList *ar;           /* Array literal.  eClass=EXPR_ARRAY */
    ExprList *st;           /* Struct literal.  eClass=EXPR_STRUCT */
  } u;
};
#define XJD1_EXPR_BI      1
#define XJD1_EXPR_TK      2
#define XJD1_EXPR_FUNC    3
#define XJD1_EXPR_Q       4
#define XJD1_EXPR_JSON    5
#define XJD1_EXPR_ARRAY   6
#define XJD1_EXPR_STRUCT  7

/* A single element of a JSON structure */
struct JsonStructElem {
  char *zLabel;             /* Label on this element */
  JsonStructElem *pNext;    /* Next element of the structure */
  JsonNode *pValue;         /* Value of this element */
};

/* A single element of a JSON value */
struct JsonNode {
  int eJType;               /* Element type */
  int nRef;                 /* Number of references */
  union {
    int b;                  /* Boolean value */
    double r;               /* Real value */
    char *z;                /* String value */
    struct {                /* Array value */
      int nElem;               /* Number of elements */
      JsonNode **apElem;       /* Value of each element */
    } ar;
    struct {                /* Struct value */
      JsonStructElem *pFirst;  /* List of structure elements */
      JsonStructElem *pLast;   /* Last element of the list */
    } st;
  } u;
};

/* Values for eJType */
#define XJD1_FALSE     0
#define XJD1_TRUE      1
#define XJD1_REAL      2
#define XJD1_NULL      3
#define XJD1_STRING    4
#define XJD1_ARRAY     5
#define XJD1_STRUCT    6

/* Parsing context */
struct Parse {
  xjd1 *pConn;                    /* Connect for recording errors */
  Pool *pPool;                    /* Memory allocation pool */
  Command *pCmd;                  /* Results */
  Token sTok;                     /* Last token seen */
................................................................................
  union {
    struct {                    /* For compound queries */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
      int doneLeft;               /* True if left is run to completion */
    } compound;
    struct {                    /* For simple queries */
      Expr *pRes;                 /* Result JSON string */
      DataSrc *pFrom;             /* The FROM clause */
      Expr *pWhere;               /* The WHERE clause */
      ExprList *pGroupBy;         /* The GROUP BY clause */
      Expr *pHaving;              /* The HAVING clause */
      ExprList *pOrderBy;         /* The ORDER BY clause */
      Expr *pLimit;               /* The LIMIT clause */
      Expr *pOffset;              /* The OFFSET clause */
................................................................................
      Token name;              /* Name of table */
    } crtab;
    struct {                /* Query statement */
      Query *pQuery;           /* The query */
    } q;
    struct {                /* Insert */
      Token name;              /* Table to insert into */
      Expr *pValue;            /* Value to be inserted */
      Query *pQuery;           /* Query to insert from */
    } ins;
    struct {                /* Delete */
      Token name;              /* Table to delete */
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      Token name;              /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */
    } update;
    struct {                /* Pragma */
      Token name;              /* Pragma name */
      Expr *pValue;            /* Argument or empty string */
    } prag;
  } u;
};
































/******************************** context.c **********************************/
void xjd1ContextUnref(xjd1_context*);

/******************************** conn.c *************************************/
void xjd1Unref(xjd1*);
void xjd1Error(xjd1*,int,const char*,...);

................................................................................
int xjd1DataSrcClose(DataSrc*);
JsonNode *xjd1DataSrcValue(DataSrc*);

/******************************** 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);
JsonNode *xjd1JsonRef(JsonNode*);
void xjd1JsonRender(String*, JsonNode*);
JsonNode *xjd1JsonNew(Pool*);
JsonNode *xjd1JsonEdit(JsonNode*);
void xjd1JsonFree(JsonNode*);

/******************************** malloc.c ***********************************/
Pool *xjd1PoolNew(void);
void xjd1PoolClear(Pool*);
void xjd1PoolDelete(Pool*);

Changes to test/base01.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- Basic sanity checking.
--
.new t1.db
.testcase 100
CREATE DATASET abc;
CREATE DATASET def;
INSERT INTO abc VALUE {"name":"abc"};
INSERT INTO def VALUE {"name":"def"};
.result

.testcase 110
SELECT FROM abc;
.result {"name":"abc"}

.testcase 120
SELECT FROM def;
.result {"name":"def"}

.testcase 130
SELECT 1 AS p, 2 AS q FROM abc;
.result {"p":1,"q":2}
.testcase 131
SELECT 1 AS p, 2+3 AS q FROM abc;
.result {"p":1,"q":5}
.testcase 132
SELECT 1 AS p, {"x":[1,2,3],"y":11} AS q FROM abc;
.result {"p":1,"q":{"x":[1,2,3],"y":11}}






|
|











|


|


|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- Basic sanity checking.
--
.new t1.db
.testcase 100
CREATE DATASET abc;
CREATE DATASET def;
INSERT INTO abc VALUE { name:"abc" };
INSERT INTO def VALUE { name:"def" };
.result

.testcase 110
SELECT FROM abc;
.result {"name":"abc"}

.testcase 120
SELECT FROM def;
.result {"name":"def"}

.testcase 130
SELECT { p:1, q:2 } FROM abc;
.result {"p":1,"q":2}
.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132
SELECT {p:1, q:{x:[1,2,3],y:11} FROM abc;
.result {"p":1,"q":{"x":[1,2,3],"y":11}}