UnQL

Check-in [26fd1b039d]
Login

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

Overview
Comment:Improvisations directed toward implementing the query engine.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 26fd1b039ddf39bc56594cef9997240ef762fb47
User & Date: drh 2011-06-21 20:36:27
Context
2011-06-24
19:14
Typing in more code. check-in: 9d3d2f9226 user: drh tags: trunk
2011-06-21
20:36
Improvisations directed toward implementing the query engine. check-in: 26fd1b039d user: drh tags: trunk
17:42
Fix an uninitialized structure that was causing segfaults. check-in: dc86933067 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to main.mk.

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
TCCX += -DSQLITE_THREADSAFE=0

# Object files for the SQLite library.
#
LIBOBJ+= complete.o conn.o context.o
LIBOBJ+= json.o
LIBOBJ+= memory.o
LIBOBJ+= parse.o
LIBOBJ+= query.o
LIBOBJ+= scan.o sqlite3.o stmt.o string.o
LIBOBJ+= tokenize.o trace.o

# All of the source code files.
#
SRC = \







|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
TCCX += -DSQLITE_THREADSAFE=0

# Object files for the SQLite library.
#
LIBOBJ+= complete.o conn.o context.o
LIBOBJ+= json.o
LIBOBJ+= memory.o
LIBOBJ+= parse.o pragma.o
LIBOBJ+= query.o
LIBOBJ+= scan.o sqlite3.o stmt.o string.o
LIBOBJ+= tokenize.o trace.o

# All of the source code files.
#
SRC = \

Changes to src/json.c.

149
150
151
152
153
154
155

156
157
158
159
160
161
162
163
164
165
166













167
168
169
170



171
172

173
174
175
176
177
178

179
180
181
182
183
184
185

186
187

188
189
190
191
192
193
194
...
214
215
216
217
218
219
220
221


222
223
224
225
226
227
228
229
230
231


232
233
234
235
236
237
238
239
240
241


242
243
244
245
246
247
248
...
249
250
251
252
253
254
255
256
257
258
259
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
292
293
294
...
426
427
428
429
430
431
432
433
434
435

436
437
438
439
440
441
#define JSON_EOF           24
#define JSON_ERROR         25

/* State of a JSON string tokenizer */
typedef struct JsonStr JsonStr;
struct JsonStr {
  const char *zIn;        /* Complete input string */

  int iCur;               /* First character of current token */
  int n;                  /* Number of charaters in current token */
  int eType;              /* Type of current token */
};

/* Return the type of the current token */
#define tokenType(X)  ((X)->eType)

/* Return a pointer to the string of a token. */
#define tokenString(X) (&(X)->zIn[(X)->iCur])














/* Advance to the next token */
void tokenNext(JsonStr *p){
  int i, n;
  const char *z = p->zIn;



  i = p->n + p->iCur;
  while( xjd1Isspace(z[i]) ){ i++; }

  p->iCur = i;
  switch( z[i] ){
    case 0: {
      p->n = 0;
      p->eType = JSON_EOF;
      break;

    }
    case '"': {
      char c;
      for(n=1; (c = z[i+n])!=0 && c!='"'; n++){
        if( c=='\\' ) n++;
      }
      if( c=='"' ) n++;

      p->n = n;
      p->eType = JSON_STRING;

      break;
    }
    case '{': {
      p->n = 1;
      p->eType = JSON_BEGIN_STRUCT;
      break;
    }
................................................................................
    }
    case ':': {
      p->n = 1;
      p->eType = JSON_COLON;
      break;
    }
    case 't': {
      if( memcmp(&z[i],"true",4)==0 && xjd1Isident(z[i+4])==0 ){


        p->n = 4;
        p->eType = JSON_TRUE;
      }else{
        p->n = 1;
        p->eType = JSON_ERROR;
      }
      break;
    }
    case 'f': {
      if( memcmp(&z[i],"false",5)==0 && xjd1Isident(z[i+5])==0 ){


        p->n = 5;
        p->eType = JSON_FALSE;
      }else{
        p->n = 1;
        p->eType = JSON_ERROR;
      }
      break;
    }
    case 'n': {
      if( memcmp(&z[i],"null",4)==0 && xjd1Isident(z[i+4])==0 ){


        p->n = 4;
        p->eType = JSON_NULL;
      }else{
        p->n = 1;
        p->eType = JSON_ERROR;
      }
      break;
................................................................................
    }
    case '-':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9': {
      n = 0;
      if( z[i]=='-' ){
        n = 1;
        if( !xjd1Isdigit(z[i+1]) ){
          p->n = 1;
          p->eType = JSON_ERROR;
          break;
        }
      }
      if( z[i+n]=='0' ){
        i++;
      }else{
        while( xjd1Isdigit(z[i+n]) ) n++;
      }
      if( z[i+n]=='.' && xjd1Isdigit(z[i+n+1]) ){
        n++;
        while( xjd1Isdigit(z[i+n]) ) n++;
      }
      if( (z[i+n]=='e' || z[i+n]=='E')
       && (((z[i+n+1]=='-' || z[i+n+1]=='+') && xjd1Isdigit(z[i+n+2]))
           || xjd1Isdigit(z[i+n+1]))
      ){
        n += 2;
        while( xjd1Isdigit(z[i+n]) ) n++;
      }
      p->n = n;
      p->eType = JSON_REAL;
      break;
    }
    default: {
      p->n = 1;
      p->eType = JSON_ERROR;
      break;
    }
  }






}

