@@ -55,6 +55,15 @@ static ValueExprNode* resolveUsingField(DsqlCompilerScratch* dsqlScratch, const
5555
5656namespace
5757{
58+ struct SpecialJoinItem
59+ {
60+ RseNode* rse;
61+ bool semiJoin;
62+ BoolExprNode* boolean;
63+ };
64+
65+ typedef HalfStaticArray<SpecialJoinItem, 4 > SpecialJoinList;
66+
5867 // Search through the list of ANDed booleans to find comparisons
5968 // referring streams of parent select expressions.
6069 // Extract those booleans and return them to the caller.
@@ -112,18 +121,17 @@ namespace
112121 bool findPossibleJoins (CompilerScratch* csb,
113122 const StreamList& rseStreams,
114123 BoolExprNode** parentBoolean,
115- RecordSourceNodeStack& rseStack,
116- BoolExprNodeStack& booleanStack)
124+ SpecialJoinList& result)
117125 {
118126 auto boolNode = *parentBoolean;
119127
120128 const auto binaryNode = nodeAs<BinaryBoolNode>(boolNode);
121129 if (binaryNode && binaryNode->blrOp == blr_and)
122130 {
123131 const bool found1 = findPossibleJoins (csb, rseStreams,
124- binaryNode->arg1 .getAddress (), rseStack, booleanStack );
132+ binaryNode->arg1 .getAddress (), result );
125133 const bool found2 = findPossibleJoins (csb, rseStreams,
126- binaryNode->arg2 .getAddress (), rseStack, booleanStack );
134+ binaryNode->arg2 .getAddress (), result );
127135
128136 if (!binaryNode->arg1 && !binaryNode->arg2 )
129137 *parentBoolean = nullptr ;
@@ -142,7 +150,7 @@ namespace
142150 auto rse = rseNode->rse ;
143151 fb_assert (rse && (rse->flags & RseNode::FLAG_SUB_QUERY));
144152
145- if (rse->rse_boolean && rse->rse_jointype == blr_inner &&
153+ if (rse->rse_boolean && rse->isInnerJoin () &&
146154 !rse->rse_first && !rse->rse_skip && !rse->rse_plan )
147155 {
148156 // Find booleans convertable into semi-joins
@@ -187,9 +195,7 @@ namespace
187195 if (!dependent)
188196 {
189197 rse->flags &= ~RseNode::FLAG_SUB_QUERY;
190- rse->flags |= RseNode::FLAG_SEMI_JOINED;
191- rseStack.push (rse);
192- booleanStack.push (boolean);
198+ result.push ({rse, true , boolean});
193199 *parentBoolean = nullptr ;
194200 return true ;
195201 }
@@ -993,7 +999,7 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
993999 // 1) If the view has a projection, sort, first/skip or explicit plan.
9941000 // 2) If it's part of an outer join.
9951001
996- if (rse->rse_jointype != blr_inner || // viewRse->rse_jointype != blr_inner || ???
1002+ if (! rse->isInnerJoin () || // ! viewRse->isInnerJoin() || ???
9971003 viewRse->rse_sorted || viewRse->rse_projection || viewRse->rse_first ||
9981004 viewRse->rse_skip || viewRse->rse_plan )
9991005 {
@@ -2913,19 +2919,19 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
29132919
29142920 switch (rse_jointype)
29152921 {
2916- case blr_inner :
2922+ case INNER_JOIN :
29172923 streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
29182924 streamList->items [1 ] = doDsqlPass (dsqlScratch, fromList->items [1 ]);
29192925 break ;
29202926
2921- case blr_left :
2927+ case LEFT_JOIN :
29222928 streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
29232929 ++dsqlScratch->inOuterJoin ;
29242930 streamList->items [1 ] = doDsqlPass (dsqlScratch, fromList->items [1 ]);
29252931 --dsqlScratch->inOuterJoin ;
29262932 break ;
29272933
2928- case blr_right :
2934+ case RIGHT_JOIN :
29292935 ++dsqlScratch->inOuterJoin ;
29302936 streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
29312937 --dsqlScratch->inOuterJoin ;
@@ -2936,7 +2942,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
29362942 streamList->items [1 ] = doDsqlPass (dsqlScratch, fromList->items [1 ]);
29372943 break ;
29382944
2939- case blr_full :
2945+ case FULL_JOIN :
29402946 ++dsqlScratch->inOuterJoin ;
29412947 streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
29422948 // Temporarily remove just created context(s) from the stack,
@@ -3008,7 +3014,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
30083014 if (matched->items .isEmpty ())
30093015 {
30103016 // There is no match. Transform to CROSS JOIN.
3011- node->rse_jointype = blr_inner ;
3017+ node->rse_jointype = INNER_JOIN ;
30123018 usingList = NULL ;
30133019
30143020 delete matched;
@@ -3223,14 +3229,14 @@ RseNode* RseNode::pass1(thread_db* tdbb, CompilerScratch* csb)
32233229 ValueExprNode* skip = rse_skip;
32243230 PlanNode* plan = rse_plan;
32253231
3226- if (rse_jointype == blr_inner )
3232+ if (isInnerJoin () )
32273233 csb->csb_inner_booleans .push (rse_boolean);
32283234
32293235 // zip thru RseNode expanding views and inner joins
32303236 for (auto sub : rse_relations)
32313237 processSource (tdbb, csb, this , sub, &boolean, stack);
32323238
3233- if (rse_jointype == blr_inner )
3239+ if (isInnerJoin () )
32343240 csb->csb_inner_booleans .pop ();
32353241
32363242 // Now, rebuild the RseNode block.
@@ -3305,7 +3311,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
33053311 return ;
33063312 }
33073313
3308- if (rse_jointype != blr_inner )
3314+ if (isOuterJoin () )
33093315 {
33103316 // Check whether any of the upper level booleans (those belonging to the WHERE clause)
33113317 // is able to filter out rows from the "inner" streams. If this is the case,
@@ -3320,15 +3326,15 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
33203326 StreamList streams;
33213327
33223328 // First check the left stream of the full outer join
3323- if (rse_jointype == blr_full )
3329+ if (isFullJoin () )
33243330 {
33253331 rse1->computeRseStreams (streams);
33263332
33273333 for (const auto boolean : csb->csb_inner_booleans )
33283334 {
33293335 if (boolean && boolean->ignoreNulls (streams))
33303336 {
3331- rse_jointype = blr_left ;
3337+ rse_jointype = LEFT_JOIN ;
33323338 break ;
33333339 }
33343340 }
@@ -3342,16 +3348,16 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
33423348 {
33433349 if (boolean && boolean->ignoreNulls (streams))
33443350 {
3345- if (rse_jointype == blr_full )
3351+ if (isFullJoin () )
33463352 {
33473353 // We should transform FULL join to RIGHT join,
33483354 // but as we don't allow them inside the engine
33493355 // just swap the sides and insist it's LEFT join
33503356 std::swap (rse_relations[0 ], rse_relations[1 ]);
3351- rse_jointype = blr_left ;
3357+ rse_jointype = LEFT_JOIN ;
33523358 }
33533359 else
3354- rse_jointype = blr_inner ;
3360+ rse_jointype = INNER_JOIN ;
33553361
33563362 break ;
33573363 }
@@ -3366,11 +3372,9 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
33663372 // where we are just trying to inner join more than 2 streams. If possible,
33673373 // try to flatten the tree out before we go any further.
33683374
3369- if (!isLateral () && !isSemiJoined () &&
3370- rse->rse_jointype == blr_inner &&
3371- rse_jointype == blr_inner &&
3372- !rse_sorted && !rse_projection &&
3373- !rse_first && !rse_skip && !rse_plan)
3375+ if (!isLateral () &&
3376+ rse->isInnerJoin () && isInnerJoin () &&
3377+ !rse_sorted && !rse_projection && !rse_first && !rse_skip && !rse_plan)
33743378 {
33753379 for (auto sub : rse_relations)
33763380 processSource (tdbb, csb, rse, sub, boolean, stack);
@@ -3461,8 +3465,9 @@ RecordSource* RseNode::compile(thread_db* tdbb, Optimizer* opt, bool innerSubStr
34613465 computeRseStreams (rseStreams);
34623466
34633467 BoolExprNodeStack conjunctStack;
3468+ StreamStateHolder stateHolder (csb, opt->getOuterStreams ());
34643469
3465- // pass RseNode boolean only to inner substreams because join condition
3470+ // Pass RseNode boolean only to inner substreams because join condition
34663471 // should never exclude records from outer substreams
34673472 if (opt->isInnerJoin () || (opt->isLeftJoin () && innerSubStream))
34683473 {
@@ -3472,47 +3477,32 @@ RecordSource* RseNode::compile(thread_db* tdbb, Optimizer* opt, bool innerSubStr
34723477 //
34733478 // dimitr: the same for lateral derived tables in inner joins
34743479
3475- StreamStateHolder stateHolder (csb, opt->getOuterStreams ());
3476-
3477- if (opt->isLeftJoin () || isLateral () || isSemiJoined ())
3478- {
3480+ if (opt->isLeftJoin () || isLateral ())
34793481 stateHolder.activate ();
34803482
3481- if (opt->isLeftJoin () || isSemiJoined ())
3482- {
3483- // Push all conjuncts except "missing" ones (e.g. IS NULL)
3484- for (auto iter = opt->getConjuncts (false , true ); iter.hasData (); ++iter)
3485- {
3486- if (iter->containsAnyStream (rseStreams))
3487- conjunctStack.push (iter);
3488- }
3489- }
3490- }
3491- else
3483+ // For the LEFT JOIN, push all conjuncts except "missing" ones (e.g. IS NULL)
3484+ for (auto iter = opt->getConjuncts (false , opt->isLeftJoin ()); iter.hasData (); ++iter)
34923485 {
3493- for (auto iter = opt->getConjuncts (); iter.hasData (); ++iter)
3494- {
3495- if (iter->containsAnyStream (rseStreams))
3496- conjunctStack.push (iter);
3497- }
3486+ if (iter->containsAnyStream (rseStreams))
3487+ conjunctStack.push (iter);
34983488 }
3499-
3500- return opt->compile (this , &conjunctStack);
35013489 }
3502-
3503- // Push only parent conjuncts to the outer stream
3504- for (auto iter = opt->getConjuncts (true , false ); iter.hasData (); ++iter)
3490+ else
35053491 {
3506- if (iter->containsAnyStream (rseStreams))
3507- conjunctStack.push (iter);
3492+ // Push only parent conjuncts to the outer stream
3493+ for (auto iter = opt->getConjuncts (true , false ); iter.hasData (); ++iter)
3494+ {
3495+ if (iter->containsAnyStream (rseStreams))
3496+ conjunctStack.push (iter);
3497+ }
35083498 }
35093499
35103500 return opt->compile (this , &conjunctStack);
35113501}
35123502
35133503RseNode* RseNode::processPossibleJoins (thread_db* tdbb, CompilerScratch* csb)
35143504{
3515- if (rse_jointype != blr_inner || !rse_boolean || rse_plan)
3505+ if (! isInnerJoin () || !rse_boolean || rse_plan)
35163506 return nullptr ;
35173507
35183508 // If the sub-query is nested inside the other sub-query which wasn't converted into semi-join,
@@ -3532,19 +3522,16 @@ RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb)
35323522 }
35333523 }
35343524
3535- RecordSourceNodeStack rseStack;
3536- BoolExprNodeStack booleanStack;
3537-
35383525 // Find possibly joinable sub-queries
35393526
35403527 StreamList rseStreams;
35413528 computeRseStreams (rseStreams);
3529+ SpecialJoinList specialJoins;
35423530
3543- if (!findPossibleJoins (csb, rseStreams, rse_boolean.getAddress (), rseStack, booleanStack ))
3531+ if (!findPossibleJoins (csb, rseStreams, rse_boolean.getAddress (), specialJoins ))
35443532 return nullptr ;
35453533
3546- fb_assert (rseStack.hasData () && booleanStack.hasData ());
3547- fb_assert (rseStack.getCount () == booleanStack.getCount ());
3534+ fb_assert (specialJoins.hasData ());
35483535
35493536 // Create joins between the original node and detected joinable nodes.
35503537 // Preserve FIRST/SKIP nodes at their original position, i.e. outside semi-joins.
@@ -3559,16 +3546,18 @@ RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb)
35593546 flags = 0 ;
35603547
35613548 auto rse = this ;
3562- while (rseStack .hasData ())
3549+ while (specialJoins .hasData ())
35633550 {
35643551 const auto newRse = FB_NEW_POOL (*tdbb->getDefaultPool ())
35653552 RseNode (*tdbb->getDefaultPool ());
35663553
3554+ const auto item = specialJoins.pop ();
3555+
35673556 newRse->rse_relations .add (rse);
3568- newRse->rse_relations .add (rseStack. pop () );
3557+ newRse->rse_relations .add (item. rse );
35693558
3570- newRse->rse_jointype = blr_inner ;
3571- newRse->rse_boolean = booleanStack. pop () ;
3559+ newRse->rse_jointype = item. semiJoin ? SEMI_JOIN : ANTI_JOIN ;
3560+ newRse->rse_boolean = item. boolean ;
35723561
35733562 rse = newRse;
35743563 }
@@ -3579,7 +3568,7 @@ RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb)
35793568 RseNode (*tdbb->getDefaultPool ());
35803569
35813570 newRse->rse_relations .add (rse);
3582- newRse->rse_jointype = blr_inner ;
3571+ newRse->rse_jointype = INNER_JOIN ;
35833572 newRse->rse_first = first;
35843573 newRse->rse_skip = skip;
35853574
0 commit comments