1 | #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" |
2 | |
3 | #include "duckdb/catalog/catalog.hpp" |
4 | #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" |
5 | #include "duckdb/common/exception.hpp" |
6 | #include "duckdb/common/serializer.hpp" |
7 | #include "duckdb/main/connection.hpp" |
8 | #include "duckdb/main/database.hpp" |
9 | #include "duckdb/parser/constraints/list.hpp" |
10 | #include "duckdb/parser/parsed_data/alter_table_info.hpp" |
11 | #include "duckdb/planner/constraints/bound_not_null_constraint.hpp" |
12 | #include "duckdb/planner/constraints/bound_unique_constraint.hpp" |
13 | #include "duckdb/planner/constraints/bound_check_constraint.hpp" |
14 | #include "duckdb/planner/expression/bound_constant_expression.hpp" |
15 | #include "duckdb/planner/parsed_data/bound_create_table_info.hpp" |
16 | #include "duckdb/storage/storage_manager.hpp" |
17 | #include "duckdb/planner/binder.hpp" |
18 | |
19 | #include "duckdb/execution/index/art/art.hpp" |
20 | #include "duckdb/parser/expression/columnref_expression.hpp" |
21 | #include "duckdb/planner/expression/bound_reference_expression.hpp" |
22 | #include "duckdb/parser/parsed_expression_iterator.hpp" |
23 | #include "duckdb/planner/expression_binder/alter_binder.hpp" |
24 | |
25 | #include <algorithm> |
26 | |
27 | using namespace duckdb; |
28 | using namespace std; |
29 | |
30 | TableCatalogEntry::TableCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, BoundCreateTableInfo *info, |
31 | std::shared_ptr<DataTable> inherited_storage) |
32 | : StandardEntry(CatalogType::TABLE, schema, catalog, info->Base().table), storage(inherited_storage), |
33 | columns(move(info->Base().columns)), constraints(move(info->Base().constraints)), |
34 | bound_constraints(move(info->bound_constraints)), name_map(info->name_map) { |
35 | this->temporary = info->Base().temporary; |
36 | // add the "rowid" alias, if there is no rowid column specified in the table |
37 | if (name_map.find("rowid" ) == name_map.end()) { |
38 | name_map["rowid" ] = COLUMN_IDENTIFIER_ROW_ID; |
39 | } |
40 | if (!storage) { |
41 | // create the physical storage |
42 | storage = make_shared<DataTable>(catalog->storage, schema->name, name, GetTypes(), move(info->data)); |
43 | |
44 | // create the unique indexes for the UNIQUE and PRIMARY KEY constraints |
45 | for (idx_t i = 0; i < bound_constraints.size(); i++) { |
46 | auto &constraint = bound_constraints[i]; |
47 | if (constraint->type == ConstraintType::UNIQUE) { |
48 | // unique constraint: create a unique index |
49 | auto &unique = (BoundUniqueConstraint &)*constraint; |
50 | // fetch types and create expressions for the index from the columns |
51 | vector<column_t> column_ids; |
52 | vector<unique_ptr<Expression>> unbound_expressions; |
53 | vector<unique_ptr<Expression>> bound_expressions; |
54 | idx_t key_nr = 0; |
55 | for (auto &key : unique.keys) { |
56 | TypeId column_type = GetInternalType(columns[key].type); |
57 | assert(key < columns.size()); |
58 | |
59 | unbound_expressions.push_back( |
60 | make_unique<BoundColumnRefExpression>(column_type, ColumnBinding(0, column_ids.size()))); |
61 | bound_expressions.push_back(make_unique<BoundReferenceExpression>(column_type, key_nr++)); |
62 | column_ids.push_back(key); |
63 | } |
64 | // create an adaptive radix tree around the expressions |
65 | auto art = make_unique<ART>(column_ids, move(unbound_expressions), true); |
66 | storage->AddIndex(move(art), bound_expressions); |
67 | } |
68 | } |
69 | } |
70 | } |
71 | |
72 | bool TableCatalogEntry::ColumnExists(const string &name) { |
73 | return name_map.find(name) != name_map.end(); |
74 | } |
75 | |
76 | unique_ptr<CatalogEntry> TableCatalogEntry::AlterEntry(ClientContext &context, AlterInfo *info) { |
77 | if (info->type != AlterType::ALTER_TABLE) { |
78 | throw CatalogException("Can only modify table with ALTER TABLE statement" ); |
79 | } |
80 | auto table_info = (AlterTableInfo *)info; |
81 | switch (table_info->alter_table_type) { |
82 | case AlterTableType::RENAME_COLUMN: { |
83 | auto rename_info = (RenameColumnInfo *)table_info; |
84 | return RenameColumn(context, *rename_info); |
85 | } |
86 | case AlterTableType::RENAME_TABLE: { |
87 | auto rename_info = (RenameTableInfo *)table_info; |
88 | auto copied_table = Copy(context); |
89 | copied_table->name = rename_info->new_table_name; |
90 | return copied_table; |
91 | } |
92 | case AlterTableType::ADD_COLUMN: { |
93 | auto add_info = (AddColumnInfo *)table_info; |
94 | return AddColumn(context, *add_info); |
95 | } |
96 | case AlterTableType::REMOVE_COLUMN: { |
97 | auto remove_info = (RemoveColumnInfo *)table_info; |
98 | return RemoveColumn(context, *remove_info); |
99 | } |
100 | case AlterTableType::SET_DEFAULT: { |
101 | auto set_default_info = (SetDefaultInfo *)table_info; |
102 | return SetDefault(context, *set_default_info); |
103 | } |
104 | case AlterTableType::ALTER_COLUMN_TYPE: { |
105 | auto change_type_info = (ChangeColumnTypeInfo *)table_info; |
106 | return ChangeColumnType(context, *change_type_info); |
107 | } |
108 | default: |
109 | throw InternalException("Unrecognized alter table type!" ); |
110 | } |
111 | } |
112 | |
113 | static void RenameExpression(ParsedExpression &expr, RenameColumnInfo &info) { |
114 | if (expr.type == ExpressionType::COLUMN_REF) { |
115 | auto &colref = (ColumnRefExpression &)expr; |
116 | if (colref.column_name == info.name) { |
117 | colref.column_name = info.new_name; |
118 | } |
119 | } |
120 | ParsedExpressionIterator::EnumerateChildren( |
121 | expr, [&](const ParsedExpression &child) { RenameExpression((ParsedExpression &)child, info); }); |
122 | } |
123 | |
124 | unique_ptr<CatalogEntry> TableCatalogEntry::RenameColumn(ClientContext &context, RenameColumnInfo &info) { |
125 | auto create_info = make_unique<CreateTableInfo>(schema->name, name); |
126 | create_info->temporary = temporary; |
127 | bool found = false; |
128 | for (idx_t i = 0; i < columns.size(); i++) { |
129 | ColumnDefinition copy = columns[i].Copy(); |
130 | |
131 | create_info->columns.push_back(move(copy)); |
132 | if (info.name == columns[i].name) { |
133 | assert(!found); |
134 | create_info->columns[i].name = info.new_name; |
135 | found = true; |
136 | } |
137 | } |
138 | if (!found) { |
139 | throw CatalogException("Table does not have a column with name \"%s\"" , info.name.c_str()); |
140 | } |
141 | for (idx_t c_idx = 0; c_idx < constraints.size(); c_idx++) { |
142 | auto copy = constraints[c_idx]->Copy(); |
143 | switch (copy->type) { |
144 | case ConstraintType::NOT_NULL: |
145 | // NOT NULL constraint: no adjustments necessary |
146 | break; |
147 | case ConstraintType::CHECK: { |
148 | // CHECK constraint: need to rename column references that refer to the renamed column |
149 | auto &check = (CheckConstraint &)*copy; |
150 | RenameExpression(*check.expression, info); |
151 | break; |
152 | } |
153 | case ConstraintType::UNIQUE: { |
154 | // UNIQUE constraint: possibly need to rename columns |
155 | auto &unique = (UniqueConstraint &)*copy; |
156 | for (idx_t i = 0; i < unique.columns.size(); i++) { |
157 | if (unique.columns[i] == info.name) { |
158 | unique.columns[i] = info.new_name; |
159 | } |
160 | } |
161 | break; |
162 | } |
163 | default: |
164 | throw CatalogException("Unsupported constraint for entry!" ); |
165 | } |
166 | create_info->constraints.push_back(move(copy)); |
167 | } |
168 | Binder binder(context); |
169 | auto bound_create_info = binder.BindCreateTableInfo(move(create_info)); |
170 | return make_unique<TableCatalogEntry>(catalog, schema, (BoundCreateTableInfo *)bound_create_info.get(), storage); |
171 | } |
172 | |
173 | unique_ptr<CatalogEntry> TableCatalogEntry::AddColumn(ClientContext &context, AddColumnInfo &info) { |
174 | auto create_info = make_unique<CreateTableInfo>(schema->name, name); |
175 | create_info->temporary = temporary; |
176 | for (idx_t i = 0; i < columns.size(); i++) { |
177 | create_info->columns.push_back(columns[i].Copy()); |
178 | } |
179 | info.new_column.oid = columns.size(); |
180 | create_info->columns.push_back(info.new_column.Copy()); |
181 | |
182 | Binder binder(context); |
183 | auto bound_create_info = binder.BindCreateTableInfo(move(create_info)); |
184 | auto new_storage = |
185 | make_shared<DataTable>(context, *storage, info.new_column, bound_create_info->bound_defaults.back().get()); |
186 | return make_unique<TableCatalogEntry>(catalog, schema, (BoundCreateTableInfo *)bound_create_info.get(), |
187 | new_storage); |
188 | } |
189 | |
190 | unique_ptr<CatalogEntry> TableCatalogEntry::RemoveColumn(ClientContext &context, RemoveColumnInfo &info) { |
191 | idx_t removed_index = INVALID_INDEX; |
192 | auto create_info = make_unique<CreateTableInfo>(schema->name, name); |
193 | create_info->temporary = temporary; |
194 | for (idx_t i = 0; i < columns.size(); i++) { |
195 | if (columns[i].name == info.removed_column) { |
196 | assert(removed_index == INVALID_INDEX); |
197 | removed_index = i; |
198 | continue; |
199 | } |
200 | create_info->columns.push_back(columns[i].Copy()); |
201 | } |
202 | if (removed_index == INVALID_INDEX) { |
203 | if (!info.if_exists) { |
204 | throw CatalogException("Table does not have a column with name \"%s\"" , info.removed_column.c_str()); |
205 | } |
206 | return nullptr; |
207 | } |
208 | if (create_info->columns.size() == 0) { |
209 | throw CatalogException("Cannot drop column: table only has one column remaining!" ); |
210 | } |
211 | // handle constraints for the new table |
212 | assert(constraints.size() == bound_constraints.size()); |
213 | for (idx_t constr_idx = 0; constr_idx < constraints.size(); constr_idx++) { |
214 | auto &constraint = constraints[constr_idx]; |
215 | auto &bound_constraint = bound_constraints[constr_idx]; |
216 | switch (bound_constraint->type) { |
217 | case ConstraintType::NOT_NULL: { |
218 | auto ¬_null_constraint = (BoundNotNullConstraint &)*bound_constraint; |
219 | if (not_null_constraint.index != removed_index) { |
220 | // the constraint is not about this column: we need to copy it |
221 | // we might need to shift the index back by one though, to account for the removed column |
222 | idx_t new_index = not_null_constraint.index; |
223 | if (not_null_constraint.index > removed_index) { |
224 | new_index -= 1; |
225 | } |
226 | create_info->constraints.push_back(make_unique<NotNullConstraint>(new_index)); |
227 | } |
228 | break; |
229 | } |
230 | case ConstraintType::CHECK: { |
231 | // CHECK constraint |
232 | auto &bound_check = (BoundCheckConstraint &)*bound_constraint; |
233 | // check if the removed column is part of the check constraint |
234 | if (bound_check.bound_columns.find(removed_index) != bound_check.bound_columns.end()) { |
235 | if (bound_check.bound_columns.size() > 1) { |
236 | // CHECK constraint that concerns mult |
237 | throw CatalogException( |
238 | "Cannot drop column \"%s\" because there is a CHECK constraint that depends on it" , |
239 | info.removed_column.c_str()); |
240 | } else { |
241 | // CHECK constraint that ONLY concerns this column, strip the constraint |
242 | } |
243 | } else { |
244 | // check constraint does not concern the removed column: simply re-add it |
245 | create_info->constraints.push_back(constraint->Copy()); |
246 | } |
247 | break; |
248 | } |
249 | case ConstraintType::UNIQUE: { |
250 | auto copy = constraint->Copy(); |
251 | auto &unique = (UniqueConstraint &) *copy; |
252 | if (unique.index != INVALID_INDEX) { |
253 | if (unique.index == removed_index) { |
254 | throw CatalogException( |
255 | "Cannot drop column \"%s\" because there is a UNIQUE constraint that depends on it" , |
256 | info.removed_column.c_str()); |
257 | } else if (unique.index > removed_index) { |
258 | unique.index--; |
259 | } |
260 | } |
261 | create_info->constraints.push_back(move(copy)); |
262 | break; |
263 | } |
264 | default: |
265 | throw InternalException("Unsupported constraint for entry!" ); |
266 | } |
267 | } |
268 | |
269 | Binder binder(context); |
270 | auto bound_create_info = binder.BindCreateTableInfo(move(create_info)); |
271 | auto new_storage = make_shared<DataTable>(context, *storage, removed_index); |
272 | return make_unique<TableCatalogEntry>(catalog, schema, (BoundCreateTableInfo *)bound_create_info.get(), |
273 | new_storage); |
274 | } |
275 | |
276 | unique_ptr<CatalogEntry> TableCatalogEntry::SetDefault(ClientContext &context, SetDefaultInfo &info) { |
277 | auto create_info = make_unique<CreateTableInfo>(schema->name, name); |
278 | bool found = false; |
279 | for (idx_t i = 0; i < columns.size(); i++) { |
280 | auto copy = columns[i].Copy(); |
281 | if (info.column_name == copy.name) { |
282 | // set the default value of this column |
283 | copy.default_value = info.expression ? info.expression->Copy() : nullptr; |
284 | found = true; |
285 | } |
286 | create_info->columns.push_back(move(copy)); |
287 | } |
288 | if (!found) { |
289 | throw BinderException("Table \"%s\" does not have a column with name \"%s\"" , info.table.c_str(), |
290 | info.column_name.c_str()); |
291 | } |
292 | |
293 | for (idx_t i = 0; i < constraints.size(); i++) { |
294 | auto constraint = constraints[i]->Copy(); |
295 | create_info->constraints.push_back(move(constraint)); |
296 | } |
297 | |
298 | Binder binder(context); |
299 | auto bound_create_info = binder.BindCreateTableInfo(move(create_info)); |
300 | return make_unique<TableCatalogEntry>(catalog, schema, (BoundCreateTableInfo *)bound_create_info.get(), storage); |
301 | } |
302 | |
303 | unique_ptr<CatalogEntry> TableCatalogEntry::ChangeColumnType(ClientContext &context, ChangeColumnTypeInfo &info) { |
304 | auto create_info = make_unique<CreateTableInfo>(schema->name, name); |
305 | idx_t change_idx = INVALID_INDEX; |
306 | for (idx_t i = 0; i < columns.size(); i++) { |
307 | auto copy = columns[i].Copy(); |
308 | if (info.column_name == copy.name) { |
309 | // set the default value of this column |
310 | change_idx = i; |
311 | copy.type = info.target_type; |
312 | } |
313 | create_info->columns.push_back(move(copy)); |
314 | } |
315 | if (change_idx == INVALID_INDEX) { |
316 | throw BinderException("Table \"%s\" does not have a column with name \"%s\"" , info.table.c_str(), |
317 | info.column_name.c_str()); |
318 | } |
319 | |
320 | for (idx_t i = 0; i < constraints.size(); i++) { |
321 | auto constraint = constraints[i]->Copy(); |
322 | switch (constraint->type) { |
323 | case ConstraintType::CHECK: { |
324 | auto &bound_check = (BoundCheckConstraint &)*bound_constraints[i]; |
325 | if (bound_check.bound_columns.find(change_idx) != bound_check.bound_columns.end()) { |
326 | throw BinderException("Cannot change the type of a column that has a CHECK constraint specified" ); |
327 | } |
328 | break; |
329 | } |
330 | case ConstraintType::NOT_NULL: |
331 | break; |
332 | case ConstraintType::UNIQUE: { |
333 | auto &bound_unique = (BoundUniqueConstraint &)*bound_constraints[i]; |
334 | if (bound_unique.keys.find(change_idx) != bound_unique.keys.end()) { |
335 | throw BinderException( |
336 | "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY constraint specified" ); |
337 | } |
338 | break; |
339 | } |
340 | default: |
341 | throw InternalException("Unsupported constraint for entry!" ); |
342 | } |
343 | create_info->constraints.push_back(move(constraint)); |
344 | } |
345 | |
346 | Binder binder(context); |
347 | // bind the specified expression |
348 | vector<column_t> bound_columns; |
349 | AlterBinder expr_binder(binder, context, name, columns, bound_columns, info.target_type); |
350 | auto expression = info.expression->Copy(); |
351 | auto bound_expression = expr_binder.Bind(expression); |
352 | auto bound_create_info = binder.BindCreateTableInfo(move(create_info)); |
353 | if (bound_columns.size() == 0) { |
354 | bound_columns.push_back(COLUMN_IDENTIFIER_ROW_ID); |
355 | } |
356 | |
357 | auto new_storage = |
358 | make_shared<DataTable>(context, *storage, change_idx, info.target_type, move(bound_columns), *bound_expression); |
359 | return make_unique<TableCatalogEntry>(catalog, schema, (BoundCreateTableInfo *)bound_create_info.get(), |
360 | new_storage); |
361 | } |
362 | |
363 | ColumnDefinition &TableCatalogEntry::GetColumn(const string &name) { |
364 | auto entry = name_map.find(name); |
365 | if (entry == name_map.end() || entry->second == COLUMN_IDENTIFIER_ROW_ID) { |
366 | throw CatalogException("Column with name %s does not exist!" , name.c_str()); |
367 | } |
368 | return columns[entry->second]; |
369 | } |
370 | |
371 | vector<TypeId> TableCatalogEntry::GetTypes() { |
372 | vector<TypeId> types; |
373 | for (auto &it : columns) { |
374 | types.push_back(GetInternalType(it.type)); |
375 | } |
376 | return types; |
377 | } |
378 | |
379 | vector<TypeId> TableCatalogEntry::GetTypes(const vector<column_t> &column_ids) { |
380 | vector<TypeId> result; |
381 | for (auto &index : column_ids) { |
382 | if (index == COLUMN_IDENTIFIER_ROW_ID) { |
383 | result.push_back(TypeId::INT64); |
384 | } else { |
385 | result.push_back(GetInternalType(columns[index].type)); |
386 | } |
387 | } |
388 | return result; |
389 | } |
390 | |
391 | void TableCatalogEntry::Serialize(Serializer &serializer) { |
392 | serializer.WriteString(schema->name); |
393 | serializer.WriteString(name); |
394 | assert(columns.size() <= std::numeric_limits<uint32_t>::max()); |
395 | serializer.Write<uint32_t>((uint32_t)columns.size()); |
396 | for (auto &column : columns) { |
397 | column.Serialize(serializer); |
398 | } |
399 | assert(constraints.size() <= std::numeric_limits<uint32_t>::max()); |
400 | serializer.Write<uint32_t>((uint32_t)constraints.size()); |
401 | for (auto &constraint : constraints) { |
402 | constraint->Serialize(serializer); |
403 | } |
404 | } |
405 | |
406 | unique_ptr<CreateTableInfo> TableCatalogEntry::Deserialize(Deserializer &source) { |
407 | auto info = make_unique<CreateTableInfo>(); |
408 | |
409 | info->schema = source.Read<string>(); |
410 | info->table = source.Read<string>(); |
411 | auto column_count = source.Read<uint32_t>(); |
412 | |
413 | for (uint32_t i = 0; i < column_count; i++) { |
414 | auto column = ColumnDefinition::Deserialize(source); |
415 | info->columns.push_back(move(column)); |
416 | } |
417 | auto constraint_count = source.Read<uint32_t>(); |
418 | |
419 | for (uint32_t i = 0; i < constraint_count; i++) { |
420 | auto constraint = Constraint::Deserialize(source); |
421 | info->constraints.push_back(move(constraint)); |
422 | } |
423 | return info; |
424 | } |
425 | |
426 | unique_ptr<CatalogEntry> TableCatalogEntry::Copy(ClientContext &context) { |
427 | auto create_info = make_unique<CreateTableInfo>(schema->name, name); |
428 | for (idx_t i = 0; i < columns.size(); i++) { |
429 | create_info->columns.push_back(columns[i].Copy()); |
430 | } |
431 | |
432 | for (idx_t i = 0; i < constraints.size(); i++) { |
433 | auto constraint = constraints[i]->Copy(); |
434 | create_info->constraints.push_back(move(constraint)); |
435 | } |
436 | |
437 | Binder binder(context); |
438 | auto bound_create_info = binder.BindCreateTableInfo(move(create_info)); |
439 | return make_unique<TableCatalogEntry>(catalog, schema, (BoundCreateTableInfo *)bound_create_info.get(), storage); |
440 | } |
441 | |
442 | void TableCatalogEntry::SetAsRoot() { |
443 | storage->SetAsRoot(); |
444 | } |
445 | |