UnQL

Check-in [0f90d3efaf]
Login

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

Overview
Comment:Basic WHERE clauses working on simple SELECT statements.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0f90d3efaf64751b4514b172992ff73034bd2b5a
User & Date: drh 2011-06-29 23:08:28
Context
2011-06-30
00:09
Get DELETE statements working. check-in: f4d26bb1e0 user: drh tags: trunk
2011-06-29
23:08
Basic WHERE clauses working on simple SELECT statements. check-in: 0f90d3efaf user: drh tags: trunk
20:10
Document references within expressions now working. check-in: ce30690c86 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
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
...
221
222
223
224
225
226
227



228
229
230
231
232
233
234
...
285
286
287
288
289
290
291






















292
293
294





295




296











297
298
299
300
301
302
303
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code used to evaluate expressions at run-time.
*/
#include "xjd1Int.h"


/*
** Information passed down into the expression walker.
*/
typedef struct WalkAction WalkAction;
struct WalkAction {
  int (*xQueryAction)(Expr*,WalkAction*);  /* Call for each EXPR_Q node */
................................................................................
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;
  JsonNode *pNode;
  if( p==0 ) return 0.0;
  if( p->eType==TK_JVALUE ){
    pNode = p->u.json.p;
  }else{
    pNode = xjd1ExprEval(p);
  }
  r = realFromJson(pNode);
  if( p->eType!=TK_JVALUE ){
    xjd1JsonFree(pNode);
  }
  return r;
}
















/*
** Allocate a NULL JSON object.
*/
static JsonNode *nullJson(void){
  JsonNode *pRes = xjd1JsonNew(0);
  if( pRes ) pRes->eJType = XJD1_NULL;
................................................................................
** Evaluate an expression.  Return the result as a JSON object.
**
** The caller must free the returned JSON by a call xjdJsonFree().
*/
JsonNode *xjd1ExprEval(Expr *p){
  JsonNode *pRes;
  double rLeft, rRight;



  if( p==0 ) return nullJson();
  switch( p->eType ){
    case TK_JVALUE: {
      return xjd1JsonRef(p->u.json.p);
    }
    case TK_DOT: {
      JsonNode *pBase = xjd1ExprEval(p->u.lvalue.pLeft);
................................................................................
        for(i=0; i<pList->nEItem; i++){
          ExprItem *pItem = &pList->apEItem[i];
          pRes->u.ar.apElem[i] = xjd1ExprEval(pItem->pExpr);
        }
      }
      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;
    }
  }







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












|





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







 







>
>
>







 







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

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







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
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
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code used to evaluate expressions at run-time.
*/
#include "xjd1Int.h"
#include <math.h>

/*
** Information passed down into the expression walker.
*/
typedef struct WalkAction WalkAction;
struct WalkAction {
  int (*xQueryAction)(Expr*,WalkAction*);  /* Call for each EXPR_Q node */
................................................................................
int xjd1ExprListClose(ExprList *p){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xQueryAction = walkCloseQueryCallback;
  return walkExprList(p,&sAction);
}

























/*
** Compute a real value from an expression
*/
static double realFromExpr(Expr *p){
  double r = 0.0;
  JsonNode *pNode;
  if( p==0 ) return 0.0;
  if( p->eType==TK_JVALUE ){
    pNode = p->u.json.p;
  }else{
    pNode = xjd1ExprEval(p);
  }
  xjd1JsonToReal(pNode, &r);
  if( p->eType!=TK_JVALUE ){
    xjd1JsonFree(pNode);
  }
  return r;
}

/*
** Return true if the JSON object is a string
*/
static int isStr(const JsonNode *p){
  if( p==0 ) return 0;
  switch( p->eJType ){
    case XJD1_TRUE:
    case XJD1_FALSE:
    case XJD1_NULL:
    case XJD1_REAL:
      return 0;
  }
  return 1;
}

/*
** Allocate a NULL JSON object.
*/
static JsonNode *nullJson(void){
  JsonNode *pRes = xjd1JsonNew(0);
  if( pRes ) pRes->eJType = XJD1_NULL;
................................................................................
** 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;
  int c;
  JsonNode *pJLeft, *pJRight;

  if( p==0 ) return nullJson();
  switch( p->eType ){
    case TK_JVALUE: {
      return xjd1JsonRef(p->u.json.p);
    }
    case TK_DOT: {
      JsonNode *pBase = xjd1ExprEval(p->u.lvalue.pLeft);
................................................................................
        for(i=0; i<pList->nEItem; i++){
          ExprItem *pItem = &pList->apEItem[i];
          pRes->u.ar.apElem[i] = xjd1ExprEval(pItem->pExpr);
        }
      }
      break;
    }
    case TK_EQ:
    case TK_NE:
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE: {
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);
      c = xjd1JsonCompare(pJLeft, pJRight);
      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);
      switch( p->eType ){
        case TK_EQ:  c = c==0;   break;
        case TK_NE:  c = c!=0;   break;
        case TK_LT:  c = c<0;    break;
        case TK_LE:  c = c<=0;   break;
        case TK_GT:  c = c>0;    break;
        case TK_GE:  c = c>=0;   break;
      }
      pRes->eJType = c ? XJD1_TRUE : XJD1_FALSE;
      break;
    }      
    case TK_PLUS: {
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);
      if( isStr(pJLeft) || isStr(pJRight) ){
        String x;
        xjd1StringInit(&x, 0, 0);
        xjd1JsonToString(pJLeft, &x);
        xjd1JsonToString(pJRight, &x);
        pRes->eJType = XJD1_STRING;
        pRes->u.z = xjd1StringGet(&x);
      }else{
        xjd1JsonToReal(pJLeft, &rLeft);
        xjd1JsonToReal(pJRight, &rRight);
        pRes->u.r = rLeft+rRight;
        pRes->eJType = XJD1_REAL;
      }
      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);
      break;
    }
    case TK_MINUS: {
      xjd1JsonToReal(pJLeft, &rLeft);
      xjd1JsonToReal(pJRight, &rRight);
      pRes->u.r = rLeft-rRight;
      pRes->eJType = XJD1_REAL;
      break;
    }
    default: {
      pRes->eJType = XJD1_NULL;
      break;
    }
  }

