use super::{
Binder, BoundAggregate, BoundExpr, BoundSource, BoundWindow, CteBinding, RecursiveTarget,
};
use crate::ast;
#[derive(Default)]
pub struct BinderScratch {
sources: Vec<BoundSource>,
scopes: Vec<Vec<usize>>,
aggregates: Vec<BoundAggregate>,
result_aliases: Vec<(Vec<u8>, BoundExpr)>,
schemas: Vec<(usize, u32)>,
ctes: Vec<Vec<CteBinding>>,
recursing: Vec<RecursiveTarget>,
binding_ctes: Vec<ast::SelectId>,
correlations: Vec<usize>,
windows: Vec<BoundWindow>,
named_windows: Vec<(Vec<u8>, ast::WindowId)>,
firing: Vec<Vec<u8>>,
firing_foreign_keys: Vec<Vec<u8>>,
pending_constraints: Vec<BoundExpr>,
}
impl BinderScratch {
pub fn new() -> BinderScratch {
BinderScratch::default()
}
fn clear(&mut self) {
self.sources.clear();
self.scopes.clear();
self.aggregates.clear();
self.result_aliases.clear();
self.schemas.clear();
self.ctes.clear();
self.recursing.clear();
self.binding_ctes.clear();
self.correlations.clear();
self.windows.clear();
self.named_windows.clear();
self.firing.clear();
self.firing_foreign_keys.clear();
self.pending_constraints.clear();
}
}
pub(super) struct BlockFrame {
windows: Vec<BoundWindow>,
named_windows: Vec<(Vec<u8>, ast::WindowId)>,
aggregates: Vec<BoundAggregate>,
result_aliases: Vec<(Vec<u8>, BoundExpr)>,
allow_aggregates: bool,
inside_aggregate: bool,
correlations: Vec<usize>,
tail_may_name_an_alias: bool,
}
impl<'a> Binder<'a> {
pub fn with_scratch(mut self, mut scratch: BinderScratch) -> Binder<'a> {
scratch.clear();
self.sources = scratch.sources;
self.scopes = scratch.scopes;
self.aggregates = scratch.aggregates;
self.result_aliases = scratch.result_aliases;
self.dependencies.schemas = scratch.schemas;
self.ctes = scratch.ctes;
self.recursing = scratch.recursing;
self.binding_ctes = scratch.binding_ctes;
self.correlations = scratch.correlations;
self.windows = scratch.windows;
self.named_windows = scratch.named_windows;
self.firing = scratch.firing;
self.firing_foreign_keys = scratch.firing_foreign_keys;
self.pending_constraints = scratch.pending_constraints;
self
}
pub fn into_scratch(self) -> BinderScratch {
BinderScratch {
sources: self.sources,
scopes: self.scopes,
aggregates: self.aggregates,
result_aliases: self.result_aliases,
schemas: self.dependencies.schemas,
ctes: self.ctes,
recursing: self.recursing,
binding_ctes: self.binding_ctes,
correlations: self.correlations,
windows: self.windows,
named_windows: self.named_windows,
firing: self.firing,
firing_foreign_keys: self.firing_foreign_keys,
pending_constraints: self.pending_constraints,
}
}
pub(super) fn enter_block(&mut self) -> BlockFrame {
self.scopes.push(Vec::new());
BlockFrame {
windows: core::mem::take(&mut self.windows),
named_windows: core::mem::take(&mut self.named_windows),
aggregates: core::mem::take(&mut self.aggregates),
result_aliases: core::mem::take(&mut self.result_aliases),
allow_aggregates: core::mem::replace(&mut self.allow_aggregates, false),
inside_aggregate: core::mem::replace(&mut self.inside_aggregate, false),
correlations: core::mem::take(&mut self.correlations),
tail_may_name_an_alias: self.tail_may_name_an_alias,
}
}
pub(super) fn leave_block(&mut self, frame: BlockFrame) -> Vec<usize> {
let ids = self.scopes.pop().unwrap_or_default();
let inner = core::mem::replace(&mut self.correlations, frame.correlations);
for id in inner {
if ids.contains(&id) {
continue;
}
let owned = self.scopes.last().is_some_and(|scope| scope.contains(&id));
if !owned && !self.correlations.contains(&id) {
self.correlations.push(id);
}
}
self.windows = frame.windows;
self.named_windows = frame.named_windows;
self.aggregates = frame.aggregates;
self.result_aliases = frame.result_aliases;
self.allow_aggregates = frame.allow_aggregates;
self.inside_aggregate = frame.inside_aggregate;
self.tail_may_name_an_alias = frame.tail_may_name_an_alias;
ids
}
}