/src/duckdb/src/planner/binder/statement/bind_simple.cpp
Line | Count | Source |
1 | | #include "duckdb/catalog/catalog.hpp" |
2 | | #include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" |
3 | | #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" |
4 | | #include "duckdb/catalog/duck_catalog.hpp" |
5 | | #include "duckdb/execution/index/art/art.hpp" |
6 | | #include "duckdb/function/table/table_scan.hpp" |
7 | | #include "duckdb/parser/constraints/unique_constraint.hpp" |
8 | | #include "duckdb/parser/parsed_data/comment_on_column_info.hpp" |
9 | | #include "duckdb/parser/statement/alter_statement.hpp" |
10 | | #include "duckdb/parser/statement/transaction_statement.hpp" |
11 | | #include "duckdb/parser/tableref/basetableref.hpp" |
12 | | #include "duckdb/planner/binder.hpp" |
13 | | #include "duckdb/planner/constraints/bound_unique_constraint.hpp" |
14 | | #include "duckdb/planner/expression_binder/index_binder.hpp" |
15 | | #include "duckdb/planner/operator/logical_create_index.hpp" |
16 | | #include "duckdb/planner/operator/logical_get.hpp" |
17 | | #include "duckdb/planner/operator/logical_simple.hpp" |
18 | | |
19 | | namespace duckdb { |
20 | | |
21 | | unique_ptr<LogicalOperator> DuckCatalog::BindAlterAddIndex(Binder &binder, TableCatalogEntry &table_entry, |
22 | | unique_ptr<LogicalOperator> plan, |
23 | | unique_ptr<CreateIndexInfo> create_info, |
24 | 0 | unique_ptr<AlterTableInfo> alter_info) { |
25 | 0 | D_ASSERT(plan->type == LogicalOperatorType::LOGICAL_GET); |
26 | 0 | IndexBinder index_binder(binder, binder.context); |
27 | 0 | return index_binder.BindCreateIndex(binder.context, std::move(create_info), table_entry, std::move(plan), |
28 | 0 | std::move(alter_info)); |
29 | 0 | } |
30 | | |
31 | | BoundStatement Binder::BindAlterAddIndex(BoundStatement &result, CatalogEntry &entry, |
32 | 0 | unique_ptr<AlterInfo> alter_info) { |
33 | 0 | auto &table_info = alter_info->Cast<AlterTableInfo>(); |
34 | 0 | auto &constraint_info = table_info.Cast<AddConstraintInfo>(); |
35 | 0 | auto &table = entry.Cast<TableCatalogEntry>(); |
36 | 0 | auto &column_list = table.GetColumns(); |
37 | |
|
38 | 0 | auto bound_constraint = BindUniqueConstraint(*constraint_info.constraint, table_info.name, column_list); |
39 | 0 | auto &bound_unique = bound_constraint->Cast<BoundUniqueConstraint>(); |
40 | | |
41 | | // Create the CreateIndexInfo. |
42 | 0 | auto create_index_info = make_uniq<CreateIndexInfo>(); |
43 | 0 | create_index_info->table = table_info.name; |
44 | 0 | create_index_info->index_type = ART::TYPE_NAME; |
45 | 0 | create_index_info->constraint_type = IndexConstraintType::PRIMARY; |
46 | |
|
47 | 0 | for (const auto &physical_index : bound_unique.keys) { |
48 | 0 | auto &col = column_list.GetColumn(physical_index); |
49 | 0 | unique_ptr<ParsedExpression> parsed = make_uniq<ColumnRefExpression>(col.GetName(), table_info.name); |
50 | 0 | create_index_info->expressions.push_back(parsed->Copy()); |
51 | 0 | create_index_info->parsed_expressions.push_back(parsed->Copy()); |
52 | 0 | } |
53 | |
|
54 | 0 | auto unique_constraint = constraint_info.constraint->Cast<UniqueConstraint>(); |
55 | 0 | auto index_name = unique_constraint.GetName(table_info.name); |
56 | 0 | create_index_info->index_name = index_name; |
57 | 0 | D_ASSERT(!create_index_info->index_name.empty()); |
58 | | |
59 | | // Plan the table scan. |
60 | 0 | TableDescription table_description(table_info.catalog, table_info.schema, table_info.name); |
61 | 0 | auto table_ref = make_uniq<BaseTableRef>(table_description); |
62 | 0 | auto bound_table = Bind(*table_ref); |
63 | 0 | if (bound_table.plan->type != LogicalOperatorType::LOGICAL_GET) { |
64 | 0 | throw BinderException("can only add an index to a base table"); |
65 | 0 | } |
66 | 0 | auto &get = bound_table.plan->Cast<LogicalGet>(); |
67 | 0 | get.names = column_list.GetColumnNames(); |
68 | |
|
69 | 0 | auto alter_table_info = unique_ptr_cast<AlterInfo, AlterTableInfo>(std::move(alter_info)); |
70 | 0 | result.plan = table.catalog.BindAlterAddIndex(*this, table, std::move(bound_table.plan), |
71 | 0 | std::move(create_index_info), std::move(alter_table_info)); |
72 | 0 | return std::move(result); |
73 | 0 | } |
74 | | |
75 | 14 | BoundStatement Binder::Bind(AlterStatement &stmt) { |
76 | 14 | BoundStatement result; |
77 | 14 | result.names = {"Success"}; |
78 | 14 | result.types = {LogicalType::BOOLEAN}; |
79 | | |
80 | | // Special handling for ALTER DATABASE - doesn't use schema binding |
81 | 14 | if (stmt.info->type == AlterType::ALTER_DATABASE) { |
82 | 0 | auto &properties = GetStatementProperties(); |
83 | 0 | properties.return_type = StatementReturnType::NOTHING; |
84 | 0 | properties.RegisterDBModify(Catalog::GetSystemCatalog(context), context); |
85 | 0 | result.plan = make_uniq<LogicalSimple>(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); |
86 | 0 | return result; |
87 | 0 | } |
88 | | |
89 | 14 | BindSchemaOrCatalog(stmt.info->catalog, stmt.info->schema); |
90 | | |
91 | 14 | optional_ptr<CatalogEntry> entry; |
92 | 14 | if (stmt.info->type == AlterType::SET_COLUMN_COMMENT) { |
93 | | // Extra step for column comments: They can alter a table or a view, and we resolve that here. |
94 | 0 | auto &info = stmt.info->Cast<SetColumnCommentInfo>(); |
95 | 0 | entry = info.TryResolveCatalogEntry(entry_retriever); |
96 | |
|
97 | 14 | } else { |
98 | | // For any other ALTER, we retrieve the catalog entry directly. |
99 | 14 | EntryLookupInfo lookup_info(stmt.info->GetCatalogType(), stmt.info->name); |
100 | 14 | entry = entry_retriever.GetEntry(stmt.info->catalog, stmt.info->schema, lookup_info, stmt.info->if_not_found); |
101 | 14 | } |
102 | | |
103 | 14 | auto &properties = GetStatementProperties(); |
104 | 14 | properties.return_type = StatementReturnType::NOTHING; |
105 | 14 | if (!entry) { |
106 | 0 | result.plan = make_uniq<LogicalSimple>(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); |
107 | 0 | return result; |
108 | 0 | } |
109 | | |
110 | 14 | D_ASSERT(!entry->deleted); |
111 | 14 | auto &catalog = entry->ParentCatalog(); |
112 | 14 | if (catalog.IsSystemCatalog()) { |
113 | 0 | throw BinderException("Can not comment on System Catalog entries"); |
114 | 0 | } |
115 | 14 | if (!entry->temporary) { |
116 | | // We can only alter temporary tables and views in read-only mode. |
117 | 0 | properties.RegisterDBModify(catalog, context); |
118 | 0 | } |
119 | 14 | stmt.info->catalog = catalog.GetName(); |
120 | 14 | stmt.info->schema = entry->ParentSchema().name; |
121 | | |
122 | 14 | if (!stmt.info->IsAddPrimaryKey()) { |
123 | 0 | result.plan = make_uniq<LogicalSimple>(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); |
124 | 0 | return result; |
125 | 0 | } |
126 | | |
127 | 14 | return BindAlterAddIndex(result, *entry, std::move(stmt.info)); |
128 | 14 | } |
129 | | |
130 | 18.8k | BoundStatement Binder::Bind(TransactionStatement &stmt) { |
131 | 18.8k | auto &properties = GetStatementProperties(); |
132 | | |
133 | | // Transaction statements do not require a valid transaction. |
134 | 18.8k | properties.requires_valid_transaction = stmt.info->type == TransactionType::BEGIN_TRANSACTION; |
135 | | |
136 | 18.8k | BoundStatement result; |
137 | 18.8k | result.names = {"Success"}; |
138 | 18.8k | result.types = {LogicalType::BOOLEAN}; |
139 | 18.8k | result.plan = make_uniq<LogicalSimple>(LogicalOperatorType::LOGICAL_TRANSACTION, std::move(stmt.info)); |
140 | 18.8k | properties.return_type = StatementReturnType::NOTHING; |
141 | 18.8k | return result; |
142 | 18.8k | } |
143 | | |
144 | | } // namespace duckdb |