4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This file implements a virtual-table that returns information about
14 ** how the query planner called the xBestIndex method. This virtual table
15 ** is intended for testing and debugging only.
17 ** The schema of the virtual table is this:
19 ** CREATE TABLE qpvtab(
20 ** vn TEXT, -- Name of an sqlite3_index_info field
21 ** ix INTEGER, -- Array index or value
22 ** cn TEXT, -- Column name
23 ** op INTEGER, -- operator
24 ** ux BOOLEAN, -- "usable" field
25 ** rhs TEXT, -- sqlite3_vtab_rhs_value()
27 ** a, b, c, d, e, -- Extra columns to attach constraints to
29 ** flags INTEGER HIDDEN -- control flags
32 ** The virtual table returns a description of the sqlite3_index_info object
33 ** that was provided to the (successful) xBestIndex method. There is one
34 ** row in the result table for each field in the sqlite3_index_info object.
36 ** The values of the "a" through "e" columns are one of:
38 ** 1. TEXT - the same as the column name
39 ** 2. INTEGER - 1 for "a", 2 for "b", and so forth
41 ** Option 1 is the default behavior. 2 is use if there is a usable
42 ** constraint on "flags" with an integer right-hand side that where the
43 ** value of the right-hand side has its 0x001 bit set.
45 ** All constraints on columns "a" through "e" are marked as "omit".
47 ** If there is a usable constraint on "flags" that has a RHS value that
48 ** is an integer and that integer has its 0x02 bit set, then the
49 ** orderByConsumed flag is set.
53 ** 0x001 Columns 'a' through 'e' have INT values
54 ** 0x002 orderByConsumed is set
55 ** 0x004 OFFSET and LIMIT have omit set
59 ** gcc -Wall -g -shared -fPIC -I. qpvtab.c -o qqvtab.so
64 ** SELECT rowid, *, flags FROM qpvtab(102)
66 ** AND b BETWEEN 4.5 and 'hello'
68 ** ORDER BY d, e DESC;
70 #if !defined(SQLITEINT_H)
71 #include "sqlite3ext.h"
73 SQLITE_EXTENSION_INIT1
78 #if !defined(SQLITE_OMIT_VIRTUALTABLE)
80 /* qpvtab_vtab is a subclass of sqlite3_vtab which is
81 ** underlying representation of the virtual table
83 typedef struct qpvtab_vtab qpvtab_vtab
;
85 sqlite3_vtab base
; /* Base class - must be first */
88 /* qpvtab_cursor is a subclass of sqlite3_vtab_cursor which will
89 ** serve as the underlying representation of a cursor that scans
90 ** over rows of the result
92 typedef struct qpvtab_cursor qpvtab_cursor
;
93 struct qpvtab_cursor
{
94 sqlite3_vtab_cursor base
; /* Base class - must be first */
95 sqlite3_int64 iRowid
; /* The rowid */
96 const char *zData
; /* Data to return */
97 int nData
; /* Number of bytes of data */
98 int flags
; /* Flags value */
104 static const char *azColname
[] = {
111 "a", "b", "c", "d", "e",
117 ** The qpvtabConnect() method is invoked to create a new
118 ** qpvtab virtual table.
120 static int qpvtabConnect(
123 int argc
, const char *const*argv
,
124 sqlite3_vtab
**ppVtab
,
130 rc
= sqlite3_declare_vtab(db
,
152 #define QPVTAB_FLAGS 11
153 #define QPVTAB_NONE 12
155 pNew
= sqlite3_malloc( sizeof(*pNew
) );
156 *ppVtab
= (sqlite3_vtab
*)pNew
;
157 if( pNew
==0 ) return SQLITE_NOMEM
;
158 memset(pNew
, 0, sizeof(*pNew
));
164 ** This method is the destructor for qpvtab_vtab objects.
166 static int qpvtabDisconnect(sqlite3_vtab
*pVtab
){
167 qpvtab_vtab
*p
= (qpvtab_vtab
*)pVtab
;
173 ** Constructor for a new qpvtab_cursor object.
175 static int qpvtabOpen(sqlite3_vtab
*p
, sqlite3_vtab_cursor
**ppCursor
){
177 pCur
= sqlite3_malloc( sizeof(*pCur
) );
178 if( pCur
==0 ) return SQLITE_NOMEM
;
179 memset(pCur
, 0, sizeof(*pCur
));
180 *ppCursor
= &pCur
->base
;
185 ** Destructor for a qpvtab_cursor.
187 static int qpvtabClose(sqlite3_vtab_cursor
*cur
){
188 qpvtab_cursor
*pCur
= (qpvtab_cursor
*)cur
;
195 ** Advance a qpvtab_cursor to its next row of output.
197 static int qpvtabNext(sqlite3_vtab_cursor
*cur
){
198 qpvtab_cursor
*pCur
= (qpvtab_cursor
*)cur
;
199 if( pCur
->iRowid
<pCur
->nData
){
200 const char *z
= &pCur
->zData
[pCur
->iRowid
];
201 const char *zEnd
= strchr(z
, '\n');
203 pCur
->iRowid
= (int)(zEnd
- pCur
->zData
);
209 ** Return values of columns for the row at which the qpvtab_cursor
210 ** is currently pointing.
212 static int qpvtabColumn(
213 sqlite3_vtab_cursor
*cur
, /* The cursor */
214 sqlite3_context
*ctx
, /* First argument to sqlite3_result_...() */
215 int i
/* Which column to return */
217 qpvtab_cursor
*pCur
= (qpvtab_cursor
*)cur
;
218 if( i
>=QPVTAB_VN
&& i
<=QPVTAB_RHS
&& pCur
->iRowid
<pCur
->nData
){
219 const char *z
= &pCur
->zData
[pCur
->iRowid
];
224 zEnd
= strchr(z
, j
==QPVTAB_RHS
? '\n' : ',');
225 if( j
==i
|| zEnd
==0 ) break;
230 sqlite3_result_null(ctx
);
231 }else if( i
==QPVTAB_IX
|| i
==QPVTAB_OP
|| i
==QPVTAB_UX
){
232 sqlite3_result_int(ctx
, atoi(z
));
234 sqlite3_result_text64(ctx
, z
, zEnd
-z
, SQLITE_TRANSIENT
, SQLITE_UTF8
);
236 }else if( i
>=QPVTAB_A
&& i
<=QPVTAB_E
){
237 if( pCur
->flags
& 0x001 ){
238 sqlite3_result_int(ctx
, i
-QPVTAB_A
+1);
240 char x
= 'a'+i
-QPVTAB_A
;
241 sqlite3_result_text64(ctx
, &x
, 1, SQLITE_TRANSIENT
, SQLITE_UTF8
);
243 }else if( i
==QPVTAB_FLAGS
){
244 sqlite3_result_int(ctx
, pCur
->flags
);
250 ** Return the rowid for the current row. In this implementation, the
251 ** rowid is the same as the output value.
253 static int qpvtabRowid(sqlite3_vtab_cursor
*cur
, sqlite_int64
*pRowid
){
254 qpvtab_cursor
*pCur
= (qpvtab_cursor
*)cur
;
255 *pRowid
= pCur
->iRowid
;
260 ** Return TRUE if the cursor has been moved off of the last
263 static int qpvtabEof(sqlite3_vtab_cursor
*cur
){
264 qpvtab_cursor
*pCur
= (qpvtab_cursor
*)cur
;
265 return pCur
->iRowid
>=pCur
->nData
;
269 ** This method is called to "rewind" the qpvtab_cursor object back
270 ** to the first row of output. This method is always called at least
271 ** once prior to any call to qpvtabColumn() or qpvtabRowid() or
274 static int qpvtabFilter(
275 sqlite3_vtab_cursor
*pVtabCursor
,
276 int idxNum
, const char *idxStr
,
277 int argc
, sqlite3_value
**argv
279 qpvtab_cursor
*pCur
= (qpvtab_cursor
*)pVtabCursor
;
281 pCur
->zData
= idxStr
;
282 pCur
->nData
= (int)strlen(idxStr
);
283 pCur
->flags
= idxNum
;
288 ** Append the text of a value to pStr
290 static void qpvtabStrAppendValue(
294 switch( sqlite3_value_type(pVal
) ){
296 sqlite3_str_appendf(pStr
, "NULL");
299 sqlite3_str_appendf(pStr
, "%lld", sqlite3_value_int64(pVal
));
302 sqlite3_str_appendf(pStr
, "%!f", sqlite3_value_double(pVal
));
306 const char *a
= (const char*)sqlite3_value_text(pVal
);
307 int n
= sqlite3_value_bytes(pVal
);
308 sqlite3_str_append(pStr
, "'", 1);
311 if( c
=='\n' ) c
= ' ';
312 sqlite3_str_append(pStr
, &c
, 1);
313 if( c
=='\'' ) sqlite3_str_append(pStr
, &c
, 1);
315 sqlite3_str_append(pStr
, "'", 1);
320 const unsigned char *a
= sqlite3_value_blob(pVal
);
321 int n
= sqlite3_value_bytes(pVal
);
322 sqlite3_str_append(pStr
, "x'", 2);
324 sqlite3_str_appendf(pStr
, "%02x", a
[i
]);
326 sqlite3_str_append(pStr
, "'", 1);
333 ** SQLite will invoke this method one or more times while planning a query
334 ** that uses the virtual table. This routine needs to create
335 ** a query plan for each invocation and compute an estimated cost for that
338 static int qpvtabBestIndex(
340 sqlite3_index_info
*pIdxInfo
342 sqlite3_str
*pStr
= sqlite3_str_new(0);
345 sqlite3_str_appendf(pStr
, "nConstraint,%d,,,,\n", pIdxInfo
->nConstraint
);
346 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
348 int iCol
= pIdxInfo
->aConstraint
[i
].iColumn
;
349 int op
= pIdxInfo
->aConstraint
[i
].op
;
350 if( iCol
==QPVTAB_FLAGS
&& pIdxInfo
->aConstraint
[i
].usable
){
352 rc
= sqlite3_vtab_rhs_value(pIdxInfo
, i
, &pVal
);
353 assert( rc
==SQLITE_OK
|| pVal
==0 );
355 pIdxInfo
->idxNum
= sqlite3_value_int(pVal
);
356 if( pIdxInfo
->idxNum
& 0x002 ) pIdxInfo
->orderByConsumed
= 1;
359 if( op
==SQLITE_INDEX_CONSTRAINT_LIMIT
360 || op
==SQLITE_INDEX_CONSTRAINT_OFFSET
364 sqlite3_str_appendf(pStr
,"aConstraint,%d,%s,%d,%d,",
368 pIdxInfo
->aConstraint
[i
].usable
);
370 rc
= sqlite3_vtab_rhs_value(pIdxInfo
, i
, &pVal
);
371 assert( rc
==SQLITE_OK
|| pVal
==0 );
373 qpvtabStrAppendValue(pStr
, pVal
);
375 sqlite3_str_append(pStr
, "\n", 1);
377 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
378 int iCol
= pIdxInfo
->aConstraint
[i
].iColumn
;
379 int op
= pIdxInfo
->aConstraint
[i
].op
;
380 if( op
==SQLITE_INDEX_CONSTRAINT_LIMIT
381 || op
==SQLITE_INDEX_CONSTRAINT_OFFSET
385 if( iCol
>=QPVTAB_A
&& pIdxInfo
->aConstraint
[i
].usable
){
386 pIdxInfo
->aConstraintUsage
[i
].argvIndex
= ++k
;
387 if( iCol
<=QPVTAB_FLAGS
|| (pIdxInfo
->idxNum
& 0x004)!=0 ){
388 pIdxInfo
->aConstraintUsage
[i
].omit
= 1;
392 sqlite3_str_appendf(pStr
, "nOrderBy,%d,,,,\n", pIdxInfo
->nOrderBy
);
393 for(i
=0; i
<pIdxInfo
->nOrderBy
; i
++){
394 int iCol
= pIdxInfo
->aOrderBy
[i
].iColumn
;
395 sqlite3_str_appendf(pStr
, "aOrderBy,%d,%s,%d,,\n",i
,
396 iCol
>=0 ? azColname
[iCol
] : "rowid",
397 pIdxInfo
->aOrderBy
[i
].desc
400 sqlite3_str_appendf(pStr
, "sqlite3_vtab_distinct,%d,,,,\n",
401 sqlite3_vtab_distinct(pIdxInfo
));
402 sqlite3_str_appendf(pStr
, "idxFlags,%d,,,,\n", pIdxInfo
->idxFlags
);
403 sqlite3_str_appendf(pStr
, "colUsed,%d,,,,\n", (int)pIdxInfo
->colUsed
);
404 pIdxInfo
->estimatedCost
= (double)10;
405 pIdxInfo
->estimatedRows
= 10;
406 sqlite3_str_appendf(pStr
, "idxNum,%d,,,,\n", pIdxInfo
->idxNum
);
407 sqlite3_str_appendf(pStr
, "orderByConsumed,%d,,,,\n",
408 pIdxInfo
->orderByConsumed
);
409 pIdxInfo
->idxStr
= sqlite3_str_finish(pStr
);
410 pIdxInfo
->needToFreeIdxStr
= 1;
415 ** This following structure defines all the methods for the
418 static sqlite3_module qpvtabModule
= {
421 /* xConnect */ qpvtabConnect
,
422 /* xBestIndex */ qpvtabBestIndex
,
423 /* xDisconnect */ qpvtabDisconnect
,
425 /* xOpen */ qpvtabOpen
,
426 /* xClose */ qpvtabClose
,
427 /* xFilter */ qpvtabFilter
,
428 /* xNext */ qpvtabNext
,
429 /* xEof */ qpvtabEof
,
430 /* xColumn */ qpvtabColumn
,
431 /* xRowid */ qpvtabRowid
,
445 #endif /* SQLITE_OMIT_VIRTUALTABLE */
449 __declspec(dllexport
)
451 int sqlite3_qpvtab_init(
454 const sqlite3_api_routines
*pApi
457 SQLITE_EXTENSION_INIT2(pApi
);
458 #ifndef SQLITE_OMIT_VIRTUALTABLE
459 rc
= sqlite3_create_module(db
, "qpvtab", &qpvtabModule
, 0);