@@ -2177,62 +2177,94 @@ unsigned Optimizer::distributeEqualities(BoolExprNodeStack& orgStack, unsigned b
2177
2177
{
2178
2178
const auto boolean = iter.object ();
2179
2179
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
2180
- ValueExprNode* node1;
2181
- ValueExprNode* node2;
2180
+ const auto listNode = nodeAs<InListBoolNode>(boolean);
2182
2181
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)
2194
2183
continue ;
2195
2184
2185
+ ValueExprNode* fieldNode;
2196
2186
bool reverse = false ;
2197
2187
2198
- if (!nodeIs<FieldNode>(node1) )
2188
+ if (cmpNode )
2199
2189
{
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
+ }
2204
2217
}
2218
+ else // listNode != nullptr
2219
+ {
2220
+ fieldNode = listNode->arg ;
2205
2221
2206
- if (!nodeIs<FieldNode>(node1 ))
2207
- continue ;
2222
+ if (!nodeIs<FieldNode>(fieldNode ))
2223
+ continue ;
2208
2224
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));
2211
2243
2212
2244
for (eq_class = classes.begin (); eq_class != classes.end (); ++eq_class)
2213
2245
{
2214
- if (searchStack (node1 , *eq_class))
2246
+ if (searchStack (fieldNode , *eq_class))
2215
2247
{
2216
2248
for (ValueExprNodeStack::iterator temp (*eq_class); temp.hasData (); ++temp)
2217
2249
{
2218
- if (!fieldEqual (node1 , temp.object ()) && count < MAX_CONJUNCTS_TO_INJECT)
2250
+ if (!fieldEqual (fieldNode , temp.object ()) && count < MAX_CONJUNCTS_TO_INJECT)
2219
2251
{
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;
2222
2255
2223
- if (reverse )
2256
+ if (cmpNode )
2224
2257
{
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 );
2227
2261
}
2228
- else
2262
+ else // listNode != nullptr
2229
2263
{
2230
- arg1 = temp.object ();
2231
- arg2 = cmpNode->arg2 ;
2264
+ newNode = makeInferenceNode (boolean, temp.object (), listNode->list );
2232
2265
}
2233
2266
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);
2236
2268
2237
2269
if (augmentStack (newNode, orgStack))
2238
2270
{
@@ -3127,6 +3159,37 @@ BoolExprNode* Optimizer::makeInferenceNode(BoolExprNode* boolean,
3127
3159
}
3128
3160
3129
3161
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
+
3130
3193
//
3131
3194
// Optimize a LIKE/SIMILAR expression, if possible, into a "STARTING WITH" AND a "LIKE/SIMILAR".
3132
3195
// This will allow us to use the index for the starting with, and the LIKE/SIMILAR can just tag
0 commit comments