Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::pretty_print::*;
use crate::plan::{Filter, FilterItem};
use crate::planner::filter::{Filter, FilterItem};
use itertools::Itertools;

#[derive(Default)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use itertools::Itertools;

use crate::logical_plan::*;
use crate::plan::FilterItem;
use crate::planner::filter::FilterItem;
use crate::planner::sql_evaluator::MemberSymbol;
use std::rc::Rc;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use super::CompiledPreAggregation;
use crate::plan::filter::FilterGroupOperator;
use crate::plan::FilterItem;
use crate::planner::filter::BaseFilter;
use crate::planner::filter::{BaseFilter, FilterGroupOperator, FilterItem};
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::DimensionSymbol;
use crate::planner::sql_evaluator::MemberSymbol;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::PreAggregationsCompiler;
use super::*;
use crate::logical_plan::visitor::{LogicalPlanRewriter, NodeRewriteResult};
use crate::logical_plan::*;
use crate::plan::FilterItem;
use crate::planner::filter::FilterItem;
use crate::planner::filter::FilterOp;
use crate::planner::join_hints::JoinHints;
use crate::planner::multi_fact_join_groups::{MeasuresJoinHints, MultiFactJoinGroups};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::plan::FilterItem;
use crate::planner::filter::FilterItem;
use crate::planner::sql_evaluator::MemberSymbol;
use std::rc::Rc;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::plan::{
AliasedExpr, Cte, Expr, Filter, From, FromSource, MemberExpression, OrderBy,
QualifiedColumnName, Schema, SchemaColumn, Select, SingleAliasedSource, SingleSource,
AliasedExpr, Cte, Expr, From, FromSource, MemberExpression, OrderBy, QualifiedColumnName,
Schema, SchemaColumn, Select, SingleAliasedSource, SingleSource,
};
use crate::planner::filter::Filter;

use crate::plan::expression::FunctionExpression;
use crate::planner::query_tools::QueryTools;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use super::ToSql;
use crate::planner::filter::typed_filter::resolve_base_symbol;
use crate::planner::filter::BaseFilter;
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::sql_nodes::SqlNode;
use crate::planner::sql_evaluator::SqlEvaluatorVisitor;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::FiltersContext;
use cubenativeutils::CubeError;
use std::rc::Rc;

