diff --git a/src/jrd/recsrc/RecordSource.h b/src/jrd/recsrc/RecordSource.h index 2b81225ec63..236c256c790 100644 --- a/src/jrd/recsrc/RecordSource.h +++ b/src/jrd/recsrc/RecordSource.h @@ -1626,32 +1626,14 @@ namespace Jrd struct Impure final : public TableValueFunctionScan::Impure { - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_start; - - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_finish; - - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_step; - - union - { - SINT64 vlu_int64; - Firebird::Int128 vlu_int128; - } m_result; + impure_value m_start; + impure_value m_finish; + impure_value m_step; + impure_value m_result; - UCHAR m_dtype; + USHORT m_flags; SCHAR m_scale; + SCHAR m_stepSign; }; public: diff --git a/src/jrd/recsrc/TableValueFunctionScan.cpp b/src/jrd/recsrc/TableValueFunctionScan.cpp index 637d5f49cb6..b0b5bbe30b3 100644 --- a/src/jrd/recsrc/TableValueFunctionScan.cpp +++ b/src/jrd/recsrc/TableValueFunctionScan.cpp @@ -407,54 +407,43 @@ void GenSeriesFunctionScan::internalOpen(thread_db* tdbb) const const auto impure = request->getImpure(m_impure); impure->m_recordBuffer = nullptr; - // common scale - impure->m_scale = MIN(MIN(startDesc->dsc_scale, finishDesc->dsc_scale), stepDesc->dsc_scale); - // common type - impure->m_dtype = MAX(MAX(startDesc->dsc_dtype, finishDesc->dsc_dtype), stepDesc->dsc_dtype); + ArithmeticNode::getDescDialect3(tdbb, &impure->m_result.vlu_desc, *startDesc, *stepDesc, blr_add, &impure->m_scale, &impure->m_flags); - if (impure->m_dtype != dtype_int128) - { - const auto start = MOV_get_int64(tdbb, startDesc, impure->m_scale); - const auto finish = MOV_get_int64(tdbb, finishDesc, impure->m_scale); - const auto step = MOV_get_int64(tdbb, stepDesc, impure->m_scale); + SLONG zero = 0; + dsc zeroDesc; + zeroDesc.makeLong(0, &zero); + impure->m_stepSign = MOV_compare(tdbb, stepDesc, &zeroDesc); - if (step == 0) - status_exception::raise(Arg::Gds(isc_genseq_stepmustbe_nonzero) << Arg::Str(m_name)); + if (impure->m_stepSign == 0) + status_exception::raise(Arg::Gds(isc_genseq_stepmustbe_nonzero) << Arg::Str(m_name)); - // validate parameter value - if (((step > 0) && (start > finish)) || - ((step < 0) && (start < finish))) - { - return; - } - - impure->m_start.vlu_int64 = start; - impure->m_finish.vlu_int64 = finish; - impure->m_step.vlu_int64 = step; - impure->m_result.vlu_int64 = start; - } - else + const auto boundaryComparison = MOV_compare(tdbb, startDesc, finishDesc); + // validate parameter value + if (((impure->m_stepSign > 0) && (boundaryComparison > 0)) || + ((impure->m_stepSign < 0) && (boundaryComparison < 0))) { - const auto start = MOV_get_int128(tdbb, startDesc, impure->m_scale); - const auto finish = MOV_get_int128(tdbb, finishDesc, impure->m_scale); - const auto step = MOV_get_int128(tdbb, stepDesc, impure->m_scale); + return; + } - if (step.sign() == 0) - status_exception::raise(Arg::Gds(isc_genseq_stepmustbe_nonzero) << Arg::Str(m_name)); + EVL_make_value(tdbb, startDesc, &impure->m_start); + EVL_make_value(tdbb, finishDesc, &impure->m_finish); + EVL_make_value(tdbb, stepDesc, &impure->m_step); - // validate parameter value - if (((step.sign() > 0) && (start.compare(finish) > 0)) || - ((step.sign() < 0) && (start.compare(finish) < 0))) - { - return; - } - - impure->m_start.vlu_int128 = start; - impure->m_finish.vlu_int128 = finish; - impure->m_step.vlu_int128 = step; - impure->m_result.vlu_int128 = start; + switch (impure->m_result.vlu_desc.dsc_dtype) + { + case dtype_int64: + impure->m_result.vlu_desc.dsc_address = reinterpret_cast(&impure->m_result.vlu_misc.vlu_int64); + break; + case dtype_int128: + impure->m_result.vlu_desc.dsc_address = reinterpret_cast(&impure->m_result.vlu_misc.vlu_int128); + break; + default: + fb_assert(false); } + // result = start + MOV_move(tdbb, startDesc, &impure->m_result.vlu_desc); + impure->irsb_flags |= irsb_open; VIO_record(tdbb, rpb, m_format, &pool); @@ -505,51 +494,40 @@ bool GenSeriesFunctionScan::nextBuffer(thread_db* tdbb) const const auto request = tdbb->getRequest(); const auto impure = request->getImpure(m_impure); - if (impure->m_dtype != dtype_int128) + const auto comparison = MOV_compare(tdbb, &impure->m_result.vlu_desc, &impure->m_finish.vlu_desc); + if (((impure->m_stepSign > 0) && (comparison <= 0)) || + ((impure->m_stepSign < 0) && (comparison >= 0))) { - auto result = impure->m_result.vlu_int64; - const auto finish = impure->m_finish.vlu_int64; - const auto step = impure->m_step.vlu_int64; + Record* const record = request->req_rpb[m_stream].rpb_record; - if (((step > 0) && (result <= finish)) || - ((step < 0) && (result >= finish))) - { - Record* const record = request->req_rpb[m_stream].rpb_record; + auto toDesc = m_format->fmt_desc.begin(); - auto toDesc = m_format->fmt_desc.begin(); - - dsc fromDesc; - fromDesc.makeInt64(impure->m_scale, &result); - assignParameter(tdbb, &fromDesc, toDesc, 0, record); + assignParameter(tdbb, &impure->m_result.vlu_desc, toDesc, 0, record); - result += step; - impure->m_result.vlu_int64 = result; - - return true; + // evaluate next result + try + { + impure_value nextValue; + + ArithmeticNode::add(tdbb, + &impure->m_step.vlu_desc, + &impure->m_result.vlu_desc, + &nextValue, + blr_add, + false, + impure->m_scale, + impure->m_flags); + + MOV_move(tdbb, &nextValue.vlu_desc, &impure->m_result.vlu_desc); } - } - else - { - auto result = impure->m_result.vlu_int128; - const auto finish = impure->m_finish.vlu_int128; - const auto step = impure->m_step.vlu_int128; - - if (((step.sign() > 0) && (result.compare(finish) <= 0)) || - ((step.sign() < 0) && (result.compare(finish) >= 0))) + catch (const status_exception&) { - Record* const record = request->req_rpb[m_stream].rpb_record; - - auto toDesc = m_format->fmt_desc.begin(); - - dsc fromDesc; - fromDesc.makeInt128(impure->m_scale, &result); - assignParameter(tdbb, &fromDesc, toDesc, 0, record); - - result = result.add(step); - impure->m_result.vlu_int128 = result; - - return true; + tdbb->tdbb_status_vector->clearException(); + // stop evaluate next result + impure->m_stepSign = 0; } + + return true; } return false;