/* Convert the current token (which must be a string) into a true
** string (resolving all of the backslash escapes) and return a pointer
** to the true string.  Space is obtained form malloc().
*/
static char *tokenDequoteString(JsonStr *pIn){
................................................................................
  free(pNew);
  return 0;
}

/*
** Parse up a JSON string
*/
JsonNode *xjd1JsonParse(const char *zIn){
  JsonStr x;
  x.zIn = zIn;

  x.iCur = 0;
  x.n = 0;
  x.eType = 0;
  tokenNext(&x);
  return parseJson(&x);
}







>











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

|


>
>
>

|
>

|

<
<
<
>


<
|



>

<
>







 







|
>
>









|
>
>









|
>
>







 







|








|

|

|

|
<
<
<

|











>
>
>
>
>
>







 







|


>






149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193



194
195
196

197
198
199
200
201
202

203
204
205
206
207
208
209
210
...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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
292
293



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
#define JSON_EOF           24
#define JSON_ERROR         25

/* State of a JSON string tokenizer */
typedef struct JsonStr JsonStr;
struct JsonStr {
  const char *zIn;        /* Complete input string */
  int mxIn;               /* Number of characters in input string */
  int iCur;               /* First character of current token */
  int n;                  /* Number of charaters in current token */
  int eType;              /* Type of current token */
};

/* Return the type of the current token */
#define tokenType(X)  ((X)->eType)

/* Return a pointer to the string of a token. */
#define tokenString(X) (&(X)->zIn[(X)->iCur])

/* Return TRUE if z[0..n-1] is the beginning of engineering notation:
**
**      [eE](+|-)[0-9]+
*/
static int isExp(const char *z, int n){
  if( n<2 ) return 0;
  if( z[0]!='e' && z[0]!='E' ) return 0; 
  if( xjd1Isdigit(z[1]) ) return 1;
  if( n<3 || (z[1]!='-' && z[1]!='+') ) return 0;
  if( xjd1Isdigit(z[2]) ) return 1;
  return 0;
}

/* Advance to the next token */
static void tokenNext(JsonStr *p){
  int i, n;
  const char *z = p->zIn;
  int mx = p->mxIn;
  char c;

  i = p->n + p->iCur;
  while( i<mx && xjd1Isspace(z[i]) ){ i++; }
  if( i>=mx ) goto token_eof;
  p->iCur = i;
  switch( i<mx ? z[i] : 0 ){
    case 0: {



      goto token_eof;
    }
    case '"': {

     for(n=1; i+n<mx && (c = z[i+n])!=0 && c!='"'; n++){
        if( c=='\\' ) n++;
      }
      if( c=='"' ) n++;
      if( i+n>mx ){ n = mx - i; c = 0; }
      p->n = n;

      p->eType = (c=='"' ? JSON_STRING : JSON_ERROR);
      break;
    }
    case '{': {
      p->n = 1;
      p->eType = JSON_BEGIN_STRUCT;
      break;
    }
................................................................................
    }
    case ':': {
      p->n = 1;
      p->eType = JSON_COLON;
      break;
    }
    case 't': {
      if( i+4<=mx && memcmp(&z[i],"true",4)==0
       && (i+4==mx || xjd1Isident(z[i+4])==0)
      ){
        p->n = 4;
        p->eType = JSON_TRUE;
      }else{
        p->n = 1;
        p->eType = JSON_ERROR;
      }
      break;
    }
    case 'f': {
      if( i+5<=mx && memcmp(&z[i],"false",5)==0 
       && (i+5==mx || xjd1Isident(z[i+5])==0)
      ){
        p->n = 5;
        p->eType = JSON_FALSE;
      }else{
        p->n = 1;
        p->eType = JSON_ERROR;
      }
      break;
    }
    case 'n': {
      if( i+4<=mx && memcmp(&z[i],"null",4)==0
       && (i+4==mx || xjd1Isident(z[i+4])==0)
      ){
        p->n = 4;
        p->eType = JSON_NULL;
      }else{
        p->n = 1;
        p->eType = JSON_ERROR;
      }
      break;
................................................................................
    }
    case '-':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9': {
      n = 0;
      if( z[i]=='-' ){
        n = 1;
        if( i+1>=mx || !xjd1Isdigit(z[i+1]) ){
          p->n = 1;
          p->eType = JSON_ERROR;
          break;
        }
      }
      if( z[i+n]=='0' ){
        i++;
      }else{
        while( i+n<mx && xjd1Isdigit(z[i+n]) ) n++;
      }
      if( i+n+1<mx && z[i+n]=='.' && xjd1Isdigit(z[i+n+1]) ){
        n++;
        while( i+n<mx && xjd1Isdigit(z[i+n]) ) n++;
      }
      if( isExp(&z[i+n], mx-(i+n)) ){



        n += 2;
        while( i+n<mx && xjd1Isdigit(z[i+n]) ) n++;
      }
      p->n = n;
      p->eType = JSON_REAL;
      break;
    }
    default: {
      p->n = 1;
      p->eType = JSON_ERROR;
      break;
    }
  }
  return;

