UnQL

Check-in [8b4dcb6e8a]
Login

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

Overview
Comment:Return an error when an unknown object is referenced. i.e. for "SELECT x FROM y", return the error "no such object: x".
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8b4dcb6e8a2faa7f0ca351b21760a0bda0648ffc
User & Date: dan 2011-07-23 19:53:54
Context
2011-07-25
09:46
Add support for scalar sub-queries. check-in: 9648d8798c user: dan tags: trunk
2011-07-23
19:53
Return an error when an unknown object is referenced. i.e. for "SELECT x FROM y", return the error "no such object: x". check-in: 8b4dcb6e8a user: dan tags: trunk
19:16
Add forgotten test file base06.test. check-in: 806a057fa4 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/datasrc.c.

240
241
242
243
244
245
246
247


















































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



























































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

static int datasrcResolveRecursive(
  DataSrc *p, 
  int *piEntry, 
  const char *zDocname
){
  int ret = 0;
  if( p->eDSType==TK_COMMA ){
    ret = datasrcResolveRecursive(p->u.join.pLeft, piEntry, zDocname);
    if( 0==ret ){
      ret = datasrcResolveRecursive(p->u.join.pRight, piEntry, zDocname);
    }
  }else{
    if( (p->zAs && 0==strcmp(zDocname, p->zAs))
     || (p->zAs==0 && p->eDSType==TK_ID && strcmp(p->u.tab.zName, zDocname)==0)
    ){
      ret = *piEntry;
    }
    (*piEntry)++;
  }
  return ret;
}
int xjd1DataSrcResolve(DataSrc *p, const char *zDocname){
  int iEntry = 1;
  return datasrcResolveRecursive(p, &iEntry, zDocname);
}

static JsonNode *datasrcReadRecursive(
  DataSrc *p, 
  int *piEntry, 
  int iDoc
){
  JsonNode *pRet = 0;
  if( p->eDSType==TK_COMMA ){
    pRet = datasrcReadRecursive(p->u.join.pLeft, piEntry, iDoc);
    if( 0==pRet ){
      pRet = datasrcReadRecursive(p->u.join.pRight, piEntry, iDoc);
    }
  }else{
    if( *piEntry==iDoc ){
      pRet = xjd1JsonRef(p->pValue);
    }
    (*piEntry)++;
  }
  return pRet;
}
JsonNode *xjd1DataSrcRead(DataSrc *p, int iDoc){
  int iEntry = 1;
  return datasrcReadRecursive(p, &iEntry, iDoc);
}

Changes to src/expr.c.

98
99
100
101
102
103
104





























































105
106
107
108
109
110
111
...
113
114
115
116
117
118
119
120
121





122
123
124
125
126
127
128
...
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
...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
      walkExpr(p->u.lvalue.pLeft, pAction);
      break;
    }
  }
  return rc;
}































































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

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





      break;
    }

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

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


/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
  assert( p );
