1 /* 2 ** 2022-01-19 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 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. 10 ** 11 ************************************************************************* 12 ** 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. 16 ** 17 ** The schema of the virtual table is this: 18 ** 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() 26 ** 27 ** a, b, c, d, e, -- Extra columns to attach constraints to 28 ** 29 ** flags INTEGER HIDDEN -- control flags 30 ** ); 31 ** 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. 35 ** 36 ** The values of the "a" through "e" columns are one of: 37 ** 38 ** 1. TEXT - the same as the column name 39 ** 2. INTEGER - 1 for "a", 2 for "b", and so forth 40 ** 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. 44 ** 45 ** All constraints on columns "a" through "e" are marked as "omit". 46 ** 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. 50 ** 51 ** FLAGS SUMMARY: 52 ** 53 ** 0x001 Columns 'a' through 'e' have INT values 54 ** 0x002 orderByConsumed is set 55 ** 0x004 OFFSET and LIMIT have omit set 56 ** 57 ** COMPILE: 58 ** 59 ** gcc -Wall -g -shared -fPIC -I. qpvtab.c -o qqvtab.so 60 ** 61 ** EXAMPLE USAGE: 62 ** 63 ** .load ./qpvtab 64 ** SELECT rowid, *, flags FROM qpvtab(102) 65 ** WHERE a=19 66 ** AND b BETWEEN 4.5 and 'hello' 67 ** AND c<>x'aabbcc' 68 ** ORDER BY d, e DESC; 69 */ 70 #if !defined(SQLITEINT_H) 71 #include "sqlite3ext.h" 72 #endif 73 SQLITE_EXTENSION_INIT1 74 #include <string.h> 75 #include <assert.h> 76 #include <stdlib.h> 77 78 #if !defined(SQLITE_OMIT_VIRTUALTABLE) 79 80 /* qpvtab_vtab is a subclass of sqlite3_vtab which is 81 ** underlying representation of the virtual table 82 */ 83 typedef struct qpvtab_vtab qpvtab_vtab; 84 struct qpvtab_vtab { 85 sqlite3_vtab base; /* Base class - must be first */ 86 }; 87 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 91 */ 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 */ 99 }; 100 101 /* 102 ** Names of columns 103 */ 104 static const char *azColname[] = { 105 "vn", 106 "ix", 107 "cn", 108 "op", 109 "ux", 110 "rhs", 111 "a", "b", "c", "d", "e", 112 "flags", 113 "" 114 }; 115 116 /* 117 ** The qpvtabConnect() method is invoked to create a new 118 ** qpvtab virtual table. 119 */ 120 static int qpvtabConnect( 121 sqlite3 *db, 122 void *pAux, 123 int argc, const char *const*argv, 124 sqlite3_vtab **ppVtab, 125 char **pzErr 126 ){ 127 qpvtab_vtab *pNew; 128 int rc; 129 130 rc = sqlite3_declare_vtab(db, 131 "CREATE TABLE x(" 132 " vn TEXT," 133 " ix INT," 134 " cn TEXT," 135 " op INT," 136 " ux BOOLEAN," 137 " rhs TEXT," 138 " a, b, c, d, e," 139 " flags INT HIDDEN)" 140 ); 141 #define QPVTAB_VN 0 142 #define QPVTAB_IX 1 143 #define QPVTAB_CN 2 144 #define QPVTAB_OP 3 145 #define QPVTAB_UX 4 146 #define QPVTAB_RHS 5 147 #define QPVTAB_A 6 148 #define QPVTAB_B 7 149 #define QPVTAB_C 8 150 #define QPVTAB_D 9 151 #define QPVTAB_E 10 152 #define QPVTAB_FLAGS 11 153 #define QPVTAB_NONE 12 154 if( rc==SQLITE_OK ){ 155 pNew = sqlite3_malloc( sizeof(*pNew) ); 156 *ppVtab = (sqlite3_vtab*)pNew; 157 if( pNew==0 ) return SQLITE_NOMEM; 158 memset(pNew, 0, sizeof(*pNew)); 159 } 160 return rc; 161 } 162 163 /* 164 ** This method is the destructor for qpvtab_vtab objects. 165 */ 166 static int qpvtabDisconnect(sqlite3_vtab *pVtab){ 167 qpvtab_vtab *p = (qpvtab_vtab*)pVtab; 168 sqlite3_free(p); 169 return SQLITE_OK; 170 } 171 172 /* 173 ** Constructor for a new qpvtab_cursor object. 174 */ 175 static int qpvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ 176 qpvtab_cursor *pCur; 177 pCur = sqlite3_malloc( sizeof(*pCur) ); 178 if( pCur==0 ) return SQLITE_NOMEM; 179 memset(pCur, 0, sizeof(*pCur)); 180 *ppCursor = &pCur->base; 181 return SQLITE_OK; 182 } 183 184 /* 185 ** Destructor for a qpvtab_cursor. 186 */ 187 static int qpvtabClose(sqlite3_vtab_cursor *cur){ 188 qpvtab_cursor *pCur = (qpvtab_cursor*)cur; 189 sqlite3_free(pCur); 190 return SQLITE_OK; 191 } 192 193 194 /* 195 ** Advance a qpvtab_cursor to its next row of output. 196 */ 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'); 202 if( zEnd ) zEnd++; 203 pCur->iRowid = (int)(zEnd - pCur->zData); 204 } 205 return SQLITE_OK; 206 } 207 208 /* 209 ** Return values of columns for the row at which the qpvtab_cursor 210 ** is currently pointing. 211 */ 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 */ 216 ){ 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]; 220 const char *zEnd; 221 int j; 222 j = QPVTAB_VN; 223 while(1){ 224 zEnd = strchr(z, j==QPVTAB_RHS ? '\n' : ','); 225 if( j==i || zEnd==0 ) break; 226 z = zEnd+1; 227 j++; 228 } 229 if( zEnd==z ){ 230 sqlite3_result_null(ctx); 231 }else if( i==QPVTAB_IX || i==QPVTAB_OP || i==QPVTAB_UX ){ 232 sqlite3_result_int(ctx, atoi(z)); 233 }else{ 234 sqlite3_result_text64(ctx, z, zEnd-z, SQLITE_TRANSIENT, SQLITE_UTF8); 235 } 236 }else if( i>=QPVTAB_A && i<=QPVTAB_E ){ 237 if( pCur->flags & 0x001 ){ 238 sqlite3_result_int(ctx, i-QPVTAB_A+1); 239 }else{ 240 char x = 'a'+i-QPVTAB_A; 241 sqlite3_result_text64(ctx, &x, 1, SQLITE_TRANSIENT, SQLITE_UTF8); 242 } 243 }else if( i==QPVTAB_FLAGS ){ 244 sqlite3_result_int(ctx, pCur->flags); 245 } 246 return SQLITE_OK; 247 } 248 249 /* 250 ** Return the rowid for the current row. In this implementation, the 251 ** rowid is the same as the output value. 252 */ 253 static int qpvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 254 qpvtab_cursor *pCur = (qpvtab_cursor*)cur; 255 *pRowid = pCur->iRowid; 256 return SQLITE_OK; 257 } 258 259 /* 260 ** Return TRUE if the cursor has been moved off of the last 261 ** row of output. 262 */ 263 static int qpvtabEof(sqlite3_vtab_cursor *cur){ 264 qpvtab_cursor *pCur = (qpvtab_cursor*)cur; 265 return pCur->iRowid>=pCur->nData; 266 } 267 268 /* 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 272 ** qpvtabEof(). 273 */ 274 static int qpvtabFilter( 275 sqlite3_vtab_cursor *pVtabCursor, 276 int idxNum, const char *idxStr, 277 int argc, sqlite3_value **argv 278 ){ 279 qpvtab_cursor *pCur = (qpvtab_cursor *)pVtabCursor; 280 pCur->iRowid = 0; 281 pCur->zData = idxStr; 282 pCur->nData = (int)strlen(idxStr); 283 pCur->flags = idxNum; 284 return SQLITE_OK; 285 } 286 287 /* 288 ** Append the text of a value to pStr 289 */ 290 static void qpvtabStrAppendValue( 291 sqlite3_str *pStr, 292 sqlite3_value *pVal 293 ){ 294 switch( sqlite3_value_type(pVal) ){ 295 case SQLITE_NULL: 296 sqlite3_str_appendf(pStr, "NULL"); 297 break; 298 case SQLITE_INTEGER: 299 sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pVal)); 300 break; 301 case SQLITE_FLOAT: 302 sqlite3_str_appendf(pStr, "%!f", sqlite3_value_double(pVal)); 303 break; 304 case SQLITE_TEXT: { 305 int i; 306 const char *a = (const char*)sqlite3_value_text(pVal); 307 int n = sqlite3_value_bytes(pVal); 308 sqlite3_str_append(pStr, "'", 1); 309 for(i=0; i<n; i++){ 310 char c = a[i]; 311 if( c=='\n' ) c = ' '; 312 sqlite3_str_append(pStr, &c, 1); 313 if( c=='\'' ) sqlite3_str_append(pStr, &c, 1); 314 } 315 sqlite3_str_append(pStr, "'", 1); 316 break; 317 } 318 case SQLITE_BLOB: { 319 int i; 320 const unsigned char *a = sqlite3_value_blob(pVal); 321 int n = sqlite3_value_bytes(pVal); 322 sqlite3_str_append(pStr, "x'", 2); 323 for(i=0; i<n; i++){ 324 sqlite3_str_appendf(pStr, "%02x", a[i]); 325 } 326 sqlite3_str_append(pStr, "'", 1); 327 break; 328 } 329 } 330 } 331 332 /* 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 336 ** plan. 337 */ 338 static int qpvtabBestIndex( 339 sqlite3_vtab *tab, 340 sqlite3_index_info *pIdxInfo 341 ){ 342 sqlite3_str *pStr = sqlite3_str_new(0); 343 int i, k = 0; 344 int rc; 345 sqlite3_str_appendf(pStr, "nConstraint,%d,,,,\n", pIdxInfo->nConstraint); 346 for(i=0; i<pIdxInfo->nConstraint; i++){ 347 sqlite3_value *pVal; 348 int iCol = pIdxInfo->aConstraint[i].iColumn; 349 int op = pIdxInfo->aConstraint[i].op; 350 if( iCol==QPVTAB_FLAGS && pIdxInfo->aConstraint[i].usable ){ 351 pVal = 0; 352 rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); 353 assert( rc==SQLITE_OK || pVal==0 ); 354 if( pVal ){ 355 pIdxInfo->idxNum = sqlite3_value_int(pVal); 356 if( pIdxInfo->idxNum & 0x002 ) pIdxInfo->orderByConsumed = 1; 357 } 358 } 359 if( op==SQLITE_INDEX_CONSTRAINT_LIMIT 360 || op==SQLITE_INDEX_CONSTRAINT_OFFSET 361 ){ 362 iCol = QPVTAB_NONE; 363 } 364 sqlite3_str_appendf(pStr,"aConstraint,%d,%s,%d,%d,", 365 i, 366 azColname[iCol], 367 op, 368 pIdxInfo->aConstraint[i].usable); 369 pVal = 0; 370 rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); 371 assert( rc==SQLITE_OK || pVal==0 ); 372 if( pVal ){ 373 qpvtabStrAppendValue(pStr, pVal); 374 } 375 sqlite3_str_append(pStr, "\n", 1); 376 } 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 382 ){ 383 iCol = QPVTAB_NONE; 384 } 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; 389 } 390 } 391 } 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 398 ); 399 } 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; 411 return SQLITE_OK; 412 } 413 414 /* 415 ** This following structure defines all the methods for the 416 ** virtual table. 417 */ 418 static sqlite3_module qpvtabModule = { 419 /* iVersion */ 0, 420 /* xCreate */ 0, 421 /* xConnect */ qpvtabConnect, 422 /* xBestIndex */ qpvtabBestIndex, 423 /* xDisconnect */ qpvtabDisconnect, 424 /* xDestroy */ 0, 425 /* xOpen */ qpvtabOpen, 426 /* xClose */ qpvtabClose, 427 /* xFilter */ qpvtabFilter, 428 /* xNext */ qpvtabNext, 429 /* xEof */ qpvtabEof, 430 /* xColumn */ qpvtabColumn, 431 /* xRowid */ qpvtabRowid, 432 /* xUpdate */ 0, 433 /* xBegin */ 0, 434 /* xSync */ 0, 435 /* xCommit */ 0, 436 /* xRollback */ 0, 437 /* xFindMethod */ 0, 438 /* xRename */ 0, 439 /* xSavepoint */ 0, 440 /* xRelease */ 0, 441 /* xRollbackTo */ 0, 442 /* xShadowName */ 0 443 }; 444 #endif /* SQLITE_OMIT_VIRTUALTABLE */ 445 446 447 #ifdef _WIN32 448 __declspec(dllexport) 449 #endif 450 int sqlite3_qpvtab_init( 451 sqlite3 *db, 452 char **pzErrMsg, 453 const sqlite3_api_routines *pApi 454 ){ 455 int rc = SQLITE_OK; 456 SQLITE_EXTENSION_INIT2(pApi); 457 #ifndef SQLITE_OMIT_VIRTUALTABLE 458 rc = sqlite3_create_module(db, "qpvtab", &qpvtabModule, 0); 459 #endif 460 return rc; 461 } 462