use super::logical_plan::{
children, own_exprs, walk_plan, Binding, BoundColumn, Expr, LogicalPlan,
};
use crate::reference::{ColumnRead, ColumnReference, ResolutionKind, TableRead};
pub(super) fn collect_reads(plan: &LogicalPlan) -> Vec<ColumnRead> {
let mut out = Vec::new();
reads_into(plan, &mut out);
out
}
pub(super) fn collect_table_reads(plan: &LogicalPlan) -> Vec<TableRead> {
let mut out = Vec::new();
walk_plan(plan, &mut |o| match o {
LogicalPlan::Scan(s) => out.push(TableRead {
reference: s.table.clone(),
resolution: s.resolution,
}),
LogicalPlan::CreateTableAs(c) => {
if let Some(schema_source) = &c.schema_source {
out.push(schema_source.source.clone());
}
}
_ => {}
});
let writes = super::tables::collect_table_writes(plan);
for read in collect_reads(plan) {
let Some(table) = &read.reference.table else {
continue;
};
if out.iter().any(|r| &r.reference == table) {
continue;
}
let resolution = writes
.iter()
.find(|w| &w.reference == table)
.map(|w| w.resolution)
.unwrap_or(read.resolution);
out.push(TableRead {
reference: table.clone(),
resolution,
});
}
out
}
fn reads_into(op: &LogicalPlan, out: &mut Vec<ColumnRead>) {
for expr in own_exprs(op) {
expr_reads(expr, out);
}
for child in children(op) {
reads_into(child, out);
}
if let LogicalPlan::With(w) = op {
for cte in &w.ctes {
reads_into(&cte.body, out);
}
}
}
fn expr_reads(expr: &Expr, out: &mut Vec<ColumnRead>) {
match expr {
Expr::Column(c) => out.extend(column_read(c)),
Expr::Fanin(refs) => out.extend(refs.iter().filter_map(column_read)),
_ => {}
}
for sub in expr
.value_subplans()
.into_iter()
.chain(expr.filter_subplans())
{
reads_into(sub, out);
}
for child in expr
.value_operands()
.into_iter()
.chain(expr.filter_operands())
{
expr_reads(child, out);
}
}
pub(super) fn column_read(c: &BoundColumn) -> Option<ColumnRead> {
let (table, resolution) = match &c.binding {
Binding::Base { table, resolution } => (Some(table.clone()), *resolution),
Binding::Unresolved => (None, ResolutionKind::Unresolved),
Binding::Ambiguous => (None, ResolutionKind::Ambiguous),
Binding::Derived | Binding::Local => return None,
};
Some(ColumnRead {
reference: ColumnReference {
table,
name: c.name.clone(),
},
resolution,
})
}