Skip to content

Commit 67161cc

Browse files
committed
Add support of the IN <list> predicate to the equality distribution logic (#8732)
1 parent 9397a86 commit 67161cc

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
@@ -2180,62 +2180,94 @@ unsigned Optimizer::distributeEqualities(BoolExprNodeStack& orgStack, unsigned b
21802180
{
21812181
const auto boolean = iter.object();
21822182
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
2183-
ValueExprNode* node1;
2184-
ValueExprNode* node2;
2183+
const auto listNode = nodeAs<InListBoolNode>(boolean);
21852184

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

2188+
ValueExprNode* fieldNode;
21992189
bool reverse = false;
22002190

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

2209-
if (!nodeIs<FieldNode>(node1))
2210-
continue;
2225+
if (!nodeIs<FieldNode>(fieldNode))
2226+
continue;
22112227

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

22152247
for (eq_class = classes.begin(); eq_class != classes.end(); ++eq_class)
22162248
{
2217-
if (searchStack(node1, *eq_class))
2249+
if (searchStack(fieldNode, *eq_class))
22182250
{
22192251
for (ValueExprNodeStack::iterator temp(*eq_class); temp.hasData(); ++temp)
22202252
{
2221-
if (!fieldEqual(node1, temp.object()) && count < MAX_CONJUNCTS_TO_INJECT)
2253+
if (!fieldEqual(fieldNode, temp.object()) && count < MAX_CONJUNCTS_TO_INJECT)
22222254
{
2223-
ValueExprNode* arg1;
2224-
ValueExprNode* arg2;
2255+
// From the conjuncts X(A,B) and A=C, infer the conjunct X(C,B)
2256+
2257+
AutoPtr<BoolExprNode> newNode;
22252258

2226-
if (reverse)
2259+
if (cmpNode)
22272260
{
2228-
arg1 = cmpNode->arg1;
2229-
arg2 = temp.object();
2261+
newNode = reverse ?
2262+
makeInferenceNode(boolean, cmpNode->arg1, temp.object()) :
2263+
makeInferenceNode(boolean, temp.object(), cmpNode->arg2);
22302264
}
2231-
else
2265+
else // listNode != nullptr
22322266
{
2233-
arg1 = temp.object();
2234-
arg2 = cmpNode->arg2;
2267+
newNode = makeInferenceNode(boolean, temp.object(), listNode->list);
22352268
}
22362269

2237-
// From the conjuncts X(A,B) and A=C, infer the conjunct X(C,B)
2238-
AutoPtr<BoolExprNode> newNode(makeInferenceNode(boolean, arg1, arg2));
2270+
fb_assert(newNode);
22392271

22402272
if (augmentStack(newNode, orgStack))
22412273
{
@@ -3236,6 +3268,37 @@ BoolExprNode* Optimizer::makeInferenceNode(BoolExprNode* boolean,
32363268
}
32373269

32383270

3271+
BoolExprNode* Optimizer::makeInferenceNode(BoolExprNode* boolean,
3272+
ValueExprNode* arg,
3273+
ValueListNode* list)
3274+
{
3275+
const auto listNode = nodeAs<InListBoolNode>(boolean);
3276+
fb_assert(listNode); // see our caller
3277+
3278+
// Clone the input predicate
3279+
const auto newListNode =
3280+
FB_NEW_POOL(getPool()) InListBoolNode(getPool());
3281+
3282+
// But substitute new values for some of the predicate arguments
3283+
SubExprNodeCopier copier(csb->csb_pool, csb);
3284+
newListNode->arg = copier.copy(tdbb, arg);
3285+
newListNode->list = copier.copy(tdbb, list);
3286+
3287+
// We may safely copy invariantness flag because:
3288+
// (1) we only distribute field equalities
3289+
// (2) invariantness of second argument of STARTING WITH or LIKE is solely
3290+
// determined by its dependency on any of the fields
3291+
// If provisions above change the line below will have to be modified.
3292+
newListNode->nodFlags = listNode->nodFlags;
3293+
3294+
// We cannot safely share the impure area because the original/new data types
3295+
// for the substituted field could be different, thus affecting the lookup table.
3296+
// Thus perform the second pass to properly set up the boolean for execution.
3297+
3298+
return newListNode->pass2(tdbb, csb);
3299+
}
3300+
3301+
32393302
//
32403303
// Optimize a LIKE/SIMILAR expression, if possible, into a "STARTING WITH" AND a "LIKE/SIMILAR".
32413304
// 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
@@ -541,6 +541,10 @@ class Optimizer : public Firebird::PermanentStorage
541541
BoolExprNode* makeInferenceNode(BoolExprNode* boolean,
542542
ValueExprNode* arg1,
543543
ValueExprNode* arg2);
544+
BoolExprNode* makeInferenceNode(BoolExprNode* boolean,
545+
ValueExprNode* arg,
546+
ValueListNode* list);
547+
544548
ValueExprNode* optimizeLikeSimilar(ComparativeBoolNode* cmpNode);
545549

546550
thread_db* const tdbb;

0 commit comments

Comments
 (0)