/src/duckdb/src/planner/binder/statement/bind_vacuum.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "duckdb/parser/expression/columnref_expression.hpp" |
2 | | #include "duckdb/parser/statement/vacuum_statement.hpp" |
3 | | #include "duckdb/planner/binder.hpp" |
4 | | #include "duckdb/planner/operator/logical_get.hpp" |
5 | | #include "duckdb/planner/operator/logical_projection.hpp" |
6 | | #include "duckdb/planner/operator/logical_vacuum.hpp" |
7 | | #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" |
8 | | |
9 | | namespace duckdb { |
10 | | |
11 | 44 | void Binder::BindVacuumTable(LogicalVacuum &vacuum, unique_ptr<LogicalOperator> &root) { |
12 | 44 | auto &info = vacuum.GetInfo(); |
13 | 44 | if (!info.has_table) { |
14 | 23 | return; |
15 | 23 | } |
16 | | |
17 | 21 | D_ASSERT(vacuum.column_id_map.empty()); |
18 | 21 | auto bound_table = Bind(*info.ref); |
19 | 21 | if (bound_table->type != TableReferenceType::BASE_TABLE) { |
20 | 0 | throw InvalidInputException("can only vacuum or analyze base tables"); |
21 | 0 | } |
22 | 21 | auto ref = unique_ptr_cast<BoundTableRef, BoundBaseTableRef>(std::move(bound_table)); |
23 | 21 | auto &table = ref->table; |
24 | 21 | vacuum.SetTable(table); |
25 | | |
26 | 21 | vector<unique_ptr<Expression>> select_list; |
27 | 21 | auto &columns = info.columns; |
28 | 21 | if (columns.empty()) { |
29 | | // Empty means ALL columns should be vacuumed/analyzed |
30 | 0 | for (auto &col : table.GetColumns().Physical()) { |
31 | 0 | columns.push_back(col.GetName()); |
32 | 0 | } |
33 | 0 | } |
34 | | |
35 | 21 | case_insensitive_set_t column_name_set; |
36 | 21 | vector<string> non_generated_column_names; |
37 | 21 | for (auto &col_name : columns) { |
38 | 0 | if (column_name_set.count(col_name) > 0) { |
39 | 0 | throw BinderException("cannot vacuum or analyze the same column twice, i.e., there is a duplicate entry in " |
40 | 0 | "the list of column names"); |
41 | 0 | } |
42 | 0 | column_name_set.insert(col_name); |
43 | 0 | if (!table.ColumnExists(col_name)) { |
44 | 0 | throw BinderException("Column with name \"%s\" does not exist", col_name); |
45 | 0 | } |
46 | 0 | auto &col = table.GetColumn(col_name); |
47 | | // ignore generated column |
48 | 0 | if (col.Generated()) { |
49 | 0 | throw BinderException( |
50 | 0 | "cannot vacuum or analyze generated column \"%s\" - specify non-generated columns to vacuum or analyze", |
51 | 0 | col.GetName()); |
52 | 0 | } |
53 | 0 | non_generated_column_names.push_back(col_name); |
54 | 0 | ColumnRefExpression colref(col_name, table.name); |
55 | 0 | auto result = bind_context.BindColumn(colref, 0); |
56 | 0 | if (result.HasError()) { |
57 | 0 | result.error.Throw(); |
58 | 0 | } |
59 | 0 | select_list.push_back(std::move(result.expression)); |
60 | 0 | } |
61 | 21 | info.columns = std::move(non_generated_column_names); |
62 | | |
63 | 21 | auto table_scan = CreatePlan(*ref); |
64 | 21 | D_ASSERT(table_scan->type == LogicalOperatorType::LOGICAL_GET); |
65 | | |
66 | 21 | auto &get = table_scan->Cast<LogicalGet>(); |
67 | | |
68 | 21 | auto &column_ids = get.GetColumnIds(); |
69 | 21 | D_ASSERT(select_list.size() == column_ids.size()); |
70 | 21 | D_ASSERT(info.columns.size() == column_ids.size()); |
71 | 21 | for (idx_t i = 0; i < column_ids.size(); i++) { |
72 | 0 | vacuum.column_id_map[i] = table.GetColumns().LogicalToPhysical(column_ids[i].ToLogical()).index; |
73 | 0 | } |
74 | | |
75 | 21 | auto projection = make_uniq<LogicalProjection>(GenerateTableIndex(), std::move(select_list)); |
76 | 21 | projection->children.push_back(std::move(table_scan)); |
77 | | |
78 | 21 | root = std::move(projection); |
79 | 21 | } |
80 | | |
81 | 44 | BoundStatement Binder::Bind(VacuumStatement &stmt) { |
82 | 44 | BoundStatement result; |
83 | | |
84 | 44 | unique_ptr<LogicalOperator> root; |
85 | | |
86 | 44 | auto vacuum = make_uniq<LogicalVacuum>(std::move(stmt.info)); |
87 | 44 | BindVacuumTable(*vacuum, root); |
88 | 44 | if (root) { |
89 | 0 | vacuum->children.push_back(std::move(root)); |
90 | 0 | } |
91 | | |
92 | 44 | result.names = {"Success"}; |
93 | 44 | result.types = {LogicalType::BOOLEAN}; |
94 | 44 | result.plan = std::move(vacuum); |
95 | | |
96 | 44 | auto &properties = GetStatementProperties(); |
97 | 44 | properties.return_type = StatementReturnType::NOTHING; |
98 | 44 | return result; |
99 | 44 | } |
100 | | |
101 | | } // namespace duckdb |