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
10namespace duckdb {
11
12unique_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
32unique_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