token_eof:
  p->n = 0;
  p->eType = JSON_EOF;
  return;
}

/* Convert the current token (which must be a string) into a true
** string (resolving all of the backslash escapes) and return a pointer
** to the true string.  Space is obtained form malloc().
*/
static char *tokenDequoteString(JsonStr *pIn){
................................................................................
  free(pNew);
  return 0;
}

/*
** Parse up a JSON string
*/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn){
  JsonStr x;
  x.zIn = zIn;
  x.mxIn = mxIn ? mxIn : xjd1Strlen30(zIn);
  x.iCur = 0;
  x.n = 0;
  x.eType = 0;
  tokenNext(&x);
  return parseJson(&x);
}

Changes to src/parse.y.

499
500
501
502
503
504
505





















  if( pNew ){
    pNew->eCmdType = TK_INSERT;
    pNew->u.ins.name = N;
    pNew->u.ins.pQuery = Q;
  }
  A = pNew;
}




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  if( pNew ){
    pNew->eCmdType = TK_INSERT;
    pNew->u.ins.name = N;
    pNew->u.ins.pQuery = Q;
  }
  A = pNew;
}

////////////////////////// The PRAGMA command /////////////////////////////////
//
%include {
  static Command *makePrag(Parse *p, Token *pName, Token *pValue){
    Command *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eCmdType = TK_PRAGMA;
      pNew->u.prag.name = *pName;
      if( pValue ){
        pNew->u.prag.jvalue = *pValue;
      }else{
        pNew->u.prag.jvalue.n = 0;
      }
    }
    return pNew;
  }
}
cmd(A) ::= PRAGMA ID(N).                  {A = makePrag(p,&N,0);}
cmd(A) ::= PRAGMA ID(N) EQ jvalue(V).     {A = makePrag(p,&N,&V);}
cmd(A) ::= PRAGMA ID(N) LP jvalue(V) RP.  {A = makePrag(p,&N,&V);}

Added src/pragma.c.

































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
** Copyright (c) 2011 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Code to evaluate a pragma.
*/
#include "xjd1Int.h"

/*
** Evaluate a pragma.
**
** Unknown pragmas are silently ignored.
*/
int xjd1PragmaStep(xjd1_stmt *pStmt){
  Command *pCmd = pStmt->pCmd;
  int rc = XJD1_OK;
  assert( pCmd!=0 );
  assert( pCmd->eCmdType==TK_PRAGMA );
  return rc;
}

Changes to src/shell.c.

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  }
  xjd1_config(pDb, XJD1_CONFIG_PARSERTRACE, parserTrace);
  isTTY = isatty(0);
  while( !feof(stdin) ){
    if( isTTY ) printf("%s", zPrompt);
    if( fgets(zLine, sizeof(zLine), stdin)==0 ) break;
    if( testJson ){
      JsonNode *pNode = xjd1JsonParse(zLine);
      if( pNode ){
        String out;
        xjd1StringInit(&out, 0, 0);
        xjd1JsonRender(&out, pNode);
        xjd1JsonFree(pNode);
        printf("%s\n", xjd1StringText(&out));
        xjd1StringClear(&out);







|







120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  }
  xjd1_config(pDb, XJD1_CONFIG_PARSERTRACE, parserTrace);
  isTTY = isatty(0);
  while( !feof(stdin) ){
    if( isTTY ) printf("%s", zPrompt);
    if( fgets(zLine, sizeof(zLine), stdin)==0 ) break;
    if( testJson ){
      JsonNode *pNode = xjd1JsonParse(zLine, -1);
      if( pNode ){
        String out;
        xjd1StringInit(&out, 0, 0);
        xjd1JsonRender(&out, pNode);
        xjd1JsonFree(pNode);
        printf("%s\n", xjd1StringText(&out));
        xjd1StringClear(&out);

Changes to src/stmt.c.

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
...
175
176
177
178
179
180
181




182
183
184
185
186
187
188
      char *zErr;
      char *zSql;
      if( pCmd->u.ins.pQuery ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, 
                 "INSERT INTO ... SELECT not yet implemented");
        break;
      }
      pNode = xjd1JsonParse(pCmd->u.ins.jvalue.z);
      if( pNode==0 ){
        xjd1Error(pStmt->pConn, XJD1_ERROR,
                  "malformed JSON");
        break;
      }
      xjd1StringInit(&json,0,0);
      xjd1JsonRender(&json, pNode);
................................................................................
      }
      sqlite3_free(zSql);
      break;
    }
    case TK_SELECT: {
      rc = xjd1QueryStep(pStmt->pCmd->u.q.pQuery);
      break;




    }
  }
  return rc;
}

