Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for simple aggregates. Fix a problem with joins. |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
514e16d7cb18ebb37972548953fa511d |
User & Date: | dan 2011-07-20 19:50:22 |
Context
2011-07-21
| ||
17:08 | Add support for GROUP BY and HAVING. check-in: 8c09ee47d8 user: dan tags: trunk | |
2011-07-20
| ||
19:50 | Add support for simple aggregates. Fix a problem with joins. check-in: 514e16d7cb user: dan tags: trunk | |
14:13 | Improve error handling. check-in: f19d31ea5d user: dan tags: trunk | |
Changes
Changes to src/datasrc.c.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 ... 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 ... 176 177 178 179 180 181 182 |
** the step results in a row of content being available. */ int xjd1DataSrcStep(DataSrc *p){ int rc= XJD1_DONE; if( p==0 ) return XJD1_DONE; switch( p->eDSType ){ case TK_COMMA: { rc = xjd1DataSrcStep(p->u.join.pRight); if( rc==XJD1_DONE ){ xjd1DataSrcRewind(p->u.join.pRight); rc = xjd1DataSrcStep(p->u.join.pLeft); } break; } case TK_SELECT: { xjd1JsonFree(p->pValue); p->pValue = 0; rc = xjd1QueryStep(p->u.subq.q); ................................................................................ break; } } return pRes; } /* ** Rewind a data source so that it is pointing at the first row. ** Return XJD1_DONE if the data source is empty and XJD1_ROW if ** the rewind results in a row of content being available. */ int xjd1DataSrcRewind(DataSrc *p){ if( p==0 ) return XJD1_DONE; xjd1JsonFree(p->pValue); p->pValue = 0; switch( p->eDSType ){ case TK_COMMA: { xjd1DataSrcRewind(p->u.join.pLeft); xjd1DataSrcRewind(p->u.join.pRight); break; } case TK_SELECT: { xjd1QueryRewind(p->u.subq.q); break; } case TK_ID: { sqlite3_reset(p->u.tab.pStmt); return xjd1DataSrcStep(p); } case TK_NULL: { p->u.null.isDone = 0; return xjd1DataSrcStep(p); } } return XJD1_DONE; } /* ** The destructor for a Query object. ................................................................................ case TK_ID: { sqlite3_finalize(p->u.tab.pStmt); break; } } return XJD1_OK; } |
> > > > > > > > > | | > | | < > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 ... 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 ... 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
** the step results in a row of content being available. */ int xjd1DataSrcStep(DataSrc *p){ int rc= XJD1_DONE; if( p==0 ) return XJD1_DONE; switch( p->eDSType ){ case TK_COMMA: { if( p->u.join.bStart==0 ){ p->u.join.bStart = 1; rc = xjd1DataSrcStep(p->u.join.pLeft); if( rc!=XJD1_ROW ) break; } rc = xjd1DataSrcStep(p->u.join.pRight); if( rc==XJD1_DONE ){ rc = xjd1DataSrcStep(p->u.join.pLeft); if( rc==XJD1_ROW ) { xjd1DataSrcRewind(p->u.join.pRight); rc = xjd1DataSrcStep(p->u.join.pRight); } } break; } case TK_SELECT: { xjd1JsonFree(p->pValue); p->pValue = 0; rc = xjd1QueryStep(p->u.subq.q); ................................................................................ break; } } return pRes; } /* ** Rewind a data source so that the next call to DataSrcStep() will cause ** it to point to the first row. */ int xjd1DataSrcRewind(DataSrc *p){ if( p==0 ) return XJD1_DONE; xjd1JsonFree(p->pValue); p->pValue = 0; switch( p->eDSType ){ case TK_COMMA: { p->u.join.bStart = 0; xjd1DataSrcRewind(p->u.join.pLeft); xjd1DataSrcRewind(p->u.join.pRight); break; } case TK_SELECT: { xjd1QueryRewind(p->u.subq.q); break; } case TK_ID: { sqlite3_reset(p->u.tab.pStmt); break; } case TK_NULL: { p->u.null.isDone = 0; break; } } return XJD1_DONE; } /* ** The destructor for a Query object. ................................................................................ case TK_ID: { sqlite3_finalize(p->u.tab.pStmt); break; } } return XJD1_OK; } int xjd1DataSrcCount(DataSrc *p){ int n = 1; if( p->eDSType==TK_COMMA ){ n = xjd1DataSrcCount(p->u.join.pLeft) + xjd1DataSrcCount(p->u.join.pRight); } return n; } static void cacheSaveRecursive(DataSrc *p, JsonNode ***papNode){ if( p->eDSType==TK_COMMA ){ cacheSaveRecursive(p->u.join.pLeft, papNode); cacheSaveRecursive(p->u.join.pRight, papNode); }else{ xjd1JsonFree(**papNode); **papNode = xjd1JsonRef(p->pValue); (*papNode)++; } } void xjd1DataSrcCacheSave(DataSrc *p, JsonNode **apNode){ JsonNode **pp = apNode; cacheSaveRecursive(p, &pp); } static JsonNode *cacheReadRecursive( DataSrc *p, JsonNode ***papNode, const char *zDocname ){ JsonNode *pRet = 0; if( p->eDSType==TK_COMMA ){ pRet = cacheReadRecursive(p->u.join.pLeft, papNode, zDocname); if( !pRet ) pRet = cacheReadRecursive(p->u.join.pRight, papNode, zDocname); }else{ if( zDocname==0 || (p->zAs && 0==strcmp(zDocname, p->zAs)) || (p->zAs==0 && p->eDSType==TK_ID && strcmp(p->u.tab.zName, zDocname)==0) ){ pRet = xjd1JsonRef(**papNode); } (*papNode)++; } return pRet; } JsonNode *xjd1DataSrcCacheRead( DataSrc *p, /* The data-source */ JsonNode **apNode, /* Array of cached values */ const char *zDocname /* The document name to search for */ ){ JsonNode **pp = apNode; return cacheReadRecursive(p, &pp, zDocname); } |
Changes to src/expr.c.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
p->pStmt = pAction->pStmt;
p->pQuery = pAction->pQuery;
switch( p->eClass ){
case XJD1_EXPR_Q:
rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery);
break;
case XJD1_EXPR_FUNC:
rc = xjd1FunctionInit(p, pAction->pStmt);
break;
default:
break;
}
return rc;
}
/*
** Initialize an expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery){
WalkAction sAction;
memset(&sAction, 0, sizeof(sAction));
sAction.xNodeAction = walkInitCallback;
sAction.pStmt = pStmt;
sAction.pQuery = pQuery;
return walkExpr(p, &sAction);
}
/*
** Initialize a list of expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprListInit(ExprList *p, xjd1_stmt *pStmt, Query *pQuery){
WalkAction sAction;
memset(&sAction, 0, sizeof(sAction));
sAction.xNodeAction = walkInitCallback;
sAction.pStmt = pStmt;
sAction.pQuery = pQuery;
return walkExprList(p, &sAction);
}
/* Walker callback for ExprClose() */
static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){
assert( p );
|
| > | > | > > > > > > | > > |
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
p->pStmt = pAction->pStmt; p->pQuery = pAction->pQuery; switch( p->eClass ){ case XJD1_EXPR_Q: rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery); break; case XJD1_EXPR_FUNC: { int bAggOk = *(int *)pAction->pArg; rc = xjd1FunctionInit(p, pAction->pStmt, pAction->pQuery, bAggOk); break; } default: break; } return rc; } /* ** Initialize an expression in preparation for evaluation of a ** statement. */ int xjd1ExprInit( Expr *p, /* Expression to initialize */ xjd1_stmt *pStmt, /* Statement expression belongs to */ Query *pQuery, /* Query expression belongs to (or NULL) */ int bAggOk /* True if an aggregate function is Ok */ ){ WalkAction sAction; memset(&sAction, 0, sizeof(sAction)); sAction.xNodeAction = walkInitCallback; sAction.pStmt = pStmt; sAction.pQuery = pQuery; sAction.pArg = (void *)&bAggOk; return walkExpr(p, &sAction); } /* ** Initialize a list of expression in preparation for evaluation of a ** statement. */ int xjd1ExprListInit(ExprList *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk){ WalkAction sAction; assert( bAggOk==0 || pQuery ); memset(&sAction, 0, sizeof(sAction)); sAction.xNodeAction = walkInitCallback; sAction.pStmt = pStmt; sAction.pQuery = pQuery; sAction.pArg = (int *)&bAggOk; return walkExprList(p, &sAction); } /* Walker callback for ExprClose() */ static int walkCloseQueryCallback(Expr *p, WalkAction *pAction){ assert( p ); |
Changes to src/func.c.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 .. 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 .. 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
************************************************************************* */ #include "xjd1Int.h" struct Function { int nArg; const char *zName; JsonNode *(*xFunc)(int nArg, JsonNode **apArg); }; #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** Implementation of "length(x)". */ static JsonNode *xLength(int nArg, JsonNode **apArg){ JsonNode *pRet; JsonNode *pStr; int nRet; assert( nArg==1 ); ................................................................................ pRet = xjd1JsonNew(0); pRet->eJType = XJD1_REAL; pRet->u.r = (double)nRet; return pRet; } /* ** The expression passed as the first argument is of type TK_FUNCTION. ** This function initializes the expression object. If successful, XJD1_OK ** is returned. Otherwise, an error code is returned and an error left in ** the pStmt statement handle. */ int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt){ char *zName; int nArg; int nByte; int i; static Function aFunc[] = { { 1, "length", xLength }, }; assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC ); zName = p->u.func.zFName; nArg = p->u.func.args->nEItem; for(i=0; i<ArraySize(aFunc); i++){ Function *pFunc = &aFunc[i]; if( strcmp(pFunc->zName, zName)==0 && nArg==pFunc->nArg ){ p->u.func.pFunction = pFunc; break; } } if( !p->u.func.pFunction ){ xjd1StmtError(pStmt, XJD1_ERROR, "no such function: %s", zName); ................................................................................ if( !p->u.func.apArg ){ return XJD1_NOMEM; } return XJD1_OK; } JsonNode *xjd1FunctionEval(Expr *p){ Function *pFunc = p->u.func.pFunction; int i; int nItem = p->u.func.args->nEItem; JsonNode *pRet; for(i=0; i<nItem; i++){ p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr); } pRet = pFunc->xFunc(nItem, p->u.func.apArg); for(i=0; i<nItem; i++){ xjd1JsonFree(p->u.func.apArg[i]); } return pRet; } |
> > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | > > > > > > > > > > > > | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > | > |
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 .. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 ... 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
************************************************************************* */ #include "xjd1Int.h" struct Function { int nArg; const char *zName; JsonNode *(*xFunc)(int nArg, JsonNode **apArg); int (*xStep)(int nArg, JsonNode **apArg, void **); JsonNode *(*xFinal)(void *); }; #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** Implementation of scalar function "length(x)". */ static JsonNode *xLength(int nArg, JsonNode **apArg){ JsonNode *pRet; JsonNode *pStr; int nRet; assert( nArg==1 ); ................................................................................ pRet = xjd1JsonNew(0); pRet->eJType = XJD1_REAL; pRet->u.r = (double)nRet; return pRet; } static int xCountStep(int nArg, JsonNode **apArg, void **pp){ int nCount = (int)*pp; nCount++; *pp = (void *)nCount; return XJD1_OK; } static JsonNode *xCountFinal(void *p){ JsonNode *pRet; pRet = xjd1JsonNew(0); pRet->eJType = XJD1_REAL; pRet->u.r = (double)(int)p; return pRet; } int xjd1AggregateInit(xjd1_stmt *pStmt, Query *pQuery, Expr *p){ Aggregate *pAgg = pQuery->pAgg; if( pAgg==0 ){ int nDatasrc; pAgg = (Aggregate *)xjd1PoolMallocZero(&pStmt->sPool, sizeof(Aggregate)); if( pAgg==0 ) return XJD1_NOMEM; pQuery->pAgg = pAgg; pAgg->nNode = xjd1DataSrcCount(pQuery->u.simple.pFrom); nDatasrc = pAgg->nNode * sizeof(JsonNode *); pAgg->apNode = (JsonNode **)xjd1PoolMallocZero(&pStmt->sPool, nDatasrc); if( pAgg->apNode==0 ) return XJD1_NOMEM; } if( p ){ static const int ARRAY_ALLOC_INCR = 8; if( (pAgg->nExpr % ARRAY_ALLOC_INCR)==0 ){ int nByte; /* Size of new allocation in bytes */ int nCopy; /* Size of old allocation in bytes */ Expr **apNew; /* Pointer to new allocation */ nByte = (pAgg->nExpr + ARRAY_ALLOC_INCR) * sizeof(Expr *); nCopy = pAgg->nExpr * sizeof(Expr *); apNew = (Expr **)xjd1PoolMallocZero(&pStmt->sPool, nByte); if( apNew==0 ) return XJD1_NOMEM; memcpy(apNew, pAgg->apExpr, nCopy); pAgg->apExpr = apNew; } pAgg->apExpr[pAgg->nExpr++] = p; } return XJD1_OK; } /* ** The expression passed as the first argument is of type TK_FUNCTION. ** This function initializes the expression object. If successful, XJD1_OK ** is returned. Otherwise, an error code is returned and an error left in ** the pStmt statement handle. */ int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk){ char *zName; int nArg; int nByte; int i; static Function aFunc[] = { { 1, "length", xLength, 0, 0 }, { -1, "count", 0, xCountStep, xCountFinal }, }; assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC ); assert( pQuery || bAggOk==0 ); zName = p->u.func.zFName; nArg = p->u.func.args->nEItem; for(i=0; i<ArraySize(aFunc); i++){ Function *pFunc = &aFunc[i]; assert( (pFunc->xFunc==0)==(pFunc->xStep && pFunc->xFinal) ); if( !strcmp(pFunc->zName, zName) && (nArg==pFunc->nArg || 0>pFunc->nArg) ){ if( pFunc->xStep ){ int rc; if( bAggOk==0 ){ const char *zErrMsg = "illegal use of aggregate function: %s"; xjd1StmtError(pStmt, XJD1_ERROR, zErrMsg, zName); return XJD1_ERROR; } /* Add this aggregate function to the Query.pAgg->apExpr[] array. */ rc = xjd1AggregateInit(pStmt, pQuery, p); if( rc!=XJD1_OK ) return rc; } p->u.func.pFunction = pFunc; break; } } if( !p->u.func.pFunction ){ xjd1StmtError(pStmt, XJD1_ERROR, "no such function: %s", zName); ................................................................................ if( !p->u.func.apArg ){ return XJD1_NOMEM; } return XJD1_OK; } int xjd1AggregateStep(Expr *p){ Function *pFunc = p->u.func.pFunction; int i; int nItem = p->u.func.args->nEItem; assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC ); assert( pFunc->xStep && pFunc->xFinal && pFunc->xFunc==0 ); for(i=0; i<nItem; i++){ p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr); } pFunc->xStep(nItem, p->u.func.apArg, &p->u.func.pAggCtx); for(i=0; i<nItem; i++){ xjd1JsonFree(p->u.func.apArg[i]); } return XJD1_OK; } /* ** Call any outstanding xFinal() functions for aggregate functions in the ** query. This is required to reset the aggregate contexts when a query is ** rewound following an error. */ void xjd1AggregateClear(Query *pQuery){ Aggregate *pAgg = pQuery->pAgg; if( pAgg ){ int i; for(i=0; i<pAgg->nNode; i++){ xjd1JsonFree(pAgg->apNode[i]); pAgg->apNode[i] = 0; } for(i=0; i<pAgg->nExpr; i++){ Expr *p = pAgg->apExpr[i]; /* Aggregate expression to finalize */ xjd1JsonFree( p->u.func.pFunction->xFinal(p->u.func.pAggCtx) ); p->u.func.pAggCtx = 0; } } } JsonNode *xjd1FunctionEval(Expr *p){ JsonNode *pRet; Function *pFunc = p->u.func.pFunction; assert( p->eType==TK_FUNCTION && p->eClass==XJD1_EXPR_FUNC ); if( pFunc->xFunc ){ /* A scalar function. */ int i; int nItem = p->u.func.args->nEItem; for(i=0; i<nItem; i++){ p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr); } pRet = pFunc->xFunc(nItem, p->u.func.apArg); for(i=0; i<nItem; i++){ xjd1JsonFree(p->u.func.apArg[i]); } }else{ /* This is the xFinal() call of an aggregate function. */ assert( pFunc->xStep && pFunc->xFinal ); pRet = pFunc->xFinal(p->u.func.pAggCtx); p->u.func.pAggCtx = 0; } return pRet; } |
Changes to src/query.c.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 ... 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 ... 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 ... 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ... 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
*/ int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){ int rc; if( pQuery==0 ) return XJD1_OK; pQuery->pStmt = pStmt; pQuery->pOuter = pOuter; if( pQuery->eQType==TK_SELECT ){ rc = xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery); if( !rc ) rc = xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery); if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery); if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery); }else{ rc = xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter); if( !rc ) rc = xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter); } return rc; } ................................................................................ */ int xjd1QueryRewind(Query *p){ if( p==0 ) return XJD1_OK; if( p->eQType==TK_SELECT ){ xjd1DataSrcRewind(p->u.simple.pFrom); p->bUseResultList = 0; p->bStarted = 0; clearResultList(&p->result); }else{ xjd1QueryRewind(p->u.compound.pLeft); p->u.compound.doneLeft = 0; xjd1QueryRewind(p->u.compound.pRight); } return XJD1_OK; } /* ** Advance to the next row of the TK_SELECT query passed as the first ** argument, disregarding any ORDER BY, OFFSET or LIMIT clause. ** ** Return XJD1_ROW if there is such a row, or XJD1_EOF if there is not. Or ** return an error code if an error occurs. */ static int selectStepUnordered(Query *p){ int rc; /* Return code */ assert( p->eQType==TK_SELECT ); do{ rc = xjd1DataSrcStep(p->u.simple.pFrom); }while( ................................................................................ ** ** Return XJD1_ROW if there is such a row, or XJD1_EOF if there is not. Or ** return an error code if an error occurs. */ static int selectStepOrdered(Query *p){ int rc; if( p->u.simple.pOrderBy ){ /* There is an ORDER BY clause. */ if( p->bUseResultList==0 ){ int nKey = p->u.simple.pOrderBy->nEItem + 1; ExprList *pOrderBy = p->u.simple.pOrderBy; Pool *pPool; JsonNode **apKey; ................................................................................ /* ** Advance a query to the next row. Return XDJ1_DONE if there is no ** next row, or XJD1_ROW if the step was successful. */ int xjd1QueryStep(Query *p){ int rc = XJD1_ROW; if( p==0 ) return XJD1_DONE; if( p->eQType==TK_SELECT ){ /* Calculate the values, if any, of the LIMIT and OFFSET clauses. ** ** TBD: Should this throw an exception if the result of evaluating ** either of these clauses cannot be converted to a number? */ ................................................................................ if( p ){ if( p->eQType==TK_SELECT ){ if( p->bUseResultList ){ assert( zDocName==0 && p->result.pItem ); pOut = xjd1JsonRef(p->result.pItem->apKey[p->result.nKey-1]); }else if( zDocName==0 && p->u.simple.pRes ){ pOut = xjd1ExprEval(p->u.simple.pRes); }else{ pOut = xjd1DataSrcDoc(p->u.simple.pFrom, zDocName); } }else if( !p->u.compound.doneLeft ){ pOut = xjd1QueryDoc(p->u.compound.pLeft, zDocName); }else{ pOut = xjd1QueryDoc(p->u.compound.pRight, zDocName); } if( pOut==0 && zDocName ){ pOut = xjd1QueryDoc(p->pOuter, zDocName); |
| | | | | | | > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > |
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 ... 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 ... 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 ... 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 ... 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
*/ int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){ int rc; if( pQuery==0 ) return XJD1_OK; pQuery->pStmt = pStmt; pQuery->pOuter = pOuter; if( pQuery->eQType==TK_SELECT ){ rc = xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery, 1); if( !rc ) rc = xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery, 0); if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery,0); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery, 1); if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery,1); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery, 0); if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery, 0); if( !rc && pQuery->u.simple.pGroupBy ){ rc = xjd1AggregateInit(pStmt, pQuery, 0); } }else{ rc = xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter); if( !rc ) rc = xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter); } return rc; } ................................................................................ */ int xjd1QueryRewind(Query *p){ if( p==0 ) return XJD1_OK; if( p->eQType==TK_SELECT ){ xjd1DataSrcRewind(p->u.simple.pFrom); p->bUseResultList = 0; p->bStarted = 0; p->bDone = 0; clearResultList(&p->result); xjd1AggregateClear(p); }else{ xjd1QueryRewind(p->u.compound.pLeft); p->u.compound.doneLeft = 0; xjd1QueryRewind(p->u.compound.pRight); } return XJD1_OK; } /* ** Advance to the next row of the TK_SELECT query passed as the first ** argument, disregarding any ORDER BY, OFFSET or LIMIT clause. ** ** Return XJD1_ROW if there is such a row, or XJD1_DONE at EOF. Or return ** an error code if an error occurs. */ static int selectStepUnordered(Query *p){ int rc; /* Return code */ assert( p->eQType==TK_SELECT ); do{ rc = xjd1DataSrcStep(p->u.simple.pFrom); }while( ................................................................................ ** ** Return XJD1_ROW if there is such a row, or XJD1_EOF if there is not. Or ** return an error code if an error occurs. */ static int selectStepOrdered(Query *p){ int rc; if( p->pAgg ){ Aggregate *pAgg = p->pAgg; if( p->u.simple.pGroupBy==0 ){ /* An aggregate query with no GROUP BY clause. If there is no GROUP BY, ** then exactly one row is returned, which makes ORDER BY and DISTINCT ** no-ops. And it is not possible to have a HAVING clause without a ** GROUP BY, so no need to worry about that either. */ assert( p->u.simple.pHaving==0 ); pAgg->eAction = XJD1_AGG_STEP; while( XJD1_ROW==(rc = selectStepUnordered(p) ) ){ int i; for(i=0; i<pAgg->nExpr; i++){ rc = xjd1AggregateStep(pAgg->apExpr[i]); if( rc!=XJD1_OK ) return rc; } xjd1DataSrcCacheSave(p->u.simple.pFrom, pAgg->apNode); } if( rc!=XJD1_DONE ) return rc; pAgg->eAction = XJD1_AGG_FINAL; p->bDone = 1; rc = XJD1_ROW; }else{ assert(0); } }else if( p->u.simple.pOrderBy ){ /* There is an ORDER BY clause. */ if( p->bUseResultList==0 ){ int nKey = p->u.simple.pOrderBy->nEItem + 1; ExprList *pOrderBy = p->u.simple.pOrderBy; Pool *pPool; JsonNode **apKey; ................................................................................ /* ** Advance a query to the next row. Return XDJ1_DONE if there is no ** next row, or XJD1_ROW if the step was successful. */ int xjd1QueryStep(Query *p){ int rc = XJD1_ROW; if( p==0 || p->bDone ) return XJD1_DONE; if( p->eQType==TK_SELECT ){ /* Calculate the values, if any, of the LIMIT and OFFSET clauses. ** ** TBD: Should this throw an exception if the result of evaluating ** either of these clauses cannot be converted to a number? */ ................................................................................ if( p ){ if( p->eQType==TK_SELECT ){ if( p->bUseResultList ){ assert( zDocName==0 && p->result.pItem ); pOut = xjd1JsonRef(p->result.pItem->apKey[p->result.nKey-1]); }else if( zDocName==0 && p->u.simple.pRes ){ pOut = xjd1ExprEval(p->u.simple.pRes); }else if( p->pAgg && p->pAgg->eAction==XJD1_AGG_FINAL ){ pOut = xjd1DataSrcCacheRead(p->u.simple.pFrom,p->pAgg->apNode,zDocName); }else{ pOut = xjd1DataSrcDoc(p->u.simple.pFrom, zDocName); } }else if( !p->u.compound.doneLeft ){ pOut = xjd1QueryDoc(p->u.compound.pLeft, zDocName); }else{ pOut = xjd1QueryDoc(p->u.compound.pRight, zDocName); } if( pOut==0 && zDocName ){ pOut = xjd1QueryDoc(p->pOuter, zDocName); |
Changes to src/stmt.c.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
break; } case TK_INSERT: { xjd1QueryInit(pCmd->u.ins.pQuery, p, 0); break; } case TK_DELETE: { xjd1ExprInit(pCmd->u.del.pWhere, p, 0); break; } case TK_UPDATE: { xjd1ExprInit(pCmd->u.update.pWhere, p, 0); xjd1ExprListInit(pCmd->u.update.pChng, p, 0); xjd1ExprInit(pCmd->u.update.pUpsert, p, 0); break; } } if( p->errCode ){ xjd1Error(pConn, p->errCode, "%s", p->errMsg.zBuf); rc = p->errCode; |
| | | | |
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
break; } case TK_INSERT: { xjd1QueryInit(pCmd->u.ins.pQuery, p, 0); break; } case TK_DELETE: { xjd1ExprInit(pCmd->u.del.pWhere, p, 0, 0); break; } case TK_UPDATE: { xjd1ExprInit(pCmd->u.update.pWhere, p, 0, 0); xjd1ExprListInit(pCmd->u.update.pChng, p, 0, 0); xjd1ExprInit(pCmd->u.update.pUpsert, p, 0, 0); break; } } if( p->errCode ){ xjd1Error(pConn, p->errCode, "%s", p->errMsg.zBuf); rc = p->errCode; |
Changes to src/xjd1Int.h.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 ... 158 159 160 161 162 163 164 165 166 167 168 169 170 171 ... 236 237 238 239 240 241 242 243 244 245 246 247 248 249 ... 259 260 261 262 263 264 265 266 267 268 269 270 271 272 ... 274 275 276 277 278 279 280 281 282 283 284 285 286 287 ... 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 ... 431 432 433 434 435 436 437 438 439 440 441 442 |
#define TK_DROPCOLLECTION 104 #define TK_ARRAY 105 #define TK_STRUCT 106 #define TK_JVALUE 107 typedef unsigned char u8; typedef unsigned short int u16; typedef struct Command Command; typedef struct DataSrc DataSrc; typedef struct Expr Expr; typedef struct ExprItem ExprItem; typedef struct ExprList ExprList; typedef struct Function Function; typedef struct JsonNode JsonNode; ................................................................................ char *zId; /* token value. eClass=EXPR_TK */ } id; struct { /* Function calls. eClass=EXPR_FUNC */ char *zFName; /* Name of the function */ ExprList *args; /* List of arguments */ Function *pFunction; /* Function object */ JsonNode **apArg; /* Array to martial function arguments in */ } func; struct { /* Subqueries. eClass=EXPR_Q */ Query *p; /* The subquery */ } subq; struct { /* Literal value. eClass=EXPR_JSON */ JsonNode *p; /* The value */ } json; ................................................................................ /* A list of sorted results. */ struct ResultList { Pool *pPool; int nKey; ResultItem *pItem; }; /* A query statement */ struct Query { int eQType; /* Query type */ xjd1_stmt *pStmt; /* Statement this query is part of */ Query *pOuter; /* Next outer query for a subquery */ union { struct { /* For compound queries */ ................................................................................ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit; /* The LIMIT clause */ Expr *pOffset; /* The OFFSET clause */ } simple; } u; int bStarted; /* Set to true after first Step() */ int nLimit; /* Stop after returning this many more rows */ int bUseResultList; /* True to read results from Query.result */ ResultList result; /* List of query results in sorted order */ }; /* A Data Source is a representation of a term out of the FROM clause. */ ................................................................................ int eDSType; /* Source type */ char *zAs; /* The identifier after the AS keyword */ Query *pQuery; /* Query this data source services */ JsonNode *pValue; /* Current value for this data source */ int isOwner; /* True if this DataSrc owns the pOut line */ union { struct { /* For a join. eDSType==TK_COMMA */ DataSrc *pLeft; /* Data source on the left */ DataSrc *pRight; /* Data source on the right */ } join; struct { /* For a named collection. eDSType==TK_ID */ char *zName; /* The collection name */ sqlite3_stmt *pStmt; /* Cursor for reading content */ int eofSeen; /* True if at EOF */ ................................................................................ void xjd1Error(xjd1*,int,const char*,...); /******************************** datasrc.c **********************************/ int xjd1DataSrcInit(DataSrc*,Query*); int xjd1DataSrcRewind(DataSrc*); int xjd1DataSrcStep(DataSrc*); int xjd1DataSrcClose(DataSrc*); JsonNode *xjd1DataSrcDoc(DataSrc*, const char*); /******************************** delete.c ***********************************/ int xjd1DeleteStep(xjd1_stmt*); /******************************** expr.c *************************************/ int xjd1ExprInit(Expr*, xjd1_stmt*, Query*); int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*); JsonNode *xjd1ExprEval(Expr*); int xjd1ExprTrue(Expr*); int xjd1ExprClose(Expr*); int xjd1ExprListClose(ExprList*); /******************************** json.c *************************************/ JsonNode *xjd1JsonParse(const char *zIn, int mxIn); ................................................................................ void xjd1TraceExpr(String*,const Expr*); void xjd1TraceExprList(String*,int, const ExprList*); /******************************** update.c ***********************************/ int xjd1UpdateStep(xjd1_stmt*); /******************************** func.c *************************************/ int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt); void xjd1FunctionClose(Expr *p); JsonNode *xjd1FunctionEval(Expr *p); #endif /* _XJD1INT_H */ |
> > > > > > > > > > > > > > > > > > > > | | | < > > > > > |
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ... 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 ... 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 ... 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 ... 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 ... 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 ... 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
#define TK_DROPCOLLECTION 104 #define TK_ARRAY 105 #define TK_STRUCT 106 #define TK_JVALUE 107 typedef unsigned char u8; typedef unsigned short int u16; typedef struct Aggregate Aggregate; typedef struct Command Command; typedef struct DataSrc DataSrc; typedef struct Expr Expr; typedef struct ExprItem ExprItem; typedef struct ExprList ExprList; typedef struct Function Function; typedef struct JsonNode JsonNode; ................................................................................ char *zId; /* token value. eClass=EXPR_TK */ } id; struct { /* Function calls. eClass=EXPR_FUNC */ char *zFName; /* Name of the function */ ExprList *args; /* List of arguments */ Function *pFunction; /* Function object */ JsonNode **apArg; /* Array to martial function arguments in */ void *pAggCtx; /* Context for aggregate functions */ } func; struct { /* Subqueries. eClass=EXPR_Q */ Query *p; /* The subquery */ } subq; struct { /* Literal value. eClass=EXPR_JSON */ JsonNode *p; /* The value */ } json; ................................................................................ /* A list of sorted results. */ struct ResultList { Pool *pPool; int nKey; ResultItem *pItem; }; struct Aggregate { int eAction; /* One of XJD1_AGG_STEP or XJD1_AGG_FINAL */ int nNode; /* Size of apNode array */ JsonNode **apNode; /* Cache of datasource values */ int nExpr; /* Number of aggregate functions */ Expr **apExpr; /* Array of aggregate functions */ }; #define XJD1_AGG_STEP 0 #define XJD1_AGG_FINAL 1 /* A query statement */ struct Query { int eQType; /* Query type */ xjd1_stmt *pStmt; /* Statement this query is part of */ Query *pOuter; /* Next outer query for a subquery */ union { struct { /* For compound queries */ ................................................................................ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit; /* The LIMIT clause */ Expr *pOffset; /* The OFFSET clause */ } simple; } u; Aggregate *pAgg; /* Aggregation info. NULL for non-aggregates */ int bDone; /* Set to true after query is finished */ int bStarted; /* Set to true after first Step() */ int nLimit; /* Stop after returning this many more rows */ int bUseResultList; /* True to read results from Query.result */ ResultList result; /* List of query results in sorted order */ }; /* A Data Source is a representation of a term out of the FROM clause. */ ................................................................................ int eDSType; /* Source type */ char *zAs; /* The identifier after the AS keyword */ Query *pQuery; /* Query this data source services */ JsonNode *pValue; /* Current value for this data source */ int isOwner; /* True if this DataSrc owns the pOut line */ union { struct { /* For a join. eDSType==TK_COMMA */ int bStart; /* True if has already started */ DataSrc *pLeft; /* Data source on the left */ DataSrc *pRight; /* Data source on the right */ } join; struct { /* For a named collection. eDSType==TK_ID */ char *zName; /* The collection name */ sqlite3_stmt *pStmt; /* Cursor for reading content */ int eofSeen; /* True if at EOF */ ................................................................................ void xjd1Error(xjd1*,int,const char*,...); /******************************** datasrc.c **********************************/ int xjd1DataSrcInit(DataSrc*,Query*); int xjd1DataSrcRewind(DataSrc*); int xjd1DataSrcStep(DataSrc*); int xjd1DataSrcClose(DataSrc*); int xjd1DataSrcCount(DataSrc*); JsonNode *xjd1DataSrcDoc(DataSrc*, const char*); int xjd1DataSrcCount(DataSrc *); JsonNode *xjd1DataSrcCacheRead(DataSrc *, JsonNode **, const char *zDocname); void xjd1DataSrcCacheSave(DataSrc *, JsonNode **); /******************************** delete.c ***********************************/ int xjd1DeleteStep(xjd1_stmt*); /******************************** expr.c *************************************/ int xjd1ExprInit(Expr*, xjd1_stmt*, Query*, int); int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*, int); JsonNode *xjd1ExprEval(Expr*); int xjd1ExprTrue(Expr*); int xjd1ExprClose(Expr*); int xjd1ExprListClose(ExprList*); /******************************** json.c *************************************/ JsonNode *xjd1JsonParse(const char *zIn, int mxIn); ................................................................................ void xjd1TraceExpr(String*,const Expr*); void xjd1TraceExprList(String*,int, const ExprList*); /******************************** update.c ***********************************/ int xjd1UpdateStep(xjd1_stmt*); /******************************** func.c *************************************/ int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery, int bAggOk); JsonNode *xjd1FunctionEval(Expr *p); void xjd1FunctionClose(Expr *p); int xjd1AggregateInit(xjd1_stmt *, Query *, Expr *); int xjd1AggregateStep(Expr *p); void xjd1AggregateClear(Query *); #endif /* _XJD1INT_H */ |
Changes to test/base05.test.
61 62 63 64 65 66 67 68 69 70 |
SELECT length(null); .result 11 2 4 5 4 .testcase 10 SELECT xyz("hello world"); .error ERROR no such function: xyz |
> > > > > > > > > > > > > > > > > > > |
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
SELECT length(null); .result 11 2 4 5 4 .testcase 10 SELECT xyz("hello world"); .error ERROR no such function: xyz .testcase 11 SELECT FROM c1 WHERE count(c1); .error ERROR illegal use of aggregate function: count .testcase 12 SELECT count(c1) FROM c1; SELECT count(c1) FROM c1 WHERE c1.i < 10; .result 17 9 .testcase 13 SELECT {a: count(c1), b : c1} FROM c1; .result {"a":17,"b":{"i":11,"z":"Fig"}} .testcase 14 SELECT count(x) FROM c1, c1 AS b; SELECT count(x) FROM c1, c1 AS b WHERE c1.i<3 && b.i<3; SELECT count(x) FROM c1, c1 AS b WHERE c1.i==1; .result 289 4 17 |