1 | #include "duckdb/execution/operator/projection/physical_projection.hpp" |
2 | #include "duckdb/execution/operator/projection/physical_tableinout_function.hpp" |
3 | #include "duckdb/execution/operator/scan/physical_table_scan.hpp" |
4 | #include "duckdb/execution/physical_plan_generator.hpp" |
5 | #include "duckdb/function/table/table_scan.hpp" |
6 | #include "duckdb/planner/expression/bound_constant_expression.hpp" |
7 | #include "duckdb/planner/expression/bound_reference_expression.hpp" |
8 | #include "duckdb/planner/operator/logical_get.hpp" |
9 | |
10 | namespace duckdb { |
11 | |
12 | unique_ptr<TableFilterSet> CreateTableFilterSet(TableFilterSet &table_filters, vector<column_t> &column_ids) { |
13 | // create the table filter map |
14 | auto table_filter_set = make_uniq<TableFilterSet>(); |
15 | for (auto &table_filter : table_filters.filters) { |
16 | // find the relative column index from the absolute column index into the table |
17 | idx_t column_index = DConstants::INVALID_INDEX; |
18 | for (idx_t i = 0; i < column_ids.size(); i++) { |
19 | if (table_filter.first == column_ids[i]) { |
20 | column_index = i; |
21 | break; |
22 | } |
23 | } |
24 | if (column_index == DConstants::INVALID_INDEX) { |
25 | throw InternalException("Could not find column index for table filter" ); |
26 | } |
27 | table_filter_set->filters[column_index] = std::move(table_filter.second); |
28 | } |
29 | return table_filter_set; |
30 | } |
31 | |
32 | unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalGet &op) { |
33 | if (!op.children.empty()) { |
34 | // this is for table producing functions that consume subquery results |
35 | D_ASSERT(op.children.size() == 1); |
36 | auto node = make_uniq<PhysicalTableInOutFunction>(args&: op.types, args&: op.function, args: std::move(op.bind_data), args&: op.column_ids, |
37 | args&: op.estimated_cardinality, args: std::move(op.projected_input)); |
38 | node->children.push_back(x: CreatePlan(logical: std::move(op.children[0]))); |
39 | return std::move(node); |
40 | } |
41 | if (!op.projected_input.empty()) { |
42 | throw InternalException("LogicalGet::project_input can only be set for table-in-out functions" ); |
43 | } |
44 | |
45 | unique_ptr<TableFilterSet> table_filters; |
46 | if (!op.table_filters.filters.empty()) { |
47 | table_filters = CreateTableFilterSet(table_filters&: op.table_filters, column_ids&: op.column_ids); |
48 | } |
49 | |
50 | if (op.function.dependency) { |
51 | op.function.dependency(dependencies, op.bind_data.get()); |
52 | } |
53 | // create the table scan node |
54 | if (!op.function.projection_pushdown) { |
55 | // function does not support projection pushdown |
56 | auto node = make_uniq<PhysicalTableScan>(args&: op.returned_types, args&: op.function, args: std::move(op.bind_data), |
57 | args&: op.returned_types, args&: op.column_ids, args: vector<column_t>(), args&: op.names, |
58 | args: std::move(table_filters), args&: op.estimated_cardinality); |
59 | // first check if an additional projection is necessary |
60 | if (op.column_ids.size() == op.returned_types.size()) { |
61 | bool projection_necessary = false; |
62 | for (idx_t i = 0; i < op.column_ids.size(); i++) { |
63 | if (op.column_ids[i] != i) { |
64 | projection_necessary = true; |
65 | break; |
66 | } |
67 | } |
68 | if (!projection_necessary) { |
69 | // a projection is not necessary if all columns have been requested in-order |
70 | // in that case we just return the node |
71 | |
72 | return std::move(node); |
73 | } |
74 | } |
75 | // push a projection on top that does the projection |
76 | vector<LogicalType> types; |
77 | vector<unique_ptr<Expression>> expressions; |
78 | for (auto &column_id : op.column_ids) { |
79 | if (column_id == COLUMN_IDENTIFIER_ROW_ID) { |
80 | types.emplace_back(args: LogicalType::BIGINT); |
81 | expressions.push_back(x: make_uniq<BoundConstantExpression>(args: Value::BIGINT(value: 0))); |
82 | } else { |
83 | auto type = op.returned_types[column_id]; |
84 | types.push_back(x: type); |
85 | expressions.push_back(x: make_uniq<BoundReferenceExpression>(args&: type, args&: column_id)); |
86 | } |
87 | } |
88 | |
89 | auto projection = |
90 | make_uniq<PhysicalProjection>(args: std::move(types), args: std::move(expressions), args&: op.estimated_cardinality); |
91 | projection->children.push_back(x: std::move(node)); |
92 | return std::move(projection); |
93 | } else { |
94 | return make_uniq<PhysicalTableScan>(args&: op.types, args&: op.function, args: std::move(op.bind_data), args&: op.returned_types, |
95 | args&: op.column_ids, args&: op.projection_ids, args&: op.names, args: std::move(table_filters), |
96 | args&: op.estimated_cardinality); |
97 | } |
98 | } |
99 | |
100 | } // namespace duckdb |
101 | |