................................................................................
      xjd1JsonFree(pJRight);
      if( pRes==0 ) pRes = nullJson();
      return pRes;
    }

    case TK_ID: {
      if( p->pQuery ){
        return xjd1QueryDoc(p->pQuery, p->u.id.zId);
      }else{
        return xjd1StmtDoc(p->pStmt, p->u.id.zId);
      }
    }

    /* The following two logical operators work in the same way as their
    ** javascript counterparts. i.e.
    **
    **    1. "x AND y" is equivalent to "x ? y : x"







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







 







|
|
>
>
>
>
>







 







|






|







|

|




|







 







|

|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
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
...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
      walkExpr(p->u.lvalue.pLeft, pAction);
      break;
    }
  }
  return rc;
}

static int exprResolve(Expr *p, WalkAction *pAction){
  int eExpr = *(int *)pAction->pArg;
  const char *zDoc;

  assert( eExpr>0 || (pAction->pQuery==0 && pAction->pStmt) );

  zDoc = p->u.id.zId;
  if( eExpr==0 ){
    Command *pCmd = pAction->pStmt->pCmd;
    switch( pCmd->eCmdType ){
      case TK_DELETE:
        if( 0==strcmp(zDoc, pCmd->u.del.zName) ) return XJD1_OK;
        break;
      case TK_UPDATE:
        if( 0==strcmp(zDoc, pCmd->u.update.zName) ) return XJD1_OK;
        break;

      default:
        assert( 0 );
        break;
    }
  }else{
    Query *pQuery = pAction->pQuery;
    int bFound = 0;

    assert( pQuery->eQType==TK_SELECT || eExpr==XJD1_EXPR_ORDERBY );

    /* Search the FROM clause. */
    if( pQuery->eQType==TK_SELECT && (
          eExpr==XJD1_EXPR_RESULT  || eExpr==XJD1_EXPR_WHERE ||
          eExpr==XJD1_EXPR_GROUPBY || eExpr==XJD1_EXPR_HAVING ||
          eExpr==XJD1_EXPR_ORDERBY
    )){
      int iDatasrc = xjd1DataSrcResolve(pQuery->u.simple.pFrom, zDoc);
      if( iDatasrc ){
        p->u.id.iDatasrc = iDatasrc;
        bFound = 1;
      }
    }

    /* Match against any 'AS' alias on the query result */
    if( bFound==0 && pQuery->zAs ){
      if( eExpr==XJD1_EXPR_ORDERBY 
       || eExpr==XJD1_EXPR_HAVING
       || (eExpr==XJD1_EXPR_WHERE && pQuery->u.simple.pAgg==0)
      ){
        if( 0==strcmp(zDoc, pQuery->zAs) ){
          bFound = 1;
        }
      }
    }

    if( bFound ){
      p->u.id.pQuery = pQuery;
      return XJD1_OK;
    }
  }

  xjd1StmtError(pAction->pStmt, XJD1_ERROR, "no such object: %s", zDoc);
  return XJD1_ERROR;
}

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

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

    case XJD1_EXPR_TK: {
      rc = exprResolve(p, pAction);
      break;
    }

    default:
      break;
  }
  
................................................................................
** Initialize an expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprInit(
  Expr *p,                        /* Expression to initialize */
  xjd1_stmt *pStmt,               /* Statement expression belongs to */
  Query *pQuery,                  /* Query expression belongs to (or NULL) */
  int eExpr                       /* How the expression features in the query */
){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  sAction.pArg = (void *)&eExpr;
  return walkExpr(p, &sAction);
}

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


/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
  assert( p );
................................................................................
      xjd1JsonFree(pJRight);
      if( pRes==0 ) pRes = nullJson();
      return pRes;
    }

    case TK_ID: {
      if( p->pQuery ){
        return xjd1QueryDoc(p->pQuery, p->u.id.iDatasrc);
      }else{
        return xjd1StmtDoc(p->pStmt);
      }
    }

    /* The following two logical operators work in the same way as their
    ** javascript counterparts. i.e.
    **
    **    1. "x AND y" is equivalent to "x ? y : x"

Changes to src/func.c.

107
108
109
110
111
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126






127
128
129
130
131
132
133

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


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

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







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

  for(i=0; i<ArraySize(aFunc); i++){
    Function *pFunc = &aFunc[i];
    assert( (pFunc->xFunc==0)==(pFunc->xStep && pFunc->xFinal) );







|




>







|
>
>
>
>
>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

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

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

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

  /* Set bAggOk to true if aggregate functions may be used in this context. */
  bAggOk = (pQuery && pQuery->eQType==TK_SELECT
        && (eExpr==XJD1_EXPR_RESULT || eExpr==XJD1_EXPR_GROUPBY 
         || eExpr==XJD1_EXPR_HAVING || eExpr==XJD1_EXPR_ORDERBY 
  ));

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

  for(i=0; i<ArraySize(aFunc); i++){
    Function *pFunc = &aFunc[i];
    assert( (pFunc->xFunc==0)==(pFunc->xStep && pFunc->xFinal) );

Changes to src/parse.y.

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
388
389
390
391
392
393
394

395
396
397
398
399
400
401
    GroupByHaving *pGroupBy
  ){
    Query *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eQType = TK_SELECT;
      pNew->u.simple.isDistinct = isDistinct;
      pNew->u.simple.pRes = pRes;
      pNew->u.simple.zAs = zAs;
      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;
    }
    return pNew;
  }
................................................................................
    Query *pRight
  ){
    Query *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eQType = eOp;
      pNew->u.compound.pLeft = pLeft;
      pNew->u.compound.pRight = pRight;

    }
    return pNew;
  }
}










|







 







