1 | #include "duckdb/catalog/duck_catalog.hpp" |
2 | #include "duckdb/catalog/dependency_manager.hpp" |
3 | #include "duckdb/catalog/catalog_entry/duck_schema_entry.hpp" |
4 | #include "duckdb/storage/storage_manager.hpp" |
5 | #include "duckdb/parser/parsed_data/drop_info.hpp" |
6 | #include "duckdb/parser/parsed_data/create_schema_info.hpp" |
7 | #include "duckdb/catalog/default/default_schemas.hpp" |
8 | #include "duckdb/function/built_in_functions.hpp" |
9 | #include "duckdb/main/attached_database.hpp" |
10 | #ifndef DISABLE_CORE_FUNCTIONS_EXTENSION |
11 | #include "duckdb/core_functions/core_functions.hpp" |
12 | #endif |
13 | |
14 | namespace duckdb { |
15 | |
16 | DuckCatalog::DuckCatalog(AttachedDatabase &db) |
17 | : Catalog(db), dependency_manager(make_uniq<DependencyManager>(args&: *this)), |
18 | schemas(make_uniq<CatalogSet>(args&: *this, args: make_uniq<DefaultSchemaGenerator>(args&: *this))) { |
19 | } |
20 | |
21 | DuckCatalog::~DuckCatalog() { |
22 | } |
23 | |
24 | void DuckCatalog::Initialize(bool load_builtin) { |
25 | // first initialize the base system catalogs |
26 | // these are never written to the WAL |
27 | // we start these at 1 because deleted entries default to 0 |
28 | auto data = CatalogTransaction::GetSystemTransaction(db&: GetDatabase()); |
29 | |
30 | // create the default schema |
31 | CreateSchemaInfo info; |
32 | info.schema = DEFAULT_SCHEMA; |
33 | info.internal = true; |
34 | CreateSchema(transaction: data, info); |
35 | |
36 | if (load_builtin) { |
37 | // initialize default functions |
38 | BuiltinFunctions builtin(data, *this); |
39 | builtin.Initialize(); |
40 | |
41 | #ifndef DISABLE_CORE_FUNCTIONS_EXTENSION |
42 | CoreFunctions::RegisterFunctions(catalog&: *this, transaction: data); |
43 | #endif |
44 | } |
45 | |
46 | Verify(); |
47 | } |
48 | |
49 | bool DuckCatalog::IsDuckCatalog() { |
50 | return true; |
51 | } |
52 | |
53 | //===--------------------------------------------------------------------===// |
54 | // Schema |
55 | //===--------------------------------------------------------------------===// |
56 | optional_ptr<CatalogEntry> DuckCatalog::CreateSchemaInternal(CatalogTransaction transaction, CreateSchemaInfo &info) { |
57 | DependencyList dependencies; |
58 | auto entry = make_uniq<DuckSchemaEntry>(args&: *this, args&: info.schema, args&: info.internal); |
59 | auto result = entry.get(); |
60 | if (!schemas->CreateEntry(transaction, name: info.schema, value: std::move(entry), dependencies)) { |
61 | return nullptr; |
62 | } |
63 | return (CatalogEntry *)result; |
64 | } |
65 | |
66 | optional_ptr<CatalogEntry> DuckCatalog::CreateSchema(CatalogTransaction transaction, CreateSchemaInfo &info) { |
67 | D_ASSERT(!info.schema.empty()); |
68 | auto result = CreateSchemaInternal(transaction, info); |
69 | if (!result) { |
70 | switch (info.on_conflict) { |
71 | case OnCreateConflict::ERROR_ON_CONFLICT: |
72 | throw CatalogException("Schema with name %s already exists!" , info.schema); |
73 | case OnCreateConflict::REPLACE_ON_CONFLICT: { |
74 | DropInfo drop_info; |
75 | drop_info.type = CatalogType::SCHEMA_ENTRY; |
76 | drop_info.catalog = info.catalog; |
77 | drop_info.name = info.schema; |
78 | DropSchema(transaction, info&: drop_info); |
79 | result = CreateSchemaInternal(transaction, info); |
80 | if (!result) { |
81 | throw InternalException("Failed to create schema entry in CREATE_OR_REPLACE" ); |
82 | } |
83 | break; |
84 | } |
85 | case OnCreateConflict::IGNORE_ON_CONFLICT: |
86 | break; |
87 | default: |
88 | throw InternalException("Unsupported OnCreateConflict for CreateSchema" ); |
89 | } |
90 | return nullptr; |
91 | } |
92 | return result; |
93 | } |
94 | |
95 | void DuckCatalog::DropSchema(CatalogTransaction transaction, DropInfo &info) { |
96 | D_ASSERT(!info.name.empty()); |
97 | ModifyCatalog(); |
98 | if (!schemas->DropEntry(transaction, name: info.name, cascade: info.cascade)) { |
99 | if (info.if_not_found == OnEntryNotFound::THROW_EXCEPTION) { |
100 | throw CatalogException("Schema with name \"%s\" does not exist!" , info.name); |
101 | } |
102 | } |
103 | } |
104 | |
105 | void DuckCatalog::DropSchema(ClientContext &context, DropInfo &info) { |
106 | DropSchema(transaction: GetCatalogTransaction(context), info); |
107 | } |
108 | |
109 | void DuckCatalog::ScanSchemas(ClientContext &context, std::function<void(SchemaCatalogEntry &)> callback) { |
110 | schemas->Scan(transaction: GetCatalogTransaction(context), |
111 | callback: [&](CatalogEntry &entry) { callback(entry.Cast<SchemaCatalogEntry>()); }); |
112 | } |
113 | |
114 | void DuckCatalog::ScanSchemas(std::function<void(SchemaCatalogEntry &)> callback) { |
115 | schemas->Scan(callback: [&](CatalogEntry &entry) { callback(entry.Cast<SchemaCatalogEntry>()); }); |
116 | } |
117 | |
118 | optional_ptr<SchemaCatalogEntry> DuckCatalog::GetSchema(CatalogTransaction transaction, const string &schema_name, |
119 | OnEntryNotFound if_not_found, QueryErrorContext error_context) { |
120 | D_ASSERT(!schema_name.empty()); |
121 | auto entry = schemas->GetEntry(transaction, name: schema_name); |
122 | if (!entry) { |
123 | if (if_not_found == OnEntryNotFound::THROW_EXCEPTION) { |
124 | throw CatalogException(error_context.FormatError(msg: "Schema with name %s does not exist!" , params: schema_name)); |
125 | } |
126 | return nullptr; |
127 | } |
128 | return &entry->Cast<SchemaCatalogEntry>(); |
129 | } |
130 | |
131 | DatabaseSize DuckCatalog::GetDatabaseSize(ClientContext &context) { |
132 | return db.GetStorageManager().GetDatabaseSize(); |
133 | } |
134 | |
135 | bool DuckCatalog::InMemory() { |
136 | return db.GetStorageManager().InMemory(); |
137 | } |
138 | |
139 | string DuckCatalog::GetDBPath() { |
140 | return db.GetStorageManager().GetDBPath(); |
141 | } |
142 | |
143 | void DuckCatalog::Verify() { |
144 | #ifdef DEBUG |
145 | Catalog::Verify(); |
146 | schemas->Verify(*this); |
147 | #endif |
148 | } |
149 | |
150 | } // namespace duckdb |
151 | |