use sqlparser::ast::{self, Select};
use super::cte_catalog::CteCatalog;
use super::derived_output::rekey_join_output;
use super::entry::plan_query;
use super::query_tail::QueryTail;
use super::select_stmt::{PlannedSelect, plan_select};
use crate::error::Result;
use crate::functions::registry::FunctionRegistry;
use crate::temporal::TemporalScope;
use crate::types::*;
pub(in crate::planner::select) fn try_plan_derived_from(
select: &Select,
catalog: &dyn SqlCatalog,
functions: &FunctionRegistry,
temporal: TemporalScope,
tail: &QueryTail<'_>,
statement_output: bool,
) -> Result<Option<PlannedSelect>> {
if select.from.len() != 1 {
return Ok(None);
}
let from = &select.from[0];
if !from.joins.is_empty() {
return Ok(None);
}
let (subquery, alias_ident) = match &from.relation {
ast::TableFactor::Derived {
lateral: false,
subquery,
alias: Some(alias),
..
} => (subquery, alias),
_ => return Ok(None),
};
let alias_name = crate::reserved::check_ast_identifier(&alias_ident.name)?;
let declared: Vec<String> = alias_ident
.columns
.iter()
.map(|column| crate::reserved::check_ast_identifier(&column.name))
.collect::<Result<_>>()?;
let inner_plan = plan_query(subquery, catalog, functions, temporal)?;
let relation = crate::resolver::derived::infer_subquery_relation(
catalog,
&alias_name,
subquery,
Some(&inner_plan),
functions,
temporal,
)?;
let derived_catalog = CteCatalog {
inner: catalog,
relations: vec![(
alias_name.clone(),
crate::resolver::derived::rename_output_columns(relation, &declared),
)],
};
let mut outer_select = select.clone();
outer_select.from[0].relation = ast::TableFactor::Table {
name: ast::ObjectName(vec![ast::ObjectNamePart::Identifier(
alias_ident.name.clone(),
)]),
alias: None,
args: None,
with_hints: Vec::new(),
version: None,
with_ordinality: false,
partitions: Vec::new(),
json_path: None,
sample: None,
index_hints: Vec::new(),
};
let outer = plan_select(
&outer_select,
&derived_catalog,
functions,
temporal,
tail,
statement_output,
)?;
Ok(Some(PlannedSelect {
plan: SqlPlan::Cte(CtePlan {
definitions: vec![(alias_name, rekey_join_output(inner_plan))],
outer: Box::new(outer.plan),
}),
scope: outer.scope,
}))
}