Skip to content

Commit 933b8f1

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

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
@@ -3787,11 +3787,11 @@ export class BaseQuery {
37873787
}
37883788

37893789
// eslint-disable-next-line consistent-return
3790-
preAggregationQueryForSqlEvaluation(cube, preAggregation) {
3790+
preAggregationQueryForSqlEvaluation(cube, preAggregation, context = {}) {
37913791
if (preAggregation.type === 'autoRollup') {
37923792
return this.preAggregations.autoRollupPreAggregationQuery(cube, preAggregation);
37933793
} else if (preAggregation.type === 'rollup') {
3794-
return this.preAggregations.rollupPreAggregationQuery(cube, preAggregation);
3794+
return this.preAggregations.rollupPreAggregationQuery(cube, preAggregation, context);
37953795
} else if (preAggregation.type === 'originalSql') {
37963796
return this;
37973797
}

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

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

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

5559
export type CanUsePreAggregationFn = (references: PreAggregationReferences) => boolean;
@@ -583,12 +587,15 @@ export class PreAggregations {
583587
const dimensionsTrimmed = references
584588
.dimensions
585589
.map(d => CubeSymbols.joinHintFromPath(d).path);
590+
const multipliedMeasuresTrimmed = references
591+
.multipliedMeasures?.map(m => CubeSymbols.joinHintFromPath(m).path);
586592

587593
return {
588594
...references,
589595
dimensions: dimensionsTrimmed,
590596
measures: measuresTrimmed,
591597
timeDimensions: timeDimensionsTrimmed,
598+
multipliedMeasures: multipliedMeasuresTrimmed,
592599
};
593600
}
594601

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

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

1174-
public rollupPreAggregationQuery(cube: string, aggregation): BaseQuery {
1194+
public rollupPreAggregationQuery(cube: string, aggregation: PreAggregationDefinition, context: EvaluateReferencesContext = {}): BaseQuery {
11751195
// `this.evaluateAllReferences` will retain not only members, but their join path as well, and pass join hints
11761196
// to subquery. Otherwise, members in subquery would regenerate new join tree from clean state,
11771197
// and it can be different from expected by join path in pre-aggregation declaration
1178-
const references = this.evaluateAllReferences(cube, aggregation);
1198+
const references = this.evaluateAllReferences(cube, aggregation, null, context);
11791199
const cubeQuery = this.query.newSubQueryForCube(cube, {});
11801200
return this.query.newSubQueryForCube(cube, {
11811201
rowLimit: null,
@@ -1203,7 +1223,7 @@ export class PreAggregations {
12031223
});
12041224
}
12051225

1206-
public autoRollupPreAggregationQuery(cube: string, aggregation): BaseQuery {
1226+
public autoRollupPreAggregationQuery(cube: string, aggregation: PreAggregationDefinition): BaseQuery {
12071227
return this.query.newSubQueryForCube(
12081228
cube,
12091229
{
@@ -1244,13 +1264,18 @@ export class PreAggregations {
12441264
.toLowerCase();
12451265
}
12461266

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

12521272
const evaluateReferences = () => {
12531273
const references = this.query.cubeEvaluator.evaluatePreAggregationReferences(cube, aggregation);
1274+
if (!context.inPreAggEvaluation) {
1275+
const preAggQuery = this.query.preAggregationQueryForSqlEvaluation(cube, aggregation, { inPreAggEvaluation: true });
1276+
const aggregateMeasures = preAggQuery?.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true });
1277+
references.multipliedMeasures = aggregateMeasures?.multipliedMeasures?.map(m => m.measure);
1278+
}
12541279
if (aggregation.type === 'rollupLambda') {
12551280
if (references.rollups.length > 0) {
12561281
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)