UnQL

Check-in [ce30690c86]
Login

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

Overview
Comment:Document references within expressions now working.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ce30690c8604baa00ccc2982ec1fa262d4587522
User & Date: drh 2011-06-29 20:10:02
Context
2011-06-29
23:08
Basic WHERE clauses working on simple SELECT statements. check-in: 0f90d3efaf user: drh tags: trunk
20:10
Document references within expressions now working. check-in: ce30690c86 user: drh tags: trunk
19:02
Change the parse tree to use zero-terminated strings rather than Token objects. check-in: 365b149fa1 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/datasrc.c.

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
      break;
    }
  }
  return rc;
}

/*
** Return the value after the most recent Step.  The returned JsonNode
** is managed by the DataSrc object will be freed by the next call to
** DataSrcStep(), DataSrcRewind(), or DataSrcClose().



*/
JsonNode *xjd1DataSrcValue(DataSrc *p){
  JsonNode *pOut = 0;
  if( p==0 ) return 0;



  switch( p->eDSType ){





    case TK_ID: {
      pOut = p->pValue;







      break;
    }
  }
  return pOut;
}

/*
** Rewind a data source so that it is pointing at the first row.
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the rewind results in a row of content being available.
*/







|
|
|
>
>
>

|
|

>
>
>

>
>
>
>
>

<
>
>
>
>
>
>
>



|







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
      break;
    }
  }
  return rc;
}

/*
** Return the document that this data source if the document if the AS
** name of the document is zDocName or if zDocName==0.  The AS name is
** important since a join might have multiple documents.
**
** xjd1JsonRef() has been called on the returned string.  The caller
** must invoke xjd1JsonFree().
*/
JsonNode *xjd1DataSrcDoc(DataSrc *p, const char *zDocName){
  JsonNode *pRes = 0;
  if( p==0 ) return 0;
  if( zDocName && p->zAs && strcmp(p->zAs, zDocName) ){
    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;
    }
    default: {
      pRes = xjd1JsonRef(p->pValue);
      break;
    }
  }
  return pRes;
}

/*
** Rewind a data source so that it is pointing at the first row.
** Return XJD1_DONE if the data source is empty and XJD1_ROW if
** the rewind results in a row of content being available.
*/

Changes to src/expr.c.

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
** Initialize an expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xQueryAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  return walkExpr(p, &sAction);
}

