8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 02:03:04 +01:00

Revert back to separate methods, this fixes #7474 (Incorrect condition evaluation)

This commit is contained in:
Dmitry Yemanov 2023-03-01 12:12:18 +03:00
parent eb147356d2
commit 841d1df632
6 changed files with 98 additions and 60 deletions

View File

@ -51,6 +51,13 @@ public:
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual bool ignoreNulls(const StreamList& streams) const
{
return (blrOp == blr_or) ?
arg1->ignoreNulls(streams) && arg2->ignoreNulls(streams) :
BoolExprNode::ignoreNulls(streams);
}
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const; virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
virtual bool sameAs(const ExprNode* other, bool ignoreStreams) const; virtual bool sameAs(const ExprNode* other, bool ignoreStreams) const;
@ -96,11 +103,14 @@ public:
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual bool possiblyUnknown(const StreamList& streams) const virtual bool possiblyUnknown() const
{ {
return (blrOp == blr_equiv) ? return (blrOp == blr_equiv) ? true : BoolExprNode::possiblyUnknown();
arg1->containsAnyStream(streams) || arg2->containsAnyStream(streams) : }
BoolExprNode::possiblyUnknown(streams);
virtual bool ignoreNulls(const StreamList& streams) const
{
return (blrOp == blr_equiv) ? false : BoolExprNode::ignoreNulls(streams);
} }
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
@ -146,9 +156,14 @@ public:
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual bool possiblyUnknown(const StreamList& streams) const virtual bool possiblyUnknown() const
{ {
return arg->containsAnyStream(streams); return true;
}
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
} }
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
@ -222,11 +237,16 @@ public:
return true; return true;
} }
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return true; return true;
} }
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
}
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const; virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
virtual bool sameAs(const ExprNode* other, bool ignoreStreams) const; virtual bool sameAs(const ExprNode* other, bool ignoreStreams) const;

View File

@ -289,14 +289,28 @@ bool ExprNode::sameAs(const ExprNode* other, bool ignoreStreams) const
return true; return true;
} }
bool ExprNode::possiblyUnknown(const StreamList& streams) const bool ExprNode::possiblyUnknown() const
{ {
NodeRefsHolder holder; NodeRefsHolder holder;
getChildren(holder, false); getChildren(holder, false);
for (auto i : holder.refs) for (auto i : holder.refs)
{ {
if (*i && (*i)->possiblyUnknown(streams)) if (*i && (*i)->possiblyUnknown())
return true;
}
return false;
}
bool ExprNode::ignoreNulls(const StreamList& streams) const
{
NodeRefsHolder holder;
getChildren(holder, false);
for (auto i : holder.refs)
{
if (*i && (*i)->ignoreNulls(streams))
return true; return true;
} }

View File

@ -312,14 +312,13 @@ public:
virtual ValueExprNode* pass2(thread_db* tdbb, CompilerScratch* csb); virtual ValueExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual dsc* execute(thread_db* tdbb, Request* request) const; virtual dsc* execute(thread_db* tdbb, Request* request) const;
virtual bool possiblyUnknown(const StreamList& streams) const virtual bool possiblyUnknown() const
{ {
for (const auto& item : args->items) return true;
{ }
if (item->containsAnyStream(streams))
return true;
}
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false; return false;
} }
@ -667,11 +666,6 @@ public:
fb_assert(false); fb_assert(false);
} }
virtual bool possiblyUnknown(const StreamList& /*streams*/) const
{
return true;
}
virtual void collectStreams(SortedStreamList& streamList) const; virtual void collectStreams(SortedStreamList& streamList) const;
virtual bool computable(CompilerScratch* csb, StreamType stream, virtual bool computable(CompilerScratch* csb, StreamType stream,
@ -787,11 +781,16 @@ public:
dsqlDesc = desc; dsqlDesc = desc;
} }
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return false; return false;
} }
virtual bool ignoreNulls(const StreamList& streams) const
{
return streams.exist(fieldStream);
}
virtual void collectStreams(SortedStreamList& streamList) const virtual void collectStreams(SortedStreamList& streamList) const
{ {
if (!streamList.exist(fieldStream)) if (!streamList.exist(fieldStream))
@ -1661,11 +1660,16 @@ public:
virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return false; return false;
} }
virtual bool ignoreNulls(const StreamList& streams) const
{
return streams.exist(recStream);
}
virtual void collectStreams(SortedStreamList& streamList) const virtual void collectStreams(SortedStreamList& streamList) const
{ {
if (!streamList.exist(recStream)) if (!streamList.exist(recStream))
@ -1924,11 +1928,16 @@ public:
return false; return false;
} }
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return true; return true;
} }
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
}
virtual void collectStreams(SortedStreamList& streamList) const; virtual void collectStreams(SortedStreamList& streamList) const;
virtual bool computable(CompilerScratch* csb, StreamType stream, virtual bool computable(CompilerScratch* csb, StreamType stream,
@ -2133,11 +2142,16 @@ public:
virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return true; return true;
} }
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
}
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc); virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const; virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
@ -2182,11 +2196,14 @@ public:
virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual bool possiblyUnknown(const StreamList& streams) const virtual bool possiblyUnknown() const
{ {
return condition->containsAnyStream(streams) || return true;
trueValue->containsAnyStream(streams) || }
falseValue->containsAnyStream(streams);
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
} }
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc); virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);

