/ Check-in [233b3338]
Login

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

Overview
Comment:Add a prototype intarray($PTR,$N) table valued function.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | prototype-int-array
Files: files | file ages | folders
SHA1: 233b33382dc70de45f90b6dfdb5785f20b21489e
User & Date: drh 2016-06-29 05:00:30
Context
2016-06-29
05:08
Another test case for the intarray($PTR,$N) virtual table. check-in: 06e1fab7 user: drh tags: prototype-int-array
05:00
Add a prototype intarray($PTR,$N) table valued function. check-in: 233b3338 user: drh tags: prototype-int-array
2016-06-26
04:06
Prevent the WhereLoop.rSetup cost estimate from going negative on complex queries. check-in: f8105085 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to Makefile.in.

412
413
414
415
416
417
418

419
420
421
422
423
424
425
  $(TOP)/ext/session/test_session.c \
  $(TOP)/ext/rbu/test_rbu.c 

# Statically linked extensions
#
TESTSRC += \
  $(TOP)/ext/misc/amatch.c \

  $(TOP)/ext/misc/closure.c \
  $(TOP)/ext/misc/csv.c \
  $(TOP)/ext/misc/eval.c \
  $(TOP)/ext/misc/fileio.c \
  $(TOP)/ext/misc/fuzzer.c \
  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \







>







412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  $(TOP)/ext/session/test_session.c \
  $(TOP)/ext/rbu/test_rbu.c 

# Statically linked extensions
#
TESTSRC += \
  $(TOP)/ext/misc/amatch.c \
  $(TOP)/ext/misc/array.c \
  $(TOP)/ext/misc/closure.c \
  $(TOP)/ext/misc/csv.c \
  $(TOP)/ext/misc/eval.c \
  $(TOP)/ext/misc/fileio.c \
  $(TOP)/ext/misc/fuzzer.c \
  $(TOP)/ext/fts5/fts5_tcl.c \
  $(TOP)/ext/fts5/fts5_test_mi.c \

Added ext/misc/array.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
211
212
213
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
295
296
/*
** 2016-06-29
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file demonstrates how to create a table-valued-function that
** returns the values in a C-language array.
** Examples:
**
**      SELECT * FROM intarray($ptr,5)
**
** The query above returns 5 integers contained in a C-language array
** at the address $ptr.  $ptr is a pointer to the array of integers that
** has been cast to an integer.
**
** HOW IT WORKS
**
** The intarray "function" is really a virtual table with the
** following schema:
**
**     CREATE FUNCTION intarray(
**       value,
**       pointer HIDDEN,
**       count HIDDEN
**     );
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>

#ifndef SQLITE_OMIT_VIRTUALTABLE


/* intarray_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
** over rows of the result
*/
typedef struct intarray_cursor intarray_cursor;
struct intarray_cursor {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  int isDesc;                /* True to count down rather than up */
  sqlite3_int64 iRowid;      /* The rowid */
  sqlite3_int64 iPtr;        /* Pointer to array of integers */
  sqlite3_int64 iCnt;        /* Number of integers in the array */
};

/*
** The intarrayConnect() method is invoked to create a new
** intarray_vtab that describes the intarray virtual table.
**
** Think of this routine as the constructor for intarray_vtab objects.
**
** All this routine needs to do is:
**
**    (1) Allocate the intarray_vtab object and initialize all fields.
**
**    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
**        result set of queries against intarray will look like.
*/
static int intarrayConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  sqlite3_vtab *pNew;
  int rc;

/* Column numbers */
#define INTARRAY_COLUMN_VALUE   0
#define INTARRAY_COLUMN_POINTER 1
#define INTARRAY_COLUMN_COUNT   2

  rc = sqlite3_declare_vtab(db,
     "CREATE TABLE x(value,pointer hidden,count hidden)");
  if( rc==SQLITE_OK ){
    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
    if( pNew==0 ) return SQLITE_NOMEM;
    memset(pNew, 0, sizeof(*pNew));
  }
  return rc;
}

/*
** This method is the destructor for intarray_cursor objects.
*/
static int intarrayDisconnect(sqlite3_vtab *pVtab){
  sqlite3_free(pVtab);
  return SQLITE_OK;
}

/*
** Constructor for a new intarray_cursor object.
*/
static int intarrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
  intarray_cursor *pCur;
  pCur = sqlite3_malloc( sizeof(*pCur) );
  if( pCur==0 ) return SQLITE_NOMEM;
  memset(pCur, 0, sizeof(*pCur));
  *ppCursor = &pCur->base;
  return SQLITE_OK;
}

