UnQL

Check-in [6d55502945]
Login

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

Overview
Comment:Begin adding support for the expression list in between SELECT and FROM.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6d55502945eccdd69aeba984b2db46d4c2c1b264
User & Date: drh 2011-06-27 16:01:03
Context
2011-06-27
17:27
Reference counting of JsonNode objects. check-in: 0d3c641331 user: drh tags: trunk
16:01
Begin adding support for the expression list in between SELECT and FROM. check-in: 6d55502945 user: drh tags: trunk
14:08
Base test infrastructure working. Added "make test" to the makefile. check-in: 9432de00a5 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

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
...
190
191
192
193
194
195
196











197
198
199
200
201
202
203
...
221
222
223
224
225
226
227
































*/
int xjd1ExprListClose(ExprList *p){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xQueryAction = walkCloseQueryCallback;
  return walkExprList(p,&sAction);
}
























































/*
** Evaluate an expression.  Return the result as a JSON object.
**
** The caller must free the returned JSON by a call xjdJsonFree().
*/
JsonNode *xjd1ExprEval(Expr *p){
  JsonNode *pRes;

  pRes = malloc( sizeof(*pRes) );
  if( pRes==0 ) return 0;
  memset(pRes, 0, sizeof(*pRes));
  if( p==0 ){
    pRes->eJType = XJD1_NULL;
    return pRes;
  }
................................................................................
  switch( p->eType ){
    case TK_INTEGER:
    case TK_FLOAT: {
      pRes->u.r = atof(p->u.tk.z);
      pRes->eJType = XJD1_REAL;
      break;
    }
    default:
    case TK_NULL: {
      pRes->eJType = XJD1_NULL;
      break;
    }
    case TK_TRUE: {
      pRes->eJType = XJD1_TRUE;
      break;
................................................................................
          pRes->u.z[++j] = c;
        }
        pRes->u.z[j] = 0;
      }
      pRes->eJType = XJD1_STRING;
      break;
    }











  }
  return pRes;
}


/*
** Return TRUE if the given expression evaluates to TRUE.
................................................................................
      rc = atof(pValue->u.z)!=0.0;
      break;
    }
  }
  xjd1JsonFree(pValue);
  return rc;
}







































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








>







 







<







 







>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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
...
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
...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
*/
int xjd1ExprListClose(ExprList *p){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xQueryAction = walkCloseQueryCallback;
  return walkExprList(p,&sAction);
}

/*
** Return a numeric value for a JsonNode.  Do whatever type
** conversions are necessary.
*/
static double realFromJson(JsonNode *pNode){
  double r = 0.0;
  if( pNode==0 ) return 0.0;
  switch( pNode->eJType ){
    case XJD1_TRUE: {
      r = 1.0;
      break;
    }
    case XJD1_REAL: {
      r = pNode->u.r;
      break;
    }
    case XJD1_STRING: {
      r = atof(pNode->u.z);
      break;
    }
  }
  return r;
}

/*
** Compute a real value from an expression
*/
static double realFromExpr(Expr *p){
  double r = 0.0;
  if( p==0 ) return 0.0;
  switch( p->eType ){
    case TK_STRING:
    case TK_INTEGER:
    case TK_FLOAT: {
      r = atof(p->u.tk.z);
      break;
    }
    case TK_TRUE: {
      r = 1.0;
      break;
    }
    case TK_FALSE:
    case TK_NULL: {
      break;
    }
    default: {
      JsonNode *pNode = xjd1ExprEval(p);
      r = realFromJson(pNode);
      xjd1JsonFree(pNode);
      break;
    }
  }
  return r;
}

