UnQL

Check-in [365b149fa1]
Login

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

Overview
Comment:Change the parse tree to use zero-terminated strings rather than Token objects.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 365b149fa10753bd11650fa5bbaa2e3ec0b4f0a1
User & Date: drh 2011-06-29 19:02:28
Context
2011-06-29
20:10
Document references within expressions now working. check-in: ce30690c86 user: drh tags: trunk
19:02
Change the parse tree to use zero-terminated strings rather than Token objects. check-in: 365b149fa1 user: drh tags: trunk
17:53
Change DATASET to COLLECTION. check-in: 1db9558acf user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/datasrc.c.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
      break;
    }
    case TK_SELECT: {
      xjd1QueryInit(p->u.subq.q, pQuery->pStmt, pQuery);
      break;
    }
    case TK_ID: {
      char *zSql = sqlite3_mprintf("SELECT x FROM \"%.*w\"",
                            p->u.tab.name.n, p->u.tab.name.z);
      sqlite3_prepare_v2(pQuery->pStmt->pConn->db, zSql, -1, 
                         &p->u.tab.pStmt, 0);
      sqlite3_free(zSql);
      break;
    }
  }
  return XJD1_OK;







|
<







30
31
32
33
34
35
36
37

38
39
40
41
42
43
44
      break;
    }
    case TK_SELECT: {
      xjd1QueryInit(p->u.subq.q, pQuery->pStmt, pQuery);
      break;
    }
    case TK_ID: {
      char *zSql = sqlite3_mprintf("SELECT x FROM \"%w\"", p->u.tab.zName);

      sqlite3_prepare_v2(pQuery->pStmt->pConn->db, zSql, -1, 
                         &p->u.tab.pStmt, 0);
      sqlite3_free(zSql);
      break;
    }
  }
  return XJD1_OK;

Changes to src/expr.c.

84
85
86
87
88
89
90




91
92
93
94
95
96
97
...
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
...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
      walkExprList(p->u.ar, pAction);
      break;
    }
    case XJD1_EXPR_STRUCT: {
      walkExprList(p->u.st, pAction);
      break;
    }




  }
  return rc;
}


/*
** Callback for query expressions
................................................................................
  }
  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;
  pRes->eJType = XJD1_NULL;
  switch( p->eType ){
    case TK_STRUCT: {
      int i;
................................................................................
      for(i=0; i<pList->nEItem; i++){
        ExprItem *pItem = &pList->apEItem[i];
        pElem = malloc( sizeof(*pElem) );
        if( pElem==0 ) break;
        *ppPrev = pRes->u.st.pLast = pElem;
        ppPrev = &pElem->pNext;
        memset(pElem, 0, sizeof(*pElem));
        pElem->zLabel = xjd1PoolDup(0, pItem->tkAs.z, pItem->tkAs.n);
        pElem->pValue = xjd1ExprEval(pItem->pExpr);
      }
      break;
    }
    case TK_ARRAY: {
      int i;
      ExprList *pList = p->u.st;







>
>
>
>







 







>
>
>
>
>
>
>
>
>









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







 







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
...
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
...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
      walkExprList(p->u.ar, pAction);
      break;
    }
    case XJD1_EXPR_STRUCT: {
      walkExprList(p->u.st, pAction);
      break;
    }
    case XJD1_EXPR_LVALUE: {
      walkExpr(p->u.lvalue.pLeft, pAction);
      break;
    }
  }
  return rc;
}


/*
** Callback for query expressions
................................................................................
  }
  r = realFromJson(pNode);
  if( p->eType!=TK_JVALUE ){
    xjd1JsonFree(pNode);
  }
  return r;
}

/*
** Allocate a NULL JSON object.
*/
static JsonNode *nullJson(void){
  JsonNode *pRes = xjd1JsonNew(0);
  if( pRes ) pRes->eJType = XJD1_NULL;
  return pRes;
}

