@@ -1339,8 +1339,69 @@ BoolExprNode* InListBoolNode::copy(thread_db* tdbb, NodeCopier& copier) const
13391339 return node;
13401340}
13411341
1342+ BoolExprNode* InListBoolNode::decompose (CompilerScratch* csb)
1343+ {
1344+ // Search for list items depending on record streams.
1345+ // If found, decompose expression:
1346+ // <arg> IN (<item1>, <item2>, <item3>, <item4> ...)
1347+ // into:
1348+ // <arg> IN (<item1>, <item2>, ...) OR <arg> = <item3> OR <arg> = <item4> ...
1349+ // where the ORed booleans are known to be stream-based (i.e. contain fields inside)
1350+ // and thus could use an index, if possible.
1351+ //
1352+ // See #8109 in the tracker, example:
1353+ //
1354+ // SELECT e.*
1355+ // FROM Employees e
1356+ // WHERE :SomeID IN (e.LeaderID, e.DispEmpID)
1357+
1358+ auto & pool = csb->csb_pool ;
1359+ BoolExprNode* boolNode = nullptr ;
1360+
1361+ for (auto iter = list->items .begin (); iter != list->items .end ();)
1362+ {
1363+ ValueExprNode* const item = *iter;
1364+
1365+ SortedStreamList streams;
1366+ item->collectStreams (streams);
1367+
1368+ if (streams.isEmpty ())
1369+ {
1370+ iter++;
1371+ continue ;
1372+ }
1373+
1374+ list->items .remove (iter);
1375+
1376+ const auto cmpNode = FB_NEW_POOL (pool) ComparativeBoolNode (pool, blr_eql, arg, item);
1377+
1378+ if (boolNode)
1379+ boolNode = FB_NEW_POOL (pool) BinaryBoolNode (pool, blr_or, boolNode, cmpNode);
1380+ else
1381+ boolNode = cmpNode;
1382+ }
1383+
1384+ if (boolNode && list->items .hasData ())
1385+ {
1386+ BoolExprNode* priorNode = this ;
1387+
1388+ if (list->items .getCount () == 1 )
1389+ {
1390+ // Convert A IN (B) into A = B
1391+ priorNode = FB_NEW_POOL (pool) ComparativeBoolNode (pool, blr_eql, arg, list->items .front ());
1392+ }
1393+
1394+ boolNode = FB_NEW_POOL (pool) BinaryBoolNode (pool, blr_or, boolNode, priorNode);
1395+ }
1396+
1397+ return boolNode;
1398+ }
1399+
13421400BoolExprNode* InListBoolNode::pass1 (thread_db* tdbb, CompilerScratch* csb)
13431401{
1402+ if (const auto node = decompose (csb))
1403+ return node->pass1 (tdbb, csb);
1404+
13441405 doPass1 (tdbb, csb, arg.getAddress ());
13451406
13461407 nodFlags |= FLAG_INVARIANT;
0 commit comments