UnQL

Check-in [0d9044c381]
Login

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

Overview
Comment:Add support for the [] operator on arrays and strings.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0d9044c3817efdb0bb282d440f06bf72391cf26f
User & Date: dan 2011-07-16 15:47:11
Context
2011-07-16
16:12
Fix problems with arrays and objects with zero members. check-in: 5b31aa5264 user: dan tags: trunk
15:47
Add support for the [] operator on arrays and strings. check-in: 0d9044c381 user: dan tags: trunk
15:28
Add a FIX ME comment on the unfinished "\uXXXX" translator. check-in: b77b043f2d user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

306
307
308
309
310
311
312

313
314
315
316
317
318
319
...
343
344
345
346
347
348
349










350
351
352
353
354
355
356
...
373
374
375
376
377
378
379







380
381
382
383

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
409
410
411
412
413
      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){
................................................................................
    }
    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){
................................................................................
    }

    /* The x[y] operator. The result depends on the type of value x.
    **
    ** If x is of type XJD1_STRUCT, then expression y is converted to
    ** a string. The value returned is the value of property y of 
    ** object x.







    */
    case TK_LB: {
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);


      switch( pJLeft->eJType ){
        case XJD1_STRUCT: {
          String idx;
          xjd1StringInit(&idx, 0, 0);
          xjd1JsonToString(pJRight, &idx);
          pRes = getProperty(pJLeft, idx.zBuf);
          xjd1StringClear(&idx);
          break;
        }

        case XJD1_ARRAY:









        case XJD1_STRING: {





















          break;
        }

        default:
          pRes = nullJson();
          break;
      }

      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);

      return pRes;
    }

    case TK_ID: {
      if( p->pQuery ){
        return xjd1QueryDoc(p->pQuery, p->u.id.zId);
      }else{







>







 







>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>




>











|
>
>
>
>
>
>
>
>
>

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




<





>







306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
...
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
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
437
438
439
440
441
442
443
444
445
446
447
448
449

450
451
452
453
454
455
456
457
458
459
460
461
462
      rc = 0;
    }
  }
  return rc;
}

/*
** Evaluate an expression.  Return the result as a JSON object.
** 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){
................................................................................
    }
    default: {
      rc = 0;
    }
  }
  return rc;
}

/*
** Assuming zIn points to the first byte of a UTF-8 character,
** advance zIn to point to the first byte of the next UTF-8 character.
*/
#define XJD1_SKIP_UTF8(zIn) {                          \
    if( (*(zIn++))>=0xc0 ){                            \
          while( (*zIn & 0xc0)==0x80 ){ zIn++; }       \
    }                                                  \
}

/*
** 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){
................................................................................
    }

    /* The x[y] operator. The result depends on the type of value x.
    **
    ** If x is of type XJD1_STRUCT, then expression y is converted to
    ** a string. The value returned is the value of property y of 
    ** object x.
    **
    ** If x is of type XJD1_ARRAY, then expression y is converted to
    ** a number. If that number is an integer, then it is the index of
    ** the array element to return.
    **
    ** If x is of type XJD1_STRING, then it is treated as an array of 
    ** characters. Processing proceeds as for XJD1_ARRAY.
    */
    case TK_LB: {
      pJLeft = xjd1ExprEval(p->u.bi.pLeft);
      pJRight = xjd1ExprEval(p->u.bi.pRight);
      pRes = 0;

      switch( pJLeft->eJType ){
        case XJD1_STRUCT: {
          String idx;
          xjd1StringInit(&idx, 0, 0);
          xjd1JsonToString(pJRight, &idx);
          pRes = getProperty(pJLeft, idx.zBuf);
          xjd1StringClear(&idx);
          break;
        }

        case XJD1_ARRAY: {
          int iIdx;
          if( xjd1JsonToReal(pJRight, &rRight) ) break;
          iIdx = (int)rRight;
          if( (double)iIdx==rRight && iIdx>=0 && iIdx<pJLeft->u.ar.nElem ){
            pRes = xjd1JsonRef(pJLeft->u.ar.apElem[iIdx]);
          }
          break;
        }

        case XJD1_STRING: {
          int iIdx;
          if( xjd1JsonToReal(pJRight, &rRight) ) break;
          iIdx = (int)rRight;
          if( (double)iIdx==rRight && iIdx>=0 ){
            char *z = pJLeft->u.z;
            for(z=pJLeft->u.z; *z && iIdx!=0; iIdx--){
              XJD1_SKIP_UTF8(z);
            }
            if( *z ){
              String x;
              char *zEnd = z;
              pRes = xjd1JsonNew(0);
              if( pRes ){
                XJD1_SKIP_UTF8(zEnd);
                xjd1StringInit(&x, 0, 0);
                xjd1StringAppend(&x, z, zEnd-z);
                pRes->eJType = XJD1_STRING;
                pRes->u.z = xjd1StringGet(&x);
              }
            }
          }
          break;
        }

        default:

          break;
      }

      xjd1JsonFree(pJLeft);
      xjd1JsonFree(pJRight);
      if( pRes==0 ) pRes = nullJson();
      return pRes;
    }

    case TK_ID: {
      if( p->pQuery ){
        return xjd1QueryDoc(p->pQuery, p->u.id.zId);
      }else{

Changes to test/base02.test.

118
119
120
121
122
123
124

125
126










127














.testcase 17
CREATE COLLECTION c2;
INSERT INTO c2 VALUE { a:1, b:2, c:"d", d:3 };
SELECT c2.a FROM c2;
SELECT c2["b"] FROM c2;
SELECT c2[c2.c] FROM c2;

.result 1 2 3
































>
|

>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
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

.testcase 17
CREATE COLLECTION c2;
INSERT INTO c2 VALUE { a:1, b:2, c:"d", d:3 };
SELECT c2.a FROM c2;
SELECT c2["b"] FROM c2;
SELECT c2[c2.c] FROM c2;
SELECT c2["e"] FROM c2;
.result 1 2 3 null

.testcase 18
DELETE FROM c2;
INSERT INTO c2 VALUE { x: [10,11,12,13,14,15,16] };
SELECT c2.x[0]          FROM c2;
SELECT c2.x["1"]        FROM c2;
SELECT c2.x[2.01]       FROM c2;
SELECT c2.x[c2.x[6]-13] FROM c2;
SELECT c2.x[-1]         FROM c2;
SELECT c2.x[7]          FROM c2;
.result 10 11 null 13 null null

.testcase 19
DELETE FROM c2;
INSERT INTO c2 VALUE { x: "abcdefg" };
SELECT c2.x[0]       FROM c2;
SELECT c2.x["1"]     FROM c2;
SELECT c2.x[2.01]    FROM c2;
SELECT c2.x[1+1+1]   FROM c2;
SELECT c2.x[-1]      FROM c2;
SELECT c2.x[7]       FROM c2;
SELECT c2.x[0][0][0] FROM c2;
.result "a" "b" null "d" null null "a"