Skip to content

Commit 2501da7

Browse files
authored
fix(binder): correct join statistics propagation (#20122)
* x * fix(query): invalidate stats when DPhyp replaces joins * fix(query): replace DPhyp join tree directly * x * x * x
1 parent 0166045 commit 2501da7

29 files changed

Lines changed: 3963 additions & 1543 deletions

src/query/sql/src/planner/binder/bind_context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ pub struct CteContext {
205205
pub cte_map: Box<IndexMap<String, CteInfo>>,
206206
/// Pending output columns generated by materialized CTE virtual-column rewrite.
207207
/// `init_cte` consumes this map and stores the per-CTE result in `CteInfo`.
208-
pub virtual_column_outputs: HashMap<String, HashSet<String>>,
208+
pub virtual_column_outputs: HashMap<String, BTreeSet<String>>,
209209
}
210210

211211
impl CteContext {
@@ -241,7 +241,7 @@ impl CteContext {
241241
#[derive(Clone, Debug)]
242242
pub struct CteInfo {
243243
pub columns_alias: Vec<String>,
244-
pub virtual_column_outputs: HashSet<String>,
244+
pub virtual_column_outputs: BTreeSet<String>,
245245
pub query: Query,
246246
pub recursive: bool,
247247
pub logical_recursive_cte_id: Option<u32>,

src/query/sql/src/planner/binder/virtual_column.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
use std::collections::BTreeMap;
16+
use std::collections::BTreeSet;
1617
use std::collections::HashMap;
1718
use std::collections::HashSet;
1819

@@ -291,7 +292,7 @@ impl Binder {
291292
bind_context: &BindContext,
292293
with: &mut With,
293294
body: &mut SetExpr,
294-
) -> HashMap<String, HashSet<String>> {
295+
) -> HashMap<String, BTreeSet<String>> {
295296
if !bind_context.allow_virtual_column || with.recursive {
296297
return HashMap::new();
297298
}

src/query/sql/src/planner/format/display.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ where
192192
));
193193
}
194194

195-
if s_expr.plan.is_join() {
195+
if let RelOperator::MaterializedCTERef(_) = op {
196+
// MaterializedCTERef definitions are represented by their producer MaterializedCTE
197+
// in the surrounding Sequence.
198+
} else if s_expr.plan.is_join() {
196199
tree.children
197200
.push(self.humanize_s_expr(s_expr.build_side_child())?);
198201
tree.children

src/query/sql/src/planner/format/display_rel_operator.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use crate::plans::Exchange;
2626
use crate::plans::Filter;
2727
use crate::plans::Join;
2828
use crate::plans::Limit;
29+
use crate::plans::MaterializedCTE;
30+
use crate::plans::MaterializedCTERef;
2931
use crate::plans::Mutation;
3032
use crate::plans::Operator;
3133
use crate::plans::RelOperator;
@@ -63,6 +65,10 @@ fn to_format_tree<I: IdHumanizer>(id_humanizer: &I, op: &RelOperator) -> FormatT
6365
RelOperator::ConstantTableScan(op) => constant_scan_to_format_tree(id_humanizer, op),
6466
RelOperator::UnionAll(op) => union_all_to_format_tree(id_humanizer, op),
6567
RelOperator::Mutation(op) => merge_into_to_format_tree(id_humanizer, op),
68+
RelOperator::MaterializedCTE(op) => materialized_cte_to_format_tree(op),
69+
RelOperator::MaterializedCTERef(op) => {
70+
materialized_cte_ref_to_format_tree(id_humanizer, op)
71+
}
6672
_ => FormatTreeNode::with_children(format!("{:?}", op), vec![]),
6773
}
6874
}
@@ -501,6 +507,44 @@ fn union_all_to_format_tree<I: IdHumanizer>(id_humanizer: &I, op: &UnionAll) ->
501507
FormatTreeNode::with_children(format!("{:?}", op.rel_op()), children)
502508
}
503509

510+
fn materialized_cte_to_format_tree(op: &MaterializedCTE) -> FormatTreeNode {
511+
FormatTreeNode::with_children("MaterializedCTE".to_string(), vec![
512+
FormatTreeNode::new(format!("cte_name: {}", op.cte_name)),
513+
FormatTreeNode::new(format!("ref_count: {}", op.ref_count)),
514+
FormatTreeNode::new(format!("channel_size: {:?}", op.channel_size)),
515+
])
516+
}
517+
518+
fn materialized_cte_ref_to_format_tree<I: IdHumanizer>(
519+
id_humanizer: &I,
520+
op: &MaterializedCTERef,
521+
) -> FormatTreeNode {
522+
let output_columns = op
523+
.output_columns
524+
.iter()
525+
.map(|idx| id_humanizer.humanize_column_id(*idx))
526+
.join(", ");
527+
528+
let column_mapping = op
529+
.column_mapping
530+
.iter()
531+
.sorted_by_key(|(from, to)| (**from, **to))
532+
.map(|(from, to)| {
533+
format!(
534+
"{} -> {}",
535+
id_humanizer.humanize_column_id(*from),
536+
id_humanizer.humanize_column_id(*to)
537+
)
538+
})
539+
.join(", ");
540+
541+
FormatTreeNode::with_children("MaterializedCTERef".to_string(), vec![
542+
FormatTreeNode::new(format!("cte_name: {}", op.cte_name)),
543+
FormatTreeNode::new(format!("output columns: [{}]", output_columns)),
544+
FormatTreeNode::new(format!("column mapping: [{}]", column_mapping)),
545+
])
546+
}
547+
504548
fn merge_into_to_format_tree<I: IdHumanizer>(
505549
id_humanizer: &I,
506550
merge_into: &Mutation,

src/query/sql/src/planner/optimizer/ir/expr/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
mod extract;
1616
mod m_expr;
1717
mod s_expr;
18+
mod type_validator;
1819
mod visitor;
1920

2021
pub use extract::Matcher;

0 commit comments

Comments
 (0)