/ Check-in [29199eee]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:The echo module test is now running. Added the tclvar module test but have not yet done anything with it. (CVS 3234)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 29199eeea4c46168ccaa7535d4941bd740479dee
User & Date: drh 2006-06-13 23:51:34
Context
2006-06-14
06:31
Add tests for error conditions surrounding the creation/connection of virtual tables. (CVS 3235) check-in: 5e592c42 user: danielk1977 tags: trunk
2006-06-13
23:51
The echo module test is now running. Added the tclvar module test but have not yet done anything with it. (CVS 3234) check-in: 29199eee user: drh tags: trunk
19:26
The (unsupported) soundex() function returns '?000' when given a NULL. Ticket #1845. (CVS 3233) check-in: 9372481f user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

207
208
209
210
211
212
213

214
215
216
217
218
219
220
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test7.c \
  $(TOP)/src/test8.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_server.c \

  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/where.c

# Header files used by all library source files.
#







>







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test7.c \
  $(TOP)/src/test8.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/where.c

# Header files used by all library source files.
#

Changes to main.mk.

140
141
142
143
144
145
146

147
148
149
150
151
152
153
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test7.c \
  $(TOP)/src/test8.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_server.c \

  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/where.c

# Header files used by all library source files.
#







>







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test7.c \
  $(TOP)/src/test8.c \
  $(TOP)/src/test_async.c \
  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \
  $(TOP)/src/where.c

# Header files used by all library source files.
#

Changes to src/sqlite.h.in.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
922
923
924
925
926
927
928

929
930
931
932
933
934
935
....
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
....
1591
1592
1593
1594
1595
1596
1597
1598

1599
1600
1601
1602
1603
1604
1605
....
1622
1623
1624
1625
1626
1627
1628
1629

1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
....
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.173 2006/06/13 15:00:55 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);


/*
** The sqlite3_finalize() function is called to delete a compiled
** SQL statement obtained by a previous call to sqlite3_prepare()
** or sqlite3_prepare16(). If the statement was executed successfully, or
** not executed at all, then SQLITE_OK is returned. If execution of the
** statement failed then an error code is returned. 
................................................................................
               int argc, char **argv,
               sqlite3_vtab **ppVTab);
  int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
  int (*xDisconnect)(sqlite3_vtab *pVTab);
  int (*xDestroy)(sqlite3_vtab *pVTab);
  int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
  int (*xClose)(sqlite3_vtab_cursor*);
  int (*xFilter)(sqlite3_vtab_cursor*, char *zPlan, int nPlan,
                int argc, sqlite3_value **argv);
  int (*xNext)(sqlite3_vtab_cursor*);
  int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
  int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid);
  int (*xInsert)(sqlite3_vtab *pVTab, sqlite3_value **apData);
  int (*xDelete)(sqlite3_vtab *pVTab, sqlite_int64 rowid);
  int (*xBegin)(sqlite3_vtab *pVTab);
................................................................................
** The xBestIndex method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter.  If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv.  If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and is not checked again by SQLite.
**
** The idxNum value is recorded and passed into xFilter.  

**
** The orderByConsumed means that output from xFilter will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
** sorting step is required.
**
** The estimatedCost value is an estimate of the cost of doing the
** particular lookup.  A full scan of a table with N entries should have
................................................................................
  } *const aOrderBy;         /* The ORDER BY clause */

  /* Outputs */
  struct sqlite3_index_constraint_usage {
    int argvIndex;           /* if >0, constraint is part of argv to xFilter */
    unsigned char omit;      /* Do not code a test for this constraint */
  } *const aConstraintUsage;


  char *zPlan;               /* xBestIndex blob passed to xFilter */
  int nPlan;                 /* Size of nPlan */

  int orderByConsumed;       /* True if output is already ordered */
  double estimatedCost;      /* Estimated cost of using this index */
};
#define SQLITE_INDEX_CONSTRAINT_EQ    2
#define SQLITE_INDEX_CONSTRAINT_GT    4
#define SQLITE_INDEX_CONSTRAINT_LE    8
#define SQLITE_INDEX_CONSTRAINT_LT    16
................................................................................
/*
** The xCreate and xConnect methods of a module use the following API
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);

/*
** This function is called by the xBestIndex method of a module to 
** allocate space to store the query-plan passed to the corresponding
** xFilter invocation(s).
*/
char *sqlite3_allocate_queryplan(sqlite3_index_info *, int);

