UnQL

Check-in [e2bc14a5be]
Login

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

Overview
Comment:Basic UPDATE statements (and UPSERT) is now working. However, new fields are not added yet.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e2bc14a5be042ea6f112de98312ffdc6c1ab76d1
User & Date: drh 2011-06-30 20:44:41
Context
2011-06-30
22:24
Update adds new fields as appropriate. check-in: 05d60ec33a user: drh tags: trunk
20:44
Basic UPDATE statements (and UPSERT) is now working. However, new fields are not added yet. check-in: e2bc14a5be user: drh tags: trunk
20:13
Incremental check-in. Various bug fixes. Progress toward getting UPDATE running. check-in: 0a23ab0e48 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
** Initialize a list of expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprListInit(ExprList *p, xjd1_stmt *pStmt, Query *pQuery){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xQueryAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  return walkExprList(p, &sAction);
}


/* Walker callback for ExprClose() */







|







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
** Initialize a list of expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprListInit(ExprList *p, xjd1_stmt *pStmt, Query *pQuery){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  return walkExprList(p, &sAction);
}


/* Walker callback for ExprClose() */

Changes to src/json.c.

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
**
*************************************************************************
** 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 ){
      case XJD1_STRING: {
        free(p->u.z);
        break;
      }
      case XJD1_ARRAY: {
        int i;
        for(i=0; i<p->u.ar.nElem; i++){
          xjd1JsonFree(p->u.ar.apElem[i]);
        }
        free(p->u.ar.apElem);
        break;
      }
      case XJD1_STRUCT: {
        JsonStructElem *pElem, *pNext;
        for(pElem=p->u.st.pFirst; pElem; pElem=pNext){
          pNext = pElem->pNext;
          free(pElem->zLabel);
          xjd1JsonFree(pElem->pValue);
          free(pElem);
        }
        break;
      }
    }









    free(p);
  }
}

/*
** Allocate a new Json node.
*/







>

<
>

|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>







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
**
*************************************************************************
** This file contains code used to parse and render JSON strings.
*/
#include "xjd1Int.h"
#include <ctype.h>


/*

** Change a JsonNode to be a NULL.  Any substructure is deleted.
*/
void xjd1JsonToNull(JsonNode *p){

  if( p==0 ) return;
  switch( p->eJType ){
    case XJD1_STRING: {
      free(p->u.z);
      break;
    }
    case XJD1_ARRAY: {
      int i;
      for(i=0; i<p->u.ar.nElem; i++){
        xjd1JsonFree(p->u.ar.apElem[i]);
      }
      free(p->u.ar.apElem);
      break;
    }
    case XJD1_STRUCT: {
      JsonStructElem *pElem, *pNext;
      for(pElem=p->u.st.pFirst; pElem; pElem=pNext){
        pNext = pElem->pNext;
        free(pElem->zLabel);
        xjd1JsonFree(pElem->pValue);
        free(pElem);
      }
      break;
    }
  }
  p->eJType = XJD1_NULL;
}

/*
** Reclaim memory used by JsonNode objects 
*/
void xjd1JsonFree(JsonNode *p){
  if( p && (--p->nRef)<=0 ){
    xjd1JsonToNull(p);
    free(p);
  }
}

/*
** Allocate a new Json node.
*/

Changes to src/update.c.

14
15
16
17
18
19
20
















21














22
23
24
25
26
27
28
29
30









31
32
33
34
35
36
37
..
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Code to evaluate an UPDATE statement
*/
#include "xjd1Int.h"
































/*
** Perform an edit on a JSON value.  Return the document after the change.
*/
static JsonNode *reviseOneField(
  JsonNode *pDoc,        /* The document to be edited */
  Expr *pLvalue,         /* Definition of field in document to be changed */
  Expr *pValue           /* New value for the field */
){
  return pDoc;









}


/*
** Evaluate an UPDATE.
*/
int xjd1UpdateStep(xjd1_stmt *pStmt){
................................................................................

        pNewDoc  = xjd1JsonRef(pStmt->pDoc);
        pChng = pCmd->u.update.pChng;
        n = pChng->nEItem;
        for(i=0; i<n-1; i += 2){
          Expr *pLvalue = pChng->apEItem[i].pExpr;
          Expr *pExpr = pChng->apEItem[i+1].pExpr;
          pNewDoc = reviseOneField(pNewDoc, pLvalue, pExpr);
        }
        xjd1StringInit(&jsonNewDoc, 0, 0);
        xjd1JsonRender(&jsonNewDoc, pNewDoc);
        sqlite3_bind_int64(pReplace, 1, sqlite3_column_int64(pQuery, 0));
        sqlite3_bind_text(pReplace, 2, xjd1StringText(&jsonNewDoc), -1,
                          SQLITE_STATIC);
        sqlite3_step(pReplace);
        sqlite3_reset(pReplace);
        xjd1StringClear(&jsonNewDoc);
        xjd1JsonFree(pNewDoc);
        nUpdate++;
      }







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



