1 /* 2 ** 2013 Jan 11 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 ** Code for testing the virtual table interfaces. This code 13 ** is not included in the SQLite library. It is used for automated 14 ** testing of the SQLite library. 15 ** 16 ** The FS virtual table is created as follows: 17 ** 18 ** CREATE VIRTUAL TABLE tbl USING fs(idx); 19 ** 20 ** where idx is the name of a table in the db with 2 columns. The virtual 21 ** table also has two columns - file path and file contents. 22 ** 23 ** The first column of table idx must be an IPK, and the second contains file 24 ** paths. For example: 25 ** 26 ** CREATE TABLE idx(id INTEGER PRIMARY KEY, path TEXT); 27 ** INSERT INTO idx VALUES(4, '/etc/passwd'); 28 ** 29 ** Adding the row to the idx table automatically creates a row in the 30 ** virtual table with rowid=4, path=/etc/passwd and a text field that 31 ** contains data read from file /etc/passwd on disk. 32 ** 33 ************************************************************************* 34 ** Virtual table module "fsdir" 35 ** 36 ** This module is designed to be used as a read-only eponymous virtual table. 37 ** Its schema is as follows: 38 ** 39 ** CREATE TABLE fsdir(dir TEXT, name TEXT); 40 ** 41 ** When queried, a WHERE term of the form "dir = $dir" must be provided. The 42 ** virtual table then appears to have one row for each entry in file-system 43 ** directory $dir. Column dir contains a copy of $dir, and column "name" 44 ** contains the name of the directory entry. 45 ** 46 ** If the specified $dir cannot be opened or is not a directory, it is not 47 ** an error. The virtual table appears to be empty in this case. 48 ** 49 ************************************************************************* 50 ** Virtual table module "fstree" 51 ** 52 ** This module is also a read-only eponymous virtual table with the 53 ** following schema: 54 ** 55 ** CREATE TABLE fstree(path TEXT, size INT, data BLOB); 56 ** 57 ** Running a "SELECT * FROM fstree" query on this table returns the entire 58 ** contents of the file-system, starting at "/". To restrict the search 59 ** space, the virtual table supports LIKE and GLOB constraints on the 60 ** 'path' column. For example: 61 ** 62 ** SELECT * FROM fstree WHERE path LIKE '/home/dan/sqlite/%' 63 */ 64 #include "sqliteInt.h" 65 #if defined(INCLUDE_SQLITE_TCL_H) 66 # include "sqlite_tcl.h" 67 #else 68 # include "tcl.h" 69 #endif 70 71 #include <stdlib.h> 72 #include <string.h> 73 #include <sys/types.h> 74 #include <sys/stat.h> 75 #include <fcntl.h> 76 77 #if SQLITE_OS_UNIX || defined(__MINGW_H) 78 # include <unistd.h> 79 # include <dirent.h> 80 # ifndef DIRENT 81 # define DIRENT dirent 82 # endif 83 #endif 84 #if SQLITE_OS_WIN 85 # include <io.h> 86 # if !defined(__MINGW_H) 87 # include "test_windirent.h" 88 # endif 89 # ifndef S_ISREG 90 # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 91 # endif 92 #endif 93 94 #ifndef SQLITE_OMIT_VIRTUALTABLE 95 96 typedef struct fs_vtab fs_vtab; 97 typedef struct fs_cursor fs_cursor; 98 99 /* 100 ** A fs virtual-table object 101 */ 102 struct fs_vtab { 103 sqlite3_vtab base; 104 sqlite3 *db; 105 char *zDb; /* Name of db containing zTbl */ 106 char *zTbl; /* Name of docid->file map table */ 107 }; 108 109 /* A fs cursor object */ 110 struct fs_cursor { 111 sqlite3_vtab_cursor base; 112 sqlite3_stmt *pStmt; 113 char *zBuf; 114 int nBuf; 115 int nAlloc; 116 }; 117 118 /************************************************************************* 119 ** Start of fsdir implementation. 120 */ 121 typedef struct FsdirVtab FsdirVtab; 122 typedef struct FsdirCsr FsdirCsr; 123 struct FsdirVtab { 124 sqlite3_vtab base; 125 }; 126 127 struct FsdirCsr { 128 sqlite3_vtab_cursor base; 129 char *zDir; /* Buffer containing directory scanned */ 130 DIR *pDir; /* Open directory */ 131 sqlite3_int64 iRowid; 132 struct DIRENT entry; /* Current entry */ 133 }; 134 135 /* 136 ** This function is the implementation of both the xConnect and xCreate 137 ** methods of the fsdir virtual table. 138 ** 139 ** The argv[] array contains the following: 140 ** 141 ** argv[0] -> module name ("fs") 142 ** argv[1] -> database name 143 ** argv[2] -> table name 144 ** argv[...] -> other module argument fields. 145 */ 146 static int fsdirConnect( 147 sqlite3 *db, 148 void *pAux, 149 int argc, const char *const*argv, 150 sqlite3_vtab **ppVtab, 151 char **pzErr 152 ){ 153 FsdirVtab *pTab; 154 155 if( argc!=3 ){ 156 *pzErr = sqlite3_mprintf("wrong number of arguments"); 157 return SQLITE_ERROR; 158 } 159 160 pTab = (FsdirVtab *)sqlite3_malloc(sizeof(FsdirVtab)); 161 if( !pTab ) return SQLITE_NOMEM; 162 memset(pTab, 0, sizeof(FsdirVtab)); 163 164 *ppVtab = &pTab->base; 165 sqlite3_declare_vtab(db, "CREATE TABLE xyz(dir, name);"); 166 167 return SQLITE_OK; 168 } 169 170 /* 171 ** xDestroy/xDisconnect implementation. 172 */ 173 static int fsdirDisconnect(sqlite3_vtab *pVtab){ 174 sqlite3_free(pVtab); 175 return SQLITE_OK; 176 } 177 178 /* 179 ** xBestIndex implementation. The only constraint supported is: 180 ** 181 ** (dir = ?) 182 */ 183 static int fsdirBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 184 int ii; 185 186 pIdxInfo->estimatedCost = 1000000000.0; 187 188 for(ii=0; ii<pIdxInfo->nConstraint; ii++){ 189 struct sqlite3_index_constraint const *p = &pIdxInfo->aConstraint[ii]; 190 if( p->iColumn==0 && p->usable && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ 191 struct sqlite3_index_constraint_usage *pUsage; 192 pUsage = &pIdxInfo->aConstraintUsage[ii]; 193 pUsage->omit = 1; 194 pUsage->argvIndex = 1; 195 pIdxInfo->idxNum = 1; 196 pIdxInfo->estimatedCost = 1.0; 197 break; 198 } 199 } 200 201 return SQLITE_OK; 202 } 203 204 /* 205 ** xOpen implementation. 206 ** 207 ** Open a new fsdir cursor. 208 */ 209 static int fsdirOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 210 FsdirCsr *pCur; 211 /* Allocate an extra 256 bytes because it is undefined how big dirent.d_name 212 ** is and we need enough space. Linux provides plenty already, but 213 ** Solaris only provides one byte. */ 214 pCur = (FsdirCsr*)sqlite3_malloc(sizeof(FsdirCsr)+256); 215 if( pCur==0 ) return SQLITE_NOMEM; 216 memset(pCur, 0, sizeof(FsdirCsr)); 217 *ppCursor = &pCur->base; 218 return SQLITE_OK; 219 } 220 221 /* 222 ** Close a fsdir cursor. 223 */ 224 static int fsdirClose(sqlite3_vtab_cursor *cur){ 225 FsdirCsr *pCur = (FsdirCsr*)cur; 226 if( pCur->pDir ) closedir(pCur->pDir); 227 sqlite3_free(pCur->zDir); 228 sqlite3_free(pCur); 229 return SQLITE_OK; 230 } 231 232 /* 233 ** Skip the cursor to the next entry. 234 */ 235 static int fsdirNext(sqlite3_vtab_cursor *cur){ 236 FsdirCsr *pCsr = (FsdirCsr*)cur; 237 238 if( pCsr->pDir ){ 239 struct DIRENT *pRes = 0; 240 #if defined(__MINGW_H) 241 pRes = readdir(pCsr->pDir); 242 if( pRes!=0 ){ 243 memcpy(&pCsr->entry, pRes, sizeof(struct DIRENT)); 244 } 245 #else 246 readdir_r(pCsr->pDir, &pCsr->entry, &pRes); 247 #endif 248 if( pRes==0 ){ 249 closedir(pCsr->pDir); 250 pCsr->pDir = 0; 251 } 252 pCsr->iRowid++; 253 } 254 255 return SQLITE_OK; 256 } 257 258 /* 259 ** xFilter method implementation. 260 */ 261 static int fsdirFilter( 262 sqlite3_vtab_cursor *pVtabCursor, 263 int idxNum, const char *idxStr, 264 int argc, sqlite3_value **argv 265 ){ 266 FsdirCsr *pCsr = (FsdirCsr*)pVtabCursor; 267 const char *zDir; 268 int nDir; 269 270 271 if( idxNum!=1 || argc!=1 ){ 272 return SQLITE_ERROR; 273 } 274 275 pCsr->iRowid = 0; 276 sqlite3_free(pCsr->zDir); 277 if( pCsr->pDir ){ 278 closedir(pCsr->pDir); 279 pCsr->pDir = 0; 280 } 281 282 zDir = (const char*)sqlite3_value_text(argv[0]); 283 nDir = sqlite3_value_bytes(argv[0]); 284 pCsr->zDir = sqlite3_malloc(nDir+1); 285 if( pCsr->zDir==0 ) return SQLITE_NOMEM; 286 memcpy(pCsr->zDir, zDir, nDir+1); 287 288 pCsr->pDir = opendir(pCsr->zDir); 289 return fsdirNext(pVtabCursor); 290 } 291 292 /* 293 ** xEof method implementation. 294 */ 295 static int fsdirEof(sqlite3_vtab_cursor *cur){ 296 FsdirCsr *pCsr = (FsdirCsr*)cur; 297 return pCsr->pDir==0; 298 } 299 300 /* 301 ** xColumn method implementation. 302 */ 303 static int fsdirColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ 304 FsdirCsr *pCsr = (FsdirCsr*)cur; 305 switch( i ){ 306 case 0: /* dir */ 307 sqlite3_result_text(ctx, pCsr->zDir, -1, SQLITE_STATIC); 308 break; 309 310 case 1: /* name */ 311 sqlite3_result_text(ctx, pCsr->entry.d_name, -1, SQLITE_TRANSIENT); 312 break; 313 314 default: 315 assert( 0 ); 316 } 317 318 return SQLITE_OK; 319 } 320 321 /* 322 ** xRowid method implementation. 323 */ 324 static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 325 FsdirCsr *pCsr = (FsdirCsr*)cur; 326 *pRowid = pCsr->iRowid; 327 return SQLITE_OK; 328 } 329 /* 330 ** End of fsdir implementation. 331 *************************************************************************/ 332 333 /************************************************************************* 334 ** Start of fstree implementation. 335 */ 336 typedef struct FstreeVtab FstreeVtab; 337 typedef struct FstreeCsr FstreeCsr; 338 struct FstreeVtab { 339 sqlite3_vtab base; 340 sqlite3 *db; 341 }; 342 343 struct FstreeCsr { 344 sqlite3_vtab_cursor base; 345 sqlite3_stmt *pStmt; /* Statement to list paths */ 346 int fd; /* File descriptor open on current path */ 347 }; 348 349 /* 350 ** This function is the implementation of both the xConnect and xCreate 351 ** methods of the fstree virtual table. 352 ** 353 ** The argv[] array contains the following: 354 ** 355 ** argv[0] -> module name ("fs") 356 ** argv[1] -> database name 357 ** argv[2] -> table name 358 ** argv[...] -> other module argument fields. 359 */ 360 static int fstreeConnect( 361 sqlite3 *db, 362 void *pAux, 363 int argc, const char *const*argv, 364 sqlite3_vtab **ppVtab, 365 char **pzErr 366 ){ 367 FstreeVtab *pTab; 368 369 if( argc!=3 ){ 370 *pzErr = sqlite3_mprintf("wrong number of arguments"); 371 return SQLITE_ERROR; 372 } 373 374 pTab = (FstreeVtab *)sqlite3_malloc(sizeof(FstreeVtab)); 375 if( !pTab ) return SQLITE_NOMEM; 376 memset(pTab, 0, sizeof(FstreeVtab)); 377 pTab->db = db; 378 379 *ppVtab = &pTab->base; 380 sqlite3_declare_vtab(db, "CREATE TABLE xyz(path, size, data);"); 381 382 return SQLITE_OK; 383 } 384 385 /* 386 ** xDestroy/xDisconnect implementation. 387 */ 388 static int fstreeDisconnect(sqlite3_vtab *pVtab){ 389 sqlite3_free(pVtab); 390 return SQLITE_OK; 391 } 392 393 /* 394 ** xBestIndex implementation. The only constraint supported is: 395 ** 396 ** (dir = ?) 397 */ 398 static int fstreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 399 int ii; 400 401 for(ii=0; ii<pIdxInfo->nConstraint; ii++){ 402 struct sqlite3_index_constraint const *p = &pIdxInfo->aConstraint[ii]; 403 if( p->iColumn==0 && p->usable && ( 404 p->op==SQLITE_INDEX_CONSTRAINT_GLOB 405 || p->op==SQLITE_INDEX_CONSTRAINT_LIKE 406 || p->op==SQLITE_INDEX_CONSTRAINT_EQ 407 )){ 408 struct sqlite3_index_constraint_usage *pUsage; 409 pUsage = &pIdxInfo->aConstraintUsage[ii]; 410 pIdxInfo->idxNum = p->op; 411 pUsage->argvIndex = 1; 412 pIdxInfo->estimatedCost = 100000.0; 413 return SQLITE_OK; 414 } 415 } 416 417 pIdxInfo->estimatedCost = 1000000000.0; 418 return SQLITE_OK; 419 } 420 421 /* 422 ** xOpen implementation. 423 ** 424 ** Open a new fstree cursor. 425 */ 426 static int fstreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 427 FstreeCsr *pCur; 428 pCur = (FstreeCsr*)sqlite3_malloc(sizeof(FstreeCsr)); 429 if( pCur==0 ) return SQLITE_NOMEM; 430 memset(pCur, 0, sizeof(FstreeCsr)); 431 pCur->fd = -1; 432 *ppCursor = &pCur->base; 433 return SQLITE_OK; 434 } 435 436 static void fstreeCloseFd(FstreeCsr *pCsr){ 437 if( pCsr->fd>=0 ){ 438 close(pCsr->fd); 439 pCsr->fd = -1; 440 } 441 } 442 443 /* 444 ** Close a fstree cursor. 445 */ 446 static int fstreeClose(sqlite3_vtab_cursor *cur){ 447 FstreeCsr *pCsr = (FstreeCsr*)cur; 448 sqlite3_finalize(pCsr->pStmt); 449 fstreeCloseFd(pCsr); 450 sqlite3_free(pCsr); 451 return SQLITE_OK; 452 } 453 454 /* 455 ** Skip the cursor to the next entry. 456 */ 457 static int fstreeNext(sqlite3_vtab_cursor *cur){ 458 FstreeCsr *pCsr = (FstreeCsr*)cur; 459 int rc; 460 461 fstreeCloseFd(pCsr); 462 rc = sqlite3_step(pCsr->pStmt); 463 if( rc!=SQLITE_ROW ){ 464 rc = sqlite3_finalize(pCsr->pStmt); 465 pCsr->pStmt = 0; 466 }else{ 467 rc = SQLITE_OK; 468 pCsr->fd = open((const char*)sqlite3_column_text(pCsr->pStmt, 0), O_RDONLY); 469 } 470 471 return rc; 472 } 473 474 /* 475 ** xFilter method implementation. 476 */ 477 static int fstreeFilter( 478 sqlite3_vtab_cursor *pVtabCursor, 479 int idxNum, const char *idxStr, 480 int argc, sqlite3_value **argv 481 ){ 482 FstreeCsr *pCsr = (FstreeCsr*)pVtabCursor; 483 FstreeVtab *pTab = (FstreeVtab*)(pCsr->base.pVtab); 484 int rc; 485 const char *zSql = 486 "WITH r(d) AS (" 487 " SELECT CASE WHEN dir=?2 THEN ?3 ELSE dir END || '/' || name " 488 " FROM fsdir WHERE dir=?1 AND name NOT LIKE '.%'" 489 " UNION ALL" 490 " SELECT dir || '/' || name FROM r, fsdir WHERE dir=d AND name NOT LIKE '.%'" 491 ") SELECT d FROM r;"; 492 493 char *zRoot; 494 int nRoot; 495 char *zPrefix; 496 int nPrefix; 497 const char *zDir; 498 int nDir; 499 char aWild[2] = { '\0', '\0' }; 500 501 #if SQLITE_OS_WIN 502 const char *zDrive = windirent_getenv("fstreeDrive"); 503 if( zDrive==0 ){ 504 zDrive = windirent_getenv("SystemDrive"); 505 } 506 zRoot = sqlite3_mprintf("%s%c", zDrive, '/'); 507 nRoot = sqlite3Strlen30(zRoot); 508 zPrefix = sqlite3_mprintf("%s", zDrive); 509 nPrefix = sqlite3Strlen30(zPrefix); 510 #else 511 zRoot = "/"; 512 nRoot = 1; 513 zPrefix = ""; 514 nPrefix = 0; 515 #endif 516 517 zDir = zRoot; 518 nDir = nRoot; 519 520 fstreeCloseFd(pCsr); 521 sqlite3_finalize(pCsr->pStmt); 522 pCsr->pStmt = 0; 523 rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); 524 if( rc!=SQLITE_OK ) return rc; 525 526 if( idxNum ){ 527 const char *zQuery = (const char*)sqlite3_value_text(argv[0]); 528 switch( idxNum ){ 529 case SQLITE_INDEX_CONSTRAINT_GLOB: 530 aWild[0] = '*'; 531 aWild[1] = '?'; 532 break; 533 case SQLITE_INDEX_CONSTRAINT_LIKE: 534 aWild[0] = '_'; 535 aWild[1] = '%'; 536 break; 537 } 538 539 if( sqlite3_strnicmp(zQuery, zPrefix, nPrefix)==0 ){ 540 int i; 541 for(i=nPrefix; zQuery[i]; i++){ 542 if( zQuery[i]==aWild[0] || zQuery[i]==aWild[1] ) break; 543 if( zQuery[i]=='/' ) nDir = i; 544 } 545 zDir = zQuery; 546 } 547 } 548 if( nDir==0 ) nDir = 1; 549 550 sqlite3_bind_text(pCsr->pStmt, 1, zDir, nDir, SQLITE_TRANSIENT); 551 sqlite3_bind_text(pCsr->pStmt, 2, zRoot, nRoot, SQLITE_TRANSIENT); 552 sqlite3_bind_text(pCsr->pStmt, 3, zPrefix, nPrefix, SQLITE_TRANSIENT); 553 554 #if SQLITE_OS_WIN 555 sqlite3_free(zPrefix); 556 sqlite3_free(zRoot); 557 #endif 558 559 return fstreeNext(pVtabCursor); 560 } 561 562 /* 563 ** xEof method implementation. 564 */ 565 static int fstreeEof(sqlite3_vtab_cursor *cur){ 566 FstreeCsr *pCsr = (FstreeCsr*)cur; 567 return pCsr->pStmt==0; 568 } 569 570 /* 571 ** xColumn method implementation. 572 */ 573 static int fstreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ 574 FstreeCsr *pCsr = (FstreeCsr*)cur; 575 if( i==0 ){ /* path */ 576 sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, 0)); 577 }else{ 578 struct stat sBuf; 579 fstat(pCsr->fd, &sBuf); 580 581 if( S_ISREG(sBuf.st_mode) ){ 582 if( i==1 ){ 583 sqlite3_result_int64(ctx, sBuf.st_size); 584 }else{ 585 int nRead; 586 char *aBuf = sqlite3_malloc(sBuf.st_mode+1); 587 if( !aBuf ) return SQLITE_NOMEM; 588 nRead = read(pCsr->fd, aBuf, sBuf.st_mode); 589 if( nRead!=sBuf.st_mode ){ 590 return SQLITE_IOERR; 591 } 592 sqlite3_result_blob(ctx, aBuf, nRead, SQLITE_TRANSIENT); 593 sqlite3_free(aBuf); 594 } 595 } 596 } 597 598 return SQLITE_OK; 599 } 600 601 /* 602 ** xRowid method implementation. 603 */ 604 static int fstreeRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 605 *pRowid = 0; 606 return SQLITE_OK; 607 } 608 /* 609 ** End of fstree implementation. 610 *************************************************************************/ 611 612 613 614 615 /* 616 ** This function is the implementation of both the xConnect and xCreate 617 ** methods of the fs virtual table. 618 ** 619 ** The argv[] array contains the following: 620 ** 621 ** argv[0] -> module name ("fs") 622 ** argv[1] -> database name 623 ** argv[2] -> table name 624 ** argv[...] -> other module argument fields. 625 */ 626 static int fsConnect( 627 sqlite3 *db, 628 void *pAux, 629 int argc, const char *const*argv, 630 sqlite3_vtab **ppVtab, 631 char **pzErr 632 ){ 633 fs_vtab *pVtab; 634 int nByte; 635 const char *zTbl; 636 const char *zDb = argv[1]; 637 638 if( argc!=4 ){ 639 *pzErr = sqlite3_mprintf("wrong number of arguments"); 640 return SQLITE_ERROR; 641 } 642 zTbl = argv[3]; 643 644 nByte = sizeof(fs_vtab) + (int)strlen(zTbl) + 1 + (int)strlen(zDb) + 1; 645 pVtab = (fs_vtab *)sqlite3MallocZero( nByte ); 646 if( !pVtab ) return SQLITE_NOMEM; 647 648 pVtab->zTbl = (char *)&pVtab[1]; 649 pVtab->zDb = &pVtab->zTbl[strlen(zTbl)+1]; 650 pVtab->db = db; 651 memcpy(pVtab->zTbl, zTbl, strlen(zTbl)); 652 memcpy(pVtab->zDb, zDb, strlen(zDb)); 653 *ppVtab = &pVtab->base; 654 sqlite3_declare_vtab(db, "CREATE TABLE x(path TEXT, data TEXT)"); 655 656 return SQLITE_OK; 657 } 658 /* Note that for this virtual table, the xCreate and xConnect 659 ** methods are identical. */ 660 661 static int fsDisconnect(sqlite3_vtab *pVtab){ 662 sqlite3_free(pVtab); 663 return SQLITE_OK; 664 } 665 /* The xDisconnect and xDestroy methods are also the same */ 666 667 /* 668 ** Open a new fs cursor. 669 */ 670 static int fsOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 671 fs_cursor *pCur; 672 pCur = sqlite3MallocZero(sizeof(fs_cursor)); 673 *ppCursor = &pCur->base; 674 return SQLITE_OK; 675 } 676 677 /* 678 ** Close a fs cursor. 679 */ 680 static int fsClose(sqlite3_vtab_cursor *cur){ 681 fs_cursor *pCur = (fs_cursor *)cur; 682 sqlite3_finalize(pCur->pStmt); 683 sqlite3_free(pCur->zBuf); 684 sqlite3_free(pCur); 685 return SQLITE_OK; 686 } 687 688 static int fsNext(sqlite3_vtab_cursor *cur){ 689 fs_cursor *pCur = (fs_cursor *)cur; 690 int rc; 691 692 rc = sqlite3_step(pCur->pStmt); 693 if( rc==SQLITE_ROW || rc==SQLITE_DONE ) rc = SQLITE_OK; 694 695 return rc; 696 } 697 698 static int fsFilter( 699 sqlite3_vtab_cursor *pVtabCursor, 700 int idxNum, const char *idxStr, 701 int argc, sqlite3_value **argv 702 ){ 703 int rc; 704 fs_cursor *pCur = (fs_cursor *)pVtabCursor; 705 fs_vtab *p = (fs_vtab *)(pVtabCursor->pVtab); 706 707 assert( (idxNum==0 && argc==0) || (idxNum==1 && argc==1) ); 708 if( idxNum==1 ){ 709 char *zStmt = sqlite3_mprintf( 710 "SELECT * FROM %Q.%Q WHERE rowid=?", p->zDb, p->zTbl); 711 if( !zStmt ) return SQLITE_NOMEM; 712 rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0); 713 sqlite3_free(zStmt); 714 if( rc==SQLITE_OK ){ 715 sqlite3_bind_value(pCur->pStmt, 1, argv[0]); 716 } 717 }else{ 718 char *zStmt = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zTbl); 719 if( !zStmt ) return SQLITE_NOMEM; 720 rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0); 721 sqlite3_free(zStmt); 722 } 723 724 if( rc==SQLITE_OK ){ 725 rc = fsNext(pVtabCursor); 726 } 727 return rc; 728 } 729 730 static int fsColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ 731 fs_cursor *pCur = (fs_cursor*)cur; 732 733 assert( i==0 || i==1 || i==2 ); 734 if( i==0 ){ 735 sqlite3_result_value(ctx, sqlite3_column_value(pCur->pStmt, 0)); 736 }else{ 737 const char *zFile = (const char *)sqlite3_column_text(pCur->pStmt, 1); 738 struct stat sbuf; 739 int fd; 740 741 int n; 742 fd = open(zFile, O_RDONLY); 743 if( fd<0 ) return SQLITE_IOERR; 744 fstat(fd, &sbuf); 745 746 if( sbuf.st_size>=pCur->nAlloc ){ 747 int nNew = sbuf.st_size*2; 748 char *zNew; 749 if( nNew<1024 ) nNew = 1024; 750 751 zNew = sqlite3Realloc(pCur->zBuf, nNew); 752 if( zNew==0 ){ 753 close(fd); 754 return SQLITE_NOMEM; 755 } 756 pCur->zBuf = zNew; 757 pCur->nAlloc = nNew; 758 } 759 760 n = (int)read(fd, pCur->zBuf, sbuf.st_size); 761 close(fd); 762 if( n!=sbuf.st_size ) return SQLITE_ERROR; 763 pCur->nBuf = sbuf.st_size; 764 pCur->zBuf[pCur->nBuf] = '\0'; 765 766 sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT); 767 } 768 return SQLITE_OK; 769 } 770 771 static int fsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 772 fs_cursor *pCur = (fs_cursor*)cur; 773 *pRowid = sqlite3_column_int64(pCur->pStmt, 0); 774 return SQLITE_OK; 775 } 776 777 static int fsEof(sqlite3_vtab_cursor *cur){ 778 fs_cursor *pCur = (fs_cursor*)cur; 779 return (sqlite3_data_count(pCur->pStmt)==0); 780 } 781 782 static int fsBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 783 int ii; 784 785 for(ii=0; ii<pIdxInfo->nConstraint; ii++){ 786 struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii]; 787 if( pCons->iColumn<0 && pCons->usable 788 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ 789 struct sqlite3_index_constraint_usage *pUsage; 790 pUsage = &pIdxInfo->aConstraintUsage[ii]; 791 pUsage->omit = 0; 792 pUsage->argvIndex = 1; 793 pIdxInfo->idxNum = 1; 794 pIdxInfo->estimatedCost = 1.0; 795 break; 796 } 797 } 798 799 return SQLITE_OK; 800 } 801 802 /* 803 ** A virtual table module that provides read-only access to a 804 ** Tcl global variable namespace. 805 */ 806 static sqlite3_module fsModule = { 807 0, /* iVersion */ 808 fsConnect, 809 fsConnect, 810 fsBestIndex, 811 fsDisconnect, 812 fsDisconnect, 813 fsOpen, /* xOpen - open a cursor */ 814 fsClose, /* xClose - close a cursor */ 815 fsFilter, /* xFilter - configure scan constraints */ 816 fsNext, /* xNext - advance a cursor */ 817 fsEof, /* xEof - check for end of scan */ 818 fsColumn, /* xColumn - read data */ 819 fsRowid, /* xRowid - read data */ 820 0, /* xUpdate */ 821 0, /* xBegin */ 822 0, /* xSync */ 823 0, /* xCommit */ 824 0, /* xRollback */ 825 0, /* xFindMethod */ 826 0, /* xRename */ 827 }; 828 829 static sqlite3_module fsdirModule = { 830 0, /* iVersion */ 831 fsdirConnect, /* xCreate */ 832 fsdirConnect, /* xConnect */ 833 fsdirBestIndex, /* xBestIndex */ 834 fsdirDisconnect, /* xDisconnect */ 835 fsdirDisconnect, /* xDestroy */ 836 fsdirOpen, /* xOpen - open a cursor */ 837 fsdirClose, /* xClose - close a cursor */ 838 fsdirFilter, /* xFilter - configure scan constraints */ 839 fsdirNext, /* xNext - advance a cursor */ 840 fsdirEof, /* xEof - check for end of scan */ 841 fsdirColumn, /* xColumn - read data */ 842 fsdirRowid, /* xRowid - read data */ 843 0, /* xUpdate */ 844 0, /* xBegin */ 845 0, /* xSync */ 846 0, /* xCommit */ 847 0, /* xRollback */ 848 0, /* xFindMethod */ 849 0, /* xRename */ 850 }; 851 852 static sqlite3_module fstreeModule = { 853 0, /* iVersion */ 854 fstreeConnect, /* xCreate */ 855 fstreeConnect, /* xConnect */ 856 fstreeBestIndex, /* xBestIndex */ 857 fstreeDisconnect, /* xDisconnect */ 858 fstreeDisconnect, /* xDestroy */ 859 fstreeOpen, /* xOpen - open a cursor */ 860 fstreeClose, /* xClose - close a cursor */ 861 fstreeFilter, /* xFilter - configure scan constraints */ 862 fstreeNext, /* xNext - advance a cursor */ 863 fstreeEof, /* xEof - check for end of scan */ 864 fstreeColumn, /* xColumn - read data */ 865 fstreeRowid, /* xRowid - read data */ 866 0, /* xUpdate */ 867 0, /* xBegin */ 868 0, /* xSync */ 869 0, /* xCommit */ 870 0, /* xRollback */ 871 0, /* xFindMethod */ 872 0, /* xRename */ 873 }; 874 875 /* 876 ** Decode a pointer to an sqlite3 object. 877 */ 878 extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); 879 880 /* 881 ** Register the echo virtual table module. 882 */ 883 static int SQLITE_TCLAPI register_fs_module( 884 ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ 885 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 886 int objc, /* Number of arguments */ 887 Tcl_Obj *CONST objv[] /* Command arguments */ 888 ){ 889 sqlite3 *db; 890 if( objc!=2 ){ 891 Tcl_WrongNumArgs(interp, 1, objv, "DB"); 892 return TCL_ERROR; 893 } 894 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 895 #ifndef SQLITE_OMIT_VIRTUALTABLE 896 sqlite3_create_module(db, "fs", &fsModule, (void *)interp); 897 sqlite3_create_module(db, "fsdir", &fsdirModule, 0); 898 sqlite3_create_module(db, "fstree", &fstreeModule, 0); 899 #endif 900 return TCL_OK; 901 } 902 903 #endif 904 905 906 /* 907 ** Register commands with the TCL interpreter. 908 */ 909 int Sqlitetestfs_Init(Tcl_Interp *interp){ 910 #ifndef SQLITE_OMIT_VIRTUALTABLE 911 static struct { 912 char *zName; 913 Tcl_ObjCmdProc *xProc; 914 void *clientData; 915 } aObjCmd[] = { 916 { "register_fs_module", register_fs_module, 0 }, 917 }; 918 int i; 919 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 920 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 921 aObjCmd[i].xProc, aObjCmd[i].clientData, 0); 922 } 923 #endif 924 return TCL_OK; 925 } 926