/*
** 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 ) return nullJson();
  switch( p->eType ){
    case TK_JVALUE: {
      return xjd1JsonRef(p->u.json.p);
    }
    case TK_DOT: {
      JsonNode *pBase = xjd1ExprEval(p->u.lvalue.pLeft);
      JsonStructElem *pElem;
      pRes = 0;
      if( pBase && pBase->eJType==XJD1_STRUCT ){
        for(pElem=pBase->u.st.pFirst; pElem; pElem=pElem->pNext){
          if( strcmp(pElem->zLabel, p->u.lvalue.zId)==0 ){
            pRes = xjd1JsonRef(pElem->pValue);

            break;
          }
        }
      }
      xjd1JsonFree(pBase);
      if( pRes==0 ) pRes = nullJson();
      return pRes;
    }


    case TK_LB: {
      return nullJson();   /* TBD */
    }
    case TK_ID: {
      return 0;
    }
  }
  pRes = xjd1JsonNew(0);
  if( pRes==0 ) return 0;
  pRes->eJType = XJD1_NULL;
  switch( p->eType ){
    case TK_STRUCT: {
      int i;
................................................................................
      for(i=0; i<pList->nEItem; i++){
        ExprItem *pItem = &pList->apEItem[i];
        pElem = malloc( sizeof(*pElem) );
        if( pElem==0 ) break;
        *ppPrev = pRes->u.st.pLast = pElem;
        ppPrev = &pElem->pNext;
        memset(pElem, 0, sizeof(*pElem));
        pElem->zLabel = xjd1PoolDup(0, pItem->zAs, -1);
        pElem->pValue = xjd1ExprEval(pItem->pExpr);
      }
      break;
    }
    case TK_ARRAY: {
      int i;
      ExprList *pList = p->u.st;

Changes to src/parse.y.

73
74
75
76
77
78
79





80
81
82
83
84
85
86
87
88
89
90
91
92
93
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
...
140
141
142
143
144
145
146











147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
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
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    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);
      xjd1DequoteString(pNew->u.z, pTok->n);
    }
    return pNew;
  }

  /* A JSON literal for a boolean or NULL */
  static JsonNode *jsonType(Parse *p, int eJType){
................................................................................
%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){
................................................................................
      pNew->eType = eOp; 
      pNew->eClass = XJD1_EXPR_BI;
      pNew->u.bi.pLeft = pLeft;
      pNew->u.bi.pRight = pRight;
    }
    return pNew;
  }












  /* Generate an Expr object that is a function call. */
  static Expr *funcExpr(Parse *p, Token *pFName, ExprList *pArgs){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_FUNCTION; 
      pNew->eClass = XJD1_EXPR_FUNC;
      pNew->u.func.name = *pFName;
      pNew->u.func.args = pArgs;
    }
    return pNew;
  }

  /* Generate an Expr object that is a subquery. */
  static Expr *subqExpr(Parse *p, Query *pQuery){
................................................................................
      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++];
    if( pT ){
      pItem->tkAs = *pT;
    }else{
      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);}
................................................................................
%type fromitem {DataSrc*}
%include {
  /* Create a new data source that is a named table */
  static DataSrc *tblDataSrc(Parse *p, Token *pTab, Token *pAs){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eDSType = TK_ID;
      pNew->u.tab.name = *pTab;
      if( pAs ) pNew->asId = *pAs;
    }
    return pNew;
  }

  /* Create a new data source that is a join */
  static DataSrc *joinDataSrc(Parse *p, DataSrc *pLeft, DataSrc *pRight){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
................................................................................

  /* Create a new subquery data source */
  static DataSrc *subqDataSrc(Parse *p, Query *pSubq, Token *pAs){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eDSType = TK_SELECT;
      pNew->u.subq.q = pSubq;
      pNew->asId = *pAs;
    }
    return pNew;
  }

  /* Create a new data source that is a FLATTEN or EACH operator */
  static DataSrc *flattenDataSrc(
    Parse *p,
................................................................................
    Token *pOp,
    ExprList *pArgs
  ){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eDSType = TK_FLATTENOP;
      pNew->u.flatten.pNext = pLeft;
      pNew->u.flatten.opName = *pOp;
      pNew->u.flatten.pList = pArgs;
    }
    return pNew;
  }
}
from(A) ::= .                                    {A = 0;}
from(A) ::= FROM fromlist(X).                    {A = X;}
................................................................................
///////////////////// The CREATE COLLECTION statement ////////////////////////
//
cmd(A) ::= CREATE COLLECTION ifnotexists(B) tabname(N). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_CREATECOLLECTION;
    pNew->u.crtab.ifExists = B;
    pNew->u.crtab.name = N;
  }
  A = pNew;
}
%type ifnotexists {int}
ifnotexists(A) ::= .                    {A = 0;}
ifnotexists(A) ::= IF NOT EXISTS.       {A = 1;}
tabname(A) ::= ID(X).                   {A = X;}
................................................................................
////////////////////////// The DROP COLLECTION ///////////////////////////////
//
cmd(A) ::= DROP COLLECTION ifexists(B) tabname(N). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_DROPCOLLECTION;
    pNew->u.crtab.ifExists = B;
    pNew->u.crtab.name = N;
  }
  A = pNew;
}
%type ifexists {int}
ifexists(A) ::= IF EXISTS.  {A = 1;}
ifexists(A) ::= .           {A = 0;}

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

