UnQL

Check-in [a6fb845b35]
Login

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

Overview
Comment:Add a scalar length() function to return the length of strings. In preparation for adding aggregation.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a6fb845b358dbe9ed20b69f88b431914e72fd04f
User & Date: dan 2011-07-19 19:31:48
Context
2011-07-20
14:13
Improve error handling. check-in: f19d31ea5d user: dan tags: trunk
2011-07-19
19:31
Add a scalar length() function to return the length of strings. In preparation for adding aggregation. check-in: a6fb845b35 user: dan tags: trunk
17:59
Add support for OFFSET and LIMIT on simple SELECT statements. check-in: 885cc57b2c user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to main.mk.

30
31
32
33
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48

# This is how we compile
#
TCCX =  $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP)
TCCX += -DSQLITE_OMIT_LOAD_EXTENSION
TCCX += -DSQLITE_THREADSAFE=0

# Object files for the SQLite library.
#
LIBOBJ+= complete.o conn.o context.o
LIBOBJ+= datasrc.o delete.o
LIBOBJ+= expr.o

LIBOBJ+= json.o
LIBOBJ+= memory.o
LIBOBJ+= parse.o pragma.o
LIBOBJ+= query.o
LIBOBJ+= sqlite3.o stmt.o string.o
LIBOBJ+= tokenize.o trace.o
LIBOBJ+= update.o







|




>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# This is how we compile
#
TCCX =  $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP)
TCCX += -DSQLITE_OMIT_LOAD_EXTENSION
TCCX += -DSQLITE_THREADSAFE=0

# Object files for the XJD1 library.
#
LIBOBJ+= complete.o conn.o context.o
LIBOBJ+= datasrc.o delete.o
LIBOBJ+= expr.o
LIBOBJ+= func.o
LIBOBJ+= json.o
LIBOBJ+= memory.o
LIBOBJ+= parse.o pragma.o
LIBOBJ+= query.o
LIBOBJ+= sqlite3.o stmt.o string.o
LIBOBJ+= tokenize.o trace.o
LIBOBJ+= update.o

Changes to src/expr.c.

107
108
109
110
111
112
113

114
115

116








117
118
119
120
121
122
123
...
477
478
479
480
481
482
483





484
485
486
487
488
489
490
** Callback for query expressions
*/
static int walkInitCallback(Expr *p, WalkAction *pAction){
  int rc = XJD1_OK;
  assert( p );
  p->pStmt = pAction->pStmt;
  p->pQuery = pAction->pQuery;

  if( p->eClass==XJD1_EXPR_Q ){
    rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery);

  }








  return rc;
}


/*
** Initialize an expression in preparation for evaluation of a
** statement.
................................................................................
        pRes = pJLeft;
      }else{
        xjd1JsonFree(pJLeft);
        pRes = xjd1ExprEval(p->u.bi.pRight);
      }
      return pRes;
    }





  }


  pRes = xjd1JsonNew(0);
  if( pRes==0 ) return 0;
  pRes->eJType = XJD1_NULL;
  switch( p->eType ){







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







 







>
>
>
>
>







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
...
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
** Callback for query expressions
*/
static int walkInitCallback(Expr *p, WalkAction *pAction){
  int rc = XJD1_OK;
  assert( p );
  p->pStmt = pAction->pStmt;
  p->pQuery = pAction->pQuery;
  switch( p->eClass ){
    case XJD1_EXPR_Q:
      rc = xjd1QueryInit(p->u.subq.p, pAction->pStmt, pAction->pQuery);
      break;

    case XJD1_EXPR_FUNC:
      rc = xjd1FunctionInit(p, pAction->pStmt);
      break;

    default:
      break;
  }
  
  return rc;
}


/*
** Initialize an expression in preparation for evaluation of a
** statement.
................................................................................
        pRes = pJLeft;
      }else{
        xjd1JsonFree(pJLeft);
        pRes = xjd1ExprEval(p->u.bi.pRight);
      }
      return pRes;
    }

    case TK_FUNCTION: {
      pRes = xjd1FunctionEval(p);
      return pRes;
    }
  }


  pRes = xjd1JsonNew(0);
  if( pRes==0 ) return 0;
  pRes->eJType = XJD1_NULL;
  switch( p->eType ){

Added src/func.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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
/*
** 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/
**
*************************************************************************
*/
#include "xjd1Int.h"

struct Function {
  int nArg;
  const char *zName;
  JsonNode *(*xFunc)(int nArg, JsonNode **apArg);
};

#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))