/*
** Initialize a list of expression in preparation for evaluation of a
................................................................................
      if( pRes==0 ) pRes = nullJson();
      return pRes;
    }
    case TK_LB: {
      return nullJson();   /* TBD */
    }
    case TK_ID: {
      return 0;
    }
  }
  pRes = xjd1JsonNew(0);
  if( pRes==0 ) return 0;
  pRes->eJType = XJD1_NULL;
  switch( p->eType ){
    case TK_STRUCT: {







|







 







|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
** Initialize an expression in preparation for evaluation of a
** statement.
*/
int xjd1ExprInit(Expr *p, xjd1_stmt *pStmt, Query *pQuery){
  WalkAction sAction;
  memset(&sAction, 0, sizeof(sAction));
  sAction.xNodeAction = walkInitCallback;
  sAction.pStmt = pStmt;
  sAction.pQuery = pQuery;
  return walkExpr(p, &sAction);
}

/*
** Initialize a list of expression in preparation for evaluation of a
................................................................................
      if( pRes==0 ) pRes = nullJson();
      return pRes;
    }
    case TK_LB: {
      return nullJson();   /* TBD */
    }
    case TK_ID: {
      return xjd1StmtDoc(p->pStmt, p->u.id.zId);
    }
  }
  pRes = xjd1JsonNew(0);
  if( pRes==0 ) return 0;
  pRes->eJType = XJD1_NULL;
  switch( p->eType ){
    case TK_STRUCT: {

Changes to src/parse.y.

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
%include {
  /* Generate an Expr object from an identifer token */
  static Expr *idExpr(Parse *p, Token *pTok){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_ID;
      pNew->eClass = XJD1_EXPR_TK;
      pNew->u.tk.zId = tokenStr(p, pTok);
    }
    return pNew;
  }

  /* Generate an Expr object that is a binary operator on two
  ** other Expr objects. */
  static Expr *biExpr(Parse *p, Expr *pLeft, int eOp, Expr *pRight){







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
%include {
  /* Generate an Expr object from an identifer token */
  static Expr *idExpr(Parse *p, Token *pTok){
    Expr *pNew = xjd1PoolMallocZero(p->pPool, sizeof(*pNew));
    if( pNew ){
      pNew->eType = TK_ID;
      pNew->eClass = XJD1_EXPR_TK;
      pNew->u.id.zId = tokenStr(p, pTok);
    }
    return pNew;
  }

  /* Generate an Expr object that is a binary operator on two
  ** other Expr objects. */
  static Expr *biExpr(Parse *p, Expr *pLeft, int eOp, Expr *pRight){

Changes to src/query.c.

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
..
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
...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;
  if( p->pOut ){
    xjd1JsonFree(p->pOut);
    p->pOut = 0;
  }
  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);
  }
................................................................................
/*
** Advance a query to the next row.  Return XDJ1_DONE if there is no
** next row, or XJD1_ROW if the step was successful.
*/
int xjd1QueryStep(Query *p){
  int rc;
  if( p==0 ) return XJD1_DONE;
  if( p->pOut ){
    xjd1JsonFree(p->pOut);
    p->pOut = 0;
  }
  if( p->eQType==TK_SELECT ){
    do{
      rc = xjd1DataSrcStep(p->u.simple.pFrom);
    }while(
         rc==XJD1_ROW
      && (p->u.simple.pWhere!=0 && !xjd1ExprTrue(p->u.simple.pWhere))
    );
................................................................................
      rc = xjd1QueryStep(p->u.compound.pRight);
    }
  }
  return rc;
}

/*
** Return the value from the most recent query step.  

**
** The pointer returned is managed by the query.  It will be freed
** by the next call to QueryStep(), QueryReset(), or QueryClose().
*/
JsonNode *xjd1QueryValue(Query *p){
  JsonNode *pOut = 0;
  if( p ){
    if( p->pOut ){ xjd1JsonFree(p->pOut); p->pOut = 0; }
    if( p->eQType==TK_SELECT ){
      if(  p->u.simple.pRes ){
        pOut = p->pOut = xjd1ExprEval(p->u.simple.pRes);
      }else{
        pOut = xjd1DataSrcValue(p->u.simple.pFrom);
      }
    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryValue(p->u.compound.pLeft);
    }else{
      pOut = xjd1QueryValue(p->u.compound.pRight);
    }
  }
  return pOut;
}


/* Return true if there are no more rows available on this query */
................................................................................

/*
** The destructor for a Query object.
*/
int xjd1QueryClose(Query *pQuery){
  int rc = XJD1_OK;
  if( pQuery==0 ) return rc;
  if( pQuery->pOut ){
    xjd1JsonFree(pQuery->pOut);
    pQuery->pOut = 0;
  }
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprClose(pQuery->u.simple.pRes);
    xjd1DataSrcClose(pQuery->u.simple.pFrom);
    xjd1ExprClose(pQuery->u.simple.pWhere);
    xjd1ExprListClose(pQuery->u.simple.pGroupBy);
    xjd1ExprClose(pQuery->u.simple.pHaving);
    xjd1ExprListClose(pQuery->u.simple.pOrderBy);







<
<
<
<







 







<
<
<
<







 







|
>

<
|

|


<

|
|

|


|

|







 







<
<
<
<







43
44
45
46
47
48
49




50
51
52
53
54
55
56
..
60
61
62
63
64
65
66




67
68
69
70
71
72
73
..
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
...
129
130
131
132
133
134
135




136
137
138
139
140
141
142
}

/*
** Rewind a query so that it is pointing at the first row.
*/
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);
  }