/*
** The interface to the virtual-table mechanism defined above (back up
** to a comment remarkably similar to this one) is currently considered
** to be experimental.  The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
**
** When the virtual-table mechanism stablizes, we will declare the







|







 







>







 







|







 







|
>







 







<
>
|
|
<







 







<
<
<
<
<
<
<







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
....
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
....
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
....
1624
1625
1626
1627
1628
1629
1630

1631
1632
1633

1634
1635
1636
1637
1638
1639
1640
....
1682
1683
1684
1685
1686
1687
1688







1689
1690
1691
1692
1693
1694
1695
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.174 2006/06/13 23:51:34 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);
sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);

/*
** The sqlite3_finalize() function is called to delete a compiled
** SQL statement obtained by a previous call to sqlite3_prepare()
** or sqlite3_prepare16(). If the statement was executed successfully, or
** not executed at all, then SQLITE_OK is returned. If execution of the
** statement failed then an error code is returned. 
................................................................................
               int argc, char **argv,
               sqlite3_vtab **ppVTab);
  int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
  int (*xDisconnect)(sqlite3_vtab *pVTab);
  int (*xDestroy)(sqlite3_vtab *pVTab);
  int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
  int (*xClose)(sqlite3_vtab_cursor*);
  int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
                int argc, sqlite3_value **argv);
  int (*xNext)(sqlite3_vtab_cursor*);
  int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
  int (*xRowid)(sqlite3_vtab_cursor*, sqlite_int64 *pRowid);
  int (*xInsert)(sqlite3_vtab *pVTab, sqlite3_value **apData);
  int (*xDelete)(sqlite3_vtab *pVTab, sqlite_int64 rowid);
  int (*xBegin)(sqlite3_vtab *pVTab);
................................................................................
** The xBestIndex method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter.  If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv.  If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
** virtual table and is not checked again by SQLite.
**
** The idxNum and idxPtr values are recorded and passed into xFilter.
** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true.
**
** The orderByConsumed means that output from xFilter will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
** sorting step is required.
**
** The estimatedCost value is an estimate of the cost of doing the
** particular lookup.  A full scan of a table with N entries should have
................................................................................
  } *const aOrderBy;         /* The ORDER BY clause */

  /* Outputs */
  struct sqlite3_index_constraint_usage {
    int argvIndex;           /* if >0, constraint is part of argv to xFilter */
    unsigned char omit;      /* Do not code a test for this constraint */
  } *const aConstraintUsage;

  int idxNum;                /* Number used to identify the index */
  char *idxStr;              /* String, possibly obtained from sqlite3_malloc */
  int needToFreeIdxStr;      /* Free idxStr using sqlite3_free() if true */

  int orderByConsumed;       /* True if output is already ordered */
  double estimatedCost;      /* Estimated cost of using this index */
};
#define SQLITE_INDEX_CONSTRAINT_EQ    2
#define SQLITE_INDEX_CONSTRAINT_GT    4
#define SQLITE_INDEX_CONSTRAINT_LE    8
#define SQLITE_INDEX_CONSTRAINT_LT    16
................................................................................
/*
** The xCreate and xConnect methods of a module use the following API
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);








/*
** The interface to the virtual-table mechanism defined above (back up
** to a comment remarkably similar to this one) is currently considered
** to be experimental.  The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
**
** When the virtual-table mechanism stablizes, we will declare the

Changes to src/tclsqlite.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2151
2152
2153
2154
2155
2156
2157

2158
2159
2160
2161
2162
2163
2164
2165
2166
2167

2168
2169
2170
2171
2172
2173
2174
**    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.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.157 2006/06/11 23:41:56 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "hash.h"
#include "tcl.h"
#include <stdlib.h>
................................................................................
    extern int Sqlitetest5_Init(Tcl_Interp*);
    extern int Sqlitetest6_Init(Tcl_Interp*);
    extern int Sqlitetest7_Init(Tcl_Interp*);
    extern int Sqlitetest8_Init(Tcl_Interp*);
    extern int Md5_Init(Tcl_Interp*);
    extern int Sqlitetestsse_Init(Tcl_Interp*);
    extern int Sqlitetestasync_Init(Tcl_Interp*);


    Sqlitetest1_Init(interp);
    Sqlitetest2_Init(interp);
    Sqlitetest3_Init(interp);
    Sqlitetest4_Init(interp);
    Sqlitetest5_Init(interp);
    Sqlitetest6_Init(interp);
    Sqlitetest7_Init(interp);
    Sqlitetest8_Init(interp);
    Sqlitetestasync_Init(interp);

    Md5_Init(interp);
#ifdef SQLITE_SSE
    Sqlitetestsse_Init(interp);
#endif
  }
#endif
  if( argc>=2 || TCLSH==2 ){







|







 







>










>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
**    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.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.158 2006/06/13 23:51:35 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "hash.h"
#include "tcl.h"
#include <stdlib.h>
................................................................................
    extern int Sqlitetest5_Init(Tcl_Interp*);
    extern int Sqlitetest6_Init(Tcl_Interp*);
    extern int Sqlitetest7_Init(Tcl_Interp*);
    extern int Sqlitetest8_Init(Tcl_Interp*);
    extern int Md5_Init(Tcl_Interp*);
    extern int Sqlitetestsse_Init(Tcl_Interp*);
    extern int Sqlitetestasync_Init(Tcl_Interp*);
    extern int Sqlitetesttclvar_Init(Tcl_Interp*);

    Sqlitetest1_Init(interp);
    Sqlitetest2_Init(interp);
    Sqlitetest3_Init(interp);
    Sqlitetest4_Init(interp);
    Sqlitetest5_Init(interp);
    Sqlitetest6_Init(interp);
    Sqlitetest7_Init(interp);
    Sqlitetest8_Init(interp);
    Sqlitetestasync_Init(interp);
    Sqlitetesttclvar_Init(interp);
    Md5_Init(interp);
#ifdef SQLITE_SSE
    Sqlitetestsse_Init(interp);
#endif
  }
#endif
  if( argc>=2 || TCLSH==2 ){

Changes to src/test8.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
31
32
33
34
35
36
37

38
39
40
41
42
43
44
...
220
221
222
223
224
225
226

227
228
229
230
231
232
233
...
257
258
259
260
261
262
263

264
265
266
267
268
269
270
...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361




362



363
364

365
366

367












368
369
370






371
372
373
374
375
376
377
...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
...
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437


438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test8.c,v 1.10 2006/06/13 15:00:55 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
** the same number of entries as there are columns in the underlying
** real table.
*/
struct echo_vtab {
  sqlite3_vtab base;
  Tcl_Interp *interp;
  sqlite3 *db;

  char *zStmt;                 /* "SELECT rowid, * FROM <real-table-name> " */

  int *aIndex;
  int nCol;
  char **aCol;
};

................................................................................

  pVtab = sqliteMalloc( sizeof(*pVtab) );

  *ppVtab = &pVtab->base;
  pVtab->base.pModule = pModule;
  pVtab->interp = pModule->pAux;
  pVtab->db = db;

  for(i=0; i<argc; i++){
    appendToEchoModule(pVtab->interp, argv[i]);
  }

  echoDeclareVtab(pVtab, db, argc, argv);
  return 0;
}
................................................................................
  echo_vtab *p = (echo_vtab*)pVtab;
  sqliteFree(p->zStmt);
  sqliteFree(p->aIndex);
  for(ii=0; ii<p->nCol; ii++){
    sqliteFree(p->aCol[ii]);
  }
  sqliteFree(p->aCol);

  sqliteFree(p);
  return 0;
}

static int echoDisconnect(sqlite3_vtab *pVtab){
  appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDisconnect");
  return echoDestructor(pVtab);
................................................................................
}

