UnQL

Check-in [c0f72777e2]
Login

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

Overview
Comment:Added preliminary UPSERT syntax. Added some simple UPDATE test cases, but since the UPDATE code is not in place, those test cases are currently failing.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c0f72777e2a310bc8b04d658171192f8ee82056a
User & Date: drh 2011-06-30 15:51:05
Context
2011-06-30
20:13
Incremental check-in. Various bug fixes. Progress toward getting UPDATE running. check-in: 0a23ab0e48 user: drh tags: trunk
15:51
Added preliminary UPSERT syntax. Added some simple UPDATE test cases, but since the UPDATE code is not in place, those test cases are currently failing. check-in: c0f72777e2 user: drh tags: trunk
00:09
Get DELETE statements working. check-in: f4d26bb1e0 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

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







|











|
|
|
|
|
|







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
        for(i=0; i<pList->nEItem; i++){
          ExprItem *pItem = &pList->apEItem[i];
          pRes->u.ar.apElem[i] = xjd1ExprEval(pItem->pExpr);
        }
      }
      break;
    }
    case TK_EQEQ:
    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_EQEQ: 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);

Changes to src/parse.y.

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
539
540
541
542
543
544
545
546
547
548
549
550
551
552

553
554
555
556
557
558
559
...
560
561
562
563
564
565
566




567
568
569
570
571
572
573
jvalue(A) ::= FALSE.                   {A = jsonType(p,XJD1_FALSE);}
jvalue(A) ::= NULL.                    {A = jsonType(p,XJD1_NULL);}


%left OR.
%left AND.
%right NOT.
%left IS LIKEOP BETWEEN IN NE EQ.
%left GT LE LT GE.
%right ESCAPE.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%left COLLATE.
................................................................................



expr(A) ::= ID(X) LP exprlist(Y) RP.  {A = funcExpr(p,&X,Y);}
expr(A) ::= expr(X) AND(OP) expr(Y).  {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) OR(OP) expr(Y).              {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).     {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y).           {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
                                                 {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).      {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).  {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y).          {A = biExpr(p,X,@OP,Y);}
%type likeop {int}
likeop(A) ::= LIKEOP(OP).                        {A = @OP;}
................................................................................
    pNew->u.del.pWhere = W;
  }
  A = pNew;
}

////////////////////////// The UPDATE command ////////////////////////////////
//
cmd(A) ::= UPDATE tabname(N) SET setlist(L) where_opt(W). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_UPDATE;
    pNew->u.update.zName = tokenStr(p, &N);
    pNew->u.update.pWhere = W;
    pNew->u.update.pChng = L;

  }
  A = pNew;
}

%type setlist {ExprList*}
setlist(A) ::= setlist(X) COMMA lvalue(Y) EQ expr(Z). {
   A = apndExpr(p,X,Y,0);
................................................................................
   A = apndExpr(p,A,Z,0);
}
setlist(A) ::= lvalue(Y) EQ expr(Z). {
   A = apndExpr(p,0,Y,0);
   A = apndExpr(p,A,Z,0);
}







