From 5ed57cb43bd70b53db16ee05eb4667ea7fcc5436 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Tue, 29 Oct 2024 15:46:54 +0300 Subject: [PATCH] Fix #8214: Incorrect result of index list scan for a composite index, the second segment of which is a text field with COLLATE UNICODE_CI --- src/jrd/btr.cpp | 5 ++++- src/jrd/optimizer/Retrieval.cpp | 18 ++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index 658fa0d7da..fdcc71672b 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -766,7 +766,10 @@ void IndexScanListIterator::makeKeys(thread_db* tdbb, temporary_key* lower, temp m_upperValues[m_segno] = *m_iterator; const auto keyType = - (m_retrieval->irb_desc.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT; + (m_retrieval->irb_generic & irb_multi_starting) ? INTL_KEY_MULTI_STARTING : + (m_retrieval->irb_generic & irb_starting) ? INTL_KEY_PARTIAL : + (m_retrieval->irb_desc.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : + INTL_KEY_SORT; // Make the lower bound key diff --git a/src/jrd/optimizer/Retrieval.cpp b/src/jrd/optimizer/Retrieval.cpp index 668859e283..a240c4b88d 100644 --- a/src/jrd/optimizer/Retrieval.cpp +++ b/src/jrd/optimizer/Retrieval.cpp @@ -877,10 +877,6 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions, // We can't use the next segments, and we'll need to use // INTL_KEY_PARTIAL to construct the last segment's key. scratch.usePartialKey = true; - - // It's currently impossible to use a list scan with INTL_KEY_PARTIAL - if (scanType == segmentScanList) - scanType = segmentScanNone; } } @@ -931,16 +927,14 @@ void Retrieval::getInversionCandidates(InversionCandidateList& inversions, // An equality scan for any unique index cannot retrieve more // than one row. The same is true for an equivalence scan for - // any primary index. - const bool single_match = + // any primary index. A missing scan for any primary index is + // known to return no rows, but let's treat it the same way. + const bool uniqueMatch = (scanType == segmentScanEqual && (idx->idx_flags & idx_unique)) || - (scanType == segmentScanEquivalent && (idx->idx_flags & idx_primary)); + (scanType == segmentScanEquivalent && (idx->idx_flags & idx_primary)) || + (scanType == segmentScanMissing && (idx->idx_flags & idx_primary)); - // dimitr: IS NULL scan against primary key is guaranteed - // to return zero rows. Do we need yet another - // special case here? - - if (single_match && ((j + 1) == idx->idx_count)) + if (uniqueMatch && ((j + 1) == idx->idx_count)) { // We have found a full equal matching index and it's unique, // so we can stop looking further, because this is the best