Skip to content
Open
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
4 changes: 2 additions & 2 deletions rust/cubesqlplanner/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl Compiler {
factory: T,
) -> Result<Rc<MemberSymbol>, CubeError> {
let node = factory.build(self)?;
node.validate()?;
let key = (T::symbol_name().to_string(), full_name.clone());
if T::is_cachable() {
self.members.insert(key, node.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use super::{symbols::MemberSymbol, SqlEvaluatorVisitor};
use crate::cube_bridge::member_sql::{FilterParamsColumn, SecutityContextProps, SqlTemplate};
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::sql_nodes::SqlNodesFactory;
use crate::planner::sql_evaluator::CubeNameSymbol;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::VisitorContext;
use cubenativeutils::CubeError;
use itertools::Itertools;
use std::collections::HashMap;
use std::rc::Rc;
use typed_builder::TypedBuilder;

pub struct SqlCallArg;

Expand Down Expand Up @@ -50,7 +50,7 @@ pub struct SqlCallFilterGroupItem {
pub filter_params: Vec<SqlCallFilterParamsItem>,
}

#[derive(Clone, TypedBuilder, Debug)]
#[derive(Clone, Debug)]
pub struct SqlCall {
template: SqlTemplate,
deps: Vec<SqlCallDependency>,
Expand All @@ -60,6 +60,22 @@ pub struct SqlCall {
}

impl SqlCall {
pub(super) fn new(
template: SqlTemplate,
deps: Vec<SqlCallDependency>,
filter_params: Vec<SqlCallFilterParamsItem>,
filter_groups: Vec<SqlCallFilterGroupItem>,
security_context: SecutityContextProps,
) -> Self {
Self {
template,
deps,
filter_params,
filter_groups,
security_context,
}
}

pub fn eval(
&self,
visitor: &SqlEvaluatorVisitor,
Expand All @@ -71,7 +87,6 @@ impl SqlCall {
let (filter_params, filter_groups, deps, context_values) =
self.prepare_template_params(visitor, node_processor, &query_tools, templates)?;

// Substitute placeholders in template in a single pass
Self::substitute_template(
template,
&deps,
Expand Down Expand Up @@ -122,6 +137,27 @@ impl SqlCall {
Ok(result)
}

pub fn is_owned_by_cube(&self) -> bool {
if self.deps.is_empty() {
true
} else {
self.deps.iter().any(|dep| dep.symbol.is_cube())
}
}

pub fn cube_name_deps(&self) -> Vec<Rc<CubeNameSymbol>> {
self.deps
.iter()
.filter_map(|dep| {
if let Ok(cube) = dep.symbol.as_cube_name() {
Some(cube.clone())
} else {
None
}
})
.collect()
}

fn prepare_template_params(
&self,
visitor: &SqlEvaluatorVisitor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ impl<'a> SqlCallBuilder<'a> {
.map(|itm| self.build_filter_group_item(itm))
.collect::<Result<Vec<_>, _>>()?;

let result = SqlCall::builder()
.template(template.clone())
.deps(deps)
.filter_params(filter_params)
.filter_groups(filter_groups)
.security_context(template_args.security_context.clone())
.build();
let result = SqlCall::new(
template.clone(),
deps,
filter_params,
filter_groups,
template_args.security_context.clone(),
);
Ok(result)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl CaseDefinition {
}
}

pub fn apply_to_deps<F: Fn(&Rc<MemberSymbol>) -> Result<Rc<MemberSymbol>, CubeError>>(
fn apply_to_deps<F: Fn(&Rc<MemberSymbol>) -> Result<Rc<MemberSymbol>, CubeError>>(
&self,
f: &F,
) -> Result<Self, CubeError> {
Expand All @@ -77,6 +77,18 @@ impl CaseDefinition {
let res = CaseDefinition { items, else_label };
Ok(res)
}

fn iter_sql_calls(&self) -> Box<dyn Iterator<Item = &Rc<SqlCall>> + '_> {
Box::new(self.items.iter().map(|item| &item.sql))
}

fn is_owned_by_cube(&self) -> bool {
let mut owned = false;
for itm in self.items.iter() {
owned |= itm.sql.is_owned_by_cube();
}
owned
}
}

#[derive(Clone)]
Expand Down Expand Up @@ -106,7 +118,7 @@ impl CaseSwitchItem {
}
}

pub fn apply_to_deps<F: Fn(&Rc<MemberSymbol>) -> Result<Rc<MemberSymbol>, CubeError>>(
fn apply_to_deps<F: Fn(&Rc<MemberSymbol>) -> Result<Rc<MemberSymbol>, CubeError>>(
&self,
f: &F,
) -> Result<Self, CubeError> {
Expand All @@ -116,6 +128,13 @@ impl CaseSwitchItem {
};
Ok(res)
}

fn iter_sql_calls(&self) -> Box<dyn Iterator<Item = &Rc<SqlCall>> + '_> {
match self {
CaseSwitchItem::Sql(sql_call) => Box::new(std::iter::once(sql_call)),
CaseSwitchItem::Member(_) => Box::new(std::iter::empty()),
}
}
}

#[derive(Clone)]
Expand Down Expand Up @@ -164,6 +183,32 @@ impl CaseSwitchDefinition {
}
values_len == 1
}

fn iter_sql_calls(&self) -> Box<dyn Iterator<Item = &Rc<SqlCall>> + '_> {
let result = self
.switch
.iter_sql_calls()
.chain(self.items.iter().map(|item| &item.sql));
if let Some(else_sql) = &self.else_sql {
Box::new(result.chain(std::iter::once(else_sql)))
} else {
Box::new(result)
}
}
fn is_owned_by_cube(&self) -> bool {
let mut owned = false;
if let CaseSwitchItem::Sql(sql) = &self.switch {
owned |= sql.is_owned_by_cube();
}
for itm in self.items.iter() {
owned |= itm.sql.is_owned_by_cube();
}
if let Some(sql) = &self.else_sql {
owned |= sql.is_owned_by_cube();
}
owned
}

fn extract_symbol_deps(&self, result: &mut Vec<Rc<MemberSymbol>>) {
self.switch.extract_symbol_deps(result);
for itm in self.items.iter() {
Expand Down Expand Up @@ -370,6 +415,19 @@ impl Case {
Case::CaseSwitch(case) => case.is_single_value(),
}
}

pub fn iter_sql_calls(&self) -> Box<dyn Iterator<Item = &Rc<SqlCall>> + '_> {
match self {
Case::Case(case) => Box::new(case.iter_sql_calls()),
Case::CaseSwitch(case) => Box::new(case.iter_sql_calls()),
}
}
pub fn is_owned_by_cube(&self) -> bool {
match self {
Case::Case(case) => case.is_owned_by_cube(),
Case::CaseSwitch(case) => case.is_owned_by_cube(),
}
}
}

impl crate::utils::debug::DebugSql for Case {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,16 @@ impl DimensionSymbol {
Ok(MemberSymbol::new_dimension(Rc::new(result)))
}

pub fn iter_sql_calls(&self) -> Box<dyn Iterator<Item = &Rc<SqlCall>> + '_> {
let result = self
.member_sql
.iter()
.chain(self.latitude.iter())
.chain(self.longitude.iter())
.chain(self.case.iter().flat_map(|case| case.iter_sql_calls()));
Box::new(result)
}

pub fn get_dependencies(&self) -> Vec<Rc<MemberSymbol>> {
let mut deps = vec![];
if let Some(member_sql) = &self.member_sql {
Expand Down Expand Up @@ -517,13 +527,27 @@ impl SymbolFactory for DimensionSymbolFactory {
None
};

let is_sub_query = definition.static_data().sub_query.unwrap_or(false);
let is_multi_stage = definition.static_data().multi_stage.unwrap_or(false);

//TODO move owned logic to rust
let owned_by_cube = definition.static_data().owned_by_cube.unwrap_or(true);
let owned_by_cube =
owned_by_cube && !is_multi_stage && definition.static_data().dimension_type != "switch";
let is_sub_query = definition.static_data().sub_query.unwrap_or(false);
let owned_by_cube = if is_multi_stage || dimension_type == "switch" {
false
} else {
let mut owned = false;
if let Some(sql) = &sql {
owned |= sql.is_owned_by_cube();
}
if let Some(sql) = &latitude {
owned |= sql.is_owned_by_cube();
}
if let Some(sql) = &longitude {
owned |= sql.is_owned_by_cube();
}
if let Some(case) = &case {
owned |= case.is_owned_by_cube();
}
owned
};
let is_reference = (is_view && is_sql_direct_ref)
|| (!owned_by_cube
&& !is_sub_query
Expand Down Expand Up @@ -595,12 +619,10 @@ impl SymbolFactory for DimensionSymbolFactory {

impl crate::utils::debug::DebugSql for DimensionSymbol {
fn debug_sql(&self, expand_deps: bool) -> String {
// Handle case expressions
if let Some(case) = &self.case {
return case.debug_sql(expand_deps);
}

// Handle geo dimensions (latitude/longitude pair)
if self.dimension_type == "geo" {
let lat = self
.latitude
Expand All @@ -615,12 +637,10 @@ impl crate::utils::debug::DebugSql for DimensionSymbol {
return format!("GEO({}, {})", lat, lon);
}

// Handle switch type dimensions without SQL
if self.dimension_type == "switch" && self.member_sql.is_none() {
return format!("SWITCH({})", self.full_name());
}

// Standard dimension SQL
let res = if let Some(sql) = &self.member_sql {
sql.debug_sql(expand_deps)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,16 @@ impl MeasureSymbol {
Ok(MemberSymbol::new_measure(Rc::new(result)))
}

pub fn iter_sql_calls(&self) -> Box<dyn Iterator<Item = &Rc<SqlCall>> + '_> {
//FIXME We don't include filters and order_by here for backward compatibility
// because BaseQuery doesn't validate these SQL calls
let result = self
.member_sql
.iter()
.chain(self.case.iter().flat_map(|case| case.iter_sql_calls()));
Box::new(result)
}

pub fn get_dependencies(&self) -> Vec<Rc<MemberSymbol>> {
let mut deps = vec![];
if let Some(member_sql) = &self.member_sql {
Expand Down Expand Up @@ -746,14 +756,32 @@ impl SymbolFactory for MeasureSymbolFactory {
None
};

let is_calculated =
MeasureSymbol::is_calculated_type(&definition.static_data().measure_type)
&& !definition.static_data().multi_stage.unwrap_or(false);
let measure_type = &definition.static_data().measure_type;
let is_calculated = MeasureSymbol::is_calculated_type(&measure_type)
&& !definition.static_data().multi_stage.unwrap_or(false);

let is_multi_stage = definition.static_data().multi_stage.unwrap_or(false);
//TODO move owned logic to rust
let owned_by_cube = definition.static_data().owned_by_cube.unwrap_or(true);
let owned_by_cube = owned_by_cube && !is_multi_stage;
let owned_by_cube = if is_multi_stage {
false
} else if measure_type == "count" && sql.is_none() {
true
} else {
let mut owned = false;
if let Some(sql) = &sql {
owned |= sql.is_owned_by_cube();
}
for sql in &measure_filters {
owned |= sql.is_owned_by_cube();
}
for sql in &measure_drill_filters {
owned |= sql.is_owned_by_cube();
}
if let Some(case) = &case {
owned |= case.is_owned_by_cube();
}
owned
};

let cube = cube_evaluator.cube_from_path(cube_name.clone())?;
let alias =
PlanSqlTemplates::memeber_alias_name(cube.static_data().resolved_alias(), &name, &None);
Expand Down
Loading
Loading