/////////////////////////// The DELETE statement /////////////////////////////
//
cmd(A) ::= DELETE FROM tabname(N) where_opt(W). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_DELETE;
    pNew->u.del.name = N;
    pNew->u.del.pWhere = W;
  }
  A = pNew;
}

////////////////////////// The UPDATE command ////////////////////////////////
//
cmd(A) ::= UPDATE tabname(N) SET setlist(L) where_opt(W). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_UPDATE;
    pNew->u.update.name = N;
    pNew->u.update.pWhere = W;
    pNew->u.update.pChng = L;
  }
  A = pNew;
}

%type setlist {ExprList*}
................................................................................

////////////////////////// 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;
    pNew->u.ins.name = N;
    pNew->u.ins.pQuery = Q;
  }
  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);}







>
>
>
>
>






|







 







|







 







>
>
>
>
>
>
>
>
>
>
>







|







 







|
<
<
<
<







|







 







|
|







 







|







 







|







 







|







 







|







 







|











|







 







|








|












|
<
|
<







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
...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
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
...
233
234
235
236
237
238
239
240




241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
...
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

598

599
600
601
602
603
604
605
    JsonNode *pNew = xjd1JsonNew(p->pPool);
    if( pNew ){
      pNew->eJType = XJD1_REAL;
      pNew->u.r = atof(pTok->z);
    }
    return pNew;
  }

  /* Convert a token into a zero-terminated string */
  static char *tokenStr(Parse *p, Token *pTok){
    return pTok ? xjd1PoolDup(p->pPool, pTok->z, pTok->n) : 0;
  }

  /* 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 = tokenStr(p, pTok);
      xjd1DequoteString(pNew->u.z, pTok->n);
    }
    return pNew;
  }

  /* A JSON literal for a boolean or NULL */
  static JsonNode *jsonType(Parse *p, int eJType){
................................................................................
%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.zId = tokenStr(p, 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){
................................................................................
      pNew->eType = eOp; 
      pNew->eClass = XJD1_EXPR_BI;
      pNew->u.bi.pLeft = pLeft;
      pNew->u.bi.pRight = pRight;
    }
    return pNew;
  }
  /* Generate an Expr object for an lvalue */
  static Expr *lvalueExpr(Parse *p, Expr *pLeft, Token *pId){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_DOT; 
      pNew->eClass = XJD1_EXPR_LVALUE;
      pNew->u.lvalue.pLeft = pLeft;
      pNew->u.lvalue.zId = tokenStr(p, pId);
    }
    return pNew;
  }

  /* Generate an Expr object that is a function call. */
  static Expr *funcExpr(Parse *p, Token *pFName, ExprList *pArgs){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_FUNCTION; 
      pNew->eClass = XJD1_EXPR_FUNC;
      pNew->u.func.zFName = tokenStr(p, pFName);
      pNew->u.func.args = pArgs;
    }
    return pNew;
  }

  /* Generate an Expr object that is a subquery. */
  static Expr *subqExpr(Parse *p, Query *pQuery){
................................................................................
      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++];
    pItem->zAs = tokenStr(p, pT);




    pItem->pExpr = pExpr;
    return pList;
  }
}