/*
** Implementation of "length(x)".
*/
static JsonNode *xLength(int nArg, JsonNode **apArg){
  JsonNode *pRet;
  JsonNode *pStr;
  int nRet;
  assert( nArg==1 );

  pStr = apArg[0];
  if( pStr->eJType==XJD1_STRING ){
    nRet = xjd1Strlen30(pStr->u.z);
  }else{
    String str;

    xjd1StringInit(&str, 0, 0);
    xjd1JsonToString(pStr, &str);
    nRet = str.nUsed;
    xjd1StringClear(&str);
  }

  pRet = xjd1JsonNew(0);
  pRet->eJType = XJD1_REAL;
  pRet->u.r = (double)nRet;

  return pRet;
}

int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt){
  char *zName;
  int nArg;
  int nByte;
  int i;

  static Function aFunc[] = {
    { 1, "length", xLength },
  };

  zName = p->u.func.zFName;
  nArg = p->u.func.args->nEItem;

  for(i=0; i<ArraySize(aFunc); i++){
    Function *pFunc = &aFunc[i];
    if( strcmp(pFunc->zName, zName)==0 && nArg==pFunc->nArg ){
      p->u.func.pFunction = pFunc;
      break;
    }
  }

  if( !p->u.func.pFunction ){
    return XJD1_ERROR;
  }

  nByte = sizeof(JsonNode *) * nArg;
  p->u.func.apArg = (JsonNode **)xjd1PoolMallocZero(&pStmt->sPool, nByte);
  if( !p->u.func.apArg ){
    return XJD1_NOMEM;
  }

  return XJD1_OK;
}


JsonNode *xjd1FunctionEval(Expr *p){
  Function *pFunc = p->u.func.pFunction;
  int i;
  int nItem = p->u.func.args->nEItem;
  JsonNode *pRet;

  for(i=0; i<nItem; i++){
    p->u.func.apArg[i] = xjd1ExprEval(p->u.func.args->apEItem[i].pExpr);
  }

  pRet = pFunc->xFunc(nItem, p->u.func.apArg);
  for(i=0; i<nItem; i++){
    xjd1JsonFree(p->u.func.apArg[i]);
  }

  return pRet;
}

Changes to src/query.c.

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
170
171
172
}

