test_fs.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. #include "sqliteInt.h"
  34. #include "tcl.h"
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #if SQLITE_OS_UNIX
  41. # include <unistd.h>
  42. #endif
  43. #if SQLITE_OS_WIN
  44. # include <io.h>
  45. #endif
  46. #ifndef SQLITE_OMIT_VIRTUALTABLE
  47. typedef struct fs_vtab fs_vtab;
  48. typedef struct fs_cursor fs_cursor;
  49. /*
  50. ** A fs virtual-table object
  51. */
  52. struct fs_vtab {
  53. sqlite3_vtab base;
  54. sqlite3 *db;
  55. char *zDb; /* Name of db containing zTbl */
  56. char *zTbl; /* Name of docid->file map table */
  57. };
  58. /* A fs cursor object */
  59. struct fs_cursor {
  60. sqlite3_vtab_cursor base;
  61. sqlite3_stmt *pStmt;
  62. char *zBuf;
  63. int nBuf;
  64. int nAlloc;
  65. };
  66. /*
  67. ** This function is the implementation of both the xConnect and xCreate
  68. ** methods of the fs virtual table.
  69. **
  70. ** The argv[] array contains the following:
  71. **
  72. ** argv[0] -> module name ("fs")
  73. ** argv[1] -> database name
  74. ** argv[2] -> table name
  75. ** argv[...] -> other module argument fields.
  76. */
  77. static int fsConnect(
  78. sqlite3 *db,
  79. void *pAux,
  80. int argc, const char *const*argv,
  81. sqlite3_vtab **ppVtab,
  82. char **pzErr
  83. ){
  84. fs_vtab *pVtab;
  85. int nByte;
  86. const char *zTbl;
  87. const char *zDb = argv[1];
  88. if( argc!=4 ){
  89. *pzErr = sqlite3_mprintf("wrong number of arguments");
  90. return SQLITE_ERROR;
  91. }
  92. zTbl = argv[3];
  93. nByte = sizeof(fs_vtab) + (int)strlen(zTbl) + 1 + (int)strlen(zDb) + 1;
  94. pVtab = (fs_vtab *)sqlite3MallocZero( nByte );
  95. if( !pVtab ) return SQLITE_NOMEM;
  96. pVtab->zTbl = (char *)&pVtab[1];
  97. pVtab->zDb = &pVtab->zTbl[strlen(zTbl)+1];
  98. pVtab->db = db;
  99. memcpy(pVtab->zTbl, zTbl, strlen(zTbl));
  100. memcpy(pVtab->zDb, zDb, strlen(zDb));
  101. *ppVtab = &pVtab->base;
  102. sqlite3_declare_vtab(db, "CREATE TABLE xyz(path TEXT, data TEXT)");
  103. return SQLITE_OK;
  104. }
  105. /* Note that for this virtual table, the xCreate and xConnect
  106. ** methods are identical. */
  107. static int fsDisconnect(sqlite3_vtab *pVtab){
  108. sqlite3_free(pVtab);
  109. return SQLITE_OK;
  110. }
  111. /* The xDisconnect and xDestroy methods are also the same */
  112. /*
  113. ** Open a new fs cursor.
  114. */
  115. static int fsOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  116. fs_cursor *pCur;
  117. pCur = sqlite3MallocZero(sizeof(fs_cursor));
  118. *ppCursor = &pCur->base;
  119. return SQLITE_OK;
  120. }
  121. /*
  122. ** Close a fs cursor.
  123. */
  124. static int fsClose(sqlite3_vtab_cursor *cur){
  125. fs_cursor *pCur = (fs_cursor *)cur;
  126. sqlite3_finalize(pCur->pStmt);
  127. sqlite3_free(pCur->zBuf);
  128. sqlite3_free(pCur);
  129. return SQLITE_OK;
  130. }
  131. static int fsNext(sqlite3_vtab_cursor *cur){
  132. fs_cursor *pCur = (fs_cursor *)cur;
  133. int rc;
  134. rc = sqlite3_step(pCur->pStmt);
  135. if( rc==SQLITE_ROW || rc==SQLITE_DONE ) rc = SQLITE_OK;
  136. return rc;
  137. }
  138. static int fsFilter(
  139. sqlite3_vtab_cursor *pVtabCursor,
  140. int idxNum, const char *idxStr,
  141. int argc, sqlite3_value **argv
  142. ){
  143. int rc;
  144. fs_cursor *pCur = (fs_cursor *)pVtabCursor;
  145. fs_vtab *p = (fs_vtab *)(pVtabCursor->pVtab);
  146. assert( (idxNum==0 && argc==0) || (idxNum==1 && argc==1) );
  147. if( idxNum==1 ){
  148. char *zStmt = sqlite3_mprintf(
  149. "SELECT * FROM %Q.%Q WHERE rowid=?", p->zDb, p->zTbl);
  150. if( !zStmt ) return SQLITE_NOMEM;
  151. rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0);
  152. sqlite3_free(zStmt);
  153. if( rc==SQLITE_OK ){
  154. sqlite3_bind_value(pCur->pStmt, 1, argv[0]);
  155. }
  156. }else{
  157. char *zStmt = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zTbl);
  158. if( !zStmt ) return SQLITE_NOMEM;
  159. rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0);
  160. sqlite3_free(zStmt);
  161. }
  162. if( rc==SQLITE_OK ){
  163. rc = fsNext(pVtabCursor);
  164. }
  165. return rc;
  166. }
  167. static int fsColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  168. fs_cursor *pCur = (fs_cursor*)cur;
  169. assert( i==0 || i==1 );
  170. if( i==0 ){
  171. sqlite3_result_value(ctx, sqlite3_column_value(pCur->pStmt, 0));
  172. }else{
  173. const char *zFile = (const char *)sqlite3_column_text(pCur->pStmt, 1);
  174. struct stat sbuf;
  175. int fd;
  176. int n;
  177. fd = open(zFile, O_RDONLY);
  178. if( fd<0 ) return SQLITE_IOERR;
  179. fstat(fd, &sbuf);
  180. if( sbuf.st_size>=pCur->nAlloc ){
  181. int nNew = sbuf.st_size*2;
  182. char *zNew;
  183. if( nNew<1024 ) nNew = 1024;
  184. zNew = sqlite3Realloc(pCur->zBuf, nNew);
  185. if( zNew==0 ){
  186. close(fd);
  187. return SQLITE_NOMEM;
  188. }
  189. pCur->zBuf = zNew;
  190. pCur->nAlloc = nNew;
  191. }
  192. n = (int)read(fd, pCur->zBuf, sbuf.st_size);
  193. close(fd);
  194. if( n!=sbuf.st_size ) return SQLITE_ERROR;
  195. pCur->nBuf = sbuf.st_size;
  196. pCur->zBuf[pCur->nBuf] = '\0';
  197. sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT);
  198. }
  199. return SQLITE_OK;
  200. }
  201. static int fsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  202. fs_cursor *pCur = (fs_cursor*)cur;
  203. *pRowid = sqlite3_column_int64(pCur->pStmt, 0);
  204. return SQLITE_OK;
  205. }
  206. static int fsEof(sqlite3_vtab_cursor *cur){
  207. fs_cursor *pCur = (fs_cursor*)cur;
  208. return (sqlite3_data_count(pCur->pStmt)==0);
  209. }
  210. static int fsBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  211. int ii;
  212. for(ii=0; ii<pIdxInfo->nConstraint; ii++){
  213. struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
  214. if( pCons->iColumn<0 && pCons->usable
  215. && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
  216. struct sqlite3_index_constraint_usage *pUsage;
  217. pUsage = &pIdxInfo->aConstraintUsage[ii];
  218. pUsage->omit = 0;
  219. pUsage->argvIndex = 1;
  220. pIdxInfo->idxNum = 1;
  221. pIdxInfo->estimatedCost = 1.0;
  222. break;
  223. }
  224. }
  225. return SQLITE_OK;
  226. }
  227. /*
  228. ** A virtual table module that provides read-only access to a
  229. ** Tcl global variable namespace.
  230. */
  231. static sqlite3_module fsModule = {
  232. 0, /* iVersion */
  233. fsConnect,
  234. fsConnect,
  235. fsBestIndex,
  236. fsDisconnect,
  237. fsDisconnect,
  238. fsOpen, /* xOpen - open a cursor */
  239. fsClose, /* xClose - close a cursor */
  240. fsFilter, /* xFilter - configure scan constraints */
  241. fsNext, /* xNext - advance a cursor */
  242. fsEof, /* xEof - check for end of scan */
  243. fsColumn, /* xColumn - read data */
  244. fsRowid, /* xRowid - read data */
  245. 0, /* xUpdate */
  246. 0, /* xBegin */
  247. 0, /* xSync */
  248. 0, /* xCommit */
  249. 0, /* xRollback */
  250. 0, /* xFindMethod */
  251. 0, /* xRename */
  252. };
  253. /*
  254. ** Decode a pointer to an sqlite3 object.
  255. */
  256. extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
  257. /*
  258. ** Register the echo virtual table module.
  259. */
  260. static int register_fs_module(
  261. ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  262. Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
  263. int objc, /* Number of arguments */
  264. Tcl_Obj *CONST objv[] /* Command arguments */
  265. ){
  266. sqlite3 *db;
  267. if( objc!=2 ){
  268. Tcl_WrongNumArgs(interp, 1, objv, "DB");
  269. return TCL_ERROR;
  270. }
  271. if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  272. #ifndef SQLITE_OMIT_VIRTUALTABLE
  273. sqlite3_create_module(db, "fs", &fsModule, (void *)interp);
  274. #endif
  275. return TCL_OK;
  276. }
  277. #endif
  278. /*
  279. ** Register commands with the TCL interpreter.
  280. */
  281. int Sqlitetestfs_Init(Tcl_Interp *interp){
  282. #ifndef SQLITE_OMIT_VIRTUALTABLE
  283. static struct {
  284. char *zName;
  285. Tcl_ObjCmdProc *xProc;
  286. void *clientData;
  287. } aObjCmd[] = {
  288. { "register_fs_module", register_fs_module, 0 },
  289. };
  290. int i;
  291. for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
  292. Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
  293. aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
  294. }
  295. #endif
  296. return TCL_OK;
  297. }