@@ -639,6 +639,16 @@ export class PreAggregations {
639639 transformedQuery . allBackAliasMembers [ r ] || r
640640 ) ) ;
641641
642+ const buildPath = ( cube : string ) : string [ ] => {
643+ const path = [ cube ] ;
644+ const parentMap = transformedQuery . joinsMap ;
645+ while ( parentMap [ cube ] ) {
646+ cube = parentMap [ cube ] ;
647+ path . push ( cube ) ;
648+ }
649+ return path . reverse ( ) ;
650+ } ;
651+
642652 /**
643653 * Determine whether pre-aggregation can be used or not.
644654 */
@@ -647,8 +657,32 @@ export class PreAggregations {
647657 const qryTimeDimensions = references . allowNonStrictDateRangeMatch
648658 ? transformedQuery . timeDimensions
649659 : transformedQuery . sortedTimeDimensions ;
650- const backAliasMeasures = backAlias ( references . measures ) ;
651- const backAliasDimensions = backAlias ( references . dimensions ) ;
660+
661+ let dimsToMatch : string [ ] ;
662+ let measToMatch : string [ ] ;
663+
664+ if ( references . rollups . length > 0 ) {
665+ // In 'rollupJoin' / 'rollupLambda' pre-aggregations fullName members will be empty, because there are
666+ // no connections in the joinTree between cubes from different datasources
667+ // but joinGraph of the query has all the connections, necessary for serving the query,
668+ // so we use this information to complete the full paths of members from the root of the query
669+ // up to the pre-agg cube.
670+ // We use references from the underlying pre-aggregations, filtered with members existing in the root
671+ // pre-aggregation itself.
672+
673+ dimsToMatch = references . rollupsReferences
674+ . flatMap ( rolRef => rolRef . fullNameDimensions )
675+ . filter ( d => references . dimensions . some ( rd => d . endsWith ( rd ) ) ) ;
676+ measToMatch = references . rollupsReferences
677+ . flatMap ( rolRef => rolRef . fullNameMeasures )
678+ . filter ( m => references . measures . some ( rm => m . endsWith ( rm ) ) ) ;
679+ } else {
680+ dimsToMatch = references . fullNameDimensions ;
681+ measToMatch = references . fullNameMeasures ;
682+ }
683+
684+ const backAliasMeasures = backAlias ( measToMatch ) ;
685+ const backAliasDimensions = backAlias ( dimsToMatch ) ;
652686 return ( (
653687 transformedQuery . hasNoTimeDimensionsWithoutGranularity
654688 ) && (
@@ -741,7 +775,6 @@ export class PreAggregations {
741775
742776 let dimsToMatch : string [ ] ;
743777 let timeDimsToMatch : PreAggregationTimeDimensionReference [ ] ;
744- let dimensionsMatch : ( dimensions : string [ ] , doBackAlias : boolean ) => boolean ;
745778
746779 if ( references . rollups . length > 0 ) {
747780 // In 'rollupJoin' / 'rollupLambda' pre-aggregations fullName members will be empty, because there are
@@ -754,44 +787,28 @@ export class PreAggregations {
754787
755788 dimsToMatch = references . rollupsReferences
756789 . flatMap ( rolRef => rolRef . fullNameDimensions )
757- . filter ( d => references . dimensions . some ( rd => d . endsWith ( rd ) ) ) ;
758- timeDimsToMatch = references . rollupsReferences
759- . flatMap ( rolRef => rolRef . fullNameTimeDimensions )
760- . filter ( d => references . timeDimensions . some ( rd => d . dimension . endsWith ( rd . dimension ) ) ) ;
761-
762- const buildPath = ( cube : string ) : string [ ] => {
763- const path = [ cube ] ;
764- const parentMap = transformedQuery . joinsMap ;
765- while ( parentMap [ cube ] ) {
766- cube = parentMap [ cube ] ;
767- path . push ( cube ) ;
768- }
769- return path . reverse ( ) ;
770- } ;
771-
772- dimensionsMatch = ( dimensions , doBackAlias ) => {
773- let target = doBackAlias ? backAlias ( dimsToMatch ) : dimsToMatch ;
774- target = target . map ( dim => {
775- const [ cube , ...restPath ] = dim . split ( '.' ) ;
790+ . filter ( d => references . dimensions . some ( rd => d . endsWith ( rd ) ) )
791+ . map ( d => {
792+ const [ cube , ...restPath ] = d . split ( '.' ) ;
776793 if ( cube === transformedQuery . joinGraphRoot ) {
777- return dim ;
794+ return d ;
778795 }
779796 const path = buildPath ( cube ) ;
780797 return `${ path . join ( '.' ) } .${ restPath . join ( '.' ) } ` ;
781798 } ) ;
782-
783- return dimensions . every ( d => target . includes ( d ) ) ;
784- } ;
799+ timeDimsToMatch = references . rollupsReferences
800+ . flatMap ( rolRef => rolRef . fullNameTimeDimensions )
801+ . filter ( d => references . timeDimensions . some ( rd => d . dimension . endsWith ( rd . dimension ) ) ) ;
785802 } else {
786803 dimsToMatch = references . fullNameDimensions ;
787804 timeDimsToMatch = references . fullNameTimeDimensions ;
788-
789- dimensionsMatch = ( dimensions , doBackAlias ) => {
790- const target = doBackAlias ? backAlias ( dimsToMatch ) : dimsToMatch ;
791- return dimensions . every ( d => target . includes ( d ) ) ;
792- } ;
793805 }
794806
807+ const dimensionsMatch = ( dimensions , doBackAlias ) => {
808+ const target = doBackAlias ? backAlias ( dimsToMatch ) : dimsToMatch ;
809+ return dimensions . every ( d => target . includes ( d ) ) ;
810+ } ;
811+
795812 const timeDimensionsMatch = ( timeDimensionsList , doBackAlias ) => R . allPass (
796813 timeDimensionsList . map (
797814 tds => R . anyPass ( tds . map ( ( td : [ string , string ] ) => {
@@ -1005,10 +1022,28 @@ export class PreAggregations {
10051022 return this . query . cacheValue (
10061023 [ 'buildRollupJoin' , JSON . stringify ( preAggObj ) , JSON . stringify ( preAggObjsToJoin ) ] ,
10071024 ( ) => {
1025+ // It's important to build join graph not only using the pre-agg members, but also
1026+ // taking into account all explicit underlying rollup pre-aggregation joins, because
1027+ // otherwise the built join tree might differ from the actual pre-aggregation.
1028+ const preAggJoinsJoinHints = preAggObj . references . rollupsReferences . map ( r => {
1029+ if ( ! r . joinTree ) {
1030+ return [ ] ;
1031+ }
1032+
1033+ const hints : ( string | string [ ] ) [ ] = [ r . joinTree . root ] ;
1034+
1035+ for ( const j of r . joinTree . joins ) {
1036+ hints . push ( [ j . from , j . to ] ) ;
1037+ }
1038+
1039+ return hints ;
1040+ } ) . flat ( ) ;
10081041 const targetJoins = this . resolveJoinMembers (
1009- // TODO join hints?
1010- this . query . joinGraph . buildJoin ( this . cubesFromPreAggregation ( preAggObj ) )
1042+ this . query . joinGraph . buildJoin (
1043+ preAggJoinsJoinHints . concat ( this . cubesFromPreAggregation ( preAggObj ) )
1044+ )
10111045 ) ;
1046+ // const targetJoins = this.resolveJoinMembers(this.query.joinGraph.buildJoin(this.cubesFromPreAggregation(preAggObj)));
10121047 const existingJoins = R . unnest ( preAggObjsToJoin . map (
10131048 // TODO join hints?
10141049 p => this . resolveJoinMembers ( this . query . joinGraph . buildJoin ( this . cubesFromPreAggregation ( p ) ) )
@@ -1114,11 +1149,12 @@ export class PreAggregations {
11141149 preAggregationsToJoin . forEach ( preAgg => {
11151150 references . rollupsReferences . push ( preAgg . references ) ;
11161151 } ) ;
1152+ const canUsePreAggregationResult = canUsePreAggregation ( references ) ;
11171153 return {
11181154 ...preAggObj ,
1119- canUsePreAggregation : canUsePreAggregation ( references ) ,
1155+ canUsePreAggregation : canUsePreAggregationResult ,
11201156 preAggregationsToJoin,
1121- rollupJoin : this . buildRollupJoin ( preAggObj , preAggregationsToJoin )
1157+ rollupJoin : canUsePreAggregationResult ? this . buildRollupJoin ( preAggObj , preAggregationsToJoin ) : null ,
11221158 } ;
11231159 } else if ( preAggregation . type === 'rollupLambda' ) {
11241160 // TODO evaluation optimizations. Should be cached or moved to compile time.
0 commit comments