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: |
8b4dcb6e8a2faa7f0ca351b21760a0bd |
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
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 |