>







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    GroupByHaving *pGroupBy
  ){
    Query *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eQType = TK_SELECT;
      pNew->u.simple.isDistinct = isDistinct;
      pNew->u.simple.pRes = pRes;
      pNew->zAs = zAs;
      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;
    }
    return pNew;
  }
................................................................................
    Query *pRight
  ){
    Query *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eQType = eOp;
      pNew->u.compound.pLeft = pLeft;
      pNew->u.compound.pRight = pRight;
      pNew->zAs = pLeft->zAs;
    }
    return pNew;
  }
}



Changes to src/query.c.

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
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663


664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
  memset(pList, 0, sizeof(ResultList));
}

/*
** Called after statement parsing to initalize every Query object
** within the statement.
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){
  int rc;
  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    rc = xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery, 1);

    if( !rc ) rc = xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);


    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery, 0);


    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery,0);


    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery, 1);

    if( !rc && pQuery->u.simple.pGroupBy ){ 
      rc = xjd1AggregateInit(pStmt, pQuery, 0);
    }
  }else{
    rc = xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter);
    if( !rc ) rc = xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter);
  }

  if( !rc ) rc = xjd1ExprListInit(pQuery->pOrderBy, pStmt, pQuery,1);
  if( !rc ) rc = xjd1ExprInit(pQuery->pLimit, pStmt, pQuery, 0);
  if( !rc ) rc = xjd1ExprInit(pQuery->pOffset, pStmt, pQuery, 0);
  return rc;
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
................................................................................

/*
** Return a document currently referenced by a query.  If zDocName==0 then
** return the constructed result set of the query.
**
** The caller must invoke JsonFree() when it is done with this value.
*/
JsonNode *xjd1QueryDoc(Query *p, const char *zDocName){
  JsonNode *pOut = 0;
  if( p ){
    if( p->eQType==TK_SELECT ){
      switch( p->eDocFrom ){
        case XJD1_FROM_ORDERED:
          assert( zDocName==0 && p->ordered.pItem );
          pOut = xjd1JsonRef(p->ordered.pItem->apKey[p->ordered.nKey-1]);
          break;



        case XJD1_FROM_DISTINCTED:
          if( zDocName==0 ){
            pOut = xjd1JsonRef(p->u.simple.distincted.pItem->apKey[0]);
          }else{
            JsonNode **apSrc = &p->u.simple.distincted.pItem->apKey[1];
            pOut = xjd1DataSrcCacheRead(p->u.simple.pFrom, apSrc, zDocName);
          }
          break;

        case XJD1_FROM_GROUPED:
          if( zDocName==0 && p->u.simple.pRes ){
            pOut = xjd1ExprEval(p->u.simple.pRes);
          }else{
            JsonNode **apSrc = p->u.simple.grouped.pItem->apKey;
            if( p->u.simple.pGroupBy ){
              apSrc = &apSrc[p->u.simple.pGroupBy->nEItem];
            }
            pOut = xjd1DataSrcCacheRead(p->u.simple.pFrom, apSrc, zDocName);
          }
          break;

        case XJD1_FROM_DATASRC:
          if( zDocName==0 && p->u.simple.pRes ){
            pOut = xjd1ExprEval(p->u.simple.pRes);
          }else{
            pOut = xjd1DataSrcDoc(p->u.simple.pFrom, zDocName);
          }
          break;
      }
    }else{
      if( p->eDocFrom==XJD1_FROM_ORDERED ){
        assert( zDocName==0 && p->ordered.pItem );
        pOut = xjd1JsonRef(p->ordered.pItem->apKey[p->ordered.nKey-1]);
      }else{
        pOut = xjd1JsonRef(p->u.compound.pOut);
      }
    }

    /* If no document has been found and this is a sub-query, search the 
    ** parent query for a document of the specified name. 
    */
    if( pOut==0 && zDocName ){
      pOut = xjd1QueryDoc(p->pOuter, zDocName);
    }
  }
  return pOut;
}