/*
** Destructor for a intarray_cursor.
*/
static int intarrayClose(sqlite3_vtab_cursor *cur){
  sqlite3_free(cur);
  return SQLITE_OK;
}


/*
** Advance a intarray_cursor to its next row of output.
*/
static int intarrayNext(sqlite3_vtab_cursor *cur){
  intarray_cursor *pCur = (intarray_cursor*)cur;
  pCur->iRowid++;
  return SQLITE_OK;
}

/*
** Return values of columns for the row at which the intarray_cursor
** is currently pointing.
*/
static int intarrayColumn(
  sqlite3_vtab_cursor *cur,   /* The cursor */
  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
  int i                       /* Which column to return */
){
  intarray_cursor *pCur = (intarray_cursor*)cur;
  sqlite3_int64 x = 0;
  switch( i ){
    case INTARRAY_COLUMN_POINTER:   x = pCur->iPtr;   break;
    case INTARRAY_COLUMN_COUNT:     x = pCur->iCnt;   break;
    default: {
      int *p = (int*)pCur->iPtr;
      x = (int)p[pCur->iRowid-1];
      break;
    }
  }
  sqlite3_result_int64(ctx, x);
  return SQLITE_OK;
}

/*
** Return the rowid for the current row.  In this implementation, the
** rowid is the same as the output value.
*/
static int intarrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  intarray_cursor *pCur = (intarray_cursor*)cur;
  *pRowid = pCur->iRowid;
  return SQLITE_OK;
}

/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int intarrayEof(sqlite3_vtab_cursor *cur){
  intarray_cursor *pCur = (intarray_cursor*)cur;
  return pCur->iRowid>=pCur->iCnt;
}

/*
** This method is called to "rewind" the intarray_cursor object back
** to the first row of output.
*/
static int intarrayFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  intarray_cursor *pCur = (intarray_cursor *)pVtabCursor;
  int i = 0;
  if( idxNum ){
    pCur->iPtr = sqlite3_value_int64(argv[0]);
    pCur->iCnt = sqlite3_value_int64(argv[1]);
  }else{
    pCur->iPtr = 0;
    pCur->iCnt = 0;
  }
  pCur->iRowid = 1;
  return SQLITE_OK;
}

/*
** SQLite will invoke this method one or more times while planning a query
** that uses the intarray virtual table.  This routine needs to create
** a query plan for each invocation and compute an estimated cost for that
** plan.
**
** In this implementation idxNum is used to represent the
** query plan.  idxStr is unused.
**
** idxNum is 1 if the pointer= and count= constraints exist and is 0 otherwise.
** If idxNum is 0, then intarray becomes an empty table.
*/
static int intarrayBestIndex(
  sqlite3_vtab *tab,
  sqlite3_index_info *pIdxInfo
){
  int i;                 /* Loop over constraints */
  int idxNum = 0;        /* The query plan bitmask */
  int ptrIdx = -1;       /* Index of the pointer= constraint, or -1 if none */
  int cntIdx = -1;       /* Index of the count= constraint, or -1 if none */
  int nArg = 0;          /* Number of arguments that intarrayFilter() expects */

  const struct sqlite3_index_constraint *pConstraint;
  pConstraint = pIdxInfo->aConstraint;
  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    if( pConstraint->usable==0 ) continue;
    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
    switch( pConstraint->iColumn ){
      case INTARRAY_COLUMN_POINTER:
        ptrIdx = i;
        break;
      case INTARRAY_COLUMN_COUNT:
        cntIdx = i;
        break;
    }
  }
  if( ptrIdx>=0 && cntIdx>=0 ){
    pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
    pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
    pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
    pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
    pIdxInfo->estimatedCost = (double)1;
    pIdxInfo->estimatedRows = (double)100;
    pIdxInfo->idxNum = 1;
  }else{
    pIdxInfo->estimatedCost = (double)2147483647;
    pIdxInfo->estimatedRows = (double)2147483647;
    pIdxInfo->idxNum = 0;
  }
  return SQLITE_OK;
}

