Try to convert nodes of expression: select ... from where not in (select from ) (and its variants that uses the same BLR: {NOT (a = ANY b)} and {a <> ALL b}) to: select ... from where not ((x is null and exists (select 1 from )) or exists (select from where = or is null)) Because the second form can use indexes. Returns NULL when not converted, and a
| 2079 | // Because the second form can use indexes. |
| 2080 | // Returns NULL when not converted, and a new node to be processed when converted. |
| 2081 | BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratch* csb) |
| 2082 | { |
| 2083 | SET_TDBB(tdbb); |
| 2084 | |
| 2085 | fb_assert(blrOp == blr_ansi_all); |
| 2086 | |
| 2087 | RseNode* outerRse = rse; // blr_ansi_all rse |
| 2088 | ComparativeBoolNode* outerRseNeq; |
| 2089 | |
| 2090 | if (!outerRse || |
| 2091 | outerRse->getType() != RseNode::TYPE || // Reduntant test? |
| 2092 | outerRse->rse_relations.getCount() != 1 || |
| 2093 | !outerRse->rse_boolean || |
| 2094 | !(outerRseNeq = nodeAs<ComparativeBoolNode>(outerRse->rse_boolean)) || |
| 2095 | outerRseNeq->blrOp != blr_neq) |
| 2096 | { |
| 2097 | return NULL; |
| 2098 | } |
| 2099 | |
| 2100 | RseNode* innerRse = static_cast<RseNode*>(outerRse->rse_relations[0].getObject()); // user rse |
| 2101 | |
| 2102 | // If the rse is different than we expected, do nothing. Do nothing also if it uses FIRST or |
| 2103 | // SKIP, as we can't inject booleans there without changing the behavior. |
| 2104 | if (!innerRse || innerRse->getType() != RseNode::TYPE || innerRse->rse_first || innerRse->rse_skip) |
| 2105 | return NULL; |
| 2106 | |
| 2107 | NotBoolNode* newNode = FB_NEW_POOL(csb->csb_pool) NotBoolNode(csb->csb_pool); |
| 2108 | |
| 2109 | BinaryBoolNode* orNode = FB_NEW_POOL(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_or); |
| 2110 | |
| 2111 | newNode->arg = orNode; |
| 2112 | |
| 2113 | BinaryBoolNode* andNode = FB_NEW_POOL(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_and); |
| 2114 | |
| 2115 | orNode->arg1 = andNode; |
| 2116 | |
| 2117 | MissingBoolNode* missNode = FB_NEW_POOL(csb->csb_pool) MissingBoolNode(csb->csb_pool); |
| 2118 | missNode->arg = outerRseNeq->arg1; |
| 2119 | |
| 2120 | andNode->arg1 = missNode; |
| 2121 | |
| 2122 | RseNode* newInnerRse1 = innerRse->clone(csb->csb_pool); |
| 2123 | newInnerRse1->flags |= RseNode::FLAG_SUB_QUERY; |
| 2124 | |
| 2125 | RseBoolNode* rseBoolNode = FB_NEW_POOL(csb->csb_pool) RseBoolNode(csb->csb_pool, blr_any); |
| 2126 | rseBoolNode->rse = newInnerRse1; |
| 2127 | rseBoolNode->ownSavepoint = this->ownSavepoint; |
| 2128 | |
| 2129 | andNode->arg2 = rseBoolNode; |
| 2130 | |
| 2131 | RseNode* newInnerRse2 = innerRse->clone(csb->csb_pool); |
| 2132 | newInnerRse2->flags |= RseNode::FLAG_SUB_QUERY; |
| 2133 | |
| 2134 | rseBoolNode = FB_NEW_POOL(csb->csb_pool) RseBoolNode(csb->csb_pool, blr_any); |
| 2135 | rseBoolNode->rse = newInnerRse2; |
| 2136 | rseBoolNode->ownSavepoint = this->ownSavepoint; |
| 2137 | |
| 2138 | orNode->arg2 = rseBoolNode; |
nothing calls this directly
no test coverage detected