@@ -2180,62 +2180,94 @@ unsigned Optimizer::distributeEqualities(BoolExprNodeStack& orgStack, unsigned b
2180
2180
{
2181
2181
const auto boolean = iter.object ();
2182
2182
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
2183
- ValueExprNode* node1;
2184
- ValueExprNode* node2;
2183
+ const auto listNode = nodeAs<InListBoolNode>(boolean);
2185
2184
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)
2197
2186
continue ;
2198
2187
2188
+ ValueExprNode* fieldNode;
2199
2189
bool reverse = false ;
2200
2190
2201
- if (!nodeIs<FieldNode>(node1) )
2191
+ if (cmpNode )
2202
2192
{
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
+ }
2207
2220
}
2221
+ else // listNode != nullptr
2222
+ {
2223
+ fieldNode = listNode->arg ;
2208
2224
2209
- if (!nodeIs<FieldNode>(node1 ))
2210
- continue ;
2225
+ if (!nodeIs<FieldNode>(fieldNode ))
2226
+ continue ;
2211
2227
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));
2214
2246
2215
2247
for (eq_class = classes.begin (); eq_class != classes.end (); ++eq_class)
2216
2248
{
2217
- if (searchStack (node1 , *eq_class))
2249
+ if (searchStack (fieldNode , *eq_class))
2218
2250
{
2219
2251
for (ValueExprNodeStack::iterator temp (*eq_class); temp.hasData (); ++temp)
2220
2252
{
2221
- if (!fieldEqual (node1 , temp.object ()) && count < MAX_CONJUNCTS_TO_INJECT)
2253
+ if (!fieldEqual (fieldNode , temp.object ()) && count < MAX_CONJUNCTS_TO_INJECT)
2222
2254
{
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;
2225
2258
2226
- if (reverse )
2259
+ if (cmpNode )
2227
2260
{
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 );
2230
2264
}
2231
- else
2265
+ else // listNode != nullptr
2232
2266
{
2233
- arg1 = temp.object ();
2234
- arg2 = cmpNode->arg2 ;
2267
+ newNode = makeInferenceNode (boolean, temp.object (), listNode->list );
2235
2268
}
2236
2269
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);
2239
2271
2240
2272
if (augmentStack (newNode, orgStack))
2241
2273
{
@@ -3236,6 +3268,37 @@ BoolExprNode* Optimizer::makeInferenceNode(BoolExprNode* boolean,
3236
3268
}
3237
3269
3238
3270
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
+
3239
3302
//
3240
3303
// Optimize a LIKE/SIMILAR expression, if possible, into a "STARTING WITH" AND a "LIKE/SIMILAR".
3241
3304
// This will allow us to use the index for the starting with, and the LIKE/SIMILAR can just tag
0 commit comments