1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/catalog/catalog_set.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/catalog/catalog_entry.hpp" |
12 | #include "duckdb/catalog/default/default_generator.hpp" |
13 | #include "duckdb/common/common.hpp" |
14 | #include "duckdb/common/case_insensitive_map.hpp" |
15 | #include "duckdb/common/pair.hpp" |
16 | #include "duckdb/common/unordered_set.hpp" |
17 | #include "duckdb/common/mutex.hpp" |
18 | #include "duckdb/parser/column_definition.hpp" |
19 | #include "duckdb/transaction/transaction.hpp" |
20 | #include "duckdb/catalog/catalog_transaction.hpp" |
21 | #include "duckdb/catalog/similar_catalog_entry.hpp" |
22 | #include <functional> |
23 | #include <memory> |
24 | |
25 | namespace duckdb { |
26 | struct AlterInfo; |
27 | |
28 | class ClientContext; |
29 | class DependencyList; |
30 | struct MappingValue; |
31 | struct EntryIndex; |
32 | |
33 | class DuckCatalog; |
34 | class TableCatalogEntry; |
35 | class SequenceCatalogEntry; |
36 | |
37 | typedef unordered_map<CatalogSet *, unique_lock<mutex>> set_lock_map_t; |
38 | |
39 | struct EntryValue { |
40 | EntryValue() { |
41 | throw InternalException("EntryValue called without a catalog entry" ); |
42 | } |
43 | |
44 | explicit EntryValue(unique_ptr<CatalogEntry> entry_p) : entry(std::move(entry_p)), reference_count(0) { |
45 | } |
46 | //! enable move constructors |
47 | EntryValue(EntryValue &&other) noexcept { |
48 | Swap(other); |
49 | } |
50 | EntryValue &operator=(EntryValue &&other) noexcept { |
51 | Swap(other); |
52 | return *this; |
53 | } |
54 | void Swap(EntryValue &other) { |
55 | std::swap(a&: entry, b&: other.entry); |
56 | idx_t count = reference_count; |
57 | reference_count = other.reference_count.load(); |
58 | other.reference_count = count; |
59 | } |
60 | |
61 | unique_ptr<CatalogEntry> entry; |
62 | atomic<idx_t> reference_count; |
63 | }; |
64 | |
65 | //! The Catalog Set stores (key, value) map of a set of CatalogEntries |
66 | class CatalogSet { |
67 | friend class DependencyManager; |
68 | friend class EntryDropper; |
69 | friend struct EntryIndex; |
70 | |
71 | public: |
72 | DUCKDB_API explicit CatalogSet(Catalog &catalog, unique_ptr<DefaultGenerator> defaults = nullptr); |
73 | ~CatalogSet(); |
74 | |
75 | //! Create an entry in the catalog set. Returns whether or not it was |
76 | //! successful. |
77 | DUCKDB_API bool CreateEntry(CatalogTransaction transaction, const string &name, unique_ptr<CatalogEntry> value, |
78 | DependencyList &dependencies); |
79 | DUCKDB_API bool CreateEntry(ClientContext &context, const string &name, unique_ptr<CatalogEntry> value, |
80 | DependencyList &dependencies); |
81 | |
82 | DUCKDB_API bool AlterEntry(CatalogTransaction transaction, const string &name, AlterInfo &alter_info); |
83 | |
84 | DUCKDB_API bool DropEntry(CatalogTransaction transaction, const string &name, bool cascade, |
85 | bool allow_drop_internal = false); |
86 | DUCKDB_API bool DropEntry(ClientContext &context, const string &name, bool cascade, |
87 | bool allow_drop_internal = false); |
88 | |
89 | DUCKDB_API DuckCatalog &GetCatalog(); |
90 | |
91 | bool AlterOwnership(CatalogTransaction transaction, ChangeOwnershipInfo &info); |
92 | |
93 | void CleanupEntry(CatalogEntry &catalog_entry); |
94 | |
95 | //! Returns the entry with the specified name |
96 | DUCKDB_API optional_ptr<CatalogEntry> GetEntry(CatalogTransaction transaction, const string &name); |
97 | DUCKDB_API optional_ptr<CatalogEntry> GetEntry(ClientContext &context, const string &name); |
98 | |
99 | //! Gets the entry that is most similar to the given name (i.e. smallest levenshtein distance), or empty string if |
100 | //! none is found. The returned pair consists of the entry name and the distance (smaller means closer). |
101 | SimilarCatalogEntry SimilarEntry(CatalogTransaction transaction, const string &name); |
102 | |
103 | //! Rollback <entry> to be the currently valid entry for a certain catalog |
104 | //! entry |
105 | void Undo(CatalogEntry &entry); |
106 | |
107 | //! Scan the catalog set, invoking the callback method for every committed entry |
108 | DUCKDB_API void Scan(const std::function<void(CatalogEntry &)> &callback); |
109 | //! Scan the catalog set, invoking the callback method for every entry |
110 | DUCKDB_API void Scan(CatalogTransaction transaction, const std::function<void(CatalogEntry &)> &callback); |
111 | DUCKDB_API void Scan(ClientContext &context, const std::function<void(CatalogEntry &)> &callback); |
112 | |
113 | template <class T> |
114 | vector<reference<T>> GetEntries(CatalogTransaction transaction) { |
115 | vector<reference<T>> result; |
116 | Scan(transaction, [&](CatalogEntry &entry) { result.push_back(entry.Cast<T>()); }); |
117 | return result; |
118 | } |
119 | |
120 | DUCKDB_API bool HasConflict(CatalogTransaction transaction, transaction_t timestamp); |
121 | DUCKDB_API bool UseTimestamp(CatalogTransaction transaction, transaction_t timestamp); |
122 | |
123 | void UpdateTimestamp(CatalogEntry &entry, transaction_t timestamp); |
124 | |
125 | void Verify(Catalog &catalog); |
126 | |
127 | private: |
128 | //! Adjusts table dependencies on the event of an UNDO |
129 | void AdjustTableDependencies(CatalogEntry &entry); |
130 | //! Adjust one dependency |
131 | void AdjustDependency(CatalogEntry &entry, TableCatalogEntry &table, ColumnDefinition &column, bool remove); |
132 | //! Adjust User dependency |
133 | void AdjustUserDependency(CatalogEntry &entry, ColumnDefinition &column, bool remove); |
134 | //! Given a root entry, gets the entry valid for this transaction |
135 | CatalogEntry &GetEntryForTransaction(CatalogTransaction transaction, CatalogEntry ¤t); |
136 | CatalogEntry &GetCommittedEntry(CatalogEntry ¤t); |
137 | optional_ptr<CatalogEntry> GetEntryInternal(CatalogTransaction transaction, const string &name, |
138 | EntryIndex *entry_index); |
139 | optional_ptr<CatalogEntry> GetEntryInternal(CatalogTransaction transaction, EntryIndex &entry_index); |
140 | //! Drops an entry from the catalog set; must hold the catalog_lock to safely call this |
141 | void DropEntryInternal(CatalogTransaction transaction, EntryIndex entry_index, CatalogEntry &entry, bool cascade); |
142 | optional_ptr<CatalogEntry> CreateEntryInternal(CatalogTransaction transaction, unique_ptr<CatalogEntry> entry); |
143 | optional_ptr<MappingValue> GetMapping(CatalogTransaction transaction, const string &name, bool get_latest = false); |
144 | void PutMapping(CatalogTransaction transaction, const string &name, EntryIndex entry_index); |
145 | void DeleteMapping(CatalogTransaction transaction, const string &name); |
146 | void DropEntryDependencies(CatalogTransaction transaction, EntryIndex &entry_index, CatalogEntry &entry, |
147 | bool cascade); |
148 | |
149 | //! Create all default entries |
150 | void CreateDefaultEntries(CatalogTransaction transaction, unique_lock<mutex> &lock); |
151 | //! Attempt to create a default entry with the specified name. Returns the entry if successful, nullptr otherwise. |
152 | optional_ptr<CatalogEntry> CreateDefaultEntry(CatalogTransaction transaction, const string &name, |
153 | unique_lock<mutex> &lock); |
154 | |
155 | EntryIndex PutEntry(idx_t entry_index, unique_ptr<CatalogEntry> entry); |
156 | void PutEntry(EntryIndex index, unique_ptr<CatalogEntry> entry); |
157 | |
158 | private: |
159 | DuckCatalog &catalog; |
160 | //! The catalog lock is used to make changes to the data |
161 | mutex catalog_lock; |
162 | //! The set of catalog entries |
163 | unordered_map<idx_t, EntryValue> entries; |
164 | //! Mapping of string to catalog entry |
165 | case_insensitive_map_t<unique_ptr<MappingValue>> mapping; |
166 | //! The current catalog entry index |
167 | idx_t current_entry = 0; |
168 | //! The generator used to generate default internal entries |
169 | unique_ptr<DefaultGenerator> defaults; |
170 | }; |
171 | } // namespace duckdb |
172 | |