UnQL

Check-in [8facf6305c]
Login

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

Overview
Comment:Completed handling of array-style lhs in UPDATE. Some semantics need review.
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA1: 8facf6305cd38ca6e8ca5173950cb17aa722c4e7
User & Date: pnr 2011-08-11 23:04:38
Context
2011-08-11
23:04
Completed handling of array-style lhs in UPDATE. Some semantics need review. Leaf check-in: 8facf6305c user: pnr tags: trunk
2011-08-09
21:44
Added initial support for array-style lhs in the UPDATE command. Assignments that would grow an array are still unimplemented, as is accessing characters of a string using the array syntax. check-in: d5e5efe19b user: pnr tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/shell.c.

385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
static int shellRead(Shell *p, int argc, char **argv){
  if( argc>=2 ){
    int nErr = p->nErr;
    String newFile;
    char *zNew;
    xjd1StringInit(&newFile, 0, 0);
    if( argv[1][0]=='/' || strcmp(p->zFile,"-")==0 ){
      xjd1StringAppend(&newFile, argv[1], 0);
    }else{
      int i, j;
      for(i=j=0; p->zFile[i]; i++){ if( p->zFile[i]=='/' ) j = i; }
      xjd1StringAppendF(&newFile, "%.*s/%s", j, p->zFile, argv[1]);
    }
    zNew = xjd1StringText(&newFile);
    printf("BEGIN %s\n", zNew);







|







385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
static int shellRead(Shell *p, int argc, char **argv){
  if( argc>=2 ){
    int nErr = p->nErr;
    String newFile;
    char *zNew;
    xjd1StringInit(&newFile, 0, 0);
    if( argv[1][0]=='/' || strcmp(p->zFile,"-")==0 ){
      xjd1StringAppend(&newFile, argv[1], -1);
    }else{
      int i, j;
      for(i=j=0; p->zFile[i]; i++){ if( p->zFile[i]=='/' ) j = i; }
      xjd1StringAppendF(&newFile, "%.*s/%s", j, p->zFile, argv[1]);
    }
    zNew = xjd1StringText(&newFile);
    printf("BEGIN %s\n", zNew);

Changes to src/update.c.

16
17
18
19
20
21
22
23

24
25
26
27
28
29

30
31
32
33
34
35
36
..
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
*************************************************************************
** Code to evaluate an UPDATE statement
*/
#include "xjd1Int.h"


/*
** pBase is a JSON structure object.  Or if it is not, it should be

** converted into one.  Then lookup or insert the zField element.
*/
static JsonNode *findStructElement(JsonNode *pBase, const char *zField){
  JsonStructElem *pElem;
  if( pBase==0 ) return 0;
  if( pBase->eJType!=XJD1_STRUCT ){

    xjd1JsonToNull(pBase);
    pBase->eJType = XJD1_STRUCT;
    pBase->u.st.pFirst = 0;
    pBase->u.st.pLast = 0;
  }
  for(pElem=pBase->u.st.pFirst; pElem; pElem=pElem->pNext){
    if( strcmp(pElem->zLabel, zField)==0 ){
................................................................................

    /* 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 reference node is 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 reference node is
    ** element y of array x. ** TBD: extending array size as needed **
    **
    ** If x is of type XJD1_STRING, then it is treated as an array of 
    ** characters. Processing proceeds as for XJD1_ARRAY. ** TBD **


    */
    case TK_LB: {
      JsonNode *pBase = findOrCreateJsonNode(pRoot, p->u.bi.pLeft);
      switch( pBase->eJType ){
        case XJD1_STRUCT: {
          JsonNode *pRes;
          String idx;
................................................................................
        }

        case XJD1_ARRAY: {
          double rRight;
          int iIdx;
          if( xjd1JsonToReal(xjd1ExprEval(p->u.bi.pRight), &rRight) ) break;
          iIdx = (int)rRight;
          if( (double)iIdx==rRight && iIdx>=0 && iIdx<pBase->u.ar.nElem ){

            return pBase->u.ar.apElem[iIdx];














            



          }
          break;
        }

        case XJD1_STRING: {
          /* TBD */
          break;
        }
      }
    }
    break;
      
    case TK_ID: {







|
>
|





>







 







|
|

|
|
>
>







 







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




|
|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
..
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
*************************************************************************
** Code to evaluate an UPDATE statement
*/
#include "xjd1Int.h"


/*
** pBase is a JSON structure object.  If it is not, overwrite the current
** value with an empty structure object. [[TBD: If it is not, return 0;]]
** Otherwise, lookup or insert the zField element.
*/
static JsonNode *findStructElement(JsonNode *pBase, const char *zField){
  JsonStructElem *pElem;
  if( pBase==0 ) return 0;
  if( pBase->eJType!=XJD1_STRUCT ){
//    return 0;
    xjd1JsonToNull(pBase);
    pBase->eJType = XJD1_STRUCT;
    pBase->u.st.pFirst = 0;
    pBase->u.st.pLast = 0;
  }
  for(pElem=pBase->u.st.pFirst; pElem; pElem=pElem->pNext){
    if( strcmp(pElem->zLabel, zField)==0 ){
................................................................................

    /* 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 reference node is 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 the reference node
    ** is element y of array x. Grow the array as needed.
    **
    ** If x is of any other type the assignment is silently ignored.
    ** Note that individual string characters can be read, but not
    ** written using the x[y] syntax. 
    ** TBD: should x===null throw an error?
    */
    case TK_LB: {
      JsonNode *pBase = findOrCreateJsonNode(pRoot, p->u.bi.pLeft);
      switch( pBase->eJType ){
        case XJD1_STRUCT: {
          JsonNode *pRes;
          String idx;
................................................................................
        }

        case XJD1_ARRAY: {
          double rRight;
          int iIdx;
          if( xjd1JsonToReal(xjd1ExprEval(p->u.bi.pRight), &rRight) ) break;
          iIdx = (int)rRight;
          if( (double)iIdx==rRight && iIdx>=0 ){
            if( iIdx<pBase->u.ar.nElem ){
              return pBase->u.ar.apElem[iIdx];
            }else{
              JsonNode **pNewArray;
              int i;
              /* Grow the array as needed. TBD: find a way to handle very
              ** large, sparse arrays. As a temporary drafting precaution,
              ** assert that the value of iIdx is less than 1024. 
              */
              assert( iIdx<1024 );
              pNewArray = xjd1_realloc(pBase->u.ar.apElem, sizeof(JsonNode*)*(iIdx+1));
              if( pNewArray==0 ) break;
              pBase->u.ar.apElem = pNewArray;
              for(i=pBase->u.ar.nElem; i<=iIdx; i++) {
                pNewArray[i] = xjd1JsonNew(0);
                pNewArray[i]->eJType = XJD1_NULL;
              }
              pBase->u.ar.nElem = iIdx+1;
              return pBase->u.ar.apElem[iIdx];
            }
          }
          break;
        }

        case XJD1_NULL: {
          /* TBD: throw error? */
          break;
        }
      }
    }
    break;
      
    case TK_ID: {

Added test/base11.test.









































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
-- Test UPDATE statement
--

.new t1.db
CREATE COLLECTION c1;
INSERT INTO c1 VALUE null;
INSERT INTO c1 VALUE true;
INSERT INTO c1 VALUE 1;
INSERT INTO c1 VALUE "abc";
INSERT INTO c1 VALUE [1,2,3,4];
INSERT INTO c1 VALUE {a: 1, b:2, c:3};

.testcase 0
SELECT FROM c1;
.json null\
      true\
      1\
      "abc"\
      [1,2,3,4]\
      {"a":1,"b":2,"c":3}

-- setting named properties on primitives or
-- arrays is ignored
.testcase 1
UPDATE c1 SET c1.a = 2;
SELECT FROM c1;
.json null\
      true\
      1\
      "abc"\
      [1,2,3,4]\
      {"a":2,"b":2,"c":3}

-- setting named properties on primitives or
-- arrays is ignored, also when x[y] syntax is used
.testcase 2
UPDATE c1 SET c1["a"] = 3;
SELECT FROM c1;
.json null\
      true\
      1\
      "abc"\
      [1,2,3,4]\
      {"a":3,"b":2,"c":3}

-- setting number properties on primitives is
-- ignored, but honoured on arrays and objects
.testcase 3
UPDATE c1 SET c1["2"] = 7;
SELECT FROM c1;
.json null\
      true\
      1\
      "abc"\
      [1,2,7,4]\
      {"a":3,"b":2,"c":3, "2":7}

-- setting number properties on arrays potentially
-- grows the array, padding skipped elements with null
.testcase 4
UPDATE c1 SET c1["7"] = 9;
SELECT FROM c1;
.json null\
      true\
      1\
      "abc"\
      [1,2,7,4,null,null,null,9]\
      {"a":3,"b":2,"c":3, "2":7, "7":9}