use sqlparser::ast;
use crate::error::{Result, SqlError};
use crate::functions::registry::FunctionRegistry;
use crate::planner::select::rekey_join_output;
use crate::resolver::columns::TableScope;
use crate::types::*;
pub(super) fn plan_derived_side(
factor: &ast::TableFactor,
scope: &TableScope,
catalog: &dyn SqlCatalog,
functions: &FunctionRegistry,
temporal: crate::TemporalScope,
) -> Result<Option<SqlPlan>> {
let ast::TableFactor::Derived {
lateral: false,
subquery,
alias,
..
} = factor
else {
return Ok(None);
};
let alias = alias.as_ref().ok_or_else(|| SqlError::Unsupported {
detail: "a subquery in a JOIN must have an alias: write JOIN (SELECT ...) AS name ON ..."
.into(),
})?;
let name = crate::reserved::check_ast_identifier(&alias.name)?;
let relation = scope
.table_by_ref(&name)
.ok_or_else(|| SqlError::UnknownTable { name: name.clone() })?;
let body = crate::planner::select::plan_query(subquery, catalog, functions, temporal)?;
Ok(Some(SqlPlan::Cte(CtePlan {
definitions: vec![(name.clone(), rekey_join_output(body))],
outer: Box::new(SqlPlan::Scan {
collection: name.clone(),
alias: Some(name),
engine: relation.info.engine,
filters: Vec::new(),
projection: Vec::new(),
sort_keys: Vec::new(),
limit: None,
offset: 0,
distinct: false,
window_functions: Vec::new(),
temporal: crate::TemporalScope::default(),
}),
})))
}