use super::super::ScriptExecutor;
use crate::ast::{JoinClause, SelectAssignStmt, SelectItem, TableRef};
use crate::catalog::Catalog;
use crate::error::DbError;
use crate::executor::context::ExecutionContext;
use crate::executor::evaluator::eval_expr;
use crate::executor::query::plan::{
FilterPlan, PaginationPlan, ProjectionPlan, RelationalQuery, SortPlan,
};
use crate::executor::query::QueryExecutor;
use crate::executor::result::QueryResult;
use crate::executor::value_ops::coerce_value_to_type_with_dateformat;
use crate::storage::Storage;
fn build_from_clause(from: Option<TableRef>, joins: &[JoinClause]) -> Option<crate::ast::FromNode> {
let mut node = from.map(crate::ast::FromNode::Table)?;
for join in joins {
node = crate::ast::FromNode::Join {
left: Box::new(node),
join_type: join.join_type,
right: Box::new(crate::ast::FromNode::Table(join.table.clone())),
on: join.on.clone(),
};
}
Some(node)
}
impl<'a> ScriptExecutor<'a> {
pub(crate) fn execute_select_assign(
&mut self,
stmt: SelectAssignStmt,
ctx: &mut ExecutionContext<'_>,
) -> Result<Option<QueryResult>, DbError> {
if stmt.targets.is_empty() {
return Ok(None);
}
if stmt.from.is_none() {
for t in stmt.targets {
let val = eval_expr(&t.expr, &[], ctx, self.catalog, self.storage, self.clock)?;
if let Some((ty, var)) = ctx.session.variables.get_mut(&t.variable) {
*var = coerce_value_to_type_with_dateformat(val, ty, &ctx.options.dateformat)?;
} else {
return Err(DbError::invalid_identifier(&t.variable));
}
}
return Ok(None);
}
let q = RelationalQuery {
from_clause: build_from_clause(stmt.from, &stmt.joins),
applies: vec![],
projection: ProjectionPlan {
items: stmt
.targets
.iter()
.map(|t| SelectItem {
expr: t.expr.clone(),
alias: None,
})
.collect(),
distinct: false,
},
filter: FilterPlan {
selection: stmt.selection,
group_by: vec![],
having: None,
},
sort: SortPlan { order_by: vec![] },
pagination: PaginationPlan {
top: None,
offset: None,
fetch: None,
},
into_table: None,
set_op: None,
};
let result = QueryExecutor {
catalog: self.catalog as &dyn Catalog,
storage: self.storage as &dyn Storage,
clock: self.clock,
}
.execute_select(q, ctx)?;
if let Some(last) = result.rows.last() {
for (idx, t) in stmt.targets.iter().enumerate() {
if let Some((ty, var)) = ctx.session.variables.get_mut(&t.variable) {
*var = coerce_value_to_type_with_dateformat(
last[idx].clone(),
ty,
&ctx.options.dateformat,
)?;
} else {
return Err(DbError::invalid_identifier(&t.variable));
}
}
}
Ok(None)
}
}