diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index fdcc71672b..71d5e6224c 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -6769,7 +6769,7 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB const bool partUpper = (retrieval->irb_upper_count < idx->idx_count); // Reset flags this routine does not check in the loop below - flag &= ~(irb_equality | irb_ignore_null_value_key | irb_root_list_scan); + flag &= ~(irb_equality | irb_unique | irb_ignore_null_value_key | irb_root_list_scan); flag &= ~(irb_exclude_lower | irb_exclude_upper); IndexNode node; diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 8e71c7d988..7f1bc99303 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -237,6 +237,7 @@ const int irb_exclude_lower = 32; // exclude lower bound keys while scanning i const int irb_exclude_upper = 64; // exclude upper bound keys while scanning index const int irb_multi_starting = 128; // Use INTL_KEY_MULTI_STARTING const int irb_root_list_scan = 256; // Locate list items from the root +const int irb_unique = 512; // Unique match (currently used only for plan output) // Force include flags - always include appropriate key while scanning index const int irb_force_lower = irb_exclude_lower; diff --git a/src/jrd/optimizer/Retrieval.cpp b/src/jrd/optimizer/Retrieval.cpp index a240c4b88d..e92b090d5a 100644 --- a/src/jrd/optimizer/Retrieval.cpp +++ b/src/jrd/optimizer/Retrieval.cpp @@ -1245,6 +1245,9 @@ InversionNode* Retrieval::makeIndexScanNode(IndexScratch* indexScratch) const // Check to see if this is really an equality retrieval if (retrieval->irb_lower_count == retrieval->irb_upper_count) { + const bool fullMatch = (retrieval->irb_lower_count == idx->idx_count); + bool uniqueMatch = false; + retrieval->irb_generic |= irb_equality; for (unsigned i = 0; i < retrieval->irb_lower_count; i++) @@ -1254,7 +1257,22 @@ InversionNode* Retrieval::makeIndexScanNode(IndexScratch* indexScratch) const retrieval->irb_generic &= ~irb_equality; break; } + + if (segments[i].scanType == segmentScanMissing || + segments[i].scanType == segmentScanEquivalent) + { + if (fullMatch && (idx->idx_flags & idx_primary)) + uniqueMatch = true; + } + else if (segments[i].scanType == segmentScanEqual) + { + if (fullMatch && (idx->idx_flags & idx_unique)) + uniqueMatch = true; + } } + + if ((retrieval->irb_generic & irb_equality) && uniqueMatch) + retrieval->irb_generic |= irb_unique; } // If we are matching less than the full index, this is a partial match diff --git a/src/jrd/recsrc/RecordSource.cpp b/src/jrd/recsrc/RecordSource.cpp index cb65597aa0..8cf68d9de0 100644 --- a/src/jrd/recsrc/RecordSource.cpp +++ b/src/jrd/recsrc/RecordSource.cpp @@ -203,26 +203,18 @@ void RecordSource::printInversion(thread_db* tdbb, const InversionNode* inversio } const index_desc& idx = retrieval->irb_desc; - const bool primaryIdx = (idx.idx_flags & idx_primary); - const bool uniqueIdx = (idx.idx_flags & idx_unique); const USHORT segCount = idx.idx_count; const USHORT minSegs = MIN(retrieval->irb_lower_count, retrieval->irb_upper_count); const USHORT maxSegs = MAX(retrieval->irb_lower_count, retrieval->irb_upper_count); const bool equality = (retrieval->irb_generic & irb_equality); + const bool unique = (retrieval->irb_generic & irb_unique); const bool partial = (retrieval->irb_generic & irb_partial); const bool fullscan = (maxSegs == 0); const bool list = (retrieval->irb_list != nullptr); - bool unique = false; - if (!list && equality && minSegs == segCount) - { - unique = (retrieval->irb_generic & irb_ignore_null_value_key) ? - uniqueIdx : primaryIdx; - } - string bounds; if (!unique && !fullscan) {