| 3301 | } |
| 3302 | |
| 3303 | RseNode* RseNode::processPossibleJoins(thread_db* tdbb, CompilerScratch* csb) |
| 3304 | { |
| 3305 | if (!isInnerJoin() || !rse_boolean || rse_plan) |
| 3306 | return nullptr; |
| 3307 | |
| 3308 | const auto dbb = tdbb->getDatabase(); |
| 3309 | if (!dbb->dbb_config->getSubQueryConversion()) |
| 3310 | return nullptr; |
| 3311 | |
| 3312 | // If the sub-query is nested inside the other sub-query which wasn't converted into semi-join, |
| 3313 | // it makes no sense to apply a semi-join at the deeper levels, as a sub-query is expected |
| 3314 | // to be executed repeatedly. |
| 3315 | // This is a temporary fix until nested loop semi-joins are allowed by the optimizer. |
| 3316 | |
| 3317 | if (flags & FLAG_SUB_QUERY) |
| 3318 | return nullptr; |
| 3319 | |
| 3320 | for (const auto node : csb->csb_current_nodes) |
| 3321 | { |
| 3322 | if (const auto rse = nodeAs<RseNode>(node)) |
| 3323 | { |
| 3324 | if (rse->flags & FLAG_SUB_QUERY) |
| 3325 | return nullptr; |
| 3326 | } |
| 3327 | } |
| 3328 | |
| 3329 | RecordSourceNodeStack rseStack; |
| 3330 | BoolExprNodeStack booleanStack; |
| 3331 | |
| 3332 | // Find possibly joinable sub-queries |
| 3333 | |
| 3334 | StreamList rseStreams; |
| 3335 | computeRseStreams(rseStreams); |
| 3336 | |
| 3337 | if (!findPossibleJoins(csb, rseStreams, rse_boolean.getAddress(), rseStack, booleanStack)) |
| 3338 | return nullptr; |
| 3339 | |
| 3340 | fb_assert(rseStack.hasData() && booleanStack.hasData()); |
| 3341 | fb_assert(rseStack.getCount() == booleanStack.getCount()); |
| 3342 | |
| 3343 | // Create joins between the original node and detected joinable nodes. |
| 3344 | // Preserve FIRST/SKIP nodes at their original position, i.e. outside semi-joins. |
| 3345 | |
| 3346 | const auto first = rse_first; |
| 3347 | rse_first = nullptr; |
| 3348 | |
| 3349 | const auto skip = rse_skip; |
| 3350 | rse_skip = nullptr; |
| 3351 | |
| 3352 | const auto orgFlags = flags; |
| 3353 | flags = 0; |
| 3354 | |
| 3355 | auto rse = this; |
| 3356 | while (rseStack.hasData()) |
| 3357 | { |
| 3358 | const auto newRse = FB_NEW_POOL(*tdbb->getDefaultPool()) |
| 3359 | RseNode(*tdbb->getDefaultPool()); |
| 3360 |
nothing calls this directly
no test coverage detected