static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  int iCol = i + 1;
  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;

  assert( sqlite3_data_count(pStmt)>iCol );
  switch( sqlite3_column_type(pStmt, iCol) ){
    case SQLITE_INTEGER:
      sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
      break;
    case SQLITE_FLOAT:
      sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
      break;
    case SQLITE_TEXT:
      sqlite3_result_text(ctx, 
          sqlite3_column_text(pStmt, iCol),
          sqlite3_column_bytes(pStmt, iCol),
          SQLITE_TRANSIENT
      );
      break;
    case SQLITE_BLOB:
      sqlite3_result_blob(ctx, 
          sqlite3_column_blob(pStmt, iCol),
          sqlite3_column_bytes(pStmt, iCol),
          SQLITE_TRANSIENT
      );
      break;
  }
  return SQLITE_OK;
}

static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
  *pRowid = sqlite3_column_int64(pStmt, 0);
  return SQLITE_OK;
}


static int echoFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  char *zPlan, int nPlan,
  int argc, 
  sqlite3_value **argv
){
  int rc;
  int ii;

  echo_cursor *pCur = (echo_cursor *)pVtabCursor;
  echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
  sqlite3 *db = pVtab->db;

  appendToEchoModule(pVtab->interp, "xFilter");
  appendToEchoModule(pVtab->interp, zPlan);
  for(ii=0; ii<argc; ii++){
    appendToEchoModule(pVtab->interp, sqlite3_value_text(argv[ii]));




  }




  sqlite3_finalize(pCur->pStmt);

  pCur->pStmt = 0;
  rc = sqlite3_prepare(db, pVtab->zStmt, -1, &pCur->pStmt, 0);














  if( rc==SQLITE_OK ){
    rc = echoNext(pVtabCursor);
  }







  return rc;
}

/*
** The echo module implements the subset of query constraints and sort
** orders that may take advantage of SQLite indices on the underlying
................................................................................
**
** then the echo module handles WHERE or ORDER BY clauses that refer
** to the column "b", but not "a" or "c". If a multi-column index is
** present, only it's left most column is considered. 
*/
static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  int ii;
  char *zWhere = 0;
  char *zOrder = 0;
  char *zPlan = 0;
  int nPlan = 0;
  int nArg = 0;
  echo_vtab *pVtab = (echo_vtab *)tab;

  for(ii=0; ii<pIdxInfo->nConstraint; ii++){
    const struct sqlite3_index_constraint *pConstraint;
    struct sqlite3_index_constraint_usage *pUsage;

    pConstraint = &pIdxInfo->aConstraint[ii];
    pUsage = &pIdxInfo->aConstraintUsage[ii];

................................................................................
        case SQLITE_INDEX_CONSTRAINT_LE:
          zOp = "<="; break;
        case SQLITE_INDEX_CONSTRAINT_GE:
          zOp = ">="; break;
        case SQLITE_INDEX_CONSTRAINT_MATCH:
          zOp = "MATCH"; break;
      }
      if( zWhere ){
        char *zTmp = zWhere;
        zWhere = sqlite3MPrintf("%s AND %s %s ?", zWhere, zCol, zOp);
        sqliteFree(zTmp);
      } else {
        zWhere = sqlite3MPrintf("WHERE %s %s ?", zCol, zOp);
      }

      pUsage->argvIndex = ++nArg;
      pUsage->omit = 1;
    }
  }

  appendToEchoModule(pVtab->interp, "xBestIndex");;
  appendToEchoModule(pVtab->interp, zWhere);
  appendToEchoModule(pVtab->interp, zOrder);



  nPlan = 2;
  if( zWhere ){
    nPlan += strlen(zWhere);
  }
  if( zOrder ){
    nPlan += strlen(zWhere);
  }
  zPlan = sqlite3_allocate_queryplan(pIdxInfo, nPlan);
  if( zPlan ){
    sprintf(zPlan, "%s%s%s", 
        zWhere?zWhere:"", (zOrder&&zWhere)?" ":"", zOrder?zOrder:"");
  }

  sqliteFree(zWhere);
  sqliteFree(zOrder);

  return SQLITE_OK;
}

/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/







|







 







>







 







>







 







>







 







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












|
<
|


|





|
|
|
|
>
>
>
>
|
>
>
>
|
<
>
|
<
>
|
>
>
>
>
>
>
>
>
>
>
>
>



>
>
>
>
>
>







 







|
|
|
|
|
|
|







 







|
|
|
|
<
<
<
<




<

|
<

>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
309
310
311
312
313
314
315
316





















317
318
319
320
321
322
323
324
325
326
327
328
329

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351

352
353

354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
...
420
421
422
423
424
425
426
427
428
429
430




431
432
433
434

435
436

437
438
439
440















441
442
443
444
445
446
447
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test8.c,v 1.11 2006/06/13 23:51:35 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
** the same number of entries as there are columns in the underlying
** real table.
*/
struct echo_vtab {
  sqlite3_vtab base;
  Tcl_Interp *interp;
  sqlite3 *db;
  char *zTableName;       /* Name of the real table */
  char *zStmt;                 /* "SELECT rowid, * FROM <real-table-name> " */

  int *aIndex;
  int nCol;
  char **aCol;
};

................................................................................

  pVtab = sqliteMalloc( sizeof(*pVtab) );

  *ppVtab = &pVtab->base;
  pVtab->base.pModule = pModule;
  pVtab->interp = pModule->pAux;
  pVtab->db = db;
  pVtab->zTableName = sqlite3MPrintf("%s", argv[1]);
  for(i=0; i<argc; i++){
    appendToEchoModule(pVtab->interp, argv[i]);
  }

  echoDeclareVtab(pVtab, db, argc, argv);
  return 0;
}
................................................................................
  echo_vtab *p = (echo_vtab*)pVtab;
  sqliteFree(p->zStmt);
  sqliteFree(p->aIndex);
  for(ii=0; ii<p->nCol; ii++){
    sqliteFree(p->aCol[ii]);
  }
  sqliteFree(p->aCol);
  sqliteFree(p->zTableName);
  sqliteFree(p);
  return 0;
}