impl ToSql for BaseFilter {
fn to_sql(
&self,
visitor: &SqlEvaluatorVisitor,
node_processor: Rc<dyn SqlNode>,
query_tools: Rc<QueryTools>,
templates: &PlanSqlTemplates,
filters_ctx: &FiltersContext,
) -> Result<String, CubeError> {
if !filters_ctx.filter_params_columns.is_empty() {
let symbol_to_match =
resolve_base_symbol(self.raw_member_evaluator_ref()).resolve_reference_chain();
if let Some(filter_params_column) = filters_ctx
.filter_params_columns
.get(&symbol_to_match.full_name())
{
return self.typed_filter().to_sql_for_filter_params(
filter_params_column,
templates,
filters_ctx,
);
}
}
self.typed_filter()
.to_sql(visitor, node_processor, query_tools, templates, filters_ctx)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use super::ToSql;
use crate::planner::filter::BaseSegment;
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::sql_nodes::SqlNode;
use crate::planner::sql_evaluator::SqlEvaluatorVisitor;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::FiltersContext;
use cubenativeutils::CubeError;
use std::rc::Rc;

impl ToSql for BaseSegment {
fn to_sql(
&self,
visitor: &SqlEvaluatorVisitor,
node_processor: Rc<dyn SqlNode>,
_query_tools: Rc<QueryTools>,
templates: &PlanSqlTemplates,
_filters_ctx: &FiltersContext,
) -> Result<String, CubeError> {
visitor.apply(&self.member_evaluator(), node_processor, templates)
}
}
86 changes: 86 additions & 0 deletions rust/cube/cubesqlplanner/cubesqlplanner/src/plan/filter/filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use super::ToSql;
use crate::planner::filter::{Filter, FilterItem};
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::sql_nodes::SqlNode;
use crate::planner::sql_evaluator::SqlEvaluatorVisitor;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::FiltersContext;
use cubenativeutils::CubeError;
use std::rc::Rc;

impl ToSql for FilterItem {
fn to_sql(
&self,
visitor: &SqlEvaluatorVisitor,
node_processor: Rc<dyn SqlNode>,
query_tools: Rc<QueryTools>,
templates: &PlanSqlTemplates,
filters_ctx: &FiltersContext,
) -> Result<String, CubeError> {
let res = match self {
FilterItem::Group(group) => {
let operator = format!(" {} ", group.operator.to_string());
let items_sql = group
.items
.iter()
.map(|itm| {
itm.to_sql(
visitor,
node_processor.clone(),
query_tools.clone(),
templates,
filters_ctx,
)
})
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.filter(|itm| !itm.is_empty())
.collect::<Vec<_>>();
if items_sql.is_empty() {
"".to_string()
} else {
let result = items_sql.join(&operator);
format!("({})", result)
}
}
FilterItem::Item(item) => {
let sql =
item.to_sql(visitor, node_processor, query_tools, templates, filters_ctx)?;
format!("({})", sql)
}
FilterItem::Segment(item) => {
let sql =
item.to_sql(visitor, node_processor, query_tools, templates, filters_ctx)?;
format!("({})", sql)
}
};
Ok(res)
}
}

impl ToSql for Filter {
fn to_sql(
&self,
visitor: &SqlEvaluatorVisitor,
node_processor: Rc<dyn SqlNode>,
query_tools: Rc<QueryTools>,
templates: &PlanSqlTemplates,
filters_ctx: &FiltersContext,
) -> Result<String, CubeError> {
let res = self
.items
.iter()
.map(|itm| {
itm.to_sql(
visitor,
node_processor.clone(),
query_tools.clone(),
templates,
filters_ctx,
)
})
.collect::<Result<Vec<_>, _>>()?
.join(" AND ");
Ok(res)
}
}
10 changes: 10 additions & 0 deletions rust/cube/cubesqlplanner/cubesqlplanner/src/plan/filter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub mod base_filter;
pub mod base_segment;
pub mod filter;
pub(crate) mod operators;
pub mod render_filter;
pub mod to_sql;
pub mod typed_filter;

pub use render_filter::{render_filter, render_filter_item};
pub use to_sql::ToSql;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use super::{FilterOperationSql, FilterSqlContext};
use crate::planner::filter::operators::comparison::{ComparisonKind, ComparisonOp};
use cubenativeutils::CubeError;

impl FilterOperationSql for ComparisonOp {
fn to_sql(&self, ctx: &FilterSqlContext) -> Result<String, CubeError> {
let param = ctx.allocate_and_cast(&self.value, &self.member_type)?;
match self.kind {
ComparisonKind::Gt => ctx.plan_templates.gt(ctx.member_sql.to_string(), param),
ComparisonKind::Gte => ctx.plan_templates.gte(ctx.member_sql.to_string(), param),
ComparisonKind::Lt => ctx.plan_templates.lt(ctx.member_sql.to_string(), param),
ComparisonKind::Lte => ctx.plan_templates.lte(ctx.member_sql.to_string(), param),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use super::{FilterOperationSql, FilterSqlContext};
use crate::planner::filter::operators::date_range::{DateRangeKind, DateRangeOp};
use cubenativeutils::CubeError;

impl FilterOperationSql for DateRangeOp {
fn to_sql(&self, ctx: &FilterSqlContext) -> Result<String, CubeError> {
let from_param = ctx.format_and_allocate_from_date(&self.from)?;
let to_param = ctx.format_and_allocate_to_date(&self.to)?;
match self.kind {
DateRangeKind::InRange => ctx.plan_templates.time_range_filter(
ctx.member_sql.to_string(),
from_param,
to_param,
),
DateRangeKind::NotInRange => ctx.plan_templates.time_not_in_range_filter(
ctx.member_sql.to_string(),
from_param,
to_param,
),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use super::{FilterOperationSql, FilterSqlContext};
use crate::planner::filter::operators::date_single::{DateSingleKind, DateSingleOp};
use cubenativeutils::CubeError;

impl FilterOperationSql for DateSingleOp {
fn to_sql(&self, ctx: &FilterSqlContext) -> Result<String, CubeError> {
match self.kind {
DateSingleKind::Before | DateSingleKind::AfterOrOn => {
let param = ctx.format_and_allocate_from_date(&self.value)?;
match self.kind {
DateSingleKind::Before => {
ctx.plan_templates.lt(ctx.member_sql.to_string(), param)
}
DateSingleKind::AfterOrOn => {
ctx.plan_templates.gte(ctx.member_sql.to_string(), param)
}
_ => unreachable!(),
}
}
DateSingleKind::BeforeOrOn | DateSingleKind::After => {
let param = ctx.format_and_allocate_to_date(&self.value)?;
match self.kind {
DateSingleKind::BeforeOrOn => {
ctx.plan_templates.lte(ctx.member_sql.to_string(), param)
}
DateSingleKind::After => {
ctx.plan_templates.gt(ctx.member_sql.to_string(), param)
}
_ => unreachable!(),
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use super::{FilterOperationSql, FilterSqlContext};
use crate::planner::filter::operators::equality::EqualityOp;
use cubenativeutils::CubeError;

impl FilterOperationSql for EqualityOp {
fn to_sql(&self, ctx: &FilterSqlContext) -> Result<String, CubeError> {
let param = ctx.allocate_and_cast(&self.value, &self.member_type)?;
// For negated (notEquals), add OR IS NULL check when value is not null
let need_null_check = self.negated;
if self.negated {
ctx.plan_templates
.not_equals(ctx.member_sql.to_string(), param, need_null_check)
} else {
ctx.plan_templates
.equals(ctx.member_sql.to_string(), param, false)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::{FilterOperationSql, FilterSqlContext};
use crate::planner::filter::operators::in_list::InListOp;
use cubenativeutils::CubeError;

impl FilterOperationSql for InListOp {
fn to_sql(&self, ctx: &FilterSqlContext) -> Result<String, CubeError> {
let has_null = self.values.iter().any(|v| v.is_none());
let need_null_check = if self.negated { !has_null } else { has_null };
let allocated = ctx.allocate_and_cast_values(&self.values, &self.member_type)?;

if self.negated {
ctx.plan_templates
.not_in_where(ctx.member_sql.to_string(), allocated, need_null_check)
} else {
ctx.plan_templates
.in_where(ctx.member_sql.to_string(), allocated, need_null_check)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use super::{FilterOperationSql, FilterSqlContext};
use crate::planner::filter::operators::like::LikeOp;
use cubenativeutils::CubeError;

impl FilterOperationSql for LikeOp {
fn to_sql(&self, ctx: &FilterSqlContext) -> Result<String, CubeError> {
let allocated = ctx.allocate_and_cast_values(
&self
.values
.iter()
.map(|v| Some(v.clone()))
.collect::<Vec<_>>(),
&self.member_type,
)?;

let like_parts = allocated
.into_iter()
.map(|v| {
ctx.plan_templates.ilike(
ctx.member_sql,
&v,
self.start_wild,
self.end_wild,
self.negated,
)
})
.collect::<Result<Vec<_>, _>>()?;

let logical_symbol = if self.negated { " AND " } else { " OR " };
let need_null_check = if self.negated {
!self.has_null
} else {
self.has_null
};
let null_check = if need_null_check {
ctx.plan_templates
.or_is_null_check(ctx.member_sql.to_string())?
} else {
"".to_string()
};

Ok(format!(
"({}){}",
like_parts.join(logical_symbol),
null_check
))
}
}
Loading
Loading