Skip to content

Commit

Permalink
Rework fix for #8290: Unique scan is incorrectly reported in the expl…
Browse files Browse the repository at this point in the history
…ained plan for unique index and IS NULL predicate
  • Loading branch information
dyemanov committed Oct 30, 2024
1 parent 5ed57cb commit e7e9e01
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/jrd/btr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/jrd/btr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions src/jrd/optimizer/Retrieval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
Expand All @@ -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
Expand Down
10 changes: 1 addition & 9 deletions src/jrd/recsrc/RecordSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit e7e9e01

Please sign in to comment.