static int echoDisconnect(sqlite3_vtab *pVtab){
  appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDisconnect");
  return echoDestructor(pVtab);
................................................................................
}

static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  int iCol = i + 1;
  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;

  assert( sqlite3_data_count(pStmt)>iCol );
  sqlite3_result_value(ctx, sqlite3_column_value(pStmt, iCol));





















  return SQLITE_OK;
}

static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
  *pRowid = sqlite3_column_int64(pStmt, 0);
  return SQLITE_OK;
}


static int echoFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,

  int argc, sqlite3_value **argv
){
  int rc;
  int i;

  echo_cursor *pCur = (echo_cursor *)pVtabCursor;
  echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
  sqlite3 *db = pVtab->db;

  sqlite3_finalize(pCur->pStmt);
  pCur->pStmt = 0;
  rc = sqlite3_prepare(db, idxStr, -1, &pCur->pStmt, 0);
  for(i=0; i<argc; i++){
    switch( sqlite3_value_type(argv[i]) ){
      case SQLITE_INTEGER: {
        sqlite3_bind_int64(pCur->pStmt, i+1, sqlite3_value_int64(argv[i]));
        break;
      }
      case SQLITE_FLOAT: {
        sqlite3_bind_double(pCur->pStmt, i+1, sqlite3_value_double(argv[i]));
        break;
      }

      case SQLITE_NULL: {
        sqlite3_bind_null(pCur->pStmt, i+1);

        break;
      }
      case SQLITE_TEXT: {
        sqlite3_bind_text(pCur->pStmt, i+1, sqlite3_value_text(argv[i]),
                          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
        break;
      }
      case SQLITE_BLOB: {
        sqlite3_bind_blob(pCur->pStmt, i+1, sqlite3_value_blob(argv[i]),
                          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
        break;
      }
    }
  }
  if( rc==SQLITE_OK ){
    rc = echoNext(pVtabCursor);
  }

  appendToEchoModule(pVtab->interp, "xFilter");
  appendToEchoModule(pVtab->interp, idxStr);
  for(i=0; i<argc; i++){
    appendToEchoModule(pVtab->interp, sqlite3_value_text(argv[i]));
  }

  return rc;
}

/*
** The echo module implements the subset of query constraints and sort
** orders that may take advantage of SQLite indices on the underlying
................................................................................
**
** then the echo module handles WHERE or ORDER BY clauses that refer
** to the column "b", but not "a" or "c". If a multi-column index is
** present, only it's left most column is considered. 
*/
static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  int ii;
  char *zQuery = 0;
  char *zNew;
  int nArg = 0;
  const char *zSep = "WHERE";
  echo_vtab *pVtab = (echo_vtab *)tab;

  zQuery = sqlite3_mprintf("SELECT rowid, * FROM %Q", pVtab->zTableName);
  for(ii=0; ii<pIdxInfo->nConstraint; ii++){
    const struct sqlite3_index_constraint *pConstraint;
    struct sqlite3_index_constraint_usage *pUsage;

    pConstraint = &pIdxInfo->aConstraint[ii];
    pUsage = &pIdxInfo->aConstraintUsage[ii];

................................................................................
        case SQLITE_INDEX_CONSTRAINT_LE:
          zOp = "<="; break;
        case SQLITE_INDEX_CONSTRAINT_GE:
          zOp = ">="; break;
        case SQLITE_INDEX_CONSTRAINT_MATCH:
          zOp = "MATCH"; break;
      }
      zNew = sqlite3_mprintf("%s %s %s %s ?", zQuery, zSep, zCol, zOp);
      sqlite3_free(zQuery);
      zQuery = zNew;
      zSep = "AND";




      pUsage->argvIndex = ++nArg;
      pUsage->omit = 1;
    }
  }

  appendToEchoModule(pVtab->interp, "xBestIndex");;
  appendToEchoModule(pVtab->interp, zQuery);


  pIdxInfo->idxStr = zQuery;
  pIdxInfo->needToFreeIdxStr = 1;
  pIdxInfo->estimatedCost = 1.0;















  return SQLITE_OK;
}

/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/

Added src/test_tclvar.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
/*
** 2006 June 13
**
** 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.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** The emphasis of this file is a virtual table that provides
** access to TCL variables.
**
** $Id: test_tclvar.c,v 1.1 2006/06/13 23:51:35 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

typedef struct tclvar_vtab tclvar_vtab;
typedef struct tclvar_cursor tclvar_cursor;

/* 
** A tclvar virtual-table object 
*/
struct tclvar_vtab {
  sqlite3_vtab base;
  Tcl_Interp *interp;
};

/* A tclvar cursor object */
struct tclvar_cursor {
  sqlite3_vtab_cursor base;
  Tcl_Obj *pList1, *pList2;
  int i, j;
};

/* Methods for the tclvar module */
static int tclvarConnect(
  sqlite3 *db,
  const sqlite3_module *pModule,
  int argc, char **argv,
  sqlite3_vtab **ppVtab
){
  tclvar_vtab *pVtab;
  static const char zSchema[] = 
     "CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
  pVtab = sqliteMalloc( sizeof(*pVtab) );
  if( pVtab==0 ) return SQLITE_NOMEM;
  *ppVtab = &pVtab->base;
  pVtab->base.pModule = pModule;
  pVtab->interp = pModule->pAux;
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_declare_vtab(db, zSchema);
#endif
  return SQLITE_OK;
}
/* Note that for this virtual table, the xCreate and xConnect
** methods are identical. */
static int tclvarDisconnect(sqlite3_vtab *pVtab){
  free(pVtab);
}
/* The xDisconnect and xDestroy methods are also the same */

static int tclvarOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  tclvar_cursor *pCur;
  pCur = sqliteMalloc(sizeof(tclvar_cursor));
  *ppCursor = &pCur->base;
  return SQLITE_OK;
}

