From 41e13dbd28cc6904618eecea62b607e5c60e8b1c Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Wed, 5 Nov 2025 22:25:01 -0300 Subject: [PATCH 1/3] Add TriState::empty() --- src/common/classes/TriState.h | 14 ++++++++++---- src/dsql/parse.y | 8 ++++---- src/jrd/jrd.cpp | 2 +- src/jrd/pag_proto.h | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/common/classes/TriState.h b/src/common/classes/TriState.h index 8a9778aac48..37308593a77 100644 --- a/src/common/classes/TriState.h +++ b/src/common/classes/TriState.h @@ -34,8 +34,14 @@ namespace Firebird { class TriState { public: - TriState() noexcept; - explicit TriState(bool input) noexcept; + static constexpr TriState empty() noexcept + { + return TriState(); + } + +public: + constexpr TriState() noexcept; + explicit constexpr TriState(bool input) noexcept; bool operator ==(const TriState& o) const noexcept { @@ -62,13 +68,13 @@ class TriState }; // The var is left uninitialized. -inline TriState::TriState() noexcept +inline constexpr TriState::TriState() noexcept : m_init(false), m_val(false) { } // The var is initialized to the explicit value. -inline TriState::TriState(bool input) noexcept +inline constexpr TriState::TriState(bool input) noexcept : m_init(true), m_val(input) { } diff --git a/src/dsql/parse.y b/src/dsql/parse.y index a31c7e3d4aa..66ef6b8022e 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2395,7 +2395,7 @@ sql_security_clause %type sql_security_clause_opt sql_security_clause_opt - : /* nothing */ { $$ = TriState(); } + : /* nothing */ { $$ = TriState::empty(); } | sql_security_clause { $$ = $1; } ; @@ -4244,7 +4244,7 @@ trigger_active | INACTIVE { $$ = TriState(false); } | // nothing - { $$ = TriState(); } + { $$ = TriState::empty(); } ; %type trigger_type() @@ -4590,7 +4590,7 @@ alter_op($relationNode) } | DROP SQL SECURITY { - setClause($relationNode->ssDefiner, "SQL SECURITY", TriState()); + setClause($relationNode->ssDefiner, "SQL SECURITY", TriState::empty()); RelationNode::Clause* clause = newNode(RelationNode::Clause::TYPE_ALTER_SQL_SECURITY); $relationNode->clauses.add(clause); @@ -6321,7 +6321,7 @@ optimize_clause : OPTIMIZE optimize_mode { $$ = TriState($2); } | // nothing - { $$ = TriState(); } + { $$ = TriState::empty(); } ; %type optimize_mode diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 700b63d4b94..dcbddf62e9d 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -1860,7 +1860,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // The actual FW mode (if different) will be fixed afterwards by PIO_header(). const TriState newForceWrite = options.dpb_set_force_write ? - TriState(options.dpb_force_write) : TriState(); + TriState(options.dpb_force_write) : TriState::empty(); // Set the FW flag inside the database block to be considered by PIO routines if (newForceWrite.valueOr(true)) diff --git a/src/jrd/pag_proto.h b/src/jrd/pag_proto.h index 084b55a2a34..025b7fd2519 100644 --- a/src/jrd/pag_proto.h +++ b/src/jrd/pag_proto.h @@ -45,7 +45,7 @@ bool PAG_delete_clump_entry(Jrd::thread_db* tdbb, USHORT); void PAG_format_header(Jrd::thread_db*); void PAG_format_pip(Jrd::thread_db*, Jrd::PageSpace& pageSpace); bool PAG_get_clump(Jrd::thread_db*, USHORT, USHORT*, UCHAR*); -void PAG_header(Jrd::thread_db*, bool, const Firebird::TriState newForceWrite = Firebird::TriState()); +void PAG_header(Jrd::thread_db*, bool, const Firebird::TriState newForceWrite = Firebird::TriState::empty()); void PAG_header_init(Jrd::thread_db*); void PAG_init(Jrd::thread_db*); void PAG_init2(Jrd::thread_db*); From 3782f556492b5f2c229d02383479aca337d8701d Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Wed, 5 Nov 2025 22:25:01 -0300 Subject: [PATCH 2/3] Cleanup: get rid of req_null --- src/dsql/AggNodes.cpp | 20 +-- src/dsql/BoolNodes.cpp | 241 ++++++++++----------------- src/dsql/BoolNodes.h | 21 +-- src/dsql/ExprNodes.cpp | 229 +++++++++---------------- src/dsql/Nodes.h | 3 +- src/dsql/StmtNodes.cpp | 27 ++- src/dsql/WinNodes.cpp | 36 ++-- src/jrd/SysFunction.cpp | 165 +++++++++--------- src/jrd/blb.cpp | 4 +- src/jrd/btr.cpp | 10 +- src/jrd/btr.h | 2 +- src/jrd/evl.cpp | 11 +- src/jrd/evl_proto.h | 11 +- src/jrd/exe.cpp | 15 +- src/jrd/exe_proto.h | 2 +- src/jrd/extds/ExtDS.cpp | 9 +- src/jrd/fun.epp | 57 ++----- src/jrd/recsrc/AggregatedStream.cpp | 2 +- src/jrd/recsrc/ConditionalStream.cpp | 2 +- src/jrd/recsrc/FilteredStream.cpp | 69 +++----- src/jrd/recsrc/FirstRowsStream.cpp | 2 +- src/jrd/recsrc/HashJoin.cpp | 4 +- src/jrd/recsrc/IndexTableScan.cpp | 2 +- src/jrd/recsrc/NestedLoopJoin.cpp | 2 +- src/jrd/recsrc/RecordSource.h | 6 +- src/jrd/recsrc/SkipRowsStream.cpp | 2 +- src/jrd/recsrc/SortedStream.cpp | 2 +- src/jrd/recsrc/WindowedStream.cpp | 2 +- src/jrd/req.h | 23 ++- src/jrd/val.h | 5 +- src/jrd/vio.cpp | 8 - 31 files changed, 387 insertions(+), 607 deletions(-) diff --git a/src/dsql/AggNodes.cpp b/src/dsql/AggNodes.cpp index 0025bc6377f..4d86f3c82d7 100644 --- a/src/dsql/AggNodes.cpp +++ b/src/dsql/AggNodes.cpp @@ -388,7 +388,7 @@ bool AggNode::aggPass(thread_db* tdbb, Request* request) const if (arg) { desc = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) + if (!desc) return false; if (distinct) @@ -597,7 +597,7 @@ void AnyValueAggNode::aggPass(thread_db* tdbb, Request* request, dsc* desc) cons { const auto argValue = EVL_expr(tdbb, request, arg); - if (!(request->req_flags & req_null)) + if (!argValue) EVL_make_value(tdbb, argValue, impure); } @@ -1037,7 +1037,7 @@ void ListAggNode::aggPass(thread_db* tdbb, Request* request, dsc* desc) const { const dsc* const delimiterDesc = EVL_expr(tdbb, request, delimiter); - if (request->req_flags & req_null) + if (!delimiterDesc) { // Mark the result as NULL. impure->vlu_desc.dsc_dtype = 0; @@ -2031,11 +2031,11 @@ bool CorrAggNode::aggPass(thread_db* tdbb, Request* request) const dsc* desc2 = NULL; desc = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) + if (!desc) return false; desc2 = EVL_expr(tdbb, request, arg2); - if (request->req_flags & req_null) + if (!desc2) return false; ++impure->vlux_count; @@ -2307,11 +2307,11 @@ bool RegrAggNode::aggPass(thread_db* tdbb, Request* request) const dsc* desc2 = NULL; desc = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) + if (!desc) return false; desc2 = EVL_expr(tdbb, request, arg2); - if (request->req_flags & req_null) + if (!desc2) return false; ++impure->vlux_count; @@ -2559,12 +2559,10 @@ void RegrCountAggNode::aggInit(thread_db* tdbb, Request* request) const bool RegrCountAggNode::aggPass(thread_db* tdbb, Request* request) const { - EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) + if (!EVL_expr(tdbb, request, arg)) return false; - EVL_expr(tdbb, request, arg2); - if (request->req_flags & req_null) + if (!EVL_expr(tdbb, request, arg2)) return false; impure_value_ex* impure = request->getImpure(impureOffset); diff --git a/src/dsql/BoolNodes.cpp b/src/dsql/BoolNodes.cpp index c77dc540743..5e7c0b4574f 100644 --- a/src/dsql/BoolNodes.cpp +++ b/src/dsql/BoolNodes.cpp @@ -244,7 +244,7 @@ BoolExprNode* BinaryBoolNode::copy(thread_db* tdbb, NodeCopier& copier) const return node; } -bool BinaryBoolNode::execute(thread_db* tdbb, Request* request) const +TriState BinaryBoolNode::execute(thread_db* tdbb, Request* request) const { switch (blrOp) { @@ -256,10 +256,10 @@ bool BinaryBoolNode::execute(thread_db* tdbb, Request* request) const } fb_assert(false); - return false; + return TriState::empty(); } -bool BinaryBoolNode::executeAnd(thread_db* tdbb, Request* request) const +TriState BinaryBoolNode::executeAnd(thread_db* tdbb, Request* request) const { // If either operand is false, then the result is false; // If both are true, the result is true; @@ -277,35 +277,22 @@ bool BinaryBoolNode::executeAnd(thread_db* tdbb, Request* request) const // N T N // N N N - const bool value1 = arg1->execute(tdbb, request); - - // Save null state and get other operand. - const USHORT firstnull = request->req_flags & req_null; - request->req_flags &= ~req_null; + const TriState value1 = arg1->execute(tdbb, request); - if (!value1 && !firstnull) + if (value1.isAssigned()) { - // First term is false, why the whole expression is false. - // NULL flag is already turned off a few lines above. - return false; - } + if (!value1.asBool()) + return TriState(false); - const bool value2 = arg2->execute(tdbb, request); - const USHORT secondnull = request->req_flags & req_null; - request->req_flags &= ~req_null; - - if (!value2 && !secondnull) - return false; // at least one operand was false + return arg2->execute(tdbb, request); + } - if (value1 && value2) - return true; // both true + const TriState value2 = arg2->execute(tdbb, request); - // otherwise, return null - request->req_flags |= req_null; - return false; + return value2 == TriState(false) ? TriState(false) : TriState::empty(); } -bool BinaryBoolNode::executeOr(thread_db* tdbb, Request* request) const +TriState BinaryBoolNode::executeOr(thread_db* tdbb, Request* request) const { // If either operand is true, then the result is true; // If both are false, the result is false; @@ -323,32 +310,19 @@ bool BinaryBoolNode::executeOr(thread_db* tdbb, Request* request) const // N T T // N N N - const bool value1 = arg1->execute(tdbb, request); + const TriState first = arg1->execute(tdbb, request); - const ULONG flags = request->req_flags; - request->req_flags &= ~req_null; - - if (value1) + if (first.isAssigned()) { - // First term is true, why the whole expression is true. - // NULL flag is already turned off a few lines above. - return true; - } - - const bool value2 = arg2->execute(tdbb, request); + if (first.asBool()) + return TriState(true); - if (value1 || value2) - { - request->req_flags &= ~req_null; - return true; + return arg2->execute(tdbb, request); } - // restore saved NULL state - - if (flags & req_null) - request->req_flags |= req_null; + const TriState value2 = arg2->execute(tdbb, request); - return false; + return value2 == TriState(true) ? TriState(true) : TriState::empty(); } @@ -731,9 +705,9 @@ void ComparativeBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, st } } -bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const +TriState ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const { - dsc* desc[2] = {NULL, NULL}; + dsc* desc[2] = {nullptr, nullptr}; bool computed_invariant = false; request->req_flags &= ~req_same_tx_upd; @@ -745,9 +719,8 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const desc[0] = EVL_expr(tdbb, request, arg1); // arg1 IS NULL - const bool null1 = (request->req_flags & req_null); + const bool null1 = !desc[0]; - request->req_flags &= ~req_null; bool force_equal = (request->req_flags & req_same_tx_upd) != 0; // Currently only nod_like, nod_contains, nod_starts and nod_similar may be marked invariant @@ -771,20 +744,15 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const if (impure->vlu_flags & VLU_computed) { - if (impure->vlu_flags & VLU_null) - request->req_flags |= req_null; - else + if (!(impure->vlu_flags & VLU_null)) computed_invariant = true; } else { desc[1] = EVL_expr(tdbb, request, arg2); - if (request->req_flags & req_null) - { - impure->vlu_flags |= VLU_computed; - impure->vlu_flags |= VLU_null; - } + if (!desc[1]) + impure->vlu_flags |= VLU_computed | VLU_null; else { impure->vlu_flags &= ~VLU_null; @@ -812,37 +780,27 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const desc[1] = EVL_expr(tdbb, request, arg2); // arg2 IS NULL - const bool null2 = (request->req_flags & req_null); + const bool null2 = !computed_invariant && !desc[1]; // 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 (null1 && null2) - { - request->req_flags &= ~req_null; - return true; - } + return TriState(true); if (null1 || null2) - { - request->req_flags &= ~req_null; - return false; - } + return TriState(false); } - // If either of expressions above returned NULL set req_null flag - // and return false. The exception is BETWEEN operator that could + // If either of expressions above returned NULL return unknown. + // The exception is BETWEEN operator that could // return FALSE even when arg2 IS NULL, for example: // 1 BETWEEN NULL AND 0 if (null1 || (null2 && (blrOp != blr_between))) - { - request->req_flags |= req_null; - return false; - } + return TriState::empty(); force_equal |= (request->req_flags & req_same_tx_upd) != 0; int comparison; // while the two switch() below are in sync, no need to initialize @@ -864,7 +822,7 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const { comparison = MOV_compare(tdbb, desc[0], desc[1]); if (comparison < 0) - return false; + return TriState(false); } else comparison = -1; @@ -879,47 +837,38 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const if (recVersionNode && recVersionNode->blrOp == blr_record_version && force_equal) comparison = 0; - request->req_flags &= ~(req_null | req_same_tx_upd); + request->req_flags &= ~req_same_tx_upd; switch (blrOp) { case blr_eql: case blr_equiv: - return comparison == 0; + return TriState(comparison == 0); case blr_gtr: - return comparison > 0; + return TriState(comparison > 0); case blr_geq: - return comparison >= 0; + return TriState(comparison >= 0); case blr_lss: - return comparison < 0; + return TriState(comparison < 0); case blr_leq: - return comparison <= 0; + return TriState(comparison <= 0); case blr_neq: - return comparison != 0; + return TriState(comparison != 0); 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; - } + if (!desc[1]) + return !null2 && comparison < 0 ? TriState(false) : TriState::empty(); + { // 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; + return null2 && cmp1_3 ? TriState::empty() : TriState(cmp1_3); } case blr_containing: @@ -930,15 +879,15 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const return stringBoolean(tdbb, request, desc[0], desc[1], computed_invariant); case blr_matching2: - return sleuth(tdbb, request, desc[0], desc[1]); + return TriState(sleuth(tdbb, request, desc[0], desc[1])); } - return false; + return TriState(false); } // Perform one of the complex string functions CONTAINING, MATCHES, or STARTS WITH. -bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, dsc* desc1, - dsc* desc2, bool computedInvariant) const +TriState ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, + dsc* desc1, dsc* desc2, bool computedInvariant) const { SET_TDBB(tdbb); @@ -950,7 +899,7 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, dsc* { // No MATCHES support for blob if (blrOp == blr_matching) - return false; + return TriState(false); type1 = desc1->dsc_sub_type == isc_blob_text ? desc1->dsc_blob_ttype() : ttype_none; } @@ -971,7 +920,7 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, dsc* // Convert ESCAPE to operation character set dsc* desc = EVL_expr(tdbb, request, arg3); - if (request->req_flags & req_null) + if (!desc) { if (nodFlags & FLAG_INVARIANT) { @@ -979,7 +928,8 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, dsc* impure->vlu_flags |= VLU_computed; impure->vlu_flags |= VLU_null; } - return false; + + return TriState::empty(); } escapeLen = MOV_make_string(tdbb, desc, type1, @@ -1095,23 +1045,29 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, dsc* if (evaluator) { evaluator->process(str, strLen); - return evaluator->result(); + return TriState(evaluator->result()); } else { if (blrOp == blr_containing) - return obj->contains(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen); + return TriState(obj->contains(*tdbb->getDefaultPool(), + str, strLen, patternStr, patternLen)); else if (blrOp == blr_starting) - return obj->starts(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen); + return TriState(obj->starts(*tdbb->getDefaultPool(), + str, strLen, patternStr, patternLen)); else if (blrOp == blr_like) - return obj->like(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen, escapeStr, escapeLen); + return TriState(obj->like(*tdbb->getDefaultPool(), str, strLen, + patternStr, patternLen, escapeStr, escapeLen)); else if (blrOp == blr_similar) { - return obj->similarTo(tdbb, *tdbb->getDefaultPool(), - str, strLen, patternStr, patternLen, escapeStr, escapeLen); + return TriState(obj->similarTo(tdbb, *tdbb->getDefaultPool(), + str, strLen, patternStr, patternLen, escapeStr, escapeLen)); } else // blr_matching - return obj->matches(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen); + { + return TriState(obj->matches(*tdbb->getDefaultPool(), + str, strLen, patternStr, patternLen)); + } } } @@ -1139,12 +1095,12 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, dsc* break; } - return evaluator->result(); + return TriState(evaluator->result()); } // Execute SLEUTH operator. -bool ComparativeBoolNode::sleuth(thread_db* tdbb, Request* request, const dsc* desc1, - const dsc* desc2) const +bool ComparativeBoolNode::sleuth(thread_db* tdbb, Request* request, + const dsc* desc1, const dsc* desc2) const { SET_TDBB(tdbb); @@ -1563,16 +1519,18 @@ void InListBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::fu lookup = FB_NEW_POOL(csb->csb_pool) LookupValueList(csb->csb_pool, list, impureOffset); } -bool InListBoolNode::execute(thread_db* tdbb, Request* request) const +TriState InListBoolNode::execute(thread_db* tdbb, Request* request) const { if (const auto argDesc = EVL_expr(tdbb, request, arg)) { - bool anyMatch = false, anyNull = false; + bool anyMatch = false; + bool anyNull = false; if (nodFlags & FLAG_INVARIANT) { - anyMatch = lookup->find(tdbb, request, arg, argDesc); - anyNull = (request->req_flags & req_null); + const auto lookupState = lookup->find(tdbb, request, arg, argDesc); + anyMatch = lookupState.asBool(); + anyNull = lookupState.isUnknown(); } else { @@ -1587,22 +1545,18 @@ bool InListBoolNode::execute(thread_db* tdbb, Request* request) const } } else - { anyNull = true; - } } } - request->req_flags &= ~req_null; - if (anyMatch) - return true; + return TriState(true); - if (anyNull) - request->req_flags |= req_null; + if (!anyNull) + return TriState(false); } - return false; // for argDesc == nullptr, req_null is already set by EVL_expr() + return TriState::empty(); } @@ -1690,17 +1644,9 @@ void MissingBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::f arg->getDesc(tdbb, csb, &descriptor_a); } -bool MissingBoolNode::execute(thread_db* tdbb, Request* request) const +TriState MissingBoolNode::execute(thread_db* tdbb, Request* request) const { - EVL_expr(tdbb, request, arg); - - if (request->req_flags & req_null) - { - request->req_flags &= ~req_null; - return true; - } - - return false; + return TriState(!EVL_expr(tdbb, request, arg)); } @@ -1765,14 +1711,10 @@ BoolExprNode* NotBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb) return BoolExprNode::pass1(tdbb, csb); } -bool NotBoolNode::execute(thread_db* tdbb, Request* request) const +TriState NotBoolNode::execute(thread_db* tdbb, Request* request) const { - bool value = arg->execute(tdbb, request); - - if (request->req_flags & req_null) - return false; - - return !value; + const TriState value = arg->execute(tdbb, request); + return value.isUnknown() ? TriState::empty() : TriState(!value.asBool()); } // Replace NOT with an appropriately inverted condition, if possible. @@ -2117,7 +2059,7 @@ void RseBoolNode::pass2Boolean(thread_db* tdbb, CompilerScratch* csb, std::funct csb->csb_fors.add(subQuery); } -bool RseBoolNode::execute(thread_db* tdbb, Request* request) const +TriState RseBoolNode::execute(thread_db* tdbb, Request* request) const { USHORT* invariant_flags; impure_value* impure; @@ -2132,11 +2074,12 @@ bool RseBoolNode::execute(thread_db* tdbb, Request* request) const // An invariant node has already been computed. if (blrOp == blr_ansi_any && (*invariant_flags & VLU_null)) - request->req_flags |= req_null; - else - request->req_flags &= ~req_null; + { + fb_assert(impure->vlu_misc.vlu_short == 0); + return TriState::empty(); + } - return impure->vlu_misc.vlu_short != 0; + return TriState(impure->vlu_misc.vlu_short != 0); } } @@ -2167,22 +2110,22 @@ bool RseBoolNode::execute(thread_db* tdbb, Request* request) const savePoint.release(); - if (blrOp == blr_any || blrOp == blr_unique) - request->req_flags &= ~req_null; - // If this is an invariant node, save the return value. if (nodFlags & FLAG_INVARIANT) { *invariant_flags |= VLU_computed; + /* Cannot see how the old code can mark the flag with VLU_null + // Note that above only blr_ansi_any is considered when looking for VLU_null if ((blrOp == blr_ansi_any || blrOp == blr_ansi_all) && (request->req_flags & req_null)) *invariant_flags |= VLU_null; + */ impure->vlu_misc.vlu_short = value ? TRUE : FALSE; } - return value; + return TriState(value); } // Try to convert nodes of expression: diff --git a/src/dsql/BoolNodes.h b/src/dsql/BoolNodes.h index bf121ff595a..bdf0301f654 100644 --- a/src/dsql/BoolNodes.h +++ b/src/dsql/BoolNodes.h @@ -61,11 +61,11 @@ class BinaryBoolNode final : public TypedNode process) override; - bool execute(thread_db* tdbb, Request* request) const override; + Firebird::TriState execute(thread_db* tdbb, Request* request) const override; private: - bool stringBoolean(thread_db* tdbb, Request* request, dsc* desc1, dsc* desc2, + Firebird::TriState stringBoolean(thread_db* tdbb, Request* request, dsc* desc1, dsc* desc2, bool computedInvariant) const; - bool sleuth(thread_db* tdbb, Request* request, const dsc* desc1, const dsc* desc2) const; + bool sleuth(thread_db* tdbb, Request* request, const dsc* desc1, + const dsc* desc2) const; BoolExprNode* createRseNode(DsqlCompilerScratch* dsqlScratch, UCHAR rseBlrOp); @@ -185,7 +186,7 @@ class InListBoolNode final : public TypedNode process) override; - bool execute(thread_db* tdbb, Request* request) const override; + Firebird::TriState execute(thread_db* tdbb, Request* request) const override; private: BoolExprNode* decompose(CompilerScratch* csb); @@ -227,7 +228,7 @@ class MissingBoolNode final : public TypedNode process) override; - bool execute(thread_db* tdbb, Request* request) const override; + Firebird::TriState execute(thread_db* tdbb, Request* request) const override; public: bool dsqlUnknown; @@ -254,7 +255,7 @@ class NotBoolNode final : public TypedNode process) override; - bool execute(thread_db* tdbb, Request* request) const override; + Firebird::TriState execute(thread_db* tdbb, Request* request) const override; private: BoolExprNode* convertNeqAllToNotAny(thread_db* tdbb, CompilerScratch* csb); diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 458e521d8c7..83108cb2ee5 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -285,17 +285,15 @@ const SortedValueList* LookupValueList::init(thread_db* tdbb, Request* request) return createList(); } -bool LookupValueList::find(thread_db* tdbb, Request* request, const ValueExprNode* value, const dsc* desc) const +TriState LookupValueList::find(thread_db* tdbb, Request* request, const ValueExprNode* value, const dsc* desc) const { const auto sortedList = init(tdbb, request); fb_assert(sortedList && sortedList->hasData()); if (!sortedList->front().desc) - request->req_flags |= req_null; - else - request->req_flags &= ~req_null; + return TriState::empty(); - return sortedList->exist(SortValueItem(value, desc)); + return TriState(sortedList->exist(SortValueItem(value, desc))); } //-------------------- @@ -2002,25 +2000,15 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; - // Evaluate arguments. If either is null, result is null, but in // any case, evaluate both, since some expressions may later depend // on mappings which are developed here const dsc* desc1 = EVL_expr(tdbb, request, arg1); - const ULONG flags = request->req_flags; - request->req_flags &= ~req_null; - const dsc* desc2 = EVL_expr(tdbb, request, arg2); - // restore saved NULL state - - if (flags & req_null) - request->req_flags |= req_null; - - if (request->req_flags & req_null) - return NULL; + if (!desc1 || !desc2) + return nullptr; EVL_make_value(tdbb, desc1, impure); @@ -3357,17 +3345,16 @@ ValueExprNode* AtNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* AtNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; dsc* dateTimeDesc = EVL_expr(tdbb, request, dateTimeArg); - if (!dateTimeDesc || (request->req_flags & req_null)) - return NULL; + if (!dateTimeDesc) + return nullptr; dsc* zoneDesc = zoneArg ? EVL_expr(tdbb, request, zoneArg) : NULL; - if (zoneArg && (!zoneDesc || (request->req_flags & req_null))) - return NULL; + if (zoneArg && !zoneDesc) + return nullptr; USHORT zone; @@ -3474,12 +3461,13 @@ ValueExprNode* BoolAsValueNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* BoolAsValueNode::execute(thread_db* tdbb, Request* request) const { - UCHAR booleanVal = (UCHAR) boolean->execute(tdbb, request); + const auto booleanState = boolean->execute(tdbb, request); - if (request->req_flags & req_null) - return NULL; + if (booleanState.isUnknown()) + return nullptr; const auto impure = request->getImpure(impureOffset); + UCHAR booleanVal = (UCHAR) booleanState.asBool(); dsc desc; desc.makeBoolean(&booleanVal); @@ -3716,9 +3704,6 @@ dsc* CastNode::execute(thread_db* tdbb, Request* request) const { dsc* value = EVL_expr(tdbb, request, source); - if (request->req_flags & req_null) - value = nullptr; - const auto impure = request->getImpure(impureOffset); return perform(tdbb, impure, value, &castDesc, itemInfo, format); @@ -4159,16 +4144,10 @@ ValueExprNode* ConcatenateNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* ConcatenateNode::execute(thread_db* tdbb, Request* request) const { const dsc* value1 = EVL_expr(tdbb, request, arg1); - const ULONG flags = request->req_flags; const dsc* value2 = EVL_expr(tdbb, request, arg2); - // restore saved NULL state - - if (flags & req_null) - request->req_flags |= req_null; - - if (request->req_flags & req_null) - return NULL; + if (!value1 || !value2) + return nullptr; impure_value* impure = request->getImpure(impureOffset); dsc desc; @@ -4392,7 +4371,6 @@ ValueExprNode* CurrentDateNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* CurrentDateNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; // Use the request timestamp. impure->vlu_misc.vlu_sql_date = request->getLocalTimeStamp().timestamp_date; @@ -4495,7 +4473,6 @@ ValueExprNode* CurrentTimeNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/) dsc* CurrentTimeNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; // Use the request timestamp. impure->vlu_misc.vlu_sql_time_tz = request->getTimeTz(); @@ -4600,7 +4577,6 @@ ValueExprNode* CurrentTimeStampNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch dsc* CurrentTimeStampNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; // Use the request timestamp. impure->vlu_misc.vlu_timestamp_tz = request->getTimeStampTz(); @@ -4678,7 +4654,6 @@ ValueExprNode* CurrentRoleNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* CurrentRoleNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; impure->vlu_desc.dsc_dtype = dtype_text; impure->vlu_desc.dsc_sub_type = 0; @@ -4850,7 +4825,6 @@ ValueExprNode* CurrentUserNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* CurrentUserNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; impure->vlu_desc.dsc_dtype = dtype_text; impure->vlu_desc.dsc_sub_type = 0; @@ -5100,7 +5074,7 @@ dsc* DecodeNode::execute(thread_db* tdbb, Request* request) const // The comparisons are done with "equal" operator semantics, so if the test value is // NULL we have nothing to compare. - if (testDesc && !(request->req_flags & req_null)) + if (testDesc) { const NestConst* valuesPtr = values->items.begin(); @@ -5108,7 +5082,7 @@ dsc* DecodeNode::execute(thread_db* tdbb, Request* request) const { dsc* desc = EVL_expr(tdbb, request, condition); - if (desc && !(request->req_flags & req_null) && MOV_compare(tdbb, testDesc, desc) == 0) + if (desc && MOV_compare(tdbb, testDesc, desc) == 0) return EVL_expr(tdbb, request, *valuesPtr); ++valuesPtr; @@ -5463,10 +5437,6 @@ dsc* DerivedExprNode::execute(thread_db* tdbb, Request* request) const if (request->req_rpb[i].rpb_number.isValid()) { value = EVL_expr(tdbb, request, arg); - - if (request->req_flags & req_null) - value = NULL; - break; } } @@ -5751,12 +5721,11 @@ ValueExprNode* ExtractNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* ExtractNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; dsc* value = EVL_expr(tdbb, request, arg); - if (!value || (request->req_flags & req_null)) - return NULL; + if (!value) + return nullptr; impure->vlu_desc.makeShort(0, &impure->vlu_misc.vlu_short); @@ -7359,8 +7328,6 @@ ValueExprNode* GenIdNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* GenIdNode::execute(thread_db* tdbb, Request* request) const { - request->req_flags &= ~req_null; - impure_value* const impure = request->getImpure(impureOffset); SINT64 change = step; @@ -7368,8 +7335,8 @@ dsc* GenIdNode::execute(thread_db* tdbb, Request* request) const { const dsc* const value = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) - return NULL; + if (!value) + return nullptr; change = MOV_get_int64(tdbb, value, 0); } @@ -7558,11 +7525,10 @@ ValueExprNode* InternalInfoNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* InternalInfoNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; const dsc* value = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) - return NULL; + if (!value) + return nullptr; fb_assert(value->dsc_dtype == dtype_long); const InfoType infoType = static_cast(*reinterpret_cast(value->dsc_address)); @@ -8431,7 +8397,6 @@ ValueExprNode* LocalTimeNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/) dsc* LocalTimeNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; // Use the request timestamp. impure->vlu_misc.vlu_sql_time = request->getLocalTimeStamp().timestamp_time; @@ -8523,7 +8488,6 @@ ValueExprNode* LocalTimeStampNode::dsqlPass(DsqlCompilerScratch* /*dsqlScratch*/ dsc* LocalTimeStampNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; // Use the request timestamp. impure->vlu_misc.vlu_timestamp = request->getLocalTimeStamp(); @@ -9108,11 +9072,9 @@ ValueExprNode* NegateNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* NegateNode::execute(thread_db* tdbb, Request* request) const { - request->req_flags &= ~req_null; - const dsc* desc = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) - return NULL; + if (!desc) + return nullptr; impure_value* const impure = request->getImpure(impureOffset); EVL_make_value(tdbb, desc, impure); @@ -10038,13 +10000,13 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const tdbb, &thread_db::getRequest, &thread_db::setRequest, paramRequest); const dsc* desc; - request->req_flags &= ~req_null; + bool isNull = false; if (argFlag) { desc = EVL_expr(tdbb, request, argFlag); if (MOV_get_long(tdbb, desc, 0)) - request->req_flags |= req_null; + isNull = true; } desc = &message->getFormat(paramRequest)->fmt_desc[argNumber]; @@ -10055,7 +10017,7 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const retDesc->dsc_scale = desc->dsc_scale; retDesc->dsc_sub_type = desc->dsc_sub_type; - if (!(request->req_flags & req_null)) + if (!isNull) { if (impureForOuter) EVL_make_value(tdbb, retDesc, impureForOuter); @@ -10066,7 +10028,7 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const if (!(*impureFlags & VLU_checked)) { - if (!(request->req_flags & req_null)) + if (!isNull) { if (DTYPE_IS_TEXT(retDesc->dsc_dtype)) @@ -10118,14 +10080,14 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const if (argInfo) { EVL_validate(tdbb, Item(Item::TYPE_PARAMETER, message->messageNumber, argNumber), - argInfo, retDesc, request->req_flags & req_null); + argInfo, retDesc, isNull); } *impureFlags |= VLU_checked; } // This block is after validation because having here a malformed data would produce a wrong result - if (!(request->req_flags & req_null) && retDesc->dsc_dtype == dtype_text && maxCharLength != 0) + if (!isNull && retDesc->dsc_dtype == dtype_text && maxCharLength != 0) { // Data in the message buffer can be in a padded Firebird format or in an application-defined format with real length. // API provides no way to distinguish these cases so we must use some heuristics: @@ -10143,7 +10105,7 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const } } - return (request->req_flags & req_null) ? nullptr : retDesc; + return isNull ? nullptr : retDesc; } @@ -10597,10 +10559,7 @@ dsc* RecordKeyNode::execute(thread_db* /*tdbb*/, Request* request) const // If it doesn't point to a valid record, return NULL if (!rpb->rpb_number.isValid() || rpb->rpb_number.isBof() || !relation) - { - request->req_flags |= req_null; - return NULL; - } + return nullptr; // Format dbkey as vector of relation id, record number @@ -10662,10 +10621,7 @@ dsc* RecordKeyNode::execute(thread_db* /*tdbb*/, Request* request) const // If it doesn't point to a valid record, return NULL. if (!rpb->rpb_number.isValid() || !relation || relation->isVirtual() || relation->rel_file) - { - request->req_flags |= req_null; - return NULL; - } + return nullptr; impure->vlu_misc.vlu_int64 = rpb->rpb_transaction_nr; impure->vlu_desc.makeInt64(0, &impure->vlu_misc.vlu_int64); @@ -10777,8 +10733,8 @@ dsc* ScalarNode::execute(thread_db* tdbb, Request* request) const impure_value* const impure = request->getImpure(impureOffset); const dsc* desc = EVL_expr(tdbb, request, field); - if (request->req_flags & req_null) - return NULL; + if (!desc) + return nullptr; if (desc->dsc_dtype != dtype_array) IBERROR(261); // msg 261 scalar operator used on field which is not an array @@ -10793,10 +10749,10 @@ dsc* ScalarNode::execute(thread_db* tdbb, Request* request) const { const dsc* temp = EVL_expr(tdbb, request, subscript); - if (temp && !(request->req_flags & req_null)) + if (temp) numSubscripts[iter++] = MOV_get_long(tdbb, temp, 0); else - return NULL; + return nullptr; } blb::scalar(tdbb, request->req_transaction, reinterpret_cast(desc->dsc_address), @@ -10989,12 +10945,11 @@ ValueExprNode* StrCaseNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* StrCaseNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; const dsc* value = EVL_expr(tdbb, request, arg); - if (request->req_flags & req_null) - return NULL; + if (!value) + return nullptr; TextType* textType = INTL_texttype_lookup(tdbb, value->getTextType()); CharSet* charSet = textType->getCharSet(); @@ -11207,14 +11162,13 @@ ValueExprNode* StrLenNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* StrLenNode::execute(thread_db* tdbb, Request* request) const { impure_value* const impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; const dsc* value = EVL_expr(tdbb, request, arg); impure->vlu_desc.makeInt64(0, &impure->vlu_misc.vlu_int64); - if (!value || (request->req_flags & req_null)) - return NULL; + if (!value) + return nullptr; FB_UINT64 length; @@ -11672,7 +11626,6 @@ ValueExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const { impure_value* impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; dsc* desc = &impure->vlu_desc; USHORT* invariant_flags = NULL; @@ -11684,13 +11637,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const if (*invariant_flags & VLU_computed) { // An invariant node has already been computed. - - if (*invariant_flags & VLU_null) - request->req_flags |= req_null; - else - request->req_flags &= ~req_null; - - return (request->req_flags & req_null) ? NULL : desc; + return (*invariant_flags & VLU_null) ? nullptr : desc; } } @@ -11699,7 +11646,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const impure->vlu_desc.dsc_length = sizeof(SLONG); impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_long; - ULONG flag = req_null; + bool isNull = true; StableCursorSavePoint savePoint(tdbb, request->req_transaction, blrOp == blr_via && ownSavepoint); @@ -11715,7 +11662,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const switch (blrOp) { case blr_count: - flag = 0; + isNull = false; while (subQuery->fetch(tdbb)) ++impure->vlu_misc.vlu_long; break; @@ -11725,15 +11672,15 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const while (subQuery->fetch(tdbb)) { dsc* value = EVL_expr(tdbb, request, value1); - if (request->req_flags & req_null) + if (!value) continue; int result; - if (flag || ((result = MOV_compare(tdbb, value, desc)) < 0 && blrOp == blr_minimum) || + if (isNull || ((result = MOV_compare(tdbb, value, desc)) < 0 && blrOp == blr_minimum) || (blrOp != blr_minimum && result > 0)) { - flag = 0; + isNull = false; EVL_make_value(tdbb, value, impure); } } @@ -11744,7 +11691,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const while (subQuery->fetch(tdbb)) { desc = EVL_expr(tdbb, request, value1); - if (request->req_flags & req_null) + if (!desc) continue; // Note: if the field being SUMed or AVERAGEd is short or long, @@ -11760,7 +11707,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const if (blrOp == blr_total) { - flag = 0; + isNull = false; break; } @@ -11772,7 +11719,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const impure->vlu_desc.dsc_dtype = DEFAULT_DOUBLE; impure->vlu_desc.dsc_length = sizeof(double); impure->vlu_desc.dsc_scale = 0; - flag = 0; + isNull = false; break; case blr_via: @@ -11786,7 +11733,7 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const ERR_post(Arg::Gds(isc_from_no_match)); } - flag = request->req_flags; + isNull = !desc; break; default: @@ -11798,8 +11745,6 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const try { subQuery->close(tdbb); - request->req_flags &= ~req_null; - request->req_flags |= flag; } catch (const Exception&) {} // ignore any error to report the original one @@ -11813,8 +11758,8 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const savePoint.release(); - request->req_flags &= ~req_null; - request->req_flags |= flag; + if (isNull) + desc = nullptr; // If this is an invariant node, save the return value. If the descriptor does not point to the // impure area for this node then point this node's descriptor to the correct place; @@ -11824,13 +11769,13 @@ dsc* SubQueryNode::execute(thread_db* tdbb, Request* request) const { *invariant_flags |= VLU_computed; - if (request->req_flags & req_null) + if (!desc) *invariant_flags |= VLU_null; if (desc && (desc != &impure->vlu_desc)) impure->vlu_desc = *desc; } - return (request->req_flags & req_null) ? NULL : desc; + return desc; } @@ -12000,19 +11945,14 @@ dsc* SubstringNode::execute(thread_db* tdbb, Request* request) const // Run all expression arguments. const dsc* exprDesc = EVL_expr(tdbb, request, expr); - exprDesc = (request->req_flags & req_null) ? NULL : exprDesc; - const dsc* startDesc = EVL_expr(tdbb, request, start); - startDesc = (request->req_flags & req_null) ? NULL : startDesc; - const dsc* lengthDesc = EVL_expr(tdbb, request, length); - lengthDesc = (request->req_flags & req_null) ? NULL : lengthDesc; if (exprDesc && startDesc && lengthDesc) return perform(tdbb, impure, exprDesc, startDesc, lengthDesc); - // If any of them is NULL, return NULL. - return NULL; + // If any of them IS NULL, return nullptr. + return nullptr; } dsc* SubstringNode::perform(thread_db* tdbb, impure_value* impure, const dsc* valueDsc, @@ -12306,17 +12246,12 @@ dsc* SubstringSimilarNode::execute(thread_db* tdbb, Request* request) const // Run all expression arguments. const dsc* exprDesc = EVL_expr(tdbb, request, expr); - exprDesc = (request->req_flags & req_null) ? NULL : exprDesc; - const dsc* patternDesc = EVL_expr(tdbb, request, pattern); - patternDesc = (request->req_flags & req_null) ? NULL : patternDesc; - const dsc* escapeDesc = EVL_expr(tdbb, request, escape); - escapeDesc = (request->req_flags & req_null) ? NULL : escapeDesc; - // If any of them is NULL, return NULL. + // If any of them IS NULL, return nullptr. if (!exprDesc || !patternDesc || !escapeDesc) - return NULL; + return nullptr; USHORT textType = exprDesc->getTextType(); Collation* collation = INTL_texttype_lookup(tdbb, textType); @@ -12870,15 +12805,14 @@ ValueExprNode* TrimNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* TrimNode::execute(thread_db* tdbb, Request* request) const { impure_value* impure = request->getImpure(impureOffset); - request->req_flags &= ~req_null; dsc* trimCharsDesc = (trimChars ? EVL_expr(tdbb, request, trimChars) : NULL); - if (request->req_flags & req_null) - return NULL; + if (trimChars && !trimCharsDesc) + return nullptr; dsc* valueDesc = EVL_expr(tdbb, request, value); - if (request->req_flags & req_null) - return NULL; + if (!valueDesc) + return nullptr; USHORT ttype = INTL_TEXT_TYPE(*valueDesc); TextType* tt = INTL_texttype_lookup(tdbb, ttype); @@ -13652,14 +13586,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const if (nodFlags & FLAG_INVARIANT) { if (invariantFlags & VLU_computed) - { - if (invariantFlags & VLU_null) - request->req_flags |= req_null; - else - request->req_flags &= ~req_null; - - return (request->req_flags & req_null) ? NULL : &value->vlu_desc; - } + return invariantFlags & VLU_null ? nullptr : &value->vlu_desc; } if (!function->isImplemented()) @@ -13696,6 +13623,9 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const } FUN_evaluate(tdbb, function, args->items, value, *impureArea->temp); + + if (value->vlu_desc.dsc_flags & DSC_null) + value = nullptr; } else { @@ -13723,7 +13653,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const SSHORT* const nullPtr = reinterpret_cast(inMsg + nullOffset); dsc* const srcDesc = EVL_expr(tdbb, request, source); - if (srcDesc && !(request->req_flags & req_null)) + if (srcDesc) { *nullPtr = 0; MOV_move(tdbb, srcDesc, &argDesc); @@ -13786,13 +13716,11 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const if (*nullPtr) { - request->req_flags |= req_null; + value = nullptr; trace.finish(ITracePlugin::RESULT_SUCCESS); } else { - request->req_flags &= ~req_null; - const ULONG argOffset = (IPTR) fmtDesc[0].dsc_address; value->vlu_desc = *fmtDesc; value->vlu_desc.dsc_address = outMsg + argOffset; @@ -13807,7 +13735,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const funcRequest->invalidateTimeStamp(); } - if (!(request->req_flags & req_null)) + if (value) INTL_adjust_text_descriptor(tdbb, &value->vlu_desc); // If the function is declared as invariant, mark it as computed. @@ -13815,11 +13743,11 @@ dsc* UdfCallNode::execute(thread_db* tdbb, Request* request) const { invariantFlags |= VLU_computed; - if (request->req_flags & req_null) + if (!value) invariantFlags |= VLU_null; } - return (request->req_flags & req_null) ? NULL : &value->vlu_desc; + return value ? &value->vlu_desc : nullptr; } ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) @@ -14165,7 +14093,8 @@ ValueExprNode* ValueIfNode::pass2(thread_db* tdbb, CompilerScratch* csb) dsc* ValueIfNode::execute(thread_db* tdbb, Request* request) const { - return EVL_expr(tdbb, request, (condition->execute(tdbb, request) ? trueValue : falseValue)); + const auto conditionVal = condition->execute(tdbb, request).asBool(); + return EVL_expr(tdbb, request, (conditionVal ? trueValue : falseValue)); } @@ -14381,7 +14310,7 @@ dsc* VariableNode::execute(thread_db* tdbb, Request* request) const ERR_post(Arg::Gds(isc_uninitialized_var) << s); } - request->req_flags &= ~req_null; + bool isNull = false; dsc* desc; @@ -14390,7 +14319,7 @@ dsc* VariableNode::execute(thread_db* tdbb, Request* request) const const auto impure = request->getImpure(impureOffset); if (varImpure->vlu_desc.dsc_flags & DSC_null) - request->req_flags |= req_null; + isNull = true; else { auto varDesc = varImpure->vlu_desc; @@ -14422,7 +14351,7 @@ dsc* VariableNode::execute(thread_db* tdbb, Request* request) const desc = request->getImpure(impureOffset); if (varImpure->vlu_desc.dsc_flags & DSC_null) - request->req_flags |= req_null; + isNull = true; *desc = varImpure->vlu_desc; @@ -14441,7 +14370,7 @@ dsc* VariableNode::execute(thread_db* tdbb, Request* request) const } } - return (request->req_flags & req_null) ? nullptr : desc; + return isNull ? nullptr : desc; } diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index 3f824a22267..f769b4b33ed 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -28,6 +28,7 @@ #include "../dsql/Visitors.h" #include "../common/classes/array.h" #include "../common/classes/NestConst.h" +#include "../common/classes/TriState.h" #include #include #include @@ -786,7 +787,7 @@ class BoolExprNode : public ExprNode } BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) const override = 0; - virtual bool execute(thread_db* tdbb, Request* request) const = 0; + virtual Firebird::TriState execute(thread_db* tdbb, Request* request) const = 0; }; class ValueExprNode : public ExprNode diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index 85c58e99225..b3c50644f9c 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -1191,8 +1191,7 @@ const StmtNode* CursorStmtNode::execute(thread_db* tdbb, Request* request, ExeSt fb_assert(cursorOp == blr_cursor_fetch_scroll); const dsc* desc = EVL_expr(tdbb, request, scrollExpr); - const bool unknown = !desc || (request->req_flags & req_null); - const SINT64 offset = unknown ? 0 : MOV_get_int64(tdbb, desc, 0); + const SINT64 offset = desc ? MOV_get_int64(tdbb, desc, 0) : 0; switch (scrollOp) { @@ -1209,10 +1208,10 @@ const StmtNode* CursorStmtNode::execute(thread_db* tdbb, Request* request, ExeSt fetched = cursor->fetchLast(tdbb); break; case blr_scroll_absolute: - fetched = unknown ? false : cursor->fetchAbsolute(tdbb, offset); + fetched = desc ? cursor->fetchAbsolute(tdbb, offset) : false; break; case blr_scroll_relative: - fetched = unknown ? false : cursor->fetchRelative(tdbb, offset); + fetched = desc ? cursor->fetchRelative(tdbb, offset) : false; break; default: fb_assert(false); @@ -4551,7 +4550,7 @@ void ExecStatementNode::getString(thread_db* tdbb, Request* request, const Value int len = 0; const dsc* dsc = node ? EVL_expr(tdbb, request, node) : NULL; - if (dsc && !(request->req_flags & req_null)) + if (dsc) { const Jrd::Attachment* att = tdbb->getAttachment(); len = MOV_make_string2(tdbb, dsc, (useAttCS ? att->att_charset : dsc->getTextType()), @@ -4636,7 +4635,7 @@ const StmtNode* IfNode::execute(thread_db* tdbb, Request* request, ExeState* /*e { if (request->req_operation == Request::req_evaluate) { - if (condition->execute(tdbb, request)) + if (condition->execute(tdbb, request).asBool()) { request->req_operation = Request::req_evaluate; return trueAction; @@ -4961,7 +4960,7 @@ const StmtNode* InitVariableNode::execute(thread_db* tdbb, Request* request, Exe { dsc* value = EVL_expr(tdbb, request, fieldInfo.defaultValue); - if (value && !(request->req_flags & req_null)) + if (value) { toDesc->dsc_flags &= ~DSC_null; MOV_move(tdbb, value, toDesc); @@ -5487,7 +5486,7 @@ void ExceptionNode::setError(thread_db* tdbb) const // Evaluate exception message and convert it to string. const dsc* const desc = EVL_expr(tdbb, request, messageExpr); - if (desc && !(request->req_flags & req_null)) + if (desc) { MoveBuffer temp; UCHAR* string = NULL; @@ -5558,7 +5557,7 @@ void ExceptionNode::setError(thread_db* tdbb) const { const dsc* value = EVL_expr(tdbb, request, *parameter); - if (!value || (request->req_flags & req_null)) + if (!value) paramsStr.push(NULL_STRING_MARK); else { @@ -6188,7 +6187,7 @@ const StmtNode* ForRangeNode::execute(thread_db* tdbb, Request* request, ExeStat case Request::req_evaluate: { const auto initialDesc = EVL_expr(tdbb, request, initialExpr); - EXE_assignment(tdbb, variable, initialDesc, !initialDesc, nullptr, nullptr); + EXE_assignment(tdbb, variable, initialDesc, nullptr, nullptr); if (!initialDesc) { @@ -6257,7 +6256,7 @@ const StmtNode* ForRangeNode::execute(thread_db* tdbb, Request* request, ExeStat incDecScale, incDecFlags); - EXE_assignment(tdbb, variable, &nextValue.vlu_desc, false, nullptr, nullptr); + EXE_assignment(tdbb, variable, &nextValue.vlu_desc, nullptr, nullptr); } const auto comparison = MOV_compare(tdbb, variableDesc, &impure->finalValue.vlu_desc); @@ -12196,17 +12195,17 @@ static void validateExpressions(thread_db* tdbb, const Array& vali { Request* request = tdbb->getRequest(); - if (!i->boolean->execute(tdbb, request) && !(request->req_flags & req_null)) + if (i->boolean->execute(tdbb, request) == TriState(false)) { // Validation error -- report result const char* value; VaryStr temp; const dsc* desc = EVL_expr(tdbb, request, i->value); - const USHORT length = (desc && !(request->req_flags & req_null)) ? + const USHORT length = desc ? MOV_make_string(tdbb, desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1) : 0; - if (!desc || (request->req_flags & req_null)) + if (!desc) value = NULL_STRING_MARK; else if (!length) value = ""; diff --git a/src/dsql/WinNodes.cpp b/src/dsql/WinNodes.cpp index be21f0fe6c4..4f03eceea4c 100644 --- a/src/dsql/WinNodes.cpp +++ b/src/dsql/WinNodes.cpp @@ -437,11 +437,11 @@ void FirstValueWinNode::aggInit(thread_db* tdbb, Request* request) const dsc* FirstValueWinNode::winPass(thread_db* tdbb, Request* request, SlidingWindow* window) const { if (!window->moveWithinFrame(-window->getInFrameOffset())) - return NULL; + return nullptr; dsc* desc = EVL_expr(tdbb, request, arg); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; return desc; } @@ -498,11 +498,11 @@ void LastValueWinNode::aggInit(thread_db* tdbb, Request* request) const dsc* LastValueWinNode::winPass(thread_db* tdbb, Request* request, SlidingWindow* window) const { if (!window->moveWithinFrame(window->getFrameEnd() - window->getRecordPosition())) - return NULL; + return nullptr; dsc* desc = EVL_expr(tdbb, request, arg); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; return desc; } @@ -573,8 +573,8 @@ void NthValueWinNode::aggInit(thread_db* tdbb, Request* request) const dsc* NthValueWinNode::winPass(thread_db* tdbb, Request* request, SlidingWindow* window) const { dsc* desc = EVL_expr(tdbb, request, row); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; SINT64 records = MOV_get_int64(tdbb, desc, 0); if (records <= 0) @@ -592,11 +592,11 @@ dsc* NthValueWinNode::winPass(thread_db* tdbb, Request* request, SlidingWindow* records = window->getFrameEnd() - window->getRecordPosition() - records + 1; if (!window->moveWithinFrame(records)) - return NULL; + return nullptr; desc = EVL_expr(tdbb, request, arg); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; return desc; } @@ -664,8 +664,8 @@ void LagLeadWinNode::aggInit(thread_db* tdbb, Request* request) const dsc* LagLeadWinNode::winPass(thread_db* tdbb, Request* request, SlidingWindow* window) const { dsc* desc = EVL_expr(tdbb, request, rows); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; SINT64 records = MOV_get_int64(tdbb, desc, 0); if (records < 0) @@ -677,15 +677,15 @@ dsc* LagLeadWinNode::winPass(thread_db* tdbb, Request* request, SlidingWindow* w if (!window->moveWithinPartition(records * direction)) { desc = EVL_expr(tdbb, request, outExpr); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; return desc; } desc = EVL_expr(tdbb, request, arg); - if (!desc || (request->req_flags & req_null)) - return NULL; + if (!desc) + return nullptr; return desc; } @@ -834,7 +834,7 @@ void NTileWinNode::aggInit(thread_db* tdbb, Request* request) const dsc* desc = EVL_expr(tdbb, request, arg); - if (!desc || (request->req_flags & req_null)) + if (!desc) { status_exception::raise( Arg::Gds(isc_sysf_argnmustbe_positive) << diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index a40a4f17f88..ced246ce991 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -1967,7 +1967,7 @@ dsc* evlStdMath(thread_db* tdbb, const SysFunction* function, const NestValueArr Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const double v = MOV_get_double(tdbb, value); @@ -2067,7 +2067,7 @@ dsc* evlAbs(thread_db* tdbb, const SysFunction*, const NestValueArray& args, imp Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; EVL_make_value(tdbb, value, impure); @@ -2125,7 +2125,7 @@ dsc* evlAsciiChar(thread_db* tdbb, const SysFunction*, const NestValueArray& arg Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const SLONG code = MOV_get_long(tdbb, value, 0); @@ -2147,7 +2147,7 @@ dsc* evlAsciiVal(thread_db* tdbb, const SysFunction*, const NestValueArray& args Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const CharSet* cs = INTL_charset_lookup(tdbb, value->getCharSet()); @@ -2182,11 +2182,11 @@ dsc* evlAtan2(thread_db* tdbb, const SysFunction* function, const NestValueArray Request* request = tdbb->getRequest(); const dsc* desc1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if desc1 is NULL + if (!desc1) // return NULL if desc1 is NULL return NULL; const dsc* desc2 = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if desc2 is NULL + if (!desc2) // return NULL if desc2 is NULL return NULL; const double value1 = MOV_get_double(tdbb, desc1); @@ -2254,7 +2254,7 @@ dsc* evlBin(thread_db* tdbb, const SysFunction* function, const NestValueArray& for (unsigned i = 0; i < args.getCount(); ++i) { const dsc* value = EVL_expr(tdbb, request, args[i]); - if (request->req_flags & req_null) // return nullptr if value is null + if (!value) // return nullptr if value is null return nullptr; if (value->dsc_dtype == dtype_int128) @@ -2317,11 +2317,11 @@ dsc* evlBinShift(thread_db* tdbb, const SysFunction* function, const NestValueAr Request* request = tdbb->getRequest(); const dsc* value1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value1 is NULL + if (!value1) // return NULL if value1 is NULL return NULL; const dsc* value2 = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value2 is NULL + if (!value2) // return NULL if value2 is NULL return NULL; const SINT64 shift = MOV_get_int64(tdbb, value2, 0); @@ -2408,7 +2408,7 @@ dsc* evlBlobAppend(thread_db* tdbb, const SysFunction* function, const NestValue dsc blobDsc; const dsc* argDsc = EVL_expr(tdbb, request, args[0]); - const bool arg0_null = (request->req_flags & req_null) || (argDsc == NULL); + const bool arg0_null = !argDsc; if (!arg0_null && argDsc->isBlob()) { @@ -2452,7 +2452,7 @@ dsc* evlBlobAppend(thread_db* tdbb, const SysFunction* function, const NestValue else { argDsc = EVL_expr(tdbb, request, args[i]); - if ((request->req_flags & req_null) || !argDsc) + if (!argDsc) continue; } @@ -2510,7 +2510,7 @@ dsc* evlCeil(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; EVL_make_value(tdbb, value, impure); @@ -2595,7 +2595,7 @@ dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValue Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; if (!value->isText()) @@ -2732,15 +2732,15 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr Request* request = tdbb->getRequest(); const dsc* quantityDsc = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if quantityDsc is NULL + if (!quantityDsc) // return NULL if quantityDsc is NULL return NULL; const dsc* partDsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if partDsc is NULL + if (!partDsc) // return NULL if partDsc is NULL return NULL; const dsc* valueDsc = EVL_expr(tdbb, request, args[2]); - if (request->req_flags & req_null) // return NULL if valueDsc is NULL + if (!valueDsc) // return NULL if valueDsc is NULL return NULL; const SLONG part = MOV_get_long(tdbb, partDsc, 0); @@ -3854,7 +3854,7 @@ dsc* evlRsaPrivate(thread_db* tdbb, const SysFunction* function, const NestValue Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const SLONG length = MOV_get_long(tdbb, value, 0); @@ -3885,7 +3885,7 @@ dsc* evlRsaPublic(thread_db* tdbb, const SysFunction* function, const NestValueA Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; DscValue data(tdbb, value, "private key"); @@ -4052,15 +4052,15 @@ dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueAr Request* request = tdbb->getRequest(); const dsc* partDsc = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if partDsc is NULL + if (!partDsc) // return NULL if partDsc is NULL return NULL; const dsc* value1Dsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value1Dsc is NULL + if (!value1Dsc) // return NULL if value1Dsc is NULL return NULL; const dsc* value2Dsc = EVL_expr(tdbb, request, args[2]); - if (request->req_flags & req_null) // return NULL if value2Dsc is NULL + if (!value2Dsc) // return NULL if value2Dsc is NULL return NULL; TimeStamp timestamp1; @@ -4283,7 +4283,7 @@ dsc* evlExp(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; if (value->isDecOrInt128()) @@ -4320,11 +4320,11 @@ dsc* evlFirstLastDay(thread_db* tdbb, const SysFunction* function, const NestVal Request* request = tdbb->getRequest(); const dsc* partDsc = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if partDsc is NULL + if (!partDsc) // return NULL if partDsc is NULL return NULL; const dsc* valueDsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if valueDsc is NULL + if (!valueDsc) // return NULL if valueDsc is NULL return NULL; TimeStamp timestamp; @@ -4456,7 +4456,7 @@ dsc* evlFloor(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; EVL_make_value(tdbb, value, impure); @@ -4540,7 +4540,7 @@ dsc* evlGenUuid(thread_db* tdbb, const SysFunction*, const NestValueArray& args, { const auto* const versionDsc = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) + if (!versionDsc) return nullptr; version = MOV_get_long(tdbb, versionDsc, 0); @@ -4576,13 +4576,12 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar jrd_tra* transaction = tdbb->getTransaction(); Request* request = tdbb->getRequest(); - request->req_flags &= ~req_null; const dsc* nameSpace = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // Complain if namespace is null + if (!nameSpace) // Complain if namespace is null ERR_post(Arg::Gds(isc_ctx_bad_argument) << Arg::Str(RDB_GET_CONTEXT)); const dsc* name = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // Complain if variable name is null + if (!name) // Complain if variable name is null ERR_post(Arg::Gds(isc_ctx_bad_argument) << Arg::Str(RDB_GET_CONTEXT)); const string nameSpaceStr(MOV_make_string2(tdbb, nameSpace, ttype_none)); @@ -4590,7 +4589,6 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar string resultStr; USHORT resultType = ttype_none; - request->req_flags |= req_null; if (nameSpaceStr == SYSTEM_NAMESPACE) // Handle system variables { @@ -4872,7 +4870,6 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar result.makeBlob(isc_blob_text, ttype_metadata, (ISC_QUAD*) &impure->vlu_misc.vlu_bid); EVL_make_value(tdbb, &result, impure); - request->req_flags &= ~req_null; return &impure->vlu_desc; } else @@ -4904,7 +4901,6 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar (UCHAR*) const_cast(resultStr.c_str())); // safe const_cast EVL_make_value(tdbb, &result, impure); - request->req_flags &= ~req_null; return &impure->vlu_desc; } @@ -4918,13 +4914,12 @@ dsc* evlSetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar jrd_tra* transaction = tdbb->getTransaction(); Request* request = tdbb->getRequest(); - request->req_flags &= ~req_null; const dsc* nameSpace = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // Complain if namespace is null + if (!nameSpace) // Complain if namespace is null ERR_post(Arg::Gds(isc_ctx_bad_argument) << Arg::Str(RDB_SET_CONTEXT)); const dsc* name = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // Complain if variable name is null + if (!name) // Complain if variable name is null ERR_post(Arg::Gds(isc_ctx_bad_argument) << Arg::Str(RDB_SET_CONTEXT)); const dsc* value = EVL_expr(tdbb, request, args[2]); @@ -5005,7 +5000,6 @@ dsc* evlSetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar attachment->att_trace_manager->event_set_context(&conn, &tran, &ctxvar); } - request->req_flags &= ~req_null; return &impure->vlu_desc; } @@ -5018,9 +5012,8 @@ dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueA Database* dbb = tdbb->getDatabase(); Request* request = tdbb->getRequest(); - request->req_flags &= ~req_null; const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) + if (!value) return NULL; const TraNumber traNum = MOV_get_int64(tdbb, value, 0); @@ -5035,10 +5028,7 @@ dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueA } if (traNum > traMax) - { - request->req_flags |= req_null; return NULL; - } CommitNumber cn = dbb->dbb_tip_cache->snapshotState(tdbb, traNum); @@ -5047,7 +5037,6 @@ dsc* evlGetTranCN(thread_db* tdbb, const SysFunction* function, const NestValueA EVL_make_value(tdbb, &result, impure); - request->req_flags &= ~req_null; return &impure->vlu_desc; } @@ -5060,7 +5049,7 @@ dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray& Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; AutoPtr hashContext; @@ -5069,7 +5058,7 @@ dsc* evlHash(thread_db* tdbb, const SysFunction* function, const NestValueArray& if (args.getCount() >= 2) { const dsc* algorithmDesc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if algorithm is NULL + if (!algorithmDesc) // return NULL if algorithm is NULL return NULL; const HashAlgorithmDescriptor* d = getHashAlgorithmDesc(tdbb, function, algorithmDesc); @@ -5119,11 +5108,11 @@ dsc* evlLeft(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* str = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if str is NULL + if (!str) // return NULL if str is NULL return NULL; const dsc* len = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if len is NULL + if (!len) // return NULL if len is NULL return NULL; SLONG start = 0; @@ -5143,7 +5132,7 @@ dsc* evlLnLog10(thread_db* tdbb, const SysFunction* function, const NestValueArr Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; if (value->isDecOrInt128()) @@ -5217,11 +5206,11 @@ dsc* evlLog(thread_db* tdbb, const SysFunction* function, const NestValueArray& const dsc* value[2]; value[0] = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[0]) // return NULL if value is NULL return NULL; value[1] = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[1]) // return NULL if value is NULL return NULL; if (!areParamsDouble(2, value)) @@ -5283,11 +5272,11 @@ dsc* evlQuantize(thread_db* tdbb, const SysFunction* function, const NestValueAr const dsc* value[2]; value[0] = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[0]) // return NULL if value is NULL return NULL; value[1] = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[1]) // return NULL if value is NULL return NULL; const DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; @@ -5322,11 +5311,11 @@ dsc* evlCompare(thread_db* tdbb, const SysFunction* function, const NestValueArr const dsc* value[2]; value[0] = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[0]) // return NULL if value is NULL return NULL; value[1] = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[1]) // return NULL if value is NULL return NULL; if (value[0]->dsc_dtype == dtype_dec64) @@ -5378,7 +5367,7 @@ dsc* evlNormDec(thread_db* tdbb, const SysFunction* function, const NestValueArr const dsc* value; value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; @@ -5413,7 +5402,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV fb_assert(args.getCount() >= 2 && args.getCount() <= 4); dsc* argDsc = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if relation is NULL + if (!argDsc) // return NULL if relation is NULL return NULL; USHORT relId; @@ -5441,7 +5430,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV } argDsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) + if (!argDsc) return NULL; SINT64 recNo = MOV_get_int64(tdbb, argDsc, 0); @@ -5451,7 +5440,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV if (args.getCount() > 2) { argDsc = EVL_expr(tdbb, request, args[2]); - if (request->req_flags & req_null) + if (!argDsc) return NULL; dpNum = MOV_get_int64(tdbb, argDsc, 0); @@ -5462,7 +5451,7 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV if (args.getCount() > 3) { argDsc = EVL_expr(tdbb, request, args[3]); - if (request->req_flags & req_null) + if (!argDsc) return NULL; ppNum = MOV_get_int64(tdbb, argDsc, 0); @@ -5518,7 +5507,7 @@ dsc* evlMaxMinValue(thread_db* tdbb, const SysFunction* function, const NestValu for (FB_SIZE_T i = 0; i < args.getCount(); ++i) { const auto value = EVL_expr(tdbb, request, args[i]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return nullptr; argTypes.add(value); @@ -5565,11 +5554,11 @@ dsc* evlMod(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value1 is NULL + if (!value1) // return NULL if value1 is NULL return NULL; const dsc* value2 = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value2 is NULL + if (!value2) // return NULL if value2 is NULL return NULL; EVL_make_value(tdbb, value1, impure); @@ -5628,15 +5617,15 @@ dsc* evlOverlay(thread_db* tdbb, const SysFunction* function, const NestValueArr Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const dsc* placing = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if placing is NULL + if (!placing) // return NULL if placing is NULL return NULL; const dsc* fromDsc = EVL_expr(tdbb, request, args[2]); - if (request->req_flags & req_null) // return NULL if fromDsc is NULL + if (!fromDsc) // return NULL if fromDsc is NULL return NULL; const dsc* lengthDsc = NULL; @@ -5645,7 +5634,7 @@ dsc* evlOverlay(thread_db* tdbb, const SysFunction* function, const NestValueArr if (args.getCount() >= 4) { lengthDsc = EVL_expr(tdbb, request, args[3]); - if (request->req_flags & req_null) // return NULL if lengthDsc is NULL + if (!lengthDsc) // return NULL if lengthDsc is NULL return NULL; const SLONG auxlen = MOV_get_long(tdbb, lengthDsc, 0); @@ -5812,11 +5801,11 @@ dsc* evlPad(thread_db* tdbb, const SysFunction* function, const NestValueArray& Request* request = tdbb->getRequest(); const dsc* value1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value1 is NULL + if (!value1) // return NULL if value1 is NULL return NULL; const dsc* padLenDsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if padLenDsc is NULL + if (!padLenDsc) // return NULL if padLenDsc is NULL return NULL; const SLONG padLenArg = MOV_get_long(tdbb, padLenDsc, 0); @@ -5834,7 +5823,7 @@ dsc* evlPad(thread_db* tdbb, const SysFunction* function, const NestValueArray& if (args.getCount() >= 3) { value2 = EVL_expr(tdbb, request, args[2]); - if (request->req_flags & req_null) // return NULL if value2 is NULL + if (!value2) // return NULL if value2 is NULL return NULL; } @@ -5987,11 +5976,11 @@ dsc* evlPosition(thread_db* tdbb, const SysFunction* function, const NestValueAr Request* request = tdbb->getRequest(); const dsc* value1 = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value1 is NULL + if (!value1) // return NULL if value1 is NULL return NULL; const dsc* value2 = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value2 is NULL + if (!value2) // return NULL if value2 is NULL return NULL; SLONG start = 1; @@ -5999,7 +5988,7 @@ dsc* evlPosition(thread_db* tdbb, const SysFunction* function, const NestValueAr if (args.getCount() >= 3) { const dsc* value3 = EVL_expr(tdbb, request, args[2]); - if (request->req_flags & req_null) // return NULL if value3 is NULL + if (!value3) // return NULL if value3 is NULL return NULL; start = MOV_get_long(tdbb, value3, 0); @@ -6114,11 +6103,11 @@ dsc* evlPower(thread_db* tdbb, const SysFunction* function, const NestValueArray const dsc* value[2]; value[0] = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[0]) // return NULL if value is NULL return NULL; value[1] = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value[1]) // return NULL if value is NULL return NULL; if (!areParamsDouble(2, value)) @@ -6193,7 +6182,7 @@ dsc* evlReplace(thread_db* tdbb, const SysFunction*, const NestValueArray& args, for (int i = 0; i < 3; ++i) { values[i] = EVL_expr(tdbb, request, args[i]); - if (request->req_flags & req_null) // return NULL if values[i] is NULL + if (!values[i]) // return NULL if values[i] is NULL return NULL; if (!firstBlob && values[i]->isBlob()) @@ -6347,7 +6336,7 @@ dsc* evlReverse(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; CharSet* cs = INTL_charset_lookup(tdbb, value->getCharSet()); @@ -6450,11 +6439,11 @@ dsc* evlRight(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const dsc* len = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if len is NULL + if (!len) // return NULL if len is NULL return NULL; const CharSet* charSet = INTL_charset_lookup(tdbb, value->getCharSet()); @@ -6503,7 +6492,7 @@ dsc* evlRound(thread_db* tdbb, const SysFunction* function, const NestValueArray Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; SLONG scale = 0; @@ -6511,7 +6500,7 @@ dsc* evlRound(thread_db* tdbb, const SysFunction* function, const NestValueArray if (args.getCount() > 1) { const dsc* scaleDsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if scaleDsc is NULL + if (!scaleDsc) // return NULL if scaleDsc is NULL return NULL; scale = MOV_get_long(tdbb, scaleDsc, 0); @@ -6551,7 +6540,7 @@ dsc* evlSign(thread_db* tdbb, const SysFunction*, const NestValueArray& args, Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; if (value->isDecFloat()) @@ -6582,7 +6571,7 @@ dsc* evlSqrt(thread_db* tdbb, const SysFunction* function, const NestValueArray& Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; if (value->isDecOrInt128()) @@ -6625,14 +6614,14 @@ dsc* evlTrunc(thread_db* tdbb, const SysFunction* function, const NestValueArray Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; SLONG resultScale = 0; if (args.getCount() > 1) { const dsc* scaleDsc = EVL_expr(tdbb, request, args[1]); - if (request->req_flags & req_null) // return NULL if scaleDsc is NULL + if (!scaleDsc) // return NULL if scaleDsc is NULL return NULL; resultScale = MOV_get_long(tdbb, scaleDsc, 0); @@ -6758,7 +6747,7 @@ dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValue Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; if (!value->isText()) @@ -6801,7 +6790,7 @@ dsc* evlRoleInUse(thread_db* tdbb, const SysFunction*, const NestValueArray& arg const Jrd::Attachment* attachment = tdbb->getAttachment(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; string roleStr(MOV_make_string2(tdbb, value, ttype_none)); @@ -6826,7 +6815,7 @@ dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction*, const NestValueArra Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; fb_assert(value->dsc_dtype == dtype_short); @@ -6849,7 +6838,7 @@ dsc* evlUnicodeChar(thread_db* tdbb, const SysFunction* function, const NestValu Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; const UChar32 code = MOV_get_long(tdbb, value, 0); @@ -6884,7 +6873,7 @@ dsc* evlUnicodeVal(thread_db* tdbb, const SysFunction*, const NestValueArray& ar Request* request = tdbb->getRequest(); const dsc* value = EVL_expr(tdbb, request, args[0]); - if (request->req_flags & req_null) // return NULL if value is NULL + if (!value) // return NULL if value is NULL return NULL; MoveBuffer buffer; diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index 351fd363dc5..95e385dc990 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -1056,7 +1056,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, // Use local copy of source blob id to not change contents of from_desc in // a case when it points to materialized temporary blob (see below for // assignment to *source). - bid srcBlobID = *(bid*)from_desc->dsc_address; + bid srcBlobID = *(bid*) from_desc->dsc_address; bid* source = &srcBlobID; bid* destination = (bid*) to_desc->dsc_address; @@ -1117,7 +1117,7 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, // If either the source value is null or the blob id itself is null // (all zeros), then the blob is null. - if ((request->req_flags & req_null) || source->isEmpty()) + if (source->isEmpty()) { record->setNull(fieldId); destination->clear(); diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index bf010642fa1..1fc07ca7660 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -392,25 +392,24 @@ IndexCondition::~IndexCondition() } } -bool IndexCondition::evaluate(Record* record) const +TriState IndexCondition::evaluate(Record* record) const { if (!m_request || !m_condition) - return true; + return TriState(true); const auto orgRequest = m_tdbb->getRequest(); m_tdbb->setRequest(m_request); m_request->req_rpb[0].rpb_record = record; - m_request->req_flags &= ~req_null; FbLocalStatus status; - bool result = false; + TriState result(false); try { Jrd::ContextPoolHolder context(m_tdbb, m_request->req_pool); - result = m_condition->execute(m_tdbb, m_request); + result = m_condition->execute(m_tdbb, m_request).asBool(); } catch (const Exception& ex) { @@ -507,7 +506,6 @@ dsc* IndexExpression::evaluate(Record* record) const m_tdbb->setRequest(m_request); m_request->req_rpb[0].rpb_record = record; - m_request->req_flags &= ~req_null; FbLocalStatus status; dsc* result = nullptr; diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 556c4ea9b13..c01866a80ef 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -356,7 +356,7 @@ class IndexCondition BoolExprNode* m_condition = nullptr; Request* m_request = nullptr; - bool evaluate(Record* record) const; + Firebird::TriState evaluate(Record* record) const; }; class IndexExpression diff --git a/src/jrd/evl.cpp b/src/jrd/evl.cpp index 5cf45ad0605..149aaf78665 100644 --- a/src/jrd/evl.cpp +++ b/src/jrd/evl.cpp @@ -248,8 +248,7 @@ RecordBitmap** EVL_bitmap(thread_db* tdbb, const InversionNode* node, RecordBitm RecordBitmap::reset(impure->inv_bitmap); const dsc* const desc = EVL_expr(tdbb, request, node->value); - if (!(tdbb->getRequest()->req_flags & req_null) && - (desc->isText() || desc->isDbKey())) + if (desc && (desc->isText() || desc->isDbKey())) { UCHAR* ptr = NULL; const int length = MOV_get_string(tdbb, desc, &ptr, NULL, 0); @@ -311,8 +310,7 @@ void EVL_dbkey_bounds(thread_db* tdbb, const Array& ranges, { const auto desc = EVL_expr(tdbb, request, node->lower); - if (!(request->req_flags & req_null) && - desc && (desc->isText() || desc->isDbKey())) + if (desc && desc && (desc->isText() || desc->isDbKey())) { UCHAR* ptr = NULL; const auto length = MOV_get_string(tdbb, desc, &ptr, NULL, 0); @@ -344,8 +342,7 @@ void EVL_dbkey_bounds(thread_db* tdbb, const Array& ranges, { const auto desc = EVL_expr(tdbb, request, node->upper); - if (!(request->req_flags & req_null) && - desc && (desc->isText() || desc->isDbKey())) + if (desc && (desc->isText() || desc->isDbKey())) { UCHAR* ptr = NULL; const auto length = MOV_get_string(tdbb, desc, &ptr, NULL, 0); @@ -634,7 +631,7 @@ void EVL_validate(thread_db* tdbb, const Item& item, const ItemInfo* itemInfo, d request->req_domain_validation = desc; const ULONG flags = request->req_flags; - if (!fieldInfo.validationExpr->execute(tdbb, request) && !(request->req_flags & req_null)) + if (fieldInfo.validationExpr->execute(tdbb, request) == TriState(false)) { const USHORT length = desc_is_null ? 0 : MOV_make_string(tdbb, desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1); diff --git a/src/jrd/evl_proto.h b/src/jrd/evl_proto.h index cfaa53eafa2..0053be18dbd 100644 --- a/src/jrd/evl_proto.h +++ b/src/jrd/evl_proto.h @@ -55,16 +55,7 @@ namespace Jrd JRD_reschedule(tdbb); - request->req_flags &= ~req_null; - - dsc* desc = node->execute(tdbb, request); - - if (desc) - request->req_flags &= ~req_null; - else - request->req_flags |= req_null; - - return desc; + return node->execute(tdbb, request); } } diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 3fbe78dc67c..023cae34bcf 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -323,11 +323,9 @@ void EXE_assignment(thread_db* tdbb, const AssignmentNode* node) Request* request = tdbb->getRequest(); // Get descriptors of src field/parameter/variable, etc. - request->req_flags &= ~req_null; dsc* from_desc = EVL_expr(tdbb, request, node->asgnFrom); - EXE_assignment(tdbb, node->asgnTo, from_desc, (request->req_flags & req_null), - node->missing, node->missing2); + EXE_assignment(tdbb, node->asgnTo, from_desc, node->missing, node->missing2); } // Perform an assignment. @@ -337,14 +335,13 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* source, const ValueExp Request* request = tdbb->getRequest(); // Get descriptors of src field/parameter/variable, etc. - request->req_flags &= ~req_null; dsc* from_desc = EVL_expr(tdbb, request, source); - EXE_assignment(tdbb, target, from_desc, (request->req_flags & req_null), NULL, NULL); + EXE_assignment(tdbb, target, from_desc, nullptr, nullptr); } // Perform an assignment. -void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bool from_null, +void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, const ValueExprNode* missing_node, const ValueExprNode* missing2_node) { SET_TDBB(tdbb); @@ -365,9 +362,7 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo missing = EVL_expr(tdbb, request, missing_node); // Get descriptor of target field/parameter/variable, etc. - DSC* to_desc = EVL_assign_to(tdbb, to); - - request->req_flags &= ~req_null; + dsc* to_desc = EVL_assign_to(tdbb, to); // NS: If we are assigning to NULL, we finished. // This functionality is currently used to allow calling UDF routines @@ -375,7 +370,7 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo if (!to_desc) return; - SSHORT null = from_null ? -1 : 0; + SSHORT null = from_desc ? 0 : -1; if (!null && missing && MOV_compare(tdbb, missing, from_desc) == 0) null = -1; diff --git a/src/jrd/exe_proto.h b/src/jrd/exe_proto.h index 4a28c6dd5ea..64d8e243732 100644 --- a/src/jrd/exe_proto.h +++ b/src/jrd/exe_proto.h @@ -35,7 +35,7 @@ namespace Jrd { void EXE_assignment(Jrd::thread_db*, const Jrd::AssignmentNode*); void EXE_assignment(Jrd::thread_db*, const Jrd::ValueExprNode*, const Jrd::ValueExprNode*); -void EXE_assignment(Jrd::thread_db* tdbb, const Jrd::ValueExprNode* to, dsc* from_desc, bool from_null, +void EXE_assignment(Jrd::thread_db* tdbb, const Jrd::ValueExprNode* to, dsc* from_desc, const Jrd::ValueExprNode* missing_node, const Jrd::ValueExprNode* missing2_node); void EXE_execute_db_triggers(Jrd::thread_db*, Jrd::jrd_tra*, enum TriggerAction); diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index d61925631c9..15ee3112d59 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -2331,12 +2331,7 @@ void Statement::doSetInParams(thread_db* tdbb, unsigned int count, const MetaStr paramDescs.put(*jrdVar, src); if (src) - { - if (request->req_flags & req_null) - src->setNull(); - else - src->clearNull(); - } + src->clearNull(); } const bool srcNull = !src || src->isNull(); @@ -2419,7 +2414,7 @@ void Statement::getOutParams(thread_db* tdbb, const ValueListNode* params) } // and assign to the target - EXE_assignment(tdbb, *jrdVar, local, srcNull, NULL, NULL); + EXE_assignment(tdbb, *jrdVar, (srcNull ? nullptr : local), nullptr, nullptr); } } diff --git a/src/jrd/fun.epp b/src/jrd/fun.epp index b43f118d35f..30192901c8e 100644 --- a/src/jrd/fun.epp +++ b/src/jrd/fun.epp @@ -364,10 +364,6 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra const Parameter* return_ptr = function->getOutputFields()[0]; Request* request = tdbb->getRequest(); - // CVC: restoring the null flag seems like a Borland hack to try to - // patch a bug with null handling. There's no evident reason to restore it - // because EVL_expr() resets it every time it's called. Kept it for now. - const bool null_flag = ((request->req_flags & req_null) == req_null); FbLocalStatus status; CleanupPtrs cleanupList; @@ -393,7 +389,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra // We'll use to this trick to give the UDF a way to signal // "I sent a null blob" when not using descriptors. - udf_blob* return_blob_struct = 0; + udf_blob* return_blob_struct = nullptr; DSC temp_desc; double d; @@ -408,12 +404,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra DSC* input; if (*tail == return_ptr) - { - input = &value->vlu_desc; // (DSC*) value; - // CVC: The return param we build for the UDF is not null!!! - // This closes SF Bug #544132. - request->req_flags &= ~req_null; - } + input = &value->vlu_desc; else input = EVL_expr(tdbb, request, *ptr++); @@ -428,14 +419,11 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra // doesn't carry the null flag in the descriptor. Why Borland didn't // set on such flag is maybe because it only has local meaning. // This closes SF Bug #728839. - if ((request->req_flags & req_null) && !(input && (input->dsc_flags & DSC_null))) - { - *arg_ptr++ = NULL; - } + if (!(input && (input->dsc_flags & DSC_null))) + *arg_ptr++ = nullptr; else - { - *arg_ptr++ = input; - } + *arg_ptr++ = input; + continue; } @@ -445,7 +433,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra // If we've got a null argument, just pass zeros (got any better ideas?) - if (!input || (request->req_flags & req_null)) + if (!input) { if (parameter->prm_fun_mechanism == FUN_value) { @@ -677,20 +665,15 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra } else { - bid blob_id; - if (request->req_flags & req_null) - { - memset(&blob_id, 0, sizeof(bid)); - } - else + fb_assert(input); + + if (input->dsc_dtype != dtype_quad && input->dsc_dtype != dtype_blob) { - if (input->dsc_dtype != dtype_quad && input->dsc_dtype != dtype_blob) - { - ERR_post(Arg::Gds(isc_wish_list) << - Arg::Gds(isc_blobnotsup) << Arg::Str("conversion")); - } - blob_id = *(bid*) input->dsc_address; + ERR_post(Arg::Gds(isc_wish_list) << + Arg::Gds(isc_blobnotsup) << Arg::Str("conversion")); } + + const auto blob_id = *(bid*) input->dsc_address; blob = blb::open(tdbb, tdbb->getRequest()->req_transaction, &blob_id); } blob_stack.push(blob); @@ -776,10 +759,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra } if (result_was_null) - { - request->req_flags |= req_null; - value->vlu_desc.dsc_flags |= DSC_null; // redundant, but be safe - } + value->vlu_desc.dsc_flags |= DSC_null; else { switch (value->vlu_desc.dsc_dtype) @@ -830,7 +810,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra break; } - request->req_flags &= ~req_null; + value->vlu_desc.dsc_flags &= ~DSC_null; } blob_stack.close(); @@ -849,11 +829,6 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra delete[] cleanupList.pop(); status.check(); - - if (null_flag) - { - request->req_flags |= req_null; - } } diff --git a/src/jrd/recsrc/AggregatedStream.cpp b/src/jrd/recsrc/AggregatedStream.cpp index be3a9f507d4..dcc5a43337a 100644 --- a/src/jrd/recsrc/AggregatedStream.cpp +++ b/src/jrd/recsrc/AggregatedStream.cpp @@ -341,7 +341,7 @@ int BaseAggWinStream::lookForChange(thread_db* tdbb, Request dsc* desc = EVL_expr(tdbb, request, from); int n; - if (request->req_flags & req_null) + if (!desc) { if (vtemp->vlu_desc.dsc_address) return -1 * nullsPlacement; diff --git a/src/jrd/recsrc/ConditionalStream.cpp b/src/jrd/recsrc/ConditionalStream.cpp index 8a1cc48c7c9..674e1affcea 100644 --- a/src/jrd/recsrc/ConditionalStream.cpp +++ b/src/jrd/recsrc/ConditionalStream.cpp @@ -57,7 +57,7 @@ void ConditionalStream::internalOpen(thread_db* tdbb) const Request* const request = tdbb->getRequest(); Impure* const impure = request->getImpure(m_impure); - impure->irsb_next = m_boolean->execute(tdbb, request) ? m_first : m_second; + impure->irsb_next = m_boolean->execute(tdbb, request).asBool() ? m_first : m_second; impure->irsb_flags = irsb_open; impure->irsb_next->open(tdbb); diff --git a/src/jrd/recsrc/FilteredStream.cpp b/src/jrd/recsrc/FilteredStream.cpp index 744ebf484dd..0e66b3c0173 100644 --- a/src/jrd/recsrc/FilteredStream.cpp +++ b/src/jrd/recsrc/FilteredStream.cpp @@ -64,7 +64,7 @@ void FilteredStream::internalOpen(thread_db* tdbb) const Request* const request = tdbb->getRequest(); Impure* const impure = request->getImpure(m_impure); - if (!m_invariant || m_boolean->execute(tdbb, request)) + if (!m_invariant || m_boolean->execute(tdbb, request).asBool()) { impure->irsb_flags = irsb_open; @@ -98,7 +98,7 @@ bool FilteredStream::internalGetRecord(thread_db* tdbb) const if (!(impure->irsb_flags & irsb_open)) return false; - if (!evaluateBoolean(tdbb)) + if (!evaluateBoolean(tdbb).asBool()) { invalidateRecords(request); return false; @@ -112,7 +112,7 @@ bool FilteredStream::refetchRecord(thread_db* tdbb) const Request* const request = tdbb->getRequest(); return m_next->refetchRecord(tdbb) && - m_boolean->execute(tdbb, request); + m_boolean->execute(tdbb, request).asBool(); } WriteLockResult FilteredStream::lockRecord(thread_db* tdbb) const @@ -168,7 +168,7 @@ void FilteredStream::nullRecords(thread_db* tdbb) const m_next->nullRecords(tdbb); } -bool FilteredStream::evaluateBoolean(thread_db* tdbb) const +Firebird::TriState FilteredStream::evaluateBoolean(thread_db* tdbb) const { Request* const request = tdbb->getRequest(); @@ -223,7 +223,9 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const while (m_next->getRecord(tdbb)) { - if (m_boolean->execute(tdbb, request)) + const auto booleanState = m_boolean->execute(tdbb, request); + + if (booleanState.asBool()) { // found a TRUE value @@ -235,7 +237,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const if (!select_node) { - if (request->req_flags & req_null) + if (booleanState.isUnknown()) { any_null = true; break; @@ -243,23 +245,16 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const } else { - request->req_flags &= ~req_null; - // select for ANY/ALL processing - const bool select_value = select_node->execute(tdbb, request); + const bool select_value = select_node->execute(tdbb, request).asBool(); // see if any record in select stream if (select_value) { - // see if any nulls - - request->req_flags &= ~req_null; - column_node->execute(tdbb, request); - // see if any record is null - if (request->req_flags & req_null) + if (column_node->execute(tdbb, request).isUnknown()) { any_null = true; break; @@ -268,9 +263,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const } } - request->req_flags &= ~req_null; - - return any_null || any_true; + return TriState(any_null || any_true); } // do ANY @@ -279,15 +272,14 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const bool result = false; while (m_next->getRecord(tdbb)) { - if (m_boolean->execute(tdbb, request)) + if (m_boolean->execute(tdbb, request).asBool()) { result = true; break; } } - request->req_flags &= ~req_null; - return result; + return TriState(result); } if (column_node && m_ansiAll) @@ -300,20 +292,16 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const bool any_false = false; // some records false for ANY/ALL while (m_next->getRecord(tdbb)) { - request->req_flags &= ~req_null; - // look for a FALSE (and not null either) - if (!m_boolean->execute(tdbb, request) && !(request->req_flags & req_null)) + if (m_boolean->execute(tdbb, request) == TriState(false)) { // make sure it wasn't FALSE because there's no select stream record if (select_node) { - request->req_flags &= ~req_null; - // select for ANY/ALL processing - const bool select_value = select_node->execute(tdbb, request); + const bool select_value = select_node->execute(tdbb, request).asBool(); if (select_value) { any_false = true; @@ -328,9 +316,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const } } - request->req_flags &= ~req_null; - - return !any_false; + return TriState(!any_false); } // do ALL @@ -343,20 +329,16 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const bool any_false = false; // some records false for ANY/ALL while (m_next->getRecord(tdbb)) { - request->req_flags &= ~req_null; - // look for a FALSE or null - if (!m_boolean->execute(tdbb, request)) + if (m_boolean->execute(tdbb, request) != TriState(true)) { // make sure it wasn't FALSE because there's no select stream record if (select_node) { - request->req_flags &= ~req_null; - // select for ANY/ALL processing - const bool select_value = select_node->execute(tdbb, request); + const bool select_value = select_node->execute(tdbb, request).asBool(); if (select_value) { any_false = true; @@ -371,27 +353,24 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const } } - request->req_flags &= ~req_null; - - return !any_false; + return TriState(!any_false); } bool nullFlag = false; bool result = false; while (m_next->getRecord(tdbb)) { - if (m_boolean->execute(tdbb, request)) + const auto booleanState = m_boolean->execute(tdbb, request); + + if (booleanState.asBool()) { result = true; break; } - if (request->req_flags & req_null) + if (booleanState.isUnknown()) nullFlag = true; } - if (nullFlag) - request->req_flags |= req_null; - - return result; + return nullFlag && !result ? TriState::empty() : TriState(result); } diff --git a/src/jrd/recsrc/FirstRowsStream.cpp b/src/jrd/recsrc/FirstRowsStream.cpp index e811166450c..1c9aaf41ac5 100644 --- a/src/jrd/recsrc/FirstRowsStream.cpp +++ b/src/jrd/recsrc/FirstRowsStream.cpp @@ -60,7 +60,7 @@ void FirstRowsStream::internalOpen(thread_db* tdbb) const impure->irsb_flags = 0; const dsc* desc = EVL_expr(tdbb, request, m_value); - const SINT64 value = (desc && !(request->req_flags & req_null)) ? MOV_get_int64(tdbb, desc, 0) : 0; + const SINT64 value = desc ? MOV_get_int64(tdbb, desc, 0) : 0; if (value < 0) status_exception::raise(Arg::Gds(isc_bad_limit_param)); diff --git a/src/jrd/recsrc/HashJoin.cpp b/src/jrd/recsrc/HashJoin.cpp index 4c254f6b017..982b3c38bfb 100644 --- a/src/jrd/recsrc/HashJoin.cpp +++ b/src/jrd/recsrc/HashJoin.cpp @@ -415,7 +415,7 @@ bool HashJoin::internalGetRecord(thread_db* tdbb) const if (!m_leader.source->getRecord(tdbb)) return false; - if (m_boolean && !m_boolean->execute(tdbb, request)) + if (m_boolean && m_boolean->execute(tdbb, request) != TriState(true)) { // The boolean pertaining to the left sub-stream is false // so just join sub-stream to a null valued right sub-stream @@ -568,7 +568,7 @@ ULONG HashJoin::computeHash(thread_db* tdbb, dsc* const desc = EVL_expr(tdbb, request, (*sub.keys)[i]); const USHORT keyLength = sub.keyLengths[i]; - if (desc && !(request->req_flags & req_null)) + if (desc) { if (desc->isText()) { diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index bf44b8bd768..de5e6759c2c 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -765,7 +765,7 @@ bool IndexTableScan::setupBitmaps(thread_db* tdbb, Impure* impure) const // view of the database when the stream is opened if (m_inversion) { - if (!m_condition || !m_condition->execute(tdbb, tdbb->getRequest())) + if (!m_condition || m_condition->execute(tdbb, tdbb->getRequest()) != TriState(true)) { impure->irsb_flags &= ~irsb_mustread; // There is no need to reset or release the bitmap, it is diff --git a/src/jrd/recsrc/NestedLoopJoin.cpp b/src/jrd/recsrc/NestedLoopJoin.cpp index 08cf4ded760..13318514047 100644 --- a/src/jrd/recsrc/NestedLoopJoin.cpp +++ b/src/jrd/recsrc/NestedLoopJoin.cpp @@ -197,7 +197,7 @@ bool NestedLoopJoin::internalGetRecord(thread_db* tdbb) const if (!outer->getRecord(tdbb)) return false; - if (m_boolean && !m_boolean->execute(tdbb, request)) + if (m_boolean && m_boolean->execute(tdbb, request) != TriState(true)) { // The boolean pertaining to the left sub-stream is false // so just join sub-stream to a null valued right sub-stream diff --git a/src/jrd/recsrc/RecordSource.h b/src/jrd/recsrc/RecordSource.h index bc5df3dfed2..447d4e4bbd4 100644 --- a/src/jrd/recsrc/RecordSource.h +++ b/src/jrd/recsrc/RecordSource.h @@ -618,7 +618,7 @@ namespace Jrd bool m_invariant = false; private: - bool evaluateBoolean(thread_db* tdbb) const; + Firebird::TriState evaluateBoolean(thread_db* tdbb) const; NestConst m_next; NestConst const m_boolean; @@ -912,8 +912,8 @@ namespace Jrd dsc* desc = EVL_expr(tdbb, request, from); - if (request->req_flags & req_null) - target->vlu_desc.dsc_address = NULL; + if (!desc) + target->vlu_desc.dsc_address = nullptr; else { EVL_make_value(tdbb, desc, target); diff --git a/src/jrd/recsrc/SkipRowsStream.cpp b/src/jrd/recsrc/SkipRowsStream.cpp index 2f20cf76729..1ebc2650bdc 100644 --- a/src/jrd/recsrc/SkipRowsStream.cpp +++ b/src/jrd/recsrc/SkipRowsStream.cpp @@ -55,7 +55,7 @@ void SkipRowsStream::internalOpen(thread_db* tdbb) const impure->irsb_flags = irsb_open; const dsc* desc = EVL_expr(tdbb, request, m_value); - const SINT64 value = (desc && !(request->req_flags & req_null)) ? MOV_get_int64(tdbb, desc, 0) : 0; + const SINT64 value = desc ? MOV_get_int64(tdbb, desc, 0) : 0; if (value < 0) { diff --git a/src/jrd/recsrc/SortedStream.cpp b/src/jrd/recsrc/SortedStream.cpp index 90a6e54bd8c..c2462094c47 100644 --- a/src/jrd/recsrc/SortedStream.cpp +++ b/src/jrd/recsrc/SortedStream.cpp @@ -232,7 +232,7 @@ Sort* SortedStream::init(thread_db* tdbb) const if (item->node) { from = EVL_expr(tdbb, request, item->node); - if (request->req_flags & req_null) + if (!from) flag = true; } else diff --git a/src/jrd/recsrc/WindowedStream.cpp b/src/jrd/recsrc/WindowedStream.cpp index 511b8bef411..7063e9bdeaf 100644 --- a/src/jrd/recsrc/WindowedStream.cpp +++ b/src/jrd/recsrc/WindowedStream.cpp @@ -963,7 +963,7 @@ void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, Request* reque dsc* desc = EVL_expr(tdbb, request, frame->value); bool error = false; - if (request->req_flags & req_null) + if (!desc) error = true; else { diff --git a/src/jrd/req.h b/src/jrd/req.h index 42be7c319e2..b2c61fdd074 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -551,18 +551,17 @@ class Request : public pool_alloc inline constexpr ULONG req_active = 0x1L; inline constexpr ULONG req_stall = 0x2L; inline constexpr ULONG req_leave = 0x4L; -inline constexpr ULONG req_null = 0x8L; -inline constexpr ULONG req_abort = 0x10L; -inline constexpr ULONG req_error_handler = 0x20L; // looper is called to handle error -inline constexpr ULONG req_warning = 0x40L; -inline constexpr ULONG req_in_use = 0x80L; -inline constexpr ULONG req_continue_loop = 0x100L; // PSQL continue statement -inline constexpr ULONG req_proc_fetch = 0x200L; // Fetch from procedure in progress -inline constexpr ULONG req_proc_select = 0x400L; // Select from procedure in progress -inline constexpr ULONG req_same_tx_upd = 0x800L; // record was updated by same transaction -inline constexpr ULONG req_reserved = 0x1000L; // Request reserved for client -inline constexpr ULONG req_update_conflict = 0x2000L; // We need to restart request due to update conflict -inline constexpr ULONG req_restart_ready = 0x4000L; // Request is ready to restart in case of update conflict +inline constexpr ULONG req_abort = 0x8L; +inline constexpr ULONG req_error_handler = 0x10L; // looper is called to handle error +inline constexpr ULONG req_warning = 0x20L; +inline constexpr ULONG req_in_use = 0x40L; +inline constexpr ULONG req_continue_loop = 0x80L; // PSQL continue statement +inline constexpr ULONG req_proc_fetch = 0x100L; // Fetch from procedure in progress +inline constexpr ULONG req_proc_select = 0x200L; // Select from procedure in progress +inline constexpr ULONG req_same_tx_upd = 0x400L; // record was updated by same transaction +inline constexpr ULONG req_reserved = 0x800L; // Request reserved for client +inline constexpr ULONG req_update_conflict = 0x1000L; // We need to restart request due to update conflict +inline constexpr ULONG req_restart_ready = 0x2000L; // Request is ready to restart in case of update conflict // Index lock block diff --git a/src/jrd/val.h b/src/jrd/val.h index a65baf9c92e..25fe48fa238 100644 --- a/src/jrd/val.h +++ b/src/jrd/val.h @@ -31,6 +31,7 @@ #include "../include/fb_blk.h" #include "../common/classes/array.h" +#include "../common/classes/TriState.h" #include "../jrd/intl_classes.h" #include "../jrd/MetaName.h" #include "../jrd/RecordNumber.h" @@ -101,9 +102,7 @@ class LookupValueList ValueExprNode** end() { return m_values.end(); } const SortedValueList* init(thread_db* tdbb, Request* request) const; - - bool find(thread_db* tdbb, Request* request, - const ValueExprNode* value, const dsc* desc) const; + Firebird::TriState find(thread_db* tdbb, Request* request, const ValueExprNode* value, const dsc* desc) const; private: Firebird::HalfStaticArray m_values; diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 44760b74b11..c02d026b323 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -1712,14 +1712,6 @@ void VIO_copy_record(thread_db* tdbb, jrd_rel* relation, Record* orgRecord, Reco * Copy the given record to a new destination, * taking care about possible format differences. **************************************/ - // dimitr: Clear the req_null flag that may stay active after the last - // boolean evaluation. Here we use only EVL_field() calls that - // do not touch this flag and data copying is done only for - // non-NULL fields, so req_null should never be seen inside blb::move(). - // See CORE-6090 for details. - - const auto request = tdbb->getRequest(); - request->req_flags &= ~req_null; const auto orgFormat = orgRecord->getFormat(); const auto newFormat = newRecord->getFormat(); From 5d2b20f0c16dcf7cd14a841e9876cc6aa7e7731f Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Thu, 6 Nov 2025 21:25:09 -0300 Subject: [PATCH 3/3] Misc --- src/dsql/BoolNodes.cpp | 19 ++++++++----------- src/jrd/fun.epp | 6 +----- src/jrd/recsrc/FilteredStream.cpp | 12 ++++-------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/dsql/BoolNodes.cpp b/src/dsql/BoolNodes.cpp index 5e7c0b4574f..8e83a0cc249 100644 --- a/src/dsql/BoolNodes.cpp +++ b/src/dsql/BoolNodes.cpp @@ -281,7 +281,7 @@ TriState BinaryBoolNode::executeAnd(thread_db* tdbb, Request* request) const if (value1.isAssigned()) { - if (!value1.asBool()) + if (value1 != TriState(true)) return TriState(false); return arg2->execute(tdbb, request); @@ -863,12 +863,12 @@ TriState ComparativeBoolNode::execute(thread_db* tdbb, Request* request) const case blr_between: desc[1] = EVL_expr(tdbb, request, arg3); if (!desc[1]) - return !null2 && comparison < 0 ? TriState(false) : TriState::empty(); + return (!null2 && comparison < 0) ? TriState(false) : TriState::empty(); { // arg1 <= arg3 const bool cmp1_3 = (MOV_compare(tdbb, desc[0], desc[1]) <= 0); - return null2 && cmp1_3 ? TriState::empty() : TriState(cmp1_3); + return (null2 && cmp1_3) ? TriState::empty() : TriState(cmp1_3); } case blr_containing: @@ -1050,24 +1050,21 @@ TriState ComparativeBoolNode::stringBoolean(thread_db* tdbb, Request* request, else { if (blrOp == blr_containing) - return TriState(obj->contains(*tdbb->getDefaultPool(), - str, strLen, patternStr, patternLen)); + return TriState(obj->contains(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen)); else if (blrOp == blr_starting) - return TriState(obj->starts(*tdbb->getDefaultPool(), - str, strLen, patternStr, patternLen)); + return TriState(obj->starts(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen)); else if (blrOp == blr_like) + { return TriState(obj->like(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen, escapeStr, escapeLen)); + } else if (blrOp == blr_similar) { return TriState(obj->similarTo(tdbb, *tdbb->getDefaultPool(), str, strLen, patternStr, patternLen, escapeStr, escapeLen)); } else // blr_matching - { - return TriState(obj->matches(*tdbb->getDefaultPool(), - str, strLen, patternStr, patternLen)); - } + return TriState(obj->matches(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen)); } } diff --git a/src/jrd/fun.epp b/src/jrd/fun.epp index 30192901c8e..97b48074b63 100644 --- a/src/jrd/fun.epp +++ b/src/jrd/fun.epp @@ -419,11 +419,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra // doesn't carry the null flag in the descriptor. Why Borland didn't // set on such flag is maybe because it only has local meaning. // This closes SF Bug #728839. - if (!(input && (input->dsc_flags & DSC_null))) - *arg_ptr++ = nullptr; - else - *arg_ptr++ = input; - + *arg_ptr++ = (input && !input->isNull()) ? input : nullptr; continue; } diff --git a/src/jrd/recsrc/FilteredStream.cpp b/src/jrd/recsrc/FilteredStream.cpp index 0e66b3c0173..ead4bda7332 100644 --- a/src/jrd/recsrc/FilteredStream.cpp +++ b/src/jrd/recsrc/FilteredStream.cpp @@ -98,7 +98,7 @@ bool FilteredStream::internalGetRecord(thread_db* tdbb) const if (!(impure->irsb_flags & irsb_open)) return false; - if (!evaluateBoolean(tdbb).asBool()) + if (evaluateBoolean(tdbb) != TriState(true)) { invalidateRecords(request); return false; @@ -246,11 +246,9 @@ Firebird::TriState FilteredStream::evaluateBoolean(thread_db* tdbb) const else { // select for ANY/ALL processing - const bool select_value = select_node->execute(tdbb, request).asBool(); - // see if any record in select stream - if (select_value) + if (select_node->execute(tdbb, request).asBool()) { // see if any record is null @@ -301,8 +299,7 @@ Firebird::TriState FilteredStream::evaluateBoolean(thread_db* tdbb) const if (select_node) { // select for ANY/ALL processing - const bool select_value = select_node->execute(tdbb, request).asBool(); - if (select_value) + if (select_node->execute(tdbb, request).asBool()) { any_false = true; break; @@ -338,8 +335,7 @@ Firebird::TriState FilteredStream::evaluateBoolean(thread_db* tdbb) const if (select_node) { // select for ANY/ALL processing - const bool select_value = select_node->execute(tdbb, request).asBool(); - if (select_value) + if (select_node->execute(tdbb, request).asBool()) { any_false = true; break;