Changes to src/json.c.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
...
208
209
210
211
212
213
214




















































































































































215
216
217
218
219
220
221
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code used to parse and render JSON strings.
*/
#include "xjd1Int.h"


/*
** Reclaim memory used by JsonNode objects 
*/
void xjd1JsonFree(JsonNode *p){
  if( p && (--p->nRef)<=0 ){
    switch( p->eJType ){
................................................................................
  }
}


/*
** Append the text for a JSON string.
*/
void xjd1JsonRender(String *pOut, JsonNode *p){
  if( p==0 ){
    xjd1StringAppend(pOut, "null", 4);
  }else{
    switch( p->eJType ){
      case XJD1_FALSE: {
        xjd1StringAppend(pOut, "false", 5);
        break;
................................................................................
        }
        xjd1StringAppend(pOut, "}", 1);
        break;
      }
    }
  }
}






















































































































































/* JSON parser token types */
#define JSON_FALSE          XJD1_FALSE
#define JSON_TRUE           XJD1_TRUE
#define JSON_REAL           XJD1_REAL
#define JSON_NULL           XJD1_NULL







|







 







|







 







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







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code used to parse and render JSON strings.
*/
#include "xjd1Int.h"
#include <ctype.h>

/*
** Reclaim memory used by JsonNode objects 
*/
void xjd1JsonFree(JsonNode *p){
  if( p && (--p->nRef)<=0 ){
    switch( p->eJType ){
................................................................................
  }
}


/*
** Append the text for a JSON string.
*/
void xjd1JsonRender(String *pOut, const JsonNode *p){
  if( p==0 ){
    xjd1StringAppend(pOut, "null", 4);
  }else{
    switch( p->eJType ){
      case XJD1_FALSE: {
        xjd1StringAppend(pOut, "false", 5);
        break;
................................................................................
        }
        xjd1StringAppend(pOut, "}", 1);
        break;
      }
    }
  }
}

/*
** Attempt to convert a JSON object into a real number.  Return 0
** if successful and 1 if there is an error.
*/
int xjd1JsonToReal(const JsonNode *p, double *pRes){
  double x = 0.0;
  *pRes = 0.0/x;
  if( p==0 ) return 1;
  switch( p->eJType ){
    case XJD1_FALSE: {
      *pRes = 0.0;
      return 0;
    }
    case XJD1_TRUE: {
      *pRes = 1.0;
      return 0;
    }
    case XJD1_REAL: {
      *pRes = p->u.r;
      return 0;
    }
    case XJD1_NULL: {
      return 1;
    }
    case XJD1_STRING: {
      char *zEnd;
      if( isspace(p->u.z[0]) ){
        return 1;
      }else{
        *pRes = strtod(p->u.z, &zEnd);
        if( zEnd[0]!=0 ){
          return 1;
        }
        return 0;
      }
    }
    case XJD1_ARRAY: {
      return 1;
    }
    case XJD1_STRUCT: {
      return 1;
    }
  }
}

