use crate::{
db::{
query::builder::scalar_projection::render_scalar_projection_expr_plan_label,
query::{
explain::ExplainExecutionNodeDescriptor,
plan::{
AccessPlannedQuery,
expr::{Expr, ProjectionField, ProjectionSpec},
},
},
},
model::field::FieldModel,
value::Value,
};
pub(in crate::db::session::sql) fn projection_labels_from_projection_spec(
projection: &ProjectionSpec,
) -> Vec<String> {
let mut labels = Vec::with_capacity(projection.len());
for field in projection.fields() {
match field {
ProjectionField::Scalar {
expr: _,
alias: Some(alias),
} => labels.push(alias.as_str().to_string()),
ProjectionField::Scalar { expr, alias: None } => {
labels.push(match expr {
Expr::Field(field) => field.as_str().to_string(),
Expr::Aggregate(aggregate) => {
let kind = aggregate.kind().canonical_label();
let distinct = if aggregate.is_distinct() {
"DISTINCT "
} else {
""
};
if let Some(input_expr) = aggregate.input_expr() {
let input = render_scalar_projection_expr_plan_label(input_expr);
format!("{kind}({distinct}{input})")
} else {
format!("{kind}({distinct}*)")
}
}
#[cfg(test)]
Expr::Alias { name, .. } => name.as_str().to_string(),
Expr::FieldPath(_)
| Expr::Literal(_)
| Expr::FunctionCall { .. }
| Expr::Case { .. }
| Expr::Binary { .. }
| Expr::Unary { .. } => render_scalar_projection_expr_plan_label(expr),
});
}
}
}
labels
}
pub(in crate::db::session::sql) fn projection_fixed_scales_from_projection_spec(
projection: &ProjectionSpec,
) -> Vec<Option<u32>> {
projection
.fields()
.map(|field| match field {
ProjectionField::Scalar { expr, .. } => {
let Expr::FunctionCall { function, args } = expr else {
return None;
};
function.fixed_decimal_scale(args)
}
})
.collect()
}
pub(in crate::db::session::sql) fn annotate_sql_projection_debug_on_execution_descriptor(
descriptor: &mut ExplainExecutionNodeDescriptor,
plan: &AccessPlannedQuery,
projection: &ProjectionSpec,
) {
let labels = projection_labels_from_projection_spec(projection)
.into_iter()
.map(Value::from)
.collect();
descriptor
.node_properties
.insert("proj_fields", Value::List(labels));
let materialization = if !plan.scalar_plan().mode.is_load()
|| plan.grouped_plan().is_some()
|| plan.scalar_projection_plan().is_none()
{
None
} else if descriptor.covering_scan() == Some(true) {
Some("covering_read")
} else {
let direct_slot_projection =
plan.frozen_direct_projection_slots()
.is_some_and(|direct_projection_slots| {
let projection = plan.frozen_projection_spec();
projection.len() == direct_projection_slots.len()
&& projection
.fields()
.all(|field| field.direct_field_name().is_some())
});
if direct_slot_projection {
Some("direct_slot_row")
} else {
Some("scalar_projection")
}
};
if let Some(materialization) = materialization {
descriptor
.node_properties
.insert("proj_materialization", Value::from(materialization));
}
}
pub(in crate::db::session::sql) fn projection_labels_from_fields(
fields: &'static [FieldModel],
) -> Vec<String> {
fields
.iter()
.map(|field| field.name().to_string())
.collect()
}