/*
** Evaluate an expression.  Return the result as a JSON object.
**
** The caller must free the returned JSON by a call xjdJsonFree().
*/
JsonNode *xjd1ExprEval(Expr *p){
  JsonNode *pRes;
  double rLeft, rRight;
  pRes = malloc( sizeof(*pRes) );
  if( pRes==0 ) return 0;
  memset(pRes, 0, sizeof(*pRes));
  if( p==0 ){
    pRes->eJType = XJD1_NULL;
    return pRes;
  }
................................................................................
  switch( p->eType ){
    case TK_INTEGER:
    case TK_FLOAT: {
      pRes->u.r = atof(p->u.tk.z);
      pRes->eJType = XJD1_REAL;
      break;
    }

    case TK_NULL: {
      pRes->eJType = XJD1_NULL;
      break;
    }
    case TK_TRUE: {
      pRes->eJType = XJD1_TRUE;
      break;
................................................................................
          pRes->u.z[++j] = c;
        }
        pRes->u.z[j] = 0;
      }
      pRes->eJType = XJD1_STRING;
      break;
    }
    case TK_PLUS: {
      rLeft = realFromExpr(p->u.bi.pLeft);
      rRight = realFromExpr(p->u.bi.pRight);
      pRes->eJType = XJD1_REAL;
      pRes->u.r = rLeft+rRight;  break;
      break;
    }
    default: {
      pRes->eJType = XJD1_NULL;
      break;
    }
  }
  return pRes;
}