static int tclvarClose(sqlite3_vtab_cursor *cur){
  tclvar_cursor *pCur = (tclvar_cursor *)cur;
  if( pCur->pList1 ){
    Tcl_DecrRefCount(pCur->pList1);
  }
  if( pCur->pList2 ){
    Tcl_DecrRefCount(pCur->pList2);
  }
  sqliteFree(pCur);
  return SQLITE_OK;
}

static int tclvarNext(sqlite3_vtab_cursor *cur){
  tclvar_cursor *pCur = (tclvar_cursor *)cur;
  return 0;
}

static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  tclvar_cursor *pCur = (tclvar_cursor*)cur;
  return SQLITE_OK;
}

static int tclvarRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  tclvar_cursor *pCur = (tclvar_cursor*)cur;
  return SQLITE_OK;
}

static int tclvarFilter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  tclvar_cursor *pCur = (tclvar_cursor *)pVtabCursor;
  tclvar_vtab *pVtab = (tclvar_vtab *)pCur->base.pVtab;
  return 0;
}

/*
*/
static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  tclvar_vtab *pVtab = (tclvar_vtab *)tab;
  return SQLITE_OK;
}

/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/
static sqlite3_module tclvarModule = {
  0,                         /* iVersion */
  "tclvar",                  /* zName */
  0,                         /* pAux */
  tclvarConnect,
  tclvarConnect,
  tclvarBestIndex,
  tclvarDisconnect, 
  tclvarDisconnect,
  tclvarOpen,                  /* xOpen - open a cursor */
  tclvarClose,                 /* xClose - close a cursor */
  tclvarFilter,                /* xFilter - configure scan constraints */
  tclvarNext,                  /* xNext - advance a cursor */
  tclvarColumn,                /* xColumn - read data */
  tclvarRowid                  /* xRowid - read data */
};

/*
** Decode a pointer to an sqlite3 object.
*/
static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
  *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
  return TCL_OK;
}


/*
** Register the echo virtual table module.
*/
static int register_tclvar_module(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  tclvarModule.pAux = interp;
#ifndef SQLITE_OMIT_VIRTUALTABLE
  sqlite3_create_module(db, "tclvar", &tclvarModule);
#endif
  return TCL_OK;
}


/*
** Register commands with the TCL interpreter.
*/
int Sqlitetesttclvar_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     void *clientData;
  } aObjCmd[] = {
     { "register_tclvar_module",   register_tclvar_module, 0 },
  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
  }
  return TCL_OK;
}

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
4589
4590
4591
4592
4593
4594
4595
4596


4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
....
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631

4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.557 2006/06/13 15:00:55 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 P3
**
** P1 is a cursor opened using VOpen.  P2 is an address to jump to if
** the filtered result set is empty.
**
** P3 points to enough free space to use to marshall the arguments.


**
** This opcode invokes the xFilter method on the virtual table specified
** by P1.  The query plan parameter to xFilter is the top of the stack.
** Next down on the stack is the argc parameter.  Beneath the
** next of stack are argc additional parameters which are passed to
** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
** the stack) becomes argv[argc-1] when passed to xFilter.
**
** The query plan, argc, and all argv stack values are popped from the
** stack before this instruction completes.
**
** A jump is made to P2 if the result set after filtering would be 
** empty.
*/
case OP_VFilter: {
  int nArg;

................................................................................

  Cursor *pCur = p->apCsr[pOp->p1];
  assert( pCur->pVtabCursor );
  pModule = pCur->pVtabCursor->pVtab->pModule;

  /* Grab the index number and argc parameters off the top of the stack. */
  assert( (&pTos[-1])>=p->aStack );
  assert( pTos[0].flags&MEM_Blob && pTos[-1].flags==MEM_Int );
  nArg = pTos[-1].i;

  /* Invoke the xFilter method if one is defined. */
  if( pModule->xFilter ){
    int res;
    int ii;
    Mem **apArg = (Mem **)pOp->p3;
    for(ii = 0; ii<nArg; ii++){
      apArg[ii] = &pTos[ii+1-2-nArg];

    }

    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    res = pModule->xFilter(pCur->pVtabCursor, pTos->z, pTos->n, nArg, apArg);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;

    if( res==0 ){
      pc = pOp->p2 - 1;
    }
  }








|







 







|
>
>


|
|




|
|







 







|





|
|
|
|
>



|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
....
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.558 2006/06/13 23:51:35 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................

#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 P3
**
** P1 is a cursor opened using VOpen.  P2 is an address to jump to if
** the filtered result set is empty.
**
** P3 is either NULL or a string that was generated by the xBestIndex
** method of the module.  The interpretation of the P3 string is left
** to the module implementation.
**
** This opcode invokes the xFilter method on the virtual table specified
** by P1.  The integer query plan parameter to xFilter is the top of the
** stack.  Next down on the stack is the argc parameter.  Beneath the
** next of stack are argc additional parameters which are passed to
** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
** the stack) becomes argv[argc-1] when passed to xFilter.
**
** The integer query plan parameter, argc, and all argv stack values 
** are popped from the stack before this instruction completes.
**
** A jump is made to P2 if the result set after filtering would be 
** empty.
*/
case OP_VFilter: {
  int nArg;

................................................................................

  Cursor *pCur = p->apCsr[pOp->p1];
  assert( pCur->pVtabCursor );
  pModule = pCur->pVtabCursor->pVtab->pModule;

  /* Grab the index number and argc parameters off the top of the stack. */
  assert( (&pTos[-1])>=p->aStack );
  assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
  nArg = pTos[-1].i;

  /* Invoke the xFilter method if one is defined. */
  if( pModule->xFilter ){
    int res;
    int i;
    Mem **apArg = p->apArg;
    for(i = 0; i<nArg; i++){
      apArg[i] = &pTos[i+1-2-nArg];
      storeTypeInfo(apArg[i], 0);
    }

    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    res = pModule->xFilter(pCur->pVtabCursor, pTos->i, pOp->p3, nArg, apArg);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;

    if( res==0 ){
      pc = pOp->p2 - 1;
    }
  }

Changes to src/vdbe.h.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
67
68
69
70
71
72
73

74
75
76
77
78
79
80
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.104 2006/06/13 01:04:53 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
#define P3_COLLSEQ  (-4)  /* P3 is a pointer to a CollSeq structure */
#define P3_FUNCDEF  (-5)  /* P3 is a pointer to a FuncDef structure */
#define P3_KEYINFO  (-6)  /* P3 is a pointer to a KeyInfo structure */
#define P3_VDBEFUNC (-7)  /* P3 is a pointer to a VdbeFunc structure */
#define P3_MEM      (-8)  /* P3 is a pointer to a Mem*    structure */
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
#define P3_VTAB     (-10) /* P3 is a pointer to an sqlite3_vtab structure */


/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
** is made.  That copy is freed when the Vdbe is finalized.  But if the
** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used.  It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc().  But no copy is made and the calling
** function should *not* try to free the KeyInfo.







|







 







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.105 2006/06/13 23:51:35 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
#define P3_COLLSEQ  (-4)  /* P3 is a pointer to a CollSeq structure */
#define P3_FUNCDEF  (-5)  /* P3 is a pointer to a FuncDef structure */
#define P3_KEYINFO  (-6)  /* P3 is a pointer to a KeyInfo structure */
#define P3_VDBEFUNC (-7)  /* P3 is a pointer to a VdbeFunc structure */
#define P3_MEM      (-8)  /* P3 is a pointer to a Mem*    structure */
#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */
#define P3_VTAB     (-10) /* P3 is a pointer to an sqlite3_vtab structure */
#define P3_MPRINTF  (-11) /* P3 is a string obtained from sqlite3_mprintf() */

/* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
** is made.  That copy is freed when the Vdbe is finalized.  But if the
** argument is P3_KEYINFO_HANDOFF, the passed in pointer is used.  It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc().  But no copy is made and the calling
** function should *not* try to free the KeyInfo.

Changes to src/vdbeapi.c.

450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
  return val;
}
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
  const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
  columnMallocFailure(pStmt);
  return val;
}
#if 0
sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
  return columnMem(pStmt, i);
}
#endif
#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
  const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
  columnMallocFailure(pStmt);
  return val;
}
#endif /* SQLITE_OMIT_UTF16 */







<



<







450
451
452
453
454
455
456

457
458
459

460
461
462
463
464
465
466
  return val;
}
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
  const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
  columnMallocFailure(pStmt);
  return val;
}

sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
  return columnMem(pStmt, i);
}

#ifndef SQLITE_OMIT_UTF16
const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
  const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
  columnMallocFailure(pStmt);
  return val;
}
#endif /* SQLITE_OMIT_UTF16 */

Changes to src/vdbeaux.c.

259
260
261
262
263
264
265
266





267
268
269
270
271
272
273
274
...
375
376
377
378
379
380
381




382
383
384
385
386
387
388
      }
    }else if( opcode==OP_IdxInsert ){
      if( pOp->p2 ){
        doesStatementRollback = 1;
      }
    }else if( opcode==OP_Statement ){
      hasStatementBegin = 1;
    }






    if( opcodeNoPush(opcode) ){
      nMaxStack--;
    }

    if( pOp->p2>=0 ) continue;
    assert( -1-pOp->p2<p->nLabel );
    pOp->p2 = aLabel[-1-pOp->p2];
................................................................................
  if( p3 ){
    switch( p3type ){
      case P3_DYNAMIC:
      case P3_KEYINFO:
      case P3_KEYINFO_HANDOFF: {
        sqliteFree(p3);
        break;




      }
      case P3_VDBEFUNC: {
        VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
        sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
        sqliteFree(pVdbeFunc);
        break;
      }







|
>
>
>
>
>
|







 







>
>
>
>







259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
      }
    }else if( opcode==OP_IdxInsert ){
      if( pOp->p2 ){
        doesStatementRollback = 1;
      }
    }else if( opcode==OP_Statement ){
      hasStatementBegin = 1;
    }else if( opcode==OP_VFilter ){
      int n;
      assert( p->nOp - i >= 3 );
      assert( pOp[-2].opcode==OP_Integer );
      n = pOp[-2].p1;
      if( n>nMaxArgs ) nMaxArgs = n;
    }
    if( opcodeNoPush(opcode) ){
      nMaxStack--;
    }

    if( pOp->p2>=0 ) continue;
    assert( -1-pOp->p2<p->nLabel );
    pOp->p2 = aLabel[-1-pOp->p2];
................................................................................
  if( p3 ){
    switch( p3type ){
      case P3_DYNAMIC:
      case P3_KEYINFO:
      case P3_KEYINFO_HANDOFF: {
        sqliteFree(p3);
        break;
      }
      case P3_MPRINTF: {
        sqlite3_free(p3);
        break;
      }
      case P3_VDBEFUNC: {
        VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
        sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
        sqliteFree(pVdbeFunc);
        break;
      }

Changes to src/vtab.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
**    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 contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.7 2006/06/13 15:00:55 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"

/*
** External API function used to create a new virtual-table module.
*/
................................................................................
      rc = sqlite3SafetyOn(db);
    }
  }

  return rc;
}

/*
** Resize pInfo->zPlan to nBytes bytes using realloc(). Set pInfo->nPlan
** to nBytes and return a pointer to the allocated memory.
*/
char *sqlite3_allocate_queryplan(sqlite3_index_info *pInfo, int nBytes){
  pInfo->nPlan = nBytes;
  sqlite3ReallocOrFree(&pInfo->zPlan, nBytes);
  return pInfo->zPlan;
}


/*
** This function is used to set the schema of a virtual table.  It is only
** valid to call this function from within the xCreate() or xConnect() of a
** virtual table module.
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){







|







 







<
<
<
<
<
<
<
<
<
<







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
273
274
275
276
277
278
279










280
281
282
283
284
285
286
**    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 contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.8 2006/06/13 23:51:35 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"

/*
** External API function used to create a new virtual-table module.
*/
................................................................................
      rc = sqlite3SafetyOn(db);
    }
  }

  return rc;
}