/*
** The destructor for a Query object.







|

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


|
|


|
|
|







 







|


<
<
|
|
|
<
<
>
>

<
|
<
<
<
<



|






|




|


|




|
<
<
<
|
|
|

<
<
<
<
<
<







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
...
655
656
657
658
659
660
661
662
663
664


665
666
667


668
669
670

671




672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695



696
697
698
699






700
701
702
703
704
705
706
  memset(pList, 0, sizeof(ResultList));
}

/*
** Called after statement parsing to initalize every Query object
** within the statement.
*/
int xjd1QueryInit(Query *p, xjd1_stmt *pStmt, Query *pOuter){
  int rc;
  if( p==0 ) return XJD1_OK;
  p->pStmt = pStmt;
  p->pOuter = pOuter;
  if( p->eQType==TK_SELECT ){
    rc = xjd1ExprInit(p->u.simple.pRes, pStmt, p, XJD1_EXPR_RESULT);
    if( !rc ){
      rc = xjd1DataSrcInit(p->u.simple.pFrom, p);
    }
    if( !rc ){
      rc = xjd1ExprInit(p->u.simple.pWhere, pStmt, p, XJD1_EXPR_WHERE);
    }
    if( !rc ){
      rc = xjd1ExprListInit(p->u.simple.pGroupBy, pStmt, p, XJD1_EXPR_GROUPBY);
    }
    if( !rc ){
      rc = xjd1ExprInit(p->u.simple.pHaving, pStmt, p, XJD1_EXPR_HAVING);
    }
    if( !rc && p->u.simple.pGroupBy ){ 
      rc = xjd1AggregateInit(pStmt, p, 0);
    }
  }else{
    rc = xjd1QueryInit(p->u.compound.pLeft, pStmt, pOuter);
    if( !rc ) rc = xjd1QueryInit(p->u.compound.pRight, pStmt, pOuter);
  }

  if( !rc ) rc = xjd1ExprListInit(p->pOrderBy, pStmt, p, XJD1_EXPR_ORDERBY);
  if( !rc ) rc = xjd1ExprInit(p->pLimit, pStmt, p, XJD1_EXPR_LIMIT);
  if( !rc ) rc = xjd1ExprInit(p->pOffset, pStmt, p, XJD1_EXPR_OFFSET);
  return rc;
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
................................................................................

/*
** Return a document currently referenced by a query.  If zDocName==0 then
** return the constructed result set of the query.
**
** The caller must invoke JsonFree() when it is done with this value.
*/
JsonNode *xjd1QueryDoc(Query *p, int iDoc){
  JsonNode *pOut = 0;
  if( p ){


    if( p->eDocFrom==XJD1_FROM_ORDERED ){
      assert( iDoc==0 && p->ordered.pItem );
      pOut = xjd1JsonRef(p->ordered.pItem->apKey[p->ordered.nKey-1]);


    }else if( p->eQType==TK_SELECT ){
      switch( p->eDocFrom ){
        case XJD1_FROM_DISTINCTED:

          pOut = xjd1JsonRef(p->u.simple.distincted.pItem->apKey[iDoc]);




          break;

        case XJD1_FROM_GROUPED:
          if( iDoc==0 && p->u.simple.pRes ){
            pOut = xjd1ExprEval(p->u.simple.pRes);
          }else{
            JsonNode **apSrc = p->u.simple.grouped.pItem->apKey;
            if( p->u.simple.pGroupBy ){
              apSrc = &apSrc[p->u.simple.pGroupBy->nEItem];
            }
            pOut = xjd1JsonRef(apSrc[(iDoc?iDoc-1:0)]);
          }
          break;

        case XJD1_FROM_DATASRC:
          if( iDoc==0 && p->u.simple.pRes ){
            pOut = xjd1ExprEval(p->u.simple.pRes);
          }else{
            pOut = xjd1DataSrcRead(p->u.simple.pFrom, (iDoc ? iDoc : 1));
          }
          break;
      }
    }else{
      assert( iDoc==0 );



      pOut = xjd1JsonRef(p->u.compound.pOut);
    }








  }
  return pOut;
}


/*
** The destructor for a Query object.

Changes to src/stmt.c.

288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

/*
** Return the current value for a particular document in the given
** statement.
**
** The caller is responsible for invoking xjd1JsonFree() on the result.
*/
JsonNode *xjd1StmtDoc(xjd1_stmt *pStmt, const char *zDocName){
  Command *pCmd;
  JsonNode *pRes = 0;
  if( pStmt==0 ) return 0;
  pCmd = pStmt->pCmd;
  if( pCmd==0 ) return 0;
  switch( pCmd->eCmdType ){
    case TK_SELECT: {
      pRes = xjd1QueryDoc(pCmd->u.q.pQuery, zDocName);
      break;
    }
    case TK_UPDATE:
    case TK_DELETE: {
      pRes = xjd1JsonRef(pStmt->pDoc);
      break;
    }







|







|







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

/*
** Return the current value for a particular document in the given
** statement.
**
** The caller is responsible for invoking xjd1JsonFree() on the result.
*/
JsonNode *xjd1StmtDoc(xjd1_stmt *pStmt){
  Command *pCmd;
  JsonNode *pRes = 0;
  if( pStmt==0 ) return 0;
  pCmd = pStmt->pCmd;
  if( pCmd==0 ) return 0;
  switch( pCmd->eCmdType ){
    case TK_SELECT: {
      pRes = xjd1QueryDoc(pCmd->u.q.pQuery, 0);
      break;
    }
    case TK_UPDATE:
    case TK_DELETE: {
      pRes = xjd1JsonRef(pStmt->pDoc);
      break;
    }

Changes to src/xjd1Int.h.

146
147
148
149
150
151
152

153















154
155
156
157
158
159
160
...
163
164
165
166
167
168
169


170
171
172
173
174
175
176
...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
...
384
385
386
387
388
389
390


391
392
393
394
395
396
397
398
399
400
401








402
403
404
405
406
407
408
...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
/* A list of expressions */
struct ExprList {
  int nEItem;               /* Number of items on the expression list */
  int nEAlloc;              /* Slots allocated in apEItem[] */
  ExprItem *apEItem;        /* The expression in the list */
};


/* A node of an expression */















struct Expr {
  u16 eType;                /* Expression node type */
  u16 eClass;               /* Expression class */
  Query *pQuery;            /* Query this expression belongs to.  May be NULL */
  xjd1_stmt *pStmt;         /* Statement this expression belongs to */
  union {
    struct {                /* Binary or unary operator. eClass==XJD1_EXPR_BI */
................................................................................
    } 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 */


    } id;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* Name of the function */
      ExprList *args;          /* List of arguments */
      Function *pFunction;     /* Function object */
      JsonNode **apArg;        /* Array to martial function arguments in */
      int iAgg;
................................................................................
      ResultList left;            /* Sorted results of pLeft */
      ResultList right;           /* Sorted results of pRight */
      JsonNode *pOut;
    } compound;
    struct {                    /* For simple queries */
      int isDistinct;             /* True if the DISTINCT keyword is present */
      Expr *pRes;                 /* Result JSON string */
      const char *zAs;            /* Alias assigned to result object (if any) */
      DataSrc *pFrom;             /* The FROM clause */
      Expr *pWhere;               /* The WHERE clause */
      ExprList *pGroupBy;         /* The GROUP BY clause */
      Expr *pHaving;              /* The HAVING clause */
      Aggregate *pAgg;            /* Aggregation info. 0 for non-aggregates */
      ResultList grouped;         /* Grouped results, for GROUP BY queries */
      ResultList distincted;      /* Distinct results */
    } simple;
  } u;

  ExprList *pOrderBy;             /* The ORDER BY clause */
  Expr *pLimit;                   /* The LIMIT clause */
  Expr *pOffset;                  /* The OFFSET clause */
  int eDocFrom;                   /* XJD1_FROM_* - configures xjd1QueryDoc() */
  ResultList ordered;             /* Query results in sorted order */
  int bLimitValid;                /* Set to true after nLimit is set */
  int nLimit;                     /* Stop after returning this many more rows */
................................................................................
int xjd1DataSrcStep(DataSrc*);
int xjd1DataSrcClose(DataSrc*);
int xjd1DataSrcCount(DataSrc*);
JsonNode *xjd1DataSrcDoc(DataSrc*, const char*);
int xjd1DataSrcCount(DataSrc *);
JsonNode *xjd1DataSrcCacheRead(DataSrc *, JsonNode **, const char *zDocname);
void xjd1DataSrcCacheSave(DataSrc *, JsonNode **);



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

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









/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn);
JsonNode *xjd1JsonRef(JsonNode*);
void xjd1JsonRender(String*, const JsonNode*);
int xjd1JsonToReal(const JsonNode*, double*);
int xjd1JsonToString(const JsonNode*, String*);
................................................................................
int xjd1PragmaStep(xjd1_stmt*);

/******************************** query.c ************************************/
int xjd1QueryInit(Query*,xjd1_stmt*,Query*);
int xjd1QueryRewind(Query*);
int xjd1QueryStep(Query*);
int xjd1QueryClose(Query*);
JsonNode *xjd1QueryDoc(Query*, const char*);

/******************************** stmt.c *************************************/
JsonNode *xjd1StmtDoc(xjd1_stmt*, const char*);
void xjd1StmtError(xjd1_stmt *,int,const char*,...);

/******************************** string.c ***********************************/
int xjd1Strlen30(const char *);
void xjd1StringInit(String*, Pool*, int);
String *xjd1StringNew(Pool*, int);
char *xjd1StringGet(String*);







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







 







>
>







 







<









>







 







>
>











>
>
>
>
>
>
>
>







 







|


|







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
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
292
293
294
295
296
297
298

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
...
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
/* A list of expressions */
struct ExprList {
  int nEItem;               /* Number of items on the expression list */
  int nEAlloc;              /* Slots allocated in apEItem[] */
  ExprItem *apEItem;        /* The expression in the list */
};

/* 
** A node of an expression.
**
** If (eClass==EXPR_TK), then this node is a reference to a data-source, or
** if the expression is part of a SELECT query, to the result of the query
** itself. If this expression is part of any type of statement other than a 
** SELECT, then iDatasrc and pQuery are both set to 0. In that case there is
** only one data-source to which the expression could refer.
**
** If the expression is part of a SELECT and the iDatasrc field is set to
** 0, then the expression refers to the return value of the SELECT statement
** pQuery. pQuery may point to the simple SELECT that the expression is part 
** of, or to some other SELECT statement if the expression is part of a
** correlated sub-select. If iDatasrc is set to N, where N is 1 or greater, 
** it refers to the Nth data-source joined together in the FROM clause of 
** pQuery, counting from left to right.
*/
struct Expr {
  u16 eType;                /* Expression node type */
  u16 eClass;               /* Expression class */
  Query *pQuery;            /* Query this expression belongs to.  May be NULL */
  xjd1_stmt *pStmt;         /* Statement this expression belongs to */
  union {
    struct {                /* Binary or unary operator. eClass==XJD1_EXPR_BI */
................................................................................
    } 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 */
      int iDatasrc;
      Query *pQuery;
    } id;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* Name of the function */
      ExprList *args;          /* List of arguments */
      Function *pFunction;     /* Function object */
      JsonNode **apArg;        /* Array to martial function arguments in */
      int iAgg;
................................................................................
      ResultList left;            /* Sorted results of pLeft */
      ResultList right;           /* Sorted results of pRight */
      JsonNode *pOut;
    } compound;
    struct {                    /* For simple queries */
      int isDistinct;             /* True if the DISTINCT keyword is present */
      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 */
      Aggregate *pAgg;            /* Aggregation info. 0 for non-aggregates */
      ResultList grouped;         /* Grouped results, for GROUP BY queries */
      ResultList distincted;      /* Distinct results */
    } simple;
  } u;
  const char *zAs;                /* Alias assigned to result object (if any) */
  ExprList *pOrderBy;             /* The ORDER BY clause */
  Expr *pLimit;                   /* The LIMIT clause */
  Expr *pOffset;                  /* The OFFSET clause */
  int eDocFrom;                   /* XJD1_FROM_* - configures xjd1QueryDoc() */
  ResultList ordered;             /* Query results in sorted order */
  int bLimitValid;                /* Set to true after nLimit is set */
  int nLimit;                     /* Stop after returning this many more rows */
................................................................................
int xjd1DataSrcStep(DataSrc*);
int xjd1DataSrcClose(DataSrc*);
int xjd1DataSrcCount(DataSrc*);
JsonNode *xjd1DataSrcDoc(DataSrc*, const char*);
int xjd1DataSrcCount(DataSrc *);
JsonNode *xjd1DataSrcCacheRead(DataSrc *, JsonNode **, const char *zDocname);
void xjd1DataSrcCacheSave(DataSrc *, JsonNode **);
int xjd1DataSrcResolve(DataSrc *, const char *zDocname);
JsonNode *xjd1DataSrcRead(DataSrc *, int);

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

/******************************** expr.c *************************************/
int xjd1ExprInit(Expr*, xjd1_stmt*, Query*, int);
int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*, int);
JsonNode *xjd1ExprEval(Expr*);
int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
int xjd1ExprListClose(ExprList*);
/* Candidates for the 4th parameter to xjd1ExprInit() */
#define XJD1_EXPR_RESULT  1
#define XJD1_EXPR_WHERE   2
#define XJD1_EXPR_GROUPBY 3
#define XJD1_EXPR_HAVING  4
#define XJD1_EXPR_ORDERBY 5
#define XJD1_EXPR_LIMIT   6
#define XJD1_EXPR_OFFSET  7

/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn);
JsonNode *xjd1JsonRef(JsonNode*);
void xjd1JsonRender(String*, const JsonNode*);
int xjd1JsonToReal(const JsonNode*, double*);
int xjd1JsonToString(const JsonNode*, String*);
................................................................................
int xjd1PragmaStep(xjd1_stmt*);

