@@ -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
0 commit comments