|
|



|
>
>
>
>
>
>
>
>
>







 







|



|
|







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
69
70
71
72
73
74
75
76
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Code to evaluate an UPDATE statement
*/
#include "xjd1Int.h"

/*
** The expression p is an L-value.  Find the corresponding JsonNode.
** Create it if necessary.
*/
static JsonNode *findOrCreateJsonNode(JsonNode **ppRoot, Expr *p){
  if( p==0 ) return 0;
  switch( p->eType ){
    case TK_DOT: {
      JsonNode *pBase = findOrCreateJsonNode(ppRoot, p->u.lvalue.pLeft);
      JsonStructElem *pElem;
      JsonNode *pRes = 0;
      if( pBase && pBase->eJType==XJD1_STRUCT ){
        for(pElem=pBase->u.st.pFirst; pElem; pElem=pElem->pNext){
          if( strcmp(pElem->zLabel, p->u.lvalue.zId)==0 ){
            pRes = pElem->pValue;
            break;
          }
        }
      }
      return pRes;
    }
    case TK_LB: {
      return 0;   /* TBD */
    }
    case TK_ID: {
      return *ppRoot;
    }
  }
  return 0;
}

/*
** Perform an edit on a JSON value.  Return the document after the change.
*/
static void reviseOneField(
  JsonNode **ppDoc,      /* The document to be edited */
  Expr *pLvalue,         /* Definition of field in document to be changed */
  Expr *pValue           /* New value for the field */
){
  JsonNode *pNode;
  JsonNode *pX;

  pNode = findOrCreateJsonNode(ppDoc, pLvalue);
  if( pNode ){
    pX = xjd1JsonEdit(xjd1ExprEval(pValue));
    xjd1JsonToNull(pNode);
    *pNode = *pX;
    free(pX);
  }
}


/*
** Evaluate an UPDATE.
*/
int xjd1UpdateStep(xjd1_stmt *pStmt){
................................................................................

        pNewDoc  = xjd1JsonRef(pStmt->pDoc);
        pChng = pCmd->u.update.pChng;
        n = pChng->nEItem;
        for(i=0; i<n-1; i += 2){
          Expr *pLvalue = pChng->apEItem[i].pExpr;
          Expr *pExpr = pChng->apEItem[i+1].pExpr;
          reviseOneField(&pNewDoc, pLvalue, pExpr);
        }
        xjd1StringInit(&jsonNewDoc, 0, 0);
        xjd1JsonRender(&jsonNewDoc, pNewDoc);
        sqlite3_bind_int64(pReplace, 2, sqlite3_column_int64(pQuery, 0));
        sqlite3_bind_text(pReplace, 1, xjd1StringText(&jsonNewDoc), -1,
                          SQLITE_STATIC);
        sqlite3_step(pReplace);
        sqlite3_reset(pReplace);
        xjd1StringClear(&jsonNewDoc);
        xjd1JsonFree(pNewDoc);
        nUpdate++;
      }

Changes to src/xjd1Int.h.

340
341
342
343
344
345
346

347
348
349
350
351
352
353
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);
void xjd1PoolClear(Pool*);
void xjd1PoolDelete(Pool*);
void *xjd1PoolMalloc(Pool*, int);







>







340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
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 xjd1JsonToNull(JsonNode*);
void xjd1DequoteString(char*,int);

/******************************** malloc.c ***********************************/
Pool *xjd1PoolNew(void);
void xjd1PoolClear(Pool*);
void xjd1PoolDelete(Pool*);
void *xjd1PoolMalloc(Pool*, int);

Changes to test/base01.test.

73
74
75
76
77
78
79
80
SELECT FROM counter;
.result {"name":"xyz","n":2}
.testcase 173
INSERT INTO counter VALUE {name:"pqr", n:0};
UPDATE counter SET counter.n=counter.n+1 WHERE counter.name=="xyz"
  ELSE INSERT {name:"xyz", n:1};
SELECT FROM counter;
.result {"name":"xyz","n":2} {"name":"pqr","n":0}







|
73
74
75
76
77
78
79
80
SELECT FROM counter;
.result {"name":"xyz","n":2}
.testcase 173
INSERT INTO counter VALUE {name:"pqr", n:0};
UPDATE counter SET counter.n=counter.n+1 WHERE counter.name=="xyz"
  ELSE INSERT {name:"xyz", n:1};
SELECT FROM counter;
.result {"name":"xyz","n":3} {"name":"pqr","n":0}