1#include "duckdb/planner/operator/logical_get.hpp"
2
3#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
4#include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp"
5#include "duckdb/common/field_writer.hpp"
6#include "duckdb/common/string_util.hpp"
7#include "duckdb/function/function_serialization.hpp"
8#include "duckdb/function/table/table_scan.hpp"
9#include "duckdb/main/config.hpp"
10#include "duckdb/storage/data_table.hpp"
11
12namespace duckdb {
13
14LogicalGet::LogicalGet(idx_t table_index, TableFunction function, unique_ptr<FunctionData> bind_data,
15 vector<LogicalType> returned_types, vector<string> returned_names)
16 : LogicalOperator(LogicalOperatorType::LOGICAL_GET), table_index(table_index), function(std::move(function)),
17 bind_data(std::move(bind_data)), returned_types(std::move(returned_types)), names(std::move(returned_names)) {
18}
19
20optional_ptr<TableCatalogEntry> LogicalGet::GetTable() const {
21 return TableScanFunction::GetTableEntry(function, bind_data: bind_data.get());
22}
23
24string LogicalGet::ParamsToString() const {
25 string result;
26 for (auto &kv : table_filters.filters) {
27 auto &column_index = kv.first;
28 auto &filter = kv.second;
29 if (column_index < names.size()) {
30 result += filter->ToString(column_name: names[column_index]);
31 }
32 result += "\n";
33 }
34 if (!function.to_string) {
35 return string();
36 }
37 return function.to_string(bind_data.get());
38}
39
40vector<ColumnBinding> LogicalGet::GetColumnBindings() {
41 if (column_ids.empty()) {
42 return {ColumnBinding(table_index, 0)};
43 }
44 vector<ColumnBinding> result;
45 if (projection_ids.empty()) {
46 for (idx_t col_idx = 0; col_idx < column_ids.size(); col_idx++) {
47 result.emplace_back(args&: table_index, args&: col_idx);
48 }
49 } else {
50 for (auto proj_id : projection_ids) {
51 result.emplace_back(args&: table_index, args&: proj_id);
52 }
53 }
54 if (!projected_input.empty()) {
55 if (children.size() != 1) {
56 throw InternalException("LogicalGet::project_input can only be set for table-in-out functions");
57 }
58 auto child_bindings = children[0]->GetColumnBindings();
59 for (auto entry : projected_input) {
60 D_ASSERT(entry < child_bindings.size());
61 result.emplace_back(args&: child_bindings[entry]);
62 }
63 }
64 return result;
65}
66
67void LogicalGet::ResolveTypes() {
68 if (column_ids.empty()) {
69 column_ids.push_back(x: COLUMN_IDENTIFIER_ROW_ID);
70 }
71
72 if (projection_ids.empty()) {
73 for (auto &index : column_ids) {
74 if (index == COLUMN_IDENTIFIER_ROW_ID) {
75 types.emplace_back(args: LogicalType::ROW_TYPE);
76 } else {
77 types.push_back(x: returned_types[index]);
78 }
79 }
80 } else {
81 for (auto &proj_index : projection_ids) {
82 auto &index = column_ids[proj_index];
83 if (index == COLUMN_IDENTIFIER_ROW_ID) {
84 types.emplace_back(args: LogicalType::ROW_TYPE);
85 } else {
86 types.push_back(x: returned_types[index]);
87 }
88 }
89 }
90 if (!projected_input.empty()) {
91 if (children.size() != 1) {
92 throw InternalException("LogicalGet::project_input can only be set for table-in-out functions");
93 }
94 for (auto entry : projected_input) {
95 D_ASSERT(entry < children[0]->types.size());
96 types.push_back(x: children[0]->types[entry]);
97 }
98 }
99}
100
101idx_t LogicalGet::EstimateCardinality(ClientContext &context) {
102 if (function.cardinality) {
103 auto node_stats = function.cardinality(context, bind_data.get());
104 if (node_stats && node_stats->has_estimated_cardinality) {
105 return node_stats->estimated_cardinality;
106 }
107 }
108 return 1;
109}
110
111void LogicalGet::Serialize(FieldWriter &writer) const {
112 writer.WriteField(element: table_index);
113 writer.WriteRegularSerializableList(elements: returned_types);
114 writer.WriteList<string>(elements: names);
115 writer.WriteList<column_t>(elements: column_ids);
116 writer.WriteList<column_t>(elements: projection_ids);
117 writer.WriteSerializable(element: table_filters);
118
119 FunctionSerializer::SerializeBase<TableFunction>(writer, function, bind_info: bind_data.get());
120 if (!function.serialize) {
121 D_ASSERT(!function.deserialize);
122 // no serialize method: serialize input values and named_parameters for rebinding purposes
123 writer.WriteRegularSerializableList(elements: parameters);
124 writer.WriteField<idx_t>(element: named_parameters.size());
125 for (auto &pair : named_parameters) {
126 writer.WriteString(val: pair.first);
127 writer.WriteSerializable(element: pair.second);
128 }
129 writer.WriteRegularSerializableList(elements: input_table_types);
130 writer.WriteList<string>(elements: input_table_names);
131 }
132 writer.WriteList<column_t>(elements: projected_input);
133}
134
135unique_ptr<LogicalOperator> LogicalGet::Deserialize(LogicalDeserializationState &state, FieldReader &reader) {
136 auto table_index = reader.ReadRequired<idx_t>();
137 auto returned_types = reader.ReadRequiredSerializableList<LogicalType, LogicalType>();
138 auto returned_names = reader.ReadRequiredList<string>();
139 auto column_ids = reader.ReadRequiredList<column_t>();
140 auto projection_ids = reader.ReadRequiredList<column_t>();
141 auto table_filters = reader.ReadRequiredSerializable<TableFilterSet>();
142
143 unique_ptr<FunctionData> bind_data;
144 bool has_deserialize;
145 auto function = FunctionSerializer::DeserializeBaseInternal<TableFunction, TableFunctionCatalogEntry>(
146 reader, state&: state.gstate, type: CatalogType::TABLE_FUNCTION_ENTRY, bind_info&: bind_data, has_deserialize);
147
148 vector<Value> parameters;
149 named_parameter_map_t named_parameters;
150 vector<LogicalType> input_table_types;
151 vector<string> input_table_names;
152 if (!has_deserialize) {
153 D_ASSERT(!bind_data);
154 parameters = reader.ReadRequiredSerializableList<Value, Value>();
155
156 auto named_parameters_size = reader.ReadRequired<idx_t>();
157 for (idx_t i = 0; i < named_parameters_size; i++) {
158 auto first = reader.ReadRequired<string>();
159 auto second = reader.ReadRequiredSerializable<Value, Value>();
160 auto pair = make_pair(x&: first, y&: second);
161 named_parameters.insert(x&: pair);
162 }
163
164 input_table_types = reader.ReadRequiredSerializableList<LogicalType, LogicalType>();
165 input_table_names = reader.ReadRequiredList<string>();
166 TableFunctionBindInput input(parameters, named_parameters, input_table_types, input_table_names,
167 function.function_info.get());
168
169 vector<LogicalType> bind_return_types;
170 vector<string> bind_names;
171 bind_data = function.bind(state.gstate.context, input, bind_return_types, bind_names);
172 if (returned_types != bind_return_types) {
173 throw SerializationException(
174 "Table function deserialization failure - bind returned different return types than were serialized");
175 }
176 // names can actually be different because of aliases - only the sizes cannot be different
177 if (returned_names.size() != bind_names.size()) {
178 throw SerializationException(
179 "Table function deserialization failure - bind returned different returned names than were serialized");
180 }
181 }
182 vector<column_t> projected_input;
183 reader.ReadList<column_t>(result&: projected_input);
184
185 auto result = make_uniq<LogicalGet>(args&: table_index, args&: function, args: std::move(bind_data), args&: returned_types, args&: returned_names);
186 result->column_ids = std::move(column_ids);
187 result->projection_ids = std::move(projection_ids);
188 result->table_filters = std::move(*table_filters);
189 result->parameters = std::move(parameters);
190 result->named_parameters = std::move(named_parameters);
191 result->input_table_types = input_table_types;
192 result->input_table_names = input_table_names;
193 result->projected_input = std::move(projected_input);
194 return std::move(result);
195}
196
197vector<idx_t> LogicalGet::GetTableIndex() const {
198 return vector<idx_t> {table_index};
199}
200
201string LogicalGet::GetName() const {
202#ifdef DEBUG
203 if (DBConfigOptions::debug_print_bindings) {
204 return StringUtil::Upper(function.name) + StringUtil::Format(" #%llu", table_index);
205 }
206#endif
207 return StringUtil::Upper(str: function.name);
208}
209
210} // namespace duckdb
211