UnQL

Check-in [8c6e6a4ed7]
Login

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

Overview
Comment:Add support for joins.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8c6e6a4ed7b6aa3582c7e38c1ced9ee286b905f3
User & Date: drh 2011-07-16 20:00:10
Context
2011-07-18
09:39
Fix handling of "AS" in FROM clauses. check-in: e7c27a9690 user: dan tags: trunk
2011-07-16
20:00
Add support for joins. check-in: 8c6e6a4ed7 user: drh tags: trunk
19:42
Fix compiler warnings. Remove an unused declaration. check-in: dba083d964 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/datasrc.c.

53
54
55
56
57
58
59












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




102
103
104
105
106
107
108
...
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
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the step results in a row of content being available.
*/
int xjd1DataSrcStep(DataSrc *p){
  int rc= XJD1_DONE;
  if( p==0 ) return XJD1_DONE;
  switch( p->eDSType ){












    case TK_ID: {
      rc = sqlite3_step(p->u.tab.pStmt);
      xjd1JsonFree(p->pValue);
      p->pValue = 0;
      if( rc==SQLITE_ROW ){
        const char *zJson = (const char*)sqlite3_column_text(p->u.tab.pStmt, 0);
        p->pValue = xjd1JsonParse(zJson, -1);
................................................................................
    return xjd1JsonRef(p->pValue);
  }
  switch( p->eDSType ){
    case TK_COMMA: {
      pRes = xjd1DataSrcDoc(p->u.join.pLeft, zDocName);
      if( pRes==0 ) pRes = xjd1DataSrcDoc(p->u.join.pRight, zDocName);
      break;




    }
    case TK_ID: {
      if( zDocName==0 || strcmp(p->u.tab.zName, zDocName)==0 ){
        pRes = xjd1JsonRef(p->pValue);
      }
      break;
    }
................................................................................
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the rewind results in a row of content being available.
*/
int xjd1DataSrcRewind(DataSrc *p){
  if( p==0 ) return XJD1_DONE;
  xjd1JsonFree(p->pValue);  p->pValue = 0;
  switch( p->eDSType ){









    case TK_ID: {
      sqlite3_reset(p->u.tab.pStmt);
      return xjd1DataSrcStep(p);
    }
    case TK_NULL: {
      p->u.null.isDone = 0;
      return xjd1DataSrcStep(p);
    }
  }
  return XJD1_DONE;
}

/*
** Return true if the data source is at the end of file
*/
int xjd1DataSrcEOF(DataSrc *p){
  return 1;
}

/*
** The destructor for a Query object.
*/
int xjd1DataSrcClose(DataSrc *p){
  if( p==0 ) return XJD1_OK;
  xjd1JsonFree(p->pValue);  p->pValue = 0;
  switch( p->eDSType ){







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







 







>
>
>
>







 







>
>
>
>
>
>
>
>
>












<
<
<
<
<
<
<







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
...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
...
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
167
168
169
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the step results in a row of content being available.
*/
int xjd1DataSrcStep(DataSrc *p){
  int rc= XJD1_DONE;
  if( p==0 ) return XJD1_DONE;
  switch( p->eDSType ){
    case TK_COMMA: {
      rc = xjd1DataSrcStep(p->u.join.pRight);
      if( rc==XJD1_DONE ){
        xjd1DataSrcRewind(p->u.join.pRight);
        rc = xjd1DataSrcStep(p->u.join.pLeft);
      }
      break;
    }
    case TK_SELECT: {
      rc = xjd1QueryStep(p->u.subq.q);
      break;
    }
    case TK_ID: {
      rc = sqlite3_step(p->u.tab.pStmt);
      xjd1JsonFree(p->pValue);
      p->pValue = 0;
      if( rc==SQLITE_ROW ){
        const char *zJson = (const char*)sqlite3_column_text(p->u.tab.pStmt, 0);
        p->pValue = xjd1JsonParse(zJson, -1);
................................................................................
    return xjd1JsonRef(p->pValue);
  }
  switch( p->eDSType ){
    case TK_COMMA: {
      pRes = xjd1DataSrcDoc(p->u.join.pLeft, zDocName);
      if( pRes==0 ) pRes = xjd1DataSrcDoc(p->u.join.pRight, zDocName);
      break;
    }
    case TK_SELECT: {
      pRes = xjd1QueryDoc(p->u.subq.q, zDocName);
      break;
    }
    case TK_ID: {
      if( zDocName==0 || strcmp(p->u.tab.zName, zDocName)==0 ){
        pRes = xjd1JsonRef(p->pValue);
      }
      break;
    }
................................................................................
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the rewind results in a row of content being available.
*/
int xjd1DataSrcRewind(DataSrc *p){
  if( p==0 ) return XJD1_DONE;
  xjd1JsonFree(p->pValue);  p->pValue = 0;
  switch( p->eDSType ){
    case TK_COMMA: {
      xjd1DataSrcRewind(p->u.join.pLeft);
      xjd1DataSrcRewind(p->u.join.pRight);
      break;
    }
    case TK_SELECT: {
      xjd1QueryRewind(p->u.subq.q);
      break;
    }
    case TK_ID: {
      sqlite3_reset(p->u.tab.pStmt);
      return xjd1DataSrcStep(p);
    }
    case TK_NULL: {
      p->u.null.isDone = 0;
      return xjd1DataSrcStep(p);
    }
  }
  return XJD1_DONE;
}








/*
** The destructor for a Query object.
*/
int xjd1DataSrcClose(DataSrc *p){
  if( p==0 ) return XJD1_OK;
  xjd1JsonFree(p->pValue);  p->pValue = 0;
  switch( p->eDSType ){

Changes to src/query.c.

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
...
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
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;
  if( p->eQType==TK_SELECT ){
    xjd1DataSrcRewind(p->u.simple.pFrom);
  }else{
    xjd1QueryRewind(p->u.compound.pLeft);
    p->u.compound.doneLeft = xjd1QueryEOF(p->u.compound.pLeft);
    xjd1QueryRewind(p->u.compound.pRight);
  }
  return XJD1_OK;
}

/*
** Advance a query to the next row.  Return XDJ1_DONE if there is no
................................................................................
      pOut = xjd1QueryDoc(p->pOuter, zDocName);
    }
  }
  return pOut;
}


/* Return true if there are no more rows available on this query */
int xjd1QueryEOF(Query *p){
  int rc;
  if( p->eQType==TK_SELECT ){
    rc = xjd1DataSrcEOF(p->u.simple.pFrom);
  }else{
    rc = 0;
    if( !p->u.compound.doneLeft ){
      rc = xjd1QueryEOF(p->u.compound.pLeft);
      if( rc ) p->u.compound.doneLeft = 1;
    }
    if( p->u.compound.doneLeft ){
      rc = xjd1QueryEOF(p->u.compound.pRight);
    }
  }
  return rc;
}

/*
** The destructor for a Query object.
*/
int xjd1QueryClose(Query *pQuery){
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;
  if( pQuery->eQType==TK_SELECT ){







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
...
108
109
110
111
112
113
114


















115
116
117
118
119
120
121
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;
  if( p->eQType==TK_SELECT ){
    xjd1DataSrcRewind(p->u.simple.pFrom);
  }else{
    xjd1QueryRewind(p->u.compound.pLeft);
    p->u.compound.doneLeft = 0;
    xjd1QueryRewind(p->u.compound.pRight);
  }
  return XJD1_OK;
}

/*
** Advance a query to the next row.  Return XDJ1_DONE if there is no
................................................................................
      pOut = xjd1QueryDoc(p->pOuter, zDocName);
    }
  }
  return pOut;
}




















/*
** The destructor for a Query object.
*/
int xjd1QueryClose(Query *pQuery){
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;
  if( pQuery->eQType==TK_SELECT ){

Changes to src/xjd1Int.h.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/* Marker for routines not intended for external use */
#define PRIVATE

/* Additional tokens above and beyond those generated by the parser and
** found in parse.h 
*/
#define TK_NOT_LIKEOP        (TK_LIKEOP+128)
#define TK_NOT_IS            (TK_IS+128)
#define TK_FUNCTION          100
#define TK_SPACE             101
#define TK_ILLEGAL           102
#define TK_CREATECOLLECTION  103
#define TK_DROPCOLLECTION    104
#define TK_ARRAY             105
#define TK_STRUCT            106
................................................................................
void xjd1Unref(xjd1*);
void xjd1Error(xjd1*,int,const char*,...);

/******************************** datasrc.c **********************************/
int xjd1DataSrcInit(DataSrc*,Query*);
int xjd1DataSrcRewind(DataSrc*);
int xjd1DataSrcStep(DataSrc*);
int xjd1DataSrcEOF(DataSrc*);
int xjd1DataSrcClose(DataSrc*);
JsonNode *xjd1DataSrcDoc(DataSrc*, const char*);

/******************************** delete.c ***********************************/
int xjd1DeleteStep(xjd1_stmt*);

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

/******************************** query.c ************************************/
int xjd1QueryInit(Query*,xjd1_stmt*,Query*);
int xjd1QueryRewind(Query*);
int xjd1QueryStep(Query*);
int xjd1QueryEOF(Query*);
int xjd1QueryClose(Query*);
JsonNode *xjd1QueryDoc(Query*, const char*);

/******************************** stmt.c *************************************/
JsonNode *xjd1StmtDoc(xjd1_stmt*, const char*);

/******************************** string.c ***********************************/







<







 







<







 







<







30
31
32
33
34
35
36

37
38
39
40
41
42
43
...
324
325
326
327
328
329
330

331
332
333
334
335
336
337
...
366
367
368
369
370
371
372

373
374
375
376
377
378
379
/* Marker for routines not intended for external use */
#define PRIVATE

/* Additional tokens above and beyond those generated by the parser and
** found in parse.h 
*/
#define TK_NOT_LIKEOP        (TK_LIKEOP+128)

#define TK_FUNCTION          100
#define TK_SPACE             101
#define TK_ILLEGAL           102
#define TK_CREATECOLLECTION  103
#define TK_DROPCOLLECTION    104
#define TK_ARRAY             105
#define TK_STRUCT            106
................................................................................
void xjd1Unref(xjd1*);
void xjd1Error(xjd1*,int,const char*,...);

/******************************** datasrc.c **********************************/
int xjd1DataSrcInit(DataSrc*,Query*);
int xjd1DataSrcRewind(DataSrc*);
int xjd1DataSrcStep(DataSrc*);

int xjd1DataSrcClose(DataSrc*);
JsonNode *xjd1DataSrcDoc(DataSrc*, const char*);

/******************************** delete.c ***********************************/
int xjd1DeleteStep(xjd1_stmt*);

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

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

int xjd1QueryClose(Query*);
JsonNode *xjd1QueryDoc(Query*, const char*);

/******************************** stmt.c *************************************/
JsonNode *xjd1StmtDoc(xjd1_stmt*, const char*);

/******************************** string.c ***********************************/

Changes to test/base01.test.

12
13
14
15
16
17
18




19
20
21
22
23
24
25
SELECT FROM abc;
.result {"name":"abc"}

.testcase 120
SELECT FROM def;
.result {"name":"def"}





.testcase 130
SELECT { p:1, q:2 } FROM abc;
.result {"p":1,"q":2}
.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132







>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
SELECT FROM abc;
.result {"name":"abc"}

.testcase 120
SELECT FROM def;
.result {"name":"def"}

.testcase 125
SELECT FROM abc UNION ALL SELECT FROM def;
.result {"name":"abc"} {"name":"def"}

.testcase 130
SELECT { p:1, q:2 } FROM abc;
.result {"p":1,"q":2}
.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132

Added test/base04.test.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- Basic sanity checking.
--
.new t1.db
.testcase 100
CREATE COLLECTION c1;
INSERT INTO c1 VALUE {a:1, b:"one"};
INSERT INTO c1 VALUE {a:2, b:"two"};
CREATE COLLECTION c2;
INSERT INTO c2 VALUE {a:1, c:"once"};
INSERT INTO c2 VALUE {a:2, c:"twice"};
INSERT INTO c2 VALUE {a:3, c:"thrice"};

SELECT {a:c1.a, b:c1.b, c:c2.c} 
  FROM c1, c2
 WHERE c1.a==c2.a;
.result {"a":1,"b":"one","c":"once"} {"a":2,"b":"two","c":"twice"}