/******************************** query.c ************************************/
int xjd1QueryInit(Query*,xjd1_stmt*,Query*);
int xjd1QueryRewind(Query*);
int xjd1QueryStep(Query*);
int xjd1QueryClose(Query*);
JsonNode *xjd1QueryDoc(Query*, int);

/******************************** stmt.c *************************************/
JsonNode *xjd1StmtDoc(xjd1_stmt*);
void xjd1StmtError(xjd1_stmt *,int,const char*,...);

/******************************** string.c ***********************************/
int xjd1Strlen30(const char *);
void xjd1StringInit(String*, Pool*, int);
String *xjd1StringNew(Pool*, int);
char *xjd1StringGet(String*);

Changes to test/all.test.

2
3
4
5
6
7
8

--
.read base01.test
.read base02.test
.read base03.test
.read base04.test
.read base05.test
.read base06.test








>
2
3
4
5
6
7
8
9
--
.read base01.test
.read base02.test
.read base03.test
.read base04.test
.read base05.test
.read base06.test
.read base07.test

Changes to test/base02.test.

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
157
158
159
160
161
162
163
164
165
166
167
168



169
170

171
172
173
174
175
176
177
...
184
185
186
187
188
189
190
191
192
193
194
195
196
SELECT 45 - 4 FROM c1;
SELECT 67 - 2 FROM c1;
.result -6 41 65