/*
** Attempt to convert a JSON object into a string.  Return 0
** if successful and 1 if there is an error.
*/
int xjd1JsonToString(const JsonNode *p, String *pOut){
  if( p==0 ){
    xjd1StringAppend(pOut, "null", 4);
    return 1;
  }
  switch( p->eJType ){
    case XJD1_FALSE: {
      xjd1StringAppend(pOut, "false", 5);
      break;
    }
    case XJD1_TRUE: {
      xjd1StringAppend(pOut, "true", 4);
      break;
    }
    case XJD1_REAL: {
      xjd1StringAppendF(pOut, "%.17g", p->u.r);
      break;
    }
    case XJD1_NULL: {
      xjd1StringAppend(pOut, "null", 4);
      break;
    }
    case XJD1_STRING: {
      xjd1StringAppend(pOut, p->u.z, -1);
      break;
    }
    case XJD1_ARRAY: {
      xjd1JsonRender(pOut, p);
      break;
    }
    case XJD1_STRUCT: {
      xjd1JsonRender(pOut, p);
      break;
    }
  }
  return 0;
}

/*
** Compare to JSON objects.  Return negative, zero, or positive if the
** first is less than, equal to, or greater than the second.
*/
int xjd1JsonCompare(const JsonNode *pLeft, const JsonNode *pRight){
  if( pLeft==0 ){
    return pRight ? -1 : 0;
  }
  if( pRight==0 ){
    return 1;
  }
  if( pLeft->eJType!=pRight->eJType ){
    return pLeft->eJType - pRight->eJType;
  }
  switch( pLeft->eJType ){
    case XJD1_REAL: {
      if( pLeft->u.r<pRight->u.r ){
        return -1;
      }
      if( pLeft->u.r>pRight->u.r ){
        return 1;
      }
      return 0;
    }
    case XJD1_STRING: {
      return strcmp(pLeft->u.z, pRight->u.z);
    }
    case XJD1_ARRAY: {
      int i, mx, c;
      mx = pLeft->u.ar.nElem;
      if( mx>pRight->u.ar.nElem ) mx = pRight->u.ar.nElem;
      for(i=0; i<mx; i++){
        c = xjd1JsonCompare(pLeft->u.ar.apElem[i], pRight->u.ar.apElem[i]);
        if( c ) return c;
      }
      return pLeft->u.ar.nElem - pRight->u.ar.nElem;
    }
    case XJD1_STRUCT: {
      JsonStructElem *pA = pLeft->u.st.pFirst;
      JsonStructElem *pB = pRight->u.st.pFirst;
      int c = 0;
      while( pA && pB ){
        c = strcmp(pA->zLabel, pB->zLabel);
        if( c ) return c;
        c = xjd1JsonCompare(pA->pValue, pB->pValue);
        if( c ) return c;
        pA = pA->pNext;
        pB = pB->pNext;
      }
      if( pA ){
        return 1;
      }
      if( pB ){
        return -1;
      }
      return 0;
    }
  }
  return 0;
}


/* JSON parser token types */
#define JSON_FALSE          XJD1_FALSE
#define JSON_TRUE           XJD1_TRUE
#define JSON_REAL           XJD1_REAL
#define JSON_NULL           XJD1_NULL

Changes to src/string.c.

57
58
59
60
61
62
63











64
65
66
67
68
69
70
*/
void xjd1StringTruncate(String *pStr){
  if( pStr ){
    pStr->nUsed = 0;
    if( pStr->zBuf ) pStr->zBuf[0] = 0;
  }
}












/*
** Append text in z to a string.  If n>=0 then append exactly
** n bytes.  If n<0 then append all of z[] up to the zero terminator.
**
** Return the number of bytes appended.  0 is returned on an OOM
** error.







>
>
>
>
>
>
>
>
>
>
>







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
*/
void xjd1StringTruncate(String *pStr){
  if( pStr ){
    pStr->nUsed = 0;
    if( pStr->zBuf ) pStr->zBuf[0] = 0;
  }
}

/*
** Return the value of a string.
*/
char *xjd1StringGet(String *pStr){
  char *z;
  if( pStr==0 ) return 0;
  z = pStr->zBuf;
  memset(pStr, 0, sizeof(*pStr));
  return z;
}

