1#include "duckdb/main/database_manager.hpp"
2#include "duckdb/catalog/catalog.hpp"
3#include "duckdb/main/attached_database.hpp"
4#include "duckdb/storage/storage_manager.hpp"
5#include "duckdb/main/client_data.hpp"
6#include "duckdb/catalog/catalog_search_path.hpp"
7
8namespace duckdb {
9
10DatabaseManager::DatabaseManager(DatabaseInstance &db) : catalog_version(0), current_query_number(1) {
11 system = make_uniq<AttachedDatabase>(args&: db);
12 databases = make_uniq<CatalogSet>(args&: system->GetCatalog());
13}
14
15DatabaseManager::~DatabaseManager() {
16}
17
18DatabaseManager &DatabaseManager::Get(AttachedDatabase &db) {
19 return DatabaseManager::Get(db&: db.GetDatabase());
20}
21
22void DatabaseManager::InitializeSystemCatalog() {
23 system->Initialize();
24}
25
26optional_ptr<AttachedDatabase> DatabaseManager::GetDatabase(ClientContext &context, const string &name) {
27 if (StringUtil::Lower(str: name) == TEMP_CATALOG) {
28 return context.client_data->temporary_objects.get();
29 }
30 return reinterpret_cast<AttachedDatabase *>(databases->GetEntry(context, name).get());
31}
32
33void DatabaseManager::AddDatabase(ClientContext &context, unique_ptr<AttachedDatabase> db_instance) {
34 auto name = db_instance->GetName();
35 db_instance->oid = ModifyCatalog();
36 DependencyList dependencies;
37 if (default_database.empty()) {
38 default_database = name;
39 }
40 if (!databases->CreateEntry(context, name, value: std::move(db_instance), dependencies)) {
41 throw BinderException("Failed to attach database: database with name \"%s\" already exists", name);
42 }
43}
44
45void DatabaseManager::DetachDatabase(ClientContext &context, const string &name, OnEntryNotFound if_not_found) {
46 if (GetDefaultDatabase(context) == name) {
47 throw BinderException("Cannot detach database \"%s\" because it is the default database. Select a different "
48 "database using `USE` to allow detaching this database",
49 name);
50 }
51 if (!databases->DropEntry(context, name, cascade: false, allow_drop_internal: true)) {
52 if (if_not_found == OnEntryNotFound::THROW_EXCEPTION) {
53 throw BinderException("Failed to detach database with name \"%s\": database not found", name);
54 }
55 }
56}
57
58optional_ptr<AttachedDatabase> DatabaseManager::GetDatabaseFromPath(ClientContext &context, const string &path) {
59 auto databases = GetDatabases(context);
60 for (auto &db_ref : databases) {
61 auto &db = db_ref.get();
62 if (db.IsSystem()) {
63 continue;
64 }
65 auto &catalog = Catalog::GetCatalog(db);
66 if (catalog.InMemory()) {
67 continue;
68 }
69 auto db_path = catalog.GetDBPath();
70 if (StringUtil::CIEquals(l1: path, l2: db_path)) {
71 return &db;
72 }
73 }
74 return nullptr;
75}
76
77const string &DatabaseManager::GetDefaultDatabase(ClientContext &context) {
78 auto &config = ClientData::Get(context);
79 auto &default_entry = config.catalog_search_path->GetDefault();
80 if (IsInvalidCatalog(str: default_entry.catalog)) {
81 auto &result = DatabaseManager::Get(db&: context).default_database;
82 if (result.empty()) {
83 throw InternalException("Calling DatabaseManager::GetDefaultDatabase with no default database set");
84 }
85 return result;
86 }
87 return default_entry.catalog;
88}
89
90// LCOV_EXCL_START
91void DatabaseManager::SetDefaultDatabase(ClientContext &context, const string &new_value) {
92 auto db_entry = GetDatabase(context, name: new_value);
93
94 if (!db_entry) {
95 throw InternalException("Database \"%s\" not found", new_value);
96 } else if (db_entry->IsTemporary()) {
97 throw InternalException("Cannot set the default database to a temporary database");
98 } else if (db_entry->IsSystem()) {
99 throw InternalException("Cannot set the default database to a system database");
100 }
101
102 default_database = new_value;
103}
104// LCOV_EXCL_STOP
105
106vector<reference<AttachedDatabase>> DatabaseManager::GetDatabases(ClientContext &context) {
107 vector<reference<AttachedDatabase>> result;
108 databases->Scan(context, callback: [&](CatalogEntry &entry) { result.push_back(x: entry.Cast<AttachedDatabase>()); });
109 result.push_back(x: *system);
110 result.push_back(x: *context.client_data->temporary_objects);
111 return result;
112}
113
114Catalog &DatabaseManager::GetSystemCatalog() {
115 D_ASSERT(system);
116 return system->GetCatalog();
117}
118
119} // namespace duckdb
120