| 1 | #include "duckdb/parser/statement/delete_statement.hpp" |
| 2 | #include "duckdb/planner/binder.hpp" |
| 3 | #include "duckdb/planner/expression_binder/where_binder.hpp" |
| 4 | #include "duckdb/planner/expression_binder/returning_binder.hpp" |
| 5 | #include "duckdb/planner/operator/logical_delete.hpp" |
| 6 | #include "duckdb/planner/operator/logical_filter.hpp" |
| 7 | #include "duckdb/planner/operator/logical_get.hpp" |
| 8 | #include "duckdb/planner/bound_tableref.hpp" |
| 9 | #include "duckdb/planner/tableref/bound_basetableref.hpp" |
| 10 | #include "duckdb/planner/operator/logical_cross_product.hpp" |
| 11 | #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" |
| 12 | |
| 13 | namespace duckdb { |
| 14 | |
| 15 | BoundStatement Binder::Bind(DeleteStatement &stmt) { |
| 16 | BoundStatement result; |
| 17 | |
| 18 | // visit the table reference |
| 19 | auto bound_table = Bind(ref&: *stmt.table); |
| 20 | if (bound_table->type != TableReferenceType::BASE_TABLE) { |
| 21 | throw BinderException("Can only delete from base table!" ); |
| 22 | } |
| 23 | auto &table_binding = bound_table->Cast<BoundBaseTableRef>(); |
| 24 | auto &table = table_binding.table; |
| 25 | |
| 26 | auto root = CreatePlan(ref&: *bound_table); |
| 27 | auto &get = root->Cast<LogicalGet>(); |
| 28 | D_ASSERT(root->type == LogicalOperatorType::LOGICAL_GET); |
| 29 | |
| 30 | if (!table.temporary) { |
| 31 | // delete from persistent table: not read only! |
| 32 | properties.modified_databases.insert(x: table.catalog.GetName()); |
| 33 | } |
| 34 | |
| 35 | // Add CTEs as bindable |
| 36 | AddCTEMap(cte_map&: stmt.cte_map); |
| 37 | |
| 38 | // plan any tables from the various using clauses |
| 39 | if (!stmt.using_clauses.empty()) { |
| 40 | unique_ptr<LogicalOperator> child_operator; |
| 41 | for (auto &using_clause : stmt.using_clauses) { |
| 42 | // bind the using clause |
| 43 | auto using_binder = Binder::CreateBinder(context, parent: this); |
| 44 | auto bound_node = using_binder->Bind(ref&: *using_clause); |
| 45 | auto op = CreatePlan(ref&: *bound_node); |
| 46 | if (child_operator) { |
| 47 | // already bound a child: create a cross product to unify the two |
| 48 | child_operator = LogicalCrossProduct::Create(left: std::move(child_operator), right: std::move(op)); |
| 49 | } else { |
| 50 | child_operator = std::move(op); |
| 51 | } |
| 52 | bind_context.AddContext(other: std::move(using_binder->bind_context)); |
| 53 | } |
| 54 | if (child_operator) { |
| 55 | root = LogicalCrossProduct::Create(left: std::move(root), right: std::move(child_operator)); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | // project any additional columns required for the condition |
| 60 | unique_ptr<Expression> condition; |
| 61 | if (stmt.condition) { |
| 62 | WhereBinder binder(*this, context); |
| 63 | condition = binder.Bind(expr&: stmt.condition); |
| 64 | |
| 65 | PlanSubqueries(expr&: condition, root); |
| 66 | auto filter = make_uniq<LogicalFilter>(args: std::move(condition)); |
| 67 | filter->AddChild(child: std::move(root)); |
| 68 | root = std::move(filter); |
| 69 | } |
| 70 | // create the delete node |
| 71 | auto del = make_uniq<LogicalDelete>(args&: table, args: GenerateTableIndex()); |
| 72 | del->AddChild(child: std::move(root)); |
| 73 | |
| 74 | // set up the delete expression |
| 75 | del->expressions.push_back(x: make_uniq<BoundColumnRefExpression>( |
| 76 | args: LogicalType::ROW_TYPE, args: ColumnBinding(get.table_index, get.column_ids.size()))); |
| 77 | get.column_ids.push_back(x: COLUMN_IDENTIFIER_ROW_ID); |
| 78 | |
| 79 | if (!stmt.returning_list.empty()) { |
| 80 | del->return_chunk = true; |
| 81 | |
| 82 | auto update_table_index = GenerateTableIndex(); |
| 83 | del->table_index = update_table_index; |
| 84 | |
| 85 | unique_ptr<LogicalOperator> del_as_logicaloperator = std::move(del); |
| 86 | return BindReturning(returning_list: std::move(stmt.returning_list), table, alias: stmt.table->alias, update_table_index, |
| 87 | child_operator: std::move(del_as_logicaloperator), result: std::move(result)); |
| 88 | } |
| 89 | result.plan = std::move(del); |
| 90 | result.names = {"Count" }; |
| 91 | result.types = {LogicalType::BIGINT}; |
| 92 | properties.allow_stream_result = false; |
| 93 | properties.return_type = StatementReturnType::CHANGED_ROWS; |
| 94 | |
| 95 | return result; |
| 96 | } |
| 97 | |
| 98 | } // namespace duckdb |
| 99 | |