////////////////////////// The INSERT command /////////////////////////////////
//
cmd(A) ::= INSERT INTO tabname(N) VALUE expr(V). {
  Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
  if( pNew ){







|







 







|







 







|






>







 







>
>
>
>







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
jvalue(A) ::= FALSE.                   {A = jsonType(p,XJD1_FALSE);}
jvalue(A) ::= NULL.                    {A = jsonType(p,XJD1_NULL);}


%left OR.
%left AND.
%right NOT.
%left IS LIKEOP BETWEEN IN NE EQEQ.
%left GT LE LT GE.
%right ESCAPE.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%left COLLATE.
................................................................................



expr(A) ::= ID(X) LP exprlist(Y) RP.  {A = funcExpr(p,&X,Y);}
expr(A) ::= expr(X) AND(OP) expr(Y).  {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) OR(OP) expr(Y).              {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).     {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) EQEQ|NE(OP) expr(Y).         {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
                                                 {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).      {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).  {A = biExpr(p,X,@OP,Y);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y).          {A = biExpr(p,X,@OP,Y);}
%type likeop {int}
likeop(A) ::= LIKEOP(OP).                        {A = @OP;}
................................................................................
    pNew->u.del.pWhere = W;
  }
  A = pNew;
}

////////////////////////// The UPDATE command ////////////////////////////////
//
cmd(A) ::= UPDATE tabname(N) SET setlist(L) where_opt(W) upsert_opt(U). {
  Command *pNew = xjd1PoolMalloc(p->pPool, sizeof(*pNew));
  if( pNew ){
    pNew->eCmdType = TK_UPDATE;
    pNew->u.update.zName = tokenStr(p, &N);
    pNew->u.update.pWhere = W;
    pNew->u.update.pChng = L;
    pNew->u.update.pUpsert = U;
  }
  A = pNew;
}

%type setlist {ExprList*}
setlist(A) ::= setlist(X) COMMA lvalue(Y) EQ expr(Z). {
   A = apndExpr(p,X,Y,0);
................................................................................
   A = apndExpr(p,A,Z,0);
}
setlist(A) ::= lvalue(Y) EQ expr(Z). {
   A = apndExpr(p,0,Y,0);
   A = apndExpr(p,A,Z,0);
}

%type upsert_opt {Expr*}
upsert_opt(A) ::= .                       {A = 0;}
upsert_opt(A) ::= ELSE INSERT expr(X).    {A = X;}



////////////////////////// The INSERT command /////////////////////////////////
//
cmd(A) ::= INSERT INTO tabname(N) VALUE expr(V). {
  Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
  if( pNew ){

Changes to src/stmt.c.

53
54
55
56
57
58
59

60
61
62
63
64
65
66
..
94
95
96
97
98
99
100

101
102
103
104
105
106
107
      case TK_DELETE: {
        xjd1ExprInit(pCmd->u.del.pWhere, p, 0);
        break;
      }
      case TK_UPDATE: {
        xjd1ExprInit(pCmd->u.update.pWhere, p, 0);
        xjd1ExprListInit(pCmd->u.update.pChng, p, 0);

        break;
      }
    }
  }
  return rc;
}

................................................................................
      case TK_DELETE: {
        xjd1ExprClose(pCmd->u.del.pWhere);
        break;
      }
      case TK_UPDATE: {
        xjd1ExprClose(pCmd->u.update.pWhere);
        xjd1ExprListClose(pCmd->u.update.pChng);

        break;
      }
    }
  }

  if( pStmt->pPrev ){
    pStmt->pPrev->pNext = pStmt->pNext;







>







 







>







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
      case TK_DELETE: {
        xjd1ExprInit(pCmd->u.del.pWhere, p, 0);
        break;
      }
      case TK_UPDATE: {
        xjd1ExprInit(pCmd->u.update.pWhere, p, 0);
        xjd1ExprListInit(pCmd->u.update.pChng, p, 0);
        xjd1ExprInit(pCmd->u.update.pUpsert, p, 0);
        break;
      }
    }
  }
  return rc;
}

................................................................................
      case TK_DELETE: {
        xjd1ExprClose(pCmd->u.del.pWhere);
        break;
      }
      case TK_UPDATE: {
        xjd1ExprClose(pCmd->u.update.pWhere);
        xjd1ExprListClose(pCmd->u.update.pChng);
        xjd1ExprClose(pCmd->u.update.pUpsert);
        break;
      }
    }
  }

  if( pStmt->pPrev ){
    pStmt->pPrev->pNext = pStmt->pNext;

Changes to src/tokenize.c.

82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};

