1#include "duckdb/main/attached_database.hpp"
2
3#include "duckdb/catalog/duck_catalog.hpp"
4#include "duckdb/common/file_system.hpp"
5#include "duckdb/parser/parsed_data/attach_info.hpp"
6#include "duckdb/storage/storage_extension.hpp"
7#include "duckdb/storage/storage_manager.hpp"
8#include "duckdb/transaction/duck_transaction_manager.hpp"
9
10namespace duckdb {
11
12AttachedDatabase::AttachedDatabase(DatabaseInstance &db, AttachedDatabaseType type)
13 : CatalogEntry(CatalogType::DATABASE_ENTRY,
14 type == AttachedDatabaseType::SYSTEM_DATABASE ? SYSTEM_CATALOG : TEMP_CATALOG, 0),
15 db(db), type(type) {
16 D_ASSERT(type == AttachedDatabaseType::TEMP_DATABASE || type == AttachedDatabaseType::SYSTEM_DATABASE);
17 if (type == AttachedDatabaseType::TEMP_DATABASE) {
18 storage = make_uniq<SingleFileStorageManager>(args&: *this, args: ":memory:", args: false);
19 }
20 catalog = make_uniq<DuckCatalog>(args&: *this);
21 transaction_manager = make_uniq<DuckTransactionManager>(args&: *this);
22 internal = true;
23}
24
25AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, string name_p, string file_path_p,
26 AccessMode access_mode)
27 : CatalogEntry(CatalogType::DATABASE_ENTRY, catalog_p, std::move(name_p)), db(db),
28 type(access_mode == AccessMode::READ_ONLY ? AttachedDatabaseType::READ_ONLY_DATABASE
29 : AttachedDatabaseType::READ_WRITE_DATABASE),
30 parent_catalog(&catalog_p) {
31 storage = make_uniq<SingleFileStorageManager>(args&: *this, args: std::move(file_path_p), args: access_mode == AccessMode::READ_ONLY);
32 catalog = make_uniq<DuckCatalog>(args&: *this);
33 transaction_manager = make_uniq<DuckTransactionManager>(args&: *this);
34 internal = true;
35}
36
37AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, StorageExtension &storage_extension,
38 string name_p, AttachInfo &info, AccessMode access_mode)
39 : CatalogEntry(CatalogType::DATABASE_ENTRY, catalog_p, std::move(name_p)), db(db),
40 type(access_mode == AccessMode::READ_ONLY ? AttachedDatabaseType::READ_ONLY_DATABASE
41 : AttachedDatabaseType::READ_WRITE_DATABASE),
42 parent_catalog(&catalog_p) {
43 catalog = storage_extension.attach(storage_extension.storage_info.get(), *this, name, info, access_mode);
44 if (!catalog) {
45 throw InternalException("AttachedDatabase - attach function did not return a catalog");
46 }
47 transaction_manager =
48 storage_extension.create_transaction_manager(storage_extension.storage_info.get(), *this, *catalog);
49 if (!transaction_manager) {
50 throw InternalException(
51 "AttachedDatabase - create_transaction_manager function did not return a transaction manager");
52 }
53 internal = true;
54}
55
56AttachedDatabase::~AttachedDatabase() {
57 if (Exception::UncaughtException()) {
58 return;
59 }
60 if (!storage) {
61 return;
62 }
63
64 // shutting down: attempt to checkpoint the database
65 // but only if we are not cleaning up as part of an exception unwind
66 try {
67 if (!storage->InMemory()) {
68 auto &config = DBConfig::GetConfig(db);
69 if (!config.options.checkpoint_on_shutdown) {
70 return;
71 }
72 storage->CreateCheckpoint(delete_wal: true);
73 }
74 } catch (...) {
75 }
76}
77
78bool AttachedDatabase::IsSystem() const {
79 D_ASSERT(!storage || type != AttachedDatabaseType::SYSTEM_DATABASE);
80 return type == AttachedDatabaseType::SYSTEM_DATABASE;
81}
82
83bool AttachedDatabase::IsTemporary() const {
84 return type == AttachedDatabaseType::TEMP_DATABASE;
85}
86bool AttachedDatabase::IsReadOnly() const {
87 return type == AttachedDatabaseType::READ_ONLY_DATABASE;
88}
89
90string AttachedDatabase::ExtractDatabaseName(const string &dbpath) {
91 if (dbpath.empty() || dbpath == ":memory:") {
92 return "memory";
93 }
94 return FileSystem::ExtractBaseName(path: dbpath);
95}
96
97void AttachedDatabase::Initialize() {
98 if (IsSystem()) {
99 catalog->Initialize(load_builtin: true);
100 } else {
101 catalog->Initialize(load_builtin: false);
102 }
103 if (storage) {
104 storage->Initialize();
105 }
106}
107
108StorageManager &AttachedDatabase::GetStorageManager() {
109 if (!storage) {
110 throw InternalException("Internal system catalog does not have storage");
111 }
112 return *storage;
113}
114
115Catalog &AttachedDatabase::GetCatalog() {
116 return *catalog;
117}
118
119TransactionManager &AttachedDatabase::GetTransactionManager() {
120 return *transaction_manager;
121}
122
123Catalog &AttachedDatabase::ParentCatalog() {
124 return *parent_catalog;
125}
126
127bool AttachedDatabase::IsInitialDatabase() const {
128 return is_initial_database;
129}
130
131void AttachedDatabase::SetInitialDatabase() {
132 is_initial_database = true;
133}
134
135} // namespace duckdb
136