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 | |
12 | namespace duckdb { |
13 | |
14 | LogicalGet::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 | |
20 | optional_ptr<TableCatalogEntry> LogicalGet::GetTable() const { |
21 | return TableScanFunction::GetTableEntry(function, bind_data: bind_data.get()); |
22 | } |
23 | |
24 | string 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 | |
40 | vector<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 | |
67 | void 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 | |
101 | idx_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 | |
111 | void 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 | |
135 | unique_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 | |
197 | vector<idx_t> LogicalGet::GetTableIndex() const { |
198 | return vector<idx_t> {table_index}; |
199 | } |
200 | |
201 | string 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 | |