1#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp"
2
3#include "duckdb/catalog/catalog.hpp"
4#include "duckdb/catalog/catalog_entry/index_catalog_entry.hpp"
5#include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp"
6#include "duckdb/catalog/catalog_entry/collate_catalog_entry.hpp"
7#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp"
8#include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp"
9#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
10#include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp"
11#include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp"
12#include "duckdb/common/exception.hpp"
13#include "duckdb/parser/parsed_data/alter_table_info.hpp"
14#include "duckdb/parser/parsed_data/create_index_info.hpp"
15#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
16#include "duckdb/parser/parsed_data/create_collation_info.hpp"
17#include "duckdb/parser/parsed_data/create_schema_info.hpp"
18#include "duckdb/parser/parsed_data/create_sequence_info.hpp"
19#include "duckdb/parser/parsed_data/create_table_function_info.hpp"
20#include "duckdb/parser/parsed_data/create_view_info.hpp"
21#include "duckdb/parser/parsed_data/drop_info.hpp"
22#include "duckdb/planner/parsed_data/bound_create_table_info.hpp"
23#include "duckdb/transaction/transaction.hpp"
24
25#include <algorithm>
26
27using namespace duckdb;
28using namespace std;
29
30SchemaCatalogEntry::SchemaCatalogEntry(Catalog *catalog, string name)
31 : CatalogEntry(CatalogType::SCHEMA, catalog, name), tables(*catalog), indexes(*catalog), table_functions(*catalog),
32 functions(*catalog), sequences(*catalog), collations(*catalog) {
33}
34
35CatalogEntry *SchemaCatalogEntry::AddEntry(ClientContext &context, unique_ptr<StandardEntry> entry,
36 OnCreateConflict on_conflict, unordered_set<CatalogEntry *> dependencies) {
37 auto entry_name = entry->name;
38 auto entry_type = entry->type;
39 auto result = entry.get();
40 auto &transaction = Transaction::GetTransaction(context);
41
42 // first find the set for this entry
43 auto &set = GetCatalogSet(entry_type);
44
45 if (name != TEMP_SCHEMA) {
46 dependencies.insert(this);
47 } else {
48 entry->temporary = true;
49 }
50 if (on_conflict == OnCreateConflict::REPLACE) {
51 // CREATE OR REPLACE: first try to drop the entry
52 auto old_entry = set.GetEntry(transaction, entry_name);
53 if (old_entry) {
54 if (old_entry->type != entry_type) {
55 throw CatalogException("Existing object %s is of type %s, trying to replace with type %s",
56 entry_name.c_str(), CatalogTypeToString(old_entry->type).c_str(),
57 CatalogTypeToString(entry_type).c_str());
58 }
59 (void)set.DropEntry(transaction, entry_name, false);
60 }
61 }
62 // now try to add the entry
63 if (!set.CreateEntry(transaction, entry_name, move(entry), dependencies)) {
64 // entry already exists!
65 if (on_conflict == OnCreateConflict::ERROR) {
66 throw CatalogException("%s with name \"%s\" already exists!", CatalogTypeToString(entry_type).c_str(),
67 entry_name.c_str());
68 } else {
69 return nullptr;
70 }
71 }
72 return result;
73}
74
75CatalogEntry *SchemaCatalogEntry::AddEntry(ClientContext &context, unique_ptr<StandardEntry> entry,
76 OnCreateConflict on_conflict) {
77 unordered_set<CatalogEntry *> dependencies;
78 return AddEntry(context, move(entry), on_conflict, dependencies);
79}
80
81CatalogEntry *SchemaCatalogEntry::CreateSequence(ClientContext &context, CreateSequenceInfo *info) {
82 auto sequence = make_unique<SequenceCatalogEntry>(catalog, this, info);
83 return AddEntry(context, move(sequence), info->on_conflict);
84}
85
86CatalogEntry *SchemaCatalogEntry::CreateTable(ClientContext &context, BoundCreateTableInfo *info) {
87 auto table = make_unique<TableCatalogEntry>(catalog, this, info);
88 return AddEntry(context, move(table), info->Base().on_conflict, info->dependencies);
89}
90
91CatalogEntry *SchemaCatalogEntry::CreateView(ClientContext &context, CreateViewInfo *info) {
92 auto view = make_unique<ViewCatalogEntry>(catalog, this, info);
93 return AddEntry(context, move(view), info->on_conflict);
94}
95
96CatalogEntry *SchemaCatalogEntry::CreateIndex(ClientContext &context, CreateIndexInfo *info) {
97 auto index = make_unique<IndexCatalogEntry>(catalog, this, info);
98 return AddEntry(context, move(index), info->on_conflict);
99}
100
101CatalogEntry *SchemaCatalogEntry::CreateCollation(ClientContext &context, CreateCollationInfo *info) {
102 auto collation = make_unique<CollateCatalogEntry>(catalog, this, info);
103 return AddEntry(context, move(collation), info->on_conflict);
104}
105
106CatalogEntry *SchemaCatalogEntry::CreateTableFunction(ClientContext &context, CreateTableFunctionInfo *info) {
107 auto table_function = make_unique<TableFunctionCatalogEntry>(catalog, this, info);
108 return AddEntry(context, move(table_function), info->on_conflict);
109}
110
111CatalogEntry *SchemaCatalogEntry::CreateFunction(ClientContext &context, CreateFunctionInfo *info) {
112 unique_ptr<StandardEntry> function;
113 if (info->type == CatalogType::SCALAR_FUNCTION) {
114 // create a scalar function
115 function = make_unique_base<StandardEntry, ScalarFunctionCatalogEntry>(catalog, this,
116 (CreateScalarFunctionInfo *)info);
117 } else {
118 assert(info->type == CatalogType::AGGREGATE_FUNCTION);
119 // create an aggregate function
120 function = make_unique_base<StandardEntry, AggregateFunctionCatalogEntry>(catalog, this,
121 (CreateAggregateFunctionInfo *)info);
122 }
123 return AddEntry(context, move(function), info->on_conflict);
124}
125
126void SchemaCatalogEntry::DropEntry(ClientContext &context, DropInfo *info) {
127 auto &set = GetCatalogSet(info->type);
128 auto &transaction = Transaction::GetTransaction(context);
129
130 // first find the entry
131 auto existing_entry = set.GetEntry(transaction, info->name);
132 if (!existing_entry) {
133 if (!info->if_exists) {
134 throw CatalogException("%s with name \"%s\" does not exist!", CatalogTypeToString(info->type).c_str(),
135 info->name.c_str());
136 }
137 return;
138 }
139 if (existing_entry->type != info->type) {
140 throw CatalogException("Existing object %s is of type %s, trying to replace with type %s", info->name.c_str(),
141 CatalogTypeToString(existing_entry->type).c_str(),
142 CatalogTypeToString(info->type).c_str());
143 }
144 if (!set.DropEntry(transaction, info->name, info->cascade)) {
145 throw InternalException("Could not drop element because of an internal error");
146 }
147}
148
149void SchemaCatalogEntry::AlterTable(ClientContext &context, AlterTableInfo *info) {
150 switch (info->alter_table_type) {
151 case AlterTableType::RENAME_TABLE: {
152 auto &transaction = Transaction::GetTransaction(context);
153 auto entry = tables.GetEntry(transaction, info->table);
154 if (entry == nullptr) {
155 throw CatalogException("Table \"%s\" doesn't exist!", info->table.c_str());
156 }
157 assert(entry->type == CatalogType::TABLE);
158
159 auto copied_entry = entry->Copy(context);
160
161 // Drop the old table entry
162 if (!tables.DropEntry(transaction, info->table, false)) {
163 throw CatalogException("Could not drop \"%s\" entry!", info->table.c_str());
164 }
165
166 // Create a new table entry
167 auto &new_table = ((RenameTableInfo *)info)->new_table_name;
168 unordered_set<CatalogEntry *> dependencies;
169 copied_entry->name = new_table;
170 if (!tables.CreateEntry(transaction, new_table, move(copied_entry), dependencies)) {
171 throw CatalogException("Could not create \"%s\" entry!", new_table.c_str());
172 }
173 break;
174 }
175 default:
176 if (!tables.AlterEntry(context, info->table, info)) {
177 throw CatalogException("Table with name \"%s\" does not exist!", info->table.c_str());
178 }
179 } // end switch
180}
181
182CatalogEntry *SchemaCatalogEntry::GetEntry(ClientContext &context, CatalogType type, const string &name,
183 bool if_exists) {
184 auto &set = GetCatalogSet(type);
185 auto &transaction = Transaction::GetTransaction(context);
186
187 auto entry = set.GetEntry(transaction, name);
188 if (!entry) {
189 if (!if_exists) {
190 throw CatalogException("%s with name %s does not exist!", CatalogTypeToString(type).c_str(), name.c_str());
191 }
192 return nullptr;
193 }
194 return entry;
195}
196
197void SchemaCatalogEntry::Serialize(Serializer &serializer) {
198 serializer.WriteString(name);
199}
200
201unique_ptr<CreateSchemaInfo> SchemaCatalogEntry::Deserialize(Deserializer &source) {
202 auto info = make_unique<CreateSchemaInfo>();
203 info->schema = source.Read<string>();
204 return info;
205}
206
207CatalogSet &SchemaCatalogEntry::GetCatalogSet(CatalogType type) {
208 switch (type) {
209 case CatalogType::VIEW:
210 case CatalogType::TABLE:
211 return tables;
212 case CatalogType::INDEX:
213 return indexes;
214 case CatalogType::TABLE_FUNCTION:
215 return table_functions;
216 case CatalogType::AGGREGATE_FUNCTION:
217 case CatalogType::SCALAR_FUNCTION:
218 return functions;
219 case CatalogType::SEQUENCE:
220 return sequences;
221 case CatalogType::COLLATION:
222 return collations;
223 default:
224 throw CatalogException("Unsupported catalog type in schema");
225 }
226}
227