................................................................................
/*
** Advance a query to the next row.  Return XDJ1_DONE if there is no
** next row, or XJD1_ROW if the step was successful.
*/
int xjd1QueryStep(Query *p){
  int rc;
  if( p==0 ) return XJD1_DONE;




  if( p->eQType==TK_SELECT ){
    do{
      rc = xjd1DataSrcStep(p->u.simple.pFrom);
    }while(
         rc==XJD1_ROW
      && (p->u.simple.pWhere!=0 && !xjd1ExprTrue(p->u.simple.pWhere))
    );
................................................................................
      rc = xjd1QueryStep(p->u.compound.pRight);
    }
  }
  return rc;
}

/*
** Return a document currently referenced by a query.  If zDocName==0 then
** return the constructed result set of the query.
**

** The caller must invoke JsonFree() when it is done with this value.
*/
JsonNode *xjd1QueryDoc(Query *p, const char *zDocName){
  JsonNode *pOut = 0;
  if( p ){

    if( p->eQType==TK_SELECT ){
      if( zDocName==0 && p->u.simple.pRes ){
        pOut = xjd1ExprEval(p->u.simple.pRes);
      }else{
        pOut = xjd1DataSrcDoc(p->u.simple.pFrom, zDocName);
      }
    }else if( !p->u.compound.doneLeft ){
      pOut = xjd1QueryDoc(p->u.compound.pLeft, zDocName);
    }else{
      pOut = xjd1QueryDoc(p->u.compound.pRight, zDocName);
    }
  }
  return pOut;
}


/* Return true if there are no more rows available on this query */
................................................................................

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




  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprClose(pQuery->u.simple.pRes);
    xjd1DataSrcClose(pQuery->u.simple.pFrom);
    xjd1ExprClose(pQuery->u.simple.pWhere);
    xjd1ExprListClose(pQuery->u.simple.pGroupBy);
    xjd1ExprClose(pQuery->u.simple.pHaving);
    xjd1ExprListClose(pQuery->u.simple.pOrderBy);

Changes to src/stmt.c.

174
175
176
177
178
179
180

181

182
183
184
185
186
187
188
...
234
235
236
237
238
239
240





















      break;
    }
    case TK_SELECT: {
      Query *pQuery = pCmd->u.q.pQuery;
      rc = xjd1QueryStep(pQuery);
      xjd1StringClear(&pStmt->retValue);
      if( rc==XJD1_ROW ){

        xjd1JsonRender(&pStmt->retValue, xjd1QueryValue(pQuery));

        pStmt->okValue = 1;
      }else{
        pStmt->okValue = 0;
      }
      break;
    }
    case TK_PRAGMA: {
................................................................................
*/
char *xjd1_stmt_debug_listing(xjd1_stmt *p){
  String x;
  xjd1StringInit(&x, 0, 0);
  xjd1TraceCommand(&x, 0, p->pCmd);
  return x.zBuf;
}




























>
|
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
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
      break;
    }
    case TK_SELECT: {
      Query *pQuery = pCmd->u.q.pQuery;
      rc = xjd1QueryStep(pQuery);
      xjd1StringClear(&pStmt->retValue);
      if( rc==XJD1_ROW ){
        JsonNode *pValue = xjd1QueryDoc(pQuery, 0);
        xjd1JsonRender(&pStmt->retValue, pValue);
        xjd1JsonFree(pValue);
        pStmt->okValue = 1;
      }else{
        pStmt->okValue = 0;
      }
      break;
    }
    case TK_PRAGMA: {
................................................................................
*/
char *xjd1_stmt_debug_listing(xjd1_stmt *p){
  String x;
  xjd1StringInit(&x, 0, 0);
  xjd1TraceCommand(&x, 0, p->pCmd);
  return x.zBuf;
}

/*
** Return the current value for a particular document in the given
** statement.
**
** The caller is responsible for invoking xjd1JsonFree() on the result.
*/
JsonNode *xjd1StmtDoc(xjd1_stmt *pStmt, const char *zDocName){
  Command *pCmd;
  JsonNode *pRes = 0;
  if( pStmt==0 ) return 0;
  pCmd = pStmt->pCmd;
  if( pCmd==0 ) return 0;
  switch( pCmd->eCmdType ){
    case TK_SELECT: {
      pRes = xjd1QueryDoc(pCmd->u.q.pQuery, zDocName);
      break;
    }
  }
  return pRes;
}

Changes to src/xjd1Int.h.

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
...
352
353
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
    } bi;
    struct {                /* Substructure nam.  eClass==EXPR_LVALUE */
      Expr *pLeft;             /* Lvalue or id to the left */
      char *zId;               /* ID to the right */
    } lvalue;
    struct {                /* Identifiers */
      char *zId;               /* token value.  eClass=EXPR_TK */
    } tk;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* Name of the function */
      ExprList *args;          /* List of argumnts */
    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