/*
** Rewind a prepared statement back to the beginning.







|







 







>
>
>
>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
      char *zErr;
      char *zSql;
      if( pCmd->u.ins.pQuery ){
        xjd1Error(pStmt->pConn, XJD1_ERROR, 
                 "INSERT INTO ... SELECT not yet implemented");
        break;
      }
      pNode = xjd1JsonParse(pCmd->u.ins.jvalue.z, pCmd->u.ins.jvalue.n);
      if( pNode==0 ){
        xjd1Error(pStmt->pConn, XJD1_ERROR,
                  "malformed JSON");
        break;
      }
      xjd1StringInit(&json,0,0);
      xjd1JsonRender(&json, pNode);
................................................................................
      }
      sqlite3_free(zSql);
      break;
    }
    case TK_SELECT: {
      rc = xjd1QueryStep(pStmt->pCmd->u.q.pQuery);
      break;
    }
    case TK_PRAGMA: {
      rc = xjd1PragmaStep(pStmt);
      break;
    }
  }
  return rc;
}

/*
** Rewind a prepared statement back to the beginning.

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
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};

/**********************************************************************
** The following code is automatically generated
** by ../tool/mkkeywordhash.c
*/
/* Hash score: 52 */
static int keywordCode(const char *z, int n){
  /* zText[] encodes 273 bytes of keywords in 191 bytes */
  /*   BEGINSERTRUEACHAVINGROUPDATESCAPEXCEPTFALSELECTALLIKEXISTS         */
  /*   ASCENDINGLOBETWEENOTCOLLATECOMMITCREATEDATASETDELETEDESCENDING     */
  /*   FLATTENULLIMITIFROMINTERSECTINTOFFSETORDEROLLBACKUNIONVALUE        */
  /*   WHEREBYDROP                                                        */
  static const char zText[190] = {
    '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','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','M','M','I',
    'T','C','R','E','A','T','E','D','A','T','A','S','E','T','D','E','L','E',
    'T','E','D','E','S','C','E','N','D','I','N','G','F','L','A','T','T','E',

    'N','U','L','L','I','M','I','T','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','D','R','O','P',
  };
  static const unsigned char aHash[79] = {
       0,  44,   0,  28,  19,  15,   0,  42,   0,  12,  45,  43,   0,
       1,   0,   6,   3,  25,   7,   0,   9,   0,  40,   0,   0,   5,
      34,  31,  23,   0,   0,   0,   0,  35,   0,   0,   0,  18,   0,
       0,  26,   0,   0,  11,   0,   0,   0,   0,  41,   0,   0,   0,
       0,   0,   0,   0,   0,  22,  24,  38,  21,   4,  33,   0,   0,
      30,  37,  16,  39,   0,  36,  10,   0,   0,   0,   0,   0,  32,
      27,
  };
  static const unsigned char aNext[45] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   2,   0,   0,   0,   0,   0,  14,   0,
       0,   8,   0,   0,   0,  17,   0,   0,  13,   0,   0,   0,  29,
       0,   0,   0,  20,   0,   0,
  };
  static const unsigned char aLen[45] = {
       5,   6,   4,   4,   6,   5,   6,   6,   6,   5,   6,   3,   4,
       6,   2,   3,   9,   2,   4,   7,   3,   7,   6,   6,   7,   3,
       6,   4,  10,   2,   7,   4,   5,   2,   4,   9,   4,   6,   5,
       8,   5,   5,   5,   2,   4,
  };
  static const unsigned short int aOffset[45] = {
       0,   3,   8,  11,  14,  19,  22,  27,  32,  38,  41,  47,  49,
      52,  54,  58,  58,  58,  66,  69,  75,  78,  85,  91,  97, 101,
     104, 110, 110, 117, 120, 126, 129, 134, 135, 139, 148, 151, 157,
     161, 169, 174, 179, 184, 186,
  };
  static const unsigned char aCode[45] = {
    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_ASCENDING,  TK_ASCENDING,  TK_AS,         TK_LIKEOP,     TK_BETWEEN,    
    TK_NOT,        TK_COLLATE,    TK_COMMIT,     TK_CREATE,     TK_DATASET,    
    TK_SET,        TK_DELETE,     TK_DESCENDING, TK_DESCENDING, TK_IN,         
    TK_FLATTENOP,  TK_NULL,       TK_LIMIT,      TK_IF,         TK_FROM,       
    TK_INTERSECT,  TK_INTO,       TK_OFFSET,     TK_ORDER,      TK_ROLLBACK,   

    TK_UNION,      TK_VALUE,      TK_WHERE,      TK_BY,         TK_DROP,       
  };
  int h, i;
  if( n<2 || z[0]<'A' || z[0]>'Z' ) return TK_ID;
  h = (z[0]*4 ^ z[n-1]*3 ^ n) % 79;
  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 45

