duckdb 0.8.2-dev2700.0 → 0.8.2-dev2842.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/icu/icu-makedate.cpp +12 -6
  3. package/src/duckdb/extension/json/include/json_deserializer.hpp +1 -1
  4. package/src/duckdb/extension/json/include/json_serializer.hpp +1 -1
  5. package/src/duckdb/extension/json/json_deserializer.cpp +10 -10
  6. package/src/duckdb/extension/json/json_scan.cpp +2 -2
  7. package/src/duckdb/extension/json/json_serializer.cpp +11 -10
  8. package/src/duckdb/extension/json/serialize_json.cpp +44 -44
  9. package/src/duckdb/extension/parquet/parquet_extension.cpp +11 -10
  10. package/src/duckdb/extension/parquet/serialize_parquet.cpp +6 -6
  11. package/src/duckdb/src/common/adbc/adbc.cpp +52 -21
  12. package/src/duckdb/src/common/adbc/driver_manager.cpp +12 -2
  13. package/src/duckdb/src/common/enum_util.cpp +5 -0
  14. package/src/duckdb/src/common/extra_type_info.cpp +2 -2
  15. package/src/duckdb/src/common/serializer/binary_deserializer.cpp +5 -3
  16. package/src/duckdb/src/common/serializer/binary_serializer.cpp +10 -5
  17. package/src/duckdb/src/common/types/column/column_data_collection.cpp +4 -4
  18. package/src/duckdb/src/common/types/row/row_data_collection_scanner.cpp +35 -5
  19. package/src/duckdb/src/common/types/value.cpp +33 -33
  20. package/src/duckdb/src/common/types/vector.cpp +20 -20
  21. package/src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp +2 -2
  22. package/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp +6 -6
  23. package/src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp +4 -4
  24. package/src/duckdb/src/core_functions/scalar/list/list_lambdas.cpp +4 -4
  25. package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +283 -91
  26. package/src/duckdb/src/execution/operator/filter/physical_filter.cpp +1 -1
  27. package/src/duckdb/src/execution/operator/join/physical_comparison_join.cpp +1 -2
  28. package/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +1 -1
  29. package/src/duckdb/src/execution/physical_plan_generator.cpp +1 -6
  30. package/src/duckdb/src/execution/window_executor.cpp +10 -1
  31. package/src/duckdb/src/function/table/read_csv.cpp +4 -4
  32. package/src/duckdb/src/function/table/table_scan.cpp +14 -14
  33. package/src/duckdb/src/function/table/version/pragma_version.cpp +5 -2
  34. package/src/duckdb/src/include/duckdb/common/adbc/adbc.hpp +2 -0
  35. package/src/duckdb/src/include/duckdb/common/enums/pending_execution_result.hpp +1 -1
  36. package/src/duckdb/src/include/duckdb/common/index_vector.hpp +2 -2
  37. package/src/duckdb/src/include/duckdb/common/serializer/binary_deserializer.hpp +7 -3
  38. package/src/duckdb/src/include/duckdb/common/serializer/binary_serializer.hpp +2 -1
  39. package/src/duckdb/src/include/duckdb/common/serializer/format_deserializer.hpp +18 -17
  40. package/src/duckdb/src/include/duckdb/common/serializer/format_serializer.hpp +10 -9
  41. package/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp +4 -0
  42. package/src/duckdb/src/include/duckdb/common/types/row/row_data_collection_scanner.hpp +5 -1
  43. package/src/duckdb/src/include/duckdb/execution/physical_operator.hpp +0 -2
  44. package/src/duckdb/src/include/duckdb/function/function_serialization.hpp +10 -10
  45. package/src/duckdb/src/include/duckdb/main/pending_query_result.hpp +5 -0
  46. package/src/duckdb/src/include/duckdb/main/relation/aggregate_relation.hpp +4 -1
  47. package/src/duckdb/src/include/duckdb/optimizer/join_order/cardinality_estimator.hpp +37 -63
  48. package/src/duckdb/src/include/duckdb/optimizer/join_order/cost_model.hpp +37 -0
  49. package/src/duckdb/src/include/duckdb/optimizer/join_order/join_node.hpp +14 -29
  50. package/src/duckdb/src/include/duckdb/optimizer/join_order/join_order_optimizer.hpp +7 -21
  51. package/src/duckdb/src/include/duckdb/optimizer/join_order/join_relation.hpp +0 -11
  52. package/src/duckdb/src/include/duckdb/optimizer/join_order/plan_enumerator.hpp +89 -0
  53. package/src/duckdb/src/include/duckdb/optimizer/join_order/query_graph.hpp +17 -31
  54. package/src/duckdb/src/include/duckdb/optimizer/join_order/query_graph_manager.hpp +113 -0
  55. package/src/duckdb/src/include/duckdb/optimizer/join_order/relation_manager.hpp +73 -0
  56. package/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp +73 -0
  57. package/src/duckdb/src/include/duckdb/parallel/task_scheduler.hpp +4 -1
  58. package/src/duckdb/src/include/duckdb/parser/group_by_node.hpp +11 -0
  59. package/src/duckdb/src/include/duckdb/parser/parser.hpp +4 -0
  60. package/src/duckdb/src/include/duckdb/planner/logical_operator.hpp +0 -2
  61. package/src/duckdb/src/include/duckdb.h +11 -1
  62. package/src/duckdb/src/main/capi/pending-c.cpp +17 -0
  63. package/src/duckdb/src/main/pending_query_result.cpp +9 -1
  64. package/src/duckdb/src/main/relation/aggregate_relation.cpp +20 -10
  65. package/src/duckdb/src/main/relation.cpp +4 -4
  66. package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +79 -325
  67. package/src/duckdb/src/optimizer/join_order/cost_model.cpp +19 -0
  68. package/src/duckdb/src/optimizer/join_order/join_node.cpp +5 -37
  69. package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +48 -1078
  70. package/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp +552 -0
  71. package/src/duckdb/src/optimizer/join_order/query_graph.cpp +32 -29
  72. package/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp +409 -0
  73. package/src/duckdb/src/optimizer/join_order/relation_manager.cpp +356 -0
  74. package/src/duckdb/src/optimizer/join_order/relation_statistics_helper.cpp +351 -0
  75. package/src/duckdb/src/parallel/executor.cpp +6 -0
  76. package/src/duckdb/src/parallel/task_scheduler.cpp +7 -0
  77. package/src/duckdb/src/parser/parser.cpp +18 -3
  78. package/src/duckdb/src/parser/tableref/pivotref.cpp +6 -6
  79. package/src/duckdb/src/planner/binder/statement/bind_execute.cpp +1 -1
  80. package/src/duckdb/src/planner/expression/bound_aggregate_expression.cpp +10 -10
  81. package/src/duckdb/src/planner/expression/bound_function_expression.cpp +6 -6
  82. package/src/duckdb/src/planner/expression/bound_window_expression.cpp +24 -24
  83. package/src/duckdb/src/planner/operator/logical_extension_operator.cpp +2 -2
  84. package/src/duckdb/src/planner/operator/logical_get.cpp +26 -22
  85. package/src/duckdb/src/storage/serialization/serialize_constraint.cpp +26 -26
  86. package/src/duckdb/src/storage/serialization/serialize_create_info.cpp +66 -66
  87. package/src/duckdb/src/storage/serialization/serialize_expression.cpp +78 -78
  88. package/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp +250 -250
  89. package/src/duckdb/src/storage/serialization/serialize_macro_function.cpp +10 -10
  90. package/src/duckdb/src/storage/serialization/serialize_nodes.cpp +206 -206
  91. package/src/duckdb/src/storage/serialization/serialize_parse_info.cpp +116 -116
  92. package/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +110 -110
  93. package/src/duckdb/src/storage/serialization/serialize_query_node.cpp +48 -48
  94. package/src/duckdb/src/storage/serialization/serialize_result_modifier.cpp +16 -16
  95. package/src/duckdb/src/storage/serialization/serialize_statement.cpp +2 -2
  96. package/src/duckdb/src/storage/serialization/serialize_table_filter.cpp +10 -10
  97. package/src/duckdb/src/storage/serialization/serialize_tableref.cpp +54 -54
  98. package/src/duckdb/src/storage/serialization/serialize_types.cpp +22 -22
  99. package/src/duckdb/src/storage/table/update_segment.cpp +1 -1
  100. package/src/duckdb/ub_src_optimizer_join_order.cpp +10 -0
