Skip to content

Commit c7cf712

Browse files
committed
fix(schema-compiler): Reject pre-agg if measure is unmultiplied in query but multiplied in pre-agg
1 parent e7f8c9f commit c7cf712

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3879,11 +3879,11 @@ export class BaseQuery {
38793879
* @returns {BaseQuery}
38803880
*/
38813881
// eslint-disable-next-line consistent-return
3882-
preAggregationQueryForSqlEvaluation(cube, preAggregation) {
3882+
preAggregationQueryForSqlEvaluation(cube, preAggregation, context = {}) {
38833883
if (preAggregation.type === 'autoRollup') {
38843884
return this.preAggregations.autoRollupPreAggregationQuery(cube, preAggregation);
38853885
} else if (preAggregation.type === 'rollup') {
3886-
return this.preAggregations.rollupPreAggregationQuery(cube, preAggregation);
3886+
return this.preAggregations.rollupPreAggregationQuery(cube, preAggregation, context);
38873887
} else if (preAggregation.type === 'originalSql') {
38883888
return this;
38893889
}

packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ export type PreAggregationForCube = {
4949
references: PreAggregationReferences;
5050
};
5151

52+
export type EvaluateReferencesContext = {
53+
inPreAggEvaluation?: boolean;
54+
};
55+
5256
export type BaseMember = BaseDimension | BaseMeasure | BaseFilter | BaseGroupFilter | BaseSegment;
5357

5458
export type CanUsePreAggregationFn = (references: PreAggregationReferences) => boolean;
@@ -582,12 +586,15 @@ export class PreAggregations {
582586
const dimensionsTrimmed = references
583587
.dimensions
584588
.map(d => CubeSymbols.joinHintFromPath(d).path);
589+
const multipliedMeasuresTrimmed = references
590+
.multipliedMeasures?.map(m => CubeSymbols.joinHintFromPath(m).path);
585591

586592
return {
587593
...references,
588594
dimensions: dimensionsTrimmed,
589595
measures: measuresTrimmed,
590596
timeDimensions: timeDimensionsTrimmed,
597+
multipliedMeasures: multipliedMeasuresTrimmed,
591598
};
592599
}
593600

@@ -722,6 +729,19 @@ export class PreAggregations {
722729
// TODO remove this in favor of matching with join path
723730
const referencesTrimmed = trimmedReferences(references);
724731

732+
// Even if there are no multiplied measures in the query (because no multiplier dimensions are requested)
733+
// but the same measures are multiplied in the pre-aggregation, we can't use pre-aggregation
734+
// for such queries.
735+
if (referencesTrimmed.multipliedMeasures) {
736+
const backAliasMultipliedMeasures = backAlias(referencesTrimmed.multipliedMeasures);
737+
738+
if (transformedQuery.leafMeasures.some(m => referencesTrimmed.multipliedMeasures.includes(m)) ||
739+
transformedQuery.measures.some(m => backAliasMultipliedMeasures.includes(m))
740+
) {
741+
return false;
742+
}
743+
}
744+
725745
const dimensionsMatch = (dimensions, doBackAlias) => R.all(
726746
d => (
727747
doBackAlias ?
@@ -1193,11 +1213,11 @@ export class PreAggregations {
11931213
);
11941214
}
11951215

1196-
public rollupPreAggregationQuery(cube: string, aggregation): BaseQuery {
1216+
public rollupPreAggregationQuery(cube: string, aggregation: PreAggregationDefinition, context: EvaluateReferencesContext = {}): BaseQuery {
11971217
// `this.evaluateAllReferences` will retain not only members, but their join path as well, and pass join hints
11981218
// to subquery. Otherwise, members in subquery would regenerate new join tree from clean state,
11991219
// and it can be different from expected by join path in pre-aggregation declaration
1200-
const references = this.evaluateAllReferences(cube, aggregation);
1220+
const references = this.evaluateAllReferences(cube, aggregation, null, context);
12011221
const cubeQuery = this.query.newSubQueryForCube(cube, {});
12021222
return this.query.newSubQueryForCube(cube, {
12031223
rowLimit: null,
@@ -1225,7 +1245,7 @@ export class PreAggregations {
12251245
});
12261246
}
12271247

1228-
public autoRollupPreAggregationQuery(cube: string, aggregation): BaseQuery {
1248+
public autoRollupPreAggregationQuery(cube: string, aggregation: PreAggregationDefinition): BaseQuery {
12291249
return this.query.newSubQueryForCube(
12301250
cube,
12311251
{
@@ -1266,13 +1286,18 @@ export class PreAggregations {
12661286
.toLowerCase();
12671287
}
12681288

1269-
private evaluateAllReferences(cube: string, aggregation: PreAggregationDefinition, preAggregationName: string | null = null): PreAggregationReferences {
1289+
private evaluateAllReferences(cube: string, aggregation: PreAggregationDefinition, preAggregationName: string | null = null, context: EvaluateReferencesOptions = {}): PreAggregationReferences {
12701290
// TODO build a join tree for all references, so they would always include full join path
12711291
// Even for preaggregation references without join path
12721292
// It is necessary to be able to match query and preaggregation based on full join tree
12731293

12741294
const evaluateReferences = () => {
12751295
const references = this.query.cubeEvaluator.evaluatePreAggregationReferences(cube, aggregation);
1296+
if (!context.inPreAggEvaluation) {
1297+
const preAggQuery = this.query.preAggregationQueryForSqlEvaluation(cube, aggregation, { inPreAggEvaluation: true });
1298+
const aggregateMeasures = preAggQuery?.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true });
1299+
references.multipliedMeasures = aggregateMeasures?.multipliedMeasures?.map(m => m.measure);
1300+
}
12761301
if (aggregation.type === 'rollupLambda') {
12771302
if (references.rollups.length > 0) {
12781303
const [firstLambdaCube] = this.query.cubeEvaluator.parsePath('preAggregations', references.rollups[0]);

packages/cubejs-schema-compiler/src/compiler/CubeEvaluator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export type PreAggregationReferences = {
121121
measures: Array<string>,
122122
timeDimensions: Array<PreAggregationTimeDimensionReference>,
123123
rollups: Array<string>,
124+
multipliedMeasures?: Array<string>,
124125
};
125126

126127
export type PreAggregationInfo = {

0 commit comments

Comments
 (0)