1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FileSystemModule.h"
11 #include "nsISimpleEnumerator.h"
16 struct VirtualTableCursorBase
18 VirtualTableCursorBase()
20 memset(&mBase
, 0, sizeof(mBase
));
23 sqlite3_vtab_cursor mBase
;
26 struct VirtualTableCursor
: public VirtualTableCursorBase
32 mCurrentFileName
.SetIsVoid(true);
35 const nsString
& DirectoryPath() const
37 return mDirectoryPath
;
40 const nsString
& CurrentFileName() const
42 return mCurrentFileName
;
50 nsresult
Init(const nsAString
& aPath
);
54 nsCOMPtr
<nsISimpleEnumerator
> mEntries
;
56 nsString mDirectoryPath
;
57 nsString mCurrentFileName
;
63 VirtualTableCursor::Init(const nsAString
& aPath
)
65 nsCOMPtr
<nsIFile
> directory
=
66 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
);
67 NS_ENSURE_TRUE(directory
, NS_ERROR_FAILURE
);
69 nsresult rv
= directory
->InitWithPath(aPath
);
70 NS_ENSURE_SUCCESS(rv
, rv
);
72 rv
= directory
->GetPath(mDirectoryPath
);
73 NS_ENSURE_SUCCESS(rv
, rv
);
75 rv
= directory
->GetDirectoryEntries(getter_AddRefs(mEntries
));
76 NS_ENSURE_SUCCESS(rv
, rv
);
79 NS_ENSURE_SUCCESS(rv
, rv
);
85 VirtualTableCursor::NextFile()
88 nsresult rv
= mEntries
->HasMoreElements(&hasMore
);
89 NS_ENSURE_SUCCESS(rv
, rv
);
92 mCurrentFileName
.SetIsVoid(true);
96 nsCOMPtr
<nsISupports
> entry
;
97 rv
= mEntries
->GetNext(getter_AddRefs(entry
));
98 NS_ENSURE_SUCCESS(rv
, rv
);
100 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(entry
);
101 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
103 rv
= file
->GetLeafName(mCurrentFileName
);
104 NS_ENSURE_SUCCESS(rv
, rv
);
111 int Connect(sqlite3
* aDB
, void* aAux
, int aArgc
, const char* const* aArgv
,
112 sqlite3_vtab
** aVtab
, char** aErr
)
114 static const char virtualTableSchema
[] =
120 int rc
= sqlite3_declare_vtab(aDB
, virtualTableSchema
);
121 if (rc
!= SQLITE_OK
) {
125 sqlite3_vtab
* vt
= new sqlite3_vtab();
126 memset(vt
, 0, sizeof(*vt
));
133 int Disconnect(sqlite3_vtab
* aVtab
)
140 int BestIndex(sqlite3_vtab
* aVtab
, sqlite3_index_info
* aInfo
)
142 // Here we specify what index constraints we want to handle. That is, there
143 // might be some columns with particular constraints in which we can help
144 // SQLite narrow down the result set.
146 // For example, take the "path = x" where x is a directory. In this case,
147 // we can narrow our search to just this directory instead of the entire file
148 // system. This can be a significant optimization. So, we want to handle that
149 // constraint. To do so, we would look for two specific input conditions:
151 // 1. aInfo->aConstraint[i].iColumn == 1
152 // 2. aInfo->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_EQ
154 // The first states that the path column is being used in one of the input
155 // constraints and the second states that the constraint involves the equal
158 // An even more specific search would be for name='xxx', in which case we
159 // can limit the search to a single file, if it exists.
161 // What we have to do here is look for all of our index searches and select
162 // the narrowest. We can only pick one, so obviously we want the one that
163 // is the most specific, which leads to the smallest result set.
165 for(int i
= 0; i
< aInfo
->nConstraint
; i
++) {
166 if (aInfo
->aConstraint
[i
].iColumn
== 1 && aInfo
->aConstraint
[i
].usable
) {
167 if (aInfo
->aConstraint
[i
].op
& SQLITE_INDEX_CONSTRAINT_EQ
) {
168 aInfo
->aConstraintUsage
[i
].argvIndex
= 1;
173 // TODO: handle single files (constrained also by the name column)
179 int Open(sqlite3_vtab
* aVtab
, sqlite3_vtab_cursor
** aCursor
)
181 VirtualTableCursor
* cursor
= new VirtualTableCursor();
183 *aCursor
= reinterpret_cast<sqlite3_vtab_cursor
*>(cursor
);
188 int Close(sqlite3_vtab_cursor
* aCursor
)
190 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
197 int Filter(sqlite3_vtab_cursor
* aCursor
, int aIdxNum
, const char* aIdxStr
,
198 int aArgc
, sqlite3_value
** aArgv
)
200 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
206 nsDependentString
path(
207 reinterpret_cast<const char16_t
*>(::sqlite3_value_text16(aArgv
[0])));
209 nsresult rv
= cursor
->Init(path
);
210 NS_ENSURE_SUCCESS(rv
, SQLITE_ERROR
);
215 int Next(sqlite3_vtab_cursor
* aCursor
)
217 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
219 nsresult rv
= cursor
->NextFile();
220 NS_ENSURE_SUCCESS(rv
, SQLITE_ERROR
);
225 int Eof(sqlite3_vtab_cursor
* aCursor
)
227 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
228 return cursor
->CurrentFileName().IsVoid() ? 1 : 0;
231 int Column(sqlite3_vtab_cursor
* aCursor
, sqlite3_context
* aContext
,
234 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
236 switch (aColumnIndex
) {
239 const nsString
& name
= cursor
->CurrentFileName();
240 sqlite3_result_text16(aContext
, name
.get(),
241 name
.Length() * sizeof(char16_t
),
248 const nsString
& path
= cursor
->DirectoryPath();
249 sqlite3_result_text16(aContext
, path
.get(),
250 path
.Length() * sizeof(char16_t
),
255 NS_NOTREACHED("Unsupported column!");
261 int RowId(sqlite3_vtab_cursor
* aCursor
, sqlite3_int64
* aRowid
)
263 VirtualTableCursor
* cursor
= reinterpret_cast<VirtualTableCursor
*>(aCursor
);
265 *aRowid
= cursor
->RowId();
275 int RegisterFileSystemModule(sqlite3
* aDB
, const char* aName
)
277 static sqlite3_module module
= {
300 return sqlite3_create_module(aDB
, aName
, &module
, nullptr);
303 } // namespace storage
304 } // namespace mozilla