/*
** Append text in z to a string.  If n>=0 then append exactly
** n bytes.  If n<0 then append all of z[] up to the zero terminator.
**
** Return the number of bytes appended.  0 is returned on an OOM
** error.

Changes to src/tokenize.c.

229
230
231
232
233
234
235

236



237

238
239
240
241
242
243
244
      return i;
    }
    case '%': {
      *tokenType = TK_REM;
      return 1;
    }
    case '=': {

      *tokenType = TK_EQ;



      return 1 + (z[1]=='=');

    }
    case '<': {
      if( (c=z[1])=='=' ){
        *tokenType = TK_LE;
        return 2;
      }else if( c=='>' ){
        *tokenType = TK_NE;







>
|
>
>
>
|
>







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
      return i;
    }
    case '%': {
      *tokenType = TK_REM;
      return 1;
    }
    case '=': {
      if( z[1]=='=' ){
        *tokenType = TK_EQ;
        return 2;
      }else{
        *tokenType = TK_ILLEGAL;
        return 1;
      }
    }
    case '<': {
      if( (c=z[1])=='=' ){
        *tokenType = TK_LE;
        return 2;
      }else if( c=='>' ){
        *tokenType = TK_NE;

Changes to src/xjd1Int.h.

328
329
330
331
332
333
334
335



336
337
338
339
340
341
342
...
360
361
362
363
364
365
366

367
368
369
370
371
372
373
int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
int xjd1ExprListClose(ExprList*);

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



JsonNode *xjd1JsonNew(Pool*);
JsonNode *xjd1JsonEdit(JsonNode*);
void xjd1JsonFree(JsonNode*);
void xjd1DequoteString(char*,int);

/******************************** malloc.c ***********************************/
Pool *xjd1PoolNew(void);
................................................................................
/******************************** stmt.c *************************************/
JsonNode *xjd1StmtDoc(xjd1_stmt*, const char*);

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

int xjd1StringAppend(String*, const char*, int);
#define xjd1StringText(S)      ((S)->zBuf)
#define xjd1StringLen(S)       ((S)->nUsed)
void xjd1StringTruncate(String*);
void xjd1StringClear(String*);
void xjd1StringDelete(String*);
void xjd1StringRemovePrefix(String*,int);







|
>
>
>







 







>







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
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 xjd1JsonCompare(const JsonNode*, const JsonNode*);
JsonNode *xjd1JsonNew(Pool*);
JsonNode *xjd1JsonEdit(JsonNode*);
void xjd1JsonFree(JsonNode*);
void xjd1DequoteString(char*,int);

/******************************** malloc.c ***********************************/
Pool *xjd1PoolNew(void);
................................................................................
/******************************** stmt.c *************************************/
JsonNode *xjd1StmtDoc(xjd1_stmt*, const char*);

/******************************** string.c ***********************************/
int xjd1Strlen30(const char *);
void xjd1StringInit(String*, Pool*, int);
String *xjd1StringNew(Pool*, int);
char *xjd1StringGet(String*);
int xjd1StringAppend(String*, const char*, int);
#define xjd1StringText(S)      ((S)->zBuf)
#define xjd1StringLen(S)       ((S)->nUsed)
void xjd1StringTruncate(String*);
void xjd1StringClear(String*);
void xjd1StringDelete(String*);
void xjd1StringRemovePrefix(String*,int);

Changes to test/base01.test.

22
23
24
25
26
27
28
29
30
31
32










.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132
SELECT {p:1, q:{x:[1,2,3],y:11}} FROM abc;
.result {"p":1,"q":{"x":[1,2,3],"y":11}}

.breakpoint
.testcase 140
SELECT { x:abc.name, y:10 } FROM abc;
.result {"x":"abc","y":10}

















<



>
>
>
>
>
>
>
>
>
>
22
23
24
25
26
27
28

29
30
31
32
33
34
35
36
37
38
39
40
41
.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132
SELECT {p:1, q:{x:[1,2,3],y:11}} FROM abc;
.result {"p":1,"q":{"x":[1,2,3],"y":11}}


.testcase 140
SELECT { x:abc.name, y:10 } FROM abc;
.result {"x":"abc","y":10}
.testcase 141
SELECT { x:[abc.name,abc,abc.xyz], y:10 } FROM abc;
.result {"x":["abc",{"name":"abc"},null],"y":10}

.testcase 150
SELECT FROM abc WHERE abc.name=="abc";
.result {"name":"abc"}
.testcase 151
SELECT FROM abc WHERE abc.name=="xyz";
.result