.testcase 16
SELECT 1.12;
SELECT "hello world";
SELECT a;
SELECT { x: "value" };
SELECT [1,4,9,16,25];
SELECT null;
SELECT true;
SELECT false;
.result 1.12 "hello world" null {"x":"value"} [1,4,9,16,25] null true false

................................................................................
INSERT INTO c3 VALUE { one: 1, two: 2 };
SELECT x.one FROM c3 AS x;
SELECT x.two FROM c3 AS x;
.result 1 2

.testcase 21
SELECT c3.one FROM c3 AS x;
SELECT c3.two FROM c3 AS x;
.result null null

.testcase 22
SELECT x FROM c3 AS x;



SELECT c3 FROM c3 AS x;
.result {"one":1,"two":2} null


.testcase 23
SELECT FROM (SELECT FROM c3) AS x;
.result {"one":1,"two":2} 

.testcase 24
SELECT FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
................................................................................
.testcase 26
SELECT x.one FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
SELECT x["one"] FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
.result 2 2

.testcase 27
SELECT c3 FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
.result null

.testcase 28
SELECT xyz FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
.result null








|







 







|
<



>
>
>

<
>







 







|



|

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171

172
173
174
175
176
177
178
179
...
186
187
188
189
190
191
192
193
194
195
196
197
198
SELECT 45 - 4 FROM c1;
SELECT 67 - 2 FROM c1;
.result -6 41 65