/**********************************************************************
** The following code is automatically generated
** by ../tool/mkkeywordhash.c
*/
/* Hash score: 55 */
static int keywordCode(const char *z, int n){
  /* zText[] encodes 290 bytes of keywords in 201 bytes */
  /*   BEGINSERTRUEACHAVINGROUPDATESCAPEXCEPTFALSELECTALLIKEXISTSAND      */
  /*   ELETEASCENDINGLOBETWEENOTCOLLATECOLLECTIONULLIMITCOMMITCREATE      */
  /*   DESCENDINGDROPRAGMAFLATTENIFROMINTERSECTINTOFFSETORDEROLLBACK      */
  /*   UNIONVALUEWHEREBY                                                  */
  static const char zText[200] = {
    'B','E','G','I','N','S','E','R','T','R','U','E','A','C','H','A','V','I',

    'N','G','R','O','U','P','D','A','T','E','S','C','A','P','E','X','C','E',
    'P','T','F','A','L','S','E','L','E','C','T','A','L','L','I','K','E','X',
    'I','S','T','S','A','N','D','E','L','E','T','E','A','S','C','E','N','D',
    'I','N','G','L','O','B','E','T','W','E','E','N','O','T','C','O','L','L',
    'A','T','E','C','O','L','L','E','C','T','I','O','N','U','L','L','I','M',
    'I','T','C','O','M','M','I','T','C','R','E','A','T','E','D','E','S','C',
    'E','N','D','I','N','G','D','R','O','P','R','A','G','M','A','F','L','A',
    'T','T','E','N','I','F','R','O','M','I','N','T','E','R','S','E','C','T',
    'I','N','T','O','F','F','S','E','T','O','R','D','E','R','O','L','L','B',
    'A','C','K','U','N','I','O','N','V','A','L','U','E','W','H','E','R','E',
    'B','Y',
  };
  static const unsigned char aHash[80] = {
       0,  48,  46,  12,  33,  22,  47,   1,   0,   6,   0,  14,  25,
       7,   9,   0,   0,  44,   0,   5,  36,  35,  28,   0,   0,   0,
       0,  37,   0,   0,   0,  18,   0,   0,   0,  41,   0,   0,  11,
       0,   0,   0,   0,  45,   0,   0,   0,   0,   0,   0,   0,   0,
      24,  29,  40,  23,  42,  27,   0,  16,  32,  39,  19,  43,   0,
      38,  10,   0,   0,  34,   0,   0,  26,  17,   0,   0,   0,  30,
      21,  15,
  };
  static const unsigned char aNext[48] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       3,   0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,  20,
       0,   0,   0,   8,   0,   0,   0,   0,   0,   0,  13,   0,   0,
       0,   0,   4,  31,   0,   0,   0,   0,   0,
  };
  static const unsigned char aLen[48] = {
       5,   6,   4,   4,   6,   5,   6,   6,   6,   5,   6,   3,   4,
       6,   2,   3,   6,   2,   3,   9,   4,   7,   3,   7,  10,   4,
       5,   6,   6,   4,  10,   2,   4,   6,   7,   2,   4,   9,   4,
       6,   3,   2,   5,   8,   5,   5,   5,   2,
  };
  static const unsigned short int aOffset[48] = {
       0,   3,   8,  11,  14,  19,  22,  27,  32,  38,  41,  47,  49,
      52,  54,  58,  60,  66,  66,  66,  74,  77,  83,  86,  93, 102,
     105, 110, 116, 122, 122, 129, 132, 135, 141, 148, 149, 153, 162,
     165, 168, 171, 171, 175, 183, 188, 193, 198,
  };
  static const unsigned char aCode[48] = {
    TK_BEGIN,      TK_INSERT,     TK_TRUE,       TK_FLATTENOP,  TK_HAVING,     
    TK_GROUP,      TK_UPDATE,     TK_ESCAPE,     TK_EXCEPT,     TK_FALSE,      
    TK_SELECT,     TK_ALL,        TK_LIKEOP,     TK_EXISTS,     TK_IS,         
    TK_AND,        TK_DELETE,     TK_AS,         TK_ASCENDING,  TK_ASCENDING,  
    TK_LIKEOP,     TK_BETWEEN,    TK_NOT,        TK_COLLATE,    TK_COLLECTION, 
    TK_NULL,       TK_LIMIT,      TK_COMMIT,     TK_CREATE,     TK_DESCENDING, 
    TK_DESCENDING, TK_IN,         TK_DROP,       TK_PRAGMA,     TK_FLATTENOP,  
    TK_IF,         TK_FROM,       TK_INTERSECT,  TK_INTO,       TK_OFFSET,     
    TK_SET,        TK_OR,         TK_ORDER,      TK_ROLLBACK,   TK_UNION,      
    TK_VALUE,      TK_WHERE,      TK_BY,         
  };
  int h, i;
  if( n<2 || z[0]<'A' || z[0]>'Z' ) return TK_ID;
  h = (z[0]*4 ^ z[n-1]*3 ^ n) % 80;
  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    if( aLen[i]==n && memcmp(&zText[aOffset[i]],z,n)==0 ){
      return aCode[i];
    }
  }
  return TK_ID;
}
#define XJD1_N_KEYWORD 48

