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

Backport bugfix for #7937: Inner join raises error 'no current record for fetch operation' if a stored procedure depends on some table via input parameter and also has an indexed relationship with another table

This commit is contained in:
Dmitry Yemanov 2024-06-17 09:34:20 +03:00
parent ad0e5ce0a9
commit b4b355978f
2 changed files with 32 additions and 10 deletions

View File

@ -174,6 +174,7 @@ namespace
// Save states of the underlying streams and restore them afterwards
StreamStateHolder stateHolder(csb, m_streams);
stateHolder.deactivate();
// Generate record source objects
@ -569,7 +570,6 @@ Optimizer::Optimizer(thread_db* aTdbb, CompilerScratch* aCsb, RseNode* aRse, boo
compileStreams(getPool()),
bedStreams(getPool()),
keyStreams(getPool()),
subStreams(getPool()),
outerStreams(getPool()),
conjuncts(getPool())
{
@ -814,7 +814,7 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
// Go through the record selection expression generating
// record source blocks for all streams
RiverList rivers;
RiverList rivers, dependentRivers;
bool innerSubStream = false;
for (auto node : rse->rse_relations)
@ -840,11 +840,13 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
StreamList localStreams;
rsb->findUsedStreams(localStreams);
bool computable = false;
// AB: Save all outer-part streams
if (isInnerJoin() || (isLeftJoin() && !innerSubStream))
{
subStreams.join(localStreams);
outerStreams.join(localStreams);
if (node->computable(csb, INVALID_STREAM, false))
computable = true;
// Apply local booleans, if any. Note that it's done
// only for inner joins and outer streams of left joins.
@ -854,7 +856,16 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
const auto river = FB_NEW_POOL(getPool()) River(csb, rsb, node, localStreams);
river->deactivate(csb);
rivers.add(river);
if (computable)
{
outerStreams.join(localStreams);
rivers.add(river);
}
else
{
dependentRivers.add(river);
}
}
else
{
@ -883,9 +894,9 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
else
rse->rse_aggregate = aggregate = nullptr;
// AB: Mark the previous used streams (sub-RseNode's) as active
for (const auto subStream : subStreams)
csb->csb_rpt[subStream].activate();
// Activate the priorly used rivers
for (const auto river : rivers)
river->activate(csb);
bool sortCanBeUsed = true;
SortNode* const orgSortNode = sort;
@ -904,7 +915,10 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
// Outer joins are processed their own way
if (!isInnerJoin())
{
rivers.join(dependentRivers);
rsb = generateOuterJoin(rivers, &sort);
}
else
{
// AB: If previous rsb's are already on the stack we can't use
@ -971,13 +985,18 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
}
}
// attempt to form joins in decreasing order of desirability
// Attempt to form joins in decreasing order of desirability
generateInnerJoin(joinStreams, rivers, &sort, rse->rse_plan);
// Re-activate remaining rivers to be hashable/mergeable
for (const auto river : rivers)
river->activate(csb);
// If there are multiple rivers, try some hashing or sort/merging
while (generateEquiJoin(rivers))
;
rivers.join(dependentRivers);
rsb = CrossJoin(csb, rivers).getRecordSource();
// Pick up any residual boolean that may have fallen thru the cracks
@ -2263,6 +2282,9 @@ bool Optimizer::generateEquiJoin(RiverList& orgRivers)
if (iter & CONJUNCT_USED)
continue;
if (!iter->computable(csb, INVALID_STREAM, false))
continue;
NestConst<ValueExprNode> node1;
NestConst<ValueExprNode> node2;

View File

@ -548,7 +548,7 @@ private:
unsigned baseParentConjuncts = 0; // number of conjuncts in our rse + distributed with parent, next are parent
unsigned baseMissingConjuncts = 0; // number of conjuncts in our and parent rse, but without missing
StreamList compileStreams, bedStreams, keyStreams, subStreams, outerStreams;
StreamList compileStreams, bedStreams, keyStreams, outerStreams;
ConjunctList conjuncts;
};