.testcase 16
SELECT 1.12;
SELECT "hello world";
SELECT ;
SELECT { x: "value" };
SELECT [1,4,9,16,25];
SELECT null;
SELECT true;
SELECT false;
.result 1.12 "hello world" null {"x":"value"} [1,4,9,16,25] null true false

................................................................................
INSERT INTO c3 VALUE { one: 1, two: 2 };
SELECT x.one FROM c3 AS x;
SELECT x.two FROM c3 AS x;
.result 1 2

.testcase 21
SELECT c3.one FROM c3 AS x;
.error ERROR no such object: c3


.testcase 22
SELECT x FROM c3 AS x;
.result {"one":1,"two":2} 

.testcase 22b
SELECT c3 FROM c3 AS x;

.error ERROR no such object: c3

.testcase 23
SELECT FROM (SELECT FROM c3) AS x;
.result {"one":1,"two":2} 

.testcase 24
SELECT FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
................................................................................
.testcase 26
SELECT x.one FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
SELECT x["one"] FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
.result 2 2

.testcase 27
SELECT c3 FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
.error ERROR no such object: c3

.testcase 28
SELECT xyz FROM (SELECT {one:c3.two, two:c3.one} FROM c3) AS x;
.error ERROR no such object: xyz

Changes to test/base03.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.result 3 6 8 12