/*
** This following structure defines all the methods for the 
** intarray virtual table.
*/
static sqlite3_module intarrayModule = {
  0,                         /* iVersion */
  0,                         /* xCreate */
  intarrayConnect,           /* xConnect */
  intarrayBestIndex,         /* xBestIndex */
  intarrayDisconnect,        /* xDisconnect */
  0,                         /* xDestroy */
  intarrayOpen,              /* xOpen - open a cursor */
  intarrayClose,             /* xClose - close a cursor */
  intarrayFilter,            /* xFilter - configure scan constraints */
  intarrayNext,              /* xNext - advance a cursor */
  intarrayEof,               /* xEof - check for end of scan */
  intarrayColumn,            /* xColumn - read data */
  intarrayRowid,             /* xRowid - read data */
  0,                         /* xUpdate */
  0,                         /* xBegin */
  0,                         /* xSync */
  0,                         /* xCommit */
  0,                         /* xRollback */
  0,                         /* xFindMethod */
  0,                         /* xRename */
};

#endif /* SQLITE_OMIT_VIRTUALTABLE */

#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_array_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( sqlite3_libversion_number()<3008012 ){
    *pzErrMsg = sqlite3_mprintf(
        "intarray() requires SQLite 3.8.12 or later");
    return SQLITE_ERROR;
  }
  rc = sqlite3_create_module(db, "intarray", &intarrayModule, 0);
#endif
  return rc;
}

Changes to src/test1.c.

3236
3237
3238
3239
3240
3241
3242








































3243
3244
3245
3246
3247
3248
3249
....
6579
6580
6581
6582
6583
6584
6585

6586
6587
6588
6589
6590
6591
6592
....
6597
6598
6599
6600
6601
6602
6603

6604
6605
6606
6607
6608
6609
6610
....
7092
7093
7094
7095
7096
7097
7098

7099
7100
7101
7102
7103
7104
7105
  if( rc!=SQLITE_OK ){
    return TCL_ERROR;
  }

  return TCL_OK;
}










































/*
** Usage:   sqlite3_bind_int64  STMT N VALUE
**
** Test the sqlite3_bind_int64 interface.  STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement.  This command
** binds a 64-bit integer VALUE to that wildcard.
................................................................................
static int tclLoadStaticExtensionCmd(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);

  extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
................................................................................
  extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  static const struct {
    const char *zExtName;
    int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
  } aExtension[] = {
    { "amatch",                sqlite3_amatch_init               },

    { "closure",               sqlite3_closure_init              },
    { "csv",                   sqlite3_csv_init                  },
    { "eval",                  sqlite3_eval_init                 },
    { "fileio",                sqlite3_fileio_init               },
    { "fuzzer",                sqlite3_fuzzer_init               },
    { "ieee754",               sqlite3_ieee_init                 },
    { "nextchar",              sqlite3_nextchar_init             },
................................................................................
     void *clientData;
  } aObjCmd[] = {
     { "sqlite3_db_config",             test_sqlite3_db_config, 0 },
     { "bad_behavior",                  test_bad_behavior,  (void*)&iZero },
     { "register_dbstat_vtab",          test_register_dbstat_vtab  },
     { "sqlite3_connection_pointer",    get_sqlite_pointer, 0 },
     { "sqlite3_bind_int",              test_bind_int,      0 },

     { "sqlite3_bind_zeroblob",         test_bind_zeroblob, 0 },
     { "sqlite3_bind_zeroblob64",       test_bind_zeroblob64, 0 },
     { "sqlite3_bind_int64",            test_bind_int64,    0 },
     { "sqlite3_bind_double",           test_bind_double,   0 },
     { "sqlite3_bind_null",             test_bind_null     ,0 },
     { "sqlite3_bind_text",             test_bind_text     ,0 },
     { "sqlite3_bind_text16",           test_bind_text16   ,0 },







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







 







>







 







>







 







>







3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
....
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
....
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
....
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
  if( rc!=SQLITE_OK ){
    return TCL_ERROR;
  }

  return TCL_OK;
}


/*
** Usage:   sqlite3_bind_intarray  STMT N INT  ...
**
** Create a C-language array of integers from the arguments.  Bind a pointer
** to this array to the NAME parameter of STMT.
*/
static int test_bind_intarray(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int idx;
  int i;
  static int *p = 0;

  sqlite3_free(p);
  p = 0;
  if( objc<4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), " STMT NAME INT...", 0);
    return TCL_ERROR;
  }

  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
  p = sqlite3_malloc( sizeof(int)*(objc-3) );
  if( p==0 ) return TCL_ERROR;
  for(i=0; i<objc-3; i++){
    if( Tcl_GetIntFromObj(interp, objv[3+i], &p[i]) ){
      sqlite3_free(p);
      return TCL_ERROR;
    }
  }  
  sqlite3_bind_int64(pStmt, idx, (sqlite3_int64)p);
  return TCL_OK;
}