/* End of the automatically generated hash code
*********************************************************************/

/*
** Return the length of the token that begins at z[0]. 
** Store the token type in *tokenType before returning.
................................................................................
    }
    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;







|

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


|
|
|
|
|
|
|

|

|
|
|

|
|
|
|
|

|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|











|







 







|


|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};

/**********************************************************************
** The following code is automatically generated
** by ../tool/mkkeywordhash.c
*/
/* Hash score: 57 */
static int keywordCode(const char *z, int n){
  /* zText[] encodes 295 bytes of keywords in 204 bytes */
  /*   BEGINSERTRUELSELECTFALSEACHAVINGROUPDATESCAPEXCEPTALLIKEXISTS      */
  /*   ANDELETEASCENDINGLOBETWEENOTCOLLATECOLLECTIONULLIMITCOMMIT         */
  /*   CREATEDESCENDINGDROPRAGMAFLATTENIFROMINTERSECTINTOFFSETORDER       */
  /*   OLLBACKUNIONVALUEWHEREBY                                           */
  static const char zText[203] = {
    'B','E','G','I','N','S','E','R','T','R','U','E','L','S','E','L','E','C',
    'T','F','A','L','S','E','A','C','H','A','V','I','N','G','R','O','U','P',
    'D','A','T','E','S','C','A','P','E','X','C','E','P','T','A','L','L','I',

    'K','E','X','I','S','T','S','A','N','D','E','L','E','T','E','A','S','C',
    'E','N','D','I','N','G','L','O','B','E','T','W','E','E','N','O','T','C',
    'O','L','L','A','T','E','C','O','L','L','E','C','T','I','O','N','U','L',
    'L','I','M','I','T','C','O','M','M','I','T','C','R','E','A','T','E','D',
    'E','S','C','E','N','D','I','N','G','D','R','O','P','R','A','G','M','A',
    'F','L','A','T','T','E','N','I','F','R','O','M','I','N','T','E','R','S',
    'E','C','T','I','N','T','O','F','F','S','E','T','O','R','D','E','R','O',
    'L','L','B','A','C','K','U','N','I','O','N','V','A','L','U','E','W','H',
    'E','R','E','B','Y',
  };
  static const unsigned char aHash[80] = {
       0,  49,  47,  13,  34,  23,  48,   1,   0,   9,   0,  15,  26,
      10,  12,   0,   0,  45,   0,   8,  37,  36,  29,   0,   0,   0,
       0,  38,   0,   0,   0,  19,   0,   0,   0,  42,   0,   0,   5,
       0,   0,   0,   0,  46,   0,   0,   0,   0,   0,   0,   0,   0,
      25,  30,  41,  24,  43,  28,   0,  17,  33,  40,  20,  44,   0,
      39,   6,   0,   0,  35,   0,   0,  27,  18,   0,   0,   0,  31,
      22,  16,
  };
  static const unsigned char aNext[49] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       0,   3,   4,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,
      21,   0,   0,   0,  11,   0,   0,   0,   0,   0,   0,  14,   0,
       0,   0,   0,   7,  32,   0,   0,   0,   0,   0,
  };
  static const unsigned char aLen[49] = {
       5,   6,   4,   4,   6,   5,   4,   6,   5,   6,   6,   6,   3,
       4,   6,   2,   3,   6,   2,   3,   9,   4,   7,   3,   7,  10,
       4,   5,   6,   6,   4,  10,   2,   4,   6,   7,   2,   4,   9,
       4,   6,   3,   2,   5,   8,   5,   5,   5,   2,
  };
  static const unsigned short int aOffset[49] = {
       0,   3,   8,  11,  13,  19,  23,  26,  31,  34,  39,  44,  50,
      52,  55,  57,  61,  63,  69,  69,  69,  77,  80,  86,  89,  96,
     105, 108, 113, 119, 125, 125, 132, 135, 138, 144, 151, 152, 156,
     165, 168, 171, 174, 174, 178, 186, 191, 196, 201,
  };
  static const unsigned char aCode[49] = {
    TK_BEGIN,      TK_INSERT,     TK_TRUE,       TK_ELSE,       TK_SELECT,     
    TK_FALSE,      TK_FLATTENOP,  TK_HAVING,     TK_GROUP,      TK_UPDATE,     
    TK_ESCAPE,     TK_EXCEPT,     TK_ALL,        TK_LIKEOP,     TK_EXISTS,     
    TK_IS,         TK_AND,        TK_DELETE,     TK_AS,         TK_ASCENDING,  
    TK_ASCENDING,  TK_LIKEOP,     TK_BETWEEN,    TK_NOT,        TK_COLLATE,    
    TK_COLLECTION, TK_NULL,       TK_LIMIT,      TK_COMMIT,     TK_CREATE,     
    TK_DESCENDING, TK_DESCENDING, TK_IN,         TK_DROP,       TK_PRAGMA,     
    TK_FLATTENOP,  TK_IF,         TK_FROM,       TK_INTERSECT,  TK_INTO,       
    TK_OFFSET,     TK_SET,        TK_OR,         TK_ORDER,      TK_ROLLBACK,   
    TK_UNION,      TK_VALUE,      TK_WHERE,      TK_BY,         
  };
  int h, i;
  if( n<2 || z[0]<'A' || z[0]>'Z' ) return TK_ID;
  h = (z[0]*4 ^ z[n-1]*3 ^ n) % 80;
  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    if( aLen[i]==n && memcmp(&zText[aOffset[i]],z,n)==0 ){
      return aCode[i];
    }
  }
  return TK_ID;
}
#define XJD1_N_KEYWORD 49