%type lvalue {Expr*}
lvalue(A) ::= ID(X).                   {A = idExpr(p,&X);}
lvalue(A) ::= lvalue(X) DOT ID(Y).     {A = lvalueExpr(p,X,&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);}
................................................................................
%type fromitem {DataSrc*}
%include {
  /* Create a new data source that is a named table */
  static DataSrc *tblDataSrc(Parse *p, Token *pTab, Token *pAs){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eDSType = TK_ID;
      pNew->u.tab.zName = tokenStr(p, pTab);
      pNew->zAs = tokenStr(p, pAs);
    }
    return pNew;
  }

  /* Create a new data source that is a join */
  static DataSrc *joinDataSrc(Parse *p, DataSrc *pLeft, DataSrc *pRight){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
................................................................................

  /* Create a new subquery data source */
  static DataSrc *subqDataSrc(Parse *p, Query *pSubq, Token *pAs){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eDSType = TK_SELECT;
      pNew->u.subq.q = pSubq;
      pNew->zAs = tokenStr(p, pAs);
    }
    return pNew;
  }

  /* Create a new data source that is a FLATTEN or EACH operator */
  static DataSrc *flattenDataSrc(
    Parse *p,
................................................................................
    Token *pOp,
    ExprList *pArgs
  ){
    DataSrc *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eDSType = TK_FLATTENOP;
      pNew->u.flatten.pNext = pLeft;
      pNew->u.flatten.cOpName = pOp->z[0];
      pNew->u.flatten.pList = pArgs;
    }
    return pNew;
  }
}
from(A) ::= .                                    {A = 0;}
from(A) ::= FROM fromlist(X).                    {A = X;}
................................................................................
///////////////////// The CREATE COLLECTION statement ////////////////////////
//
cmd(A) ::= CREATE COLLECTION ifnotexists(B) tabname(N). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_CREATECOLLECTION;
    pNew->u.crtab.ifExists = B;
    pNew->u.crtab.zName = tokenStr(p, &N);
  }
  A = pNew;
}
%type ifnotexists {int}
ifnotexists(A) ::= .                    {A = 0;}
ifnotexists(A) ::= IF NOT EXISTS.       {A = 1;}
tabname(A) ::= ID(X).                   {A = X;}
................................................................................
////////////////////////// The DROP COLLECTION ///////////////////////////////
//
cmd(A) ::= DROP COLLECTION ifexists(B) tabname(N). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_DROPCOLLECTION;
    pNew->u.crtab.ifExists = B;
    pNew->u.crtab.zName = tokenStr(p, &N);
  }
  A = pNew;
}
%type ifexists {int}
ifexists(A) ::= IF EXISTS.  {A = 1;}
ifexists(A) ::= .           {A = 0;}

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

/////////////////////////// The DELETE statement /////////////////////////////
//
cmd(A) ::= DELETE FROM tabname(N) where_opt(W). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_DELETE;
    pNew->u.del.zName = tokenStr(p, &N);
    pNew->u.del.pWhere = W;
  }
  A = pNew;
}

////////////////////////// The UPDATE command ////////////////////////////////
//
cmd(A) ::= UPDATE tabname(N) SET setlist(L) where_opt(W). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_UPDATE;
    pNew->u.update.zName = tokenStr(p, &N);
    pNew->u.update.pWhere = W;
    pNew->u.update.pChng = L;
  }
  A = pNew;
}

%type setlist {ExprList*}
................................................................................

////////////////////////// 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.zName = tokenStr(p, &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;
    pNew->u.ins.zName = tokenStr(p, &N);
    pNew->u.ins.pQuery = Q;
  }
  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.zName = tokenStr(p, pName);

      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/stmt.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
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  pCmd = pStmt->pCmd;
  if( pCmd==0 ) return rc;
  switch( pCmd->eCmdType ){
    case TK_CREATECOLLECTION: {
      char *zSql;
      int res;
      char *zErr = 0;
      zSql = sqlite3_mprintf("CREATE TABLE %s \"%!.*w\"(x)",
                 pCmd->u.crtab.ifExists ? "IF NOT EXISTS" : "",
                 pCmd->u.crtab.name.n, pCmd->u.crtab.name.z);
      res = sqlite3_exec(pStmt->pConn->db, zSql, 0, 0, &zErr);
      if( zErr ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, "%s", zErr);
        sqlite3_free(zErr);
        rc = XJD1_ERROR;
      }
      sqlite3_free(zSql);
      break;
    }
    case TK_DROPCOLLECTION: {
      char *zSql;
      int res;
      char *zErr = 0;
      zSql = sqlite3_mprintf("DROP TABLE %s \"%!.*w\"",
                 pCmd->u.crtab.ifExists ? "IF EXISTS" : "",
                 pCmd->u.crtab.name.n, pCmd->u.crtab.name.z);
      res = sqlite3_exec(pStmt->pConn->db, zSql, 0, 0, &zErr);
      if( zErr ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, "%s", zErr);
        sqlite3_free(zErr);
        rc = XJD1_ERROR;
      }
      sqlite3_free(zSql);