/*
** Usage:   sqlite3_bind_int64  STMT N VALUE
**
** Test the sqlite3_bind_int64 interface.  STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement.  This command
** binds a 64-bit integer VALUE to that wildcard.
................................................................................
static int tclLoadStaticExtensionCmd(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_array_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
................................................................................
  extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
  extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
  static const struct {
    const char *zExtName;
    int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
  } aExtension[] = {
    { "amatch",                sqlite3_amatch_init               },
    { "array",                 sqlite3_array_init                },
    { "closure",               sqlite3_closure_init              },
    { "csv",                   sqlite3_csv_init                  },
    { "eval",                  sqlite3_eval_init                 },
    { "fileio",                sqlite3_fileio_init               },
    { "fuzzer",                sqlite3_fuzzer_init               },
    { "ieee754",               sqlite3_ieee_init                 },
    { "nextchar",              sqlite3_nextchar_init             },
................................................................................
     void *clientData;
  } aObjCmd[] = {
     { "sqlite3_db_config",             test_sqlite3_db_config, 0 },
     { "bad_behavior",                  test_bad_behavior,  (void*)&iZero },
     { "register_dbstat_vtab",          test_register_dbstat_vtab  },
     { "sqlite3_connection_pointer",    get_sqlite_pointer, 0 },
     { "sqlite3_bind_int",              test_bind_int,      0 },
     { "sqlite3_bind_intarray",         test_bind_intarray, 0 },
     { "sqlite3_bind_zeroblob",         test_bind_zeroblob, 0 },
     { "sqlite3_bind_zeroblob64",       test_bind_zeroblob64, 0 },
     { "sqlite3_bind_int64",            test_bind_int64,    0 },
     { "sqlite3_bind_double",           test_bind_double,   0 },
     { "sqlite3_bind_null",             test_bind_null     ,0 },
     { "sqlite3_bind_text",             test_bind_text     ,0 },
     { "sqlite3_bind_text16",           test_bind_text16   ,0 },

Changes to test/tabfunc01.test.

18
19
20
21
22
23
24

25
26
27
28
29
30
31
...
131
132
133
134
135
136
137





















138
set testprefix tabfunc01

ifcapable !vtab {
  finish_test
  return
}
load_static_extension db series


do_execsql_test tabfunc01-1.1 {
  SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2;
} {1 | 3 | 5 | 7 | 9 |}
do_execsql_test tabfunc01-1.2 {
  SELECT *, '|' FROM generate_series LIMIT 5;
} {0 | 1 | 2 | 3 | 4 |}
................................................................................
# by virtual tables unless omit was set.
#
do_execsql_test tabfunc01-500 {
  SELECT * FROM generate_series WHERE start IN (1,7) AND stop=20 AND step=10
  ORDER BY +1;
} {1 7 11 17}






















finish_test







>







 







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

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
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
set testprefix tabfunc01

ifcapable !vtab {
  finish_test
  return
}
load_static_extension db series
load_static_extension db array

do_execsql_test tabfunc01-1.1 {
  SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2;
} {1 | 3 | 5 | 7 | 9 |}
do_execsql_test tabfunc01-1.2 {
  SELECT *, '|' FROM generate_series LIMIT 5;
} {0 | 1 | 2 | 3 | 4 |}
................................................................................
# by virtual tables unless omit was set.
#
do_execsql_test tabfunc01-500 {
  SELECT * FROM generate_series WHERE start IN (1,7) AND stop=20 AND step=10
  ORDER BY +1;
} {1 7 11 17}


do_test tabfunc01-600 {
  set TAIL {}
  set VM [sqlite3_prepare db {SELECT * FROM intarray(?2,?3)} -1 TAIL]
  set TAIL
} {}
do_test tabfunc01-610 {
  sqlite3_bind_intarray $VM 2 11 22 33 44 55
  sqlite3_bind_int $VM 3 4
  sqlite3_step $VM
} SQLITE_ROW
do_test tabfunc01-620 {
  sqlite3_column_int $VM 0
} 11
do_test tabfunc01-621 {
  sqlite3_step $VM
  sqlite3_column_int $VM 0
} 22
sqlite3_finalize $VM
catch {sqlite3_bind_intarray}

finish_test