Skip to content

Commit 13f167a

Browse files
authored
Add support of the IN <list> predicate to the equality distribution logic (#8732)
1 parent 1a0af0c commit 13f167a

File tree

2 files changed

+101
-34
lines changed

2 files changed

+101
-34
lines changed

src/jrd/optimizer/Optimizer.cpp

Lines changed: 97 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,62 +2177,94 @@ unsigned Optimizer::distributeEqualities(BoolExprNodeStack& orgStack, unsigned b
21772177
{
21782178
const auto boolean = iter.object();
21792179
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
2180-
ValueExprNode* node1;
2181-
ValueExprNode* node2;
2180+
const auto listNode = nodeAs<InListBoolNode>(boolean);
21822181

2183-
if (cmpNode &&
2184-
(cmpNode->blrOp == blr_eql ||
2185-
cmpNode->blrOp == blr_gtr || cmpNode->blrOp == blr_geq ||
2186-
cmpNode->blrOp == blr_leq || cmpNode->blrOp == blr_lss ||
2187-
cmpNode->blrOp == blr_matching || cmpNode->blrOp == blr_containing ||
2188-
cmpNode->blrOp == blr_like || cmpNode->blrOp == blr_similar))
2189-
{
2190-
node1 = cmpNode->arg1;
2191-
node2 = cmpNode->arg2;
2192-
}
2193-
else
2182+
if (!cmpNode && !listNode)
21942183
continue;
21952184

2185+
ValueExprNode* fieldNode;
21962186
bool reverse = false;
21972187

2198-
if (!nodeIs<FieldNode>(node1))
2188+
if (cmpNode)
21992189
{
2200-
ValueExprNode* swap_node = node1;
2201-
node1 = node2;
2202-
node2 = swap_node;
2203-
reverse = true;
2190+
if (cmpNode->blrOp != blr_eql &&
2191+
cmpNode->blrOp != blr_gtr && cmpNode->blrOp != blr_geq &&
2192+
cmpNode->blrOp != blr_leq && cmpNode->blrOp != blr_lss &&
2193+
cmpNode->blrOp != blr_matching && cmpNode->blrOp != blr_containing &&
2194+
cmpNode->blrOp != blr_like && cmpNode->blrOp != blr_similar)
2195+
{
2196+
continue;
2197+
}
2198+
2199+
fieldNode = cmpNode->arg1;
2200+
ValueExprNode* otherNode = cmpNode->arg2;
2201+
2202+
if (!nodeIs<FieldNode>(fieldNode))
2203+
{
2204+
std::swap(fieldNode, otherNode);
2205+
reverse = true;
2206+
}
2207+
2208+
if (!nodeIs<FieldNode>(fieldNode))
2209+
continue;
2210+
2211+
if (!nodeIs<LiteralNode>(otherNode) &&
2212+
!nodeIs<ParameterNode>(otherNode) &&
2213+
!nodeIs<VariableNode>(otherNode))
2214+
{
2215+
continue;
2216+
}
22042217
}
2218+
else // listNode != nullptr
2219+
{
2220+
fieldNode = listNode->arg;
22052221

2206-
if (!nodeIs<FieldNode>(node1))
2207-
continue;
2222+
if (!nodeIs<FieldNode>(fieldNode))
2223+
continue;
22082224

2209-
if (!nodeIs<LiteralNode>(node2) && !nodeIs<ParameterNode>(node2) && !nodeIs<VariableNode>(node2))
2210-
continue;
2225+
bool accept = true;
2226+
2227+
for (const auto item : listNode->list->items)
2228+
{
2229+
if (!nodeIs<LiteralNode>(item) &&
2230+
!nodeIs<ParameterNode>(item) &&
2231+
!nodeIs<VariableNode>(item))
2232+
{
2233+
accept = false;
2234+
break;
2235+
}
2236+
}
2237+
2238+
if (!accept)
2239+
continue;
2240+
}
2241+
2242+
fb_assert(nodeIs<FieldNode>(fieldNode));
22112243

22122244
for (eq_class = classes.begin(); eq_class != classes.end(); ++eq_class)
22132245
{
2214-
if (searchStack(node1, *eq_class))
2246+
if (searchStack(fieldNode, *eq_class))
22152247
{
22162248
for (ValueExprNodeStack::iterator temp(*eq_class); temp.hasData(); ++temp)
22172249
{
2218-
if (!fieldEqual(node1, temp.object()) && count < MAX_CONJUNCTS_TO_INJECT)
2250+
if (!fieldEqual(fieldNode, temp.object()) && count < MAX_CONJUNCTS_TO_INJECT)
22192251
{
2220-
ValueExprNode* arg1;
2221-
ValueExprNode* arg2;
2252+
// From the conjuncts X(A,B) and A=C, infer the conjunct X(C,B)
2253+
2254+
AutoPtr<BoolExprNode> newNode;
22222255

2223-
if (reverse)
2256+
if (cmpNode)
22242257
{
2225-
arg1 = cmpNode->arg1;
2226-
arg2 = temp.object();
2258+
newNode = reverse ?
2259+
makeInferenceNode(boolean, cmpNode->arg1, temp.object()) :
2260+
makeInferenceNode(boolean, temp.object(), cmpNode->arg2);
22272261
}
2228-
else
2262+
else // listNode != nullptr
22292263
{
2230-
arg1 = temp.object();
2231-
arg2 = cmpNode->arg2;
2264+
newNode = makeInferenceNode(boolean, temp.object(), listNode->list);
22322265
}
22332266

2234-
// From the conjuncts X(A,B) and A=C, infer the conjunct X(C,B)
2235-
AutoPtr<BoolExprNode> newNode(makeInferenceNode(boolean, arg1, arg2));
2267+
fb_assert(newNode);
22362268

22372269
if (augmentStack(newNode, orgStack))
22382270
{
@@ -3127,6 +3159,37 @@ BoolExprNode* Optimizer::makeInferenceNode(BoolExprNode* boolean,
31273159
}
31283160

31293161

3162+
BoolExprNode* Optimizer::makeInferenceNode(BoolExprNode* boolean,
3163+
ValueExprNode* arg,
3164+
ValueListNode* list)
3165+
{
3166+
const auto listNode = nodeAs<InListBoolNode>(boolean);
3167+
fb_assert(listNode); // see our caller
3168+
3169+
// Clone the input predicate
3170+
const auto newListNode =
3171+
FB_NEW_POOL(getPool()) InListBoolNode(getPool());
3172+
3173+
// But substitute new values for some of the predicate arguments
3174+
SubExprNodeCopier copier(csb->csb_pool, csb);
3175+
newListNode->arg = copier.copy(tdbb, arg);
3176+
newListNode->list = copier.copy(tdbb, list);
3177+
3178+
// We may safely copy invariantness flag because:
3179+
// (1) we only distribute field equalities
3180+
// (2) invariantness of second argument of STARTING WITH or LIKE is solely
3181+
// determined by its dependency on any of the fields
3182+
// If provisions above change the line below will have to be modified.
3183+
newListNode->nodFlags = listNode->nodFlags;
3184+
3185+
// We cannot safely share the impure area because the original/new data types
3186+
// for the substituted field could be different, thus affecting the lookup table.
3187+
// Thus perform the second pass to properly set up the boolean for execution.
3188+
3189+
return newListNode->pass2(tdbb, csb);
3190+
}
3191+
3192+
31303193
//
31313194
// Optimize a LIKE/SIMILAR expression, if possible, into a "STARTING WITH" AND a "LIKE/SIMILAR".
31323195
// This will allow us to use the index for the starting with, and the LIKE/SIMILAR can just tag

src/jrd/optimizer/Optimizer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,10 @@ class Optimizer final : public Firebird::PermanentStorage
579579
BoolExprNode* makeInferenceNode(BoolExprNode* boolean,
580580
ValueExprNode* arg1,
581581
ValueExprNode* arg2);
582+
BoolExprNode* makeInferenceNode(BoolExprNode* boolean,
583+
ValueExprNode* arg,
584+
ValueListNode* list);
585+
582586
ValueExprNode* optimizeLikeSimilar(ComparativeBoolNode* cmpNode);
583587

584588
thread_db* const tdbb;

0 commit comments

Comments
 (0)