From 5df6668c7bf5a4b27e15f687f8c6cc40e260ced8 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 7 Sep 2023 20:55:48 +0300 Subject: [PATCH] Allow computable but non-invariant lists to be used for index lookup --- src/dsql/BoolNodes.cpp | 5 ++--- src/dsql/ExprNodes.cpp | 39 +++++++++++++++++++++++---------- src/jrd/optimizer/Retrieval.cpp | 20 ++++++++--------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/dsql/BoolNodes.cpp b/src/dsql/BoolNodes.cpp index 6be7bd76ec..104bd07cc0 100644 --- a/src/dsql/BoolNodes.cpp +++ b/src/dsql/BoolNodes.cpp @@ -1368,10 +1368,9 @@ void InListBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::fu } if (nodFlags & FLAG_INVARIANT) - { impureOffset = csb->allocImpure(); - lookup = FB_NEW_POOL(csb->csb_pool) LookupValueList(csb->csb_pool, list, impureOffset); - } + + lookup = FB_NEW_POOL(csb->csb_pool) LookupValueList(csb->csb_pool, list, impureOffset); } bool InListBoolNode::execute(thread_db* tdbb, Request* request) const diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index d8a6c3cbf3..5a6d32be59 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -206,17 +206,10 @@ LookupValueList::LookupValueList(MemoryPool& pool, ValueListNode* values, ULONG const SortedValueList* LookupValueList::init(thread_db* tdbb, Request* request) const { - const auto impure = request->getImpure(m_impureOffset); - auto sortedList = impure->vlu_misc.vlu_sortedList; - - if (!(impure->vlu_flags & VLU_computed)) + auto createList = [&]() { - delete impure->vlu_misc.vlu_sortedList; - impure->vlu_misc.vlu_sortedList = nullptr; - - sortedList = impure->vlu_misc.vlu_sortedList = - FB_NEW_POOL(*tdbb->getDefaultPool()) - SortedValueList(*tdbb->getDefaultPool(), m_values.getCount()); + const auto sortedList = FB_NEW_POOL(*tdbb->getDefaultPool()) + SortedValueList(*tdbb->getDefaultPool(), m_values.getCount()); sortedList->setSortMode(FB_ARRAY_SORT_MANUAL); @@ -228,10 +221,32 @@ const SortedValueList* LookupValueList::init(thread_db* tdbb, Request* request) sortedList->sort(); - impure->vlu_flags |= VLU_computed; + return sortedList; + }; + + // Non-zero impure offset means that the list expression is invariant, + // so the sorted list can be cached inside the impure area + + if (m_impureOffset) + { + const auto impure = request->getImpure(m_impureOffset); + auto sortedList = impure->vlu_misc.vlu_sortedList; + + if (!(impure->vlu_flags & VLU_computed)) + { + delete impure->vlu_misc.vlu_sortedList; + impure->vlu_misc.vlu_sortedList = nullptr; + + sortedList = impure->vlu_misc.vlu_sortedList = createList(); + impure->vlu_flags |= VLU_computed; + } + + return sortedList; } - return sortedList; + // Otherwise, create a temporary list for early evaluation during index lookup + + return createList(); } TriState LookupValueList::find(thread_db* tdbb, Request* request, const ValueExprNode* value, const dsc* desc) const diff --git a/src/jrd/optimizer/Retrieval.cpp b/src/jrd/optimizer/Retrieval.cpp index 898eb0fc62..7d71aacad3 100644 --- a/src/jrd/optimizer/Retrieval.cpp +++ b/src/jrd/optimizer/Retrieval.cpp @@ -1885,19 +1885,17 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch, if (!((segment->scanType == segmentScanEqual) || (segment->scanType == segmentScanEquivalent))) { - if (auto lookup = listNode->lookup) + fb_assert(listNode->lookup); + for (auto& item : *listNode->lookup) { - for (auto& item : *lookup) - { - cast = nullptr; // create new cast node for every value - item = injectCast(csb, item, cast, matchDesc); - } - segment->lowerValue = segment->upperValue = nullptr; - segment->valueList = lookup; - segment->scanType = segmentScanList; - segment->excludeLower = false; - segment->excludeUpper = false; + cast = nullptr; // create new cast node for every value + item = injectCast(csb, item, cast, matchDesc); } + segment->lowerValue = segment->upperValue = nullptr; + segment->valueList = listNode->lookup; + segment->scanType = segmentScanList; + segment->excludeLower = false; + segment->excludeUpper = false; } } else if (missingNode)