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