/* 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.







|

|
|
|
|
|
|



|
|
|
|
>
|
|
|
<


|
|
|
|
|
|
|

|

|
|
|

|

|
|
|

|

|
|
|

|



>
|
<
|
|
|
>
|











|







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
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};

/**********************************************************************
** The following code is automatically generated
** by ../tool/mkkeywordhash.c
*/
/* Hash score: 56 */
static int keywordCode(const char *z, int n){
  /* zText[] encodes 287 bytes of keywords in 198 bytes */
  /*   BEGINSERTRUEACHAVINGROUPDATESCAPEXCEPTFALSELECTALLIKEXISTSAND      */
  /*   ATASETASCENDINGLOBETWEENOTCOLLATECOMMITCREATEDELETEDESCENDING      */
  /*   DROPRAGMAFLATTENULLIMITIFROMINTERSECTINTOFFSETORDEROLLBACK         */
  /*   UNIONVALUEWHEREBY                                                  */
  static const char zText[197] = {
    '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','A','T','A','S','E','T','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','M','M','I','T','C','R','E','A','T','E','D','E',
    'L','E','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','U','L','L','I','M','I',
    'T','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[79] = {
       0,  48,   0,  29,  22,  15,   0,  46,   0,  12,  32,  47,   0,
       1,   0,   6,   3,  17,   7,   0,   9,   0,  44,   0,   0,   5,
      37,  34,  26,   0,   0,   0,   0,  38,   0,   0,   0,  19,   0,
       0,  18,   0,   0,  11,   0,   0,   0,   0,  45,   0,   0,   0,
       0,   0,   0,   0,   0,  25,  27,  41,  24,  42,  36,   0,  16,
      31,  40,  20,  43,   0,  39,  10,   0,  33,   0,   0,   0,  35,
      28,
  };
  static const unsigned char aNext[48] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,  14,   0,   0,   0,   0,   2,   0,   0,   0,   0,
       0,   0,   8,   0,   0,   0,   0,   0,  21,   0,   0,  13,   0,
       0,   0,   4,  30,   0,   0,   0,  23,   0,
  };
  static const unsigned char aLen[48] = {
       5,   6,   4,   4,   6,   5,   6,   6,   6,   5,   6,   3,   4,
       6,   2,   3,   7,   3,   2,   3,   9,   4,   7,   3,   7,   6,
       6,   6,   4,  10,   2,   4,   6,   7,   4,   5,   2,   4,   9,
       4,   6,   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,  64,  67,  67,  67,  75,  78,  84,  87,  94,
     100, 106, 112, 112, 119, 122, 125, 131, 137, 140, 145, 146, 150,
     159, 162, 168, 168, 172, 180, 185, 190, 195,
  };
  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_DATASET,    TK_SET,        TK_AS,         TK_ASCENDING,  
    TK_ASCENDING,  TK_LIKEOP,     TK_BETWEEN,    TK_NOT,        TK_COLLATE,    

    TK_COMMIT,     TK_CREATE,     TK_DELETE,     TK_DESCENDING, TK_DESCENDING, 
    TK_IN,         TK_DROP,       TK_PRAGMA,     TK_FLATTENOP,  TK_NULL,       
    TK_LIMIT,      TK_IF,         TK_FROM,       TK_INTERSECT,  TK_INTO,       
    TK_OFFSET,     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) % 79;
  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.

Changes to src/trace.c.

169
170
171
172
173
174
175











176
177
178
179
180
181
182
      xjd1TraceExprList(pOut, indent+3, pCmd->u.update.pChng);
      if( pCmd->u.update.pWhere ){
         xjd1StringAppendF(pOut, "%*s WHERE ", indent, "");
         xjd1TraceExpr(pOut, pCmd->u.update.pWhere);
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 











    }
    default: {
      xjd1StringAppendF(pOut, "%*seCmdType = %s (%d)\n",
          indent, "", xjd1TokenName(pCmd->eCmdType), pCmd->eCmdType);
      break;
    }
  }







