UnQL

Check-in [0eba200fb2]
Login

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

Overview
Comment:Implement the WITHIN operator.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0eba200fb28d9c455c3d3cf837e1c88db17e74d8
User & Date: drh 2011-07-16 15:12:48
Context
2011-07-16
15:28
Add a FIX ME comment on the unfinished "\uXXXX" translator. check-in: b77b043f2d user: drh tags: trunk
15:12
Implement the WITHIN operator. check-in: 0eba200fb2 user: drh tags: trunk
14:53
Provide an implementation for the "in" operator. check-in: 4f893cfaf7 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

304
305
306
307
308
309
310







































311
312
313
314
315
316
317
...
594
595
596
597
598
599
600









601
602
603
604
605
606
607
    }
    default: {
      rc = 0;
    }
  }
  return rc;
}








































/*
** 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){
................................................................................
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);
      pRes->eJType = inOperator(pJLeft, pJRight) ? XJD1_TRUE : XJD1_FALSE;
      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);
      break;
    }










    default: {
      pRes->eJType = XJD1_NULL;
      break;
    }
  }
  return pRes;







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







 







>
>
>
>
>
>
>
>
>







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
...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
    }
    default: {
      rc = 0;
    }
  }
  return rc;
}

/*
** Return TRUE if and only if all of the following are true:
**
**   (1)  pA exists
**   (2)  pB exists and is an array or structure.
**   (3)  pA is value contained within pB
*/
static int withinOperator(JsonNode *pA, JsonNode *pB){
  int rc = 0;
  if( pA==0 ) return 0;
  if( pB==0 ) return 0;
  switch( pB->eJType ){
    case XJD1_ARRAY: {
      int i;
      for(i=0; i<pB->u.ar.nElem; i++){
        if( xjd1JsonCompare(pA, pB->u.ar.apElem[i])==0 ){
          rc = 1;
          break;
        }
      }
      break;
    }
    case XJD1_STRUCT: {
      JsonStructElem *p;
      for(p=pB->u.st.pFirst; p; p=p->pNext){
        if( xjd1JsonCompare(pA, p->pValue)==0 ){
          rc = 1;
          break;
        }
      }
      break;
    }
    default: {
      rc = 0;
    }
  }
  return rc;
}

/*
** 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){
................................................................................
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);
      pRes->eJType = inOperator(pJLeft, pJRight) ? XJD1_TRUE : XJD1_FALSE;
      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);
      break;
    }

    case TK_WITHIN: {
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);
      pRes->eJType = withinOperator(pJLeft, pJRight) ? XJD1_TRUE : XJD1_FALSE;
      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);
      break;
    }

    default: {
      pRes->eJType = XJD1_NULL;
      break;
    }
  }
  return pRes;

Changes to src/parse.y.

76
77
78
79
80
81
82


83





84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
      pNew->u.r = atof(pTok->z);
    }
    return pNew;
  }

  /* Convert a token into a zero-terminated string */
  static char *tokenStr(Parse *p, Token *pTok){


    return pTok ? xjd1PoolDup(p->pPool, pTok->z, pTok->n) : 0;





  }

  /* A JSON literal for a string */
  static JsonNode *jsonString(Parse *p, Token *pTok){
    JsonNode *pNew = xjd1JsonNew(p->pPool);
    if( pNew ){
      pNew->eJType = XJD1_STRING;
      pNew->u.z = tokenStr(p, pTok);
      xjd1DequoteString(pNew->u.z, pTok->n);
    }
    return pNew;
  }

  /* A JSON literal for a boolean or NULL */
  static JsonNode *jsonType(Parse *p, int eJType){
    JsonNode *pNew = xjd1JsonNew(p->pPool);







>
>
|
>
>
>
>
>








<







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
      pNew->u.r = atof(pTok->z);
    }
    return pNew;
  }

  /* Convert a token into a zero-terminated string */
  static char *tokenStr(Parse *p, Token *pTok){
    char *z;
    if( pTok ){
      z = xjd1PoolDup(p->pPool, pTok->z, pTok->n);
      if( z && z[0]=='"' ) xjd1DequoteString(z, pTok->n);
    }else{
      z = 0;
    }
    return z;
  }

  /* A JSON literal for a string */
  static JsonNode *jsonString(Parse *p, Token *pTok){
    JsonNode *pNew = xjd1JsonNew(p->pPool);
    if( pNew ){
      pNew->eJType = XJD1_STRING;
      pNew->u.z = tokenStr(p, pTok);

    }
    return pNew;
  }

  /* A JSON literal for a boolean or NULL */
  static JsonNode *jsonType(Parse *p, int eJType){
    JsonNode *pNew = xjd1JsonNew(p->pPool);

Changes to test/base03.test.

55
56
57
58
59
60
61






























.result false
.testcase 221
SELECT 1 in null;
.result false
.testcase 222
SELECT 1 in 1;
.result false





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
.result false
.testcase 221
SELECT 1 in null;
.result false
.testcase 222
SELECT 1 in 1;
.result false

.testcase 300
SELECT 0 WITHIN [1,2,3];
.result false
.testcase 301
SELECT 1 WITHIN [1,2,3];
.result true
.testcase 302
SELECT 2 WITHIN [1,2,3];
.result true
.testcase 303
SELECT 3 WITHIN [1,2,3];
.result true
.testcase 304
SELECT 4 WITHIN [1,2,3];
.result false
.testcase 305
SELECT "2" WITHIN [1,2,3];
.result false

.testcase 310
SELECT true WITHIN {a:false, b:null, c:true, d:123, e:{x:10}};
.result true
.breakpoint
.testcase 311
SELECT {"x": 10} WITHIN {a:false, b:null, c:true, d:123, e:{x:10}};
.result true
.testcase 312
SELECT {"x": 11} WITHIN {a:false, b:null, c:true, d:123, e:{x:10}};
.result false