| 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 | |
| 25 | namespace duckdb { |
| 26 | |
| 27 | static 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 | |
| 37 | static 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 | |
| 53 | static 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 ¬_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 | |
| 156 | void 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 | |
| 211 | void 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 | |
| 229 | static void (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 | |
| 240 | static void (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 | } |
| 253 | unique_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 | |
| 324 | unique_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 | |
| 330 | vector<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 | |