>
>
>
>
>
>
>
>
>
>
>







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
      xjd1TraceExprList(pOut, indent+3, pCmd->u.update.pChng);
      if( pCmd->u.update.pWhere ){
         xjd1StringAppendF(pOut, "%*s WHERE ", indent, "");
         xjd1TraceExpr(pOut, pCmd->u.update.pWhere);
         xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    case TK_PRAGMA: {
      xjd1StringAppendF(pOut, "%*sPRAGMA: %.*s",
         indent, "", pCmd->u.prag.name.n, pCmd->u.prag.name.z);
      if( pCmd->u.prag.jvalue.n>0 ){
        xjd1StringAppendF(pOut,"(%.*s)\n",
           pCmd->u.prag.jvalue.n, pCmd->u.prag.jvalue.z);
      }else{
        xjd1StringAppend(pOut, "\n", 1);
      }
      break; 
    }
    default: {
      xjd1StringAppendF(pOut, "%*seCmdType = %s (%d)\n",
          indent, "", xjd1TokenName(pCmd->eCmdType), pCmd->eCmdType);
      break;
    }
  }

Changes to src/xjd1Int.h.

45
46
47
48
49
50
51

52
53
54
55
56
57
58
...
102
103
104
105
106
107
108

109
110
111
112
113
114
115
...
155
156
157
158
159
160
161

162
163
164
165
166
167
168
...
178
179
180
181
182
183
184


185
186
187
188
189
190
191

192
193
194
195
196
197
198
199
200
201
202







203
204
205
206
207
208
209
...
225
226
227
228
229
230
231




232
233
234
235
236
237
238
...
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
typedef struct Command Command;
typedef struct DataSrc DataSrc;
typedef struct Expr Expr;
typedef struct ExprItem ExprItem;
typedef struct ExprList ExprList;
typedef struct JsonNode JsonNode;
typedef struct JsonStructElem JsonStructElem;

typedef struct Parse Parse;
typedef struct PoolChunk PoolChunk;
typedef struct Pool Pool;
typedef struct Query Query;
typedef struct String String;
typedef struct Token Token;

................................................................................
  xjd1 *pConn;                      /* Database connection */
  xjd1_stmt *pNext, *pPrev;         /* List of all statements */
  Pool sPool;                       /* Memory pool used for parsing */
  int nRef;                         /* Reference count */
  u8 isDying;                       /* True if has been closed */
  char *zCode;                      /* Text of the query */
  Command *pCmd;                    /* Parsed command */

  char *zErrMsg;                    /* Error message */
};

/* A token into to the parser */
struct Token {
  const char *z;                    /* Text of the token */
  int n;                            /* Number of characters */
................................................................................
  String errMsg;                  /* Error message string */
};

/* A query statement */
struct Query {
  int eQType;                   /* Query type */
  xjd1_stmt *pStmt;             /* Statement this query is part of */

  union {
    struct {                    /* For compound queries */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
    } compound;
    struct {                    /* For simple queries */
      ExprList *pCol;             /* List of result columns */
................................................................................
};

/* A Data Source is a representation of a term out of the FROM clause. */
struct DataSrc {
  int eDSType;              /* Source type */
  Token asId;               /* The identifier after the AS keyword */
  Query *pQuery;            /* Query this data source services */