................................................................................
};

/* 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 */
  JsonNode *pOut;               /* Output expression */
  union {
    struct {                    /* For compound queries */
      Query *pLeft;               /* Left subquery */
      Query *pRight;              /* Righ subquery */
      int doneLeft;               /* True if left is run to completion */
    } compound;
    struct {                    /* For simple queries */
................................................................................

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

/******************************** expr.c *************************************/
int xjd1ExprInit(Expr*, xjd1_stmt*, Query*);
int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*);
JsonNode *xjd1ExprEval(Expr*);
int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
................................................................................

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

/******************************** stmt.c *************************************/


/******************************** string.c ***********************************/
int xjd1Strlen30(const char *);
void xjd1StringInit(String*, Pool*, int);
String *xjd1StringNew(Pool*, int);
int xjd1StringAppend(String*, const char*, int);
#define xjd1StringText(S)      ((S)->zBuf)







|







 







<







 







|







 







|


>







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
220
221
222
223
224
225
226

227
228
229
230
231
232
233
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
    } bi;
    struct {                /* Substructure nam.  eClass==EXPR_LVALUE */
      Expr *pLeft;             /* Lvalue or id to the left */
      char *zId;               /* ID to the right */
    } lvalue;
    struct {                /* Identifiers */
      char *zId;               /* token value.  eClass=EXPR_TK */
    } id;
    struct {                /* Function calls.  eClass=EXPR_FUNC */
      char *zFName;            /* Name of the function */
      ExprList *args;          /* List of argumnts */
    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
................................................................................
};

/* 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 */
      int doneLeft;               /* True if left is run to completion */
    } compound;
    struct {                    /* For simple queries */
................................................................................

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

/******************************** expr.c *************************************/
int xjd1ExprInit(Expr*, xjd1_stmt*, Query*);
int xjd1ExprListInit(ExprList*, xjd1_stmt*, Query*);
JsonNode *xjd1ExprEval(Expr*);
int xjd1ExprTrue(Expr*);
int xjd1ExprClose(Expr*);
................................................................................

/******************************** 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 ***********************************/
int xjd1Strlen30(const char *);
void xjd1StringInit(String*, Pool*, int);
String *xjd1StringNew(Pool*, int);
int xjd1StringAppend(String*, const char*, int);
#define xjd1StringText(S)      ((S)->zBuf)

Changes to test/base01.test.

21
22
23
24
25
26
27





.result {"p":1,"q":2}
.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132
SELECT {p:1, q:{x:[1,2,3],y:11}} FROM abc;
.result {"p":1,"q":{"x":[1,2,3],"y":11}}












>
>
>
>
>
21
22
23
24
25
26
27
28
29
30
31
32
.result {"p":1,"q":2}
.testcase 131
SELECT {p:1, q:2+3} FROM abc;
.result {"p":1,"q":5}
.testcase 132
SELECT {p:1, q:{x:[1,2,3],y:11}} FROM abc;
.result {"p":1,"q":{"x":[1,2,3],"y":11}}

.breakpoint
.testcase 140
SELECT { x:abc.name, y:10 } FROM abc;
.result {"x":"abc","y":10}