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

Fixed bug #7839 : Potential bug in BETWEEN Operator

This commit is contained in:
Vlad Khorsun 2023-11-13 10:16:28 +02:00
parent 1b0e1c9f90
commit 1574aebf46

View File

@ -656,7 +656,9 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
desc[0] = EVL_expr(tdbb, request, arg1);
const ULONG flags = request->req_flags;
// arg1 IS NULL
const bool null1 = (request->req_flags & req_null);
request->req_flags &= ~req_null;
bool force_equal = (request->req_flags & req_same_tx_upd) != 0;
@ -721,19 +723,22 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
else
desc[1] = EVL_expr(tdbb, request, arg2);
// arg2 IS NULL
const bool null2 = (request->req_flags & req_null);
// An equivalence operator evaluates to true when both operands
// are NULL and behaves like an equality operator otherwise.
// Note that this operator never sets req_null flag
if (blrOp == blr_equiv)
{
if ((flags & req_null) && (request->req_flags & req_null))
if (null1 && null2)
{
request->req_flags &= ~req_null;
return true;
}
if ((flags & req_null) || (request->req_flags & req_null))
if (null1 || null2)
{
request->req_flags &= ~req_null;
return false;
@ -741,13 +746,15 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
}
// If either of expressions above returned NULL set req_null flag
// and return false
// and return false. The exception is BETWEEN operator that could
// return FALSE even when arg2 IS NULL, for example:
// 1 BETWEEN NULL AND 0
if (flags & req_null)
if (null1 || (null2 && (blrOp != blr_between)))
{
request->req_flags |= req_null;
if (request->req_flags & req_null)
return false;
}
force_equal |= (request->req_flags & req_same_tx_upd) != 0;
int comparison; // while the two switch() below are in sync, no need to initialize
@ -761,8 +768,18 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_lss:
case blr_leq:
case blr_neq:
case blr_between:
comparison = MOV_compare(tdbb, desc[0], desc[1]);
break;
case blr_between:
if (!null2)
{
comparison = MOV_compare(tdbb, desc[0], desc[1]);
if (comparison < 0)
return false;
}
else
comparison = -1;
}
// If we are checking equality of record_version
@ -799,8 +816,22 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
case blr_between:
desc[1] = EVL_expr(tdbb, request, arg3);
if (request->req_flags & req_null)
{
if (!null2 && comparison < 0)
request->req_flags &= ~req_null;
return false;
return comparison >= 0 && MOV_compare(tdbb, desc[0], desc[1]) <= 0;
}
{
// arg1 <= arg3
const bool cmp1_3 = (MOV_compare(tdbb, desc[0], desc[1]) <= 0);
if (null2)
{
if (cmp1_3)
request->req_flags |= req_null;
return false;
}
return cmp1_3;
}
case blr_containing:
case blr_starting: