1#include "duckdb/parser/constraints/list.hpp"
2#include "duckdb/parser/expression/cast_expression.hpp"
3#include "duckdb/planner/binder.hpp"
4#include "duckdb/planner/constraints/list.hpp"
5#include "duckdb/planner/expression/bound_constant_expression.hpp"
6#include "duckdb/planner/expression/bound_function_expression.hpp"
7#include "duckdb/planner/expression_binder/check_binder.hpp"
8#include "duckdb/planner/expression_binder/constant_binder.hpp"
9#include "duckdb/planner/parsed_data/bound_create_table_info.hpp"
10#include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp"
11#include "duckdb/catalog/dependency_manager.hpp"
12#include "duckdb/function/table/table_scan.hpp"
13#include "duckdb/planner/operator/logical_get.hpp"
14#include "duckdb/parser/parsed_expression_iterator.hpp"
15#include "duckdb/common/string.hpp"
16#include "duckdb/common/queue.hpp"
17#include "duckdb/parser/expression/list.hpp"
18#include "duckdb/common/index_map.hpp"
19#include "duckdb/planner/expression_iterator.hpp"
20#include "duckdb/planner/expression_binder/index_binder.hpp"
21#include "duckdb/parser/parsed_data/create_index_info.hpp"
22
23#include <algorithm>
24
25namespace duckdb {
26
27static void CreateColumnDependencyManager(BoundCreateTableInfo &info) {
28 auto &base = info.base->Cast<CreateTableInfo>();
29 for (auto &col : base.columns.Logical()) {
30 if (!col.Generated()) {
31 continue;
32 }
33 info.column_dependency_manager.AddGeneratedColumn(column: col, list: base.columns);
34 }
35}
36
37static void BindCheckConstraint(Binder &binder, BoundCreateTableInfo &info, const unique_ptr<Constraint> &cond) {
38 auto &base = info.base->Cast<CreateTableInfo>();
39
40 auto bound_constraint = make_uniq<BoundCheckConstraint>();
41 // check constraint: bind the expression
42 CheckBinder check_binder(binder, binder.context, base.table, base.columns, bound_constraint->bound_columns);
43 auto &check = cond->Cast<CheckConstraint>();
44 // create a copy of the unbound expression because the binding destroys the constraint
45 auto unbound_expression = check.expression->Copy();
46 // now bind the constraint and create a new BoundCheckConstraint
47 bound_constraint->expression = check_binder.Bind(expr&: check.expression);
48 info.bound_constraints.push_back(x: std::move(bound_constraint));
49 // move the unbound constraint back into the original check expression
50 check.expression = std::move(unbound_expression);
51}
52
53static void BindConstraints(Binder &binder, BoundCreateTableInfo &info) {
54 auto &base = info.base->Cast<CreateTableInfo>();
55
56 bool has_primary_key = false;
57 logical_index_set_t not_null_columns;
58 vector<LogicalIndex> primary_keys;
59 for (idx_t i = 0; i < base.constraints.size(); i++) {
60 auto &cond = base.constraints[i];
61 switch (cond->type) {
62 case ConstraintType::CHECK: {
63 BindCheckConstraint(binder, info, cond);
64 break;
65 }
66 case ConstraintType::NOT_NULL: {
67 auto &not_null = cond->Cast<NotNullConstraint>();
68 auto &col = base.columns.GetColumn(index: LogicalIndex(not_null.index));
69 info.bound_constraints.push_back(x: make_uniq<BoundNotNullConstraint>(args: PhysicalIndex(col.StorageOid())));
70 not_null_columns.insert(x: not_null.index);
71 break;
72 }
73 case ConstraintType::UNIQUE: {
74 auto &unique = cond->Cast<UniqueConstraint>();
75 // have to resolve columns of the unique constraint
76 vector<LogicalIndex> keys;
77 logical_index_set_t key_set;
78 if (unique.index.index != DConstants::INVALID_INDEX) {
79 D_ASSERT(unique.index.index < base.columns.LogicalColumnCount());
80 // unique constraint is given by single index
81 unique.columns.push_back(x: base.columns.GetColumn(index: unique.index).Name());
82 keys.push_back(x: unique.index);
83 key_set.insert(x: unique.index);
84 } else {
85 // unique constraint is given by list of names
86 // have to resolve names
87 D_ASSERT(!unique.columns.empty());
88 for (auto &keyname : unique.columns) {
89 if (!base.columns.ColumnExists(name: keyname)) {
90 throw ParserException("column \"%s\" named in key does not exist", keyname);
91 }
92 auto &column = base.columns.GetColumn(name: keyname);
93 auto column_index = column.Logical();
94 if (key_set.find(x: column_index) != key_set.end()) {
95 throw ParserException("column \"%s\" appears twice in "
96 "primary key constraint",
97 keyname);
98 }
99 keys.push_back(x: column_index);
100 key_set.insert(x: column_index);
101 }
102 }
103
104 if (unique.is_primary_key) {
105 // we can only have one primary key per table
106 if (has_primary_key) {
107 throw ParserException("table \"%s\" has more than one primary key", base.table);
108 }
109 has_primary_key = true;
110 primary_keys = keys;
111 }
112 info.bound_constraints.push_back(
113 x: make_uniq<BoundUniqueConstraint>(args: std::move(keys), args: std::move(key_set), args&: unique.is_primary_key));
114 break;
115 }
116 case ConstraintType::FOREIGN_KEY: {
117 auto &fk = cond->Cast<ForeignKeyConstraint>();
118 D_ASSERT((fk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE && !fk.info.pk_keys.empty()) ||
119 (fk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE && !fk.info.pk_keys.empty()) ||
120 fk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE);
121 physical_index_set_t fk_key_set, pk_key_set;
122 for (idx_t i = 0; i < fk.info.pk_keys.size(); i++) {
123 if (pk_key_set.find(x: fk.info.pk_keys[i]) != pk_key_set.end()) {
124 throw BinderException("Duplicate primary key referenced in FOREIGN KEY constraint");
125 }
126 pk_key_set.insert(x: fk.info.pk_keys[i]);
127 }
128 for (idx_t i = 0; i < fk.info.fk_keys.size(); i++) {
129 if (fk_key_set.find(x: fk.info.fk_keys[i]) != fk_key_set.end()) {
130 throw BinderException("Duplicate key specified in FOREIGN KEY constraint");
131 }
132 fk_key_set.insert(x: fk.info.fk_keys[i]);
133 }
134 info.bound_constraints.push_back(
135 x: make_uniq<BoundForeignKeyConstraint>(args&: fk.info, args: std::move(pk_key_set), args: std::move(fk_key_set)));
136 break;
137 }
138 default:
139 throw NotImplementedException("unrecognized constraint type in bind");
140 }
141 }
142 if (has_primary_key) {
143 // if there is a primary key index, also create a NOT NULL constraint for each of the columns
144 for (auto &column_index : primary_keys) {
145 if (not_null_columns.count(x: column_index)) {
146 //! No need to create a NotNullConstraint, it's already present
147 continue;
148 }
149 auto physical_index = base.columns.LogicalToPhysical(index: column_index);
150 base.constraints.push_back(x: make_uniq<NotNullConstraint>(args&: column_index));
151 info.bound_constraints.push_back(x: make_uniq<BoundNotNullConstraint>(args&: physical_index));
152 }
153 }
154}
155
156void Binder::BindGeneratedColumns(BoundCreateTableInfo &info) {
157 auto &base = info.base->Cast<CreateTableInfo>();
158
159 vector<string> names;
160 vector<LogicalType> types;
161
162 D_ASSERT(base.type == CatalogType::TABLE_ENTRY);
163 for (auto &col : base.columns.Logical()) {
164 names.push_back(x: col.Name());
165 types.push_back(x: col.Type());
166 }
167 auto table_index = GenerateTableIndex();
168
169 // Create a new binder because we dont need (or want) these bindings in this scope
170 auto binder = Binder::CreateBinder(context);
171 binder->bind_context.AddGenericBinding(index: table_index, alias: base.table, names, types);
172 auto expr_binder = ExpressionBinder(*binder, context);
173 string ignore;
174 auto table_binding = binder->bind_context.GetBinding(name: base.table, out_error&: ignore);
175 D_ASSERT(table_binding && ignore.empty());
176
177 auto bind_order = info.column_dependency_manager.GetBindOrder(columns: base.columns);
178 logical_index_set_t bound_indices;
179
180 while (!bind_order.empty()) {
181 auto i = bind_order.top();
182 bind_order.pop();
183 auto &col = base.columns.GetColumnMutable(index: i);
184
185 //! Already bound this previously
186 //! This can not be optimized out of the GetBindOrder function
187 //! These occurrences happen because we need to make sure that ALL dependencies of a column are resolved before
188 //! it gets resolved
189 if (bound_indices.count(x: i)) {
190 continue;
191 }
192 D_ASSERT(col.Generated());
193 auto expression = col.GeneratedExpression().Copy();
194
195 auto bound_expression = expr_binder.Bind(expr&: expression);
196 D_ASSERT(bound_expression);
197 D_ASSERT(!bound_expression->HasSubquery());
198 if (col.Type().id() == LogicalTypeId::ANY) {
199 // Do this before changing the type, so we know it's the first time the type is set
200 col.ChangeGeneratedExpressionType(type: bound_expression->return_type);
201 col.SetType(bound_expression->return_type);
202
203 // Update the type in the binding, for future expansions
204 string ignore;
205 table_binding->types[i.index] = col.Type();
206 }
207 bound_indices.insert(x: i);
208 }
209}
210
211void Binder::BindDefaultValues(const ColumnList &columns, vector<unique_ptr<Expression>> &bound_defaults) {
212 for (auto &column : columns.Physical()) {
213 unique_ptr<Expression> bound_default;
214 if (column.DefaultValue()) {
215 // we bind a copy of the DEFAULT value because binding is destructive
216 // and we want to keep the original expression around for serialization
217 auto default_copy = column.DefaultValue()->Copy();
218 ConstantBinder default_binder(*this, context, "DEFAULT value");
219 default_binder.target_type = column.Type();
220 bound_default = default_binder.Bind(expr&: default_copy);
221 } else {
222 // no default value specified: push a default value of constant null
223 bound_default = make_uniq<BoundConstantExpression>(args: Value(column.Type()));
224 }
225 bound_defaults.push_back(x: std::move(bound_default));
226 }
227}
228
229static void ExtractExpressionDependencies(Expression &expr, DependencyList &dependencies) {
230 if (expr.type == ExpressionType::BOUND_FUNCTION) {
231 auto &function = expr.Cast<BoundFunctionExpression>();
232 if (function.function.dependency) {
233 function.function.dependency(function, dependencies);
234 }
235 }
236 ExpressionIterator::EnumerateChildren(
237 expression&: expr, callback: [&](Expression &child) { ExtractExpressionDependencies(expr&: child, dependencies); });
238}
239
240static void ExtractDependencies(BoundCreateTableInfo &info) {
241 for (auto &default_value : info.bound_defaults) {
242 if (default_value) {
243 ExtractExpressionDependencies(expr&: *default_value, dependencies&: info.dependencies);
244 }
245 }
246 for (auto &constraint : info.bound_constraints) {
247 if (constraint->type == ConstraintType::CHECK) {
248 auto &bound_check = constraint->Cast<BoundCheckConstraint>();
249 ExtractExpressionDependencies(expr&: *bound_check.expression, dependencies&: info.dependencies);
250 }
251 }
252}
253unique_ptr<BoundCreateTableInfo> Binder::BindCreateTableInfo(unique_ptr<CreateInfo> info, SchemaCatalogEntry &schema) {
254 auto &base = info->Cast<CreateTableInfo>();
255 auto result = make_uniq<BoundCreateTableInfo>(args&: schema, args: std::move(info));
256 if (base.query) {
257 // construct the result object
258 auto query_obj = Bind(stmt&: *base.query);
259 base.query.reset();
260 result->query = std::move(query_obj.plan);
261
262 // construct the set of columns based on the names and types of the query
263 auto &names = query_obj.names;
264 auto &sql_types = query_obj.types;
265 D_ASSERT(names.size() == sql_types.size());
266 base.columns.SetAllowDuplicates(true);
267 for (idx_t i = 0; i < names.size(); i++) {
268 base.columns.AddColumn(column: ColumnDefinition(names[i], sql_types[i]));
269 }
270 CreateColumnDependencyManager(info&: *result);
271 // bind the generated column expressions
272 BindGeneratedColumns(info&: *result);
273 } else {
274 CreateColumnDependencyManager(info&: *result);
275 // bind the generated column expressions
276 BindGeneratedColumns(info&: *result);
277 // bind any constraints
278 BindConstraints(binder&: *this, info&: *result);
279 // bind the default values
280 BindDefaultValues(columns: base.columns, bound_defaults&: result->bound_defaults);
281 }
282 // extract dependencies from any default values or CHECK constraints
283 ExtractDependencies(info&: *result);
284
285 if (base.columns.PhysicalColumnCount() == 0) {
286 throw BinderException("Creating a table without physical (non-generated) columns is not supported");
287 }
288 // bind collations to detect any unsupported collation errors
289 for (idx_t i = 0; i < base.columns.PhysicalColumnCount(); i++) {
290 auto &column = base.columns.GetColumnMutable(index: PhysicalIndex(i));
291 if (column.Type().id() == LogicalTypeId::VARCHAR) {
292 ExpressionBinder::TestCollation(context, collation: StringType::GetCollation(type: column.Type()));
293 }
294 BindLogicalType(context, type&: column.TypeMutable(), catalog: &result->schema.catalog);
295 // We add a catalog dependency
296 auto type_dependency = EnumType::GetCatalog(type: column.Type());
297
298 if (type_dependency) {
299 // Only if the USER comes from a create type
300 if (!schema.catalog.IsTemporaryCatalog()) {
301 // If it is not a TEMP table we add a dependency
302 result->dependencies.AddDependency(entry&: *type_dependency);
303 } else {
304 auto enum_type = type_dependency->user_type;
305 auto &enum_entries = EnumType::GetValuesInsertOrder(type: enum_type);
306 auto enum_size = EnumType::GetSize(type: enum_type);
307 Vector copy_enum_entries_vec(LogicalType::VARCHAR, enum_size);
308 auto copy_enum_entries_ptr = FlatVector::GetData<string_t>(vector&: copy_enum_entries_vec);
309 auto enum_entries_ptr = FlatVector::GetData<string_t>(vector: enum_entries);
310 for (idx_t enum_idx = 0; enum_idx < enum_size; enum_idx++) {
311 copy_enum_entries_ptr[enum_idx] =
312 StringVector::AddStringOrBlob(vector&: copy_enum_entries_vec, data: enum_entries_ptr[enum_idx]);
313 }
314 auto copy_type = LogicalType::ENUM(enum_name: EnumType::GetTypeName(type: enum_type), ordered_data&: copy_enum_entries_vec, size: enum_size);
315 column.SetType(copy_type);
316 }
317 }
318 }
319 result->dependencies.VerifyDependencies(catalog&: schema.catalog, name: result->Base().table);
320 properties.allow_stream_result = false;
321 return result;
322}
323
324unique_ptr<BoundCreateTableInfo> Binder::BindCreateTableInfo(unique_ptr<CreateInfo> info) {
325 auto &base = info->Cast<CreateTableInfo>();
326 auto &schema = BindCreateSchema(info&: base);
327 return BindCreateTableInfo(info: std::move(info), schema);
328}
329
330vector<unique_ptr<Expression>> Binder::BindCreateIndexExpressions(TableCatalogEntry &table, CreateIndexInfo &info) {
331 auto index_binder = IndexBinder(*this, this->context, &table, &info);
332 vector<unique_ptr<Expression>> expressions;
333 expressions.reserve(n: info.expressions.size());
334 for (auto &expr : info.expressions) {
335 expressions.push_back(x: index_binder.Bind(expr));
336 }
337
338 return expressions;
339}
340
341} // namespace duckdb
342