Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tesseract): Pre-aggregation planning fallback #9230

Open
wants to merge 1 commit into
base: tesseract-exclude-values-from-filter-params
Choose a base branch
from
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
15 changes: 12 additions & 3 deletions packages/cubejs-backend-native/Cargo.lock

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

84 changes: 60 additions & 24 deletions packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,9 @@ export class BaseQuery {
return dimension;
}).filter(R.identity).map(this.newTimeDimension.bind(this));
this.allFilters = this.timeDimensions.concat(this.segments).concat(this.filters);
this.useNativeSqlPlanner = this.options.useNativeSqlPlanner ?? getEnv('nativeSqlPlanner');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add .default('false') to this env so the useNativeSqlPlanner can be always bool.

this.prebuildJoin();

if (!getEnv('nativeSqlPlanner')) {
// Tesseract doesn't require join to be prebuilt and there's a case where single join can't be built for multi-fact query
this.join = this.joinGraph.buildJoin(this.allJoinHints);
}
this.cubeAliasPrefix = this.options.cubeAliasPrefix;
this.preAggregationsSchemaOption = this.options.preAggregationsSchema ?? DEFAULT_PREAGGREGATIONS_SCHEMA;
this.externalQueryClass = this.options.externalQueryClass;
Expand All @@ -299,6 +297,15 @@ export class BaseQuery {
this.initUngrouped();
}

prebuildJoin() {
/* if (!this.useNativeSqlPlanner) { We still need this join for the follback to preaggregation to work properly. This condition should be returned after the tesseract starts working with pre-aggregations
// Tesseract doesn't require join to be prebuilt and there's a case where single join can't be built for multi-fact query
this.join = this.joinGraph.buildJoin(this.allJoinHints);
} */

this.join = this.joinGraph.buildJoin(this.allJoinHints);
}

