2 ** This file implements an eponymous, read-only table-valued function
3 ** (a virtual table) designed to be used for testing. We are not aware
4 ** of any practical real-world use case for the virtual table.
6 ** This virtual table originated in the TH3 test suite. It is still used
7 ** there, but has now been copied into the public SQLite source tree and
8 ** reused for a variety of testing purpose. The name "vt02" comes from the
9 ** fact that there are many different testing virtual tables in TH3, of which
10 ** this one is the second.
12 ** ## SUBJECT TO CHANGE
14 ** Because this virtual table is intended for testing, its interface is not
15 ** guaranteed to be stable across releases. Future releases may contain
16 ** changes in the vt02 design and interface.
20 ** The vt02 table-valued function has 10000 rows with 5 data columns.
21 ** Column X contains all integer values between 0 and 9999 inclusive.
22 ** Columns A, B, C, and D contain the individual base-10 digits associated
39 ** The xBestIndex method recognizes a variety of equality constraints
40 ** and attempts to optimize its output accordingly.
45 ** a=... AND b=... AND c=...
46 ** a=... AND b=... AND c=... AND d=...
48 ** Various ORDER BY constraints are also recognized and consumed. The
49 ** OFFSET constraint is recognized and consumed.
51 ** ## TABLE-VALUED FUNCTION
53 ** The vt02 virtual table is eponymous and has two hidden columns, meaning
54 ** that it can functions a table-valued function. The two hidden columns
55 ** are "flags" and "logtab", in that order. The "flags" column can be set
56 ** to an integer where various bits enable or disable behaviors of the
57 ** virtual table. The "logtab" can set to the name of an ordinary SQLite
58 ** table into which is written information about each call to xBestIndex.
60 ** The bits of "flags" are as follows:
62 ** 0x01 Ignore the aConstraint[].usable flag. This might
63 ** result in the xBestIndex method incorrectly using
64 ** unusable entries in the aConstraint[] array, which
65 ** should result in the SQLite core detecting and
66 ** reporting that the virtual table is not behaving
69 ** 0x02 Do not set the orderByConsumed flag, even if it
72 ** 0x04 Do not consume the OFFSET constraint, if there is
73 ** one. Instead, let the generated byte-code visit
74 ** and ignore the first few columns of output.
76 ** 0x08 Use sqlite3_mprintf() to allocate an idxStr string.
77 ** The string is never used, but allocating it does
78 ** test the idxStr deallocation logic inside of the
81 ** 0x10 Cause the xBestIndex method to generate an idxNum
82 ** that xFilter does not understand, thus causing
83 ** the OP_VFilter opcode to raise an error.
85 ** 0x20 Set the omit flag for all equality constraints on
86 ** columns X, A, B, C, and D that are used to limit
89 ** 0x40 Add all constraints against X,A,B,C,D to the
90 ** vector of results sent to xFilter. Only the first
91 ** few are used, as required by idxNum.
93 ** Because these flags take effect during xBestIndex, the RHS of the
94 ** flag= constraint must be accessible. In other words, the RHS of flag=
95 ** needs to be an integer literal, not another column of a join or a
100 ** If the "logtab" columns is set, then each call to the xBestIndex method
101 ** inserts multiple rows into the table identified by "logtab". These
102 ** rows collectively show the content of the sqlite3_index_info object and
103 ** other context associated with the xBestIndex call.
105 ** If the table named by "logtab" does not previously exist, it is created
106 ** automatically. The schema for the logtab table is like this:
108 ** CREATE TEMP TABLE vt02_log(
109 ** bi INT, -- BestIndex call counter
110 ** vn TEXT, -- Variable Name
111 ** ix INT, -- Index or value
112 ** cn TEXT, -- Column Name
113 ** op INT, -- Opcode or "DESC" value
114 ** ux INT, -- "Usable" flag
115 ** ra BOOLEAN, -- Right-hand side Available.
116 ** rhs ANY, -- Right-Hand Side value
117 ** cs TEXT -- Collating Sequence for this constraint
120 ** Because logging happens during xBestIindex, the RHS value of "logtab" must
121 ** be known to xBestIndex, which means it must be a string literal, not a
122 ** column in a join, or a bound parameter.
124 ** ## VIRTUAL TABLE SCHEMA
126 ** CREATE TABLE vt02(
127 ** x INT, -- integer between 0 and 9999 inclusive
128 ** a INT, -- The 1000s digit
129 ** b INT, -- The 100s digit
130 ** c INT, -- The 10s digit
131 ** d INT, -- The 1s digit
132 ** flags INT HIDDEN, -- Option flags
133 ** logtab TEXT HIDDEN, -- Name of table into which to log xBestIndex
136 ** ## COMPILING AND RUNNING
138 ** This file can also be compiled separately as a loadable extension
139 ** for SQLite (as long as the -DTH3_VERSION is not defined). To compile as a
140 ** loadable extension do his:
142 ** gcc -Wall -g -shared -fPIC -I. -DSQLITE_DEBUG vt02.c -o vt02.so
146 ** cl vt02.c -link -dll -out:vt02.dll
148 ** Then load into the CLI using:
150 ** .load ./vt02 sqlite3_vt02_init
154 ** The xBestIndex method communicates the query plan to xFilter using
155 ** the idxNum value, as follows:
160 ** 3 A=argv[0], B=argv[1]
161 ** 4 A=argv[0], B=argv[1], C=argv[2]
162 ** 5 A=argv[0], B=argv[1], C=argv[2], D=argv[3]
163 ** 6 A=argv[0], D IN argv[2]
164 ** 7 A=argv[0], B=argv[2], D IN argv[3]
165 ** 8 A=argv[0], B=argv[2], C=argv[3], D IN argv[4]
166 ** 1x increment by 10
167 ** 2x increment by 100
168 ** 3x increment by 1000
169 ** 1xx Use offset provided by argv[N]
172 /* These bits for separate compilation as a loadable extension, only */
173 #include "sqlite3ext.h"
174 SQLITE_EXTENSION_INIT1
180 /* Forward declarations */
181 typedef struct vt02_vtab vt02_vtab
;
182 typedef struct vt02_cur vt02_cur
;
185 ** The complete virtual table
188 sqlite3_vtab parent
; /* Base clase. Must be first. */
189 sqlite3
*db
; /* Database connection */
190 int busy
; /* Currently running xBestIndex */
193 #define VT02_IGNORE_USABLE 0x0001 /* Ignore usable flags */
194 #define VT02_NO_SORT_OPT 0x0002 /* Do not do any sorting optimizations */
195 #define VT02_NO_OFFSET 0x0004 /* Omit the offset optimization */
196 #define VT02_ALLOC_IDXSTR 0x0008 /* Alloate an idxStr */
197 #define VT02_BAD_IDXNUM 0x0010 /* Generate an invalid idxNum */
203 sqlite3_vtab_cursor parent
; /* Base class. Must be first */
204 sqlite3_int64 i
; /* Current entry */
205 sqlite3_int64 iEof
; /* Indicate EOF when reaching this value */
206 int iIncr
; /* Amount by which to increment */
207 unsigned int mD
; /* Mask of allowed D-column values */
210 /* The xConnect method */
212 sqlite3
*db
, /* The database connection */
213 void *pAux
, /* Pointer to an alternative schema */
214 int argc
, /* Number of arguments */
215 const char *const*argv
, /* Text of the arguments */
216 sqlite3_vtab
**ppVTab
, /* Write the new vtab here */
217 char **pzErr
/* Error message written here */
221 const char *zSchema
= (const char*)pAux
;
222 static const char zDefaultSchema
[] =
223 "CREATE TABLE x(x INT, a INT, b INT, c INT, d INT,"
224 " flags INT HIDDEN, logtab TEXT HIDDEN);";
230 #define VT02_COL_FLAGS 5
231 #define VT02_COL_LOGTAB 6
232 #define VT02_COL_NONE 7
234 pVtab
= sqlite3_malloc( sizeof(*pVtab
) );
236 *pzErr
= sqlite3_mprintf("out of memory");
239 memset(pVtab
, 0, sizeof(*pVtab
));
241 rc
= sqlite3_declare_vtab(db
, zSchema
? zSchema
: zDefaultSchema
);
245 *ppVTab
= &pVtab
->parent
;
250 /* the xDisconnect method
252 int vt02Disconnect(sqlite3_vtab
*pVTab
){
257 /* Put an error message into the zErrMsg string of the virtual table.
259 static void vt02ErrMsg(sqlite3_vtab
*pVtab
, const char *zFormat
, ...){
261 sqlite3_free(pVtab
->zErrMsg
);
262 va_start(ap
, zFormat
);
263 pVtab
->zErrMsg
= sqlite3_vmprintf(zFormat
, ap
);
268 /* Open a cursor for scanning
270 static int vt02Open(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
272 pCur
= sqlite3_malloc( sizeof(*pCur
) );
274 vt02ErrMsg(pVTab
, "out of memory");
277 *ppCursor
= &pCur
->parent
;
284 static int vt02Close(sqlite3_vtab_cursor
*pCursor
){
285 vt02_cur
*pCur
= (vt02_cur
*)pCursor
;
290 /* Return TRUE if we are at the end of the BVS and there are
293 static int vt02Eof(sqlite3_vtab_cursor
*pCursor
){
294 vt02_cur
*pCur
= (vt02_cur
*)pCursor
;
295 return pCur
->i
<0 || pCur
->i
>=pCur
->iEof
;
298 /* Advance the cursor to the next row in the table
300 static int vt02Next(sqlite3_vtab_cursor
*pCursor
){
301 vt02_cur
*pCur
= (vt02_cur
*)pCursor
;
303 pCur
->i
+= pCur
->iIncr
;
304 if( pCur
->i
<0 ) pCur
->i
= pCur
->iEof
;
305 }while( (pCur
->mD
& (1<<(pCur
->i
%10)))==0 && pCur
->i
<pCur
->iEof
);
309 /* Rewind a cursor back to the beginning of its scan.
311 ** Scanning is always increasing.
317 ** 3 A=argv[0], B=argv[1]
318 ** 4 A=argv[0], B=argv[1], C=argv[2]
319 ** 5 A=argv[0], B=argv[1], C=argv[2], D=argv[3]
320 ** 6 A=argv[0], D IN argv[2]
321 ** 7 A=argv[0], B=argv[2], D IN argv[3]
322 ** 8 A=argv[0], B=argv[2], C=argv[3], D IN argv[4]
323 ** 1x increment by 10
324 ** 2x increment by 100
325 ** 3x increment by 1000
326 ** 1xx Use offset provided by argv[N]
328 static int vt02Filter(
329 sqlite3_vtab_cursor
*pCursor
, /* The cursor to rewind */
330 int idxNum
, /* Search strategy */
331 const char *idxStr
, /* Not used */
332 int argc
, /* Not used */
333 sqlite3_value
**argv
/* Not used */
335 vt02_cur
*pCur
= (vt02_cur
*)pCursor
; /* The vt02 cursor */
336 int bUseOffset
= 0; /* True to use OFFSET value */
337 int iArg
= 0; /* argv[] values used so far */
338 int iOrigIdxNum
= idxNum
; /* Original value for idxNum */
346 if( idxNum
<0 || idxNum
>38 ) goto vt02_bad_idxnum
;
354 }else if( idxNum
==1 ){
355 pCur
->i
= sqlite3_value_int64(argv
[0]);
356 if( pCur
->i
<0 ) pCur
->i
= -1;
357 if( pCur
->i
>9999 ) pCur
->i
= 10000;
358 pCur
->iEof
= pCur
->i
+1;
359 if( pCur
->i
<0 || pCur
->i
>9999 ) pCur
->i
= pCur
->iEof
;
360 }else if( idxNum
>=2 && idxNum
<=5 ){
365 for(m
=1000, i
=0; i
<=e
; i
++, m
/= 10){
366 sqlite3_int64 v
= sqlite3_value_int64(argv
[iArg
++]);
370 pCur
->iEof
= pCur
->i
+m
;
372 }else if( idxNum
>=6 && idxNum
<=8 ){
374 sqlite3_value
*pIn
, *pVal
;
378 for(m
=1000, i
=0; i
<=e
; i
++, m
/= 10){
381 if( sqlite3_vtab_in_first(0, &pVal
)!=SQLITE_MISUSE
382 || sqlite3_vtab_in_first(argv
[iArg
], &pVal
)!=SQLITE_ERROR
384 vt02ErrMsg(pCursor
->pVtab
,
385 "unexpected success from sqlite3_vtab_in_first()");
388 v
= sqlite3_value_int64(argv
[iArg
++]);
392 pCur
->iEof
= pCur
->i
+m
;
396 assert( sqlite3_value_type(pIn
)==SQLITE_NULL
);
397 for( rc
= sqlite3_vtab_in_first(pIn
, &pVal
);
398 rc
==SQLITE_OK
&& pVal
!=0;
399 rc
= sqlite3_vtab_in_next(pIn
, &pVal
)
401 int eType
= sqlite3_value_numeric_type(pVal
);
402 if( eType
==SQLITE_FLOAT
){
403 double r
= sqlite3_value_double(pVal
);
404 if( r
<0.0 || r
>9.0 || r
!=(int)r
) continue;
405 }else if( eType
!=SQLITE_INTEGER
){
408 i
= sqlite3_value_int(pVal
);
409 if( i
<0 || i
>9 ) continue;
412 if( rc
!=SQLITE_OK
&& rc
!=SQLITE_DONE
){
413 vt02ErrMsg(pCursor
->pVtab
, "Error from sqlite3_vtab_in_first/next()");
417 goto vt02_bad_idxnum
;
420 int nSkip
= sqlite3_value_int(argv
[iArg
]);
421 while( nSkip
-- > 0 && pCur
->i
<pCur
->iEof
) vt02Next(pCursor
);
426 vt02ErrMsg(pCursor
->pVtab
, "invalid idxNum for vt02: %d", iOrigIdxNum
);
430 /* Return the Nth column of the current row.
432 static int vt02Column(
433 sqlite3_vtab_cursor
*pCursor
,
434 sqlite3_context
*context
,
437 vt02_cur
*pCur
= (vt02_cur
*)pCursor
;
440 sqlite3_result_int(context
, v
);
441 }else if( N
>=VT02_COL_A
&& N
<=VT02_COL_D
){
442 static const int iDivisor
[] = { 1, 1000, 100, 10, 1 };
443 v
= (v
/iDivisor
[N
])%10;
444 sqlite3_result_int(context
, v
);
449 /* Return the rowid of the current row
451 static int vt02Rowid(sqlite3_vtab_cursor
*pCursor
, sqlite3_int64
*pRowid
){
452 vt02_cur
*pCur
= (vt02_cur
*)pCursor
;
457 /*************************************************************************
460 ** The sqlite3BestIndexLog() routine implements a logging system for
461 ** xBestIndex calls. This code is portable to any virtual table.
463 ** sqlite3BestIndexLog() is the main routine, sqlite3RunSql() is a
464 ** helper routine used for running various SQL statements as part of
467 ** These two routines should be portable to other virtual tables. Simply
468 ** extract this code and call sqlite3BestIndexLog() near the end of the
469 ** xBestIndex method in cases where logging is desired.
472 ** Run SQL on behalf of sqlite3BestIndexLog.
474 ** Construct the SQL using the zFormat string and subsequent arguments.
475 ** Or if zFormat is NULL, take the SQL as the first argument after the
476 ** zFormat. In either case, the dynamically allocated SQL string is
477 ** freed after it has been run. If something goes wrong with the SQL,
478 ** then an error is left in pVTab->zErrMsg.
480 static void sqlite3RunSql(
481 sqlite3
*db
, /* Run the SQL on this database connection */
482 sqlite3_vtab
*pVTab
, /* Report errors to this virtual table */
483 const char *zFormat
, /* Format string for SQL, or NULL */
484 ... /* Arguments, according to the format string */
489 va_start(ap
, zFormat
);
491 zSql
= va_arg(ap
, char*);
493 zSql
= sqlite3_vmprintf(zFormat
, ap
);
498 (void)sqlite3_exec(db
, zSql
, 0, 0, &zErrMsg
);
500 if( pVTab
->zErrMsg
==0 ){
501 pVTab
->zErrMsg
= sqlite3_mprintf("%s in [%s]", zErrMsg
, zSql
);
503 sqlite3_free(zErrMsg
);
510 ** Record information about each xBestIndex method call in a separate
513 ** CREATE TEMP TABLE [log-table-name] (
514 ** bi INT, -- BestIndex call number
515 ** vn TEXT, -- Variable Name
516 ** ix INT, -- Index or value
517 ** cn TEXT, -- Column Name
518 ** op INT, -- Opcode or argvIndex
519 ** ux INT, -- "usable" or "omit" flag
520 ** rx BOOLEAN, -- True if has a RHS value
521 ** rhs ANY, -- The RHS value
522 ** cs TEXT, -- Collating Sequence
523 ** inop BOOLEAN -- True if this is a batchable IN operator
526 ** If an error occurs, leave an error message in pVTab->zErrMsg.
528 static void sqlite3BestIndexLog(
529 sqlite3_index_info
*pInfo
, /* The sqlite3_index_info object */
530 const char *zLogTab
, /* Log into this table */
531 sqlite3
*db
, /* Database connection containing zLogTab */
532 const char **azColname
, /* Names of columns in the virtual table */
533 sqlite3_vtab
*pVTab
/* Record errors into this object */
539 if( sqlite3_table_column_metadata(db
,0,zLogTab
,0,0,0,0,0,0) ){
540 /* The log table does not previously exist. Create it. */
541 sqlite3RunSql(db
,pVTab
,
542 "CREATE TABLE IF NOT EXISTS temp.\"%w\"(\n"
543 " bi INT, -- BestIndex call number\n"
544 " vn TEXT, -- Variable Name\n"
545 " ix INT, -- Index or value\n"
546 " cn TEXT, -- Column Name\n"
547 " op INT, -- Opcode or argvIndex\n"
548 " ux INT, -- usable for omit flag\n"
549 " rx BOOLEAN, -- Right-hand side value is available\n"
550 " rhs ANY, -- RHS value\n"
551 " cs TEXT, -- Collating Sequence\n"
552 " inop BOOLEAN -- IN operator capable of batch reads\n"
557 /* The log table does already exist. We assume that it has the
558 ** correct schema and proceed to find the largest prior "bi" value.
559 ** If the schema is wrong, errors might result. The code is able
560 ** to deal with this. */
563 zSql
= sqlite3_mprintf("SELECT max(bi) FROM temp.\"%w\"",zLogTab
);
565 sqlite3_free(pVTab
->zErrMsg
);
566 pVTab
->zErrMsg
= sqlite3_mprintf("out of memory");
569 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
572 sqlite3_free(pVTab
->zErrMsg
);
573 pVTab
->zErrMsg
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
575 }else if( sqlite3_step(pStmt
)==SQLITE_ROW
){
576 iBI
= sqlite3_column_int(pStmt
, 0)+1;
580 sqlite3_finalize(pStmt
);
582 sqlite3RunSql(db
,pVTab
,
583 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'nConstraint',%d)",
584 zLogTab
, iBI
, pInfo
->nConstraint
586 for(i
=0; i
<pInfo
->nConstraint
; i
++){
589 int iCol
= pInfo
->aConstraint
[i
].iColumn
;
590 int op
= pInfo
->aConstraint
[i
].op
;
592 if( op
==SQLITE_INDEX_CONSTRAINT_LIMIT
593 || op
==SQLITE_INDEX_CONSTRAINT_OFFSET
599 zCol
= azColname
[iCol
];
601 pStr
= sqlite3_str_new(0);
602 sqlite3_str_appendf(pStr
,
603 "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op,ux,rx,rhs,cs,inop)"
604 "VALUES(%d,'aConstraint',%d,%Q,%d,%d",
609 pInfo
->aConstraint
[i
].usable
);
611 rc
= sqlite3_vtab_rhs_value(pInfo
, i
, &pVal
);
612 assert( pVal
!=0 || rc
!=SQLITE_OK
);
614 sqlite3_str_appendf(pStr
,",1,?1");
616 sqlite3_str_appendf(pStr
,",0,NULL");
618 sqlite3_str_appendf(pStr
,",%Q,%d)",
619 sqlite3_vtab_collation(pInfo
,i
),
620 sqlite3_vtab_in(pInfo
,i
,-1));
621 zSql
= sqlite3_str_finish(pStr
);
623 if( pVTab
->zErrMsg
==0 ) pVTab
->zErrMsg
= sqlite3_mprintf("out of memory");
625 sqlite3_stmt
*pStmt
= 0;
626 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
628 if( pVTab
->zErrMsg
==0 ){
629 pVTab
->zErrMsg
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
632 if( pVal
) sqlite3_bind_value(pStmt
, 1, pVal
);
634 rc
= sqlite3_reset(pStmt
);
635 if( rc
&& pVTab
->zErrMsg
==0 ){
636 pVTab
->zErrMsg
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
639 sqlite3_finalize(pStmt
);
643 sqlite3RunSql(db
,pVTab
,
644 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'nOrderBy',%d)",
645 zLogTab
, iBI
, pInfo
->nOrderBy
647 for(i
=0; i
<pInfo
->nOrderBy
; i
++){
648 int iCol
= pInfo
->aOrderBy
[i
].iColumn
;
649 sqlite3RunSql(db
,pVTab
,
650 "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op)VALUES(%d,'aOrderBy',%d,%Q,%d)",
653 iCol
>=0 ? azColname
[iCol
] : "rowid",
654 pInfo
->aOrderBy
[i
].desc
657 sqlite3RunSql(db
,pVTab
,
658 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'sqlite3_vtab_distinct',%d)",
659 zLogTab
, iBI
, sqlite3_vtab_distinct(pInfo
)
661 sqlite3RunSql(db
,pVTab
,
662 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'colUsed',%lld)",
663 zLogTab
, iBI
, pInfo
->colUsed
665 for(i
=0; i
<pInfo
->nConstraint
; i
++){
666 int iCol
= pInfo
->aConstraint
[i
].iColumn
;
667 int op
= pInfo
->aConstraint
[i
].op
;
669 if( op
==SQLITE_INDEX_CONSTRAINT_LIMIT
670 || op
==SQLITE_INDEX_CONSTRAINT_OFFSET
676 zCol
= azColname
[iCol
];
678 sqlite3RunSql(db
,pVTab
,
679 "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op,ux)"
680 "VALUES(%d,'aConstraintUsage',%d,%Q,%d,%d)",
684 pInfo
->aConstraintUsage
[i
].argvIndex
,
685 pInfo
->aConstraintUsage
[i
].omit
688 sqlite3RunSql(db
,pVTab
,
689 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'idxNum',%d)",
690 zLogTab
, iBI
, pInfo
->idxNum
692 sqlite3RunSql(db
,pVTab
,
693 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'estimatedCost',%f)",
694 zLogTab
, iBI
, pInfo
->estimatedCost
696 sqlite3RunSql(db
,pVTab
,
697 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'estimatedRows',%lld)",
698 zLogTab
, iBI
, pInfo
->estimatedRows
701 sqlite3RunSql(db
,pVTab
,
702 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'idxStr',%Q)",
703 zLogTab
, iBI
, pInfo
->idxStr
705 sqlite3RunSql(db
,pVTab
,
706 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'needToFreeIdxStr',%d)",
707 zLogTab
, iBI
, pInfo
->needToFreeIdxStr
710 if( pInfo
->nOrderBy
){
711 sqlite3RunSql(db
,pVTab
,
712 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'orderByConsumed',%d)",
713 zLogTab
, iBI
, pInfo
->orderByConsumed
718 ** End of Logging Subsystem
719 *****************************************************************************/
722 /* Find an estimated cost of running a query against vt02.
724 static int vt02BestIndex(sqlite3_vtab
*pVTab
, sqlite3_index_info
*pInfo
){
725 int i
; /* Loop counter */
726 int isEq
[5]; /* Equality constraints on X, A, B, C, and D */
727 int isUsed
[5]; /* Other non-== cosntraints X, A, B, C, and D */
728 int argvIndex
= 0; /* Next available argv[] slot */
729 int iOffset
= -1; /* Constraint for OFFSET */
730 void *pX
= 0; /* idxStr value */
731 int flags
= 0; /* RHS value for flags= */
732 const char *zLogTab
= 0; /* RHS value for logtab= */
733 int iFlagTerm
= -1; /* Constraint term for flags= */
734 int iLogTerm
= -1; /* Constraint term for logtab= */
735 int iIn
= -1; /* Index of the IN constraint */
736 vt02_vtab
*pSelf
; /* This virtual table */
738 pSelf
= (vt02_vtab
*)pVTab
;
740 vt02ErrMsg(pVTab
, "recursive use of vt02 prohibited");
741 return SQLITE_CONSTRAINT
;
746 /* Do an initial scan for flags=N and logtab=TAB constraints with
747 ** usable RHS values */
748 for(i
=0; i
<pInfo
->nConstraint
; i
++){
750 if( !pInfo
->aConstraint
[i
].usable
) continue;
751 if( pInfo
->aConstraint
[i
].op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
752 switch( pInfo
->aConstraint
[i
].iColumn
){
754 if( sqlite3_vtab_rhs_value(pInfo
, i
, &pVal
)==SQLITE_OK
755 && sqlite3_value_type(pVal
)==SQLITE_INTEGER
757 flags
= sqlite3_value_int(pVal
);
761 case VT02_COL_LOGTAB
:
762 if( sqlite3_vtab_rhs_value(pInfo
, i
, &pVal
)==SQLITE_OK
763 && sqlite3_value_type(pVal
)==SQLITE_TEXT
765 zLogTab
= (const char*)sqlite3_value_text(pVal
);
772 /* Do a second scan to actually analyze the index information */
773 memset(isEq
, 0xff, sizeof(isEq
));
774 memset(isUsed
, 0xff, sizeof(isUsed
));
775 for(i
=0; i
<pInfo
->nConstraint
; i
++){
776 int j
= pInfo
->aConstraint
[i
].iColumn
;
777 if( j
>=VT02_COL_FLAGS
) continue;
778 if( pInfo
->aConstraint
[i
].usable
==0
779 && (flags
& VT02_IGNORE_USABLE
)==0 ) continue;
780 if( j
<0 ) j
= VT02_COL_X
;
781 switch( pInfo
->aConstraint
[i
].op
){
782 case SQLITE_INDEX_CONSTRAINT_FUNCTION
:
783 case SQLITE_INDEX_CONSTRAINT_EQ
:
786 case SQLITE_INDEX_CONSTRAINT_LT
:
787 case SQLITE_INDEX_CONSTRAINT_LE
:
788 case SQLITE_INDEX_CONSTRAINT_GT
:
789 case SQLITE_INDEX_CONSTRAINT_GE
:
792 case SQLITE_INDEX_CONSTRAINT_OFFSET
:
798 /* Use the analysis to find an appropriate query plan */
800 /* A constraint of X= takes priority */
801 pInfo
->estimatedCost
= 1;
802 pInfo
->aConstraintUsage
[isEq
[0]].argvIndex
= ++argvIndex
;
803 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[isEq
[0]].omit
= 1;
805 }else if( isEq
[1]<0 ){
806 /* If there is no X= nor A= then we have to do a full scan */
808 pInfo
->estimatedCost
= 10000;
811 pInfo
->aConstraintUsage
[isEq
[1]].argvIndex
= ++argvIndex
;
812 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[isEq
[1]].omit
= 1;
813 for(i
=2; i
<=4 && isEq
[i
]>=0; i
++){
814 if( i
==4 && sqlite3_vtab_in(pInfo
, isEq
[4], 0) ) break;
815 pInfo
->aConstraintUsage
[isEq
[i
]].argvIndex
= ++argvIndex
;
816 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[isEq
[i
]].omit
= 1;
820 if( isEq
[4]>=0 && sqlite3_vtab_in(pInfo
,isEq
[4],1) ){
822 pInfo
->aConstraintUsage
[iIn
].argvIndex
= ++argvIndex
;
823 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[iIn
].omit
= 1;
828 pInfo
->estimatedCost
= v
;
830 pInfo
->estimatedRows
= (sqlite3_int64
)pInfo
->estimatedCost
;
832 /* Attempt to consume the ORDER BY clause. Except, always leave
833 ** orderByConsumed set to 0 for vt02_no_sort_opt. In this way,
834 ** we can compare vt02 and vt02_no_sort_opt to ensure they get
837 if( pInfo
->nOrderBy
>0 && (flags
& VT02_NO_SORT_OPT
)==0 ){
838 if( pInfo
->idxNum
==1 ){
839 /* There will only be one row of output. So it is always sorted. */
840 pInfo
->orderByConsumed
= 1;
842 if( pInfo
->aOrderBy
[0].iColumn
<=0
843 && pInfo
->aOrderBy
[0].desc
==0
845 /* First column of order by is X ascending */
846 pInfo
->orderByConsumed
= 1;
848 if( sqlite3_vtab_distinct(pInfo
)>=1 ){
850 for(i
=0; i
<pInfo
->nOrderBy
; i
++){
851 int iCol
= pInfo
->aOrderBy
[i
].iColumn
;
852 if( iCol
<0 ) iCol
= 0;
855 if( sqlite3_vtab_distinct(pInfo
)==2 ){
859 pInfo
->orderByConsumed
= 1;
863 pInfo
->orderByConsumed
= 1;
867 pInfo
->orderByConsumed
= 1;
868 }else if( x
& 0x01 ){
870 pInfo
->orderByConsumed
= 1;
872 /* DISTINCT A,B,C,D */
873 pInfo
->orderByConsumed
= 1;
878 pInfo
->orderByConsumed
= 1;
881 pInfo
->orderByConsumed
= 1;
884 pInfo
->orderByConsumed
= 1;
885 }else if( x
& 0x01 ){
887 pInfo
->orderByConsumed
= 1;
889 /* GROUP BY A,B,C,D */
890 pInfo
->orderByConsumed
= 1;
896 if( flags
& VT02_ALLOC_IDXSTR
){
897 pInfo
->idxStr
= sqlite3_mprintf("test");
898 pInfo
->needToFreeIdxStr
= 1;
900 if( flags
& VT02_BAD_IDXNUM
){
901 pInfo
->idxNum
+= 1000;
905 pInfo
->aConstraintUsage
[iOffset
].argvIndex
= ++argvIndex
;
906 if( (flags
& VT02_NO_OFFSET
)==0
907 && (pInfo
->nOrderBy
==0 || pInfo
->orderByConsumed
)
909 pInfo
->aConstraintUsage
[iOffset
].omit
= 1;
910 pInfo
->idxNum
+= 100;
915 /* Always omit flags= and logtab= constraints to prevent them from
916 ** interfering with the bytecode. Put them at the end of the argv[]
917 ** array to keep them out of the way.
920 pInfo
->aConstraintUsage
[iFlagTerm
].omit
= 1;
921 pInfo
->aConstraintUsage
[iFlagTerm
].argvIndex
= ++argvIndex
;
924 pInfo
->aConstraintUsage
[iLogTerm
].omit
= 1;
925 pInfo
->aConstraintUsage
[iLogTerm
].argvIndex
= ++argvIndex
;
928 /* The 0x40 flag means add all usable constraints to the output set */
930 for(i
=0; i
<pInfo
->nConstraint
; i
++){
931 if( pInfo
->aConstraint
[i
].usable
932 && pInfo
->aConstraintUsage
[i
].argvIndex
==0
934 pInfo
->aConstraintUsage
[i
].argvIndex
= ++argvIndex
;
935 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[i
].omit
= 1;
941 /* Generate the log if requested */
943 static const char *azColname
[] = {
944 "x", "a", "b", "c", "d", "flags", "logtab"
946 sqlite3
*db
= ((vt02_vtab
*)pVTab
)->db
;
947 sqlite3BestIndexLog(pInfo
, zLogTab
, db
, azColname
, pVTab
);
951 /* Try to do a memory allocation solely for the purpose of causing
952 ** an error under OOM testing loops */
953 pX
= sqlite3_malloc(800);
954 if( pX
==0 ) return SQLITE_NOMEM
;
957 return pVTab
->zErrMsg
!=0 ? SQLITE_ERROR
: SQLITE_OK
;
960 /* This is the sqlite3_module definition for the the virtual table defined
961 ** by this include file.
963 const sqlite3_module vt02Module
= {
965 /* xCreate */ 0, /* This is an eponymous table */
966 /* xConnect */ vt02Connect
,
967 /* xBestIndex */ vt02BestIndex
,
968 /* xDisconnect */ vt02Disconnect
,
969 /* xDestroy */ vt02Disconnect
,
970 /* xOpen */ vt02Open
,
971 /* xClose */ vt02Close
,
972 /* xFilter */ vt02Filter
,
973 /* xNext */ vt02Next
,
975 /* xColumn */ vt02Column
,
976 /* xRowid */ vt02Rowid
,
982 /* xFindFunction */ 0,
989 static void vt02CoreInit(sqlite3
*db
){
990 static const char zPkXSchema
[] =
991 "CREATE TABLE x(x INT NOT NULL PRIMARY KEY, a INT, b INT, c INT, d INT,"
992 " flags INT HIDDEN, logtab TEXT HIDDEN);";
993 static const char zPkABCDSchema
[] =
994 "CREATE TABLE x(x INT, a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, "
995 "d INT NOT NULL, flags INT HIDDEN, logtab TEXT HIDDEN, "
996 "PRIMARY KEY(a,b,c,d));";
997 sqlite3_create_module(db
, "vt02", &vt02Module
, 0);
998 sqlite3_create_module(db
, "vt02pkx", &vt02Module
, (void*)zPkXSchema
);
999 sqlite3_create_module(db
, "vt02pkabcd", &vt02Module
, (void*)zPkABCDSchema
);
1003 static void vt02_init(th3state
*p
, int iDb
, char *zArg
){
1004 vt02CoreInit(th3dbPointer(p
, iDb
));
1008 __declspec(dllexport
)
1010 int sqlite3_vt02_init(
1013 const sqlite3_api_routines
*pApi
1015 SQLITE_EXTENSION_INIT2(pApi
);
1019 #endif /* TH3_VERSION */