8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 18:43:02 +01:00

Rework fix for #8290: Unique scan is incorrectly reported in the explained plan for unique index and IS NULL predicate

This commit is contained in:
Dmitry Yemanov 2024-10-29 11:28:29 +03:00
parent 5ed57cb43b
commit e7e9e01fa9
4 changed files with 21 additions and 10 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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)
{