MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / normalize_subqueries

Function normalize_subqueries

src/sql/src/plan/explain.rs:83–151  ·  view source on GitHub ↗

Normalize the way subqueries appear in [`HirScalarExpr::Exists`] or [`HirScalarExpr::Select`] variants. After the transform is applied, subqueries are pulled as a value in a let binding enclosing the [`HirRelationExpr`] parent of the [`HirScalarExpr::Exists`] or [`HirScalarExpr::Select`] where the subquery appears, and the corresponding variant references the new binding with a [`HirRelationExpr:

(expr: &'a mut HirRelationExpr)

Source from the content-addressed store, hash-verified

81/// subquery appears, and the corresponding variant references the
82/// new binding with a [`HirRelationExpr::Get`].
83pub fn normalize_subqueries<'a>(expr: &'a mut HirRelationExpr) {
84 // A helper struct to represent accumulated `$local_id = $subquery`
85 // bindings that need to be installed in `let ... in $expr` nodes
86 // that wrap their parent $expr.
87 struct Binding {
88 local_id: LocalId,
89 subquery: HirRelationExpr,
90 }
91
92 // Context for the transformation
93 // - a stack of bindings
94 let mut bindings = Vec::<Binding>::new();
95 // - a generator of fresh local ids
96 let mut id_gen = id_gen(expr).peekable();
97
98 // Grow the `bindings` stack by collecting subqueries appearing in
99 // one of the HirScalarExpr children at the given HirRelationExpr.
100 // As part of this, the subquery is replaced by a `Get(id)` for a
101 // fresh local id.
102 let mut collect_subqueries = |expr: &mut HirRelationExpr, bindings: &mut Vec<Binding>| {
103 expr.visit_mut_children(|expr: &mut HirScalarExpr| {
104 use HirRelationExpr::Get;
105 use HirScalarExpr::{Exists, Select};
106 expr.visit_mut_post(&mut |expr: &mut HirScalarExpr| match expr {
107 Exists(expr, _) | Select(expr, _) => match expr.as_mut() {
108 Get { .. } => (),
109 expr => {
110 // generate fresh local id
111 let local_id = id_gen.next().unwrap();
112 // generate a `Get(local_id)` to be used as a subquery replacement
113 let mut subquery = Get {
114 id: Id::Local(local_id.clone()),
115 typ: SqlRelationType::empty(), // TODO (aalexandrov)
116 };
117 // swap the current subquery with the replacement
118 std::mem::swap(expr, &mut subquery);
119 // push a new $local_id = $subquery binding for a wrapping Let { ... }
120 bindings.push(Binding { local_id, subquery });
121 }
122 },
123 _ => (),
124 });
125 });
126 };
127
128 // Drain the `bindings` stack by wrapping the given `HirRelationExpr` with
129 // a sequence of `Let { ... }` nodes, one for each binding.
130 let insert_let_bindings = |expr: &mut HirRelationExpr, bindings: &mut Vec<Binding>| {
131 for binding in bindings.drain(..) {
132 let name = format!("subquery-{}", Into::<u64>::into(&binding.local_id));
133 let id = binding.local_id;
134 let value = Box::new(binding.subquery);
135 let body = Box::new(expr.take());
136 *expr = HirRelationExpr::Let {
137 name,
138 id,
139 value,
140 body,

Callers 1

Calls 10

visit_mut_postMethod · 0.80
unwrapMethod · 0.80
id_genFunction · 0.70
visit_mut_childrenMethod · 0.45
as_mutMethod · 0.45
nextMethod · 0.45
cloneMethod · 0.45
pushMethod · 0.45
drainMethod · 0.45
takeMethod · 0.45

Tested by

no test coverage detected