mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 09:20:39 +01:00
Reworked fix for #7997: Unexpected results when comparing integer with string containing value out of range of that integer datatype
This commit is contained in:
parent
35ecc50863
commit
11920822e0
@ -59,7 +59,7 @@ namespace Firebird {
|
||||
|
||||
Int128 Int128::set(const char* value)
|
||||
{
|
||||
// This is simplified method - it does not perform all what's needed for CVT_decompose
|
||||
// This is simplified method - it does not perform all what's needed for full conversion
|
||||
for (v = 0; ; ++value)
|
||||
{
|
||||
if (*value < '0' or *value > '9')
|
||||
@ -319,7 +319,7 @@ Int128 Int128::set(SINT64 value, int scale)
|
||||
|
||||
Int128 Int128::set(const char* value)
|
||||
{
|
||||
// This is simplified method - it does not perform all what's needed for CVT_decompose
|
||||
// This is simplified method - it does not perform all what's needed for full conversion
|
||||
v.FromString(value);
|
||||
return *this;
|
||||
}
|
||||
|
@ -145,6 +145,11 @@ static void localError(const Firebird::Arg::StatusVector&);
|
||||
static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err);
|
||||
static void make_null_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
|
||||
namespace {
|
||||
class RetPtr;
|
||||
}
|
||||
static SSHORT cvt_decompose(const char*, USHORT, RetPtr* return_value, ErrorFunction err);
|
||||
|
||||
class DummyException {};
|
||||
|
||||
namespace
|
||||
@ -277,6 +282,88 @@ static InitInstance<TimeZoneTrie> timeZoneTrie;
|
||||
//#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class RetPtr
|
||||
{
|
||||
public:
|
||||
virtual ~RetPtr() { }
|
||||
|
||||
enum lb10 {RETVAL_OVERFLOW, RETVAL_POSSIBLE_OVERFLOW, RETVAL_NO_OVERFLOW};
|
||||
|
||||
virtual USHORT maxSize() = 0;
|
||||
virtual void truncate8() = 0;
|
||||
virtual void truncate16() = 0;
|
||||
virtual lb10 compareLimitBy10() = 0;
|
||||
virtual void nextDigit(unsigned digit, unsigned base) = 0;
|
||||
virtual bool isLowerLimit() = 0;
|
||||
virtual void neg() = 0;
|
||||
};
|
||||
|
||||
template <class Traits>
|
||||
class RetValue : public RetPtr
|
||||
{
|
||||
public:
|
||||
RetValue(typename Traits::ValueType* ptr)
|
||||
: return_value(ptr)
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
~RetValue()
|
||||
{
|
||||
*return_value = value;
|
||||
}
|
||||
|
||||
USHORT maxSize() override
|
||||
{
|
||||
return sizeof(typename Traits::ValueType);
|
||||
}
|
||||
|
||||
void truncate8() override
|
||||
{
|
||||
ULONG mask = 0xFFFFFFFF;
|
||||
value &= mask;
|
||||
}
|
||||
|
||||
void truncate16() override
|
||||
{
|
||||
FB_UINT64 mask = 0xFFFFFFFFFFFFFFFF;
|
||||
value &= mask;
|
||||
}
|
||||
|
||||
lb10 compareLimitBy10() override
|
||||
{
|
||||
if (static_cast<typename Traits::UnsignedType>(value) > Traits::UPPER_LIMIT_BY_10)
|
||||
return RETVAL_OVERFLOW;
|
||||
if (static_cast<typename Traits::UnsignedType>(value) == Traits::UPPER_LIMIT_BY_10)
|
||||
return RETVAL_POSSIBLE_OVERFLOW;
|
||||
return RETVAL_NO_OVERFLOW;
|
||||
}
|
||||
|
||||
void nextDigit(unsigned digit, unsigned base) override
|
||||
{
|
||||
value *= base;
|
||||
value += digit;
|
||||
}
|
||||
|
||||
bool isLowerLimit() override
|
||||
{
|
||||
return value == Traits::LOWER_LIMIT;
|
||||
}
|
||||
|
||||
void neg() override
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
|
||||
protected:
|
||||
typename Traits::ValueType value;
|
||||
typename Traits::ValueType* return_value;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static const double eps_double = 1e-14;
|
||||
static const double eps_float = 1e-5;
|
||||
|
||||
@ -2207,6 +2294,15 @@ void adjustForScale(V& val, SSHORT scale, const V limit, ErrorFunction err)
|
||||
}
|
||||
|
||||
|
||||
class SSHORTTraits
|
||||
{
|
||||
public:
|
||||
typedef SSHORT ValueType;
|
||||
typedef USHORT UnsignedType;
|
||||
static const USHORT UPPER_LIMIT_BY_10 = MAX_SSHORT / 10;
|
||||
static const SSHORT LOWER_LIMIT = MIN_SSHORT;
|
||||
};
|
||||
|
||||
static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
@ -2227,7 +2323,9 @@ static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt,
|
||||
VaryStr<20> buffer; // long enough to represent largest short in ASCII
|
||||
const char* p;
|
||||
USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
|
||||
scale -= CVT_decompose(p, length, &value, err);
|
||||
|
||||
RetValue<SSHORTTraits> rv(&value);
|
||||
scale -= cvt_decompose(p, length, &rv, err);
|
||||
|
||||
adjustForScale(value, scale, SHORT_LIMIT, err);
|
||||
}
|
||||
@ -2241,6 +2339,16 @@ static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt,
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
class SLONGTraits
|
||||
{
|
||||
public:
|
||||
typedef SLONG ValueType;
|
||||
typedef ULONG UnsignedType;
|
||||
static const ULONG UPPER_LIMIT_BY_10 = MAX_SLONG / 10;
|
||||
static const SLONG LOWER_LIMIT = MIN_SLONG;
|
||||
};
|
||||
|
||||
SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
@ -2354,7 +2462,9 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
|
||||
{
|
||||
USHORT length =
|
||||
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
|
||||
scale -= CVT_decompose(p, length, &value, err);
|
||||
|
||||
RetValue<SLONGTraits> rv(&value);
|
||||
scale -= cvt_decompose(p, length, &rv, err);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3623,29 +3733,12 @@ double CVT_power_of_ten(const int scale)
|
||||
}
|
||||
|
||||
|
||||
class RetPtr
|
||||
{
|
||||
public:
|
||||
virtual ~RetPtr() { }
|
||||
|
||||
enum lb10 {RETVAL_OVERFLOW, RETVAL_POSSIBLE_OVERFLOW, RETVAL_NO_OVERFLOW};
|
||||
|
||||
virtual USHORT maxSize() = 0;
|
||||
virtual void truncate8() = 0;
|
||||
virtual void truncate16() = 0;
|
||||
virtual lb10 compareLimitBy10() = 0;
|
||||
virtual void nextDigit(unsigned digit, unsigned base) = 0;
|
||||
virtual bool isLowerLimit() = 0;
|
||||
virtual void neg() = 0;
|
||||
};
|
||||
|
||||
static void hex_to_value(const char*& string, const char* end, RetPtr* retValue);
|
||||
|
||||
static SSHORT cvt_decompose(const char* string,
|
||||
USHORT length,
|
||||
RetPtr* return_value,
|
||||
ErrorFunction err,
|
||||
int* overflow = nullptr)
|
||||
ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -3743,23 +3836,15 @@ static SSHORT cvt_decompose(const char* string,
|
||||
if (p >= end)
|
||||
continue;
|
||||
}
|
||||
if (overflow)
|
||||
*overflow = 1;
|
||||
else
|
||||
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
|
||||
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
|
||||
return 0;
|
||||
|
||||
case RetPtr::RETVAL_POSSIBLE_OVERFLOW:
|
||||
if ((*p > '8' && sign == -1) || (*p > '7' && sign != -1))
|
||||
{
|
||||
if (overflow)
|
||||
*overflow = 1;
|
||||
else
|
||||
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
|
||||
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -3875,153 +3960,6 @@ static SSHORT cvt_decompose(const char* string,
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
class RetValue : public RetPtr
|
||||
{
|
||||
public:
|
||||
RetValue(typename Traits::ValueType* ptr)
|
||||
: return_value(ptr)
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
~RetValue()
|
||||
{
|
||||
*return_value = value;
|
||||
}
|
||||
|
||||
USHORT maxSize()
|
||||
{
|
||||
return sizeof(typename Traits::ValueType);
|
||||
}
|
||||
|
||||
void truncate8()
|
||||
{
|
||||
ULONG mask = 0xFFFFFFFF;
|
||||
value &= mask;
|
||||
}
|
||||
|
||||
void truncate16()
|
||||
{
|
||||
FB_UINT64 mask = 0xFFFFFFFFFFFFFFFF;
|
||||
value &= mask;
|
||||
}
|
||||
|
||||
lb10 compareLimitBy10()
|
||||
{
|
||||
if (static_cast<typename Traits::UnsignedType>(value) > Traits::UPPER_LIMIT_BY_10)
|
||||
return RETVAL_OVERFLOW;
|
||||
if (static_cast<typename Traits::UnsignedType>(value) == Traits::UPPER_LIMIT_BY_10)
|
||||
return RETVAL_POSSIBLE_OVERFLOW;
|
||||
return RETVAL_NO_OVERFLOW;
|
||||
}
|
||||
|
||||
void nextDigit(unsigned digit, unsigned base)
|
||||
{
|
||||
value *= base;
|
||||
value += digit;
|
||||
}
|
||||
|
||||
bool isLowerLimit()
|
||||
{
|
||||
return value == Traits::LOWER_LIMIT;
|
||||
}
|
||||
|
||||
void neg()
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
|
||||
private:
|
||||
typename Traits::ValueType value;
|
||||
typename Traits::ValueType* return_value;
|
||||
};
|
||||
|
||||
|
||||
class SSHORTTraits
|
||||
{
|
||||
public:
|
||||
typedef SSHORT ValueType;
|
||||
typedef USHORT UnsignedType;
|
||||
static const USHORT UPPER_LIMIT_BY_10 = MAX_SSHORT / 10;
|
||||
static const SSHORT LOWER_LIMIT = MIN_SSHORT;
|
||||
};
|
||||
|
||||
SSHORT CVT_decompose(const char* str, USHORT len, SSHORT* val, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* d e c o m p o s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Decompose a numeric string in mantissa and exponent,
|
||||
* or if it is in hexadecimal notation.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
RetValue<SSHORTTraits> value(val);
|
||||
return cvt_decompose(str, len, &value, err);
|
||||
}
|
||||
|
||||
|
||||
class SLONGTraits
|
||||
{
|
||||
public:
|
||||
typedef SLONG ValueType;
|
||||
typedef ULONG UnsignedType;
|
||||
static const ULONG UPPER_LIMIT_BY_10 = MAX_SLONG / 10;
|
||||
static const SLONG LOWER_LIMIT = MIN_SLONG;
|
||||
};
|
||||
|
||||
SSHORT CVT_decompose(const char* str, USHORT len, SLONG* val, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* d e c o m p o s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Decompose a numeric string in mantissa and exponent,
|
||||
* or if it is in hexadecimal notation.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
RetValue<SLONGTraits> value(val);
|
||||
return cvt_decompose(str, len, &value, err);
|
||||
}
|
||||
|
||||
|
||||
class SINT64Traits
|
||||
{
|
||||
public:
|
||||
typedef SINT64 ValueType;
|
||||
typedef FB_UINT64 UnsignedType;
|
||||
static const FB_UINT64 UPPER_LIMIT_BY_10 = MAX_SINT64 / 10;
|
||||
static const SINT64 LOWER_LIMIT = MIN_SINT64;
|
||||
};
|
||||
|
||||
SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err, int* overflow)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* d e c o m p o s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Decompose a numeric string in mantissa and exponent,
|
||||
* or if it is in hexadecimal notation.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
RetValue<SINT64Traits> value(val);
|
||||
return cvt_decompose(str, len, &value, err, overflow);
|
||||
}
|
||||
|
||||
|
||||
class I128Traits
|
||||
{
|
||||
public:
|
||||
@ -4034,6 +3972,25 @@ public:
|
||||
const CInt128 I128Traits::UPPER_LIMIT_BY_10(CInt128(CInt128::MkMax) / 10);
|
||||
const CInt128 I128Traits::LOWER_LIMIT(CInt128::MkMin);
|
||||
|
||||
class RetI128 : public RetValue<I128Traits>
|
||||
{
|
||||
public:
|
||||
RetI128(Int128* v)
|
||||
: RetValue<I128Traits>(v)
|
||||
{ }
|
||||
|
||||
lb10 compareLimitBy10() override
|
||||
{
|
||||
lb10 rc = RetValue<I128Traits>::compareLimitBy10();
|
||||
if (rc != RETVAL_NO_OVERFLOW)
|
||||
return rc;
|
||||
|
||||
if (value.sign() < 0)
|
||||
return RETVAL_OVERFLOW;
|
||||
return RETVAL_NO_OVERFLOW;
|
||||
}
|
||||
};
|
||||
|
||||
SSHORT CVT_decompose(const char* str, USHORT len, Int128* val, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
@ -4049,7 +4006,7 @@ SSHORT CVT_decompose(const char* str, USHORT len, Int128* val, ErrorFunction err
|
||||
**************************************/
|
||||
|
||||
|
||||
RetValue<I128Traits> value(val);
|
||||
RetI128 value(val);
|
||||
return cvt_decompose(str, len, &value, err);
|
||||
}
|
||||
|
||||
@ -4517,6 +4474,15 @@ const UCHAR* CVT_get_bytes(const dsc* desc, unsigned& size)
|
||||
}
|
||||
|
||||
|
||||
class SINT64Traits
|
||||
{
|
||||
public:
|
||||
typedef SINT64 ValueType;
|
||||
typedef FB_UINT64 UnsignedType;
|
||||
static const FB_UINT64 UPPER_LIMIT_BY_10 = MAX_SINT64 / 10;
|
||||
static const SINT64 LOWER_LIMIT = MIN_SINT64;
|
||||
};
|
||||
|
||||
SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
@ -4572,8 +4538,10 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
|
||||
{
|
||||
USHORT length =
|
||||
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
|
||||
|
||||
SINT64 i64;
|
||||
scale -= CVT_decompose(p, length, &i64, err);
|
||||
RetValue<SINT64Traits> rv(&i64);
|
||||
scale -= cvt_decompose(p, length, &rv, err);
|
||||
SINT64_to_SQUAD(i64, value);
|
||||
}
|
||||
break;
|
||||
@ -4612,7 +4580,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
|
||||
}
|
||||
|
||||
|
||||
SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err, int* overflow)
|
||||
SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -4714,7 +4682,9 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
|
||||
{
|
||||
USHORT length =
|
||||
CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err);
|
||||
scale -= CVT_decompose(p, length, &value, err, overflow);
|
||||
|
||||
RetValue<SINT64Traits> rv(&value);
|
||||
scale -= cvt_decompose(p, length, &rv, err);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -97,13 +97,10 @@ Firebird::Int128 CVT_hex_to_int128(const char* str, USHORT len);
|
||||
USHORT CVT_make_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callbacks*);
|
||||
void CVT_move(const dsc*, dsc*, Firebird::DecimalStatus, ErrorFunction);
|
||||
SSHORT CVT_decompose(const char*, USHORT, SSHORT*, ErrorFunction);
|
||||
SSHORT CVT_decompose(const char*, USHORT, SLONG*, ErrorFunction);
|
||||
SSHORT CVT_decompose(const char*, USHORT, SINT64*, ErrorFunction, int* overflow = nullptr);
|
||||
SSHORT CVT_decompose(const char*, USHORT, Firebird::Int128*, ErrorFunction);
|
||||
USHORT CVT_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
USHORT CVT_get_string_ptr_common(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, Firebird::Callbacks*);
|
||||
SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction, int* overflow = nullptr);
|
||||
SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
SQUAD CVT_get_quad(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird::EXPECT_DATETIME,
|
||||
bool, Firebird::Callbacks*);
|
||||
|
@ -101,9 +101,9 @@ const BYTE CVT2_compare_priority[] =
|
||||
10, // dtype_int64 - goes right after long
|
||||
25, // dtype_dbkey - compares with nothing except itself
|
||||
26, // dtype_boolean - compares with nothing except itself
|
||||
12, // dtype_int128 - go after quad
|
||||
16, // dec64 - go after dtype_d_float
|
||||
17, // dec128 - go after dec64 and before dtype_sql_date
|
||||
12, // dtype_int128 - go after quad
|
||||
20, // dtype_sql_time_tz - go after dtype_sql_time
|
||||
22, // dtype_timestamp_tz - go after dtype_timestamp
|
||||
99, // dtype_ex_time_tz - should not be used here
|
||||
@ -203,6 +203,39 @@ bool CVT2_get_binary_comparable_desc(dsc* result, const dsc* arg1, const dsc* ar
|
||||
}
|
||||
|
||||
|
||||
static int cmp_numeric_string(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* c m p _ n u m e r i c _ s t r i n g
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Compare any numeric value with string. Return (-1, 0, 1) if a<b, a=b, or a>b.
|
||||
*
|
||||
**************************************/
|
||||
fb_assert(arg1->isNumeric());
|
||||
fb_assert(arg2->isText());
|
||||
|
||||
Decimal128 buffer; // enough to fit any required data
|
||||
SSHORT scale = 0;
|
||||
UCHAR* text = arg2->dsc_address;
|
||||
if (arg2->dsc_dtype == dtype_varying)
|
||||
text += sizeof(USHORT);
|
||||
|
||||
dsc num2;
|
||||
num2.dsc_dtype = CVT_get_numeric(text, TEXT_LEN(arg2), &scale, &buffer);
|
||||
num2.dsc_address = (UCHAR*)&buffer;
|
||||
num2.dsc_scale = scale;
|
||||
num2.dsc_length = type_lengths[num2.dsc_dtype];
|
||||
num2.dsc_sub_type = 0;
|
||||
num2.dsc_flags = 0;
|
||||
|
||||
return CVT2_compare(arg1, &num2, decSt);
|
||||
}
|
||||
|
||||
|
||||
int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt)
|
||||
{
|
||||
/**************************************
|
||||
@ -520,13 +553,13 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
case dtype_short:
|
||||
{
|
||||
SSHORT scale;
|
||||
if (arg2->dsc_dtype > dtype_varying)
|
||||
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
else
|
||||
scale = arg1->dsc_scale;
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
const SLONG temp1 = CVT_get_long(arg1, scale, decSt, ERR_post);
|
||||
const SLONG temp2 = CVT_get_long(arg2, scale, decSt, ERR_post);
|
||||
|
||||
if (temp1 == temp2)
|
||||
return 0;
|
||||
if (temp1 > temp2)
|
||||
@ -538,22 +571,12 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
// Since longs may overflow when scaled, use int64 instead
|
||||
case dtype_int64:
|
||||
{
|
||||
SSHORT scale;
|
||||
if (arg2->dsc_dtype > dtype_varying)
|
||||
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
else
|
||||
scale = arg1->dsc_scale;
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
int overflow = 0;
|
||||
const SINT64 temp1 = CVT_get_int64(arg1, scale, decSt, ERR_post, &overflow);
|
||||
const SINT64 temp2 = CVT_get_int64(arg2, scale, decSt, ERR_post, &overflow);
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
const Int128 temp1 = CVT_get_int128(arg1, scale, decSt, ERR_post);
|
||||
const Int128 temp2 = CVT_get_int128(arg2, scale, decSt, ERR_post);
|
||||
return temp1.compare(temp2);
|
||||
}
|
||||
SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
const SINT64 temp1 = CVT_get_int64(arg1, scale, decSt, ERR_post);
|
||||
const SINT64 temp2 = CVT_get_int64(arg2, scale, decSt, ERR_post);
|
||||
|
||||
if (temp1 == temp2)
|
||||
return 0;
|
||||
@ -564,11 +587,10 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
case dtype_quad:
|
||||
{
|
||||
SSHORT scale;
|
||||
if (arg2->dsc_dtype > dtype_varying)
|
||||
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
else
|
||||
scale = arg1->dsc_scale;
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
const SQUAD temp1 = CVT_get_quad(arg1, scale, decSt, ERR_post);
|
||||
const SQUAD temp2 = CVT_get_quad(arg2, scale, decSt, ERR_post);
|
||||
return QUAD_COMPARE(&temp1, &temp2);
|
||||
@ -576,6 +598,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
case dtype_real:
|
||||
{
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
const float temp1 = (float) CVT_get_double(arg1, decSt, ERR_post);
|
||||
const float temp2 = (float) CVT_get_double(arg2, decSt, ERR_post);
|
||||
if (temp1 == temp2)
|
||||
@ -587,6 +612,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
case dtype_double:
|
||||
{
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
const double temp1 = CVT_get_double(arg1, decSt, ERR_post);
|
||||
const double temp2 = CVT_get_double(arg2, decSt, ERR_post);
|
||||
if (temp1 == temp2)
|
||||
@ -598,6 +626,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
case dtype_dec64:
|
||||
{
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
const Decimal64 temp1 = CVT_get_dec64(arg1, decSt, ERR_post);
|
||||
const Decimal64 temp2 = CVT_get_dec64(arg2, decSt, ERR_post);
|
||||
return temp1.compare(decSt, temp2);
|
||||
@ -612,12 +643,10 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
|
||||
case dtype_int128:
|
||||
{
|
||||
SSHORT scale;
|
||||
if (arg2->dsc_dtype > dtype_varying)
|
||||
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
else
|
||||
scale = arg1->dsc_scale;
|
||||
if (arg2->isText())
|
||||
return cmp_numeric_string(arg1, arg2, decSt);
|
||||
|
||||
SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
const Int128 temp1 = CVT_get_int128(arg1, scale, decSt, ERR_post);
|
||||
const Int128 temp2 = CVT_get_int128(arg2, scale, decSt, ERR_post);
|
||||
return temp1.compare(temp2);
|
||||
|
Loading…
Reference in New Issue
Block a user