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

Native precise indexing of decfloat fields

This commit is contained in:
AlexPeshkoff 2017-02-27 15:02:49 +03:00
parent 1ca3ceec16
commit 386c5030d2
5 changed files with 168 additions and 21 deletions

View File

@ -106,12 +106,8 @@ private:
CDecimal128 dmax(DBL_MAX, DecimalStatus(0)), dmin(-DBL_MAX, DecimalStatus(0));
void make(unsigned int* key,
const unsigned pMax, const int bias, const unsigned decSize,
unsigned char* coeff, int sign, int exp)
unsigned digits(const unsigned pMax, unsigned char* const coeff, int& exp)
{
// normalize coeff & exponent
bool zero = true;
for (unsigned i = 0; i < pMax; ++i)
{
if (coeff[i])
@ -122,14 +118,30 @@ void make(unsigned int* key,
memset(&coeff[pMax - i], 0, i);
exp -= i;
}
zero = false;
break;
i = pMax - i;
while (!coeff[i - 1])
{
fb_assert(i > 0);
--i;
}
return i;
}
}
return 0;
}
void make(unsigned int* key,
const unsigned pMax, const int bias, const unsigned decSize,
unsigned char* coeff, int sign, int exp)
{
// normalize coeff & exponent
unsigned dig = digits(pMax, coeff, exp);
// exponent bias and sign
exp += (bias + 2);
if (zero)
if (!dig)
exp = 1;
if (sign)
exp = -exp;
@ -146,6 +158,75 @@ void make(unsigned int* key,
}
}
struct tab { UCHAR rshift, lshift; };
tab table[4] =
{
{ 2, 6 },
{ 4, 4 },
{ 6, 2 },
{ 8, 0 }
};
ULONG indexKey(char* key, unsigned pMax, const int bias, unsigned char* coeff, int sign, int exp)
{
// normalize coeff & exponent
unsigned dig = digits(pMax, coeff, exp);
// exponent bias and sign
exp += (bias + 1);
if (!dig)
exp = 0;
if (sign)
exp = -exp;
exp += 2 * (bias + 1); // make it positive
fb_assert(exp >= 0 && exp < 64 * 1024);
// encode exp
char* k = key;
*k++ = exp >> 8;
*k++ = exp & 0xff;
// invert negative
unsigned char* const end = &coeff[dig];
if (sign && dig)
{
fb_assert(end[-1]);
--end[-1];
for (unsigned char* p = coeff; p < end; ++p)
*p = 9 - *p;
}
// Some 0's in the end - caller, do not forget to reserve additional space on stack
end[0] = end[1] = 0;
// Avoid bad data in k in case when coeff is zero
*k = 0;
// compress coeff - 3 decimal digits (999) per 10 bits (1023)
unsigned char* p = coeff;
for (tab* t = table; p < end; p += 3)
{
USHORT val = p[0] * 100 + p[1] * 10 + p[2];
fb_assert(val < 1000); // 1024, 10 bit
*k |= (val >> t->rshift);
++k;
*k = (val << t->lshift);
if (!t->lshift)
{
++k;
*k = 0;
t = table;
}
else
++t;
}
if (*k)
++k;
return k - key;
}
void grab(unsigned int* key,
const unsigned pMax, const int bias, const unsigned decSize,
unsigned char* bcd, int& sign, int& exp)
@ -346,6 +427,39 @@ Decimal64 Decimal64::neg() const
return rc;
}
void Decimal64::makeKey(unsigned int* key) const
{
unsigned char coeff[DECDOUBLE_Pmax];
int sign = decDoubleGetCoefficient(&dec, coeff);
int exp = decDoubleGetExponent(&dec);
make(key, DECDOUBLE_Pmax, DECDOUBLE_Bias, sizeof(dec), coeff, sign, exp);
}
void Decimal64::grabKey(unsigned int* key)
{
int exp, sign;
unsigned char bcd[DECDOUBLE_Pmax];
grab(key, DECDOUBLE_Pmax, DECDOUBLE_Bias, sizeof(dec), bcd, sign, exp);
decDoubleFromBCD(&dec, exp, bcd, sign);
}
ULONG Decimal64::getIndexKeyLength()
{
return 9;
}
ULONG Decimal64::makeIndexKey(vary* buf)
{
unsigned char coeff[DECDOUBLE_Pmax + 2];
int sign = decDoubleGetCoefficient(&dec, coeff);
int exp = decDoubleGetExponent(&dec);
buf->vary_length = indexKey(buf->vary_string, DECDOUBLE_Pmax, DECDOUBLE_Bias, coeff, sign, exp);
return buf->vary_length;
}
Decimal128 Decimal128::set(Decimal64 d64)
@ -678,23 +792,19 @@ void Decimal128::grabKey(unsigned int* key)
decQuadFromBCD(&dec, exp, bcd, sign);
}
void Decimal64::makeKey(unsigned int* key) const
ULONG Decimal128::getIndexKeyLength()
{
unsigned char coeff[DECDOUBLE_Pmax];
int sign = decDoubleGetCoefficient(&dec, coeff);
int exp = decDoubleGetExponent(&dec);
make(key, DECDOUBLE_Pmax, DECDOUBLE_Bias, sizeof(dec), coeff, sign, exp);
return 17;
}
void Decimal64::grabKey(unsigned int* key)
ULONG Decimal128::makeIndexKey(vary* buf)
{
int exp, sign;
unsigned char bcd[DECDOUBLE_Pmax];
unsigned char coeff[DECQUAD_Pmax + 2];
int sign = decQuadGetCoefficient(&dec, coeff);
int exp = decQuadGetExponent(&dec);
grab(key, DECDOUBLE_Pmax, DECDOUBLE_Bias, sizeof(dec), bcd, sign, exp);
decDoubleFromBCD(&dec, exp, bcd, sign);
buf->vary_length = indexKey(buf->vary_string, DECQUAD_Pmax, DECQUAD_Bias, coeff, sign, exp);
return buf->vary_length;
}
} // namespace Firebird

