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

Postfix for #7804: The partial index is not involved when filtering conditions through OR. Use the full index scan instead of multiple range scans ORed afterwards.

This commit is contained in:
Dmitry Yemanov 2025-01-19 15:06:26 +03:00
parent 63e6ead37b
commit 90401f7210

View File

@ -1414,17 +1414,37 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
for (auto inversion : inversions)
{
const auto indexScratch = inversion->scratch;
// If the explicit plan doesn't mention this index, fake it as used
// thus excluding it from the cost-based algorithm. Otherwise,
// given this index is suitable for navigation, also mark it as used.
if ((indexScratch &&
(indexScratch->index->idx_runtime_flags & idx_plan_dont_use)) ||
(!customPlan && inversion == navigationCandidate))
if (const auto indexScratch = inversion->scratch)
{
inversion->used = true;
const auto idx = indexScratch->index;
// If the explicit plan doesn't mention this index, fake it as used
// thus excluding it from the cost-based algorithm. Otherwise,
// given this index is suitable for navigation, also mark it as used.
if (((idx->idx_runtime_flags & idx_plan_dont_use)) ||
(!customPlan && inversion == navigationCandidate))
{
inversion->used = true;
}
// If the index is conditional and its condition is also present in
// some other inversion as a boolean (it represents the OR operation),
// fake these other inversions as used, so that the full index scan would
// be preferred to multiple range scans. The cost-based algorithm below
// cannot handle it currently.
if (idx->idx_flags & idx_condition)
{
for (auto otherInversion : inversions)
{
if (otherInversion->boolean &&
idx->idx_condition->sameAs(otherInversion->boolean, true))
{
otherInversion->used = true;
}
}
}
}
}
@ -1460,11 +1480,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
if (!invCandidate)
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
if (!currentInv->inversion && currentInv->scratch)
invCandidate->inversion = makeIndexScanNode(currentInv->scratch);
else
invCandidate->inversion = currentInv->inversion;
const auto inversionNode = (!currentInv->inversion && currentInv->scratch) ?
makeIndexScanNode(currentInv->scratch) : currentInv->inversion;
invCandidate->inversion = inversionNode;
invCandidate->dbkeyRanges.assign(currentInv->dbkeyRanges);
invCandidate->unique = currentInv->unique;
invCandidate->selectivity = currentInv->selectivity;
@ -1653,12 +1671,9 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
if (!invCandidate)
{
invCandidate = FB_NEW_POOL(getPool()) InversionCandidate(getPool());
if (!bestCandidate->inversion && bestCandidate->scratch) {
invCandidate->inversion = makeIndexScanNode(bestCandidate->scratch);
}
else {
invCandidate->inversion = bestCandidate->inversion;
}
const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ?
makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion;
invCandidate->inversion = inversionNode;
invCandidate->dbkeyRanges.assign(bestCandidate->dbkeyRanges);
invCandidate->unique = bestCandidate->unique;
invCandidate->selectivity = bestCandidate->selectivity;
@ -1685,17 +1700,10 @@ InversionCandidate* Retrieval::makeInversion(InversionCandidateList& inversions)
}
else if (!bestCandidate->condition)
{
if (!bestCandidate->inversion && bestCandidate->scratch)
{
invCandidate->inversion = composeInversion(invCandidate->inversion,
makeIndexScanNode(bestCandidate->scratch), InversionNode::TYPE_AND);
}
else
{
invCandidate->inversion = composeInversion(invCandidate->inversion,
bestCandidate->inversion, InversionNode::TYPE_AND);
}
const auto inversionNode = (!bestCandidate->inversion && bestCandidate->scratch) ?
makeIndexScanNode(bestCandidate->scratch) : bestCandidate->inversion;
invCandidate->inversion = composeInversion(invCandidate->inversion,
inversionNode, InversionNode::TYPE_AND);
invCandidate->dbkeyRanges.join(bestCandidate->dbkeyRanges);
invCandidate->unique = (invCandidate->unique || bestCandidate->unique);
invCandidate->selectivity = totalSelectivity;
@ -1770,6 +1778,16 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
if (boolean->nodFlags & ExprNode::FLAG_DEOPTIMIZE)
return false;
const auto idx = indexScratch->index;
if (idx->idx_flags & idx_condition)
{
// If index condition matches the boolean, this should not be
// considered a match. Full index scan will be used instead.
if (idx->idx_condition->sameAs(boolean, true))
return false;
}
const auto cmpNode = nodeAs<ComparativeBoolNode>(boolean);
const auto missingNode = nodeAs<MissingBoolNode>(boolean);
const auto listNode = nodeAs<InListBoolNode>(boolean);
@ -1804,16 +1822,6 @@ bool Retrieval::matchBoolean(IndexScratch* indexScratch,
ValueExprNode* value2 = (cmpNode && cmpNode->blrOp == blr_between) ?
cmpNode->arg3 : nullptr;
const auto idx = indexScratch->index;
if (idx->idx_flags & idx_condition)
{
// If index condition matches the boolean, this should not be
// considered a match. Full index scan will be used instead.
if (idx->idx_condition->sameAs(boolean, true))
return false;
}
if (idx->idx_flags & idx_expression)
{
// see if one side or the other is matchable to the index expression