use super::PlannerError;
use crate::ast::dml::{NamedWindow, OrderByExpr, Select, SelectItem};
use crate::ast::expr::{Expr, ExprKind, WindowSpec};
use std::collections::{HashMap, HashSet};
pub(super) fn resolve_named_windows(stmt: &Select) -> Result<Select, PlannerError> {
let mut resolver = NamedWindowResolver::new(&stmt.windows)?;
resolver.validate_all()?;
let mut resolved = stmt.clone();
for item in &mut resolved.projection {
if let SelectItem::Expr { expr, .. } = item {
*expr = resolver.resolve_expr(expr)?;
}
}
if let Some(selection) = &mut resolved.selection {
*selection = resolver.resolve_expr(selection)?;
}
if let Some(group_by) = &mut resolved.group_by {
for item in group_by {
for expr in item.exprs_mut() {
*expr = resolver.resolve_expr(expr)?;
}
}
}
if let Some(having) = &mut resolved.having {
*having = resolver.resolve_expr(having)?;
}
if let Some(qualify) = &mut resolved.qualify {
*qualify = resolver.resolve_expr(qualify)?;
}
for order in &mut resolved.order_by {
order.expr = resolver.resolve_expr(&order.expr)?;
}
resolved.windows.clear();
Ok(resolved)
}
struct NamedWindowResolver {
definitions: HashMap<String, NamedWindow>,
definition_order: Vec<String>,
resolved: HashMap<String, WindowSpec>,
resolving: HashSet<String>,
}
impl NamedWindowResolver {
fn new(definitions: &[NamedWindow]) -> Result<Self, PlannerError> {
let mut by_name = HashMap::new();
let mut definition_order = Vec::with_capacity(definitions.len());
for definition in definitions {
let key = definition.name.to_ascii_lowercase();
if by_name.insert(key.clone(), definition.clone()).is_some() {
return Err(PlannerError::invalid_expression(format!(
"named window '{}' is defined more than once",
definition.name
)));
}
definition_order.push(key);
}
Ok(Self {
definitions: by_name,
definition_order,
resolved: HashMap::new(),
resolving: HashSet::new(),
})
}
fn validate_all(&mut self) -> Result<(), PlannerError> {
let names = self.definition_order.clone();
for name in names {
self.resolve_definition(&name)?;
}
Ok(())
}
fn resolve_definition(&mut self, name: &str) -> Result<WindowSpec, PlannerError> {
let key = name.to_ascii_lowercase();
if let Some(spec) = self.resolved.get(&key) {
return Ok(spec.clone());
}
let definition = self.definitions.get(&key).cloned().ok_or_else(|| {
PlannerError::invalid_expression(format!("named window '{name}' is not defined"))
})?;
if !self.resolving.insert(key.clone()) {
return Err(PlannerError::invalid_expression(format!(
"named window inheritance cycle involving '{}'",
definition.name
)));
}
let result = self.resolve_spec(&definition.spec);
self.resolving.remove(&key);
let spec = result?;
self.resolved.insert(key, spec.clone());
Ok(spec)
}
fn resolve_spec(&mut self, spec: &WindowSpec) -> Result<WindowSpec, PlannerError> {
let mut merged = if let Some(base_name) = &spec.base {
let inherited = self.resolve_definition(base_name)?;
if !spec.partition_by.is_empty() {
return Err(PlannerError::invalid_expression(format!(
"named window '{base_name}' cannot be overridden with PARTITION BY"
)));
}
if !spec.order_by.is_empty() && !inherited.order_by.is_empty() {
return Err(PlannerError::invalid_expression(format!(
"named window '{base_name}' already defines ORDER BY"
)));
}
if spec.frame.is_some() && inherited.frame.is_some() {
return Err(PlannerError::invalid_expression(format!(
"named window '{base_name}' already defines a frame"
)));
}
WindowSpec {
base: None,
partition_by: inherited.partition_by,
order_by: if spec.order_by.is_empty() {
inherited.order_by
} else {
spec.order_by.clone()
},
frame: spec.frame.clone().or(inherited.frame),
}
} else {
let mut local = spec.clone();
local.base = None;
local
};
merged.partition_by = merged
.partition_by
.iter()
.map(|expr| self.resolve_expr(expr))
.collect::<Result<Vec<_>, _>>()?;
merged.order_by = merged
.order_by
.iter()
.map(|order| {
Ok(OrderByExpr {
expr: self.resolve_expr(&order.expr)?,
asc: order.asc,
nulls_first: order.nulls_first,
span: order.span,
})
})
.collect::<Result<Vec<_>, PlannerError>>()?;
Ok(merged)
}
fn resolve_expr(&mut self, expr: &Expr) -> Result<Expr, PlannerError> {
let mut resolved = expr.clone();
match &mut resolved.kind {
ExprKind::BinaryOp { left, right, .. } => {
**left = self.resolve_expr(left)?;
**right = self.resolve_expr(right)?;
}
ExprKind::UnaryOp { operand, .. }
| ExprKind::Cast { expr: operand, .. }
| ExprKind::TryCast { expr: operand, .. }
| ExprKind::IsNull { expr: operand, .. }
| ExprKind::TruthPredicate { expr: operand, .. } => {
**operand = self.resolve_expr(operand)?;
}
ExprKind::IsDistinctFrom { left, right, .. } => {
**left = self.resolve_expr(left)?;
**right = self.resolve_expr(right)?;
}
ExprKind::Row { items } => {
for item in items {
*item = self.resolve_expr(item)?;
}
}
ExprKind::Case {
operand,
branches,
else_expr,
} => {
if let Some(operand) = operand {
**operand = self.resolve_expr(operand)?;
}
for branch in branches {
branch.when = self.resolve_expr(&branch.when)?;
branch.then = self.resolve_expr(&branch.then)?;
}
if let Some(else_expr) = else_expr {
**else_expr = self.resolve_expr(else_expr)?;
}
}
ExprKind::FunctionCall {
args,
order_by,
within_group,
filter,
over,
..
} => {
for arg in args {
*arg = self.resolve_expr(arg)?;
}
for order in order_by {
order.expr = self.resolve_expr(&order.expr)?;
}
for order in within_group {
order.expr = self.resolve_expr(&order.expr)?;
}
if let Some(filter) = filter {
**filter = self.resolve_expr(filter)?;
}
if let Some(spec) = over {
*spec = self.resolve_spec(spec)?;
}
}
ExprKind::Between {
expr, low, high, ..
} => {
**expr = self.resolve_expr(expr)?;
**low = self.resolve_expr(low)?;
**high = self.resolve_expr(high)?;
}
ExprKind::Like {
expr,
pattern,
escape,
..
} => {
**expr = self.resolve_expr(expr)?;
**pattern = self.resolve_expr(pattern)?;
if let Some(escape) = escape {
**escape = self.resolve_expr(escape)?;
}
}
ExprKind::InList { expr, list, .. } => {
**expr = self.resolve_expr(expr)?;
for item in list {
*item = self.resolve_expr(item)?;
}
}
ExprKind::InSubquery { expr, .. } | ExprKind::Quantified { expr, .. } => {
**expr = self.resolve_expr(expr)?;
}
ExprKind::Literal { .. }
| ExprKind::ColumnRef { .. }
| ExprKind::VectorLiteral { .. }
| ExprKind::ScalarSubquery { .. }
| ExprKind::Exists { .. } => {}
}
Ok(resolved)
}
}