/* End of the automatically generated hash code
*********************************************************************/

/*
** Return the length of the token that begins at z[0]. 
** Store the token type in *tokenType before returning.
................................................................................
    }
    case '%': {
      *tokenType = TK_REM;
      return 1;
    }
    case '=': {
      if( z[1]=='=' ){
        *tokenType = TK_EQEQ;
        return 2;
      }else{
        *tokenType = TK_EQ;
        return 1;
      }
    }
    case '<': {
      if( (c=z[1])=='=' ){
        *tokenType = TK_LE;
        return 2;

Changes to src/trace.c.

93
94
95
96
97
98
99

100
101
102
103
104
105
106
  { TK_COLLECTION,       "TK_COLLECTION"      },
  { TK_IF,               "TK_IF"              },
  { TK_EXISTS,           "TK_EXISTS"          },
  { TK_DROP,             "TK_DROP"            },
  { TK_DELETE,           "TK_DELETE"          },
  { TK_UPDATE,           "TK_UPDATE"          },
  { TK_SET,              "TK_SET"             },

  { TK_INSERT,           "TK_INSERT"          },
  { TK_INTO,             "TK_INTO"            },
  { TK_VALUE,            "TK_VALUE"           },
  { TK_PRAGMA,           "TK_PRAGMA"          },
  /* End paste of parse_txt.h */
  { TK_NOT_LIKEOP,       "TK_NOT_LIKEOP"      },
  { TK_NOT_IS,           "TK_NOT_IS"          },