View File

@ -76,6 +76,8 @@ public:
void makeKey(unsigned int* key) const;
void grabKey(unsigned int* key);
static ULONG getIndexKeyLength();
ULONG makeIndexKey(vary* buf);
#ifdef DEV_BUILD
int show();
@ -127,6 +129,8 @@ public:
void makeKey(unsigned int* key) const;
void grabKey(unsigned int* key);
static ULONG getIndexKeyLength();
ULONG makeIndexKey(vary* buf);
#ifdef DEV_BUILD
int show();

View File

@ -1373,6 +1373,14 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
length = sizeof(UCHAR);
break;
case dtype_dec64:
length = Decimal64::getIndexKeyLength();
break;
case dtype_dec128:
length = Decimal128::getIndexKeyLength();
break;
default:
if (idx->idx_flags & idx_expressn)
{
@ -1425,6 +1433,12 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
case idx_boolean:
length = sizeof(UCHAR);
break;
case dtype_dec64:
length = Decimal64::getIndexKeyLength();
break;
case dtype_dec128:
length = Decimal128::getIndexKeyLength();
break;
default:
length = format->fmt_desc[tail->idx_field].dsc_length;
if (format->fmt_desc[tail->idx_field].dsc_dtype == dtype_varying)
@ -2423,6 +2437,7 @@ static void compress(thread_db* tdbb,
}
if (itype == idx_string || itype == idx_byte_array || itype == idx_metadata ||
itype == idx_dec64 || itype == idx_dec128 ||
itype >= idx_first_intl_string)
{
VaryStr<MAX_KEY> buffer;
@ -2431,7 +2446,19 @@ static void compress(thread_db* tdbb,
size_t length;
if (itype >= idx_first_intl_string || itype == idx_metadata)
if (itype == idx_dec64)
{
Decimal64 dec = MOV_get_dec64(tdbb, desc);
length = dec.makeIndexKey(&buffer);
ptr = reinterpret_cast<UCHAR*>(buffer.vary_string);
}
else if (itype == idx_dec128)
{
Decimal128 dec = MOV_get_dec128(tdbb, desc);
length = dec.makeIndexKey(&buffer);
ptr = reinterpret_cast<UCHAR*>(buffer.vary_string);
}
else if (itype >= idx_first_intl_string || itype == idx_metadata)
{
DSC to;

View File

@ -99,6 +99,8 @@ const int idx_sql_time = 6;
const int idx_timestamp = 7;
const int idx_numeric2 = 8; // Introduced for 64-bit Integer support
const int idx_boolean = 9;
const int idx_dec64 = 10;
const int idx_dec128 = 11;
// idx_itype space for future expansion
const int idx_first_intl_string = 64; // .. MAX (short) Range of computed key strings

View File

@ -1241,6 +1241,10 @@ USHORT DFW_assign_index_type(thread_db* tdbb, const Firebird::MetaName& name, SS
return idx_numeric2;
case dtype_boolean:
return idx_boolean;
case dtype_dec64:
return idx_dec64;
case dtype_dec128:
return idx_dec128;
default:
return idx_numeric;
}