................................................................................
        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);
      res = sqlite3_exec(pStmt->pConn->db, zSql, 0, 0, &zErr);
      if( zErr ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, "%s", zErr);
        sqlite3_free(zErr);
        rc = XJD1_ERROR;







|

|













|

|







 







|
|







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
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  pCmd = pStmt->pCmd;
  if( pCmd==0 ) return rc;
  switch( pCmd->eCmdType ){
    case TK_CREATECOLLECTION: {
      char *zSql;
      int res;
      char *zErr = 0;
      zSql = sqlite3_mprintf("CREATE TABLE %s \"%w\"(x)",
                 pCmd->u.crtab.ifExists ? "IF NOT EXISTS" : "",
                 pCmd->u.crtab.zName);
      res = sqlite3_exec(pStmt->pConn->db, zSql, 0, 0, &zErr);
      if( zErr ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, "%s", zErr);
        sqlite3_free(zErr);
        rc = XJD1_ERROR;
      }
      sqlite3_free(zSql);
      break;
    }
    case TK_DROPCOLLECTION: {
      char *zSql;
      int res;
      char *zErr = 0;
      zSql = sqlite3_mprintf("DROP TABLE %s \"%w\"",
                 pCmd->u.crtab.ifExists ? "IF EXISTS" : "",
                 pCmd->u.crtab.zName);
      res = sqlite3_exec(pStmt->pConn->db, zSql, 0, 0, &zErr);
      if( zErr ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, "%s", zErr);
        sqlite3_free(zErr);
        rc = XJD1_ERROR;
      }
      sqlite3_free(zSql);
................................................................................
        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.zName,
                  xjd1StringText(&json));
      xjd1StringClear(&json);
      res = sqlite3_exec(pStmt->pConn->db, zSql, 0, 0, &zErr);
      if( zErr ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, "%s", zErr);
        sqlite3_free(zErr);
        rc = XJD1_ERROR;