>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  { TK_COLLECTION,       "TK_COLLECTION"      },
  { TK_IF,               "TK_IF"              },
  { TK_EXISTS,           "TK_EXISTS"          },
  { TK_DROP,             "TK_DROP"            },
  { TK_DELETE,           "TK_DELETE"          },
  { TK_UPDATE,           "TK_UPDATE"          },
  { TK_SET,              "TK_SET"             },
  { TK_ELSE,             "TK_ELSE"            },
  { TK_INSERT,           "TK_INSERT"          },
  { TK_INTO,             "TK_INTO"            },
  { TK_VALUE,            "TK_VALUE"           },
  { TK_PRAGMA,           "TK_PRAGMA"          },
  /* End paste of parse_txt.h */
  { TK_NOT_LIKEOP,       "TK_NOT_LIKEOP"      },
  { TK_NOT_IS,           "TK_NOT_IS"          },

Changes to src/xjd1Int.h.

295
296
297
298
299
300
301

302
303
304
305
306
307
308
      char *zName;             /* Table to delete */
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      char *zName;             /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */

    } update;
    struct {                /* Pragma */
      char *zName;             /* Pragma name */
      Expr *pValue;            /* Argument or empty string */
    } prag;
  } u;
};







>







295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
      char *zName;             /* Table to delete */
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      char *zName;             /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */
      Expr *pUpsert;           /* ELSE INSERT value */
    } update;
    struct {                /* Pragma */
      char *zName;             /* Pragma name */
      Expr *pValue;            /* Argument or empty string */
    } prag;
  } u;
};

Changes to test/base01.test.

44
45
46
47
48
49
50























DELETE FROM abc WHERE abc.name=="xyz";
SELECT FROM abc;
.result {"name":"abc"}
.testcase 161
DELETE FROM abc WHERE abc.name=="abc";
SELECT FROM abc;
.result






























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
DELETE FROM abc WHERE abc.name=="xyz";
SELECT FROM abc;
.result {"name":"abc"}
.testcase 161
DELETE FROM abc WHERE abc.name=="abc";
SELECT FROM abc;
.result


.testcase 170
CREATE COLLECTION counter;
UPDATE counter SET counter.n=counter.n+1 WHERE counter.name=="xyz";
SELECT FROM counter;
.result
.testcase 171
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:1}
.testcase 172
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}
.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}

Changes to tool/mkkeywordhash.c.

70
71
72
73
74
75
76

77
78
79
80
81
82
83
  { "COMMIT",       "TK_COMMIT",     },
  { "CREATE",       "TK_CREATE",     },
  { "DELETE",       "TK_DELETE",     },
  { "DESCENDING",   "TK_DESCENDING", },
  { "DESC",         "TK_DESCENDING", },
  { "DROP",         "TK_DROP",       },
  { "EACH",         "TK_FLATTENOP",  },

  { "ESCAPE",       "TK_ESCAPE",     },
  { "EXCEPT",       "TK_EXCEPT",     },
  { "EXISTS",       "TK_EXISTS",     },
  { "FALSE",        "TK_FALSE",      },
  { "FLATTEN",      "TK_FLATTENOP",  },
  { "FROM",         "TK_FROM",       },
  { "GLOB",         "TK_LIKEOP",     },







>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  { "COMMIT",       "TK_COMMIT",     },
  { "CREATE",       "TK_CREATE",     },
  { "DELETE",       "TK_DELETE",     },
  { "DESCENDING",   "TK_DESCENDING", },
  { "DESC",         "TK_DESCENDING", },
  { "DROP",         "TK_DROP",       },
  { "EACH",         "TK_FLATTENOP",  },
  { "ELSE",         "TK_ELSE",       },
  { "ESCAPE",       "TK_ESCAPE",     },
  { "EXCEPT",       "TK_EXCEPT",     },
  { "EXISTS",       "TK_EXISTS",     },
  { "FALSE",        "TK_FALSE",      },
  { "FLATTEN",      "TK_FLATTENOP",  },
  { "FROM",         "TK_FROM",       },
  { "GLOB",         "TK_LIKEOP",     },