  union {
    struct {                /* For a join.  eDSType==TK_COMMA */
      DataSrc *pLeft;          /* Data source on the left */
      DataSrc *pRight;         /* Data source on the right */
    } join;
    struct {                /* For a named table.  eDSType==TK_ID */
      Token name;              /* The table name */

    } tab;
    struct {                /* EACH() or FLATTEN().  eDSType==TK_FLATTENOP */
      DataSrc *pNext;          /* Data source to the left */
      Token opName;            /* "EACH" or "FLATTEN" */
      ExprList *pList;         /* List of arguments */
    } flatten;
    struct {                /* A subquery.  eDSType==TK_SELECT */
      Query *q;                /* The subquery */
    } subq;
  } u;
};








/* Any command, including but not limited to a query */
struct Command {
  int eCmdType;             /* Type of command */
  union {
    struct {                /* Transaction control operations */
      Token id;                /* Transaction name */
................................................................................
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      Token name;              /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */
    } update;




  } u;
};

/* A single element of a JSON structure */
struct JsonStructElem {
  char *zLabel;             /* Label on this element */
  JsonStructElem *pNext;    /* Next element of the structure */
................................................................................
void xjd1ContextUnref(xjd1_context*);

/******************************** conn.c *************************************/
void xjd1Unref(xjd1*);
void xjd1Error(xjd1*,int,const char*,...);

/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn);
void xjd1JsonRender(String*, JsonNode*);
void xjd1JsonFree(JsonNode*);

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




/******************************** query.c ************************************/
int xjd1QueryInit(xjd1_stmt*,Query*);
int xjd1QueryRewind(Query*);
int xjd1QueryStep(Query*);
int xjd1QueryClose(Query*);








>







 







>







 







>







 







>
>







>











>
>
>
>
>
>
>







 







>
>
>
>







 







|










>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
typedef struct Command Command;
typedef struct DataSrc DataSrc;
typedef struct Expr Expr;
typedef struct ExprItem ExprItem;
typedef struct ExprList ExprList;
typedef struct JsonNode JsonNode;
typedef struct JsonStructElem JsonStructElem;
typedef struct Line Line;
typedef struct Parse Parse;
typedef struct PoolChunk PoolChunk;
typedef struct Pool Pool;
typedef struct Query Query;
typedef struct String String;
typedef struct Token Token;

................................................................................
  xjd1 *pConn;                      /* Database connection */
  xjd1_stmt *pNext, *pPrev;         /* List of all statements */
  Pool sPool;                       /* Memory pool used for parsing */
  int nRef;                         /* Reference count */
  u8 isDying;                       /* True if has been closed */
  char *zCode;                      /* Text of the query */
  Command *pCmd;                    /* Parsed command */
  Line *pLine;                      /* Active lines */
  char *zErrMsg;                    /* Error message */
};

/* A token into to the parser */
struct Token {
  const char *z;                    /* Text of the token */
  int n;                            /* Number of characters */
................................................................................
  String errMsg;                  /* Error message string */
};

/* A query statement */
struct Query {
  int eQType;                   /* Query type */
  xjd1_stmt *pStmt;             /* Statement this query is part of */
  Query *pOuter;                /* Next outer query for a subquery */
  union {
    struct {                    /* For compound queries */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
    } compound;
    struct {                    /* For simple queries */
      ExprList *pCol;             /* List of result columns */
................................................................................
};

/* A Data Source is a representation of a term out of the FROM clause. */
struct DataSrc {
  int eDSType;              /* Source type */
  Token asId;               /* The identifier after the AS keyword */
  Query *pQuery;            /* Query this data source services */
  Line *pOut;               /* Where output of this source is stored */
  int isOwner;              /* True if this DataSrc owns the pOut line */
  union {
    struct {                /* For a join.  eDSType==TK_COMMA */
      DataSrc *pLeft;          /* Data source on the left */
      DataSrc *pRight;         /* Data source on the right */
    } join;
    struct {                /* For a named table.  eDSType==TK_ID */
      Token name;              /* The table name */
      sqlite3_stmt *pStmt;     /* Cursor for reading content */
    } tab;
    struct {                /* EACH() or FLATTEN().  eDSType==TK_FLATTENOP */
      DataSrc *pNext;          /* Data source to the left */
      Token opName;            /* "EACH" or "FLATTEN" */
      ExprList *pList;         /* List of arguments */
    } flatten;
    struct {                /* A subquery.  eDSType==TK_SELECT */
      Query *q;                /* The subquery */
    } subq;
  } u;
};

/* A line is analogous to a row in an SQL database */
struct Line {
  Line *pNext;              /* Next line in a list */
  Token name;               /* Name of this line */
  JsonNode *pValue;         /* JSON associated with this line */
};

/* Any command, including but not limited to a query */
struct Command {
  int eCmdType;             /* Type of command */
  union {
    struct {                /* Transaction control operations */
      Token id;                /* Transaction name */
................................................................................
      Expr *pWhere;            /* WHERE clause */
    } del;
    struct {                /* Update */
      Token name;              /* Table to modify */
      Expr *pWhere;            /* WHERE clause */
      ExprList *pChng;         /* Alternating lvalve and new value */
    } update;
    struct {                /* Pragma */
      Token name;              /* Pragma name */
      Token jvalue;            /* Argument or empty string */
    } prag;
  } u;
};

/* A single element of a JSON structure */
struct JsonStructElem {
  char *zLabel;             /* Label on this element */
  JsonStructElem *pNext;    /* Next element of the structure */
................................................................................
void xjd1ContextUnref(xjd1_context*);

/******************************** conn.c *************************************/
void xjd1Unref(xjd1*);
void xjd1Error(xjd1*,int,const char*,...);

/******************************** json.c *************************************/
JsonNode *xjd1JsonParse(const char *zIn, int mxIn);
void xjd1JsonRender(String*, JsonNode*);
void xjd1JsonFree(JsonNode*);

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

/******************************** pragma.c ***********************************/
int xjd1PragmaStep(xjd1_stmt*);

/******************************** query.c ************************************/
int xjd1QueryInit(xjd1_stmt*,Query*);
int xjd1QueryRewind(Query*);
int xjd1QueryStep(Query*);
int xjd1QueryClose(Query*);

Changes to tool/mkkeywordhash.c.

53
54
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
92
93
94
95
96
97
98
99
100
101
102
103
104



105
106
107
108
109
110
111
  char zOrigName[20];  /* Original keyword name before processing */
};
 
/*
** These are the keywords
*/
static Keyword aKeywordTable[] = {
  { "NOT",          "TK_NOT",       },
  { "IS",           "TK_IS",        },
  { "LIKE",         "TK_LIKEOP",    },
  { "GLOB",         "TK_LIKEOP",    },
  { "BETWEEN",      "TK_BETWEEN",   },
  { "IN",           "TK_IN",        },
  { "ESCAPE",       "TK_ESCAPE",    },
  { "COLLATE",      "TK_COLLATE",   },
  { "TRUE",         "TK_TRUE",      },
  { "FALSE",        "TK_FALSE",     },
  { "NULL",         "TK_NULL",      },
  { "UNION",        "TK_UNION",     },
  { "EXCEPT",       "TK_EXCEPT",    },
  { "INTERSECT",    "TK_INTERSECT", },
  { "ALL",          "TK_ALL",       },
  { "SELECT",       "TK_SELECT",    },
  { "AS",           "TK_AS",        },
  { "FROM",         "TK_FROM",      },
  { "EACH",         "TK_FLATTENOP", },
  { "FLATTEN",      "TK_FLATTENOP", },
  { "GROUP",        "TK_GROUP",     },
  { "BY",           "TK_BY",        },
  { "HAVING",       "TK_HAVING",    },
  { "ORDER",        "TK_ORDER",     },
  { "ASCENDING",    "TK_ASCENDING", },
  { "ASC",          "TK_ASCENDING", },
  { "DESCENDING",   "TK_DESCENDING", },
  { "DESC",         "TK_DESCENDING", },
  { "LIMIT",        "TK_LIMIT",     },
  { "OFFSET",       "TK_OFFSET",    },
  { "WHERE",        "TK_WHERE",     },
  { "BEGIN",        "TK_BEGIN",     },
  { "ROLLBACK",     "TK_ROLLBACK",  },
  { "COMMIT",       "TK_COMMIT",    },
  { "CREATE",       "TK_CREATE",    },
  { "DATASET",      "TK_DATASET",   },
  { "IF",           "TK_IF",        },
  { "EXISTS",       "TK_EXISTS",    },
  { "DROP",         "TK_DROP",      },
  { "DELETE",       "TK_DELETE",    },
  { "UPDATE",       "TK_UPDATE",    },
  { "SET",          "TK_SET",       },
  { "INSERT",       "TK_INSERT",    },
  { "INTO",         "TK_INTO",      },
  { "VALUE",        "TK_VALUE",     },



};

/* Number of keywords */
static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));

/*
** Comparision function for two Keyword records







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







53
54
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  char zOrigName[20];  /* Original keyword name before processing */
};
 
