mod aggregate;
mod analysis;
mod ast_depth;
mod expr;
mod normalize;
mod predicate;
mod prepare;
mod select;
#[cfg(feature = "sql-explain")]
use crate::db::sql::parser::SqlExplainMode;
use crate::db::{
query::intent::QueryError,
sql::parser::{SqlParseError, SqlStatement},
};
use icydb_diagnostic_code::SqlLoweringCode;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum SqlParameterPlacementReason {
BindingUnsupported,
UnboundExpressionLowering,
}
#[cfg(feature = "sql-explain")]
pub(in crate::db::sql::lowering) use aggregate::LoweredSqlGlobalAggregateCommand;
pub(crate) use aggregate::SqlGlobalAggregateCommand;
#[cfg(feature = "sql-explain")]
pub(crate) use aggregate::bind_lowered_sql_explain_global_aggregate_with_schema;
pub(in crate::db) use aggregate::compile_sql_global_aggregate_command_from_prepared_with_schema;
pub(crate) use aggregate::{
PreparedSqlScalarAggregatePlanFragment, PreparedSqlScalarAggregateStrategy,
};
pub(in crate::db::sql::lowering) use analysis::{
AnalyzedLoweredExpr, LoweredExprAnalysis, LoweredExprSourceRef, analyze_lowered_expr,
};
pub(in crate::db) use prepare::bind_sql_select_statement_structural_with_schema;
#[cfg(feature = "sql-explain")]
pub(crate) use prepare::lower_sql_explain_command_from_prepared_statement_with_schema;
pub(crate) use prepare::{
extract_prepared_sql_insert_statement, extract_prepared_sql_update_statement,
lower_prepared_sql_delete_statement, lower_prepared_sql_select_statement_with_schema,
prepare_sql_statement,
};
pub(crate) use select::LoweredDeleteShape;
pub(in crate::db::sql::lowering) use select::LoweredSqlFilter;
pub(in crate::db::sql::lowering) use select::apply_lowered_base_query_shape_with_schema;
#[cfg(feature = "sql-explain")]
pub(in crate::db) use select::bind_lowered_sql_query_structural_with_schema;
pub(in crate::db::sql::lowering) use select::validate_base_query_sql_capabilities;
pub(crate) use select::{LoweredBaseQueryShape, LoweredSelectShape};
pub(in crate::db) use select::{
bind_lowered_sql_delete_query_structural_with_schema,
bind_lowered_sql_select_query_structural_with_schema,
bind_sql_delete_statement_structural_with_schema,
bind_sql_update_selector_query_structural_with_schema,
};
#[derive(Clone, Debug)]
pub struct LoweredSqlCommand(pub(in crate::db::sql::lowering) LoweredSqlCommandInner);
#[derive(Clone, Debug)]
pub(in crate::db::sql::lowering) enum LoweredSqlCommandInner {
#[cfg(feature = "sql-explain")]
Explain {
mode: SqlExplainMode,
verbose: bool,
query: Box<LoweredSqlQuery>,
},
#[cfg(feature = "sql-explain")]
ExplainGlobalAggregate {
mode: SqlExplainMode,
verbose: bool,
command: Box<LoweredSqlGlobalAggregateCommand>,
},
}
impl LoweredSqlCommand {
#[cfg(feature = "sql-explain")]
#[must_use]
pub(in crate::db) const fn is_explain_lane(&self) -> bool {
matches!(
self.0,
LoweredSqlCommandInner::Explain { .. }
| LoweredSqlCommandInner::ExplainGlobalAggregate { .. }
)
}
#[cfg(feature = "sql-explain")]
#[must_use]
pub(in crate::db) fn explain_query(&self) -> Option<(SqlExplainMode, bool, &LoweredSqlQuery)> {
match &self.0 {
LoweredSqlCommandInner::Explain {
mode,
verbose,
query,
} => Some((*mode, *verbose, query.as_ref())),
LoweredSqlCommandInner::ExplainGlobalAggregate { .. } => None,
}
}
}
#[cfg(feature = "sql-explain")]
#[derive(Clone, Debug)]
pub(crate) enum LoweredSqlQuery {
Select(LoweredSelectShape),
Delete(LoweredBaseQueryShape),
}
#[derive(Debug)]
pub(crate) enum SqlLoweringError {
Parse(SqlParseError),
Query(Box<QueryError>),
EntityMismatch {
sql_entity: String,
expected_entity: String,
},
UnsupportedSelectProjection,
UnsupportedSelectDistinct,
DistinctOrderByRequiresProjectedTuple,
UnsupportedGlobalAggregateProjection,
GlobalAggregateDoesNotSupportGroupBy,
UnsupportedSelectGroupBy,
GroupedProjectionRequiresExplicitList,
GroupedProjectionRequiresAggregate,
GroupedProjectionReferencesNonGroupField {
index: usize,
},
GroupedProjectionScalarAfterAggregate {
index: usize,
},
HavingRequiresGroupBy,
UnsupportedSelectHaving,
UnsupportedAggregateInputExpressions,
UnsupportedWhereExpression,
UnknownField {
field: String,
},
UnsupportedParameterPlacement {
index: Option<usize>,
reason: SqlParameterPlacementReason,
},
UnsupportedSqlDdl,
#[cfg(feature = "sql-explain")]
UnexpectedQueryLaneStatement,
}
impl SqlLoweringError {
fn entity_mismatch(sql_entity: impl Into<String>, expected_entity: impl Into<String>) -> Self {
Self::EntityMismatch {
sql_entity: sql_entity.into(),
expected_entity: expected_entity.into(),
}
}
const fn unsupported_select_projection() -> Self {
Self::UnsupportedSelectProjection
}
#[cfg(feature = "sql-explain")]
pub(crate) const fn unexpected_query_lane_statement() -> Self {
Self::UnexpectedQueryLaneStatement
}
const fn unsupported_select_distinct() -> Self {
Self::UnsupportedSelectDistinct
}
const fn distinct_order_by_requires_projected_tuple() -> Self {
Self::DistinctOrderByRequiresProjectedTuple
}
const fn unsupported_global_aggregate_projection() -> Self {
Self::UnsupportedGlobalAggregateProjection
}
pub(crate) const fn unsupported_where_expression() -> Self {
Self::UnsupportedWhereExpression
}
const fn global_aggregate_does_not_support_group_by() -> Self {
Self::GlobalAggregateDoesNotSupportGroupBy
}
const fn unsupported_select_group_by() -> Self {
Self::UnsupportedSelectGroupBy
}
const fn grouped_projection_requires_explicit_list() -> Self {
Self::GroupedProjectionRequiresExplicitList
}
const fn grouped_projection_requires_aggregate() -> Self {
Self::GroupedProjectionRequiresAggregate
}
const fn grouped_projection_references_non_group_field(index: usize) -> Self {
Self::GroupedProjectionReferencesNonGroupField { index }
}
const fn grouped_projection_scalar_after_aggregate(index: usize) -> Self {
Self::GroupedProjectionScalarAfterAggregate { index }
}
const fn having_requires_group_by() -> Self {
Self::HavingRequiresGroupBy
}
const fn unsupported_select_having() -> Self {
Self::UnsupportedSelectHaving
}
const fn unsupported_aggregate_input_expressions() -> Self {
Self::UnsupportedAggregateInputExpressions
}
pub(crate) fn unknown_field(field: impl Into<String>) -> Self {
Self::UnknownField {
field: field.into(),
}
}
pub(crate) const fn unsupported_parameter_placement(
index: Option<usize>,
reason: SqlParameterPlacementReason,
) -> Self {
Self::UnsupportedParameterPlacement { index, reason }
}
pub(crate) const fn unsupported_sql_ddl() -> Self {
Self::UnsupportedSqlDdl
}
pub(crate) const fn compact_diagnostic_code(&self) -> Option<SqlLoweringCode> {
match self {
Self::EntityMismatch {
sql_entity,
expected_entity,
} => {
let _ = (sql_entity, expected_entity);
Some(SqlLoweringCode::EntityMismatch)
}
Self::UnsupportedSelectProjection => Some(SqlLoweringCode::SelectProjectionShape),
Self::UnsupportedSelectDistinct => Some(SqlLoweringCode::SelectDistinct),
Self::DistinctOrderByRequiresProjectedTuple => {
Some(SqlLoweringCode::DistinctOrderByProjection)
}
Self::UnsupportedGlobalAggregateProjection => {
Some(SqlLoweringCode::GlobalAggregateProjection)
}
Self::GlobalAggregateDoesNotSupportGroupBy => {
Some(SqlLoweringCode::GlobalAggregateGroupBy)
}
Self::UnsupportedSelectGroupBy => Some(SqlLoweringCode::SelectGroupByShape),
Self::GroupedProjectionRequiresExplicitList => {
Some(SqlLoweringCode::GroupedProjectionExplicitListRequired)
}
Self::GroupedProjectionRequiresAggregate => {
Some(SqlLoweringCode::GroupedProjectionAggregateRequired)
}
Self::GroupedProjectionReferencesNonGroupField { index } => {
let _ = index;
Some(SqlLoweringCode::GroupedProjectionNonGroupField)
}
Self::GroupedProjectionScalarAfterAggregate { index } => {
let _ = index;
Some(SqlLoweringCode::GroupedProjectionScalarAfterAggregate)
}
Self::HavingRequiresGroupBy => Some(SqlLoweringCode::HavingRequiresGroupBy),
Self::UnsupportedSelectHaving => Some(SqlLoweringCode::SelectHavingShape),
Self::UnsupportedAggregateInputExpressions => {
Some(SqlLoweringCode::AggregateInputExpressions)
}
Self::UnsupportedWhereExpression => Some(SqlLoweringCode::WhereExpressionShape),
Self::UnsupportedParameterPlacement { index, reason } => {
let _ = (index, reason);
Some(SqlLoweringCode::ParameterPlacement)
}
Self::UnsupportedSqlDdl => Some(SqlLoweringCode::SqlDdlExecutionUnsupported),
Self::Parse(_) | Self::Query(_) | Self::UnknownField { .. } => None,
#[cfg(feature = "sql-explain")]
Self::UnexpectedQueryLaneStatement => None,
}
}
}
impl From<QueryError> for SqlLoweringError {
fn from(value: QueryError) -> Self {
Self::Query(Box::new(value))
}
}
impl From<SqlParseError> for SqlLoweringError {
fn from(value: SqlParseError) -> Self {
Self::Parse(value)
}
}
#[derive(Clone, Debug)]
pub(crate) struct PreparedSqlStatement {
pub(in crate::db::sql::lowering) statement: SqlStatement,
}
impl PreparedSqlStatement {
#[must_use]
pub(in crate::db) const fn statement(&self) -> &SqlStatement {
&self.statement
}
#[must_use]
pub(in crate::db) fn into_statement(self) -> SqlStatement {
self.statement
}
}