@@ -965,7 +965,7 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
965965 river->activate (csb);
966966
967967 bool sortCanBeUsed = true ;
968- SortNode* const orgSortNode = sort;
968+ const auto orgSortNode = sort;
969969
970970 // When DISTINCT and ORDER BY are done on different fields,
971971 // and ORDER BY can be mapped to an index, then the records
@@ -987,6 +987,8 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
987987 }
988988 else
989989 {
990+ fb_assert (isInnerJoin () || isSpecialJoin ());
991+
990992 // AB: If previous rsb's are already on the stack we can't use
991993 // a navigational-retrieval for an ORDER BY because the next
992994 // streams are JOINed to the previous ones
@@ -1001,61 +1003,45 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
10011003 ;
10021004 }
10031005
1004- StreamList joinStreams (compileStreams);
1005-
1006- if (isInnerJoin ())
1006+ if (compileStreams.hasData ())
10071007 {
1008- fb_assert (joinStreams. getCount () != 1 || csb-> csb_rpt [ joinStreams[ 0 ]]. csb_relation );
1008+ StreamList joinStreams (compileStreams );
10091009
1010- while ( true )
1010+ if ( isInnerJoin () )
10111011 {
1012- // AB: Determine which streams have an index relationship
1013- // with the currently active rivers. This is needed so that
1014- // no merge is made between a new cross river and the
1015- // currently active rivers. Where in the new cross river
1016- // a stream depends (index) on the active rivers.
1017- StreamList dependentStreams, freeStreams;
1018- findDependentStreams (joinStreams, dependentStreams, freeStreams);
1019-
1020- // If we have dependent and free streams then we can't rely on
1021- // the sort node to be used for index navigation
1022- if (dependentStreams.hasData () && freeStreams.hasData ())
1023- {
1024- sort = nullptr ;
1025- sortCanBeUsed = false ;
1026- }
1012+ fb_assert (joinStreams.getCount () != 1 || csb->csb_rpt [joinStreams[0 ]].csb_relation );
10271013
1028- if (dependentStreams.hasData ())
1029- {
1030- // Copy free streams
1031- joinStreams.assign (freeStreams);
1014+ // Process streams dependent on the priorly created rivers
10321015
1033- // Make rivers from the dependent streams
1034- generateInnerJoin (dependentStreams, rivers, &sort, rse->rse_plan );
1016+ if (joinDependentStreams (joinStreams, rivers, &sort))
1017+ {
1018+ // If we have dependent and free streams then we can't rely on
1019+ // the sort node to be used for index navigation
1020+ if (joinStreams.hasData ())
1021+ {
1022+ sortCanBeUsed = false ;
1023+ sort = nullptr ;
1024+ }
10351025
10361026 // Generate one river which holds a cross join rsb between
1037- // all currently available rivers
1027+ // all currently available rivers. This is needed to exclude
1028+ // dependent rivers from hashing or sort/merging that happens below.
10381029
10391030 rivers.add (FB_NEW_POOL (getPool ()) CrossJoin (this , rivers, INNER_JOIN));
10401031 rivers.back ()->activate (csb);
10411032 }
1042- else
1043- {
1044- if (freeStreams.hasData ())
1045- {
1046- // Deactivate streams from rivers on stack, because
1047- // the remaining streams don't have any indexed relationship with them
1048- for (const auto river : rivers)
1049- river->deactivate (csb);
1050- }
10511033
1052- break ;
1053- }
1034+ // Now process streams dependent on rivers that are dependent themselves
1035+
1036+ for (const auto depRiver : dependentRivers)
1037+ depRiver->activate (csb);
1038+
1039+ joinDependentStreams (joinStreams, dependentRivers, nullptr );
10541040 }
1055- }
10561041
1057- // Attempt to form joins in decreasing order of desirability
1058- generateInnerJoin (joinStreams, rivers, &sort, rse->rse_plan );
1042+ // Attempt to form joins in decreasing order of desirability
1043+ generateInnerJoin (joinStreams, rivers, &sort, rse->rse_plan );
1044+ }
10591045
10601046 if (rivers.isEmpty () && dependentRivers.isEmpty ())
10611047 {
@@ -2357,9 +2343,10 @@ unsigned Optimizer::distributeEqualities(BoolExprNodeStack& orgStack, unsigned b
23572343// Find the streams that can use an index with the currently active streams
23582344//
23592345
2360- void Optimizer::findDependentStreams (const StreamList& streams,
2361- StreamList& dependent_streams,
2362- StreamList& free_streams)
2346+ void Optimizer::findDependentStreams (const RiverList& rivers,
2347+ const StreamList& streams,
2348+ StreamList& dependentStreams,
2349+ StreamList& freeStreams)
23632350{
23642351#ifdef OPT_DEBUG_RETRIEVAL
23652352 if (streams.hasData ())
@@ -2373,7 +2360,7 @@ void Optimizer::findDependentStreams(const StreamList& streams,
23732360 // Set temporary active flag for this stream
23742361 tail->activate ();
23752362
2376- bool indexed_relationship = false ;
2363+ bool dependent = false ;
23772364
23782365 if (conjuncts.hasData ())
23792366 {
@@ -2387,19 +2374,85 @@ void Optimizer::findDependentStreams(const StreamList& streams,
23872374 const auto candidate = retrieval.getInversion ();
23882375
23892376 if (candidate->dependentFromStreams .hasData ())
2390- indexed_relationship = true ;
2377+ {
2378+ dependent = true ;
2379+
2380+ StreamList checkStreams;
2381+ checkStreams.add (stream);
2382+
2383+ for (const auto river : rivers)
2384+ {
2385+ // If some river already depends on this stream,
2386+ // then itself it cannot be dependent
2387+ if (river->isDependent (checkStreams))
2388+ {
2389+ dependent = false ;
2390+ break ;
2391+ }
2392+ }
2393+ }
23912394 }
23922395
2393- if (indexed_relationship )
2394- dependent_streams .add (stream);
2396+ if (dependent )
2397+ dependentStreams .add (stream);
23952398 else
2396- free_streams .add (stream);
2399+ freeStreams .add (stream);
23972400
23982401 // Reset active flag
23992402 tail->deactivate ();
24002403 }
24012404}
24022405
2406+ //
2407+ // Find streams dependent on the priorly created rivers and make a join from them
2408+ //
2409+
2410+ bool Optimizer::joinDependentStreams (StreamList& joinStreams, RiverList& rivers, SortNode** sort)
2411+ {
2412+ bool hasDependentStreams = false ;
2413+
2414+ while (true )
2415+ {
2416+ // AB: Determine which streams have an index relationship
2417+ // with the currently active rivers. This is needed so that
2418+ // no merge is made between a new cross river and the
2419+ // currently active rivers. Where in the new cross river
2420+ // a stream depends (index) on the active rivers.
2421+ StreamList dependentStreams, freeStreams;
2422+ findDependentStreams (rivers, joinStreams, dependentStreams, freeStreams);
2423+
2424+ // If we have dependent and free streams then we can't rely on
2425+ // the sort node to be used for index navigation
2426+ if (dependentStreams.hasData () && freeStreams.hasData ())
2427+ sort = nullptr ;
2428+
2429+ if (dependentStreams.hasData ())
2430+ {
2431+ hasDependentStreams = true ;
2432+
2433+ // Copy free streams
2434+ joinStreams.assign (freeStreams);
2435+
2436+ // Make rivers from the dependent streams
2437+ generateInnerJoin (dependentStreams, rivers, sort, rse->rse_plan );
2438+ }
2439+ else
2440+ {
2441+ if (freeStreams.hasData ())
2442+ {
2443+ // Deactivate streams from rivers on stack, because
2444+ // the remaining streams don't have any indexed relationship with them
2445+ for (const auto river : rivers)
2446+ river->deactivate (csb);
2447+ }
2448+
2449+ break ;
2450+ }
2451+ }
2452+
2453+ return hasDependentStreams;
2454+ };
2455+
24032456
24042457//
24052458// Form streams into rivers according to the user-specified plan
0 commit comments