| 140 | // They are candidates to be converted into semi- or anti-joins. |
| 141 | |
| 142 | bool findPossibleJoins(CompilerScratch* csb, |
| 143 | const StreamList& rseStreams, |
| 144 | BoolExprNode** parentBoolean, |
| 145 | RecordSourceNodeStack& rseStack, |
| 146 | BoolExprNodeStack& booleanStack) |
| 147 | { |
| 148 | auto boolNode = *parentBoolean; |
| 149 | |
| 150 | const auto binaryNode = nodeAs<BinaryBoolNode>(boolNode); |
| 151 | if (binaryNode && binaryNode->blrOp == blr_and) |
| 152 | { |
| 153 | const bool found1 = findPossibleJoins(csb, rseStreams, |
| 154 | binaryNode->arg1.getAddress(), rseStack, booleanStack); |
| 155 | const bool found2 = findPossibleJoins(csb, rseStreams, |
| 156 | binaryNode->arg2.getAddress(), rseStack, booleanStack); |
| 157 | |
| 158 | if (!binaryNode->arg1 && !binaryNode->arg2) |
| 159 | *parentBoolean = nullptr; |
| 160 | else if (!binaryNode->arg1) |
| 161 | *parentBoolean = binaryNode->arg2; |
| 162 | else if (!binaryNode->arg2) |
| 163 | *parentBoolean = binaryNode->arg1; |
| 164 | |
| 165 | return (found1 || found2); |
| 166 | } |
| 167 | |
| 168 | const auto rseNode = nodeAs<RseBoolNode>(boolNode); |
| 169 | // Both EXISTS (blr_any) and IN (blr_ansi_any) sub-queries are handled |
| 170 | if (rseNode && (rseNode->blrOp == blr_any || rseNode->blrOp == blr_ansi_any)) |
| 171 | { |
| 172 | auto rse = rseNode->rse; |
| 173 | fb_assert(rse && (rse->flags & RseNode::FLAG_SUB_QUERY)); |
| 174 | |
| 175 | if (rse->rse_boolean && rse->isInnerJoin() && |
| 176 | !rse->rse_first && !rse->rse_skip && !rse->rse_plan) |
| 177 | { |
| 178 | // Find booleans convertable into semi-joins |
| 179 | |
| 180 | BoolExprNodeStack booleans; |
| 181 | if (findDependentBooleans(csb, rseStreams, |
| 182 | rse->rse_boolean.getAddress(), |
| 183 | booleans)) |
| 184 | { |
| 185 | // Compose the conjunct boolean |
| 186 | |
| 187 | fb_assert(booleans.hasData()); |
| 188 | auto boolean = booleans.pop(); |
| 189 | while (booleans.hasData()) |
| 190 | { |
| 191 | const auto andNode = FB_NEW_POOL(csb->csb_pool) |
| 192 | BinaryBoolNode(csb->csb_pool, blr_and); |
| 193 | andNode->arg1 = boolean; |
| 194 | andNode->arg2 = booleans.pop(); |
| 195 | boolean = andNode; |
| 196 | } |
| 197 | |
| 198 | // Ensure that no external references are left inside the subquery. |
| 199 | // If so, mark the RSE as joined and add it to the stack. |
no test coverage detected