cacheValue(key, fn, { contextPropNames, inputProps, cache } = {}) {
const currentContext = this.safeEvaluateSymbolContext();
if (contextPropNames) {
Expand Down Expand Up @@ -375,8 +382,7 @@ export class BaseQuery {
initUngrouped() {
this.ungrouped = this.options.ungrouped;
if (this.ungrouped) {
// this.join is not defined for Tesseract
if (!this.options.allowUngroupedWithoutPrimaryKey && !getEnv('nativeSqlPlanner')) {
if (!this.options.allowUngroupedWithoutPrimaryKey) {
const cubes = R.uniq([this.join.root].concat(this.join.joins.map(j => j.originalTo)));
const primaryKeyNames = cubes.flatMap(c => this.primaryKeyNames(c));
const missingPrimaryKeys = primaryKeyNames.filter(key => !this.dimensions.find(d => d.dimension === key));
Expand Down Expand Up @@ -603,33 +609,61 @@ export class BaseQuery {
return false;
}

newQueryNotUseNative() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
newQueryNotUseNative() {
newQueryWithoutNative() {

const QueryClass = this.constructor;
return new QueryClass(this.compilers, { ...this.options, useNativeSqlPlanner: false });
}

/**
* Returns a pair of SQL query string and parameter values for the query.
* @param {boolean} [exportAnnotatedSql] - returns annotated sql with not rendered params if true
* @returns {[string, Array<unknown>]}
*/
buildSqlAndParams(exportAnnotatedSql) {
if (getEnv('nativeSqlPlanner')) {
return this.buildSqlAndParamsRust(exportAnnotatedSql);
} else {
if (!this.options.preAggregationQuery && !this.options.disableExternalPreAggregations && this.externalQueryClass) {
if (this.externalPreAggregationQuery()) { // TODO performance
return this.externalQuery().buildSqlAndParams(exportAnnotatedSql);
if (!this.options.preAggregationQuery && !this.options.disableExternalPreAggregations && this.externalQueryClass) {
if (this.externalPreAggregationQuery()) { // TODO performance
return this.externalQuery().buildSqlAndParams(exportAnnotatedSql);
}
}

if (this.useNativeSqlPlanner) {
let isRelatedToPreAggregation = false;
if (this.options.preAggregationQuery) {
isRelatedToPreAggregation = true;
} else if (!this.options.disableExternalPreAggregations && this.externalQueryClass) {
if (this.externalPreAggregationQuery()) {
isRelatedToPreAggregation = true;
}
} else {
let preAggForQuery =
this.preAggregations.findPreAggregationForQuery();
if (this.options.disableExternalPreAggregations && preAggForQuery && preAggForQuery.preAggregation.external) {
preAggForQuery = undefined;
}
if (preAggForQuery) {
isRelatedToPreAggregation = true;
Comment on lines +640 to +644
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like these 2 ifs can be combined into one. Smth like:

if (!(this.options.disableExternalPreAggregations && 
preAggForQuery && 
preAggForQuery.preAggregation.external)) {
  isRelatedToPreAggregation = true;

}
}
return this.compilers.compiler.withQuery(
this,
() => this.cacheValue(
['buildSqlAndParams', exportAnnotatedSql],
() => this.paramAllocator.buildSqlAndParams(
this.buildParamAnnotatedSql(),
exportAnnotatedSql,
this.shouldReuseParams
),
{ cache: this.queryCache }
)
);

if (isRelatedToPreAggregation) {
return this.newQueryNotUseNative().buildSqlAndParams(exportAnnotatedSql);
}

return this.buildSqlAndParamsRust(exportAnnotatedSql);
}

return this.compilers.compiler.withQuery(
this,
() => this.cacheValue(
['buildSqlAndParams', exportAnnotatedSql],
() => this.paramAllocator.buildSqlAndParams(
this.buildParamAnnotatedSql(),
exportAnnotatedSql,
this.shouldReuseParams
),
{ cache: this.queryCache }
)
);
}

buildSqlAndParamsRust(exportAnnotatedSql) {
Expand Down Expand Up @@ -2960,6 +2994,7 @@ export class BaseQuery {
}

newSubQueryForCube(cube, options) {
options = { ...options, useNativeSqlPlanner: false }; // We not use tesseract for pre-aggregations generation yet
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
options = { ...options, useNativeSqlPlanner: false }; // We not use tesseract for pre-aggregations generation yet
options = { ...options, useNativeSqlPlanner: false }; // We don't use tesseract for pre-aggregations generation yet

if (this.options.queryFactory) {
// When dealing with rollup joins, it's crucial to use the correct parameter allocator for the specific cube in use.
// By default, we'll use BaseQuery, but it's important to note that different databases (Oracle, PostgreSQL, MySQL, Druid, etc.)
Expand All @@ -2983,6 +3018,7 @@ export class BaseQuery {
historyQueries: this.options.historyQueries,
externalQueryClass: this.options.externalQueryClass,
queryFactory: this.options.queryFactory,
useNativeSqlPlanner: this.options.useNativeSqlPlanner,
...options,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ export class PreAggregations {
}

preAggregationCubes() {
if (getEnv('nativeSqlPlanner')) {
// No join defined in Tesseract
return [];
}
const { join } = this.query;
return join.joins.map(j => j.originalTo).concat([join.root]);
}
Expand Down
1 change: 0 additions & 1 deletion rust/cubenativeutils/src/wrappers/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub trait NativeContext<IT: InnerTypes>: Clone {
fn null(&self) -> Result<NativeObjectHandle<IT>, CubeError>;
fn empty_array(&self) -> Result<IT::Array, CubeError>;
fn empty_struct(&self) -> Result<IT::Struct, CubeError>;
//fn boxed<T: 'static>(&self, value: T) -> impl NativeBox<IT, T>;
fn to_string_fn(&self, result: String) -> Result<IT::Function, CubeError>;
}

Expand Down
13 changes: 11 additions & 2 deletions rust/cubesqlplanner/Cargo.lock

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

2 changes: 1 addition & 1 deletion rust/cubesqlplanner/cubesqlplanner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ serde = "1.0.115"
serde_json = "1.0.56"
cubenativeutils = { path = "../../cubenativeutils/" }
minijinja = { version = "1", features = ["json", "loader"] }
convert_case = "0.6"
convert_case = "0.7.1"
chrono = "0.4.15"
chrono-tz = "0.8.2"
lazy_static = "1.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ use lazy_static::lazy_static;
use regex::Regex;
use std::rc::Rc;

const FROM_PARTITION_RANGE: &'static str = "__FROM_PARTITION_RANGE";

const TO_PARTITION_RANGE: &'static str = "__TO_PARTITION_RANGE";

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FilterType {
Dimension,
Expand Down Expand Up @@ -393,7 +397,7 @@ impl BaseFilter {
let from = if let Some(from_str) = &self.values[0] {
let from = self.format_from_date(&from_str)?;

if use_db_time_zone {
if use_db_time_zone && &from != FROM_PARTITION_RANGE {
self.query_tools.base_tools().in_db_time_zone(from)?
} else {
from
Expand All @@ -407,7 +411,7 @@ impl BaseFilter {
let to = if let Some(to_str) = &self.values[1] {
let to = self.format_to_date(&to_str)?;

if use_db_time_zone {
if use_db_time_zone && &to != TO_PARTITION_RANGE {
self.query_tools.base_tools().in_db_time_zone(to)?
} else {
to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ impl SimpleQueryPlanner {
}
let render_references = dimension_subquery_planner.dimensions_refs().clone();
context_factory.set_render_references(render_references);
context_factory.set_rendered_as_multiplied_measures(
self.query_properties
.full_key_aggregate_measures()?
.rendered_as_multiplied_measures
.clone(),
);
select_builder.set_filter(filter);
select_builder.set_group_by(self.query_properties.group_by());
select_builder.set_order_by(self.order_planner.default_order());
Expand Down
6 changes: 4 additions & 2 deletions rust/cubesqlplanner/cubesqlplanner/src/planner/query_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::plan::FilterItem;
use crate::planner::sql_evaluator::collectors::collect_join_hints;
use crate::planner::sql_templates::PlanSqlTemplates;
use chrono_tz::Tz;
use convert_case::{Case, Casing};
use convert_case::{Boundary, Case, Casing};
use cubenativeutils::CubeError;
use itertools::Itertools;
use lazy_static::lazy_static;
Expand Down Expand Up @@ -187,7 +187,9 @@ impl QueryTools {
}

pub fn alias_name(&self, name: &str) -> String {
name.to_case(Case::Snake).replace(".", "__")
name.without_boundaries(&[Boundary::LOWER_DIGIT, Boundary::UPPER_DIGIT])
.to_case(Case::Snake)
.replace(".", "__")
}

pub fn escaped_alias_name(&self, name: &str) -> String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{TemplateGroupByColumn, TemplateOrderByColumn, TemplateProjectionColumn};
use crate::cube_bridge::sql_templates_render::SqlTemplatesRender;
use crate::plan::join::JoinType;
use convert_case::{Case, Casing};
use convert_case::{Boundary, Case, Casing};
use cubenativeutils::CubeError;
use minijinja::context;
use std::rc::Rc;
Expand All @@ -17,7 +17,12 @@ impl PlanSqlTemplates {
}

pub fn alias_name(name: &str) -> String {
name.to_case(Case::Snake).replace(".", "__")
let res = name
.from_case(Case::Camel)
.without_boundaries(&[Boundary::LOWER_DIGIT, Boundary::UPPER_DIGIT])
.to_case(Case::Snake)
.replace(".", "__");
res
}

pub fn memeber_alias_name(cube_name: &str, name: &str, suffix: &Option<String>) -> String {
Expand Down
Loading