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 "RETURNING iif(bi=%d,'ok',RAISE(ABORT,'wrong trigger'))",
585 /* The RETURNING clause checks to see that the returning trigger fired
586 ** for the correct INSERT in the case of nested INSERT RETURNINGs. */
587 zLogTab
, iBI
, pInfo
->nConstraint
, iBI
589 for(i
=0; i
<pInfo
->nConstraint
; i
++){
592 int iCol
= pInfo
->aConstraint
[i
].iColumn
;
593 int op
= pInfo
->aConstraint
[i
].op
;
595 if( op
==SQLITE_INDEX_CONSTRAINT_LIMIT
596 || op
==SQLITE_INDEX_CONSTRAINT_OFFSET
602 zCol
= azColname
[iCol
];
604 pStr
= sqlite3_str_new(0);
605 sqlite3_str_appendf(pStr
,
606 "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op,ux,rx,rhs,cs,inop)"
607 "VALUES(%d,'aConstraint',%d,%Q,%d,%d",
612 pInfo
->aConstraint
[i
].usable
);
614 rc
= sqlite3_vtab_rhs_value(pInfo
, i
, &pVal
);
615 assert( pVal
!=0 || rc
!=SQLITE_OK
);
617 sqlite3_str_appendf(pStr
,",1,?1");
619 sqlite3_str_appendf(pStr
,",0,NULL");
621 sqlite3_str_appendf(pStr
,",%Q,%d)",
622 sqlite3_vtab_collation(pInfo
,i
),
623 sqlite3_vtab_in(pInfo
,i
,-1));
624 zSql
= sqlite3_str_finish(pStr
);
626 if( pVTab
->zErrMsg
==0 ) pVTab
->zErrMsg
= sqlite3_mprintf("out of memory");
628 sqlite3_stmt
*pStmt
= 0;
629 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
631 if( pVTab
->zErrMsg
==0 ){
632 pVTab
->zErrMsg
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
635 if( pVal
) sqlite3_bind_value(pStmt
, 1, pVal
);
637 rc
= sqlite3_reset(pStmt
);
638 if( rc
&& pVTab
->zErrMsg
==0 ){
639 pVTab
->zErrMsg
= sqlite3_mprintf("%s", sqlite3_errmsg(db
));
642 sqlite3_finalize(pStmt
);
646 sqlite3RunSql(db
,pVTab
,
647 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'nOrderBy',%d)",
648 zLogTab
, iBI
, pInfo
->nOrderBy
650 for(i
=0; i
<pInfo
->nOrderBy
; i
++){
651 int iCol
= pInfo
->aOrderBy
[i
].iColumn
;
652 sqlite3RunSql(db
,pVTab
,
653 "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op)VALUES(%d,'aOrderBy',%d,%Q,%d)",
656 iCol
>=0 ? azColname
[iCol
] : "rowid",
657 pInfo
->aOrderBy
[i
].desc
660 sqlite3RunSql(db
,pVTab
,
661 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'sqlite3_vtab_distinct',%d)",
662 zLogTab
, iBI
, sqlite3_vtab_distinct(pInfo
)
664 sqlite3RunSql(db
,pVTab
,
665 "INSERT INTO temp.\"%w\"(bi,vn,ix) VALUES(%d,'colUsed',%lld)",
666 zLogTab
, iBI
, pInfo
->colUsed
668 for(i
=0; i
<pInfo
->nConstraint
; i
++){
669 int iCol
= pInfo
->aConstraint
[i
].iColumn
;
670 int op
= pInfo
->aConstraint
[i
].op
;
672 if( op
==SQLITE_INDEX_CONSTRAINT_LIMIT
673 || op
==SQLITE_INDEX_CONSTRAINT_OFFSET
679 zCol
= azColname
[iCol
];
681 sqlite3RunSql(db
,pVTab
,
682 "INSERT INTO temp.\"%w\"(bi,vn,ix,cn,op,ux)"
683 "VALUES(%d,'aConstraintUsage',%d,%Q,%d,%d)",
687 pInfo
->aConstraintUsage
[i
].argvIndex
,
688 pInfo
->aConstraintUsage
[i
].omit
691 sqlite3RunSql(db
,pVTab
,
692 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'idxNum',%d)",
693 zLogTab
, iBI
, pInfo
->idxNum
695 sqlite3RunSql(db
,pVTab
,
696 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'estimatedCost',%f)",
697 zLogTab
, iBI
, pInfo
->estimatedCost
699 sqlite3RunSql(db
,pVTab
,
700 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'estimatedRows',%lld)",
701 zLogTab
, iBI
, pInfo
->estimatedRows
704 sqlite3RunSql(db
,pVTab
,
705 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'idxStr',%Q)",
706 zLogTab
, iBI
, pInfo
->idxStr
708 sqlite3RunSql(db
,pVTab
,
709 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'needToFreeIdxStr',%d)",
710 zLogTab
, iBI
, pInfo
->needToFreeIdxStr
713 if( pInfo
->nOrderBy
){
714 sqlite3RunSql(db
,pVTab
,
715 "INSERT INTO temp.\"%w\"(bi,vn,ix)VALUES(%d,'orderByConsumed',%d)",
716 zLogTab
, iBI
, pInfo
->orderByConsumed
721 ** End of Logging Subsystem
722 *****************************************************************************/
725 /* Find an estimated cost of running a query against vt02.
727 static int vt02BestIndex(sqlite3_vtab
*pVTab
, sqlite3_index_info
*pInfo
){
728 int i
; /* Loop counter */
729 int isEq
[5]; /* Equality constraints on X, A, B, C, and D */
730 int isUsed
[5]; /* Other non-== cosntraints X, A, B, C, and D */
731 int argvIndex
= 0; /* Next available argv[] slot */
732 int iOffset
= -1; /* Constraint for OFFSET */
733 void *pX
= 0; /* idxStr value */
734 int flags
= 0; /* RHS value for flags= */
735 const char *zLogTab
= 0; /* RHS value for logtab= */
736 int iFlagTerm
= -1; /* Constraint term for flags= */
737 int iLogTerm
= -1; /* Constraint term for logtab= */
738 int iIn
= -1; /* Index of the IN constraint */
739 vt02_vtab
*pSelf
; /* This virtual table */
741 pSelf
= (vt02_vtab
*)pVTab
;
743 vt02ErrMsg(pVTab
, "recursive use of vt02 prohibited");
744 return SQLITE_CONSTRAINT
;
749 /* Do an initial scan for flags=N and logtab=TAB constraints with
750 ** usable RHS values */
751 for(i
=0; i
<pInfo
->nConstraint
; i
++){
753 if( !pInfo
->aConstraint
[i
].usable
) continue;
754 if( pInfo
->aConstraint
[i
].op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
755 switch( pInfo
->aConstraint
[i
].iColumn
){
757 if( sqlite3_vtab_rhs_value(pInfo
, i
, &pVal
)==SQLITE_OK
758 && sqlite3_value_type(pVal
)==SQLITE_INTEGER
760 flags
= sqlite3_value_int(pVal
);
764 case VT02_COL_LOGTAB
:
765 if( sqlite3_vtab_rhs_value(pInfo
, i
, &pVal
)==SQLITE_OK
766 && sqlite3_value_type(pVal
)==SQLITE_TEXT
768 zLogTab
= (const char*)sqlite3_value_text(pVal
);
775 /* Do a second scan to actually analyze the index information */
776 memset(isEq
, 0xff, sizeof(isEq
));
777 memset(isUsed
, 0xff, sizeof(isUsed
));
778 for(i
=0; i
<pInfo
->nConstraint
; i
++){
779 int j
= pInfo
->aConstraint
[i
].iColumn
;
780 if( j
>=VT02_COL_FLAGS
) continue;
781 if( pInfo
->aConstraint
[i
].usable
==0
782 && (flags
& VT02_IGNORE_USABLE
)==0 ) continue;
783 if( j
<0 ) j
= VT02_COL_X
;
784 switch( pInfo
->aConstraint
[i
].op
){
785 case SQLITE_INDEX_CONSTRAINT_FUNCTION
:
786 case SQLITE_INDEX_CONSTRAINT_EQ
:
789 case SQLITE_INDEX_CONSTRAINT_LT
:
790 case SQLITE_INDEX_CONSTRAINT_LE
:
791 case SQLITE_INDEX_CONSTRAINT_GT
:
792 case SQLITE_INDEX_CONSTRAINT_GE
:
795 case SQLITE_INDEX_CONSTRAINT_OFFSET
:
801 /* Use the analysis to find an appropriate query plan */
803 /* A constraint of X= takes priority */
804 pInfo
->estimatedCost
= 1;
805 pInfo
->aConstraintUsage
[isEq
[0]].argvIndex
= ++argvIndex
;
806 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[isEq
[0]].omit
= 1;
808 }else if( isEq
[1]<0 ){
809 /* If there is no X= nor A= then we have to do a full scan */
811 pInfo
->estimatedCost
= 10000;
814 pInfo
->aConstraintUsage
[isEq
[1]].argvIndex
= ++argvIndex
;
815 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[isEq
[1]].omit
= 1;
816 for(i
=2; i
<=4 && isEq
[i
]>=0; i
++){
817 if( i
==4 && sqlite3_vtab_in(pInfo
, isEq
[4], 0) ) break;
818 pInfo
->aConstraintUsage
[isEq
[i
]].argvIndex
= ++argvIndex
;
819 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[isEq
[i
]].omit
= 1;
823 if( isEq
[4]>=0 && sqlite3_vtab_in(pInfo
,isEq
[4],1) ){
825 pInfo
->aConstraintUsage
[iIn
].argvIndex
= ++argvIndex
;
826 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[iIn
].omit
= 1;
831 pInfo
->estimatedCost
= v
;
833 pInfo
->estimatedRows
= (sqlite3_int64
)pInfo
->estimatedCost
;
835 /* Attempt to consume the ORDER BY clause. Except, always leave
836 ** orderByConsumed set to 0 for vt02_no_sort_opt. In this way,
837 ** we can compare vt02 and vt02_no_sort_opt to ensure they get
840 if( pInfo
->nOrderBy
>0 && (flags
& VT02_NO_SORT_OPT
)==0 ){
841 if( pInfo
->idxNum
==1 ){
842 /* There will only be one row of output. So it is always sorted. */
843 pInfo
->orderByConsumed
= 1;
845 if( pInfo
->aOrderBy
[0].iColumn
<=0
846 && pInfo
->aOrderBy
[0].desc
==0
848 /* First column of order by is X ascending */
849 pInfo
->orderByConsumed
= 1;
851 if( sqlite3_vtab_distinct(pInfo
)>=1 ){
853 for(i
=0; i
<pInfo
->nOrderBy
; i
++){
854 int iCol
= pInfo
->aOrderBy
[i
].iColumn
;
855 if( iCol
<0 ) iCol
= 0;
858 if( sqlite3_vtab_distinct(pInfo
)==2 ){
862 pInfo
->orderByConsumed
= 1;
866 pInfo
->orderByConsumed
= 1;
870 pInfo
->orderByConsumed
= 1;
871 }else if( x
& 0x01 ){
873 pInfo
->orderByConsumed
= 1;
875 /* DISTINCT A,B,C,D */
876 pInfo
->orderByConsumed
= 1;
881 pInfo
->orderByConsumed
= 1;
884 pInfo
->orderByConsumed
= 1;
887 pInfo
->orderByConsumed
= 1;
888 }else if( x
& 0x01 ){
890 pInfo
->orderByConsumed
= 1;
892 /* GROUP BY A,B,C,D */
893 pInfo
->orderByConsumed
= 1;
899 if( flags
& VT02_ALLOC_IDXSTR
){
900 pInfo
->idxStr
= sqlite3_mprintf("test");
901 pInfo
->needToFreeIdxStr
= 1;
903 if( flags
& VT02_BAD_IDXNUM
){
904 pInfo
->idxNum
+= 1000;
908 pInfo
->aConstraintUsage
[iOffset
].argvIndex
= ++argvIndex
;
909 if( (flags
& VT02_NO_OFFSET
)==0
910 && (pInfo
->nOrderBy
==0 || pInfo
->orderByConsumed
)
912 pInfo
->aConstraintUsage
[iOffset
].omit
= 1;
913 pInfo
->idxNum
+= 100;
918 /* Always omit flags= and logtab= constraints to prevent them from
919 ** interfering with the bytecode. Put them at the end of the argv[]
920 ** array to keep them out of the way.
923 pInfo
->aConstraintUsage
[iFlagTerm
].omit
= 1;
924 pInfo
->aConstraintUsage
[iFlagTerm
].argvIndex
= ++argvIndex
;
927 pInfo
->aConstraintUsage
[iLogTerm
].omit
= 1;
928 pInfo
->aConstraintUsage
[iLogTerm
].argvIndex
= ++argvIndex
;
931 /* The 0x40 flag means add all usable constraints to the output set */
933 for(i
=0; i
<pInfo
->nConstraint
; i
++){
934 if( pInfo
->aConstraint
[i
].usable
935 && pInfo
->aConstraintUsage
[i
].argvIndex
==0
937 pInfo
->aConstraintUsage
[i
].argvIndex
= ++argvIndex
;
938 if( flags
& 0x20 ) pInfo
->aConstraintUsage
[i
].omit
= 1;
944 /* Generate the log if requested */
946 static const char *azColname
[] = {
947 "x", "a", "b", "c", "d", "flags", "logtab"
949 sqlite3
*db
= ((vt02_vtab
*)pVTab
)->db
;
950 sqlite3BestIndexLog(pInfo
, zLogTab
, db
, azColname
, pVTab
);
954 /* Try to do a memory allocation solely for the purpose of causing
955 ** an error under OOM testing loops */
956 pX
= sqlite3_malloc(800);
957 if( pX
==0 ) return SQLITE_NOMEM
;
960 return pVTab
->zErrMsg
!=0 ? SQLITE_ERROR
: SQLITE_OK
;
963 /* This is the sqlite3_module definition for the the virtual table defined
964 ** by this include file.
966 const sqlite3_module vt02Module
= {
968 /* xCreate */ 0, /* This is an eponymous table */
969 /* xConnect */ vt02Connect
,
970 /* xBestIndex */ vt02BestIndex
,
971 /* xDisconnect */ vt02Disconnect
,
972 /* xDestroy */ vt02Disconnect
,
973 /* xOpen */ vt02Open
,
974 /* xClose */ vt02Close
,
975 /* xFilter */ vt02Filter
,
976 /* xNext */ vt02Next
,
978 /* xColumn */ vt02Column
,
979 /* xRowid */ vt02Rowid
,
985 /* xFindFunction */ 0,
994 static void vt02CoreInit(sqlite3
*db
){
995 static const char zPkXSchema
[] =
996 "CREATE TABLE x(x INT NOT NULL PRIMARY KEY, a INT, b INT, c INT, d INT,"
997 " flags INT HIDDEN, logtab TEXT HIDDEN);";
998 static const char zPkABCDSchema
[] =
999 "CREATE TABLE x(x INT, a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, "
1000 "d INT NOT NULL, flags INT HIDDEN, logtab TEXT HIDDEN, "
1001 "PRIMARY KEY(a,b,c,d));";
1002 sqlite3_create_module(db
, "vt02", &vt02Module
, 0);
1003 sqlite3_create_module(db
, "vt02pkx", &vt02Module
, (void*)zPkXSchema
);
1004 sqlite3_create_module(db
, "vt02pkabcd", &vt02Module
, (void*)zPkABCDSchema
);
1008 static void vt02_init(th3state
*p
, int iDb
, char *zArg
){
1009 vt02CoreInit(th3dbPointer(p
, iDb
));
1013 __declspec(dllexport
)
1015 int sqlite3_vt02_init(
1018 const sqlite3_api_routines
*pApi
1020 SQLITE_EXTENSION_INIT2(pApi
);
1024 #endif /* TH3_VERSION */