/*
** Return TRUE if the given expression evaluates to TRUE.
................................................................................
      rc = atof(pValue->u.z)!=0.0;
      break;
    }
  }
  xjd1JsonFree(pValue);
  return rc;
}

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

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

Changes to src/query.c.

43
44
45
46
47
48
49




50
51
52
53
54
55
56
..
60
61
62
63
64
65
66




67
68
69
70
71
72
73
..
89
90
91
92
93
94
95

96



97

98
99
100
101
102
103
104
...
125
126
127
128
129
130
131




132
133
134
135
136
137
138
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;




  if( p->eQType==TK_SELECT ){
    xjd1DataSrcRewind(p->u.simple.pFrom);
  }else{
    xjd1QueryRewind(p->u.compound.pLeft);
    p->u.compound.doneLeft = xjd1QueryEOF(p->u.compound.pLeft);
    xjd1QueryRewind(p->u.compound.pRight);
  }
................................................................................
/*
** 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;
  if( p==0 ) return XJD1_DONE;




  if( p->eQType==TK_SELECT ){
    do{
      rc = xjd1DataSrcStep(p->u.simple.pFrom);
    }while(
         rc==XJD1_ROW
      && (p->u.simple.pWhere!=0 && !xjd1ExprTrue(p->u.simple.pWhere))
    );
................................................................................
**
** The pointer returned is managed by the query.  It will be freed
** by the next call to QueryStep(), QueryReset(), or QueryClose().
*/
JsonNode *xjd1QueryValue(Query *p){
  JsonNode *pOut = 0;
  if( p ){

    if( p->eQType==TK_SELECT ){



      pOut = xjd1DataSrcValue(p->u.simple.pFrom);

    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryValue(p->u.compound.pLeft);
    }else{
      pOut = xjd1QueryValue(p->u.compound.pRight);
    }
  }
  return pOut;
................................................................................

/*
** The destructor for a Query object.
*/
int xjd1QueryClose(Query *pQuery){
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;




  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprListClose(pQuery->u.simple.pCol);
    xjd1DataSrcClose(pQuery->u.simple.pFrom);
    xjd1ExprClose(pQuery->u.simple.pWhere);
    xjd1ExprListClose(pQuery->u.simple.pGroupBy);
    xjd1ExprClose(pQuery->u.simple.pHaving);
    xjd1ExprListClose(pQuery->u.simple.pOrderBy);







>
>
>
>







 







>
>
>
>







 







>

>
>
>
|
>







 







>
>
>
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;
  if( p->pOut ){
    xjd1JsonFree(p->pOut);
    p->pOut = 0;
  }
  if( p->eQType==TK_SELECT ){
    xjd1DataSrcRewind(p->u.simple.pFrom);
  }else{
    xjd1QueryRewind(p->u.compound.pLeft);
    p->u.compound.doneLeft = xjd1QueryEOF(p->u.compound.pLeft);
    xjd1QueryRewind(p->u.compound.pRight);
  }
................................................................................
/*
** 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;
  if( p==0 ) return XJD1_DONE;
  if( p->pOut ){
    xjd1JsonFree(p->pOut);
    p->pOut = 0;
  }
  if( p->eQType==TK_SELECT ){
    do{
      rc = xjd1DataSrcStep(p->u.simple.pFrom);
    }while(
         rc==XJD1_ROW
      && (p->u.simple.pWhere!=0 && !xjd1ExprTrue(p->u.simple.pWhere))
    );
................................................................................
**
** The pointer returned is managed by the query.  It will be freed
** by the next call to QueryStep(), QueryReset(), or QueryClose().
*/
JsonNode *xjd1QueryValue(Query *p){
  JsonNode *pOut = 0;
  if( p ){
    if( p->pOut ){ xjd1JsonFree(p->pOut); p->pOut = 0; }
    if( p->eQType==TK_SELECT ){
      if(  p->u.simple.pCol && p->u.simple.pCol->nEItem>0 ){
        pOut = p->pOut = xjd1ExprListEval(p->u.simple.pCol);
      }else{
        pOut = xjd1DataSrcValue(p->u.simple.pFrom);
      }
    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryValue(p->u.compound.pLeft);
    }else{
      pOut = xjd1QueryValue(p->u.compound.pRight);
    }
  }
  return pOut;
................................................................................

/*
** The destructor for a Query object.
*/
int xjd1QueryClose(Query *pQuery){
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;
  if( pQuery->pOut ){
    xjd1JsonFree(pQuery->pOut);
    pQuery->pOut = 0;
  }
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprListClose(pQuery->u.simple.pCol);
    xjd1DataSrcClose(pQuery->u.simple.pFrom);
    xjd1ExprClose(pQuery->u.simple.pWhere);
    xjd1ExprListClose(pQuery->u.simple.pGroupBy);
    xjd1ExprClose(pQuery->u.simple.pHaving);
    xjd1ExprListClose(pQuery->u.simple.pOrderBy);

Changes to src/xjd1Int.h.

164
165
166
167
168
169
170

171
172
173
174
175
176
177
...
294
295
296
297
298
299
300


301
302
303
304
305
306
307
};

/* 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 */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
      int doneLeft;               /* True if left is run to completion */
    } compound;
    struct {                    /* For simple queries */
................................................................................
int xjd1DataSrcEOF(DataSrc*);
int xjd1DataSrcClose(DataSrc*);
JsonNode *xjd1DataSrcValue(DataSrc*);

/******************************** expr.c *************************************/
int xjd1ExprInit(Expr*, xjd1_stmt*, Query*);
int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*);


int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
int xjd1ExprListClose(ExprList*);

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







>







 







>
>







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
};

/* 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 */
  JsonNode *pOut;               /* Output expression */
  union {
    struct {                    /* For compound queries */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
      int doneLeft;               /* True if left is run to completion */
    } compound;
    struct {                    /* For simple queries */
................................................................................
int xjd1DataSrcEOF(DataSrc*);
int xjd1DataSrcClose(DataSrc*);
JsonNode *xjd1DataSrcValue(DataSrc*);

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

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

Changes to test/base01.test.

11
12
13
14
15
16
17







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

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














>
>
>
>
>
>
>
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.testcase 110
SELECT FROM abc;
.result {"name":"abc"}

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

.testcase 130
SELECT 1 AS p, 2 AS q FROM abc;
.result {"p":1,"q":2}
.testcase 131
SELECT 1 AS p, 2+3 AS q FROM abc;
.result {"p":1,"q":5}