@@ -418,10 +418,29 @@ export class BaseQuery {
418418 */
419419 get allJoinHints ( ) {
420420 if ( ! this . collectedJoinHints ) {
421+ let joinHints = this . collectJoinHints ( ) ;
422+ // let joinHints = this.collectJoinHintsFromMembers(this.allMembersConcat(false));
423+
424+ // One cube may join the other cube via transitive joined cubes,
425+ // members from which are referenced in the join `on` clauses.
426+ // We need to collect such join hints and push them upfront of the joining one.
427+ // It is important to use queryLevelJoinHints during the calculation if it is set.
428+
429+ const prevJoins = this . join ;
430+
431+ let newJoin = this . joinGraph . buildJoin ( [ ...this . queryLevelJoinHints , ...joinHints ] ) ;
432+ while ( ! R . equals ( this . join , newJoin ) ) {
433+ this . join = newJoin ;
434+ joinHints = R . uniq ( [ joinHints [ 0 ] , ...this . collectJoinHintsFromMembers ( this . joinMembersFromJoin ( ) ) , ...joinHints ] ) ;
435+ newJoin = this . joinGraph . buildJoin ( [ ...this . queryLevelJoinHints , ...joinHints ] ) ;
436+ }
437+
421438 this . collectedJoinHints = [
422439 ...this . queryLevelJoinHints ,
423- ...this . collectJoinHints ( ) ,
440+ ...joinHints ,
424441 ] ;
442+
443+ this . join = prevJoins ;
425444 }
426445 return this . collectedJoinHints ;
427446 }
@@ -2401,7 +2420,20 @@ export class BaseQuery {
24012420 } else if ( s . patchedMeasure ?. patchedFrom ) {
24022421 return [ s . patchedMeasure . patchedFrom . cubeName ] . concat ( this . evaluateSymbolSql ( s . patchedMeasure . patchedFrom . cubeName , s . patchedMeasure . patchedFrom . name , s . definition ( ) ) ) ;
24032422 } else {
2404- return this . evaluateSql ( s . cube ( ) . name , s . definition ( ) . sql ) ;
2423+ const res = this . evaluateSql ( s . cube ( ) . name , s . definition ( ) . sql ) ;
2424+ if ( s . isJoinCondition ) {
2425+ // In a join between Cube A and Cube B, sql() may reference members from other cubes.
2426+ // These referenced cubes must be added as join hints before Cube B to ensure correct SQL generation.
2427+ const targetCube = s . targetCubeName ( ) ;
2428+ const { joinHints } = this . safeEvaluateSymbolContext ( ) ;
2429+ let targetIdx = joinHints . findIndex ( e => e === targetCube ) ;
2430+ while ( targetIdx > - 1 ) {
2431+ joinHints . splice ( targetIdx , 1 ) ;
2432+ targetIdx = joinHints . findIndex ( e => e === targetCube ) ;
2433+ }
2434+ joinHints . push ( targetCube ) ;
2435+ }
2436+ return res ;
24052437 }
24062438 }
24072439
@@ -2438,23 +2470,27 @@ export class BaseQuery {
24382470 } ;
24392471 } ) ;
24402472
2441- const joinMembers = this . join ? this . join . joins . map ( j => ( {
2442- getMembers : ( ) => [ {
2443- path : ( ) => null ,
2444- cube : ( ) => this . cubeEvaluator . cubeFromPath ( j . originalFrom ) ,
2445- definition : ( ) => j . join ,
2446- } ]
2447- } ) ) : [ ] ;
2448-
24492473 const membersToCollectFrom = [
24502474 ...this . allMembersConcat ( excludeTimeDimensions ) ,
2451- ...joinMembers ,
2475+ ...this . joinMembersFromJoin ( ) ,
24522476 ...customSubQueryJoinMembers ,
24532477 ] ;
24542478
24552479 return this . collectJoinHintsFromMembers ( membersToCollectFrom ) ;
24562480 }
24572481
2482+ joinMembersFromJoin ( ) {
2483+ return this . join ? this . join . joins . map ( j => ( {
2484+ getMembers : ( ) => [ {
2485+ path : ( ) => null ,
2486+ cube : ( ) => this . cubeEvaluator . cubeFromPath ( j . originalFrom ) ,
2487+ definition : ( ) => j . join ,
2488+ isJoinCondition : true ,
2489+ targetCubeName : ( ) => j . originalTo ,
2490+ } ]
2491+ } ) ) : [ ] ;
2492+ }
2493+
24582494 collectJoinHintsFromMembers ( members ) {
24592495 return [
24602496 ...members . map ( m => m . joinHint ) . filter ( h => h ?. length > 0 ) ,
@@ -2770,7 +2806,7 @@ export class BaseQuery {
27702806
27712807 pushJoinHints ( joinHints ) {
27722808 if ( this . safeEvaluateSymbolContext ( ) . joinHints && joinHints ) {
2773- if ( joinHints . length === 1 ) {
2809+ if ( Array . isArray ( joinHints ) && joinHints . length === 1 ) {
27742810 [ joinHints ] = joinHints ;
27752811 }
27762812 this . safeEvaluateSymbolContext ( ) . joinHints . push ( joinHints ) ;
0 commit comments