xref: /sqlite-3.40.0/test/vt02.c (revision 053bb22f)
171b65e88Sdrh /*
271b65e88Sdrh ** This file implements an eponymous, read-only table-valued function
371b65e88Sdrh ** (a virtual table) designed to be used for testing.  We are not aware
471b65e88Sdrh ** of any practical real-world use case for the virtual table.
571b65e88Sdrh **
671b65e88Sdrh ** This virtual table originated in the TH3 test suite.  It is still used
771b65e88Sdrh ** there, but has now been copied into the public SQLite source tree and
871b65e88Sdrh ** reused for a variety of testing purpose.  The name "vt02" comes from the
971b65e88Sdrh ** fact that there are many different testing virtual tables in TH3, of which
1071b65e88Sdrh ** this one is the second.
1171b65e88Sdrh **
1271b65e88Sdrh ** ## SUBJECT TO CHANGE
1371b65e88Sdrh **
1471b65e88Sdrh ** Because this virtual table is intended for testing, its interface is not
1571b65e88Sdrh ** guaranteed to be stable across releases.  Future releases may contain
1671b65e88Sdrh ** changes in the vt02 design and interface.
1771b65e88Sdrh **
1871b65e88Sdrh ** ## OVERVIEW
1971b65e88Sdrh **
2071b65e88Sdrh ** The vt02 table-valued function has 10000 rows with 5 data columns.
2171b65e88Sdrh ** Column X contains all integer values between 0 and 9999 inclusive.
2271b65e88Sdrh ** Columns A, B, C, and D contain the individual base-10 digits associated
2371b65e88Sdrh ** with each X value:
2471b65e88Sdrh **
2571b65e88Sdrh **      X     A  B  C  D
2671b65e88Sdrh **      ----  -  -  -  -
2771b65e88Sdrh **      0     0  0  0  0
2871b65e88Sdrh **      1     0  0  0  1
2971b65e88Sdrh **      2     0  0  0  2
3071b65e88Sdrh **              ...
3171b65e88Sdrh **      4998  4  9  9  8
3271b65e88Sdrh **      4999  4  9  9  9
3371b65e88Sdrh **      5000  5  0  0  0
3471b65e88Sdrh **              ...
3571b65e88Sdrh **      9995  9  9  9  5
3671b65e88Sdrh **      9996  9  9  9  6
3771b65e88Sdrh **      9997  9  9  9  7
3871b65e88Sdrh **
3971b65e88Sdrh ** The xBestIndex method recognizes a variety of equality constraints
4071b65e88Sdrh ** and attempts to optimize its output accordingly.
4171b65e88Sdrh **
4271b65e88Sdrh **      x=...
4371b65e88Sdrh **      a=...
4471b65e88Sdrh **      a=... AND b=...
4571b65e88Sdrh **      a=... AND b=... AND c=...
4671b65e88Sdrh **      a=... AND b=... AND c=... AND d=...
4771b65e88Sdrh **
4871b65e88Sdrh ** Various ORDER BY constraints are also recognized and consumed.  The
4971b65e88Sdrh ** OFFSET constraint is recognized and consumed.
5071b65e88Sdrh **
5171b65e88Sdrh ** ## TABLE-VALUED FUNCTION
5271b65e88Sdrh **
5371b65e88Sdrh ** The vt02 virtual table is eponymous and has two hidden columns, meaning
5471b65e88Sdrh ** that it can functions a table-valued function.  The two hidden columns
5571b65e88Sdrh ** are "flags" and "logtab", in that order.  The "flags" column can be set
5671b65e88Sdrh ** to an integer where various bits enable or disable behaviors of the
5771b65e88Sdrh ** virtual table.  The "logtab" can set to the name of an ordinary SQLite
5871b65e88Sdrh ** table into which is written information about each call to xBestIndex.
5971b65e88Sdrh **
6071b65e88Sdrh ** The bits of "flags" are as follows:
6171b65e88Sdrh **
6271b65e88Sdrh **       0x01           Ignore the aConstraint[].usable flag.  This might
6371b65e88Sdrh **                      result in the xBestIndex method incorrectly using
6471b65e88Sdrh **                      unusable entries in the aConstraint[] array, which
6571b65e88Sdrh **                      should result in the SQLite core detecting and
6671b65e88Sdrh **                      reporting that the virtual table is not behaving
6771b65e88Sdrh **                      to spec.
6871b65e88Sdrh **
6971b65e88Sdrh **       0x02           Do not set the orderByConsumed flag, even if it
7071b65e88Sdrh **                      could be set.
7171b65e88Sdrh **
7271b65e88Sdrh **       0x04           Do not consume the OFFSET constraint, if there is
7371b65e88Sdrh **                      one.  Instead, let the generated byte-code visit
7471b65e88Sdrh **                      and ignore the first few columns of output.
7571b65e88Sdrh **
7671b65e88Sdrh **       0x08           Use sqlite3_mprintf() to allocate an idxStr string.
7771b65e88Sdrh **                      The string is never used, but allocating it does
7871b65e88Sdrh **                      test the idxStr deallocation logic inside of the
7971b65e88Sdrh **                      SQLite core.
8071b65e88Sdrh **
8171b65e88Sdrh **       0x10           Cause the xBestIndex method to generate an idxNum
8271b65e88Sdrh **                      that xFilter does not understand, thus causing
8371b65e88Sdrh **                      the OP_VFilter opcode to raise an error.
8471b65e88Sdrh **
8571b65e88Sdrh **       0x20           Set the omit flag for all equality constraints on
8671b65e88Sdrh **                      columns X, A, B, C, and D that are used to limit
8771b65e88Sdrh **                      the search.
8871b65e88Sdrh **
8971b65e88Sdrh **       0x40           Add all constraints against X,A,B,C,D to the
9071b65e88Sdrh **                      vector of results sent to xFilter.  Only the first
9171b65e88Sdrh **                      few are used, as required by idxNum.
9271b65e88Sdrh **
9371b65e88Sdrh ** Because these flags take effect during xBestIndex, the RHS of the
9471b65e88Sdrh ** flag= constraint must be accessible.  In other words, the RHS of flag=
9571b65e88Sdrh ** needs to be an integer literal, not another column of a join or a
9671b65e88Sdrh ** bound parameter.
9771b65e88Sdrh **
9871b65e88Sdrh ** ## LOGGING OUTPUT
9971b65e88Sdrh **
10071b65e88Sdrh ** If the "logtab" columns is set, then each call to the xBestIndex method
10171b65e88Sdrh ** inserts multiple rows into the table identified by "logtab".  These
10271b65e88Sdrh ** rows collectively show the content of the sqlite3_index_info object and
10371b65e88Sdrh ** other context associated with the xBestIndex call.
10471b65e88Sdrh **
10571b65e88Sdrh ** If the table named by "logtab" does not previously exist, it is created
10671b65e88Sdrh ** automatically.  The schema for the logtab table is like this:
10771b65e88Sdrh **
10871b65e88Sdrh **   CREATE TEMP TABLE vt02_log(
10971b65e88Sdrh **     bi INT,         -- BestIndex call counter
11071b65e88Sdrh **     vn TEXT,        -- Variable Name
11171b65e88Sdrh **     ix INT,         -- Index or value
11271b65e88Sdrh **     cn TEXT,        -- Column Name
11371b65e88Sdrh **     op INT,         -- Opcode or "DESC" value
11471b65e88Sdrh **     ux INT,         -- "Usable" flag
11571b65e88Sdrh **     ra BOOLEAN,     -- Right-hand side Available.
11671b65e88Sdrh **     rhs ANY,        -- Right-Hand Side value
11771b65e88Sdrh **     cs TEXT         -- Collating Sequence for this constraint
11871b65e88Sdrh **  );
11971b65e88Sdrh **
12071b65e88Sdrh ** Because logging happens during xBestIindex, the RHS value of "logtab" must
12171b65e88Sdrh ** be known to xBestIndex, which means it must be a string literal, not a
12271b65e88Sdrh ** column in a join, or a bound parameter.
12371b65e88Sdrh **
12471b65e88Sdrh ** ## VIRTUAL TABLE SCHEMA
12571b65e88Sdrh **
12671b65e88Sdrh **    CREATE TABLE vt02(
12771b65e88Sdrh **      x INT,              -- integer between 0 and 9999 inclusive
12871b65e88Sdrh **      a INT,              -- The 1000s digit
12971b65e88Sdrh **      b INT,              -- The 100s digit
13071b65e88Sdrh **      c INT,              -- The 10s digit
13171b65e88Sdrh **      d INT,              -- The 1s digit
13271b65e88Sdrh **      flags INT HIDDEN,   -- Option flags
13371b65e88Sdrh **      logtab TEXT HIDDEN, -- Name of table into which to log xBestIndex
13471b65e88Sdrh **    );
13571b65e88Sdrh **
13671b65e88Sdrh ** ## COMPILING AND RUNNING
13771b65e88Sdrh **
13871b65e88Sdrh ** This file can also be compiled separately as a loadable extension
13971b65e88Sdrh ** for SQLite (as long as the -DTH3_VERSION is not defined).  To compile as a
14071b65e88Sdrh ** loadable extension do his:
14171b65e88Sdrh **
14271b65e88Sdrh **    gcc -Wall -g -shared -fPIC -I. -DSQLITE_DEBUG vt02.c -o vt02.so
14371b65e88Sdrh **
14471b65e88Sdrh ** Or on Windows:
14571b65e88Sdrh **
14671b65e88Sdrh **    cl vt02.c -link -dll -out:vt02.dll
14771b65e88Sdrh **
14871b65e88Sdrh ** Then load into the CLI using:
14971b65e88Sdrh **
15071b65e88Sdrh **    .load ./vt02 sqlite3_vt02_init
15171b65e88Sdrh **
15271b65e88Sdrh ** ## IDXNUM SUMMARY
15371b65e88Sdrh **
15471b65e88Sdrh ** The xBestIndex method communicates the query plan to xFilter using
15571b65e88Sdrh ** the idxNum value, as follows:
15671b65e88Sdrh **
15771b65e88Sdrh **     0           unconstrained
15871b65e88Sdrh **     1           X=argv[0]
15971b65e88Sdrh **     2           A=argv[0]
16071b65e88Sdrh **     3           A=argv[0], B=argv[1]
16171b65e88Sdrh **     4           A=argv[0], B=argv[1], C=argv[2]
16271b65e88Sdrh **     5           A=argv[0], B=argv[1], C=argv[2], D=argv[3]
16371b65e88Sdrh **     6           A=argv[0], D IN argv[2]
16471b65e88Sdrh **     7           A=argv[0], B=argv[2], D IN argv[3]
16571b65e88Sdrh **     8           A=argv[0], B=argv[2], C=argv[3], D IN argv[4]
16671b65e88Sdrh **    1x           increment by 10
16771b65e88Sdrh **    2x           increment by 100
16871b65e88Sdrh **    3x           increment by 1000
16971b65e88Sdrh **   1xx           Use offset provided by argv[N]
17071b65e88Sdrh */
17171b65e88Sdrh #ifndef TH3_VERSION
17271b65e88Sdrh   /* These bits for separate compilation as a loadable extension, only */
17371b65e88Sdrh   #include "sqlite3ext.h"
17471b65e88Sdrh   SQLITE_EXTENSION_INIT1
17571b65e88Sdrh   #include <stdlib.h>
17671b65e88Sdrh   #include <string.h>
17771b65e88Sdrh   #include <assert.h>
17871b65e88Sdrh #endif
17971b65e88Sdrh 
18071b65e88Sdrh /* Forward declarations */
18171b65e88Sdrh typedef struct vt02_vtab vt02_vtab;
18271b65e88Sdrh typedef struct vt02_cur vt02_cur;
18371b65e88Sdrh 
18471b65e88Sdrh /*
18571b65e88Sdrh ** The complete virtual table
18671b65e88Sdrh */
18771b65e88Sdrh struct vt02_vtab {
18871b65e88Sdrh   sqlite3_vtab parent;        /* Base clase.  Must be first. */
18971b65e88Sdrh   sqlite3 *db;                /* Database connection */
19071b65e88Sdrh   int busy;                   /* Currently running xBestIndex */
19171b65e88Sdrh };
19271b65e88Sdrh 
19371b65e88Sdrh #define VT02_IGNORE_USABLE  0x0001  /* Ignore usable flags */
19471b65e88Sdrh #define VT02_NO_SORT_OPT    0x0002  /* Do not do any sorting optimizations */
19571b65e88Sdrh #define VT02_NO_OFFSET      0x0004  /* Omit the offset optimization */
19671b65e88Sdrh #define VT02_ALLOC_IDXSTR   0x0008  /* Alloate an idxStr */
19771b65e88Sdrh #define VT02_BAD_IDXNUM     0x0010  /* Generate an invalid idxNum */
19871b65e88Sdrh 
19971b65e88Sdrh /*
20071b65e88Sdrh ** A cursor
20171b65e88Sdrh */
20271b65e88Sdrh struct vt02_cur {
20371b65e88Sdrh   sqlite3_vtab_cursor parent; /* Base class.  Must be first */
20471b65e88Sdrh   sqlite3_int64 i;            /* Current entry */
20571b65e88Sdrh   sqlite3_int64 iEof;         /* Indicate EOF when reaching this value */
20671b65e88Sdrh   int iIncr;                  /* Amount by which to increment */
20771b65e88Sdrh   unsigned int mD;            /* Mask of allowed D-column values */
20871b65e88Sdrh };
20971b65e88Sdrh 
21071b65e88Sdrh /* The xConnect method */
vt02Connect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)21171b65e88Sdrh int vt02Connect(
21271b65e88Sdrh   sqlite3 *db,                /* The database connection */
21371b65e88Sdrh   void *pAux,                 /* Pointer to an alternative schema */
21471b65e88Sdrh   int argc,                   /* Number of arguments */
21571b65e88Sdrh   const char *const*argv,     /* Text of the arguments */
21671b65e88Sdrh   sqlite3_vtab **ppVTab,      /* Write the new vtab here */
21771b65e88Sdrh   char **pzErr                /* Error message written here */
21871b65e88Sdrh ){
21971b65e88Sdrh   vt02_vtab *pVtab;
22071b65e88Sdrh   int rc;
22171b65e88Sdrh   const char *zSchema = (const char*)pAux;
22271b65e88Sdrh   static const char zDefaultSchema[] =
22371b65e88Sdrh     "CREATE TABLE x(x INT, a INT, b INT, c INT, d INT,"
22471b65e88Sdrh     " flags INT HIDDEN, logtab TEXT HIDDEN);";
22571b65e88Sdrh #define VT02_COL_X       0
22671b65e88Sdrh #define VT02_COL_A       1
22771b65e88Sdrh #define VT02_COL_B       2
22871b65e88Sdrh #define VT02_COL_C       3
22971b65e88Sdrh #define VT02_COL_D       4
23071b65e88Sdrh #define VT02_COL_FLAGS   5
23171b65e88Sdrh #define VT02_COL_LOGTAB  6
23271b65e88Sdrh #define VT02_COL_NONE    7
23371b65e88Sdrh 
23471b65e88Sdrh   pVtab = sqlite3_malloc( sizeof(*pVtab) );
23571b65e88Sdrh   if( pVtab==0 ){
23671b65e88Sdrh     *pzErr = sqlite3_mprintf("out of memory");
23771b65e88Sdrh     return SQLITE_NOMEM;
23871b65e88Sdrh   }
23971b65e88Sdrh   memset(pVtab, 0, sizeof(*pVtab));
24071b65e88Sdrh   pVtab->db = db;
24171b65e88Sdrh   rc = sqlite3_declare_vtab(db, zSchema ? zSchema : zDefaultSchema);
24271b65e88Sdrh   if( rc ){
24371b65e88Sdrh     sqlite3_free(pVtab);
24471b65e88Sdrh   }else{
24571b65e88Sdrh     *ppVTab = &pVtab->parent;
24671b65e88Sdrh   }
24771b65e88Sdrh   return rc;
24871b65e88Sdrh }
24971b65e88Sdrh 
25071b65e88Sdrh /* the xDisconnect method
25171b65e88Sdrh */
vt02Disconnect(sqlite3_vtab * pVTab)25271b65e88Sdrh int vt02Disconnect(sqlite3_vtab *pVTab){
25371b65e88Sdrh   sqlite3_free(pVTab);
25471b65e88Sdrh   return SQLITE_OK;
25571b65e88Sdrh }
25671b65e88Sdrh 
25771b65e88Sdrh /* Put an error message into the zErrMsg string of the virtual table.
25871b65e88Sdrh */
vt02ErrMsg(sqlite3_vtab * pVtab,const char * zFormat,...)25971b65e88Sdrh static void vt02ErrMsg(sqlite3_vtab *pVtab, const char *zFormat, ...){
26071b65e88Sdrh   va_list ap;
26171b65e88Sdrh   sqlite3_free(pVtab->zErrMsg);
26271b65e88Sdrh   va_start(ap, zFormat);
26371b65e88Sdrh   pVtab->zErrMsg = sqlite3_vmprintf(zFormat, ap);
26471b65e88Sdrh   va_end(ap);
26571b65e88Sdrh }
26671b65e88Sdrh 
26771b65e88Sdrh 
26871b65e88Sdrh /* Open a cursor for scanning
26971b65e88Sdrh */
vt02Open(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)27071b65e88Sdrh static int vt02Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
27171b65e88Sdrh   vt02_cur *pCur;
27271b65e88Sdrh   pCur = sqlite3_malloc( sizeof(*pCur) );
27371b65e88Sdrh   if( pCur==0 ){
27471b65e88Sdrh     vt02ErrMsg(pVTab, "out of memory");
27571b65e88Sdrh     return SQLITE_NOMEM;
27671b65e88Sdrh   }
27771b65e88Sdrh   *ppCursor = &pCur->parent;
27871b65e88Sdrh   pCur->i = -1;
27971b65e88Sdrh   return SQLITE_OK;
28071b65e88Sdrh }
28171b65e88Sdrh 
28271b65e88Sdrh /* Close a cursor
28371b65e88Sdrh */
vt02Close(sqlite3_vtab_cursor * pCursor)28471b65e88Sdrh static int vt02Close(sqlite3_vtab_cursor *pCursor){
28571b65e88Sdrh   vt02_cur *pCur = (vt02_cur*)pCursor;
28671b65e88Sdrh   sqlite3_free(pCur);
28771b65e88Sdrh   return SQLITE_OK;
28871b65e88Sdrh }
28971b65e88Sdrh 
29071b65e88Sdrh /* Return TRUE if we are at the end of the BVS and there are
29171b65e88Sdrh ** no more entries.
29271b65e88Sdrh */
vt02Eof(sqlite3_vtab_cursor * pCursor)29371b65e88Sdrh static int vt02Eof(sqlite3_vtab_cursor *pCursor){
29471b65e88Sdrh   vt02_cur *pCur = (vt02_cur*)pCursor;
29571b65e88Sdrh   return pCur->i<0 || pCur->i>=pCur->iEof;
29671b65e88Sdrh }
29771b65e88Sdrh 
29871b65e88Sdrh /* Advance the cursor to the next row in the table
29971b65e88Sdrh */
vt02Next(sqlite3_vtab_cursor * pCursor)30071b65e88Sdrh static int vt02Next(sqlite3_vtab_cursor *pCursor){
30171b65e88Sdrh   vt02_cur *pCur = (vt02_cur*)pCursor;
30271b65e88Sdrh   do{
30371b65e88Sdrh     pCur->i += pCur->iIncr;
30471b65e88Sdrh     if( pCur->i<0 ) pCur->i = pCur->iEof;
30571b65e88Sdrh   }while( (pCur->mD & (1<<(pCur->i%10)))==0 && pCur->i<pCur->iEof );
30671b65e88Sdrh   return SQLITE_OK;
30771b65e88Sdrh }
30871b65e88Sdrh 
30971b65e88Sdrh /* Rewind a cursor back to the beginning of its scan.
31071b65e88Sdrh **
31171b65e88Sdrh ** Scanning is always increasing.
31271b65e88Sdrh **
31371b65e88Sdrh **   idxNum
31471b65e88Sdrh **     0           unconstrained
31571b65e88Sdrh **     1           X=argv[0]
31671b65e88Sdrh **     2           A=argv[0]
31771b65e88Sdrh **     3           A=argv[0], B=argv[1]
31871b65e88Sdrh **     4           A=argv[0], B=argv[1], C=argv[2]
31971b65e88Sdrh **     5           A=argv[0], B=argv[1], C=argv[2], D=argv[3]
32071b65e88Sdrh **     6           A=argv[0], D IN argv[2]
32171b65e88Sdrh **     7           A=argv[0], B=argv[2], D IN argv[3]
32271b65e88Sdrh **     8           A=argv[0], B=argv[2], C=argv[3], D IN argv[4]
32371b65e88Sdrh **    1x           increment by 10
32471b65e88Sdrh **    2x           increment by 100
32571b65e88Sdrh **    3x           increment by 1000
32671b65e88Sdrh **   1xx           Use offset provided by argv[N]
32771b65e88Sdrh */
vt02Filter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)32871b65e88Sdrh static int vt02Filter(
32971b65e88Sdrh   sqlite3_vtab_cursor *pCursor, /* The cursor to rewind */
33071b65e88Sdrh   int idxNum,                   /* Search strategy */
33171b65e88Sdrh   const char *idxStr,           /* Not used */
33271b65e88Sdrh   int argc,                     /* Not used */
33371b65e88Sdrh   sqlite3_value **argv          /* Not used */
33471b65e88Sdrh ){
33571b65e88Sdrh   vt02_cur *pCur = (vt02_cur*)pCursor; /* The vt02 cursor */
33671b65e88Sdrh   int bUseOffset = 0;                  /* True to use OFFSET value */
33771b65e88Sdrh   int iArg = 0;                        /* argv[] values used so far */
33871b65e88Sdrh   int iOrigIdxNum = idxNum;            /* Original value for idxNum */
33971b65e88Sdrh 
34071b65e88Sdrh   pCur->iIncr = 1;
34171b65e88Sdrh   pCur->mD = 0x3ff;
34271b65e88Sdrh   if( idxNum>=100 ){
34371b65e88Sdrh     bUseOffset = 1;
34471b65e88Sdrh     idxNum -= 100;
34571b65e88Sdrh   }
34671b65e88Sdrh   if( idxNum<0 || idxNum>38 ) goto vt02_bad_idxnum;
34771b65e88Sdrh   while( idxNum>=10 ){
34871b65e88Sdrh     pCur->iIncr *= 10;
34971b65e88Sdrh     idxNum -= 10;
35071b65e88Sdrh   }
35171b65e88Sdrh   if( idxNum==0 ){
35271b65e88Sdrh     pCur->i = 0;
35371b65e88Sdrh     pCur->iEof = 10000;
35471b65e88Sdrh   }else if( idxNum==1 ){
35571b65e88Sdrh     pCur->i = sqlite3_value_int64(argv[0]);
35671b65e88Sdrh     if( pCur->i<0 ) pCur->i = -1;
35771b65e88Sdrh     if( pCur->i>9999 ) pCur->i = 10000;
35871b65e88Sdrh     pCur->iEof = pCur->i+1;
35971b65e88Sdrh     if( pCur->i<0 || pCur->i>9999 ) pCur->i = pCur->iEof;
36071b65e88Sdrh   }else if( idxNum>=2 && idxNum<=5 ){
36171b65e88Sdrh     int i, e, m;
36271b65e88Sdrh     e = idxNum - 2;
36371b65e88Sdrh     assert( e<=argc-1 );
36471b65e88Sdrh     pCur->i = 0;
36571b65e88Sdrh     for(m=1000, i=0; i<=e; i++, m /= 10){
36671b65e88Sdrh       sqlite3_int64 v = sqlite3_value_int64(argv[iArg++]);
36771b65e88Sdrh       if( v<0 ) v = 0;
36871b65e88Sdrh       if( v>9 ) v = 9;
36971b65e88Sdrh       pCur->i += m*v;
37071b65e88Sdrh       pCur->iEof = pCur->i+m;
37171b65e88Sdrh     }
37271b65e88Sdrh   }else if( idxNum>=6 && idxNum<=8 ){
37371b65e88Sdrh     int i, e, m, rc;
37471b65e88Sdrh     sqlite3_value *pIn, *pVal;
37571b65e88Sdrh     e = idxNum - 6;
37671b65e88Sdrh     assert( e<=argc-2 );
37771b65e88Sdrh     pCur->i = 0;
37871b65e88Sdrh     for(m=1000, i=0; i<=e; i++, m /= 10){
37971b65e88Sdrh       sqlite3_int64 v;
380*053bb22fSdrh       pVal = 0;
38171b65e88Sdrh       if( sqlite3_vtab_in_first(0, &pVal)!=SQLITE_MISUSE
38271b65e88Sdrh        || sqlite3_vtab_in_first(argv[iArg], &pVal)!=SQLITE_MISUSE
38371b65e88Sdrh       ){
38471b65e88Sdrh         vt02ErrMsg(pCursor->pVtab,
38571b65e88Sdrh                 "unexpected success from sqlite3_vtab_in_first()");
38671b65e88Sdrh         return SQLITE_ERROR;
38771b65e88Sdrh       }
38871b65e88Sdrh       v = sqlite3_value_int64(argv[iArg++]);
38971b65e88Sdrh       if( v<0 ) v = 0;
39071b65e88Sdrh       if( v>9 ) v = 9;
39171b65e88Sdrh       pCur->i += m*v;
39271b65e88Sdrh       pCur->iEof = pCur->i+m;
39371b65e88Sdrh     }
39471b65e88Sdrh     pCur->mD = 0;
39571b65e88Sdrh     pIn = argv[iArg++];
39671b65e88Sdrh     assert( sqlite3_value_type(pIn)==SQLITE_NULL );
39771b65e88Sdrh     for( rc = sqlite3_vtab_in_first(pIn, &pVal);
39871b65e88Sdrh          rc==SQLITE_OK && pVal!=0;
39971b65e88Sdrh          rc = sqlite3_vtab_in_next(pIn, &pVal)
40071b65e88Sdrh     ){
40171b65e88Sdrh       int eType = sqlite3_value_numeric_type(pVal);
40271b65e88Sdrh       if( eType==SQLITE_FLOAT ){
40371b65e88Sdrh         double r = sqlite3_value_double(pVal);
40471b65e88Sdrh         if( r<0.0 || r>9.0 || r!=(int)r ) continue;
40571b65e88Sdrh       }else if( eType!=SQLITE_INTEGER ){
40671b65e88Sdrh         continue;
40771b65e88Sdrh       }
40871b65e88Sdrh       i = sqlite3_value_int(pVal);
40971b65e88Sdrh       if( i<0 || i>9 ) continue;
41071b65e88Sdrh       pCur->mD |= 1<<i;
41171b65e88Sdrh     }
41271b65e88Sdrh     if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){
41371b65e88Sdrh       vt02ErrMsg(pCursor->pVtab, "Error from sqlite3_vtab_in_first/next()");
41471b65e88Sdrh       return rc;
41571b65e88Sdrh     }
41671b65e88Sdrh   }else{
41771b65e88Sdrh     goto vt02_bad_idxnum;
41871b65e88Sdrh   }
41971b65e88Sdrh   if( bUseOffset ){
42071b65e88Sdrh     int nSkip = sqlite3_value_int(argv[iArg]);
42171b65e88Sdrh     while( nSkip-- > 0 ) vt02Next(pCursor);
42271b65e88Sdrh   }
42371b65e88Sdrh   return SQLITE_OK;
42471b65e88Sdrh 
42571b65e88Sdrh vt02_bad_idxnum:
42671b65e88Sdrh   vt02ErrMsg(pCursor->pVtab, "invalid idxNum for vt02: %d", iOrigIdxNum);
42771b65e88Sdrh   return SQLITE_ERROR;
42871b65e88Sdrh }
42971b65e88Sdrh 
43071b65e88Sdrh /* Return the Nth column of the current row.
43171b65e88Sdrh */
vt02Column(sqlite3_vtab_cursor * pCursor,sqlite3_context * context,int N)43271b65e88Sdrh static int vt02Column(
43371b65e88Sdrh   sqlite3_vtab_cursor *pCursor,
43471b65e88Sdrh   sqlite3_context *context,
43571b65e88Sdrh   int N
43671b65e88Sdrh ){
43771b65e88Sdrh   vt02_cur *pCur = (vt02_cur*)pCursor;
43871b65e88Sdrh   int v = pCur->i;
43971b65e88Sdrh   if( N==VT02_COL_X ){
44071b65e88Sdrh     sqlite3_result_int(context, v);
44171b65e88Sdrh   }else if( N>=VT02_COL_A && N<=VT02_COL_D ){
44271b65e88Sdrh     static const int iDivisor[] = { 1, 1000, 100, 10, 1 };
44371b65e88Sdrh     v = (v/iDivisor[N])%10;
44471b65e88Sdrh     sqlite3_result_int(context, v);
44571b65e88Sdrh   }
44671b65e88Sdrh   return SQLITE_OK;
44771b65e88Sdrh }
44871b65e88Sdrh 
44971b65e88Sdrh /* Return the rowid of the current row
45071b65e88Sdrh */
vt02Rowid(sqlite3_vtab_cursor * pCursor,sqlite3_int64 * pRowid)45171b65e88Sdrh static int vt02Rowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid){
45271b65e88Sdrh   vt02_cur *pCur = (vt02_cur*)pCursor;
45371b65e88Sdrh   *pRowid = pCur->i+1;
45471b65e88Sdrh   return SQLITE_OK;
45571b65e88Sdrh }
45671b65e88Sdrh 
45771b65e88Sdrh /*************************************************************************
45871b65e88Sdrh ** Logging Subsystem
45971b65e88Sdrh **
46071b65e88Sdrh ** The sqlite3BestIndexLog() routine implements a logging system for
46171b65e88Sdrh ** xBestIndex calls.  This code is portable to any virtual table.
46271b65e88Sdrh **
46371b65e88Sdrh ** sqlite3BestIndexLog() is the main routine,  sqlite3RunSql() is a
46471b65e88Sdrh ** helper routine used for running various SQL statements as part of
46571b65e88Sdrh ** creating the log.
46671b65e88Sdrh **
46771b65e88Sdrh ** These two routines should be portable to other virtual tables.  Simply
46871b65e88Sdrh ** extract this code and call sqlite3BestIndexLog() near the end of the
46971b65e88Sdrh ** xBestIndex method in cases where logging is desired.
47071b65e88Sdrh */
47171b65e88Sdrh /*
47271b65e88Sdrh ** Run SQL on behalf of sqlite3BestIndexLog.
47371b65e88Sdrh **
47471b65e88Sdrh ** Construct the SQL using the zFormat string and subsequent arguments.
47571b65e88Sdrh ** Or if zFormat is NULL, take the SQL as the first argument after the
47671b65e88Sdrh ** zFormat.  In either case, the dynamically allocated SQL string is
47771b65e88Sdrh ** freed after it has been run.  If something goes wrong with the SQL,
47871b65e88Sdrh ** then an error is left in pVTab->zErrMsg.
47971b65e88Sdrh */
sqlite3RunSql(sqlite3 * db,sqlite3_vtab * pVTab,const char * zFormat,...)48071b65e88Sdrh static void sqlite3RunSql(
48171b65e88Sdrh   sqlite3 *db,               /* Run the SQL on this database connection */
48271b65e88Sdrh   sqlite3_vtab *pVTab,       /* Report errors to this virtual table */
48371b65e88Sdrh   const char *zFormat,       /* Format string for SQL, or NULL */
48471b65e88Sdrh   ...                        /* Arguments, according to the format string */
48571b65e88Sdrh ){
48671b65e88Sdrh   char *zSql;
48771b65e88Sdrh 
48871b65e88Sdrh   va_list ap;
48971b65e88Sdrh   va_start(ap, zFormat);
49071b65e88Sdrh   if( zFormat==0 ){
49171b65e88Sdrh     zSql = va_arg(ap, char*);
49271b65e88Sdrh   }else{
49371b65e88Sdrh     zSql = sqlite3_vmprintf(zFormat, ap);
49471b65e88Sdrh   }
49571b65e88Sdrh   va_end(ap);
49671b65e88Sdrh   if( zSql ){
49771b65e88Sdrh     char *zErrMsg = 0;
49871b65e88Sdrh     (void)sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
49971b65e88Sdrh     if( zErrMsg ){
50071b65e88Sdrh       if( pVTab->zErrMsg==0 ){
50171b65e88Sdrh         pVTab->zErrMsg = sqlite3_mprintf("%s in [%s]", zErrMsg, zSql);
50271b65e88Sdrh       }
50371b65e88Sdrh       sqlite3_free(zErrMsg);
50471b65e88Sdrh     }
50571b65e88Sdrh     sqlite3_free(zSql);
50671b65e88Sdrh   }
50771b65e88Sdrh }
50871b65e88Sdrh 
50971b65e88Sdrh /*
51071b65e88Sdrh ** Record information about each xBestIndex method call in a separate
51171b65e88Sdrh ** table:
51271b65e88Sdrh **
51371b65e88Sdrh **   CREATE TEMP TABLE [log-table-name] (
51471b65e88Sdrh **     bi INT,      -- BestIndex call number
51571b65e88Sdrh **     vn TEXT,     -- Variable Name
51671b65e88Sdrh **     ix INT,      -- Index or value
51771b65e88Sdrh **     cn TEXT,     -- Column Name
51871b65e88Sdrh **     op INT,      -- Opcode or argvIndex
51971b65e88Sdrh **     ux INT,      -- "usable" or "omit" flag
52071b65e88Sdrh **     rx BOOLEAN,  -- True if has a RHS value
52171b65e88Sdrh **     rhs ANY,     -- The RHS value
52271b65e88Sdrh **     cs TEXT,     -- Collating Sequence
52371b65e88Sdrh **     inop BOOLEAN -- True if this is a batchable IN operator
52471b65e88Sdrh **  );
52571b65e88Sdrh **
52671b65e88Sdrh ** If an error occurs, leave an error message in pVTab->zErrMsg.
52771b65e88Sdrh */
sqlite3BestIndexLog(sqlite3_index_info * pInfo,const char * zLogTab,sqlite3 * db,const char ** azColname,sqlite3_vtab * pVTab)52871b65e88Sdrh static void sqlite3BestIndexLog(
52971b65e88Sdrh   sqlite3_index_info *pInfo,  /* The sqlite3_index_info object */
53071b65e88Sdrh   const char *zLogTab,        /* Log into this table */
53171b65e88Sdrh   sqlite3 *db,                /* Database connection containing zLogTab */
53271b65e88Sdrh   const char **azColname,     /* Names of columns in the virtual table */
53371b65e88Sdrh   sqlite3_vtab *pVTab         /* Record errors into this object */
53471b65e88Sdrh ){
53571b65e88Sdrh   int i, rc;
53671b65e88Sdrh   sqlite3_str *pStr;
53771b65e88Sdrh   int iBI;
53871b65e88Sdrh 
53971b65e88Sdrh   if( sqlite3_table_column_metadata(db,0,zLogTab,0,0,0,0,0,0) ){
54071b65e88Sdrh     /* The log table does not previously exist.  Create it. */
54171b65e88Sdrh     sqlite3RunSql(db,pVTab,
54271b65e88Sdrh       "CREATE TABLE IF NOT EXISTS temp.\"%w\"(\n"
54371b65e88Sdrh       " bi INT,          -- BestIndex call number\n"
54471b65e88Sdrh       " vn TEXT,         -- Variable Name\n"
54571b65e88Sdrh       " ix INT,          -- Index or value\n"
54671b65e88Sdrh       " cn TEXT,         -- Column Name\n"
54771b65e88Sdrh       " op INT,          -- Opcode or argvIndex\n"
54871b65e88Sdrh       " ux INT,          -- usable for omit flag\n"
54971b65e88Sdrh       " rx BOOLEAN,      -- Right-hand side value is available\n"
55071b65e88Sdrh       " rhs ANY,         -- RHS value\n"
55171b65e88Sdrh       " cs TEXT,         -- Collating Sequence\n"
55271b65e88Sdrh       " inop BOOLEAN     -- IN operator capable of batch reads\n"
55371b65e88Sdrh       ");", zLogTab
55471b65e88Sdrh     );
55571b65e88Sdrh     iBI = 1;
55671b65e88Sdrh   }else{
55771b65e88Sdrh     /* The log table does already exist.  We assume that it has the
55871b65e88Sdrh     ** correct schema and proceed to find the largest prior "bi" value.
55971b65e88Sdrh     ** If the schema is wrong, errors might result.  The code is able
56071b65e88Sdrh     ** to deal with this. */
56171b65e88Sdrh     sqlite3_stmt *pStmt;
56271b65e88Sdrh     char *zSql;
56371b65e88Sdrh     zSql = sqlite3_mprintf("SELECT max(bi) FROM temp.\"%w\"",zLogTab);
56471b65e88Sdrh     if( zSql==0 ){
56571b65e88Sdrh       sqlite3_free(pVTab->zErrMsg);
56671b65e88Sdrh       pVTab->zErrMsg = sqlite3_mprintf("out of memory");
56771b65e88Sdrh       return;
56871b65e88Sdrh     }
56971b65e88Sdrh     rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
57071b65e88Sdrh     sqlite3_free(zSql);
57171b65e88Sdrh     if( rc ){
57271b65e88Sdrh       sqlite3_free(pVTab->zErrMsg);
57371b65e88Sdrh       pVTab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
57471b65e88Sdrh       iBI = 0;
57571b65e88Sdrh     }else if( sqlite3_step(pStmt)==SQLITE_ROW ){
57671b65e88Sdrh       iBI = sqlite3_column_int(pStmt, 0)+1;
57771b65e88Sdrh     }else{
57871b65e88Sdrh       iBI = 1;
57971b65e88Sdrh     }
58071b65e88Sdrh     sqlite3_finalize(pStmt);
58171b65e88Sdrh   }
58271b65e88Sdrh   sqlite3RunSql(db,pVTab,
58371b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'nConstraint',%d)",
58471b65e88Sdrh     zLogTab, iBI, pInfo->nConstraint
58571b65e88Sdrh   );
58671b65e88Sdrh   for(i=0; i<pInfo->nConstraint; i++){
58771b65e88Sdrh     sqlite3_value *pVal;
58871b65e88Sdrh     char *zSql;
58971b65e88Sdrh     int iCol = pInfo->aConstraint[i].iColumn;
59071b65e88Sdrh     int op = pInfo->aConstraint[i].op;
59171b65e88Sdrh     const char *zCol;
59271b65e88Sdrh     if( op==SQLITE_INDEX_CONSTRAINT_LIMIT
59371b65e88Sdrh      || op==SQLITE_INDEX_CONSTRAINT_OFFSET
59471b65e88Sdrh     ){
59571b65e88Sdrh       zCol = "";
59671b65e88Sdrh     }else if( iCol<0 ){
59771b65e88Sdrh       zCol = "rowid";
59871b65e88Sdrh     }else{
59971b65e88Sdrh       zCol = azColname[iCol];
60071b65e88Sdrh     }
60171b65e88Sdrh     pStr = sqlite3_str_new(0);
60271b65e88Sdrh     sqlite3_str_appendf(pStr,
60371b65e88Sdrh        "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op,ux,rx,rhs,cs,inop)"
60471b65e88Sdrh        "VALUES(%d,'aConstraint',%d,%Q,%d,%d",
60571b65e88Sdrh        zLogTab, iBI,
60671b65e88Sdrh        i,
60771b65e88Sdrh        zCol,
60871b65e88Sdrh        op,
60971b65e88Sdrh        pInfo->aConstraint[i].usable);
61071b65e88Sdrh     pVal = 0;
61171b65e88Sdrh     rc = sqlite3_vtab_rhs_value(pInfo, i, &pVal);
61271b65e88Sdrh     assert( pVal!=0 || rc!=SQLITE_OK );
61371b65e88Sdrh     if( rc==SQLITE_OK ){
61471b65e88Sdrh       sqlite3_str_appendf(pStr,",1,?1");
61571b65e88Sdrh     }else{
61671b65e88Sdrh       sqlite3_str_appendf(pStr,",0,NULL");
61771b65e88Sdrh     }
61871b65e88Sdrh     sqlite3_str_appendf(pStr,",%Q,%d)",
61971b65e88Sdrh          sqlite3_vtab_collation(pInfo,i),
62071b65e88Sdrh          sqlite3_vtab_in(pInfo,i,-1));
62171b65e88Sdrh     zSql = sqlite3_str_finish(pStr);
62271b65e88Sdrh     if( zSql==0 ){
62371b65e88Sdrh       if( pVTab->zErrMsg==0 ) pVTab->zErrMsg = sqlite3_mprintf("out of memory");
62471b65e88Sdrh     }else{
62571b65e88Sdrh       sqlite3_stmt *pStmt = 0;
62671b65e88Sdrh       rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
62771b65e88Sdrh       if( rc ){
62871b65e88Sdrh         if( pVTab->zErrMsg==0 ){
62971b65e88Sdrh           pVTab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
63071b65e88Sdrh         }
63171b65e88Sdrh       }else{
63271b65e88Sdrh         if( pVal ) sqlite3_bind_value(pStmt, 1, pVal);
63371b65e88Sdrh         sqlite3_step(pStmt);
63471b65e88Sdrh         rc = sqlite3_reset(pStmt);
63571b65e88Sdrh         if( rc && pVTab->zErrMsg==0 ){
63671b65e88Sdrh           pVTab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
63771b65e88Sdrh         }
63871b65e88Sdrh       }
63971b65e88Sdrh       sqlite3_finalize(pStmt);
64071b65e88Sdrh       sqlite3_free(zSql);
64171b65e88Sdrh     }
64271b65e88Sdrh   }
64371b65e88Sdrh   sqlite3RunSql(db,pVTab,
64471b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'nOrderBy',%d)",
64571b65e88Sdrh     zLogTab, iBI, pInfo->nOrderBy
64671b65e88Sdrh   );
64771b65e88Sdrh   for(i=0; i<pInfo->nOrderBy; i++){
64871b65e88Sdrh     int iCol = pInfo->aOrderBy[i].iColumn;
64971b65e88Sdrh     sqlite3RunSql(db,pVTab,
65071b65e88Sdrh       "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op)VALUES(%d,'aOrderBy',%d,%Q,%d)",
65171b65e88Sdrh       zLogTab, iBI,
65271b65e88Sdrh       i,
65371b65e88Sdrh       iCol>=0 ? azColname[iCol] : "rowid",
65471b65e88Sdrh       pInfo->aOrderBy[i].desc
65571b65e88Sdrh     );
65671b65e88Sdrh   }
65771b65e88Sdrh   sqlite3RunSql(db,pVTab,
65871b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'sqlite3_vtab_distinct',%d)",
65971b65e88Sdrh     zLogTab, iBI, sqlite3_vtab_distinct(pInfo)
66071b65e88Sdrh   );
66171b65e88Sdrh   sqlite3RunSql(db,pVTab,
66271b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'colUsed',%lld)",
66371b65e88Sdrh     zLogTab, iBI, pInfo->colUsed
66471b65e88Sdrh   );
66571b65e88Sdrh   for(i=0; i<pInfo->nConstraint; i++){
66671b65e88Sdrh     int iCol = pInfo->aConstraint[i].iColumn;
66771b65e88Sdrh     int op = pInfo->aConstraint[i].op;
66871b65e88Sdrh     const char *zCol;
66971b65e88Sdrh     if( op==SQLITE_INDEX_CONSTRAINT_LIMIT
67071b65e88Sdrh      || op==SQLITE_INDEX_CONSTRAINT_OFFSET
67171b65e88Sdrh     ){
67271b65e88Sdrh       zCol = "";
67371b65e88Sdrh     }else if( iCol<0 ){
67471b65e88Sdrh       zCol = "rowid";
67571b65e88Sdrh     }else{
67671b65e88Sdrh       zCol = azColname[iCol];
67771b65e88Sdrh     }
67871b65e88Sdrh     sqlite3RunSql(db,pVTab,
67971b65e88Sdrh        "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op,ux)"
68071b65e88Sdrh        "VALUES(%d,'aConstraintUsage',%d,%Q,%d,%d)",
68171b65e88Sdrh        zLogTab, iBI,
68271b65e88Sdrh        i,
68371b65e88Sdrh        zCol,
68471b65e88Sdrh        pInfo->aConstraintUsage[i].argvIndex,
68571b65e88Sdrh        pInfo->aConstraintUsage[i].omit
68671b65e88Sdrh     );
68771b65e88Sdrh   }
68871b65e88Sdrh   sqlite3RunSql(db,pVTab,
68971b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'idxNum',%d)",
69071b65e88Sdrh     zLogTab, iBI, pInfo->idxNum
69171b65e88Sdrh   );
69271b65e88Sdrh   sqlite3RunSql(db,pVTab,
69371b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'estimatedCost',%f)",
69471b65e88Sdrh     zLogTab, iBI, pInfo->estimatedCost
69571b65e88Sdrh   );
69671b65e88Sdrh   sqlite3RunSql(db,pVTab,
69771b65e88Sdrh     "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'estimatedRows',%lld)",
69871b65e88Sdrh     zLogTab, iBI, pInfo->estimatedRows
69971b65e88Sdrh   );
70071b65e88Sdrh   if( pInfo->idxStr ){
70171b65e88Sdrh     sqlite3RunSql(db,pVTab,
70271b65e88Sdrh       "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'idxStr',%Q)",
70371b65e88Sdrh       zLogTab, iBI, pInfo->idxStr
70471b65e88Sdrh     );
70571b65e88Sdrh     sqlite3RunSql(db,pVTab,
70671b65e88Sdrh       "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'needToFreeIdxStr',%d)",
70771b65e88Sdrh       zLogTab, iBI, pInfo->needToFreeIdxStr
70871b65e88Sdrh     );
70971b65e88Sdrh   }
71071b65e88Sdrh   if( pInfo->nOrderBy ){
71171b65e88Sdrh     sqlite3RunSql(db,pVTab,
71271b65e88Sdrh       "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'orderByConsumed',%d)",
71371b65e88Sdrh       zLogTab, iBI, pInfo->orderByConsumed
71471b65e88Sdrh     );
71571b65e88Sdrh   }
71671b65e88Sdrh }
71771b65e88Sdrh /*
71871b65e88Sdrh ** End of Logging Subsystem
71971b65e88Sdrh *****************************************************************************/
72071b65e88Sdrh 
72171b65e88Sdrh 
72271b65e88Sdrh /* Find an estimated cost of running a query against vt02.
72371b65e88Sdrh */
vt02BestIndex(sqlite3_vtab * pVTab,sqlite3_index_info * pInfo)72471b65e88Sdrh static int vt02BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
72571b65e88Sdrh   int i;                      /* Loop counter */
72671b65e88Sdrh   int isEq[5];                /* Equality constraints on X, A, B, C, and D */
72771b65e88Sdrh   int isUsed[5];              /* Other non-== cosntraints X, A, B, C, and D */
72871b65e88Sdrh   int argvIndex = 0;          /* Next available argv[] slot */
72971b65e88Sdrh   int iOffset = -1;           /* Constraint for OFFSET */
73071b65e88Sdrh   void *pX = 0;               /* idxStr value */
73171b65e88Sdrh   int flags = 0;              /* RHS value for flags= */
73271b65e88Sdrh   const char *zLogTab = 0;    /* RHS value for logtab= */
73371b65e88Sdrh   int iFlagTerm = -1;         /* Constraint term for flags= */
73471b65e88Sdrh   int iLogTerm = -1;          /* Constraint term for logtab= */
73571b65e88Sdrh   int iIn = -1;               /* Index of the IN constraint */
73671b65e88Sdrh   vt02_vtab *pSelf;           /* This virtual table */
73771b65e88Sdrh 
73871b65e88Sdrh   pSelf = (vt02_vtab*)pVTab;
73971b65e88Sdrh   if( pSelf->busy ){
74071b65e88Sdrh     vt02ErrMsg(pVTab, "recursive use  of vt02 prohibited");
74171b65e88Sdrh     return SQLITE_CONSTRAINT;
74271b65e88Sdrh   }
74371b65e88Sdrh   pSelf->busy++;
74471b65e88Sdrh 
74571b65e88Sdrh 
74671b65e88Sdrh   /* Do an initial scan for flags=N and logtab=TAB constraints with
74771b65e88Sdrh   ** usable RHS values */
74871b65e88Sdrh   for(i=0; i<pInfo->nConstraint; i++){
74971b65e88Sdrh     sqlite3_value *pVal;
75071b65e88Sdrh     if( !pInfo->aConstraint[i].usable ) continue;
75171b65e88Sdrh     if( pInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
75271b65e88Sdrh     switch( pInfo->aConstraint[i].iColumn ){
75371b65e88Sdrh       case VT02_COL_FLAGS:
75471b65e88Sdrh         if( sqlite3_vtab_rhs_value(pInfo, i, &pVal)==SQLITE_OK
75571b65e88Sdrh          && sqlite3_value_type(pVal)==SQLITE_INTEGER
75671b65e88Sdrh         ){
75771b65e88Sdrh           flags = sqlite3_value_int(pVal);
75871b65e88Sdrh         }
75971b65e88Sdrh         iFlagTerm = i;
76071b65e88Sdrh         break;
76171b65e88Sdrh       case VT02_COL_LOGTAB:
76271b65e88Sdrh         if( sqlite3_vtab_rhs_value(pInfo, i, &pVal)==SQLITE_OK
76371b65e88Sdrh          && sqlite3_value_type(pVal)==SQLITE_TEXT
76471b65e88Sdrh         ){
76571b65e88Sdrh           zLogTab = (const char*)sqlite3_value_text(pVal);
76671b65e88Sdrh         }
76771b65e88Sdrh         iLogTerm = i;
76871b65e88Sdrh         break;
76971b65e88Sdrh     }
77071b65e88Sdrh   }
77171b65e88Sdrh 
77271b65e88Sdrh   /* Do a second scan to actually analyze the index information */
77371b65e88Sdrh   memset(isEq, 0xff, sizeof(isEq));
77471b65e88Sdrh   memset(isUsed, 0xff, sizeof(isUsed));
77571b65e88Sdrh   for(i=0; i<pInfo->nConstraint; i++){
77671b65e88Sdrh     int j = pInfo->aConstraint[i].iColumn;
77771b65e88Sdrh     if( j>=VT02_COL_FLAGS ) continue;
77871b65e88Sdrh     if( pInfo->aConstraint[i].usable==0
77971b65e88Sdrh      && (flags & VT02_IGNORE_USABLE)==0 ) continue;
78071b65e88Sdrh     if( j<0 ) j = VT02_COL_X;
78171b65e88Sdrh     switch( pInfo->aConstraint[i].op ){
78271b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_FUNCTION:
78371b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_EQ:
78471b65e88Sdrh         isEq[j] = i;
78571b65e88Sdrh         break;
78671b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_LT:
78771b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_LE:
78871b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_GT:
78971b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_GE:
79071b65e88Sdrh         isUsed[j] = i;
79171b65e88Sdrh         break;
79271b65e88Sdrh       case SQLITE_INDEX_CONSTRAINT_OFFSET:
79371b65e88Sdrh         iOffset = i;
79471b65e88Sdrh         break;
79571b65e88Sdrh     }
79671b65e88Sdrh   }
79771b65e88Sdrh 
79871b65e88Sdrh   /* Use the analysis to find an appropriate query plan */
79971b65e88Sdrh   if( isEq[0]>=0 ){
80071b65e88Sdrh     /* A constraint of X= takes priority */
80171b65e88Sdrh     pInfo->estimatedCost = 1;
80271b65e88Sdrh     pInfo->aConstraintUsage[isEq[0]].argvIndex = ++argvIndex;
80371b65e88Sdrh     if( flags & 0x20 ) pInfo->aConstraintUsage[isEq[0]].omit = 1;
80471b65e88Sdrh     pInfo->idxNum = 1;
80571b65e88Sdrh   }else if( isEq[1]<0 ){
80671b65e88Sdrh     /* If there is no X= nor A= then we have to do a full scan */
80771b65e88Sdrh     pInfo->idxNum = 0;
80871b65e88Sdrh     pInfo->estimatedCost = 10000;
80971b65e88Sdrh   }else{
81071b65e88Sdrh     int v = 1000;
81171b65e88Sdrh     pInfo->aConstraintUsage[isEq[1]].argvIndex = ++argvIndex;
81271b65e88Sdrh     if( flags & 0x20 ) pInfo->aConstraintUsage[isEq[1]].omit = 1;
81371b65e88Sdrh     for(i=2; i<=4 && isEq[i]>=0; i++){
81471b65e88Sdrh       if( i==4 && sqlite3_vtab_in(pInfo, isEq[4], 0) ) break;
81571b65e88Sdrh       pInfo->aConstraintUsage[isEq[i]].argvIndex = ++argvIndex;
81671b65e88Sdrh       if( flags & 0x20 ) pInfo->aConstraintUsage[isEq[i]].omit = 1;
81771b65e88Sdrh       v /= 10;
81871b65e88Sdrh     }
81971b65e88Sdrh     pInfo->idxNum = i;
82071b65e88Sdrh     if( isEq[4]>=0 && sqlite3_vtab_in(pInfo,isEq[4],1) ){
82171b65e88Sdrh       iIn = isEq[4];
82271b65e88Sdrh       pInfo->aConstraintUsage[iIn].argvIndex = ++argvIndex;
82371b65e88Sdrh       if( flags & 0x20 ) pInfo->aConstraintUsage[iIn].omit = 1;
82471b65e88Sdrh       v /= 5;
82571b65e88Sdrh       i++;
82671b65e88Sdrh       pInfo->idxNum += 4;
82771b65e88Sdrh     }
82871b65e88Sdrh     pInfo->estimatedCost = v;
82971b65e88Sdrh   }
83071b65e88Sdrh   pInfo->estimatedRows = (sqlite3_int64)pInfo->estimatedCost;
83171b65e88Sdrh 
83271b65e88Sdrh   /* Attempt to consume the ORDER BY clause.  Except, always leave
83371b65e88Sdrh   ** orderByConsumed set to 0 for vt02_no_sort_opt.  In this way,
83471b65e88Sdrh   ** we can compare vt02 and vt02_no_sort_opt to ensure they get
83571b65e88Sdrh   ** the same answer.
83671b65e88Sdrh   */
83771b65e88Sdrh   if( pInfo->nOrderBy>0 && (flags & VT02_NO_SORT_OPT)==0 ){
83871b65e88Sdrh     if( pInfo->idxNum==1 ){
83971b65e88Sdrh       /* There will only be one row of output.  So it is always sorted. */
84071b65e88Sdrh       pInfo->orderByConsumed = 1;
84171b65e88Sdrh     }else
84271b65e88Sdrh     if( pInfo->aOrderBy[0].iColumn<=0
84371b65e88Sdrh      && pInfo->aOrderBy[0].desc==0
84471b65e88Sdrh     ){
84571b65e88Sdrh       /* First column of order by is X ascending */
84671b65e88Sdrh       pInfo->orderByConsumed = 1;
84771b65e88Sdrh     }else
84871b65e88Sdrh     if( sqlite3_vtab_distinct(pInfo)>=1 ){
84971b65e88Sdrh       unsigned int x = 0;
85071b65e88Sdrh       for(i=0; i<pInfo->nOrderBy; i++){
85171b65e88Sdrh         int iCol = pInfo->aOrderBy[i].iColumn;
85271b65e88Sdrh         if( iCol<0 ) iCol = 0;
85371b65e88Sdrh         x |= 1<<iCol;
85471b65e88Sdrh       }
85571b65e88Sdrh       if( sqlite3_vtab_distinct(pInfo)==2 ){
85671b65e88Sdrh         if( x==0x02 ){
85771b65e88Sdrh           /* DISTINCT A */
85871b65e88Sdrh           pInfo->idxNum += 30;
85971b65e88Sdrh           pInfo->orderByConsumed = 1;
86071b65e88Sdrh         }else if( x==0x06 ){
86171b65e88Sdrh           /* DISTINCT A,B */
86271b65e88Sdrh           pInfo->idxNum += 20;
86371b65e88Sdrh           pInfo->orderByConsumed = 1;
86471b65e88Sdrh         }else if( x==0x0e ){
86571b65e88Sdrh           /* DISTINCT A,B,C */
86671b65e88Sdrh           pInfo->idxNum += 10;
86771b65e88Sdrh           pInfo->orderByConsumed = 1;
86871b65e88Sdrh         }else if( x & 0x01 ){
86971b65e88Sdrh           /* DISTINCT X */
87071b65e88Sdrh           pInfo->orderByConsumed = 1;
87171b65e88Sdrh         }else if( x==0x1e ){
87271b65e88Sdrh           /* DISTINCT A,B,C,D */
87371b65e88Sdrh           pInfo->orderByConsumed = 1;
87471b65e88Sdrh         }
87571b65e88Sdrh       }else{
87671b65e88Sdrh         if( x==0x02 ){
87771b65e88Sdrh           /* GROUP BY A */
87871b65e88Sdrh           pInfo->orderByConsumed = 1;
87971b65e88Sdrh         }else if( x==0x06 ){
88071b65e88Sdrh           /* GROUP BY A,B */
88171b65e88Sdrh           pInfo->orderByConsumed = 1;
88271b65e88Sdrh         }else if( x==0x0e ){
88371b65e88Sdrh           /* GROUP BY A,B,C */
88471b65e88Sdrh           pInfo->orderByConsumed = 1;
88571b65e88Sdrh         }else if( x & 0x01 ){
88671b65e88Sdrh           /* GROUP BY X */
88771b65e88Sdrh           pInfo->orderByConsumed = 1;
88871b65e88Sdrh         }else if( x==0x1e ){
88971b65e88Sdrh           /* GROUP BY A,B,C,D */
89071b65e88Sdrh           pInfo->orderByConsumed = 1;
89171b65e88Sdrh         }
89271b65e88Sdrh       }
89371b65e88Sdrh     }
89471b65e88Sdrh   }
89571b65e88Sdrh 
89671b65e88Sdrh   if( flags & VT02_ALLOC_IDXSTR ){
89771b65e88Sdrh     pInfo->idxStr = sqlite3_mprintf("test");
89871b65e88Sdrh     pInfo->needToFreeIdxStr = 1;
89971b65e88Sdrh   }
90071b65e88Sdrh   if( flags & VT02_BAD_IDXNUM ){
90171b65e88Sdrh     pInfo->idxNum += 1000;
90271b65e88Sdrh   }
90371b65e88Sdrh 
90471b65e88Sdrh   if( iOffset>=0 ){
90571b65e88Sdrh     pInfo->aConstraintUsage[iOffset].argvIndex = ++argvIndex;
90671b65e88Sdrh     if( (flags & VT02_NO_OFFSET)==0
90771b65e88Sdrh      && (pInfo->nOrderBy==0 || pInfo->orderByConsumed)
90871b65e88Sdrh     ){
90971b65e88Sdrh       pInfo->aConstraintUsage[iOffset].omit = 1;
91071b65e88Sdrh       pInfo->idxNum += 100;
91171b65e88Sdrh     }
91271b65e88Sdrh   }
91371b65e88Sdrh 
91471b65e88Sdrh 
91571b65e88Sdrh   /* Always omit flags= and logtab= constraints to prevent them from
91671b65e88Sdrh   ** interfering with the bytecode.  Put them at the end of the argv[]
91771b65e88Sdrh   ** array to keep them out of the way.
91871b65e88Sdrh   */
91971b65e88Sdrh   if( iFlagTerm>=0 ){
92071b65e88Sdrh     pInfo->aConstraintUsage[iFlagTerm].omit = 1;
92171b65e88Sdrh     pInfo->aConstraintUsage[iFlagTerm].argvIndex = ++argvIndex;
92271b65e88Sdrh   }
92371b65e88Sdrh   if( iLogTerm>=0 ){
92471b65e88Sdrh     pInfo->aConstraintUsage[iLogTerm].omit = 1;
92571b65e88Sdrh     pInfo->aConstraintUsage[iLogTerm].argvIndex = ++argvIndex;
92671b65e88Sdrh   }
92771b65e88Sdrh 
92871b65e88Sdrh   /* The 0x40 flag means add all usable constraints to the output set */
92971b65e88Sdrh   if( flags & 0x40 ){
93071b65e88Sdrh     for(i=0; i<pInfo->nConstraint; i++){
93171b65e88Sdrh       if( pInfo->aConstraint[i].usable
93271b65e88Sdrh        && pInfo->aConstraintUsage[i].argvIndex==0
93371b65e88Sdrh       ){
93471b65e88Sdrh         pInfo->aConstraintUsage[i].argvIndex = ++argvIndex;
93571b65e88Sdrh         if( flags & 0x20 )  pInfo->aConstraintUsage[i].omit = 1;
93671b65e88Sdrh       }
93771b65e88Sdrh     }
93871b65e88Sdrh   }
93971b65e88Sdrh 
94071b65e88Sdrh 
94171b65e88Sdrh   /* Generate the log if requested */
94271b65e88Sdrh   if( zLogTab ){
94371b65e88Sdrh     static const char *azColname[] = {
94471b65e88Sdrh        "x", "a", "b", "c", "d", "flags", "logtab"
94571b65e88Sdrh     };
94671b65e88Sdrh     sqlite3 *db = ((vt02_vtab*)pVTab)->db;
94771b65e88Sdrh     sqlite3BestIndexLog(pInfo, zLogTab, db, azColname, pVTab);
94871b65e88Sdrh   }
94971b65e88Sdrh   pSelf->busy--;
95071b65e88Sdrh 
95171b65e88Sdrh   /* Try to do a memory allocation solely for the purpose of causing
95271b65e88Sdrh   ** an error under OOM testing loops */
95371b65e88Sdrh   pX = sqlite3_malloc(800);
95471b65e88Sdrh   if( pX==0 ) return SQLITE_NOMEM;
95571b65e88Sdrh   sqlite3_free(pX);
95671b65e88Sdrh 
95771b65e88Sdrh   return pVTab->zErrMsg!=0 ? SQLITE_ERROR : SQLITE_OK;
95871b65e88Sdrh }
95971b65e88Sdrh 
96071b65e88Sdrh /* This is the sqlite3_module definition for the the virtual table defined
96171b65e88Sdrh ** by this include file.
96271b65e88Sdrh */
96371b65e88Sdrh const sqlite3_module vt02Module = {
96471b65e88Sdrh   /* iVersion      */  2,
96571b65e88Sdrh   /* xCreate       */  0,   /* This is an eponymous table */
96671b65e88Sdrh   /* xConnect      */  vt02Connect,
96771b65e88Sdrh   /* xBestIndex    */  vt02BestIndex,
96871b65e88Sdrh   /* xDisconnect   */  vt02Disconnect,
96971b65e88Sdrh   /* xDestroy      */  vt02Disconnect,
97071b65e88Sdrh   /* xOpen         */  vt02Open,
97171b65e88Sdrh   /* xClose        */  vt02Close,
97271b65e88Sdrh   /* xFilter       */  vt02Filter,
97371b65e88Sdrh   /* xNext         */  vt02Next,
97471b65e88Sdrh   /* xEof          */  vt02Eof,
97571b65e88Sdrh   /* xColumn       */  vt02Column,
97671b65e88Sdrh   /* xRowid        */  vt02Rowid,
97771b65e88Sdrh   /* xUpdate       */  0,
97871b65e88Sdrh   /* xBegin        */  0,
97971b65e88Sdrh   /* xSync         */  0,
98071b65e88Sdrh   /* xCommit       */  0,
98171b65e88Sdrh   /* xRollback     */  0,
98271b65e88Sdrh   /* xFindFunction */  0,
98371b65e88Sdrh   /* xRename       */  0,
98471b65e88Sdrh   /* xSavepoint    */  0,
98571b65e88Sdrh   /* xRelease      */  0,
98671b65e88Sdrh   /* xRollbackTo   */  0
98771b65e88Sdrh };
98871b65e88Sdrh 
vt02CoreInit(sqlite3 * db)98971b65e88Sdrh static void vt02CoreInit(sqlite3 *db){
99071b65e88Sdrh   static const char zPkXSchema[] =
99171b65e88Sdrh     "CREATE TABLE x(x INT NOT NULL PRIMARY KEY, a INT, b INT, c INT, d INT,"
99271b65e88Sdrh     " flags INT HIDDEN, logtab TEXT HIDDEN);";
99371b65e88Sdrh   static const char zPkABCDSchema[] =
99471b65e88Sdrh     "CREATE TABLE x(x INT, a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, "
99571b65e88Sdrh     "d INT NOT NULL, flags INT HIDDEN, logtab TEXT HIDDEN, "
99671b65e88Sdrh     "PRIMARY KEY(a,b,c,d));";
99771b65e88Sdrh   sqlite3_create_module(db, "vt02", &vt02Module, 0);
99871b65e88Sdrh   sqlite3_create_module(db, "vt02pkx", &vt02Module, (void*)zPkXSchema);
99971b65e88Sdrh   sqlite3_create_module(db, "vt02pkabcd", &vt02Module, (void*)zPkABCDSchema);
100071b65e88Sdrh }
100171b65e88Sdrh 
100271b65e88Sdrh #ifdef TH3_VERSION
vt02_init(th3state * p,int iDb,char * zArg)100371b65e88Sdrh static void vt02_init(th3state *p, int iDb, char *zArg){
100471b65e88Sdrh   vt02CoreInit(th3dbPointer(p, iDb));
100571b65e88Sdrh }
100671b65e88Sdrh #else
100771b65e88Sdrh #ifdef _WIN32
100871b65e88Sdrh __declspec(dllexport)
100971b65e88Sdrh #endif
sqlite3_vt02_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)101071b65e88Sdrh int sqlite3_vt02_init(
101171b65e88Sdrh   sqlite3 *db,
101271b65e88Sdrh   char **pzErrMsg,
101371b65e88Sdrh   const sqlite3_api_routines *pApi
101471b65e88Sdrh ){
101571b65e88Sdrh   SQLITE_EXTENSION_INIT2(pApi);
101671b65e88Sdrh   vt02CoreInit(db);
101771b65e88Sdrh   return SQLITE_OK;
101871b65e88Sdrh }
101971b65e88Sdrh #endif /* TH3_VERSION */
1020