Skip to content

Commit

Permalink
Fixed ORDER BY for big (>34 digits) int128 values with indexed access (
Browse files Browse the repository at this point in the history
…#7225)

Fixed #7133: Order by for big (>34 digits) int128 values is broken when index on that field is used.
  • Loading branch information
AlexPeshkoff authored Jul 1, 2022
1 parent 203c4ea commit 65efac2
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/common/DecFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1059,9 +1059,12 @@ ULONG Decimal128::makeIndexKey(vary* buf)
unsigned char coeff[DECQUAD_Pmax + 2];
int sign = decQuadGetCoefficient(&dec, coeff);
int exp = decQuadGetExponent(&dec);
const int bias = DECQUAD_Bias;
const unsigned pMax = DECQUAD_Pmax;

return makeBcdKey(buf, coeff, sign, exp, DECQUAD_Bias, DECQUAD_Pmax);
}

ULONG Decimal128::makeBcdKey(vary* buf, unsigned char *coeff, int sign, int exp, const int bias, const unsigned pMax)
{
// normalize coeff & exponent
unsigned dig = digits(pMax, coeff, exp);

Expand Down
2 changes: 2 additions & 0 deletions src/common/DecFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ class Decimal128

void getBcd(BCD* bcd) const;

static ULONG makeBcdKey(vary* buf, unsigned char *coeff, int sign, int exp, const int bias, const unsigned pMax);

private:
decQuad dec;
};
Expand Down
29 changes: 29 additions & 0 deletions src/common/Int128.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ void Int128::overflow()
(Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_overflow)).raise();
}


#ifdef DEV_BUILD
const char* Int128::show()
{
Expand Down Expand Up @@ -646,3 +647,31 @@ CInt128 MAX_Int128(CInt128::MkMax);

#endif // FB_USE_ABSEIL_INT128


// implementation independent part

namespace Firebird
{

ULONG Int128::makeIndexKey(vary* buf, int exp)
{
fb_assert(-128 <= exp && exp <= 127);

unsigned char coeff[PMAX + 2];
unsigned char* c = &coeff[PMAX];
for (Int128 v = abs(); v.sign(); )
{
unsigned int m;
v.divMod(10, &m);

fb_assert(m < 10);
fb_assert(c >= coeff);
*--c = m;
}
memset(coeff, 0, c - coeff);

return Decimal128::makeBcdKey(buf, coeff, sign() < 0, exp, BIAS, PMAX);
}

} // namespace Firebird

34 changes: 34 additions & 0 deletions src/common/Int128.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ class Int128 //: public Decimal128Base
return rc;
}

void divMod(unsigned int divisor, unsigned int* remainder)
{
absl::int128 d = divisor;
*remainder = int(v % d);
v /= d;
}

// returns internal data in per-32bit form
void getTable32(unsigned* dwords) const
{
Expand All @@ -303,6 +310,16 @@ class Int128 //: public Decimal128Base
return (UCHAR*)(&v);
}

static const unsigned BIAS = 128;
static const unsigned PMAX = 38;

ULONG makeIndexKey(vary* buf, int scale);

static ULONG getIndexKeyLength()
{
return 19;
}

protected:
absl::int128 v;

Expand Down Expand Up @@ -532,6 +549,13 @@ class Int128 //: public Decimal128Base
return rc;
}

void divMod(unsigned int divisor, unsigned int* remainder)
{
ttmath::sint rem;
v.DivInt(divisor, &rem);
*remainder = rem;
}

void getTable32(unsigned* dwords) const; // internal data in per-32bit form
void setTable32(const unsigned* dwords);
void setScale(int scale);
Expand All @@ -541,6 +565,16 @@ class Int128 //: public Decimal128Base
return (UCHAR*)(v.table);
}

static const unsigned BIAS = 128;
static const unsigned PMAX = 38;

ULONG makeIndexKey(vary* buf, int scale);

static ULONG getIndexKeyLength()
{
return 19;
}

protected:
ttmath::Int<TTMATH_BITS(128)> v;

Expand Down
2 changes: 1 addition & 1 deletion src/common/cvt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3125,7 +3125,7 @@ Int128 CVT_get_int128(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorF
**************************************
*
* Functional description
* Convert something arbitrary to a DecFloat(34) / (128 bit).
* Convert something arbitrary to 128 bit integer.
*
**************************************/
VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII
Expand Down
17 changes: 15 additions & 2 deletions src/jrd/btr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,10 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
length = Decimal128::getIndexKeyLength();
break;

case idx_bcd:
length = Int128::getIndexKeyLength();
break;

default:
if (idx->idx_flags & idx_expressn)
{
Expand Down Expand Up @@ -1489,6 +1493,9 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
case idx_decimal:
length = Decimal128::getIndexKeyLength();
break;
case idx_bcd:
length = Int128::getIndexKeyLength();
break;
default:
length = format->fmt_desc[tail->idx_field].dsc_length;
if (format->fmt_desc[tail->idx_field].dsc_dtype == dtype_varying)
Expand Down Expand Up @@ -2504,7 +2511,7 @@ static void compress(thread_db* tdbb,
UCHAR* p = key->key_data;

if (itype == idx_string || itype == idx_byte_array || itype == idx_metadata ||
itype == idx_decimal || itype >= idx_first_intl_string)
itype == idx_decimal || itype == idx_bcd || itype >= idx_first_intl_string)
{
temporary_key* root_key = key;
bool has_next;
Expand All @@ -2519,7 +2526,13 @@ static void compress(thread_db* tdbb,
{
first_key = false;

if (itype == idx_decimal)
if (itype == idx_bcd)
{
Int128 i = MOV_get_int128(tdbb, desc, desc->dsc_scale);
length = i.makeIndexKey(&buffer, desc->dsc_scale);
ptr = reinterpret_cast<UCHAR*>(buffer.vary_string);
}
else if (itype == idx_decimal)
{
Decimal128 dec = MOV_get_dec128(tdbb, desc);
length = dec.makeIndexKey(&buffer);
Expand Down
1 change: 1 addition & 0 deletions src/jrd/btr.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ const int idx_boolean = 9;
const int idx_decimal = 10;
const int idx_sql_time_tz = 11;
const int idx_timestamp_tz = 12;
const int idx_bcd = 13; // 128-bit Integer support

// idx_itype space for future expansion
const int idx_first_intl_string = 64; // .. MAX (short) Range of computed key strings
Expand Down
3 changes: 2 additions & 1 deletion src/jrd/dfw.epp
Original file line number Diff line number Diff line change
Expand Up @@ -1302,8 +1302,9 @@ USHORT DFW_assign_index_type(thread_db* tdbb, const MetaName& name, SSHORT field
return idx_boolean;
case dtype_dec64:
case dtype_dec128:
case dtype_int128:
return idx_decimal;
case dtype_int128:
return tdbb->getDatabase()->getEncodedOdsVersion() >= ODS_13_1 ? idx_bcd : idx_decimal;
default:
return idx_numeric;
}
Expand Down

0 comments on commit 65efac2

Please sign in to comment.