diff --git a/src/duckdb/src/execution/operator/schema/physical_attach.cpp b/src/duckdb/src/execution/operator/schema/physical_attach.cpp index 90bd8e77c..95747b480 100644 --- a/src/duckdb/src/execution/operator/schema/physical_attach.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_attach.cpp @@ -56,15 +56,6 @@ void ParseOptions(const unique_ptr &info, AccessMode &access_mode, s //===--------------------------------------------------------------------===// SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const { - - // get the name and path of the database - auto &name = info->name; - const auto &path = info->path; - if (name.empty()) { - auto &fs = FileSystem::GetFileSystem(context.client); - name = AttachedDatabase::ExtractDatabaseName(path, fs); - } - // parse the options auto &config = DBConfig::GetConfig(context.client); AccessMode access_mode = config.options.access_mode; @@ -72,10 +63,17 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c string unrecognized_option; ParseOptions(info, access_mode, db_type, unrecognized_option); + // get the name and path of the database + auto &name = info->name; + auto &path = info->path; + if (name.empty()) { + auto &fs = FileSystem::GetFileSystem(context.client); + name = AttachedDatabase::ExtractDatabaseNameAndType(path, db_type, fs); + } + // check ATTACH IF NOT EXISTS auto &db_manager = DatabaseManager::Get(context.client); if (info->on_conflict == OnCreateConflict::IGNORE_ON_CONFLICT) { - // constant-time lookup in the catalog for the db name auto existing_db = db_manager.GetDatabase(context.client, name); if (existing_db) { diff --git a/src/duckdb/src/function/table/version/pragma_version.cpp b/src/duckdb/src/function/table/version/pragma_version.cpp index ce7a98bf6..ffbb9291c 100644 --- a/src/duckdb/src/function/table/version/pragma_version.cpp +++ b/src/duckdb/src/function/table/version/pragma_version.cpp @@ -1,8 +1,8 @@ #ifndef DUCKDB_VERSION -#define DUCKDB_VERSION "v0.9.3-dev759" +#define DUCKDB_VERSION "v0.9.3-dev764" #endif #ifndef DUCKDB_SOURCE_ID -#define DUCKDB_SOURCE_ID "9898183b56" +#define DUCKDB_SOURCE_ID "5080b78720" #endif #include "duckdb/function/table/system_functions.hpp" #include "duckdb/main/database.hpp" diff --git a/src/duckdb/src/include/duckdb/main/attached_database.hpp b/src/duckdb/src/include/duckdb/main/attached_database.hpp index 7ecbc14f8..dff495001 100644 --- a/src/duckdb/src/include/duckdb/main/attached_database.hpp +++ b/src/duckdb/src/include/duckdb/main/attached_database.hpp @@ -62,6 +62,7 @@ class AttachedDatabase : public CatalogEntry { void SetInitialDatabase(); static string ExtractDatabaseName(const string &dbpath, FileSystem &fs); + static string ExtractDatabaseNameAndType(string &dbpath, string &db_type, FileSystem &fs); private: DatabaseInstance &db; diff --git a/src/duckdb/src/include/duckdb/main/database_path_and_type.hpp b/src/duckdb/src/include/duckdb/main/database_path_and_type.hpp index e1dc5d469..55269320d 100644 --- a/src/duckdb/src/include/duckdb/main/database_path_and_type.hpp +++ b/src/duckdb/src/include/duckdb/main/database_path_and_type.hpp @@ -14,11 +14,12 @@ namespace duckdb { struct DBPathAndType { - //! Parse database extension type and rest of path from combined form (type:path) - static DBPathAndType Parse(const string &combined_path, const DBConfig &config); + static void ExtractExtensionPrefix(string &path, string &db_type); + //! Check the magic bytes of a file and set the database type based on that + static void CheckMagicBytes(string &path, string &db_type, const DBConfig &config); - const string path; - const string type; + //! Run ExtractExtensionPrefix followed by CheckMagicBytes + static void ResolveDatabaseType(string &path, string &db_type, const DBConfig &config); }; } // namespace duckdb diff --git a/src/duckdb/src/main/attached_database.cpp b/src/duckdb/src/main/attached_database.cpp index fc56c974a..b4a38559c 100644 --- a/src/duckdb/src/main/attached_database.cpp +++ b/src/duckdb/src/main/attached_database.cpp @@ -9,6 +9,7 @@ #include "duckdb/storage/storage_extension.hpp" #include "duckdb/storage/storage_manager.hpp" #include "duckdb/transaction/duck_transaction_manager.hpp" +#include "duckdb/main/database_path_and_type.hpp" namespace duckdb { @@ -100,6 +101,14 @@ bool AttachedDatabase::IsReadOnly() const { return type == AttachedDatabaseType::READ_ONLY_DATABASE; } +string AttachedDatabase::ExtractDatabaseNameAndType(string &dbpath, string &db_type, FileSystem &fs) { + // try to extract database type from path + if (db_type.empty()) { + DBPathAndType::ExtractExtensionPrefix(dbpath, db_type); + } + return AttachedDatabase::ExtractDatabaseName(dbpath, fs); +} + string AttachedDatabase::ExtractDatabaseName(const string &dbpath, FileSystem &fs) { if (dbpath.empty() || dbpath == IN_MEMORY_PATH) { return "memory"; diff --git a/src/duckdb/src/main/database.cpp b/src/duckdb/src/main/database.cpp index 16a32433e..e8066fdc6 100644 --- a/src/duckdb/src/main/database.cpp +++ b/src/duckdb/src/main/database.cpp @@ -221,12 +221,8 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf object_cache = make_uniq(); connection_manager = make_uniq(); - // check if we are opening a standard DuckDB database or an extension database - if (config.options.database_type.empty()) { - auto path_and_type = DBPathAndType::Parse(config.options.database_path, config); - config.options.database_type = path_and_type.type; - config.options.database_path = path_and_type.path; - } + // resolve the type of teh database we are opening + DBPathAndType::ResolveDatabaseType(config.options.database_path, config.options.database_type, config); // initialize the system catalog db_manager->InitializeSystemCatalog(); diff --git a/src/duckdb/src/main/database_manager.cpp b/src/duckdb/src/main/database_manager.cpp index f75a2bacc..a3983332d 100644 --- a/src/duckdb/src/main/database_manager.cpp +++ b/src/duckdb/src/main/database_manager.cpp @@ -125,9 +125,7 @@ void DatabaseManager::GetDatabaseType(ClientContext &context, string &db_type, A // try to extract database type from path if (db_type.empty()) { - auto path_and_type = DBPathAndType::Parse(info.path, config); - db_type = path_and_type.type; - info.path = path_and_type.path; + DBPathAndType::CheckMagicBytes(info.path, db_type, config); } // if we are loading a database type from an extension - check if that extension is loaded diff --git a/src/duckdb/src/main/database_path_and_type.cpp b/src/duckdb/src/main/database_path_and_type.cpp index 64f1f9cee..3accb4e2e 100644 --- a/src/duckdb/src/main/database_path_and_type.cpp +++ b/src/duckdb/src/main/database_path_and_type.cpp @@ -5,19 +5,38 @@ namespace duckdb { -DBPathAndType DBPathAndType::Parse(const string &combined_path, const DBConfig &config) { - auto extension = ExtensionHelper::ExtractExtensionPrefixFromPath(combined_path); +void DBPathAndType::ExtractExtensionPrefix(string &path, string &db_type) { + auto extension = ExtensionHelper::ExtractExtensionPrefixFromPath(path); if (!extension.empty()) { // path is prefixed with an extension - remove it - auto path = StringUtil::Replace(combined_path, extension + ":", ""); - auto type = ExtensionHelper::ApplyExtensionAlias(extension); - return {path, type}; + path = StringUtil::Replace(path, extension + ":", ""); + db_type = ExtensionHelper::ApplyExtensionAlias(extension); } +} + +void DBPathAndType::CheckMagicBytes(string &path, string &db_type, const DBConfig &config) { // if there isn't - check the magic bytes of the file (if any) - auto file_type = MagicBytes::CheckMagicBytes(config.file_system.get(), combined_path); + auto file_type = MagicBytes::CheckMagicBytes(config.file_system.get(), path); if (file_type == DataFileType::SQLITE_FILE) { - return {combined_path, "sqlite"}; + db_type = "sqlite"; + } else { + db_type = ""; } - return {combined_path, string()}; } + +void DBPathAndType::ResolveDatabaseType(string &path, string &db_type, const DBConfig &config) { + if (!db_type.empty()) { + // database type specified explicitly - no need to check + return; + } + // check for an extension prefix + ExtractExtensionPrefix(path, db_type); + if (!db_type.empty()) { + // extension prefix was provided (e.g. sqlite:/path/to/file.db) - we are done + return; + } + // check database type by reading the magic bytes of a file + DBPathAndType::CheckMagicBytes(path, db_type, config); +} + } // namespace duckdb