/*
** This function is used to set the schema of a virtual table.  It is only
** valid to call this function from within the xCreate() or xConnect() of a
** virtual table module.
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){

Changes to src/where.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
....
1104
1105
1106
1107
1108
1109
1110



1111
1112

1113
1114
1115
1116
1117
1118
1119
....
1568
1569
1570
1571
1572
1573
1574
1575
1576


1577
1578

1579
1580
1581
1582
1583
1584
1585
....
1857
1858
1859
1860
1861
1862
1863

1864
1865

1866
1867
1868
1869
1870
1871
1872
....
1948
1949
1950
1951
1952
1953
1954
1955





1956
1957
1958
1959
1960
1961

1962
1963
1964
1965
1966
1967
1968
1969
1970

1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  This module is reponsible for
** generating the code that loops through a table looking for applicable
** rows.  Indices are selected and used to speed the search when doing
** so is applicable.  Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.215 2006/06/13 17:39:01 drh Exp $
*/
#include "sqliteInt.h"

/*
** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
*/
#define BMS  (sizeof(Bitmask)*8)
................................................................................
  pUsage = pIdxInfo->aConstraintUsage;
  for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
    j = pIdxCons->iTermOffset;
    pTerm = &pWC->a[j];
    pIdxCons->usable =  (pTerm->prereqRight & notReady)==0;
  }
  memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);



  pIdxInfo->zPlan = 0;
  pIdxInfo->nPlan = 0;

  pIdxInfo->orderByConsumed = 0;
  pIdxInfo->estimatedCost = SQLITE_BIG_DBL;
  nOrderBy = pIdxInfo->nOrderBy;
  if( pIdxInfo->nOrderBy && !orderByUsable ){
    *(int*)&pIdxInfo->nOrderBy = 0;
  }
  pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
................................................................................
/*
** Free a WhereInfo structure
*/
static void whereInfoFree(WhereInfo *pWInfo){
  if( pWInfo ){
    int i;
    for(i=0; i<pWInfo->nLevel; i++){
      if( pWInfo->a[i].pIdxInfo ){
        sqliteFree(pWInfo->a[i].pIdxInfo->zPlan);


      }
      sqliteFree(pWInfo->a[i].pIdxInfo);

    }
    sqliteFree(pWInfo);
  }
}


/*
................................................................................
      if( (pIx = pLevel->pIdx)!=0 ){
        zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
      }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
        zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
      }
#ifndef SQLITE_OMIT_VIRTUALTABLE
      else if( pLevel->pIdxInfo ){

        zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %s",
                    pLevel->pIdxInfo->zPlan);

      }
#endif
      if( pLevel->flags & WHERE_ORDERBY ){
        zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
      }
      sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
    }
................................................................................
    }

#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( pLevel->pIdxInfo ){
      /* Case 0:  The table is a virtual-table.  Use the VFilter and VNext
      **          to access the data.
      */
      char *zSpace;     /* Space for OP_VFilter to marshall it's arguments */






      sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
      for(i=1; i<=pIdxInfo->nConstraint; i++){
        int j;
        for(j=0; j<pIdxInfo->nConstraint; j++){
          if( pIdxInfo->aConstraintUsage[j].argvIndex==i ){

            sqlite3ExprCode(pParse, wc.a[j].pExpr->pRight);
            break;
          }
        }
        if( j==pIdxInfo->nConstraint ) break;
      }
      sqlite3VdbeAddOp(v, OP_Integer, i-1, 0);
      sqlite3VdbeAddOp(v, OP_Blob, pIdxInfo->nPlan, 0);
      sqlite3VdbeChangeP3(v, -1, pIdxInfo->zPlan, P3_DYNAMIC);

      pIdxInfo->zPlan = 0;
      sqlite3VdbeAddOp(v, OP_VFilter, iCur, brk);
      zSpace = (char *)sqliteMalloc(sizeof(sqlite3_value*)*(i-1));
      sqlite3VdbeChangeP3(v, -1, zSpace, P3_DYNAMIC);
      for(i=0; i<pIdxInfo->nConstraint; i++){
        if( pIdxInfo->aConstraintUsage[i].omit ){
          disableTerm(pLevel, &wc.a[i]);
        }
      }
      pLevel->op = OP_VNext;
      pLevel->p1 = iCur;







|







 







>
>
>
|
|
>







 







|
|
>
>
|
|
>







 







>
|
<
>







 







|
>
>
>
>
>

<
|

|
|
>
|



|


|
|
>
|
<
<
<







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
....
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
....
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
....
1864
1865
1866
1867
1868
1869
1870
1871
1872

1873
1874
1875
1876
1877
1878
1879
1880
....
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969

1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985



1986
1987
1988
1989
1990
1991
1992
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  This module is reponsible for
** generating the code that loops through a table looking for applicable
** rows.  Indices are selected and used to speed the search when doing
** so is applicable.  Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
** $Id: where.c,v 1.216 2006/06/13 23:51:35 drh Exp $
*/
#include "sqliteInt.h"

/*
** The number of bits in a Bitmask.  "BMS" means "BitMask Size".
*/
#define BMS  (sizeof(Bitmask)*8)
................................................................................
  pUsage = pIdxInfo->aConstraintUsage;
  for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
    j = pIdxCons->iTermOffset;
    pTerm = &pWC->a[j];
    pIdxCons->usable =  (pTerm->prereqRight & notReady)==0;
  }
  memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
  if( pIdxInfo->needToFreeIdxStr ){
    sqlite3_free(pIdxInfo->idxStr);
  }
  pIdxInfo->idxStr = 0;
  pIdxInfo->idxNum = 0;
  pIdxInfo->needToFreeIdxStr = 0;
  pIdxInfo->orderByConsumed = 0;
  pIdxInfo->estimatedCost = SQLITE_BIG_DBL;
  nOrderBy = pIdxInfo->nOrderBy;
  if( pIdxInfo->nOrderBy && !orderByUsable ){
    *(int*)&pIdxInfo->nOrderBy = 0;
  }
  pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
