Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion R/version.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Generated by rconfigure.py, do not edit by hand
# DuckDB version information

duckdb_version <- "1.4.3-dev209"
duckdb_version <- "1.4.3-dev215"

# Function to get DuckDB version without establishing a connection
get_duckdb_version <- function() {
Expand Down
6 changes: 3 additions & 3 deletions src/duckdb/src/function/table/version/pragma_version.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef DUCKDB_PATCH_VERSION
#define DUCKDB_PATCH_VERSION "3-dev209"
#define DUCKDB_PATCH_VERSION "3-dev215"
#endif
#ifndef DUCKDB_MINOR_VERSION
#define DUCKDB_MINOR_VERSION 4
Expand All @@ -8,10 +8,10 @@
#define DUCKDB_MAJOR_VERSION 1
#endif
#ifndef DUCKDB_VERSION
#define DUCKDB_VERSION "v1.4.3-dev209"
#define DUCKDB_VERSION "v1.4.3-dev215"
#endif
#ifndef DUCKDB_SOURCE_ID
#define DUCKDB_SOURCE_ID "c08cb6c83d"
#define DUCKDB_SOURCE_ID "8a2fc1d6d5"
#endif
#include "duckdb/function/table/system_functions.hpp"
#include "duckdb/main/database.hpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct FlattenDependentJoins {
bool parent_is_dependent_join = false);

//! Mark entire subtree of Logical Operators as correlated by adding them to the has_correlated_expressions map.
bool MarkSubtreeCorrelated(LogicalOperator &op);
bool MarkSubtreeCorrelated(LogicalOperator &op, idx_t cte_index);

//! Push the dependent join down a LogicalOperator
unique_ptr<LogicalOperator> PushDownDependentJoin(unique_ptr<LogicalOperator> plan,
Expand Down
78 changes: 55 additions & 23 deletions src/duckdb/src/planner/subquery/flatten_dependent_join.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ bool FlattenDependentJoins::DetectCorrelatedExpressions(LogicalOperator &op, boo
if (DetectCorrelatedExpressions(*child, lateral, new_lateral_depth, condition)) {
has_correlation = true;
}

if (op.type == LogicalOperatorType::LOGICAL_MATERIALIZED_CTE && child_idx == 0) {
auto &setop = op.Cast<LogicalCTE>();
binder.recursive_ctes[setop.table_index] = &setop;
has_correlated_expressions[op] = has_correlation;
if (has_correlation) {
setop.correlated_columns = correlated_columns;
}
}

child_idx++;
}

Expand All @@ -261,6 +271,7 @@ bool FlattenDependentJoins::DetectCorrelatedExpressions(LogicalOperator &op, boo
return true;
}
// Found a materialized CTE, subtree correlation depends on the CTE node
has_correlated_expressions[op] = has_correlated_expressions[*cte_node];
return has_correlated_expressions[*cte_node];
}
// No CTE found: subtree is correlated
Expand All @@ -279,47 +290,32 @@ bool FlattenDependentJoins::DetectCorrelatedExpressions(LogicalOperator &op, boo
binder.recursive_ctes[setop.table_index] = &setop;
if (has_correlation) {
setop.correlated_columns = correlated_columns;
MarkSubtreeCorrelated(*op.children[1].get());
}
}

if (op.type == LogicalOperatorType::LOGICAL_MATERIALIZED_CTE) {
auto &setop = op.Cast<LogicalCTE>();
binder.recursive_ctes[setop.table_index] = &setop;
// only mark the entire subtree as correlated if the materializing side is correlated
auto entry = has_correlated_expressions.find(*op.children[0]);
if (entry != has_correlated_expressions.end()) {
if (has_correlation && entry->second) {
setop.correlated_columns = correlated_columns;
MarkSubtreeCorrelated(*op.children[1].get());
}
MarkSubtreeCorrelated(*op.children[1].get(), setop.table_index);
}
}

return has_correlation;
}

bool FlattenDependentJoins::MarkSubtreeCorrelated(LogicalOperator &op) {
bool FlattenDependentJoins::MarkSubtreeCorrelated(LogicalOperator &op, idx_t cte_index) {
// Do not mark base table scans as correlated
auto entry = has_correlated_expressions.find(op);
D_ASSERT(entry != has_correlated_expressions.end());
bool has_correlation = entry->second;
for (auto &child : op.children) {
has_correlation |= MarkSubtreeCorrelated(*child.get());
has_correlation |= MarkSubtreeCorrelated(*child.get(), cte_index);
}
if (op.type != LogicalOperatorType::LOGICAL_GET || op.children.size() == 1) {
if (op.type == LogicalOperatorType::LOGICAL_CTE_REF) {
// There may be multiple recursive CTEs. Only mark CTE_REFs as correlated,
// IFF the CTE that we are reading from is correlated.
auto &cteref = op.Cast<LogicalCTERef>();
auto cte = binder.recursive_ctes.find(cteref.cte_index);
bool has_correlation = false;
if (cte != binder.recursive_ctes.end()) {
auto &rec_cte = cte->second->Cast<LogicalCTE>();
has_correlation = !rec_cte.correlated_columns.empty();
if (cteref.cte_index != cte_index) {
has_correlated_expressions[op] = has_correlation;
return has_correlation;
}
has_correlated_expressions[op] = has_correlation;
return has_correlation;
has_correlated_expressions[op] = true;
return true;
} else {
has_correlated_expressions[op] = has_correlation;
}
Expand Down Expand Up @@ -695,6 +691,42 @@ unique_ptr<LogicalOperator> FlattenDependentJoins::PushDownDependentJoinInternal
return plan;
}
} else if (join.join_type == JoinType::MARK) {
if (!left_has_correlation && right_has_correlation) {
// found a MARK join where the left side has no correlation

ColumnBinding right_binding;

// there may still be correlation on the right side that we have to deal with
// push into the right side if necessary or decorrelate it independently otherwise
plan->children[1] = PushDownDependentJoinInternal(std::move(plan->children[1]),
parent_propagate_null_values, lateral_depth);
right_binding = this->base_binding;

// now push into the left side of the MARK join even though it has no correlation
// this is necessary to add the correlated columns to the column bindings and allow
// the join condition to be rewritten correctly
plan->children[0] = PushDownDependentJoinInternal(std::move(plan->children[0]),
parent_propagate_null_values, lateral_depth);

auto left_binding = this->base_binding;

// add the correlated columns to the join conditions
for (idx_t i = 0; i < correlated_columns.size(); i++) {
JoinCondition cond;
cond.left = make_uniq<BoundColumnRefExpression>(
correlated_columns[i].type,
ColumnBinding(left_binding.table_index, left_binding.column_index + i));
cond.right = make_uniq<BoundColumnRefExpression>(
correlated_columns[i].type,
ColumnBinding(right_binding.table_index, right_binding.column_index + i));
cond.comparison = ExpressionType::COMPARE_NOT_DISTINCT_FROM;

auto &comparison_join = join.Cast<LogicalComparisonJoin>();
comparison_join.conditions.push_back(std::move(cond));
}
return plan;
}

// push the child into the LHS
plan->children[0] = PushDownDependentJoinInternal(std::move(plan->children[0]),
parent_propagate_null_values, lateral_depth);
Expand Down