"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/jrd/Optimizer.cpp" between
Firebird-3.0.2.32703-0.tar.bz2 and Firebird-3.0.4.33054-0.tar.bz2

About: Firebird is a relational database offering many ANSI SQL standard features.

Optimizer.cpp  (Firebird-3.0.2.32703-0.tar.bz2):Optimizer.cpp  (Firebird-3.0.4.33054-0.tar.bz2)
skipping to change at line 472 skipping to change at line 472
const OptimizerBlk::opt_conjunct* const opt_end = const OptimizerBlk::opt_conjunct* const opt_end =
innerFlag ? optimizer->opt_conjuncts.begin() + optimizer->opt_bas e_missing_conjuncts : innerFlag ? optimizer->opt_conjuncts.begin() + optimizer->opt_bas e_missing_conjuncts :
optimizer->opt_conjuncts.end(); optimizer->opt_conjuncts.end();
InversionCandidate* invCandidate = NULL; InversionCandidate* invCandidate = NULL;
if (relation && !relation->rel_file && !relation->isVirtual()) if (relation && !relation->rel_file && !relation->isVirtual())
{ {
InversionCandidateList inversions; InversionCandidateList inversions;
// Check for any DB_KEY comparisons
for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end
; tail++)
{
BoolExprNode* const node = tail->opt_conjunct_node;
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && no
de)
{
invCandidate = matchDbKey(node);
if (invCandidate)
inversions.add(invCandidate);
}
}
// First, handle "AND" comparisons (all nodes except OR) // First, handle "AND" comparisons (all nodes except OR)
for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end ; tail++) for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end ; tail++)
{ {
BoolExprNode* const node = tail->opt_conjunct_node; BoolExprNode* const node = tail->opt_conjunct_node;
BinaryBoolNode* booleanNode = node->as<BinaryBoolNode>(); BinaryBoolNode* booleanNode = node->as<BinaryBoolNode>();
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && no de && if (!(tail->opt_conjunct_flags & opt_conjunct_used) && no de &&
(!booleanNode || booleanNode->blrOp != blr_or)) (!booleanNode || booleanNode->blrOp != blr_or))
{ {
matchOnIndexes(&indexScratches, node, 1); invCandidate = matchOnIndexes(&indexScratches, no
de, 1);
if (invCandidate)
inversions.add(invCandidate);
} }
} }
getInversionCandidates(&inversions, &indexScratches, 1); getInversionCandidates(&inversions, &indexScratches, 1);
// Second, handle "OR" comparisons // Second, handle "OR" comparisons
for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end ; tail++) for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end ; tail++)
{ {
BoolExprNode* const node = tail->opt_conjunct_node; BoolExprNode* const node = tail->opt_conjunct_node;
BinaryBoolNode* booleanNode = node->as<BinaryBoolNode>(); BinaryBoolNode* booleanNode = node->as<BinaryBoolNode>();
skipping to change at line 705 skipping to change at line 694
const index_desc::idx_repeat* idx_tail = idx->idx_rpt; const index_desc::idx_repeat* idx_tail = idx->idx_rpt;
const index_desc::idx_repeat* const idx_end = idx_tail + idx->idx _count; const index_desc::idx_repeat* const idx_end = idx_tail + idx->idx _count;
NestConst<ValueExprNode>* ptr = sort->expressions.begin(); NestConst<ValueExprNode>* ptr = sort->expressions.begin();
const bool* descending = sort->descending.begin(); const bool* descending = sort->descending.begin();
const int* nullOrder = sort->nullOrder.begin(); const int* nullOrder = sort->nullOrder.begin();
for (const NestConst<ValueExprNode>* const end = sort->expression s.end(); for (const NestConst<ValueExprNode>* const end = sort->expression s.end();
ptr != end; ptr != end;
++ptr, ++descending, ++nullOrder, ++idx_tail) ++ptr, ++descending, ++nullOrder, ++idx_tail)
{ {
ValueExprNode* const node = *ptr; ValueExprNode* const orgNode = *ptr;
FieldNode* fieldNode; FieldNode* fieldNode;
bool nodeMatched = false;
// Collect nodes equivalent to the given sort node
if (idx->idx_flags & idx_expressn) HalfStaticArray<ValueExprNode*, OPT_STATIC_ITEMS> nodes;
nodes.add(orgNode);
for (const OptimizerBlk::opt_conjunct* tail = optimizer->
opt_conjuncts.begin();
tail < optimizer->opt_conjuncts.end(); tail++)
{ {
if (!checkExpressionIndex(idx, node, stream)) BoolExprNode* const boolean = tail->opt_conjunct_
node;
fb_assert(boolean);
ComparativeBoolNode* const cmpNode = boolean->as<
ComparativeBoolNode>();
if (cmpNode && (cmpNode->blrOp == blr_eql || cmpN
ode->blrOp == blr_equiv))
{ {
usableIndex = false; ValueExprNode* const node1 = cmpNode->arg
break; 1;
ValueExprNode* const node2 = cmpNode->arg
2;
if (node1->sameAs(orgNode, false))
nodes.add(node2);
if (node2->sameAs(orgNode, false))
nodes.add(node1);
} }
} }
else if (!(fieldNode = node->as<FieldNode>()) || fieldNod
e->fieldStream != stream) // Check whether any of the equivalent nodes is suitable
{ for index navigation
usableIndex = false;
break; for (ValueExprNode** iter = nodes.begin(); iter != nodes.
} end(); ++iter)
else
{ {
for (; idx_tail < idx_end && fieldNode->fieldId ! ValueExprNode* const node = *iter;
= idx_tail->idx_field; idx_tail++)
{
const int segmentNumber = idx_tail - idx-
>idx_rpt;
if (segmentNumber >= equalSegments) if (idx->idx_flags & idx_expressn)
break; {
if (!checkExpressionIndex(idx, node, stre
am))
continue;
} }
else if (!(fieldNode = node->as<FieldNode>()) ||
if (idx_tail >= idx_end || fieldNode->fieldId != fieldNode->fieldStream != stream)
idx_tail->idx_field)
{ {
usableIndex = false; continue;
break;
} }
} else
{
for (; idx_tail < idx_end && fieldNode->f
ieldId != idx_tail->idx_field; idx_tail++)
{
const int segmentNumber = idx_tai
l - idx->idx_rpt;
if ((*descending && !(idx->idx_flags & idx_descending)) | if (segmentNumber >= equalSegment
| s)
(!*descending && (idx->idx_flags & idx_descending break;
)) || }
((*nullOrder == rse_nulls_first && *descending) |
| if (idx_tail >= idx_end || fieldNode->fie
(*nullOrder == rse_nulls_last && !*descending))) ldId != idx_tail->idx_field)
{ continue;
usableIndex = false; }
break;
}
dsc desc; if ((*descending && !(idx->idx_flags & idx_descen
node->getDesc(tdbb, csb, &desc); ding)) ||
(!*descending && (idx->idx_flags & idx_de
scending)) ||
((*nullOrder == rse_nulls_first && *desce
nding) ||
(*nullOrder == rse_nulls_last && !*desce
nding)))
{
continue;
}
// ASF: "desc.dsc_ttype() > ttype_last_internal" is to av dsc desc;
oid recursion node->getDesc(tdbb, csb, &desc);
// when looking for charsets/collations
if (DTYPE_IS_TEXT(desc.dsc_dtype) && desc.dsc_ttype() > t // ASF: "desc.dsc_ttype() > ttype_last_internal"
type_last_internal) is to avoid recursion
{ // when looking for charsets/collations
const TextType* const tt = INTL_texttype_lookup(t
dbb, desc.dsc_ttype());
if (idx->idx_flags & idx_unique) if (DTYPE_IS_TEXT(desc.dsc_dtype) && desc.dsc_tty pe() > ttype_last_internal)
{ {
if (tt->getFlags() & TEXTTYPE_UNSORTED_UN const TextType* const tt = INTL_texttype_
IQUE) lookup(tdbb, desc.dsc_ttype());
if (idx->idx_flags & idx_unique)
{ {
usableIndex = false; if (tt->getFlags() & TEXTTYPE_UNS
break; ORTED_UNIQUE)
continue;
} }
} else
else
{
// ASF: We currently can't use non-unique
index for GROUP BY and DISTINCT with
// multi-level and insensitive collation.
In NAV, keys are verified with memcmp
// but there we don't know length of each
level.
if (sort->unique && (tt->getFlags() & TEX
TTYPE_SEPARATE_UNIQUE))
{ {
usableIndex = false; // ASF: We currently can't use no
break; n-unique index for GROUP BY and DISTINCT with
// multi-level and insensitive co
llation. In NAV, keys are verified with memcmp
// but there we don't know length
of each level.
if (sort->unique && (tt->getFlags
() & TEXTTYPE_SEPARATE_UNIQUE))
continue;
} }
} }
nodeMatched = true;
break;
}
if (!nodeMatched)
{
usableIndex = false;
break;
} }
} }
if (!usableIndex) if (!usableIndex)
continue; continue;
// Looks like we can do a navigational walk. Remember this candid ate // Looks like we can do a navigational walk. Remember this candid ate
// and compare it against other possible candidates. // and compare it against other possible candidates.
if (!navigationCandidate) if (!navigationCandidate)
skipping to change at line 1997 skipping to change at line 2015
************************************** **************************************
* *
* Functional description * Functional description
* Check whether a boolean is a DB_KEY based comparison. * Check whether a boolean is a DB_KEY based comparison.
* *
**************************************/ **************************************/
// If this isn't an equality, it isn't even interesting // If this isn't an equality, it isn't even interesting
ComparativeBoolNode* cmpNode = boolean->as<ComparativeBoolNode>(); ComparativeBoolNode* cmpNode = boolean->as<ComparativeBoolNode>();
if (!cmpNode || cmpNode->blrOp != blr_eql) if (!cmpNode || (cmpNode->blrOp != blr_eql && cmpNode->blrOp != blr_equiv ))
return NULL; return NULL;
// Find the side of the equality that is potentially a dbkey. If // Find the side of the equality that is potentially a dbkey. If
// neither, make the obvious deduction // neither, make the obvious deduction
ValueExprNode* dbkey = cmpNode->arg1; ValueExprNode* dbkey = cmpNode->arg1;
ValueExprNode* value = cmpNode->arg2; ValueExprNode* value = cmpNode->arg2;
const RecordKeyNode* keyNode = dbkey->as<RecordKeyNode>(); const RecordKeyNode* keyNode = dbkey->as<RecordKeyNode>();
skipping to change at line 2088 skipping to change at line 2106
* If the boolean is an "OR" node then a * If the boolean is an "OR" node then a
* inversion candidate could be returned. * inversion candidate could be returned.
* *
**************************************/ **************************************/
BinaryBoolNode* binaryNode = boolean->as<BinaryBoolNode>(); BinaryBoolNode* binaryNode = boolean->as<BinaryBoolNode>();
// Handle the "OR" case up front // Handle the "OR" case up front
if (binaryNode && binaryNode->blrOp == blr_or) if (binaryNode && binaryNode->blrOp == blr_or)
{ {
InversionCandidateList inversions; InversionCandidateList inversions;
inversions.shrink(0);
// Make list for index matches // Make list for index matches
IndexScratchList indexOrScratches; IndexScratchList indexOrScratches;
// Copy information from caller // Copy information from caller
FB_SIZE_T i = 0; FB_SIZE_T i = 0;
for (; i < inputIndexScratches->getCount(); i++) for (; i < inputIndexScratches->getCount(); i++)
{ {
skipping to change at line 2204 skipping to change at line 2221
} }
} }
return invCandidate; return invCandidate;
} }
if (invCandidate1) if (invCandidate1)
{ {
BoolExprNode* condition = binaryNode->arg2; BoolExprNode* condition = binaryNode->arg2;
if (invCandidate1->condition) if (condition->computable(csb, INVALID_STREAM, false) && !condition->findStream(stream))
{ {
BinaryBoolNode* const newNode = if (invCandidate1->condition)
FB_NEW_POOL(*tdbb->getDefaultPool()) Bina {
ryBoolNode(*tdbb->getDefaultPool(), blr_or); BinaryBoolNode* const newNode =
newNode->arg1 = invCandidate1->condition; FB_NEW_POOL(*tdbb->getDefaultPool
newNode->arg2 = condition; ())
condition = newNode; BinaryBoolNode(*tdbb->get
} DefaultPool(), blr_or);
newNode->arg1 = invCandidate1->condition;
newNode->arg2 = condition;
condition = newNode;
}
invCandidate1->condition = condition; invCandidate1->condition = condition;
return invCandidate1; return invCandidate1;
}
} }
if (invCandidate2) if (invCandidate2)
{ {
BoolExprNode* condition = binaryNode->arg1; BoolExprNode* condition = binaryNode->arg1;
if (invCandidate2->condition) if (condition->computable(csb, INVALID_STREAM, false) && !condition->findStream(stream))
{ {
BinaryBoolNode* const newNode = if (invCandidate2->condition)
FB_NEW_POOL(*tdbb->getDefaultPool()) Bina {
ryBoolNode(*tdbb->getDefaultPool(), blr_or); BinaryBoolNode* const newNode =
newNode->arg1 = invCandidate2->condition; FB_NEW_POOL(*tdbb->getDefaultPool
newNode->arg2 = condition; ())
condition = newNode; BinaryBoolNode(*tdbb->get
} DefaultPool(), blr_or);
newNode->arg1 = invCandidate2->condition;
newNode->arg2 = condition;
condition = newNode;
}
invCandidate2->condition = condition; invCandidate2->condition = condition;
return invCandidate2; return invCandidate2;
}
} }
return NULL; return NULL;
} }
if (binaryNode && binaryNode->blrOp == blr_and) if (binaryNode && binaryNode->blrOp == blr_and)
{ {
// Recursively call this procedure for every boolean // Recursively call this procedure for every boolean
// and finally get candidate inversions. // and finally get candidate inversions.
// Normally we come here from within a OR conjunction. // Normally we come here from within a OR conjunction.
InversionCandidateList inversions; InversionCandidateList inversions;
inversions.shrink(0);
InversionCandidate* invCandidate = matchOnIndexes( InversionCandidate* invCandidate = matchOnIndexes(
inputIndexScratches, binaryNode->arg1, scope); inputIndexScratches, binaryNode->arg1, scope);
if (invCandidate) if (invCandidate)
inversions.add(invCandidate); inversions.add(invCandidate);
invCandidate = matchOnIndexes(inputIndexScratches, binaryNode->ar g2, scope); invCandidate = matchOnIndexes(inputIndexScratches, binaryNode->ar g2, scope);
if (invCandidate) if (invCandidate)
inversions.add(invCandidate); inversions.add(invCandidate);
return makeInversion(&inversions); return makeInversion(&inversions);
} }
// Check for DB_KEY comparison
InversionCandidate* const invCandidate = matchDbKey(boolean);
// Walk through indexes // Walk through indexes
for (FB_SIZE_T i = 0; i < inputIndexScratches->getCount(); i++) for (FB_SIZE_T i = 0; i < inputIndexScratches->getCount(); i++)
{ {
IndexScratch& indexScratch = (*inputIndexScratches)[i]; IndexScratch& indexScratch = (*inputIndexScratches)[i];
// Try to match the boolean against a index. // Try to match the boolean against a index.
if (!(indexScratch.idx->idx_runtime_flags & idx_plan_dont_use) || if (!(indexScratch.idx->idx_runtime_flags & idx_plan_dont_use) ||
(indexScratch.idx->idx_runtime_flags & idx_plan_navigate) ) (indexScratch.idx->idx_runtime_flags & idx_plan_navigate) )
{ {
matchBoolean(&indexScratch, boolean, scope); matchBoolean(&indexScratch, boolean, scope);
} }
} }
return NULL; return invCandidate;
} }
#ifdef OPT_DEBUG_RETRIEVAL #ifdef OPT_DEBUG_RETRIEVAL
void OptimizerRetrieval::printCandidate(const InversionCandidate* candidate) con st void OptimizerRetrieval::printCandidate(const InversionCandidate* candidate) con st
{ {
/************************************** /**************************************
* *
* p r i n t C a n d i d a t e * p r i n t C a n d i d a t e
* *
************************************** **************************************
 End of changes. 34 change blocks. 
105 lines changed or deleted 143 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)