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
27using namespace duckdb;
28using namespace std;
29
30TableCatalogEntry::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
72bool TableCatalogEntry::ColumnExists(const string &name) {
73 return name_map.find(name) != name_map.end();
74}
75
76unique_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
113static 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
124unique_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
173unique_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
190unique_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 &not_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
276unique_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
303unique_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
363ColumnDefinition &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
371vector<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
379vector<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
391void 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
406unique_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
426unique_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
442void TableCatalogEntry::SetAsRoot() {
443 storage->SetAsRoot();
444}
445