.testcase 110
SELECT {x: c1.a==7 ? c1.b : c1.c} FROM c1;
.result {"x":3} {"x":6} {"x":8} {"x":12}

.testcase 120
SELECT c1.a FROM c1 WHERE (c1.a==7 ? c1.b : c2.c)==9;
.result
.testcase 121
SELECT c1.a FROM c1 WHERE (c1.a==7 ? c1.b : c2.c)!=8;
.result 1 4 10

.testcase 200
SELECT 1 in [2,3,4];
.result true
.testcase 201
SELECT 3 in [2,3,4];







|


|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.result 3 6 8 12

.testcase 110
SELECT {x: c1.a==7 ? c1.b : c1.c} FROM c1;
.result {"x":3} {"x":6} {"x":8} {"x":12}

.testcase 120
SELECT c1.a FROM c1 WHERE (c1.a==7 ? c1.b : c1.c)==9;
.result
.testcase 121
SELECT c1.a FROM c1 WHERE (c1.a==7 ? c1.b : c1.c)!=8;
.result 1 4 10

.testcase 200
SELECT 1 in [2,3,4];
.result true
.testcase 201
SELECT 3 in [2,3,4];

Changes to test/base05.test.

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
.result 17 9

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

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

.testcase 15
CREATE COLLECTION c2;
INSERT INTO c2 VALUE { a:"a", b:1 };
INSERT INTO c2 VALUE { a:"b", b:2 };
INSERT INTO c2 VALUE { a:"c", b:1 };







|
|
|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
.result 17 9

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

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

.testcase 15
CREATE COLLECTION c2;
INSERT INTO c2 VALUE { a:"a", b:1 };
INSERT INTO c2 VALUE { a:"b", b:2 };
INSERT INTO c2 VALUE { a:"c", b:1 };

Changes to test/base06.test.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
INSERT INTO c2 VALUE {i:3};

.testcase 2
SELECT x.i FROM c1 AS x UNION ALL SELECT x.i FROM c2 AS x;
.result 2 1 4 3 3 5 2 4 3

.testcase 3
SELECT x.i FROM c1 AS x UNION ALL SELECT x.i FROM c2 AS x ORDER BY x;
.result 1 2 2 3 3 3 4 4 5

.testcase 4
SELECT x.i FROM c1 AS x UNION ALL (SELECT x.i FROM c2 AS x);
.result 2 1 4 3 3 5 2 4 3

.testcase 5







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
INSERT INTO c2 VALUE {i:3};

.testcase 2
SELECT x.i FROM c1 AS x UNION ALL SELECT x.i FROM c2 AS x;
.result 2 1 4 3 3 5 2 4 3

.testcase 3
SELECT c1.i AS x FROM c1 UNION ALL SELECT c2.i FROM c2 ORDER BY x;
.result 1 2 2 3 3 3 4 4 5

.testcase 4
SELECT x.i FROM c1 AS x UNION ALL (SELECT x.i FROM c2 AS x);
.result 2 1 4 3 3 5 2 4 3

.testcase 5

Added test/base07.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

.new t1.db
CREATE COLLECTION c1;
INSERT INTO c1 VALUE { i:3, z:"three" };
INSERT INTO c1 VALUE { i:1, z:"one" };
INSERT INTO c1 VALUE { i:2, z:"two" };
INSERT INTO c1 VALUE { i:4, z:"four" };

.testcase 1
SELECT FROM c1 LIMIT c1.x;
.error ERROR no such object: c1

.testcase 2
SELECT c2 FROM c1;
.error ERROR no such object: c2

.testcase 3
SELECT count(c2) FROM c1 AS c2;
.error 4

.testcase 4
SELECT count(c1) FROM c1 AS c2;
.error ERROR no such object: c1