................................................................................
/*
** Free a WhereInfo structure
*/
static void whereInfoFree(WhereInfo *pWInfo){
  if( pWInfo ){
    int i;
    for(i=0; i<pWInfo->nLevel; i++){
      sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
      if( pInfo ){
        if( pInfo->needToFreeIdxStr ){
          sqlite3_free(pInfo->idxStr);
        }
        sqliteFree(pInfo);
      }
    }
    sqliteFree(pWInfo);
  }
}


/*
................................................................................
      if( (pIx = pLevel->pIdx)!=0 ){
        zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
      }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
        zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
      }
#ifndef SQLITE_OMIT_VIRTUALTABLE
      else if( pLevel->pIdxInfo ){
        sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
        zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %d:%s",

                    pIdxInfo->idxNum, pIdxInfo->idxStr);
      }
#endif
      if( pLevel->flags & WHERE_ORDERBY ){
        zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
      }
      sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
    }
................................................................................
    }

#ifndef SQLITE_OMIT_VIRTUALTABLE
    if( pLevel->pIdxInfo ){
      /* Case 0:  The table is a virtual-table.  Use the VFilter and VNext
      **          to access the data.
      */
      sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo;
      int nConstraint = pIdxInfo->nConstraint;
      struct sqlite3_index_constraint_usage *aUsage =
                                                  pIdxInfo->aConstraintUsage;
      const struct sqlite3_index_constraint *aConstraint =
                                                  pIdxInfo->aConstraint;


      for(i=1; i<=nConstraint; i++){
        int j;
        for(j=0; j<nConstraint; j++){
          if( aUsage[j].argvIndex==i ){
            int k = aConstraint[j].iTermOffset;
            sqlite3ExprCode(pParse, wc.a[k].pExpr->pRight);
            break;
          }
        }
        if( j==nConstraint ) break;
      }
      sqlite3VdbeAddOp(v, OP_Integer, i-1, 0);
      sqlite3VdbeAddOp(v, OP_Integer, pIdxInfo->idxNum, 0);
      sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pIdxInfo->idxStr,
                      pIdxInfo->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC);
      pIdxInfo->needToFreeIdxStr = 0;



      for(i=0; i<pIdxInfo->nConstraint; i++){
        if( pIdxInfo->aConstraintUsage[i].omit ){
          disableTerm(pLevel, &wc.a[i]);
        }
      }
      pLevel->op = OP_VNext;
      pLevel->p1 = iCur;

Changes to test/vtab1.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
...
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
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.10 2006/06/13 15:00:55 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !vtab {
  finish_test
  return
................................................................................

#----------------------------------------------------------------------
# Test case vtab1-3 tests simple linear scans (no filter conditions) of 
# virtual table modules.
do_test vtab1-3.1 {
  set echo_module ""
  execsql {
    CREATE TABLE treal(a INTEGER, b VARCHAR(32), c); 
    CREATE INDEX treal_idx ON treal(b);
    CREATE VIRTUAL TABLE t1 USING echo(treal);
  }
  set echo_module
} [list xCreate echo treal]
do_test vtab1-3.2 {
  # Test that a SELECT on t2 doesn't crash. No rows are returned
................................................................................
} {1 2}

do_test vtab1-3.6 {
  set echo_module ""
  execsql {
    SELECT * FROM t1;
  }


  set echo_module
} {xBestIndex {} {} xFilter {}}

do_test vtab1-3.7 {
  set echo_module ""
  execsql {
    SELECT * FROM t1 WHERE b = 10;
  }


  set echo_module
} {xBestIndex {WHERE b = ?} {} xFilter {WHERE b = ?} 10}

do_test vtab1-3.8 {
  set echo_module ""
  execsql {
    SELECT * FROM t1 WHERE b >= 5 AND b <= 10;
  }


  set echo_module
} {xBestIndex {WHERE b >= ? AND b <= ?} {} xFilter {WHERE b >= ? AND b <= ?} 5 10}

do_test vtab1-3.9 {
  set echo_module ""
  execsql {
    SELECT * FROM t1 WHERE b BETWEEN 5 AND 10;
  }


  set echo_module
} {xBestIndex {WHERE b >= ? AND b <= ?} {} xFilter {WHERE b >= ? AND b <= ?} 5 10}


finish_test








|







 







|







 







>
>

<
>
|


|

>
>

<
>
|




>
>

<
>
|


|

>
>

<
>


<
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
...
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

#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.11 2006/06/13 23:51:35 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !vtab {
  finish_test
  return
................................................................................

#----------------------------------------------------------------------
# Test case vtab1-3 tests simple linear scans (no filter conditions) of 
# virtual table modules.
do_test vtab1-3.1 {
  set echo_module ""
  execsql {
    CREATE TABLE treal(a INTEGER, b INTEGER, c); 
    CREATE INDEX treal_idx ON treal(b);
    CREATE VIRTUAL TABLE t1 USING echo(treal);
  }
  set echo_module
} [list xCreate echo treal]
do_test vtab1-3.2 {
  # Test that a SELECT on t2 doesn't crash. No rows are returned
................................................................................
} {1 2}

do_test vtab1-3.6 {
  set echo_module ""
  execsql {
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6}
do_test vtab1-3.7 {
  set echo_module

} {xBestIndex {SELECT rowid, * FROM 'treal'} xFilter {SELECT rowid, * FROM 'treal'}}
do_test vtab1-3.8 {
  set echo_module ""
  execsql {
    SELECT * FROM t1 WHERE b = 5;
  }
} {4 5 6}
do_test vtab1-3.9 {
  set echo_module

} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b = ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b = ?} 5}
do_test vtab1-3.10 {
  set echo_module ""
  execsql {
    SELECT * FROM t1 WHERE b >= 5 AND b <= 10;
  }
} {4 5 6}
do_test vtab1-3.11 {
  set echo_module

} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 5 10}
do_test vtab1-3.12 {
  set echo_module ""
  execsql {
    SELECT * FROM t1 WHERE b BETWEEN 2 AND 10;
  }
} {1 2 3 4 5 6}
do_test vtab1-3.13 {
  set echo_module

} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 2 10}

finish_test