/*
** These are the keywords
*/
static Keyword aKeywordTable[] = {
  { "ALL",          "TK_ALL",        },
  { "AND",          "TK_AND",        },
  { "ASCENDING",    "TK_ASCENDING",  },
  { "ASC",          "TK_ASCENDING",  },
  { "AS",           "TK_AS",         },
  { "BEGIN",        "TK_BEGIN",      },
  { "BETWEEN",      "TK_BETWEEN",    },
  { "BY",           "TK_BY",         },
  { "COLLATE",      "TK_COLLATE",    },
  { "COMMIT",       "TK_COMMIT",     },
  { "CREATE",       "TK_CREATE",     },
  { "DATASET",      "TK_DATASET",    },
  { "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",     },
  { "GROUP",        "TK_GROUP",      },
  { "HAVING",       "TK_HAVING",     },
  { "IF",           "TK_IF",         },
  { "INSERT",       "TK_INSERT",     },
  { "INTERSECT",    "TK_INTERSECT",  },
  { "IN",           "TK_IN",         },
  { "INTO",         "TK_INTO",       },
  { "IS",           "TK_IS",         },
  { "LIKE",         "TK_LIKEOP",     },
  { "LIMIT",        "TK_LIMIT",      },
  { "NOT",          "TK_NOT",        },
  { "NULL",         "TK_NULL",       },
  { "OFFSET",       "TK_OFFSET",     },
  { "ORDER",        "TK_ORDER",      },
  { "OR",           "TK_OR",         },
  { "PRAGMA",       "TK_PRAGMA",     },
  { "ROLLBACK",     "TK_ROLLBACK",   },
  { "SELECT",       "TK_SELECT",     },
  { "SET",          "TK_SET",        },
  { "TRUE",         "TK_TRUE",       },
  { "UNION",        "TK_UNION",      },
  { "UPDATE",       "TK_UPDATE",     },
  { "VALUE",        "TK_VALUE",      },
  { "WHERE",        "TK_WHERE",      },
};

/* Number of keywords */
static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));

/*
** Comparision function for two Keyword records