View File

@ -658,7 +658,10 @@ public:
} }
// Check if expression could return NULL or expression can turn NULL into a true/false. // Check if expression could return NULL or expression can turn NULL into a true/false.
virtual bool possiblyUnknown(const StreamList& streams) const; virtual bool possiblyUnknown() const;
// Check if expression is known to ignore NULLs
virtual bool ignoreNulls(const StreamList& streams) const;
// Verify if this node is allowed in an unmapped boolean. // Verify if this node is allowed in an unmapped boolean.
virtual bool unmappable(const MapNode* mapNode, StreamType shellStream) const; virtual bool unmappable(const MapNode* mapNode, StreamType shellStream) const;
@ -1042,11 +1045,16 @@ public:
virtual AggNode* pass2(thread_db* tdbb, CompilerScratch* csb); virtual AggNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return true; return true;
} }
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
}
virtual void collectStreams(SortedStreamList& /*streamList*/) const virtual void collectStreams(SortedStreamList& /*streamList*/) const
{ {
// ASF: Although in v2.5 the visitor happens normally for the node childs, nod_count has // ASF: Although in v2.5 the visitor happens normally for the node childs, nod_count has
@ -1177,11 +1185,16 @@ public:
fb_assert(false); fb_assert(false);
} }
virtual bool possiblyUnknown(const StreamList& /*streams*/) const virtual bool possiblyUnknown() const
{ {
return true; return true;
} }
virtual bool ignoreNulls(const StreamList& /*streams*/) const
{
return false;
}
virtual bool unmappable(const MapNode* /*mapNode*/, StreamType /*shellStream*/) const virtual bool unmappable(const MapNode* /*mapNode*/, StreamType /*shellStream*/) const
{ {
return false; return false;

View File

@ -2907,9 +2907,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
for (const auto boolean : csb->csb_inner_booleans) for (const auto boolean : csb->csb_inner_booleans)
{ {
if (boolean && if (boolean && boolean->ignoreNulls(streams))
boolean->containsAnyStream(streams) &&
!boolean->possiblyUnknown(streams))
{ {
rse_jointype = blr_left; rse_jointype = blr_left;
break; break;
@ -2923,9 +2921,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
for (const auto boolean : csb->csb_inner_booleans) for (const auto boolean : csb->csb_inner_booleans)
{ {
if (boolean && if (boolean && boolean->ignoreNulls(streams))
boolean->containsAnyStream(streams) &&
!boolean->possiblyUnknown(streams))
{ {
if (rse_jointype == blr_full) if (rse_jointype == blr_full)
{ {

View File

@ -684,29 +684,7 @@ RecordSource* Optimizer::compile(BoolExprNodeStack* parentStack)
{ {
const auto node = iter.object(); const auto node = iter.object();
StreamList streams; if (!isInnerJoin() && node->possiblyUnknown())
if (!isInnerJoin())
{
fb_assert(rse->rse_relations.getCount() == 2);
const auto rse1 = rse->rse_relations[0];
const auto rse2 = rse->rse_relations[1];
fb_assert(rse1 && rse2);
if (isFullJoin())
{
rse1->computeRseStreams(streams);
rse2->computeRseStreams(streams);
}
else // left outer join
{
fb_assert(rse->rse_jointype == blr_left);
rse2->computeRseStreams(streams);
}
}
if (streams.hasData() && node->possiblyUnknown(streams))
{ {
// parent missing conjunctions shouldn't be // parent missing conjunctions shouldn't be
// distributed to FULL OUTER JOIN streams at all // distributed to FULL OUTER JOIN streams at all