@@ -0,0 +1,356 @@
1
+ #include "duckdb/optimizer/join_order/relation_manager.hpp"
2
+ #include "duckdb/optimizer/join_order/join_order_optimizer.hpp"
3
+ #include "duckdb/optimizer/join_order/relation_statistics_helper.hpp"
4
+ #include "duckdb/common/printer.hpp"
5
+ #include "duckdb/common/string_util.hpp"
6
+ #include "duckdb/parser/expression_map.hpp"
7
+ #include "duckdb/planner/expression_iterator.hpp"
8
+ #include "duckdb/planner/expression/list.hpp"
9
+ #include "duckdb/planner/operator/list.hpp"
10
+
11
+ #include <cmath>
12
+
13
+ namespace duckdb {
14
+
15
+ const vector<RelationStats> RelationManager::GetRelationStats() {
16
+ vector<RelationStats> ret;
17
+ for (idx_t i = 0; i < relations.size(); i++) {
18
+ ret.push_back(relations[i]->stats);
19
+ }
20
+ return ret;
21
+ }
22
+
23
+ vector<unique_ptr<SingleJoinRelation>> RelationManager::GetRelations() {
24
+ return std::move(relations);
25
+ }
26
+
27
+ idx_t RelationManager::NumRelations() {
28
+ return relations.size();
29
+ }
30
+
31
+ void RelationManager::AddAggregateRelation(LogicalOperator &op, optional_ptr<LogicalOperator> parent,
32
+ const RelationStats &stats) {
33
+ auto relation = make_uniq<SingleJoinRelation>(op, parent, stats);
34
+ auto relation_id = relations.size();
35
+
36
+ auto table_indexes = op.GetTableIndex();
37
+ for (auto &index : table_indexes) {
38
+ D_ASSERT(relation_mapping.find(index) == relation_mapping.end());
39
+ relation_mapping[index] = relation_id;
40
+ }
41
+ relations.push_back(std::move(relation));
42
+ }
43
+
44
+ void RelationManager::AddRelation(LogicalOperator &op, optional_ptr<LogicalOperator> parent,
45
+ const RelationStats &stats) {
46
+
47
+ // if parent is null, then this is a root relation
48
+ // if parent is not null, it should have multiple children
49
+ D_ASSERT(!parent || parent->children.size() >= 2);
50
+ auto relation = make_uniq<SingleJoinRelation>(op, parent, stats);
51
+ auto relation_id = relations.size();
52
+
53
+ auto table_indexes = op.GetTableIndex();
54
+ if (table_indexes.empty()) {
55
+ // relation represents a non-reorderable relation, most likely a join relation
56
+ // Get the tables referenced in the non-reorderable relation and add them to the relation mapping
57
+ // This should all table references, even if there are nested non-reorderable joins.
58
+ unordered_set<idx_t> table_references;
59
+ LogicalJoin::GetTableReferences(op, table_references);
60
+ D_ASSERT(table_references.size() > 0);
61
+ for (auto &reference : table_references) {
62
+ D_ASSERT(relation_mapping.find(reference) == relation_mapping.end());
63
+ relation_mapping[reference] = relation_id;
64
+ }
65
+ } else {
66
+ // Relations should never return more than 1 table index
67
+ D_ASSERT(table_indexes.size() == 1);
68
+ idx_t table_index = table_indexes.at(0);
69
+ D_ASSERT(relation_mapping.find(table_index) == relation_mapping.end());
70
+ relation_mapping[table_index] = relation_id;
71
+ }
72
+ relations.push_back(std::move(relation));
73
+ }
74
+
75
+ static bool OperatorNeedsRelation(LogicalOperatorType op_type) {
76
+ switch (op_type) {
77
+ case LogicalOperatorType::LOGICAL_PROJECTION:
78
+ case LogicalOperatorType::LOGICAL_EXPRESSION_GET:
79
+ case LogicalOperatorType::LOGICAL_GET:
80
+ case LogicalOperatorType::LOGICAL_DELIM_GET:
81
+ case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY:
82
+ case LogicalOperatorType::LOGICAL_WINDOW:
83
+ return true;
84
+ default:
85
+ return false;
86
+ }
87
+ }
88
+
89
+ static bool OperatorIsNonReorderable(LogicalOperatorType op_type) {
90
+ switch (op_type) {
91
+ case LogicalOperatorType::LOGICAL_UNION:
92
+ case LogicalOperatorType::LOGICAL_EXCEPT:
93
+ case LogicalOperatorType::LOGICAL_INTERSECT:
94
+ case LogicalOperatorType::LOGICAL_DELIM_JOIN:
95
+ case LogicalOperatorType::LOGICAL_ANY_JOIN:
96
+ case LogicalOperatorType::LOGICAL_ASOF_JOIN:
97
+ return true;
98
+ default:
99
+ return false;
100
+ }
101
+ }
102
+
103
+ static bool HasNonReorderableChild(LogicalOperator &op) {
104
+ LogicalOperator *tmp = &op;
105
+ while (tmp->children.size() == 1) {
106
+ if (OperatorNeedsRelation(tmp->type) || OperatorIsNonReorderable(tmp->type)) {
107
+ return true;
108
+ }
109
+ tmp = tmp->children[0].get();
110
+ if (tmp->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN) {
111
+ auto &join = tmp->Cast<LogicalComparisonJoin>();
112
+ if (join.join_type != JoinType::INNER) {
113
+ return true;
114
+ }
115
+ }
116
+ }
117
+ return tmp->children.empty();
118
+ }
119
+
120
+ bool RelationManager::ExtractJoinRelations(LogicalOperator &input_op,
121
+ vector<reference<LogicalOperator>> &filter_operators,
122
+ optional_ptr<LogicalOperator> parent) {
123
+ LogicalOperator *op = &input_op;
124
+ vector<reference<LogicalOperator>> datasource_filters;
125
+ // pass through single child operators
126
+ while (op->children.size() == 1 && !OperatorNeedsRelation(op->type)) {
127
+ if (op->type == LogicalOperatorType::LOGICAL_FILTER) {
128
+ if (HasNonReorderableChild(*op)) {
129
+ datasource_filters.push_back(*op);
130
+ }
131
+ filter_operators.push_back(*op);
132
+ }
133
+ if (op->type == LogicalOperatorType::LOGICAL_SHOW) {
134
+ return false;
135
+ }
136
+ op = op->children[0].get();
137
+ }
138
+ bool non_reorderable_operation = false;
139
+ if (OperatorIsNonReorderable(op->type)) {
140
+ // set operation, optimize separately in children
141
+ non_reorderable_operation = true;
142
+ }
143
+
144
+ if (op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN) {
145
+ auto &join = op->Cast<LogicalComparisonJoin>();
146
+ if (join.join_type == JoinType::INNER) {
147
+ // extract join conditions from inner join
148
+ filter_operators.push_back(*op);
149
+ } else {
150
+ non_reorderable_operation = true;
151
+ }
152
+ }
153
+ if (non_reorderable_operation) {
154
+ // we encountered a non-reordable operation (setop or non-inner join)
155
+ // we do not reorder non-inner joins yet, however we do want to expand the potential join graph around them
156
+ // non-inner joins are also tricky because we can't freely make conditions through them
157
+ // e.g. suppose we have (left LEFT OUTER JOIN right WHERE right IS NOT NULL), the join can generate
158
+ // new NULL values in the right side, so pushing this condition through the join leads to incorrect results
159
+ // for this reason, we just start a new JoinOptimizer pass in each of the children of the join
160
+ // stats.cardinality will be initiated to highest cardinality of the children.
161
+ vector<RelationStats> children_stats;
162
+ for (auto &child : op->children) {
163
+ auto stats = RelationStats();
164
+ JoinOrderOptimizer optimizer(context);
165
+ child = optimizer.Optimize(std::move(child), &stats);
166
+ children_stats.push_back(stats);
167
+ }
168
+
169
+ auto combined_stats = RelationStatisticsHelper::CombineStatsOfNonReorderableOperator(*op, children_stats);
170
+ if (!datasource_filters.empty()) {
171
+ combined_stats.cardinality =
172
+ (idx_t)MaxValue(combined_stats.cardinality * RelationStatisticsHelper::DEFAULT_SELECTIVITY, (double)1);
173
+ }
174
+ AddRelation(input_op, parent, combined_stats);
175
+ return true;
176
+ }
177
+
178
+ switch (op->type) {
179
+ case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: {
180
+ // optimize children
181
+ RelationStats child_stats;
182
+ JoinOrderOptimizer optimizer(context);
183
+ op->children[0] = optimizer.Optimize(std::move(op->children[0]), &child_stats);
184
+ auto &aggr = op->Cast<LogicalAggregate>();
185
+ auto operator_stats = RelationStatisticsHelper::ExtractAggregationStats(aggr, child_stats);
186
+ AddAggregateRelation(input_op, parent, operator_stats);
187
+ return true;
188
+ }
189
+ case LogicalOperatorType::LOGICAL_WINDOW: {
190
+ // optimize children
191
+ RelationStats child_stats;
192
+ JoinOrderOptimizer optimizer(context);
193
+ op->children[0] = optimizer.Optimize(std::move(op->children[0]), &child_stats);
194
+ auto &window = op->Cast<LogicalWindow>();
195
+ auto operator_stats = RelationStatisticsHelper::ExtractWindowStats(window, child_stats);
196
+ AddAggregateRelation(input_op, parent, operator_stats);
197
+ return true;
198
+ }
199
+ case LogicalOperatorType::LOGICAL_COMPARISON_JOIN:
200
+ case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: {
201
+ // Adding relations to the current join order optimizer
202
+ bool can_reorder_left = ExtractJoinRelations(*op->children[0], filter_operators, op);
203
+ bool can_reorder_right = ExtractJoinRelations(*op->children[1], filter_operators, op);
204
+ return can_reorder_left && can_reorder_right;
205
+ }
206
+ case LogicalOperatorType::LOGICAL_DUMMY_SCAN: {
207
+ auto &dummy_scan = op->Cast<LogicalDummyScan>();
208
+ auto stats = RelationStatisticsHelper::ExtractDummyScanStats(dummy_scan, context);
209
+ AddRelation(input_op, parent, stats);
210
+ return true;
211
+ }
212
+ case LogicalOperatorType::LOGICAL_EXPRESSION_GET: {
213
+ // base table scan, add to set of relations.
214
+ // create empty stats for dummy scan or logical expression get
215
+ auto &expression_get = op->Cast<LogicalExpressionGet>();
216
+ auto stats = RelationStatisticsHelper::ExtractExpressionGetStats(expression_get, context);
217
+ AddRelation(input_op, parent, stats);
218
+ return true;
219
+ }
220
+ case LogicalOperatorType::LOGICAL_GET: {
221
+ // TODO: Get stats from a logical GET
222
+ auto &get = op->Cast<LogicalGet>();
223
+ auto stats = RelationStatisticsHelper::ExtractGetStats(get, context);
224
+ // if there is another logical filter that could not be pushed down into the
225
+ // table scan, apply another selectivity.
226
+ if (!datasource_filters.empty()) {
227
+ stats.cardinality =
228
+ (idx_t)MaxValue(stats.cardinality * RelationStatisticsHelper::DEFAULT_SELECTIVITY, (double)1);
229
+ }
230
+ AddRelation(input_op, parent, stats);
231
+ return true;
232
+ }
233
+ case LogicalOperatorType::LOGICAL_DELIM_GET: {
234
+ auto &delim_get = op->Cast<LogicalDelimGet>();
235
+ auto stats = RelationStatisticsHelper::ExtractDelimGetStats(delim_get, context);
236
+ AddRelation(input_op, parent, stats);
237
+ return true;
238
+ }
239
+ case LogicalOperatorType::LOGICAL_PROJECTION: {
240
+ auto child_stats = RelationStats();
241
+ // optimize the child and copy the stats
242
+ JoinOrderOptimizer optimizer(context);
243
+ op->children[0] = optimizer.Optimize(std::move(op->children[0]), &child_stats);
244
+ auto &proj = op->Cast<LogicalProjection>();
245
+ // Projection can create columns so we need to add them here
246
+ auto proj_stats = RelationStatisticsHelper::ExtractProjectionStats(proj, child_stats);
247
+ AddRelation(input_op, parent, proj_stats);
248
+ return true;
249
+ }
250
+ default:
251
+ return false;
252
+ }
253
+ }
254
+
255
+ bool RelationManager::ExtractBindings(Expression &expression, unordered_set<idx_t> &bindings) {
256
+ if (expression.type == ExpressionType::BOUND_COLUMN_REF) {
257
+ auto &colref = expression.Cast<BoundColumnRefExpression>();
258
+ D_ASSERT(colref.depth == 0);
259
+ D_ASSERT(colref.binding.table_index != DConstants::INVALID_INDEX);
260
+ // map the base table index to the relation index used by the JoinOrderOptimizer
261
+ if (expression.alias == "SUBQUERY" &&
262
+ relation_mapping.find(colref.binding.table_index) == relation_mapping.end()) {
263
+ // most likely a BoundSubqueryExpression that was created from an uncorrelated subquery
264
+ // Here we return true and don't fill the bindings, the expression can be reordered.
265
+ // A filter will be created using this expression, and pushed back on top of the parent
266
+ // operator during plan reconstruction
267
+ return true;
268
+ }
269
+ D_ASSERT(relation_mapping.find(colref.binding.table_index) != relation_mapping.end());
270
+ bindings.insert(relation_mapping[colref.binding.table_index]);
271
+ }
272
+ if (expression.type == ExpressionType::BOUND_REF) {
273
+ // bound expression
274
+ bindings.clear();
275
+ return false;
276
+ }
277
+ D_ASSERT(expression.type != ExpressionType::SUBQUERY);
278
+ bool can_reorder = true;
279
+ ExpressionIterator::EnumerateChildren(expression, [&](Expression &expr) {
280
+ if (!ExtractBindings(expr, bindings)) {
281
+ can_reorder = false;
282
+ return;
283
+ }
284
+ });
285
+ return can_reorder;
286
+ }
287
+
288
+ vector<unique_ptr<FilterInfo>> RelationManager::ExtractEdges(LogicalOperator &op,
289
+ vector<reference<LogicalOperator>> &filter_operators,
290
+ JoinRelationSetManager &set_manager) {
291
+ // now that we know we are going to perform join ordering we actually extract the filters, eliminating duplicate
292
+ // filters in the process
293
+ vector<unique_ptr<FilterInfo>> filters_and_bindings;
294
+ expression_set_t filter_set;
295
+ for (auto &filter_op : filter_operators) {
296
+ auto &f_op = filter_op.get();
297
+ if (f_op.type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN ||
298
+ f_op.type == LogicalOperatorType::LOGICAL_ASOF_JOIN) {
299
+ auto &join = f_op.Cast<LogicalComparisonJoin>();
300
+ D_ASSERT(join.join_type == JoinType::INNER);
301
+ D_ASSERT(join.expressions.empty());
302
+ for (auto &cond : join.conditions) {
303
+ auto comparison =
304
+ make_uniq<BoundComparisonExpression>(cond.comparison, std::move(cond.left), std::move(cond.right));
305
+ if (filter_set.find(*comparison) == filter_set.end()) {
306
+ filter_set.insert(*comparison);
307
+ unordered_set<idx_t> bindings;
308
+ ExtractBindings(*comparison, bindings);
309
+ auto &set = set_manager.GetJoinRelation(bindings);
310
+ auto filter_info = make_uniq<FilterInfo>(std::move(comparison), set, filters_and_bindings.size());
311
+ filters_and_bindings.push_back(std::move(filter_info));
312
+ }
313
+ }
314
+ join.conditions.clear();
315
+ } else {
316
+ for (auto &expression : f_op.expressions) {
317
+ if (filter_set.find(*expression) == filter_set.end()) {
318
+ filter_set.insert(*expression);
319
+ unordered_set<idx_t> bindings;
320
+ ExtractBindings(*expression, bindings);
321
+ auto &set = set_manager.GetJoinRelation(bindings);
322
+ auto filter_info = make_uniq<FilterInfo>(std::move(expression), set, filters_and_bindings.size());
323
+ filters_and_bindings.push_back(std::move(filter_info));
324
+ }
325
+ }
326
+ f_op.expressions.clear();
327
+ }
328
+ }
329
+
330
+ return filters_and_bindings;
331
+ }
332
+
333
+ // LCOV_EXCL_START
334
+
335
+ void RelationManager::PrintRelationStats() {
336
+ #ifdef DEBUG
337
+ string to_print;
338
+ for (idx_t i = 0; i < relations.size(); i++) {
339
+ auto &relation = relations.at(i);
340
+ auto &stats = relation->stats;
341
+ D_ASSERT(stats.column_names.size() == stats.column_distinct_count.size());
342
+ for (idx_t i = 0; i < stats.column_names.size(); i++) {
343
+ to_print = stats.column_names.at(i) + " has estimated distinct count " +
344
+ to_string(stats.column_distinct_count.at(i).distinct_count);
345
+ Printer::Print(to_print);
346
+ }
347
+ to_print = stats.table_name + " has estimated cardinality " + to_string(stats.cardinality);
348
+ to_print += " and relation id " + to_string(i) + "\n";
349
+ Printer::Print(to_print);
350
+ }
351
+ #endif
352
+ }
353
+
354
+ // LCOV_EXCL_STOP
355
+
356
+ } // namespace duckdb