@@ -55,7 +55,16 @@ static ValueExprNode* resolveUsingField(DsqlCompilerScratch* dsqlScratch, const
55
55
56
56
namespace
57
57
{
58
- void appendContextAlias (DsqlCompilerScratch* dsqlScratch, const string& alias)
58
+ struct SpecialJoinItem
59
+ {
60
+ RseNode* rse;
61
+ bool semiJoin;
62
+ BoolExprNode* boolean;
63
+ };
64
+
65
+ typedef HalfStaticArray<SpecialJoinItem, 4 > SpecialJoinList;
66
+
67
+ void appendContextAlias (DsqlCompilerScratch* dsqlScratch, const string& alias)
59
68
{
60
69
const auto len = alias.length ();
61
70
if (len <= MAX_UCHAR)
@@ -126,18 +135,17 @@ namespace
126
135
bool findPossibleJoins (CompilerScratch* csb,
127
136
const StreamList& rseStreams,
128
137
BoolExprNode** parentBoolean,
129
- RecordSourceNodeStack& rseStack,
130
- BoolExprNodeStack& booleanStack)
138
+ SpecialJoinList& result)
131
139
{
132
140
auto boolNode = *parentBoolean;
133
141
134
142
const auto binaryNode = nodeAs<BinaryBoolNode>(boolNode);
135
143
if (binaryNode && binaryNode->blrOp == blr_and)
136
144
{
137
145
const bool found1 = findPossibleJoins (csb, rseStreams,
138
- binaryNode->arg1 .getAddress (), rseStack, booleanStack );
146
+ binaryNode->arg1 .getAddress (), result );
139
147
const bool found2 = findPossibleJoins (csb, rseStreams,
140
- binaryNode->arg2 .getAddress (), rseStack, booleanStack );
148
+ binaryNode->arg2 .getAddress (), result );
141
149
142
150
if (!binaryNode->arg1 && !binaryNode->arg2 )
143
151
*parentBoolean = nullptr ;
@@ -156,7 +164,7 @@ namespace
156
164
auto rse = rseNode->rse ;
157
165
fb_assert (rse && (rse->flags & RseNode::FLAG_SUB_QUERY));
158
166
159
- if (rse->rse_boolean && rse->rse_jointype == blr_inner &&
167
+ if (rse->rse_boolean && rse->isInnerJoin () &&
160
168
!rse->rse_first && !rse->rse_skip && !rse->rse_plan )
161
169
{
162
170
// Find booleans convertable into semi-joins
@@ -201,9 +209,7 @@ namespace
201
209
if (!dependent)
202
210
{
203
211
rse->flags &= ~RseNode::FLAG_SUB_QUERY;
204
- rse->flags |= RseNode::FLAG_SEMI_JOINED;
205
- rseStack.push (rse);
206
- booleanStack.push (boolean);
212
+ result.push ({rse, true , boolean});
207
213
*parentBoolean = nullptr ;
208
214
return true ;
209
215
}
@@ -1019,7 +1025,7 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
1019
1025
// 1) If the view has a projection, sort, first/skip or explicit plan.
1020
1026
// 2) If it's part of an outer join.
1021
1027
1022
- if (rse->rse_jointype != blr_inner || // viewRse->rse_jointype != blr_inner || ???
1028
+ if (! rse->isInnerJoin () || // ! viewRse->isInnerJoin() || ???
1023
1029
viewRse->rse_sorted || viewRse->rse_projection || viewRse->rse_first ||
1024
1030
viewRse->rse_skip || viewRse->rse_plan )
1025
1031
{
@@ -2970,19 +2976,19 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
2970
2976
2971
2977
switch (rse_jointype)
2972
2978
{
2973
- case blr_inner :
2979
+ case INNER_JOIN :
2974
2980
streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
2975
2981
streamList->items [1 ] = doDsqlPass (dsqlScratch, fromList->items [1 ]);
2976
2982
break ;
2977
2983
2978
- case blr_left :
2984
+ case LEFT_JOIN :
2979
2985
streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
2980
2986
++dsqlScratch->inOuterJoin ;
2981
2987
streamList->items [1 ] = doDsqlPass (dsqlScratch, fromList->items [1 ]);
2982
2988
--dsqlScratch->inOuterJoin ;
2983
2989
break ;
2984
2990
2985
- case blr_right :
2991
+ case RIGHT_JOIN :
2986
2992
++dsqlScratch->inOuterJoin ;
2987
2993
streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
2988
2994
--dsqlScratch->inOuterJoin ;
@@ -2993,7 +2999,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
2993
2999
streamList->items [1 ] = doDsqlPass (dsqlScratch, fromList->items [1 ]);
2994
3000
break ;
2995
3001
2996
- case blr_full :
3002
+ case FULL_JOIN :
2997
3003
++dsqlScratch->inOuterJoin ;
2998
3004
streamList->items [0 ] = doDsqlPass (dsqlScratch, fromList->items [0 ]);
2999
3005
// Temporarily remove just created context(s) from the stack,
@@ -3065,7 +3071,7 @@ RseNode* RseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
3065
3071
if (matched->items .isEmpty ())
3066
3072
{
3067
3073
// There is no match. Transform to CROSS JOIN.
3068
- node->rse_jointype = blr_inner ;
3074
+ node->rse_jointype = INNER_JOIN ;
3069
3075
usingList = NULL ;
3070
3076
3071
3077
delete matched;
@@ -3280,14 +3286,14 @@ RseNode* RseNode::pass1(thread_db* tdbb, CompilerScratch* csb)
3280
3286
ValueExprNode* skip = rse_skip;
3281
3287
PlanNode* plan = rse_plan;
3282
3288
3283
- if (rse_jointype == blr_inner )
3289
+ if (isInnerJoin () )
3284
3290
csb->csb_inner_booleans .push (rse_boolean);
3285
3291
3286
3292
// zip thru RseNode expanding views and inner joins
3287
3293
for (auto sub : rse_relations)
3288
3294
processSource (tdbb, csb, this , sub, &boolean, stack);
3289
3295
3290
- if (rse_jointype == blr_inner )
3296
+ if (isInnerJoin () )
3291
3297
csb->csb_inner_booleans .pop ();
3292
3298
3293
3299
// Now, rebuild the RseNode block.
@@ -3362,7 +3368,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
3362
3368
return ;
3363
3369
}
3364
3370
3365
- if (rse_jointype != blr_inner )
3371
+ if (isOuterJoin () )
3366
3372
{
3367
3373
// Check whether any of the upper level booleans (those belonging to the WHERE clause)
3368
3374
// is able to filter out rows from the "inner" streams. If this is the case,
@@ -3377,15 +3383,15 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
3377
3383
StreamList streams;
3378
3384
3379
3385
// First check the left stream of the full outer join
3380
- if (rse_jointype == blr_full )
3386
+ if (isFullJoin () )
3381
3387
{
3382
3388
rse1->computeRseStreams (streams);
3383
3389
3384
3390
for (const auto boolean : csb->csb_inner_booleans )
3385
3391
{
3386
3392
if (boolean && boolean->ignoreNulls (streams))
3387
3393
{
3388
- rse_jointype = blr_left ;
3394
+ rse_jointype = LEFT_JOIN ;
3389
3395
break ;
3390
3396
}
3391
3397
}
@@ -3399,16 +3405,16 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
3399
3405
{
3400
3406
if (boolean && boolean->ignoreNulls (streams))
3401
3407
{
3402
- if (rse_jointype == blr_full )
3408
+ if (isFullJoin () )
3403
3409
{
3404
3410
// We should transform FULL join to RIGHT join,
3405
3411
// but as we don't allow them inside the engine
3406
3412
// just swap the sides and insist it's LEFT join
3407
3413
std::swap (rse_relations[0 ], rse_relations[1 ]);
3408
- rse_jointype = blr_left ;
3414
+ rse_jointype = LEFT_JOIN ;
3409
3415
}
3410
3416
else
3411
- rse_jointype = blr_inner ;
3417
+ rse_jointype = INNER_JOIN ;
3412
3418
3413
3419
break ;
3414
3420
}
@@ -3423,11 +3429,9 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
3423
3429
// where we are just trying to inner join more than 2 streams. If possible,
3424
3430
// try to flatten the tree out before we go any further.
3425
3431
3426
- if (!isLateral () && !isSemiJoined () &&
3427
- rse->rse_jointype == blr_inner &&
3428
- rse_jointype == blr_inner &&
3429
- !rse_sorted && !rse_projection &&
3430
- !rse_first && !rse_skip && !rse_plan)
3432
+ if (!isLateral () &&
3433
+ rse->isInnerJoin () && isInnerJoin () &&
3434
+ !rse_sorted && !rse_projection && !rse_first && !rse_skip && !rse_plan)
3431
3435
{
3432
3436
for (auto sub : rse_relations)
3433
3437
processSource (tdbb, csb, rse, sub, boolean, stack);
@@ -3518,58 +3522,47 @@ RecordSource* RseNode::compile(thread_db* tdbb, Optimizer* opt, bool innerSubStr
3518
3522
computeRseStreams (rseStreams);
3519
3523
3520
3524
BoolExprNodeStack conjunctStack;
3525
+ StreamStateHolder stateHolder (csb, opt->getOuterStreams ());
3521
3526
3522
- // pass RseNode boolean only to inner substreams because join condition
3527
+ // Pass RseNode boolean only to inner substreams because join condition
3523
3528
// should never exclude records from outer substreams
3524
- if (opt->isInnerJoin () || (opt->isLeftJoin () && innerSubStream))
3529
+ if (opt->isInnerJoin () || (( opt->isLeftJoin () || opt-> isSpecialJoin () ) && innerSubStream))
3525
3530
{
3526
3531
// AB: For an (X LEFT JOIN Y) mark the outer-streams (X) as
3527
3532
// active because the inner-streams (Y) are always "dependent"
3528
3533
// on the outer-streams. So that index retrieval nodes could be made.
3529
3534
//
3530
3535
// dimitr: the same for lateral derived tables in inner joins
3531
3536
3532
- StreamStateHolder stateHolder (csb, opt->getOuterStreams ());
3533
-
3534
- if (opt->isLeftJoin () || isLateral () || isSemiJoined ())
3535
- {
3537
+ if (!opt->isInnerJoin () || isLateral ())
3536
3538
stateHolder.activate ();
3537
3539
3538
- if (opt->isLeftJoin () || isSemiJoined ())
3539
- {
3540
- // Push all conjuncts except "missing" ones (e.g. IS NULL)
3541
- for (auto iter = opt->getConjuncts (false , true ); iter.hasData (); ++iter)
3542
- {
3543
- if (iter->containsAnyStream (rseStreams))
3544
- conjunctStack.push (iter);
3545
- }
3546
- }
3547
- }
3548
- else
3540
+ // For the LEFT JOIN, push all conjuncts except "missing" ones (e.g. IS NULL)
3541
+ for (auto iter = opt->getConjuncts (false , opt->isLeftJoin ()); iter.hasData (); ++iter)
3549
3542
{
3550
- for (auto iter = opt->getConjuncts (); iter.hasData (); ++iter)
3551
- {
3552
- if (iter->containsAnyStream (rseStreams))
3553
- conjunctStack.push (iter);
3554
- }
3543
+ if (iter->containsAnyStream (rseStreams))
3544
+ conjunctStack.push (iter);
3555
3545
}
3556
3546
3557
- return opt->compile (this , &conjunctStack);
3547
+ if (opt->isSpecialJoin () && !opt->deliverJoinConjuncts (conjunctStack))
3548
+ conjunctStack.clear ();
3558
3549
}
3559
-
3560
- // Push only parent conjuncts to the outer stream
3561
- for (auto iter = opt->getConjuncts (true , false ); iter.hasData (); ++iter)
3550
+ else
3562
3551
{
3563
- if (iter->containsAnyStream (rseStreams))
3564
- conjunctStack.push (iter);
3552
+ // Push only parent conjuncts to the outer stream
3553
+ for (auto iter = opt->getConjuncts (true , false ); iter.hasData (); ++iter)
3554
+ {
3555
+ if (iter->containsAnyStream (rseStreams))
3556
+ conjunctStack.push (iter);
3557
+ }
3565
3558
}
3566
3559
3567
3560
return opt->compile (this , &conjunctStack);
3568
3561
}
3569
3562
3570
3563
RseNode* RseNode::processPossibleJoins (thread_db* tdbb, CompilerScratch* csb)
3571
3564
{
3572
- if (rse_jointype != blr_inner || !rse_boolean || rse_plan)
3565
+ if (! isInnerJoin () || !rse_boolean || rse_plan)
3573
3566
return nullptr ;
3574
3567
3575
3568
// If the sub-query is nested inside the other sub-query which wasn't converted into semi-join,
@@ -3589,19 +3582,16 @@ RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb)
3589
3582
}
3590
3583
}
3591
3584
3592
- RecordSourceNodeStack rseStack;
3593
- BoolExprNodeStack booleanStack;
3594
-
3595
3585
// Find possibly joinable sub-queries
3596
3586
3597
3587
StreamList rseStreams;
3598
3588
computeRseStreams (rseStreams);
3589
+ SpecialJoinList specialJoins;
3599
3590
3600
- if (!findPossibleJoins (csb, rseStreams, rse_boolean.getAddress (), rseStack, booleanStack ))
3591
+ if (!findPossibleJoins (csb, rseStreams, rse_boolean.getAddress (), specialJoins ))
3601
3592
return nullptr ;
3602
3593
3603
- fb_assert (rseStack.hasData () && booleanStack.hasData ());
3604
- fb_assert (rseStack.getCount () == booleanStack.getCount ());
3594
+ fb_assert (specialJoins.hasData ());
3605
3595
3606
3596
// Create joins between the original node and detected joinable nodes.
3607
3597
// Preserve FIRST/SKIP nodes at their original position, i.e. outside semi-joins.
@@ -3616,16 +3606,18 @@ RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb)
3616
3606
flags = 0 ;
3617
3607
3618
3608
auto rse = this ;
3619
- while (rseStack .hasData ())
3609
+ while (specialJoins .hasData ())
3620
3610
{
3621
3611
const auto newRse = FB_NEW_POOL (*tdbb->getDefaultPool ())
3622
3612
RseNode (*tdbb->getDefaultPool ());
3623
3613
3614
+ const auto item = specialJoins.pop ();
3615
+
3624
3616
newRse->rse_relations .add (rse);
3625
- newRse->rse_relations .add (rseStack. pop () );
3617
+ newRse->rse_relations .add (item. rse );
3626
3618
3627
- newRse->rse_jointype = blr_inner ;
3628
- newRse->rse_boolean = booleanStack. pop () ;
3619
+ newRse->rse_jointype = item. semiJoin ? SEMI_JOIN : ANTI_JOIN ;
3620
+ newRse->rse_boolean = item. boolean ;
3629
3621
3630
3622
rse = newRse;
3631
3623
}
@@ -3636,7 +3628,7 @@ RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb)
3636
3628
RseNode (*tdbb->getDefaultPool ());
3637
3629
3638
3630
newRse->rse_relations .add (rse);
3639
- newRse->rse_jointype = blr_inner ;
3631
+ newRse->rse_jointype = INNER_JOIN ;
3640
3632
newRse->rse_first = first;
3641
3633
newRse->rse_skip = skip;
3642
3634
0 commit comments