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
25namespace duckdb {
26struct AlterInfo;
27
28class ClientContext;
29class DependencyList;
30struct MappingValue;
31struct EntryIndex;
32
33class DuckCatalog;
34class TableCatalogEntry;
35class SequenceCatalogEntry;
36
37typedef unordered_map<CatalogSet *, unique_lock<mutex>> set_lock_map_t;
38
39struct 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
66class CatalogSet {
67 friend class DependencyManager;
68 friend class EntryDropper;
69 friend struct EntryIndex;
70
71public:
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
127private:
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 &current);
136 CatalogEntry &GetCommittedEntry(CatalogEntry &current);
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
158private:
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