Enhance the command-line completion extension to return the names of
[sqlite.git] / ext / misc / fileio.c
blob83ba1243754d410b5f42134e669bf1ed99b42f5b
1 /*
2 ** 2014-06-13
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.
11 ******************************************************************************
13 ** This SQLite extension implements SQL functions readfile() and
14 ** writefile(), and eponymous virtual type "fsdir".
16 ** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
18 ** If neither of the optional arguments is present, then this UDF
19 ** function writes blob DATA to file FILE. If successful, the number
20 ** of bytes written is returned. If an error occurs, NULL is returned.
22 ** If the first option argument - MODE - is present, then it must
23 ** be passed an integer value that corresponds to a POSIX mode
24 ** value (file type + permissions, as returned in the stat.st_mode
25 ** field by the stat() system call). Three types of files may
26 ** be written/created:
28 ** regular files: (mode & 0170000)==0100000
29 ** symbolic links: (mode & 0170000)==0120000
30 ** directories: (mode & 0170000)==0040000
32 ** For a directory, the DATA is ignored. For a symbolic link, it is
33 ** interpreted as text and used as the target of the link. For a
34 ** regular file, it is interpreted as a blob and written into the
35 ** named file. Regardless of the type of file, its permissions are
36 ** set to (mode & 0777) before returning.
38 ** If the optional MTIME argument is present, then it is interpreted
39 ** as an integer - the number of seconds since the unix epoch. The
40 ** modification-time of the target file is set to this value before
41 ** returning.
43 ** If three or more arguments are passed to this function and an
44 ** error is encountered, an exception is raised.
46 ** READFILE(FILE):
48 ** Read and return the contents of file FILE (type blob) from disk.
50 ** FSDIR:
52 ** Used as follows:
54 ** SELECT * FROM fsdir($path [, $dir]);
56 ** Parameter $path is an absolute or relative pathname. If the file that it
57 ** refers to does not exist, it is an error. If the path refers to a regular
58 ** file or symbolic link, it returns a single row. Or, if the path refers
59 ** to a directory, it returns one row for the directory, and one row for each
60 ** file within the hierarchy rooted at $path.
62 ** Each row has the following columns:
64 ** name: Path to file or directory (text value).
65 ** mode: Value of stat.st_mode for directory entry (an integer).
66 ** mtime: Value of stat.st_mtime for directory entry (an integer).
67 ** data: For a regular file, a blob containing the file data. For a
68 ** symlink, a text value containing the text of the link. For a
69 ** directory, NULL.
71 ** If a non-NULL value is specified for the optional $dir parameter and
72 ** $path is a relative path, then $path is interpreted relative to $dir.
73 ** And the paths returned in the "name" column of the table are also
74 ** relative to directory $dir.
76 #include "sqlite3ext.h"
77 SQLITE_EXTENSION_INIT1
78 #include <stdio.h>
79 #include <string.h>
80 #include <assert.h>
82 #include <sys/types.h>
83 #include <sys/stat.h>
84 #include <fcntl.h>
85 #if !defined(_WIN32) && !defined(WIN32)
86 # include <unistd.h>
87 # include <dirent.h>
88 # include <utime.h>
89 # include <sys/time.h>
90 #else
91 # include "windows.h"
92 # include <io.h>
93 # include <direct.h>
94 # include "test_windirent.h"
95 # define dirent DIRENT
96 # ifndef stat
97 # define stat _stat
98 # endif
99 # define mkdir(path,mode) _mkdir(path)
100 # define lstat(path,buf) stat(path,buf)
101 #endif
102 #include <time.h>
103 #include <errno.h>
106 #define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
109 ** Set the result stored by context ctx to a blob containing the
110 ** contents of file zName.
112 static void readFileContents(sqlite3_context *ctx, const char *zName){
113 FILE *in;
114 long nIn;
115 void *pBuf;
117 in = fopen(zName, "rb");
118 if( in==0 ) return;
119 fseek(in, 0, SEEK_END);
120 nIn = ftell(in);
121 rewind(in);
122 pBuf = sqlite3_malloc( nIn );
123 if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
124 sqlite3_result_blob(ctx, pBuf, nIn, sqlite3_free);
125 }else{
126 sqlite3_free(pBuf);
128 fclose(in);
132 ** Implementation of the "readfile(X)" SQL function. The entire content
133 ** of the file named X is read and returned as a BLOB. NULL is returned
134 ** if the file does not exist or is unreadable.
136 static void readfileFunc(
137 sqlite3_context *context,
138 int argc,
139 sqlite3_value **argv
141 const char *zName;
142 (void)(argc); /* Unused parameter */
143 zName = (const char*)sqlite3_value_text(argv[0]);
144 if( zName==0 ) return;
145 readFileContents(context, zName);
149 ** Set the error message contained in context ctx to the results of
150 ** vprintf(zFmt, ...).
152 static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
153 char *zMsg = 0;
154 va_list ap;
155 va_start(ap, zFmt);
156 zMsg = sqlite3_vmprintf(zFmt, ap);
157 sqlite3_result_error(ctx, zMsg, -1);
158 sqlite3_free(zMsg);
159 va_end(ap);
163 ** Argument zFile is the name of a file that will be created and/or written
164 ** by SQL function writefile(). This function ensures that the directory
165 ** zFile will be written to exists, creating it if required. The permissions
166 ** for any path components created by this function are set to (mode&0777).
168 ** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
169 ** SQLITE_OK is returned if the directory is successfully created, or
170 ** SQLITE_ERROR otherwise.
172 static int makeDirectory(
173 const char *zFile,
174 mode_t mode
176 char *zCopy = sqlite3_mprintf("%s", zFile);
177 int rc = SQLITE_OK;
179 if( zCopy==0 ){
180 rc = SQLITE_NOMEM;
181 }else{
182 int nCopy = (int)strlen(zCopy);
183 int i = 1;
185 while( rc==SQLITE_OK ){
186 struct stat sStat;
187 int rc2;
189 for(; zCopy[i]!='/' && i<nCopy; i++);
190 if( i==nCopy ) break;
191 zCopy[i] = '\0';
193 rc2 = stat(zCopy, &sStat);
194 if( rc2!=0 ){
195 if( mkdir(zCopy, mode & 0777) ) rc = SQLITE_ERROR;
196 }else{
197 if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
199 zCopy[i] = '/';
200 i++;
203 sqlite3_free(zCopy);
206 return rc;
210 ** This function does the work for the writefile() UDF. Refer to
211 ** header comments at the top of this file for details.
213 static int writeFile(
214 sqlite3_context *pCtx, /* Context to return bytes written in */
215 const char *zFile, /* File to write */
216 sqlite3_value *pData, /* Data to write */
217 mode_t mode, /* MODE parameter passed to writefile() */
218 sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */
220 #if !defined(_WIN32) && !defined(WIN32)
221 if( S_ISLNK(mode) ){
222 const char *zTo = (const char*)sqlite3_value_text(pData);
223 if( symlink(zTo, zFile)<0 ) return 1;
224 }else
225 #endif
227 if( S_ISDIR(mode) ){
228 if( mkdir(zFile, mode) ){
229 /* The mkdir() call to create the directory failed. This might not
230 ** be an error though - if there is already a directory at the same
231 ** path and either the permissions already match or can be changed
232 ** to do so using chmod(), it is not an error. */
233 struct stat sStat;
234 if( errno!=EEXIST
235 || 0!=stat(zFile, &sStat)
236 || !S_ISDIR(sStat.st_mode)
237 || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
239 return 1;
242 }else{
243 sqlite3_int64 nWrite = 0;
244 const char *z;
245 int rc = 0;
246 FILE *out = fopen(zFile, "wb");
247 if( out==0 ) return 1;
248 z = (const char*)sqlite3_value_blob(pData);
249 if( z ){
250 sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
251 nWrite = sqlite3_value_bytes(pData);
252 if( nWrite!=n ){
253 rc = 1;
256 fclose(out);
257 if( rc==0 && mode && chmod(zFile, mode & 0777) ){
258 rc = 1;
260 if( rc ) return 2;
261 sqlite3_result_int64(pCtx, nWrite);
265 if( mtime>=0 ){
266 #if defined(_WIN32)
267 /* Windows */
268 FILETIME lastAccess;
269 FILETIME lastWrite;
270 SYSTEMTIME currentTime;
271 LONGLONG intervals;
272 HANDLE hFile;
273 LPWSTR zUnicodeName;
274 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
276 GetSystemTime(&currentTime);
277 SystemTimeToFileTime(&currentTime, &lastAccess);
278 intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
279 lastWrite.dwLowDateTime = (DWORD)intervals;
280 lastWrite.dwHighDateTime = intervals >> 32;
281 zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
282 hFile = CreateFileW(
283 zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
284 FILE_FLAG_BACKUP_SEMANTICS, NULL
286 sqlite3_free(zUnicodeName);
287 if( hFile!=INVALID_HANDLE_VALUE ){
288 BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
289 CloseHandle(hFile);
290 return !bResult;
291 }else{
292 return 1;
294 #elif defined(AT_FDCWD) && 0 /* utimensat() is not univerally available */
295 /* Recent unix */
296 struct timespec times[2];
297 times[0].tv_nsec = times[1].tv_nsec = 0;
298 times[0].tv_sec = time(0);
299 times[1].tv_sec = mtime;
300 if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
301 return 1;
303 #else
304 /* Legacy unix */
305 struct timeval times[2];
306 times[0].tv_usec = times[1].tv_usec = 0;
307 times[0].tv_sec = time(0);
308 times[1].tv_sec = mtime;
309 if( utimes(zFile, times) ){
310 return 1;
312 #endif
315 return 0;
319 ** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
320 ** Refer to header comments at the top of this file for details.
322 static void writefileFunc(
323 sqlite3_context *context,
324 int argc,
325 sqlite3_value **argv
327 const char *zFile;
328 mode_t mode = 0;
329 int res;
330 sqlite3_int64 mtime = -1;
332 if( argc<2 || argc>4 ){
333 sqlite3_result_error(context,
334 "wrong number of arguments to function writefile()", -1
336 return;
339 zFile = (const char*)sqlite3_value_text(argv[0]);
340 if( zFile==0 ) return;
341 if( argc>=3 ){
342 mode = (mode_t)sqlite3_value_int(argv[2]);
344 if( argc==4 ){
345 mtime = sqlite3_value_int64(argv[3]);
348 res = writeFile(context, zFile, argv[1], mode, mtime);
349 if( res==1 && errno==ENOENT ){
350 if( makeDirectory(zFile, mode)==SQLITE_OK ){
351 res = writeFile(context, zFile, argv[1], mode, mtime);
355 if( argc>2 && res!=0 ){
356 if( S_ISLNK(mode) ){
357 ctxErrorMsg(context, "failed to create symlink: %s", zFile);
358 }else if( S_ISDIR(mode) ){
359 ctxErrorMsg(context, "failed to create directory: %s", zFile);
360 }else{
361 ctxErrorMsg(context, "failed to write file: %s", zFile);
367 ** SQL function: lsmode(MODE)
369 ** Given a numberic st_mode from stat(), convert it into a human-readable
370 ** text string in the style of "ls -l".
372 static void lsModeFunc(
373 sqlite3_context *context,
374 int argc,
375 sqlite3_value **argv
377 int i;
378 int iMode = sqlite3_value_int(argv[0]);
379 char z[16];
380 (void)argc;
381 if( S_ISLNK(iMode) ){
382 z[0] = 'l';
383 }else if( S_ISREG(iMode) ){
384 z[0] = '-';
385 }else if( S_ISDIR(iMode) ){
386 z[0] = 'd';
387 }else{
388 z[0] = '?';
390 for(i=0; i<3; i++){
391 int m = (iMode >> ((2-i)*3));
392 char *a = &z[1 + i*3];
393 a[0] = (m & 0x4) ? 'r' : '-';
394 a[1] = (m & 0x2) ? 'w' : '-';
395 a[2] = (m & 0x1) ? 'x' : '-';
397 z[10] = '\0';
398 sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
401 #ifndef SQLITE_OMIT_VIRTUALTABLE
404 ** Cursor type for recursively iterating through a directory structure.
406 typedef struct fsdir_cursor fsdir_cursor;
407 typedef struct FsdirLevel FsdirLevel;
409 struct FsdirLevel {
410 DIR *pDir; /* From opendir() */
411 char *zDir; /* Name of directory (nul-terminated) */
414 struct fsdir_cursor {
415 sqlite3_vtab_cursor base; /* Base class - must be first */
417 int nLvl; /* Number of entries in aLvl[] array */
418 int iLvl; /* Index of current entry */
419 FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
421 const char *zBase;
422 int nBase;
424 struct stat sStat; /* Current lstat() results */
425 char *zPath; /* Path to current entry */
426 sqlite3_int64 iRowid; /* Current rowid */
429 typedef struct fsdir_tab fsdir_tab;
430 struct fsdir_tab {
431 sqlite3_vtab base; /* Base class - must be first */
435 ** Construct a new fsdir virtual table object.
437 static int fsdirConnect(
438 sqlite3 *db,
439 void *pAux,
440 int argc, const char *const*argv,
441 sqlite3_vtab **ppVtab,
442 char **pzErr
444 fsdir_tab *pNew = 0;
445 int rc;
446 (void)pAux;
447 (void)argc;
448 (void)argv;
449 (void)pzErr;
450 rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
451 if( rc==SQLITE_OK ){
452 pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
453 if( pNew==0 ) return SQLITE_NOMEM;
454 memset(pNew, 0, sizeof(*pNew));
456 *ppVtab = (sqlite3_vtab*)pNew;
457 return rc;
461 ** This method is the destructor for fsdir vtab objects.
463 static int fsdirDisconnect(sqlite3_vtab *pVtab){
464 sqlite3_free(pVtab);
465 return SQLITE_OK;
469 ** Constructor for a new fsdir_cursor object.
471 static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
472 fsdir_cursor *pCur;
473 (void)p;
474 pCur = sqlite3_malloc( sizeof(*pCur) );
475 if( pCur==0 ) return SQLITE_NOMEM;
476 memset(pCur, 0, sizeof(*pCur));
477 pCur->iLvl = -1;
478 *ppCursor = &pCur->base;
479 return SQLITE_OK;
483 ** Reset a cursor back to the state it was in when first returned
484 ** by fsdirOpen().
486 static void fsdirResetCursor(fsdir_cursor *pCur){
487 int i;
488 for(i=0; i<=pCur->iLvl; i++){
489 FsdirLevel *pLvl = &pCur->aLvl[i];
490 if( pLvl->pDir ) closedir(pLvl->pDir);
491 sqlite3_free(pLvl->zDir);
493 sqlite3_free(pCur->zPath);
494 sqlite3_free(pCur->aLvl);
495 pCur->aLvl = 0;
496 pCur->zPath = 0;
497 pCur->zBase = 0;
498 pCur->nBase = 0;
499 pCur->nLvl = 0;
500 pCur->iLvl = -1;
501 pCur->iRowid = 1;
505 ** Destructor for an fsdir_cursor.
507 static int fsdirClose(sqlite3_vtab_cursor *cur){
508 fsdir_cursor *pCur = (fsdir_cursor*)cur;
510 fsdirResetCursor(pCur);
511 sqlite3_free(pCur);
512 return SQLITE_OK;
516 ** Set the error message for the virtual table associated with cursor
517 ** pCur to the results of vprintf(zFmt, ...).
519 static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
520 va_list ap;
521 va_start(ap, zFmt);
522 pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
523 va_end(ap);
528 ** Advance an fsdir_cursor to its next row of output.
530 static int fsdirNext(sqlite3_vtab_cursor *cur){
531 fsdir_cursor *pCur = (fsdir_cursor*)cur;
532 mode_t m = pCur->sStat.st_mode;
534 pCur->iRowid++;
535 if( S_ISDIR(m) ){
536 /* Descend into this directory */
537 int iNew = pCur->iLvl + 1;
538 FsdirLevel *pLvl;
539 if( iNew>=pCur->nLvl ){
540 int nNew = iNew+1;
541 int nByte = nNew*sizeof(FsdirLevel);
542 FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc(pCur->aLvl, nByte);
543 if( aNew==0 ) return SQLITE_NOMEM;
544 memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
545 pCur->aLvl = aNew;
546 pCur->nLvl = nNew;
548 pCur->iLvl = iNew;
549 pLvl = &pCur->aLvl[iNew];
551 pLvl->zDir = pCur->zPath;
552 pCur->zPath = 0;
553 pLvl->pDir = opendir(pLvl->zDir);
554 if( pLvl->pDir==0 ){
555 fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
556 return SQLITE_ERROR;
560 while( pCur->iLvl>=0 ){
561 FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
562 struct dirent *pEntry = readdir(pLvl->pDir);
563 if( pEntry ){
564 if( pEntry->d_name[0]=='.' ){
565 if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
566 if( pEntry->d_name[1]=='\0' ) continue;
568 sqlite3_free(pCur->zPath);
569 pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
570 if( pCur->zPath==0 ) return SQLITE_NOMEM;
571 if( lstat(pCur->zPath, &pCur->sStat) ){
572 fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
573 return SQLITE_ERROR;
575 return SQLITE_OK;
577 closedir(pLvl->pDir);
578 sqlite3_free(pLvl->zDir);
579 pLvl->pDir = 0;
580 pLvl->zDir = 0;
581 pCur->iLvl--;
584 /* EOF */
585 sqlite3_free(pCur->zPath);
586 pCur->zPath = 0;
587 return SQLITE_OK;
591 ** Return values of columns for the row at which the series_cursor
592 ** is currently pointing.
594 static int fsdirColumn(
595 sqlite3_vtab_cursor *cur, /* The cursor */
596 sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
597 int i /* Which column to return */
599 fsdir_cursor *pCur = (fsdir_cursor*)cur;
600 switch( i ){
601 case 0: { /* name */
602 sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
603 break;
606 case 1: /* mode */
607 sqlite3_result_int64(ctx, pCur->sStat.st_mode);
608 break;
610 case 2: /* mtime */
611 sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
612 break;
614 case 3: { /* data */
615 mode_t m = pCur->sStat.st_mode;
616 if( S_ISDIR(m) ){
617 sqlite3_result_null(ctx);
618 #if !defined(_WIN32) && !defined(WIN32)
619 }else if( S_ISLNK(m) ){
620 char aStatic[64];
621 char *aBuf = aStatic;
622 int nBuf = 64;
623 int n;
625 while( 1 ){
626 n = readlink(pCur->zPath, aBuf, nBuf);
627 if( n<nBuf ) break;
628 if( aBuf!=aStatic ) sqlite3_free(aBuf);
629 nBuf = nBuf*2;
630 aBuf = sqlite3_malloc(nBuf);
631 if( aBuf==0 ){
632 sqlite3_result_error_nomem(ctx);
633 return SQLITE_NOMEM;
637 sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
638 if( aBuf!=aStatic ) sqlite3_free(aBuf);
639 #endif
640 }else{
641 readFileContents(ctx, pCur->zPath);
645 return SQLITE_OK;
649 ** Return the rowid for the current row. In this implementation, the
650 ** first row returned is assigned rowid value 1, and each subsequent
651 ** row a value 1 more than that of the previous.
653 static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
654 fsdir_cursor *pCur = (fsdir_cursor*)cur;
655 *pRowid = pCur->iRowid;
656 return SQLITE_OK;
660 ** Return TRUE if the cursor has been moved off of the last
661 ** row of output.
663 static int fsdirEof(sqlite3_vtab_cursor *cur){
664 fsdir_cursor *pCur = (fsdir_cursor*)cur;
665 return (pCur->zPath==0);
669 ** xFilter callback.
671 static int fsdirFilter(
672 sqlite3_vtab_cursor *cur,
673 int idxNum, const char *idxStr,
674 int argc, sqlite3_value **argv
676 const char *zDir = 0;
677 fsdir_cursor *pCur = (fsdir_cursor*)cur;
678 (void)idxStr;
679 fsdirResetCursor(pCur);
681 if( idxNum==0 ){
682 fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
683 return SQLITE_ERROR;
686 assert( argc==idxNum && (argc==1 || argc==2) );
687 zDir = (const char*)sqlite3_value_text(argv[0]);
688 if( zDir==0 ){
689 fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
690 return SQLITE_ERROR;
692 if( argc==2 ){
693 pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
695 if( pCur->zBase ){
696 pCur->nBase = (int)strlen(pCur->zBase)+1;
697 pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
698 }else{
699 pCur->zPath = sqlite3_mprintf("%s", zDir);
702 if( pCur->zPath==0 ){
703 return SQLITE_NOMEM;
705 if( lstat(pCur->zPath, &pCur->sStat) ){
706 fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
707 return SQLITE_ERROR;
710 return SQLITE_OK;
714 ** SQLite will invoke this method one or more times while planning a query
715 ** that uses the generate_series virtual table. This routine needs to create
716 ** a query plan for each invocation and compute an estimated cost for that
717 ** plan.
719 ** In this implementation idxNum is used to represent the
720 ** query plan. idxStr is unused.
722 ** The query plan is represented by bits in idxNum:
724 ** (1) start = $value -- constraint exists
725 ** (2) stop = $value -- constraint exists
726 ** (4) step = $value -- constraint exists
727 ** (8) output in descending order
729 static int fsdirBestIndex(
730 sqlite3_vtab *tab,
731 sqlite3_index_info *pIdxInfo
733 int i; /* Loop over constraints */
734 int idx4 = -1;
735 int idx5 = -1;
736 const struct sqlite3_index_constraint *pConstraint;
738 (void)tab;
739 pConstraint = pIdxInfo->aConstraint;
740 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
741 if( pConstraint->usable==0 ) continue;
742 if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
743 if( pConstraint->iColumn==4 ) idx4 = i;
744 if( pConstraint->iColumn==5 ) idx5 = i;
747 if( idx4<0 ){
748 pIdxInfo->idxNum = 0;
749 pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50);
750 }else{
751 pIdxInfo->aConstraintUsage[idx4].omit = 1;
752 pIdxInfo->aConstraintUsage[idx4].argvIndex = 1;
753 if( idx5>=0 ){
754 pIdxInfo->aConstraintUsage[idx5].omit = 1;
755 pIdxInfo->aConstraintUsage[idx5].argvIndex = 2;
756 pIdxInfo->idxNum = 2;
757 pIdxInfo->estimatedCost = 10.0;
758 }else{
759 pIdxInfo->idxNum = 1;
760 pIdxInfo->estimatedCost = 100.0;
764 return SQLITE_OK;
768 ** Register the "fsdir" virtual table.
770 static int fsdirRegister(sqlite3 *db){
771 static sqlite3_module fsdirModule = {
772 0, /* iVersion */
773 0, /* xCreate */
774 fsdirConnect, /* xConnect */
775 fsdirBestIndex, /* xBestIndex */
776 fsdirDisconnect, /* xDisconnect */
777 0, /* xDestroy */
778 fsdirOpen, /* xOpen - open a cursor */
779 fsdirClose, /* xClose - close a cursor */
780 fsdirFilter, /* xFilter - configure scan constraints */
781 fsdirNext, /* xNext - advance a cursor */
782 fsdirEof, /* xEof - check for end of scan */
783 fsdirColumn, /* xColumn - read data */
784 fsdirRowid, /* xRowid - read data */
785 0, /* xUpdate */
786 0, /* xBegin */
787 0, /* xSync */
788 0, /* xCommit */
789 0, /* xRollback */
790 0, /* xFindMethod */
791 0, /* xRename */
792 0, /* xSavepoint */
793 0, /* xRelease */
794 0 /* xRollbackTo */
797 int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
798 return rc;
800 #else /* SQLITE_OMIT_VIRTUALTABLE */
801 # define fsdirRegister(x) SQLITE_OK
802 #endif
804 #ifdef _WIN32
805 __declspec(dllexport)
806 #endif
807 int sqlite3_fileio_init(
808 sqlite3 *db,
809 char **pzErrMsg,
810 const sqlite3_api_routines *pApi
812 int rc = SQLITE_OK;
813 SQLITE_EXTENSION_INIT2(pApi);
814 (void)pzErrMsg; /* Unused parameter */
815 rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
816 readfileFunc, 0, 0);
817 if( rc==SQLITE_OK ){
818 rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
819 writefileFunc, 0, 0);
821 if( rc==SQLITE_OK ){
822 rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
823 lsModeFunc, 0, 0);
825 if( rc==SQLITE_OK ){
826 rc = fsdirRegister(db);
828 return rc;