Changes to src/trace.c.

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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
...
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  switch( pCmd->eCmdType ){
    case TK_SELECT: {
      xjd1StringAppendF(pOut, "%*sQuery:\n", indent, "");
      xjd1TraceQuery(pOut, indent+3, pCmd->u.q.pQuery);
      break;
    }
    case TK_CREATECOLLECTION: {
      xjd1StringAppendF(pOut, "%*sCreate-Dataset: \"%.*s\" if-not-exists=%d\n",
         indent, "", pCmd->u.crtab.name.n, pCmd->u.crtab.name.z,
         pCmd->u.crtab.ifExists);
      break;
    }
    case TK_DROPCOLLECTION: {
      xjd1StringAppendF(pOut, "%*sDrop-Dataset: \"%.*s\" if-exists=%d\n",
         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",
         indent, "", pCmd->u.del.name.n, pCmd->u.del.name.z);
      if( pCmd->u.del.pWhere ){
         xjd1StringAppendF(pOut, "%*s WHERE ", indent, "");
         xjd1TraceExpr(pOut, pCmd->u.del.pWhere);
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    case TK_UPDATE: {
      xjd1StringAppendF(pOut, "%*sUPDATE: %.*s\n",
         indent, "", pCmd->u.update.name.n, pCmd->u.update.name.z);
      xjd1TraceExprList(pOut, indent+3, pCmd->u.update.pChng);
      if( pCmd->u.update.pWhere ){
         xjd1StringAppendF(pOut, "%*s WHERE ", indent, "");
         xjd1TraceExpr(pOut, pCmd->u.update.pWhere);
         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);
      }
................................................................................
** Output the content of a data source.
*/
void xjd1TraceDataSrc(String *pOut, int indent, const DataSrc *p){
  if( p==0 ) return;
  /*xjd1StringAppendF(pOut, "%*s%s\n", indent, "", xjd1TokenName(p->eDSType));*/
  switch( p->eDSType ){
    case TK_ID: {
      xjd1StringAppendF(pOut, "%*sID.%.*s", indent, "",
               p->u.tab.name.n, p->u.tab.name.z);
      if( p->asId.n ){
        xjd1StringAppendF(pOut, " AS %s", p->asId.n, p->asId.z);
      }
      xjd1StringAppend(pOut, "\n", 1);
      break;
    }
    case TK_COMMA: {
      xjd1StringAppendF(pOut, "%*sJoin:\n", indent, "");
      xjd1TraceDataSrc(pOut, indent+3, p->u.join.pLeft);
................................................................................
    case TK_SELECT: {
      xjd1StringAppendF(pOut, "%*sSubquery:\n", indent, "");
      xjd1TraceQuery(pOut, indent+3, p->u.subq.q);
      break;
    }
    case TK_FLATTENOP: {
      xjd1TraceDataSrc(pOut, indent, p->u.flatten.pNext);
      xjd1StringAppendF(pOut, "%*s%.*s:\n", indent, "",
            p->u.flatten.opName.n, p->u.flatten.opName.z);
      xjd1TraceExprList(pOut, indent+3, p->u.flatten.pList);
      break;
    }
  }
}

/*
................................................................................
    case TK_STRUCT: {
      int i;
      ExprList *pList = p->u.st;
      xjd1StringAppend(pOut, "{", 1);
      for(i=0; i<pList->nEItem; i++){
        ExprItem *pItem = &pList->apEItem[i];
        if( i>0 ) xjd1StringAppend(pOut, ",", 1);
        xjd1StringAppendF(pOut, "%.*s:", pItem->tkAs.n, pItem->tkAs.z);
        xjd1TraceExpr(pOut, pItem->pExpr);
      }
      xjd1StringAppend(pOut, "}", 1);
      break;
    }
    case TK_ARRAY: {
      int i;
................................................................................
*/
void xjd1TraceExprList(String *pOut, int indent, const ExprList *p){
  int i;
  if( p==0 || p->nEItem==0 ) return;
  for(i=0; i<p->nEItem; i++){
    xjd1StringAppendF(pOut, "%*s%d: ", indent, "", i);
    xjd1TraceExpr(pOut, p->apEItem[i].pExpr);
    if( p->apEItem[i].tkAs.n ){
      xjd1StringAppendF(pOut, " AS %.*s\n",
             p->apEItem[i].tkAs.n, p->apEItem[i].tkAs.z);
    }else{
      xjd1StringAppend(pOut, "\n", 1);
    }
  }
}







|
|




|
|




|
|

|








|
|








|
|









|
|







 







|
<
|
|







 







|
|







 







|







 







|
|
<





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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280
281
...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
...
380
381
382
383
384
385
386
387
388

389
390
391
392
393
  switch( pCmd->eCmdType ){
    case TK_SELECT: {
      xjd1StringAppendF(pOut, "%*sQuery:\n", indent, "");
      xjd1TraceQuery(pOut, indent+3, pCmd->u.q.pQuery);
      break;
    }
    case TK_CREATECOLLECTION: {
      xjd1StringAppendF(pOut, "%*sCreate-Collection: \"%s\" if-not-exists=%d\n",
         indent, "", pCmd->u.crtab.zName,
         pCmd->u.crtab.ifExists);
      break;
    }
    case TK_DROPCOLLECTION: {
      xjd1StringAppendF(pOut, "%*sDrop-Collection: \"%s\" if-exists=%d\n",
         indent, "", pCmd->u.crtab.zName,
         pCmd->u.crtab.ifExists);
      break;
    }
    case TK_INSERT: {
      xjd1StringAppendF(pOut, "%*sInsert: %s\n",
         indent, "", pCmd->u.ins.zName);
      if( pCmd->u.ins.pValue ){
         xjd1StringAppendF(pOut, "%*s value: ", indent, "");
         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",
         indent, "", pCmd->u.del.zName);
      if( pCmd->u.del.pWhere ){
         xjd1StringAppendF(pOut, "%*s WHERE ", indent, "");
         xjd1TraceExpr(pOut, pCmd->u.del.pWhere);
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    case TK_UPDATE: {
      xjd1StringAppendF(pOut, "%*sUPDATE: %s\n",
         indent, "", pCmd->u.update.zName);
      xjd1TraceExprList(pOut, indent+3, pCmd->u.update.pChng);
      if( pCmd->u.update.pWhere ){
         xjd1StringAppendF(pOut, "%*s WHERE ", indent, "");
         xjd1TraceExpr(pOut, pCmd->u.update.pWhere);
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    case TK_PRAGMA: {
      xjd1StringAppendF(pOut, "%*sPRAGMA: %s",
         indent, "", pCmd->u.prag.zName);
      if( pCmd->u.prag.pValue ){
        xjd1StringAppend(pOut, "(", 1);
        xjd1TraceExpr(pOut, pCmd->u.ins.pValue);
        xjd1StringAppend(pOut, ")\n", 2);
      }else{
        xjd1StringAppend(pOut, "\n", 1);
      }
................................................................................
** Output the content of a data source.
*/
void xjd1TraceDataSrc(String *pOut, int indent, const DataSrc *p){
  if( p==0 ) return;
  /*xjd1StringAppendF(pOut, "%*s%s\n", indent, "", xjd1TokenName(p->eDSType));*/
  switch( p->eDSType ){
    case TK_ID: {
      xjd1StringAppendF(pOut, "%*sID.%s", indent, "", p->u.tab.zName);

      if( p->zAs ){
        xjd1StringAppendF(pOut, " AS %s", p->zAs);
      }
      xjd1StringAppend(pOut, "\n", 1);
      break;
    }
    case TK_COMMA: {
      xjd1StringAppendF(pOut, "%*sJoin:\n", indent, "");
      xjd1TraceDataSrc(pOut, indent+3, p->u.join.pLeft);
................................................................................
    case TK_SELECT: {
      xjd1StringAppendF(pOut, "%*sSubquery:\n", indent, "");
      xjd1TraceQuery(pOut, indent+3, p->u.subq.q);
      break;
    }
    case TK_FLATTENOP: {
      xjd1TraceDataSrc(pOut, indent, p->u.flatten.pNext);
      xjd1StringAppendF(pOut, "%*s%s:\n", indent, "",
            p->u.flatten.cOpName=='E' ? "EACH" : "FLATTEN");
      xjd1TraceExprList(pOut, indent+3, p->u.flatten.pList);
      break;
    }
  }
}

/*
................................................................................
    case TK_STRUCT: {
      int i;
      ExprList *pList = p->u.st;
      xjd1StringAppend(pOut, "{", 1);
      for(i=0; i<pList->nEItem; i++){
        ExprItem *pItem = &pList->apEItem[i];
        if( i>0 ) xjd1StringAppend(pOut, ",", 1);
        xjd1StringAppendF(pOut, "%s:", pItem->zAs);
        xjd1TraceExpr(pOut, pItem->pExpr);
      }
      xjd1StringAppend(pOut, "}", 1);
      break;
    }
    case TK_ARRAY: {
      int i;
................................................................................
*/
void xjd1TraceExprList(String *pOut, int indent, const ExprList *p){
  int i;
  if( p==0 || p->nEItem==0 ) return;
  for(i=0; i<p->nEItem; i++){
    xjd1StringAppendF(pOut, "%*s%d: ", indent, "", i);
    xjd1TraceExpr(pOut, p->apEItem[i].pExpr);
    if( p->apEItem[i].zAs ){
      xjd1StringAppendF(pOut, " AS %s\n", p->apEItem[i].zAs);

    }else{
      xjd1StringAppend(pOut, "\n", 1);
    }
  }
}

Changes to src/xjd1Int.h.

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
140
141
142
143
144
145
146




147
148
149
150
151
152
153
154
155
156
157
158
...
164
165
166
167
168
169
170

171
172
173
174
175
176
177
...
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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
struct Token {
  const char *z;                    /* Text of the token */
  int n;                            /* Number of characters */
};

/* A single element of an expression list */
struct ExprItem {
  Token tkAs;               /* AS value, or DESCENDING, or ASCENDING */
  Expr *pExpr;              /* The expression */
};

/* A list of expressions */
struct ExprList {
  int nEItem;               /* Number of items on the expression list */
  int nEAlloc;              /* Slots allocated in apEItem[] */
................................................................................
  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 */
................................................................................
#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 */
};
................................................................................
    } simple;
  } u;
};

/* A Data Source is a representation of a term out of the FROM clause. */
struct DataSrc {
  int eDSType;              /* Source type */
  Token asId;               /* 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 table.  eDSType==TK_ID */
      Token name;              /* The table name */
      sqlite3_stmt *pStmt;     /* Cursor for reading content */
      int eofSeen;             /* True if at EOF */
    } tab;
    struct {                /* EACH() or FLATTEN().  eDSType==TK_FLATTENOP */
      DataSrc *pNext;          /* Data source to the left */
      Token opName;            /* "EACH" or "FLATTEN" */
      ExprList *pList;         /* List of arguments */
    } flatten;
    struct {                /* A subquery.  eDSType==TK_SELECT */
      Query *q;                /* The subquery */
    } subq;
  } u;
};

/* Any command, including but not limited to a query */
struct Command {
  int eCmdType;             /* Type of command */
  union {
    struct {                /* Transaction control operations */
      Token id;                /* Transaction name */
    } trans;
    struct {                /* Create or drop table */
      int ifExists;            /* IF [NOT] EXISTS 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*);







|







 







>
>
>
>

|


|







 







>







 







|








|
|





|













|



|





|




|



|




|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
...
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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
struct Token {
  const char *z;                    /* Text of the token */
  int n;                            /* Number of characters */
};

/* A single element of an expression list */
struct ExprItem {
  char *zAs;                /* AS value, or DESCENDING, or ASCENDING */
  Expr *pExpr;              /* The expression */
};

/* A list of expressions */
struct ExprList {
  int nEItem;               /* Number of items on the expression list */
  int nEAlloc;              /* Slots allocated in apEItem[] */
................................................................................
  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 {                /* Substructure nam.  eClass==EXPR_LVALUE */
      Expr *pLeft;             /* Lvalue or id to the left */
      char *zId;               /* ID to the right */
    } lvalue;
    struct {                /* Identifiers */
      char *zId;               /* token value.  eClass=EXPR_TK */
    } tk;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* 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 */
................................................................................
#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
#define XJD1_EXPR_LVALUE  8

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

/* A Data Source is a representation of a term out of the FROM clause. */
struct DataSrc {
  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 */
    } tab;
    struct {                /* EACH() or FLATTEN().  eDSType==TK_FLATTENOP */
      DataSrc *pNext;          /* Data source to the left */
      char cOpName;            /* E or F for "EACH" or "FLATTEN" */
      ExprList *pList;         /* List of arguments */
    } flatten;
    struct {                /* A subquery.  eDSType==TK_SELECT */
      Query *q;                /* The subquery */
    } subq;
  } u;
};

/* Any command, including but not limited to a query */
struct Command {
  int eCmdType;             /* Type of command */
  union {
    struct {                /* Transaction control operations */
      char *zTransId;          /* Transaction name */
    } trans;
    struct {                /* Create or drop table */
      int ifExists;            /* IF [NOT] EXISTS clause */
      char *zName;             /* Name of table */
    } crtab;
    struct {                /* Query statement */
      Query *pQuery;           /* The query */
    } q;
    struct {                /* Insert */
      char *zName;             /* Table to insert into */
      Expr *pValue;            /* Value to be inserted */
      Query *pQuery;           /* Query to insert from */
    } ins;
    struct {                /* Delete */
      char *zName;             /* Table to delete */
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      char *zName;             /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */
    } update;
    struct {                /* Pragma */
      char *zName;             /* Pragma name */
      Expr *pValue;            /* Argument or empty string */
    } prag;
  } u;
};

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