@@ -17,6 +17,7 @@ VirtualFileSystem::VirtualFileSystem(unique_ptr<FileSystem> &&inner) : default_f
1717
1818unique_ptr<FileHandle> VirtualFileSystem::OpenFileExtended (const OpenFileInfo &file, FileOpenFlags flags,
1919 optional_ptr<FileOpener> opener) {
20+
2021 auto compression = flags.Compression ();
2122 if (compression == FileCompressionType::AUTO_DETECT) {
2223 // auto-detect compression settings based on file name
@@ -34,8 +35,9 @@ unique_ptr<FileHandle> VirtualFileSystem::OpenFileExtended(const OpenFileInfo &f
3435 }
3536 }
3637 // open the base file handle in UNCOMPRESSED mode
38+
3739 flags.SetCompression (FileCompressionType::UNCOMPRESSED);
38- auto file_handle = FindFileSystem (file.path ).OpenFile (file, flags, opener);
40+ auto file_handle = FindFileSystem (file.path , opener ).OpenFile (file, flags, opener);
3941 if (!file_handle) {
4042 return nullptr ;
4143 }
@@ -111,15 +113,15 @@ void VirtualFileSystem::RemoveDirectory(const string &directory, optional_ptr<Fi
111113bool VirtualFileSystem::ListFilesExtended (const string &directory,
112114 const std::function<void (OpenFileInfo &info)> &callback,
113115 optional_ptr<FileOpener> opener) {
114- return FindFileSystem (directory).ListFiles (directory, callback, opener);
116+ return FindFileSystem (directory, opener ).ListFiles (directory, callback, opener);
115117}
116118
117119void VirtualFileSystem::MoveFile (const string &source, const string &target, optional_ptr<FileOpener> opener) {
118120 FindFileSystem (source).MoveFile (source, target, opener);
119121}
120122
121123bool VirtualFileSystem::FileExists (const string &filename, optional_ptr<FileOpener> opener) {
122- return FindFileSystem (filename).FileExists (filename, opener);
124+ return FindFileSystem (filename, opener ).FileExists (filename, opener);
123125}
124126
125127bool VirtualFileSystem::IsPipe (const string &filename, optional_ptr<FileOpener> opener) {
@@ -139,7 +141,7 @@ string VirtualFileSystem::PathSeparator(const string &path) {
139141}
140142
141143vector<OpenFileInfo> VirtualFileSystem::Glob (const string &path, FileOpener *opener) {
142- return FindFileSystem (path).Glob (path, opener);
144+ return FindFileSystem (path, opener ).Glob (path, opener);
143145}
144146
145147void VirtualFileSystem::RegisterSubSystem (unique_ptr<FileSystem> fs) {
@@ -216,16 +218,61 @@ bool VirtualFileSystem::SubSystemIsDisabled(const string &name) {
216218 return disabled_file_systems.find (name) != disabled_file_systems.end ();
217219}
218220
221+ FileSystem &VirtualFileSystem::FindFileSystem (const string &path, optional_ptr<FileOpener> opener) {
222+ return FindFileSystem (path, FileOpener::TryGetDatabase (opener));
223+ }
224+
225+ FileSystem &VirtualFileSystem::FindFileSystem (const string &path, optional_ptr<DatabaseInstance> db_instance) {
226+ auto fs = FindFileSystemInternal (path);
227+
228+ if (!fs && db_instance) {
229+ string required_extension;
230+
231+ for (const auto &entry : EXTENSION_FILE_PREFIXES) {
232+ if (StringUtil::StartsWith (path, entry.name )) {
233+ required_extension = entry.extension ;
234+ }
235+ }
236+ if (!required_extension.empty () && db_instance && !db_instance->ExtensionIsLoaded (required_extension)) {
237+ auto &dbconfig = DBConfig::GetConfig (*db_instance);
238+ if (!ExtensionHelper::CanAutoloadExtension (required_extension) ||
239+ !dbconfig.options .autoload_known_extensions ) {
240+ auto error_message = " File " + path + " requires the extension " + required_extension + " to be loaded" ;
241+ error_message =
242+ ExtensionHelper::AddExtensionInstallHintToErrorMsg (*db_instance, error_message, required_extension);
243+ throw MissingExtensionException (error_message);
244+ }
245+ // an extension is required to read this file, but it is not loaded - try to load it
246+ ExtensionHelper::AutoLoadExtension (*db_instance, required_extension);
247+ }
248+
249+ // Retry after having autoloaded
250+ fs = FindFileSystem (path);
251+ }
252+
253+ if (!fs) {
254+ fs = default_fs;
255+ }
256+ if (!disabled_file_systems.empty () && disabled_file_systems.find (fs->GetName ()) != disabled_file_systems.end ()) {
257+ throw PermissionException (" File system %s has been disabled by configuration" , fs->GetName ());
258+ }
259+ return *fs;
260+ }
261+
219262FileSystem &VirtualFileSystem::FindFileSystem (const string &path) {
220- auto &fs = FindFileSystemInternal (path);
221- if (!disabled_file_systems.empty () && disabled_file_systems.find (fs.GetName ()) != disabled_file_systems.end ()) {
222- throw PermissionException (" File system %s has been disabled by configuration" , fs.GetName ());
263+ auto fs = FindFileSystemInternal (path);
264+ if (!fs) {
265+ fs = default_fs;
266+ }
267+ if (!disabled_file_systems.empty () && disabled_file_systems.find (fs->GetName ()) != disabled_file_systems.end ()) {
268+ throw PermissionException (" File system %s has been disabled by configuration" , fs->GetName ());
223269 }
224- return fs;
270+ return * fs;
225271}
226272
227- FileSystem & VirtualFileSystem::FindFileSystemInternal (const string &path) {
273+ optional_ptr< FileSystem> VirtualFileSystem::FindFileSystemInternal (const string &path) {
228274 FileSystem *fs = nullptr ;
275+
229276 for (auto &sub_system : sub_systems) {
230277 if (sub_system->CanHandleFile (path)) {
231278 if (sub_system->IsManuallySet ()) {
@@ -237,7 +284,9 @@ FileSystem &VirtualFileSystem::FindFileSystemInternal(const string &path) {
237284 if (fs) {
238285 return *fs;
239286 }
240- return *default_fs;
287+
288+ // We could use default_fs, that's on the caller
289+ return nullptr ;
241290}
242291
243292} // namespace duckdb
0 commit comments