diff --git a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
index 1b09399c20121..80e9187d68140 100644
--- a/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
+++ b/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
@@ -332,8 +332,9 @@ export class BaseQuery {
this.useNativeSqlPlanner = this.options.useNativeSqlPlanner ?? getEnv('nativeSqlPlanner');
this.canUseNativeSqlPlannerPreAggregation = false;
if (this.useNativeSqlPlanner && !this.neverUseSqlPlannerPreaggregation()) {
- const hasMultiStageMeasures = this.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true }).multiStageMembers.length > 0;
- this.canUseNativeSqlPlannerPreAggregation = hasMultiStageMeasures;
+ const fullAggregateMeasures = this.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true });
+
+ this.canUseNativeSqlPlannerPreAggregation = fullAggregateMeasures.multiStageMembers.length > 0 || fullAggregateMeasures.cumulativeMeasures.length > 0;
}
this.queryLevelJoinHints = this.options.joinHints ?? [];
this.prebuildJoin();
@@ -775,6 +776,13 @@ export class BaseQuery {
);
}
+ driverTools(external) {
+ if (external && !this.options.disableExternalPreAggregations && this.externalQueryClass) {
+ return this.externalQuery();
+ }
+ return this;
+ }
+
buildSqlAndParamsRust(exportAnnotatedSql) {
const order = this.options.order && R.pipe(
R.map((hash) => ((!hash || !hash.id) ? null : hash)),
diff --git a/packages/cubejs-schema-compiler/src/adapter/CubeStoreQuery.ts b/packages/cubejs-schema-compiler/src/adapter/CubeStoreQuery.ts
index 5717969612fd7..7ecc8c1aad79f 100644
--- a/packages/cubejs-schema-compiler/src/adapter/CubeStoreQuery.ts
+++ b/packages/cubejs-schema-compiler/src/adapter/CubeStoreQuery.ts
@@ -334,4 +334,13 @@ export class CubeStoreQuery extends BaseQuery {
}
);
}
+
+ public sqlTemplates() {
+ const templates = super.sqlTemplates();
+ templates.statements.time_series_select = '{% for time_item in seria %}' +
+ 'select to_timestamp(\'{{ time_item[0] }}\') date_from, to_timestamp(\'{{ time_item[1] }}\') date_to \n' +
+ '{% if not loop.last %} UNION ALL\n{% endif %}' +
+ '{% endfor %}';
+ return templates;
+ }
}
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs
index 6633f487858e4..1df0a7958a6e7 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/base_tools.rs
@@ -1,4 +1,5 @@
use super::base_query_options::FilterItem;
+use super::driver_tools::{DriverTools, NativeDriverTools};
use super::filter_group::{FilterGroup, NativeFilterGroup};
use super::filter_params::{FilterParams, NativeFilterParams};
use super::pre_aggregation_obj::{NativePreAggregationObj, PreAggregationObj};
@@ -16,12 +17,7 @@ use std::rc::Rc;
#[nativebridge::native_bridge]
pub trait BaseTools {
- fn convert_tz(&self, field: String) -> Result;
- fn time_grouped_column(
- &self,
- granularity: String,
- dimension: String,
- ) -> Result;
+ fn driver_tools(&self, external: bool) -> Result, CubeError>;
fn sql_templates(&self) -> Result, CubeError>;
fn security_context_for_rust(&self) -> Result, CubeError>;
fn sql_utils_for_rust(&self) -> Result, CubeError>;
@@ -33,10 +29,6 @@ pub trait BaseTools {
&self,
used_filters: Option>,
) -> Result, CubeError>;
- fn timestamp_precision(&self) -> Result;
- fn time_stamp_cast(&self, field: String) -> Result; //TODO move to templates
- fn date_time_cast(&self, field: String) -> Result; //TODO move to templates
- fn in_db_time_zone(&self, date: String) -> Result;
fn generate_time_series(
&self,
granularity: String,
@@ -49,23 +41,8 @@ pub trait BaseTools {
origin: String,
) -> Result>, CubeError>;
fn get_allocated_params(&self) -> Result, CubeError>;
- fn subtract_interval(&self, date: String, interval: String) -> Result;
- fn add_interval(&self, date: String, interval: String) -> Result;
- fn add_timestamp_interval(&self, date: String, interval: String) -> Result;
fn all_cube_members(&self, path: String) -> Result, CubeError>;
fn interval_and_minimal_time_unit(&self, interval: String) -> Result, CubeError>;
- //===== TODO Move to templates
- fn hll_init(&self, sql: String) -> Result;
- fn hll_merge(&self, sql: String) -> Result;
- fn hll_cardinality_merge(&self, sql: String) -> Result;
- fn count_distinct_approx(&self, sql: String) -> Result;
- fn date_bin(
- &self,
- interval: String,
- source: String,
- origin: String,
- ) -> Result;
-
fn get_pre_aggregation_by_name(
&self,
cube_name: String,
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs
new file mode 100644
index 0000000000000..31efcb3e94ee4
--- /dev/null
+++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/driver_tools.rs
@@ -0,0 +1,39 @@
+use super::sql_templates_render::{NativeSqlTemplatesRender, SqlTemplatesRender};
+use cubenativeutils::wrappers::serializer::{
+ NativeDeserialize, NativeDeserializer, NativeSerialize,
+};
+use cubenativeutils::wrappers::NativeContextHolder;
+use cubenativeutils::wrappers::NativeObjectHandle;
+use cubenativeutils::CubeError;
+use std::any::Any;
+use std::rc::Rc;
+
+#[nativebridge::native_bridge]
+pub trait DriverTools {
+ fn convert_tz(&self, field: String) -> Result;
+ fn time_grouped_column(
+ &self,
+ granularity: String,
+ dimension: String,
+ ) -> Result;
+ fn sql_templates(&self) -> Result, CubeError>;
+ fn timestamp_precision(&self) -> Result;
+ fn time_stamp_cast(&self, field: String) -> Result; //TODO move to templates
+ fn date_time_cast(&self, field: String) -> Result; //TODO move to templates
+ fn in_db_time_zone(&self, date: String) -> Result;
+ fn get_allocated_params(&self) -> Result, CubeError>;
+ fn subtract_interval(&self, date: String, interval: String) -> Result;
+ fn add_interval(&self, date: String, interval: String) -> Result;
+ fn add_timestamp_interval(&self, date: String, interval: String) -> Result;
+ fn interval_and_minimal_time_unit(&self, interval: String) -> Result, CubeError>;
+ fn hll_init(&self, sql: String) -> Result;
+ fn hll_merge(&self, sql: String) -> Result;
+ fn hll_cardinality_merge(&self, sql: String) -> Result;
+ fn count_distinct_approx(&self, sql: String) -> Result;
+ fn date_bin(
+ &self,
+ interval: String,
+ source: String,
+ origin: String,
+ ) -> Result;
+}
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs
index 995438cb995b1..1262ca05575c5 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/cube_bridge/mod.rs
@@ -6,6 +6,7 @@ pub mod case_item;
pub mod case_label;
pub mod cube_definition;
pub mod dimension_definition;
+pub mod driver_tools;
pub mod evaluator;
pub mod filter_group;
pub mod filter_params;
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/optimizers/pre_aggregation/optimizer.rs b/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/optimizers/pre_aggregation/optimizer.rs
index cf1e80b170918..1fff70496060f 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/optimizers/pre_aggregation/optimizer.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/optimizers/pre_aggregation/optimizer.rs
@@ -1,5 +1,4 @@
use super::*;
-use crate::cube_bridge::pre_aggregation_obj::PreAggregationObj;
use crate::logical_plan::*;
use crate::plan::FilterItem;
use crate::planner::query_tools::QueryTools;
@@ -29,7 +28,7 @@ impl MatchState {
pub struct PreAggregationOptimizer {
query_tools: Rc,
- used_pre_aggregations: HashMap<(String, String), Rc>,
+ used_pre_aggregations: HashMap<(String, String), Rc>,
}
impl PreAggregationOptimizer {
@@ -71,7 +70,7 @@ impl PreAggregationOptimizer {
Ok(None)
}
- pub fn get_used_pre_aggregations(&self) -> Vec> {
+ pub fn get_used_pre_aggregations(&self) -> Vec> {
self.used_pre_aggregations.values().cloned().collect()
}
@@ -445,15 +444,14 @@ impl PreAggregationOptimizer {
granularity: pre_aggregation.granularity.clone(),
table_name: table_name.clone(),
cube_name: pre_aggregation.cube_name.clone(),
+ pre_aggregation_obj,
};
+ let result = Rc::new(pre_aggregation);
self.used_pre_aggregations.insert(
- (
- pre_aggregation.cube_name.clone(),
- pre_aggregation.name.clone(),
- ),
- pre_aggregation_obj.clone(),
+ (result.cube_name.clone(), result.name.clone()),
+ result.clone(),
);
- Ok(Rc::new(pre_aggregation))
+ Ok(result)
} else {
Err(CubeError::internal(format!(
"Cannot find pre aggregation object for cube {} and name {}",
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/pre_aggregation.rs b/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/pre_aggregation.rs
index 7ed2add6d21f2..85ec32be2fbc4 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/pre_aggregation.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/logical_plan/pre_aggregation.rs
@@ -1,4 +1,5 @@
use super::*;
+use crate::cube_bridge::pre_aggregation_obj::PreAggregationObj;
use crate::planner::sql_evaluator::MemberSymbol;
use itertools::Itertools;
use std::rc::Rc;
@@ -13,6 +14,7 @@ pub struct PreAggregation {
pub granularity: Option,
pub table_name: String,
pub cube_name: String,
+ pub pre_aggregation_obj: Rc,
}
impl PrettyPrint for PreAggregation {
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/builder.rs b/rust/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/builder.rs
index aa98fb7cd4b83..e1eb80557b057 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/builder.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/physical_plan_builder/builder.rs
@@ -41,15 +41,14 @@ impl PhysicalPlanBuilderContext {
pub struct PhysicalPlanBuilder {
query_tools: Rc,
- _plan_sql_templates: PlanSqlTemplates,
+ plan_sql_templates: PlanSqlTemplates,
}
impl PhysicalPlanBuilder {
- pub fn new(query_tools: Rc) -> Self {
- let plan_sql_templates = query_tools.plan_sql_templates();
+ pub fn new(query_tools: Rc, plan_sql_templates: PlanSqlTemplates) -> Self {
Self {
query_tools,
- _plan_sql_templates: plan_sql_templates,
+ plan_sql_templates,
}
}
@@ -102,6 +101,7 @@ impl PhysicalPlanBuilder {
) -> Result, CubeError> {
let mut render_references = HashMap::new();
let mut measure_references = HashMap::new();
+ let mut dimensions_references = HashMap::new();
let mut context_factory = context.make_sql_nodes_factory();
let from = match &logical_plan.source {
SimpleQuerySource::LogicalJoin(join) => self.process_logical_join(
@@ -114,8 +114,8 @@ impl PhysicalPlanBuilder {
let res = self.process_pre_aggregation(
pre_aggregation,
context,
- &mut render_references,
&mut measure_references,
+ &mut dimensions_references,
)?;
for member in logical_plan.schema.time_dimensions.iter() {
context_factory.add_dimensions_with_ignored_timezone(member.full_name());
@@ -128,6 +128,7 @@ impl PhysicalPlanBuilder {
let mut select_builder = SelectBuilder::new(from);
context_factory.set_ungrouped(logical_plan.ungrouped);
context_factory.set_pre_aggregation_measures_references(measure_references);
+ context_factory.set_pre_aggregation_dimensions_references(dimensions_references);
let mut group_by = Vec::new();
for member in logical_plan.schema.dimensions.iter() {
@@ -185,8 +186,8 @@ impl PhysicalPlanBuilder {
&self,
pre_aggregation: &Rc,
_context: &PhysicalPlanBuilderContext,
- render_references: &mut HashMap,
measure_references: &mut HashMap,
+ dimensions_references: &mut HashMap,
) -> Result, CubeError> {
let mut pre_aggregation_schema = Schema::empty();
let pre_aggregation_alias = PlanSqlTemplates::memeber_alias_name(
@@ -201,7 +202,7 @@ impl PhysicalPlanBuilder {
&dim.alias_suffix(),
self.query_tools.clone(),
)?;
- render_references.insert(
+ dimensions_references.insert(
dim.full_name(),
QualifiedColumnName::new(Some(pre_aggregation_alias.clone()), alias.clone()),
);
@@ -214,16 +215,10 @@ impl PhysicalPlanBuilder {
granularity,
self.query_tools.clone(),
)?;
- render_references.insert(
+ dimensions_references.insert(
dim.full_name(),
QualifiedColumnName::new(Some(pre_aggregation_alias.clone()), alias.clone()),
);
- if let Some(granularity) = &granularity {
- render_references.insert(
- format!("{}_{}", dim.full_name(), granularity),
- QualifiedColumnName::new(Some(pre_aggregation_alias.clone()), alias.clone()),
- );
- }
pre_aggregation_schema.add_column(SchemaColumn::new(alias, Some(dim.full_name())));
}
for meas in pre_aggregation.measures.iter() {
@@ -970,9 +965,7 @@ impl PhysicalPlanBuilder {
));
};
- let templates = self.query_tools.plan_sql_templates();
-
- let ts_date_range = if templates.supports_generated_time_series()
+ let ts_date_range = if self.plan_sql_templates.supports_generated_time_series()
&& granularity_obj.is_predefined_granularity()
{
if let Some(date_range) = time_dimension_symbol
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs b/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs
index 5998be84e3917..d7d7b896f191c 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/plan/join.rs
@@ -52,9 +52,7 @@ impl RegularRollingWindowJoinCondition {
};
let trailing_start = if let Some(trailing_interval) = &self.trailing_interval {
- templates
- .base_tools()
- .subtract_interval(start_date, trailing_interval.clone())?
+ templates.subtract_interval(start_date, trailing_interval.clone())?
} else {
start_date
};
@@ -72,9 +70,7 @@ impl RegularRollingWindowJoinCondition {
};
let leading_end = if let Some(leading_interval) = &self.leading_interval {
- templates
- .base_tools()
- .add_interval(end_date, leading_interval.clone())?
+ templates.add_interval(end_date, leading_interval.clone())?
} else {
end_date
};
@@ -121,7 +117,7 @@ pub struct ToDateRollingWindowJoinCondition {
time_series_source: String,
granularity: String,
time_dimension: Expr,
- query_tools: Rc,
+ _query_tools: Rc,
}
impl ToDateRollingWindowJoinCondition {
@@ -135,7 +131,7 @@ impl ToDateRollingWindowJoinCondition {
time_series_source,
granularity,
time_dimension,
- query_tools,
+ _query_tools: query_tools,
}
}
@@ -150,10 +146,7 @@ impl ToDateRollingWindowJoinCondition {
templates.column_reference(&Some(self.time_series_source.clone()), "date_to")?;
let date_to =
templates.column_reference(&Some(self.time_series_source.clone()), "date_from")?;
- let grouped_from = self
- .query_tools
- .base_tools()
- .time_grouped_column(self.granularity.clone(), date_from)?;
+ let grouped_from = templates.time_grouped_column(self.granularity.clone(), date_from)?;
let result = format!("{date_column} >= {grouped_from} and {date_column} <= {date_to}");
Ok(result)
}
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs b/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs
index 5661affe94f59..cdad6a3c9e20b 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/plan/time_series.rs
@@ -44,7 +44,6 @@ impl TimeSeries {
&& self.granularity.is_predefined_granularity()
{
let interval_description = templates
- .base_tools()
.interval_and_minimal_time_unit(self.granularity.granularity_interval().clone())?;
if interval_description.len() != 2 {
return Err(CubeError::internal(
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/base_query.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/base_query.rs
index 14651d0a4febf..681be99b46773 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/planner/base_query.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/base_query.rs
@@ -2,8 +2,9 @@ use super::planners::QueryPlanner;
use super::query_tools::QueryTools;
use super::QueryProperties;
use crate::cube_bridge::base_query_options::BaseQueryOptions;
-use crate::cube_bridge::pre_aggregation_obj::{NativePreAggregationObj, PreAggregationObj};
+use crate::cube_bridge::pre_aggregation_obj::NativePreAggregationObj;
use crate::logical_plan::optimizers::*;
+use crate::logical_plan::PreAggregation;
use crate::logical_plan::Query;
use crate::physical_plan_builder::PhysicalPlanBuilder;
use cubenativeutils::wrappers::inner_types::InnerTypes;
@@ -78,19 +79,30 @@ impl BaseQuery {
}
fn build_sql_and_params_impl(&self) -> Result, CubeError> {
- let templates = self.query_tools.plan_sql_templates();
let query_planner = QueryPlanner::new(self.request.clone(), self.query_tools.clone());
let logical_plan = query_planner.plan()?;
let (optimized_plan, used_pre_aggregations) =
self.try_pre_aggregations(logical_plan.clone())?;
- let physical_plan_builder = PhysicalPlanBuilder::new(self.query_tools.clone());
+ let is_external = if !used_pre_aggregations.is_empty() {
+ used_pre_aggregations
+ .iter()
+ .all(|pre_aggregation| pre_aggregation.external)
+ } else {
+ false
+ };
+
+ let templates = self.query_tools.plan_sql_templates(is_external)?;
+
+ let physical_plan_builder =
+ PhysicalPlanBuilder::new(self.query_tools.clone(), templates.clone());
let original_sql_pre_aggregations = if !self.request.is_pre_aggregation_query() {
OriginalSqlCollector::new(self.query_tools.clone()).collect(&optimized_plan)?
} else {
HashMap::new()
};
+
let physical_plan = physical_plan_builder.build(
optimized_plan,
original_sql_pre_aggregations,
@@ -98,7 +110,9 @@ impl BaseQuery {
)?;
let sql = physical_plan.to_sql(&templates)?;
- let (result_sql, params) = self.query_tools.build_sql_and_params(&sql, true)?;
+ let (result_sql, params) = self
+ .query_tools
+ .build_sql_and_params(&sql, true, &templates)?;
let res = self.context.empty_array()?;
res.set(0, result_sql.to_native(self.context.clone())?)?;
@@ -107,6 +121,7 @@ impl BaseQuery {
res.set(
2,
used_pre_aggregations
+ .pre_aggregation_obj
.clone()
.as_any()
.downcast::>()
@@ -122,7 +137,7 @@ impl BaseQuery {
fn try_pre_aggregations(
&self,
plan: Rc,
- ) -> Result<(Rc, Vec>), CubeError> {
+ ) -> Result<(Rc, Vec>), CubeError> {
let result = if !self.request.is_pre_aggregation_query() {
let mut pre_aggregation_optimizer =
PreAggregationOptimizer::new(self.query_tools.clone());
diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs
index fe3fa953d4bd8..e6d616c5c950c 100644
--- a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs
+++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs
@@ -1,8 +1,8 @@
use super::filter_operator::FilterOperator;
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_evaluator::MemberSymbol;
-use crate::planner::sql_templates::filter::FilterTemplates;
use crate::planner::sql_templates::PlanSqlTemplates;
+use crate::planner::sql_templates::TemplateProjectionColumn;
use crate::planner::QueryDateTimeHelper;
use crate::planner::{evaluate_with_context, FiltersContext, VisitorContext};
use cubenativeutils::CubeError;
@@ -26,7 +26,6 @@ pub struct BaseFilter {
filter_operator: FilterOperator,
values: Vec