/*
** Called after statement parsing to initalize every Query object
** within the statement.
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){

  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery);
    xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);
    xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery);
    xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery);
    xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery);
    xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery);
  }else{
    xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter);
    xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter);
  }
  return XJD1_OK;
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;







>




|
|
|
|
|
|
|
|

|
|

|







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
170
171
172
173
}

/*
** Called after statement parsing to initalize every Query object
** within the statement.
*/
int xjd1QueryInit(Query *pQuery, xjd1_stmt *pStmt, Query *pOuter){
  int rc;
  if( pQuery==0 ) return XJD1_OK;
  pQuery->pStmt = pStmt;
  pQuery->pOuter = pOuter;
  if( pQuery->eQType==TK_SELECT ){
    rc = xjd1ExprInit(pQuery->u.simple.pRes, pStmt, pQuery);
    if( !rc ) rc = xjd1DataSrcInit(pQuery->u.simple.pFrom, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pWhere, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pGroupBy, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pHaving, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprListInit(pQuery->u.simple.pOrderBy, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pLimit, pStmt, pQuery);
    if( !rc ) rc = xjd1ExprInit(pQuery->u.simple.pOffset, pStmt, pQuery);
  }else{
    rc = xjd1QueryInit(pQuery->u.compound.pLeft, pStmt, pOuter);
    if( !rc ) rc = xjd1QueryInit(pQuery->u.compound.pRight, pStmt, pOuter);
  }
  return rc;
}

/*
** Rewind a query so that it is pointing at the first row.
*/
int xjd1QueryRewind(Query *p){
  if( p==0 ) return XJD1_OK;

Changes to src/stmt.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
..
58
59
60
61
62
63
64






65
66
67
68
69
70
71
  p->zCode = xjd1PoolDup(&p->sPool, zStmt, -1);
  if( pN==0 ) pN = &dummy;
  rc = xjd1RunParser(pConn, p, p->zCode, pN);
  pCmd = p->pCmd;
  if( pCmd ){
    switch( pCmd->eCmdType ){
      case TK_SELECT: {
        xjd1QueryInit(pCmd->u.q.pQuery, p, 0);
        break;
      }
      case TK_INSERT: {
        xjd1QueryInit(pCmd->u.ins.pQuery, p, 0);
        break;
      }
      case TK_DELETE: {
................................................................................
        xjd1ExprInit(pCmd->u.update.pWhere, p, 0);
        xjd1ExprListInit(pCmd->u.update.pChng, p, 0);
        xjd1ExprInit(pCmd->u.update.pUpsert, p, 0);
        break;
      }
    }
  }






  return rc;
}

/*
** Configure a prepared statement.
*/
int xdj1_stmt_config(xjd1_stmt *pStmt, int op, ...){







|







 







>
>
>
>
>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
..
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  p->zCode = xjd1PoolDup(&p->sPool, zStmt, -1);
  if( pN==0 ) pN = &dummy;
  rc = xjd1RunParser(pConn, p, p->zCode, pN);
  pCmd = p->pCmd;
  if( pCmd ){
    switch( pCmd->eCmdType ){
      case TK_SELECT: {
        rc = xjd1QueryInit(pCmd->u.q.pQuery, p, 0);
        break;
      }
      case TK_INSERT: {
        xjd1QueryInit(pCmd->u.ins.pQuery, p, 0);
        break;
      }
      case TK_DELETE: {
................................................................................
        xjd1ExprInit(pCmd->u.update.pWhere, p, 0);
        xjd1ExprListInit(pCmd->u.update.pChng, p, 0);
        xjd1ExprInit(pCmd->u.update.pUpsert, p, 0);
        break;
      }
    }
  }

  if( rc!=XJD1_OK ){
    xjd1Error(pConn, rc, "");
    xjd1_stmt_delete(p);
    *ppNew = 0;
  }
  return rc;
}

/*
** Configure a prepared statement.
*/
int xdj1_stmt_config(xjd1_stmt *pStmt, int op, ...){

Changes to src/xjd1Int.h.

46
47
48
49
50
51
52

53
54
55
56
57
58
59
...
152
153
154
155
156
157
158
159


160
161
162
163
164
165
166
...
423
424
425
426
427
428
429




430
431
typedef unsigned char u8;
typedef unsigned short int u16;
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;
................................................................................
      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;
    struct {                /* Literal value.  eClass=EXPR_JSON */
      JsonNode *p;             /* The value */
    } json;
................................................................................
void xjd1TraceDataSrc(String*,int,const DataSrc*);
void xjd1TraceExpr(String*,const Expr*);
void xjd1TraceExprList(String*,int, const ExprList*);

/******************************** update.c ***********************************/
int xjd1UpdateStep(xjd1_stmt*);






#endif /* _XJD1INT_H */







>







 







|
>
>







 







>
>
>
>


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
426
427
428
429
430
431
432
433
434
435
436
437
438
typedef unsigned char u8;
typedef unsigned short int u16;
typedef struct Command Command;
typedef struct DataSrc DataSrc;
typedef struct Expr Expr;
typedef struct ExprItem ExprItem;
typedef struct ExprList ExprList;
typedef struct Function Function;
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;
................................................................................
      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 arguments */
      Function *pFunction;     /* Function object */
      JsonNode **apArg;        /* Array to martial function arguments in */
    } func;
    struct {                /* Subqueries.  eClass=EXPR_Q */
      Query *p;                /* The subquery */
    } subq;
    struct {                /* Literal value.  eClass=EXPR_JSON */
      JsonNode *p;             /* The value */
    } json;
................................................................................
void xjd1TraceDataSrc(String*,int,const DataSrc*);
void xjd1TraceExpr(String*,const Expr*);
void xjd1TraceExprList(String*,int, const ExprList*);

/******************************** update.c ***********************************/
int xjd1UpdateStep(xjd1_stmt*);

/******************************** func.c *************************************/
int xjd1FunctionInit(Expr *p, xjd1_stmt *pStmt);
void xjd1FunctionClose(Expr *p);
JsonNode *xjd1FunctionEval(Expr *p);

#endif /* _XJD1INT_H */

Changes to test/base05.test.

48
49
50
51
52
53
54
55







56







.testcase 7
SELECT c1.i FROM c1 ORDER BY c1 ASC LIMIT 3 OFFSET 3;
.result 4 5 6

.testcase 8
SELECT c1.i FROM c1 LIMIT 3 OFFSET 3;
.result 15 17 3
























>
>
>
>
>
>
>

>
>
>
>
>
>
>
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
.testcase 7
SELECT c1.i FROM c1 ORDER BY c1 ASC LIMIT 3 OFFSET 3;
.result 4 5 6

.testcase 8
SELECT c1.i FROM c1 LIMIT 3 OFFSET 3;
.result 15 17 3

.testcase 9
SELECT length("hello world");
SELECT length(11);
SELECT length(true);
SELECT length(false);
SELECT length(null);
.result 11 2 4 5 4

-- .testcase 10
-- SELECT xyz("hello world");
-- .result ERROR