mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:03:03 +01:00
High precision datatype support - Numeric(34,x) (#108)
* Raise underflow when close to 0 decfloat value casted to double * High precision NUMERIC datatype based on DECFLOAT * Fixed bulk insert mode in isql for decfloat values * Enforce correct decQuad format after arithmetic operations * Minimum docs for high precision NUMERIC/DECIMAL * Some fixes of code suggested by Adriano: - Use "const" keyword for Decimal128 constants declared internally - Remove unneeded buffer initialization - Remove unused function makeDecimalFixed() - Follow firebird naming conventions to make code better readable and avoid possible conflicts with various .h files - Added forgotten scale for DecimalFixed
This commit is contained in:
parent
f0154f8822
commit
6198bc8ee1
@ -185,3 +185,33 @@ DECFLOAT (FB 4.0)
|
||||
as a literal, instead you can use the equivalent in scientific notation: 1.1E-1022.
|
||||
Similarly 10<1022 zeroes>0 can be presented as 1.0E1024.
|
||||
|
||||
|
||||
Enhancement in precision of calculations with NUMERIC/DECIMAL (FB 4.0)
|
||||
--------------
|
||||
|
||||
Function:
|
||||
Maximum precision of NUMERIC and DECIMAL data types is increased to 34 digits.
|
||||
|
||||
Author:
|
||||
Alex Peshkoff <peshkoff@mail.ru>
|
||||
|
||||
Syntax rules:
|
||||
NUMERIC ( P {, N} )
|
||||
DECIMAL ( P {, N} )
|
||||
where P is precision (P <= 34, was limited prior with 18 digits) and N is optional number
|
||||
of digits after decimal separator (as before).
|
||||
|
||||
Storage:
|
||||
128-bit, format according to IEEE 754.
|
||||
|
||||
Example(s):
|
||||
1. DECLARE VARIABLE VAR1 DECIMAL(25);
|
||||
2. CREATE TABLE TABLE1 (FIELD1 NUMERIC(34, 17));
|
||||
|
||||
Note(s):
|
||||
Numerics with precision less than 19 digits use SMALLINT, INTEGER, BIGINT or DOUBLE PRECISION
|
||||
as base datatype depending upon number of digits and dialect. When precision is between 19 and
|
||||
34 digits DECFLOAT(34) is used for it. Actual precision is always increased to 34 digits. For
|
||||
complex calculations such digits are casted (internally, in trivial way) to DECFLOAT(34) and
|
||||
the result of various math (log, exp, etc.) and aggregate functions using high precision
|
||||
numeric argument is DECFLOAT(34).
|
||||
|
@ -163,6 +163,7 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool_t
|
||||
break;
|
||||
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
if (!xdr_dec128(xdrs, (Firebird::Decimal128*) p))
|
||||
return FALSE;
|
||||
break;
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
init(DEC_INIT_DECIMAL64);
|
||||
}
|
||||
|
||||
DecimalContext(const Decimal128*, DecimalStatus ds)
|
||||
DecimalContext(const Decimal128Base*, DecimalStatus ds)
|
||||
: decSt(ds)
|
||||
{
|
||||
init(DEC_INIT_DECIMAL128);
|
||||
@ -116,8 +116,10 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
CDecimal128 dmax(DBL_MAX, DecimalStatus(0)), dmin(-DBL_MAX, DecimalStatus(0));
|
||||
CDecimal128 i64max(MAX_SINT64, DecimalStatus(0)), i64min(MIN_SINT64, DecimalStatus(0));
|
||||
const CDecimal128 dmax(DBL_MAX, DecimalStatus(0)), dmin(-DBL_MAX, DecimalStatus(0));
|
||||
const CDecimal128 dzup(DBL_MIN, DecimalStatus(0)), dzlw(-DBL_MIN, DecimalStatus(0));
|
||||
const CDecimal128 i64max(MAX_SINT64, DecimalStatus(0)), i64min(MIN_SINT64, DecimalStatus(0));
|
||||
const CDecimal128 c1(1);
|
||||
|
||||
unsigned digits(const unsigned pMax, unsigned char* const coeff, int& exp)
|
||||
{
|
||||
@ -257,6 +259,15 @@ Decimal64 Decimal64::set(SLONG value, DecimalStatus decSt, int scale)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Decimal64 Decimal64::set(DecimalFixed value, DecimalStatus decSt, int scale)
|
||||
{
|
||||
Decimal128 tmp;
|
||||
tmp.set(value, decSt, scale);
|
||||
*this = tmp.toDecimal64(decSt);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Decimal64 Decimal64::set(SINT64 value, DecimalStatus decSt, int scale)
|
||||
{
|
||||
{
|
||||
@ -499,6 +510,14 @@ Decimal128 Decimal128::set(SLONG value, DecimalStatus decSt, int scale)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::set(DecimalFixed value, DecimalStatus decSt, int scale)
|
||||
{
|
||||
*this = value;
|
||||
setScale(decSt, -scale);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::set(SINT64 value, DecimalStatus decSt, int scale)
|
||||
{
|
||||
{
|
||||
@ -538,6 +557,62 @@ Decimal128 Decimal128::set(double value, DecimalStatus decSt)
|
||||
return *this;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::set(SLONG value)
|
||||
{
|
||||
decQuadFromInt32(&dec, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::set(SINT64 value)
|
||||
{
|
||||
int high = value >> 32;
|
||||
unsigned low = value & 0xFFFFFFFF;
|
||||
|
||||
DecimalContext context(this, DecimalStatus(0));
|
||||
decQuad pow2_32;
|
||||
decQuadFromString(&pow2_32, "4294967296", &context);
|
||||
|
||||
decQuad up, down;
|
||||
decQuadFromInt32(&up, high);
|
||||
decQuadFromUInt32(&down, low);
|
||||
decQuadFMA(&dec, &up, &pow2_32, &down, &context);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::set(const char* value, int scale, DecimalStatus decSt)
|
||||
{
|
||||
{ // scope for 'context'
|
||||
DecimalContext context(this, decSt);
|
||||
decQuadFromString(&dec, value, &context);
|
||||
}
|
||||
|
||||
exactInt(decSt, scale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::set(double value, int scale, DecimalStatus decSt)
|
||||
{
|
||||
char s[50];
|
||||
sprintf(s, "%18.016e", value);
|
||||
{ // scope for 'context'
|
||||
DecimalContext context(this, decSt);
|
||||
decQuadFromString(&dec, s, &context);
|
||||
}
|
||||
|
||||
exactInt(decSt, scale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DecimalFixed::exactInt(DecimalStatus decSt, int scale)
|
||||
{
|
||||
setScale(decSt, -scale);
|
||||
|
||||
DecimalContext context(this, decSt);
|
||||
decQuadToIntegralExact(&dec, &dec, &context);
|
||||
decQuadQuantize(&dec, &dec, &c1.dec, &context);
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::operator=(Decimal64 d64)
|
||||
{
|
||||
decDoubleToWider(&d64.dec, &dec);
|
||||
@ -553,6 +628,13 @@ int Decimal128::toInteger(DecimalStatus decSt, int scale) const
|
||||
return decQuadToInt32(&tmp.dec, &context, rMode);
|
||||
}
|
||||
|
||||
int DecimalFixed::toInteger(DecimalStatus decSt) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
enum rounding rMode = decContextGetRounding(&context);
|
||||
return decQuadToInt32(&dec, &context, rMode);
|
||||
}
|
||||
|
||||
void Decimal128::toString(DecimalStatus decSt, unsigned length, char* to) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
@ -582,16 +664,37 @@ void Decimal128::toString(string& to) const
|
||||
to.recalculate_length();
|
||||
}
|
||||
|
||||
double Decimal128::toDouble(DecimalStatus decSt) const
|
||||
Decimal128 DecimalFixed::scaled128(DecimalStatus decSt, int scale) const
|
||||
{
|
||||
Decimal128 tmp;
|
||||
tmp.set(*this, decSt, -scale);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void DecimalFixed::toString(DecimalStatus decSt, int scale, unsigned length, char* to) const
|
||||
{
|
||||
scaled128(decSt, scale).toString(decSt, length, to);
|
||||
}
|
||||
|
||||
void DecimalFixed::toString(DecimalStatus decSt, int scale, string& to) const
|
||||
{
|
||||
scaled128(decSt, scale).toString(to);
|
||||
}
|
||||
|
||||
double Decimal128Base::toDouble(DecimalStatus decSt) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
|
||||
if (compare(decSt, dmin) < 0 || compare(decSt, dmax) > 0)
|
||||
decContextSetStatus(&context, DEC_Overflow);
|
||||
else if ((!decQuadIsZero(&dec)) && compare(decSt, dzlw) > 0 && compare(decSt, dzup) < 0)
|
||||
{
|
||||
decContextSetStatus(&context, DEC_Underflow);
|
||||
return 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char s[IDecFloat34::STRING_SIZE];
|
||||
memset(s, 0, sizeof(s));
|
||||
decQuadToString(&dec, s);
|
||||
return atof(s);
|
||||
}
|
||||
@ -630,12 +733,37 @@ SINT64 Decimal128::toInt64(DecimalStatus decSt, int scale) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
UCHAR* Decimal128::getBytes()
|
||||
SINT64 DecimalFixed::toInt64(DecimalStatus decSt) const
|
||||
{
|
||||
if (compare(decSt, i64min) < 0 || compare(decSt, i64max) > 0)
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
decContextSetStatus(&context, DEC_Invalid_operation);
|
||||
return 0; // in case of no trap on invalid operation
|
||||
}
|
||||
|
||||
unsigned char coeff[DECQUAD_Pmax];
|
||||
int sign = decQuadGetCoefficient(&dec, coeff);
|
||||
SINT64 rc = 0;
|
||||
|
||||
for (int i = 0; i < DECQUAD_Pmax; ++i)
|
||||
{
|
||||
rc *= 10;
|
||||
if (sign)
|
||||
rc -= coeff[i];
|
||||
else
|
||||
rc += coeff[i];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
UCHAR* Decimal128Base::getBytes()
|
||||
{
|
||||
return dec.bytes;
|
||||
}
|
||||
|
||||
Decimal64 Decimal128::toDecimal64(DecimalStatus decSt) const
|
||||
Decimal64 Decimal128Base::toDecimal64(DecimalStatus decSt) const
|
||||
{
|
||||
Decimal64 rc;
|
||||
DecimalContext context(this, decSt);
|
||||
@ -643,7 +771,7 @@ Decimal64 Decimal128::toDecimal64(DecimalStatus decSt) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Decimal128::setScale(DecimalStatus decSt, int scale)
|
||||
void Decimal128Base::setScale(DecimalStatus decSt, int scale)
|
||||
{
|
||||
if (scale)
|
||||
{
|
||||
@ -653,7 +781,7 @@ void Decimal128::setScale(DecimalStatus decSt, int scale)
|
||||
}
|
||||
}
|
||||
|
||||
int Decimal128::compare(DecimalStatus decSt, Decimal128 tgt) const
|
||||
int Decimal128Base::compare(DecimalStatus decSt, Decimal128Base tgt) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
decQuad r;
|
||||
@ -661,7 +789,7 @@ int Decimal128::compare(DecimalStatus decSt, Decimal128 tgt) const
|
||||
return decQuadToInt32(&r, &context, DEC_ROUND_HALF_UP);
|
||||
}
|
||||
|
||||
bool Decimal128::isInf() const
|
||||
bool Decimal128Base::isInf() const
|
||||
{
|
||||
switch(decQuadClass(&dec))
|
||||
{
|
||||
@ -673,7 +801,7 @@ bool Decimal128::isInf() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Decimal128::isNan() const
|
||||
bool Decimal128Base::isNan() const
|
||||
{
|
||||
switch(decQuadClass(&dec))
|
||||
{
|
||||
@ -685,7 +813,7 @@ bool Decimal128::isNan() const
|
||||
return false;
|
||||
}
|
||||
|
||||
int Decimal128::sign() const
|
||||
int Decimal128Base::sign() const
|
||||
{
|
||||
if (decQuadIsZero(&dec))
|
||||
return 0;
|
||||
@ -694,13 +822,6 @@ int Decimal128::sign() const
|
||||
return 1;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::abs() const
|
||||
{
|
||||
Decimal128 rc;
|
||||
decQuadCopyAbs(&rc.dec, &dec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::ceil(DecimalStatus decSt) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
@ -718,13 +839,27 @@ Decimal128 Decimal128::floor(DecimalStatus decSt) const
|
||||
}
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
int Decimal128::show()
|
||||
int Decimal128Base::show()
|
||||
{
|
||||
decQuadShow(&dec, "");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Decimal128 Decimal128::abs() const
|
||||
{
|
||||
Decimal128 rc;
|
||||
decQuadCopyAbs(&rc.dec, &dec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::neg() const
|
||||
{
|
||||
Decimal128 rc;
|
||||
decQuadCopyNegate(&rc.dec, &dec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::add(DecimalStatus decSt, Decimal128 op2) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
@ -749,6 +884,50 @@ Decimal128 Decimal128::mul(DecimalStatus decSt, Decimal128 op2) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::abs() const
|
||||
{
|
||||
DecimalFixed rc;
|
||||
decQuadCopyAbs(&rc.dec, &dec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::neg() const
|
||||
{
|
||||
DecimalFixed rc;
|
||||
decQuadCopyNegate(&rc.dec, &dec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::add(DecimalStatus decSt, DecimalFixed op2) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
DecimalFixed rc;
|
||||
decQuadAdd(&rc.dec, &dec, &op2.dec, &context);
|
||||
context.checkForExceptions();
|
||||
decQuadQuantize(&rc.dec, &rc.dec, &c1.dec, &context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::sub(DecimalStatus decSt, DecimalFixed op2) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
DecimalFixed rc;
|
||||
decQuadSubtract(&rc.dec, &dec, &op2.dec, &context);
|
||||
context.checkForExceptions();
|
||||
decQuadQuantize(&rc.dec, &rc.dec, &c1.dec, &context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::mul(DecimalStatus decSt, DecimalFixed op2) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
DecimalFixed rc;
|
||||
decQuadMultiply(&rc.dec, &dec, &op2.dec, &context);
|
||||
context.checkForExceptions();
|
||||
decQuadQuantize(&rc.dec, &rc.dec, &c1.dec, &context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::div(DecimalStatus decSt, Decimal128 op2) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
@ -757,10 +936,24 @@ Decimal128 Decimal128::div(DecimalStatus decSt, Decimal128 op2) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
Decimal128 Decimal128::neg() const
|
||||
DecimalFixed DecimalFixed::div(DecimalStatus decSt, DecimalFixed op2, int scale) const
|
||||
{
|
||||
Decimal128 rc;
|
||||
decQuadCopyNegate(&rc.dec, &dec);
|
||||
DecimalContext context(this, decSt);
|
||||
DecimalFixed rc;
|
||||
|
||||
// first divide with full decfloat precision
|
||||
decQuadDivide(&rc.dec, &dec, &op2.dec, &context);
|
||||
|
||||
// next re-scale & int-ize
|
||||
rc.exactInt(decSt, scale);
|
||||
return rc;
|
||||
}
|
||||
|
||||
DecimalFixed DecimalFixed::mod(DecimalStatus decSt, DecimalFixed op2) const
|
||||
{
|
||||
DecimalContext context(this, decSt);
|
||||
DecimalFixed rc;
|
||||
decQuadRemainder(&rc.dec, &dec, &op2.dec, &context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -825,7 +1018,7 @@ Decimal128 Decimal128::log10(DecimalStatus decSt) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Decimal128::makeKey(ULONG* key) const
|
||||
void Decimal128Base::makeKey(ULONG* key) const
|
||||
{
|
||||
unsigned char coeff[DECQUAD_Pmax];
|
||||
int sign = decQuadGetCoefficient(&dec, coeff);
|
||||
@ -834,7 +1027,7 @@ void Decimal128::makeKey(ULONG* key) const
|
||||
make(key, DECQUAD_Pmax, DECQUAD_Bias, sizeof(dec), coeff, sign, exp);
|
||||
}
|
||||
|
||||
void Decimal128::grabKey(ULONG* key)
|
||||
void Decimal128Base::grabKey(ULONG* key)
|
||||
{
|
||||
int exp, sign;
|
||||
unsigned char bcd[DECQUAD_Pmax];
|
||||
@ -844,12 +1037,12 @@ void Decimal128::grabKey(ULONG* key)
|
||||
decQuadFromBCD(&dec, exp, bcd, sign);
|
||||
}
|
||||
|
||||
ULONG Decimal128::getIndexKeyLength()
|
||||
ULONG Decimal128Base::getIndexKeyLength()
|
||||
{
|
||||
return 17;
|
||||
}
|
||||
|
||||
ULONG Decimal128::makeIndexKey(vary* buf)
|
||||
ULONG Decimal128Base::makeIndexKey(vary* buf)
|
||||
{
|
||||
unsigned char coeff[DECQUAD_Pmax + 2];
|
||||
int sign = decQuadGetCoefficient(&dec, coeff);
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "firebird/Interface.h"
|
||||
#include "fb_exception.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "classes/fb_string.h"
|
||||
|
||||
extern "C"
|
||||
@ -63,9 +65,13 @@ struct DecimalBinding
|
||||
SCHAR numScale;
|
||||
};
|
||||
|
||||
class DecimalFixed;
|
||||
|
||||
class Decimal64
|
||||
{
|
||||
friend class Decimal128;
|
||||
friend class DecimalFixed;
|
||||
friend class Decimal128Base;
|
||||
|
||||
public:
|
||||
#if SIZEOF_LONG < 8
|
||||
@ -75,6 +81,7 @@ public:
|
||||
Decimal64 set(SINT64 value, DecimalStatus decSt, int scale);
|
||||
Decimal64 set(const char* value, DecimalStatus decSt);
|
||||
Decimal64 set(double value, DecimalStatus decSt);
|
||||
Decimal64 set(DecimalFixed value, DecimalStatus decSt, int scale);
|
||||
|
||||
UCHAR* getBytes();
|
||||
Decimal64 abs() const;
|
||||
@ -103,12 +110,43 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
decDouble dec;
|
||||
|
||||
void setScale(DecimalStatus decSt, int scale);
|
||||
|
||||
decDouble dec;
|
||||
};
|
||||
|
||||
class Decimal128
|
||||
class Decimal128Base
|
||||
{
|
||||
friend class Decimal128;
|
||||
friend class DecimalFixed;
|
||||
|
||||
public:
|
||||
double toDouble(DecimalStatus decSt) const;
|
||||
Decimal64 toDecimal64(DecimalStatus decSt) const;
|
||||
|
||||
UCHAR* getBytes();
|
||||
int compare(DecimalStatus decSt, Decimal128Base tgt) const;
|
||||
|
||||
bool isInf() const;
|
||||
bool isNan() const;
|
||||
int sign() const;
|
||||
|
||||
void makeKey(ULONG* key) const;
|
||||
void grabKey(ULONG* key);
|
||||
static ULONG getIndexKeyLength();
|
||||
ULONG makeIndexKey(vary* buf);
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
int show();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void setScale(DecimalStatus decSt, int scale);
|
||||
|
||||
decQuad dec;
|
||||
};
|
||||
|
||||
class Decimal128 : public Decimal128Base
|
||||
{
|
||||
friend class Decimal64;
|
||||
|
||||
@ -121,53 +159,40 @@ public:
|
||||
Decimal128 set(SINT64 value, DecimalStatus decSt, int scale);
|
||||
Decimal128 set(const char* value, DecimalStatus decSt);
|
||||
Decimal128 set(double value, DecimalStatus decSt);
|
||||
Decimal128 set(DecimalFixed value, DecimalStatus decSt, int scale);
|
||||
|
||||
Decimal128 operator=(Decimal64 d64);
|
||||
|
||||
int toInteger(DecimalStatus decSt, int scale) const;
|
||||
void toString(DecimalStatus decSt, unsigned length, char* to) const;
|
||||
void toString(string& to) const;
|
||||
double toDouble(DecimalStatus decSt) const;
|
||||
int toInteger(DecimalStatus decSt, int scale) const;
|
||||
SINT64 toInt64(DecimalStatus decSt, int scale) const;
|
||||
UCHAR* getBytes();
|
||||
Decimal64 toDecimal64(DecimalStatus decSt) const;
|
||||
Decimal128 abs() const;
|
||||
Decimal128 ceil(DecimalStatus decSt) const;
|
||||
Decimal128 floor(DecimalStatus decSt) const;
|
||||
Decimal128 abs() const;
|
||||
Decimal128 neg() const;
|
||||
Decimal128 add(DecimalStatus decSt, Decimal128 op2) const;
|
||||
Decimal128 sub(DecimalStatus decSt, Decimal128 op2) const;
|
||||
Decimal128 mul(DecimalStatus decSt, Decimal128 op2) const;
|
||||
Decimal128 div(DecimalStatus decSt, Decimal128 op2) const;
|
||||
Decimal128 neg() const;
|
||||
Decimal128 fma(DecimalStatus decSt, Decimal128 op2, Decimal128 op3) const;
|
||||
|
||||
Decimal128 sqrt(DecimalStatus decSt) const;
|
||||
Decimal128 pow(DecimalStatus decSt, Decimal128 op2) const;
|
||||
Decimal128 ln(DecimalStatus decSt) const;
|
||||
Decimal128 log10(DecimalStatus decSt) const;
|
||||
|
||||
int compare(DecimalStatus decSt, Decimal128 tgt) const;
|
||||
bool isInf() const;
|
||||
bool isNan() const;
|
||||
int sign() const;
|
||||
|
||||
void makeKey(ULONG* key) const;
|
||||
void grabKey(ULONG* key);
|
||||
static ULONG getIndexKeyLength();
|
||||
ULONG makeIndexKey(vary* buf);
|
||||
|
||||
Decimal128 quantize(DecimalStatus decSt, Decimal128 op2) const;
|
||||
Decimal128 normalize(DecimalStatus decSt) const;
|
||||
short totalOrder(Decimal128 op2) const;
|
||||
short decCompare(Decimal128 op2) const;
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
int show();
|
||||
#endif
|
||||
|
||||
private:
|
||||
decQuad dec;
|
||||
|
||||
void setScale(DecimalStatus decSt, int scale);
|
||||
Decimal128 operator=(Decimal128Base d128b)
|
||||
{
|
||||
memcpy(&dec, &d128b.dec, sizeof(dec));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class CDecimal128 : public Decimal128
|
||||
@ -189,6 +214,45 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DecimalFixed : public Decimal128Base
|
||||
{
|
||||
public:
|
||||
#if SIZEOF_LONG < 8
|
||||
DecimalFixed set(int value)
|
||||
{
|
||||
return set(SLONG(value));
|
||||
}
|
||||
#endif
|
||||
DecimalFixed set(SLONG value);
|
||||
DecimalFixed set(SINT64 value);
|
||||
DecimalFixed set(const char* value, int scale, DecimalStatus decSt);
|
||||
DecimalFixed set(double value, int scale, DecimalStatus decSt);
|
||||
|
||||
int toInteger(DecimalStatus decSt) const;
|
||||
SINT64 toInt64(DecimalStatus decSt) const;
|
||||
void toString(DecimalStatus decSt, int scale, unsigned length, char* to) const;
|
||||
void toString(DecimalStatus decSt, int scale, string& to) const;
|
||||
|
||||
DecimalFixed abs() const;
|
||||
DecimalFixed neg() const;
|
||||
DecimalFixed add(DecimalStatus decSt, DecimalFixed op2) const;
|
||||
DecimalFixed sub(DecimalStatus decSt, DecimalFixed op2) const;
|
||||
DecimalFixed mul(DecimalStatus decSt, DecimalFixed op2) const;
|
||||
DecimalFixed div(DecimalStatus decSt, DecimalFixed op2, int scale) const;
|
||||
DecimalFixed mod(DecimalStatus decSt, DecimalFixed op2) const;
|
||||
|
||||
DecimalFixed operator=(Decimal128Base d128b)
|
||||
{
|
||||
memcpy(&dec, &d128b.dec, sizeof(dec));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void exactInt(DecimalStatus decSt, int scale); // rescale & make it integer after conversions
|
||||
|
||||
private:
|
||||
Decimal128 scaled128(DecimalStatus decSt, int scale) const;
|
||||
};
|
||||
|
||||
} // namespace Firebird
|
||||
|
||||
|
||||
|
@ -182,6 +182,12 @@ MetadataFromBlr::MetadataFromBlr(unsigned aBlrLength, const unsigned char* aBlr,
|
||||
item->length = sizeof(Decimal128);
|
||||
break;
|
||||
|
||||
case blr_dec_fixed:
|
||||
item->type = SQL_DEC_FIXED;
|
||||
item->length = sizeof(DecimalFixed);
|
||||
item->scale = rdr.getByte();
|
||||
break;
|
||||
|
||||
default:
|
||||
(Arg::Gds(isc_sqlerr) << Arg::Num(-804) <<
|
||||
Arg::Gds(isc_dsql_sqlda_err)
|
||||
|
@ -307,13 +307,12 @@ static void decimal_float_to_text(const dsc* from, dsc* to, DecimalStatus decSt,
|
||||
|
||||
try
|
||||
{
|
||||
Decimal128 d;
|
||||
if (from->dsc_dtype == dtype_dec64)
|
||||
d = *((Decimal64*) from->dsc_address);
|
||||
((Decimal64*) from->dsc_address)->toString(decSt, sizeof(temp), temp);
|
||||
else if (from->dsc_dtype == dtype_dec128)
|
||||
((Decimal128*) from->dsc_address)->toString(decSt, sizeof(temp), temp);
|
||||
else
|
||||
d = *((Decimal128*) from->dsc_address);
|
||||
|
||||
d.toString(decSt, sizeof(temp), temp);
|
||||
((DecimalFixed*) from->dsc_address)->toString(decSt, from->dsc_scale, sizeof(temp), temp);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
@ -982,6 +981,10 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
|
||||
|
||||
return d128.toInteger(decSt, scale);
|
||||
|
||||
case dtype_dec_fixed:
|
||||
value = ((DecimalFixed*) p)->toInteger(decSt);
|
||||
break;
|
||||
|
||||
case dtype_real:
|
||||
case dtype_double:
|
||||
if (desc->dsc_dtype == dtype_real)
|
||||
@ -1182,6 +1185,10 @@ double CVT_get_double(const dsc* desc, DecimalStatus decSt, ErrorFunction err, b
|
||||
return d128.toDouble(decSt);
|
||||
}
|
||||
|
||||
case dtype_dec_fixed:
|
||||
value = ((DecimalFixed*) desc->dsc_address)->toDouble(decSt);
|
||||
break;
|
||||
|
||||
case dtype_varying:
|
||||
case dtype_cstring:
|
||||
case dtype_text:
|
||||
@ -1470,6 +1477,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
case dtype_boolean:
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
CVT_conversion_error(from, cb->err);
|
||||
break;
|
||||
}
|
||||
@ -1505,6 +1513,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
case dtype_boolean:
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
CVT_conversion_error(from, cb->err);
|
||||
break;
|
||||
}
|
||||
@ -1540,6 +1549,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
case dtype_boolean:
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
CVT_conversion_error(from, cb->err);
|
||||
break;
|
||||
}
|
||||
@ -1729,6 +1739,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
decimal_float_to_text(from, to, decSt, cb);
|
||||
return;
|
||||
|
||||
@ -1855,6 +1866,10 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
*((Decimal128*) p) = CVT_get_dec128(from, decSt, cb->err);
|
||||
return;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
*((DecimalFixed*) p) = CVT_get_dec_fixed(from, (SSHORT) to->dsc_scale, decSt, cb->err);
|
||||
return;
|
||||
|
||||
case dtype_boolean:
|
||||
switch (from->dsc_dtype)
|
||||
{
|
||||
@ -1877,6 +1892,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
|
||||
case dtype_double:
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
CVT_conversion_error(from, cb->err);
|
||||
break;
|
||||
}
|
||||
@ -2591,7 +2607,10 @@ Decimal64 CVT_get_dec64(const dsc* desc, DecimalStatus decSt, ErrorFunction err)
|
||||
return *(Decimal64*) p;
|
||||
|
||||
case dtype_dec128:
|
||||
return ((Decimal128*) p)->toDecimal64(decSt);
|
||||
return ((Decimal128Base*) p)->toDecimal64(decSt);
|
||||
|
||||
case dtype_dec_fixed:
|
||||
return d64.set(*((DecimalFixed*) p), decSt, scale);
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
@ -2672,11 +2691,14 @@ Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction er
|
||||
return d128.set(*((double*) p), decSt);
|
||||
|
||||
case dtype_dec64:
|
||||
return (d128 = (*(Decimal64*) p)); // cast to higher precision never cause rounding/traps
|
||||
return (d128 = *((Decimal64*) p)); // cast to higher precision never cause rounding/traps
|
||||
|
||||
case dtype_dec128:
|
||||
return *(Decimal128*) p;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
return d128.set(*((DecimalFixed*) p), decSt, scale);
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
err(Arg::Gds(isc_badblk)); // internal error
|
||||
@ -2695,6 +2717,104 @@ Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction er
|
||||
}
|
||||
|
||||
|
||||
DecimalFixed CVT_get_dec_fixed(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* C V T _ g e t _ d e c 1 2 8
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Convert something arbitrary to a DecFloat(34) / (128 bit).
|
||||
*
|
||||
**************************************/
|
||||
VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII
|
||||
DecimalFixed dfix;
|
||||
Decimal128 tmp;
|
||||
|
||||
// adjust exact numeric values to same scaling
|
||||
if (DTYPE_IS_EXACT(desc->dsc_dtype))
|
||||
scale -= desc->dsc_scale;
|
||||
|
||||
const char* p = reinterpret_cast<char*>(desc->dsc_address);
|
||||
|
||||
try
|
||||
{
|
||||
switch (desc->dsc_dtype)
|
||||
{
|
||||
case dtype_short:
|
||||
dfix.set(*(SSHORT*) p);
|
||||
break;
|
||||
|
||||
case dtype_long:
|
||||
dfix.set(*(SLONG*) p);
|
||||
break;
|
||||
|
||||
case dtype_quad:
|
||||
dfix.set(CVT_get_int64(desc, 0, decSt, err));
|
||||
break;
|
||||
|
||||
case dtype_int64:
|
||||
dfix.set(*(SINT64*) p);
|
||||
break;
|
||||
|
||||
case dtype_varying:
|
||||
case dtype_cstring:
|
||||
case dtype_text:
|
||||
CVT_make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err);
|
||||
dfix.set(buffer.vary_string, scale, decSt);
|
||||
return dfix; // scale already corrected
|
||||
break;
|
||||
|
||||
case dtype_blob:
|
||||
case dtype_sql_date:
|
||||
case dtype_sql_time:
|
||||
case dtype_timestamp:
|
||||
case dtype_array:
|
||||
case dtype_dbkey:
|
||||
case dtype_boolean:
|
||||
CVT_conversion_error(desc, err);
|
||||
break;
|
||||
|
||||
case dtype_real:
|
||||
dfix.set(*((float*) p), scale, decSt);
|
||||
return dfix; // scale already corrected
|
||||
|
||||
case dtype_double:
|
||||
dfix.set(*((double*) p), scale, decSt);
|
||||
return dfix; // scale already corrected
|
||||
|
||||
case dtype_dec64:
|
||||
dfix = tmp = *((Decimal64*) p);
|
||||
break;
|
||||
|
||||
case dtype_dec128:
|
||||
dfix = *((Decimal128*) p);
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
dfix = *((DecimalFixed*) p);
|
||||
break;
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
err(Arg::Gds(isc_badblk)); // internal error
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
// reraise using passed error function
|
||||
Arg::StatusVector v(ex);
|
||||
err(v);
|
||||
}
|
||||
|
||||
dfix.exactInt(decSt, scale);
|
||||
return dfix;
|
||||
}
|
||||
|
||||
|
||||
SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err)
|
||||
{
|
||||
/**************************************
|
||||
@ -2766,6 +2886,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
SINT64_to_SQUAD(CVT_get_int64(desc, scale, decSt, err), value);
|
||||
break;
|
||||
|
||||
@ -2841,6 +2962,10 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu
|
||||
return d128.toInt64(decSt, scale);
|
||||
}
|
||||
|
||||
case dtype_dec_fixed:
|
||||
value = ((DecimalFixed*) p)->toInt64(decSt);
|
||||
break;
|
||||
|
||||
case dtype_real:
|
||||
case dtype_double:
|
||||
if (desc->dsc_dtype == dtype_real)
|
||||
|
@ -77,6 +77,7 @@ bool CVT_get_boolean(const dsc*, ErrorFunction);
|
||||
double CVT_get_double(const dsc*, Firebird::DecimalStatus, ErrorFunction, bool* getNumericOverflow = nullptr);
|
||||
Firebird::Decimal64 CVT_get_dec64(const dsc*, Firebird::DecimalStatus, ErrorFunction);
|
||||
Firebird::Decimal128 CVT_get_dec128(const dsc*, Firebird::DecimalStatus, ErrorFunction);
|
||||
Firebird::DecimalFixed CVT_get_dec_fixed(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
USHORT CVT_make_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
void CVT_make_null_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
|
||||
void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callbacks*);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -60,7 +60,7 @@ inline bool DTYPE_IS_BLOB_OR_QUAD(UCHAR d)
|
||||
// Exact numeric?
|
||||
inline bool DTYPE_IS_EXACT(UCHAR d)
|
||||
{
|
||||
return d == dtype_int64 || d == dtype_long || d == dtype_short;
|
||||
return d == dtype_int64 || d == dtype_long || d == dtype_short || d == dtype_dec_fixed;
|
||||
}
|
||||
|
||||
inline bool DTYPE_IS_APPROX(UCHAR d)
|
||||
@ -70,7 +70,7 @@ inline bool DTYPE_IS_APPROX(UCHAR d)
|
||||
|
||||
inline bool DTYPE_IS_DECFLOAT(UCHAR d)
|
||||
{
|
||||
return d == dtype_dec128 || d == dtype_dec64;
|
||||
return d == dtype_dec128 || d == dtype_dec64 || d == dtype_dec_fixed;
|
||||
}
|
||||
|
||||
inline bool DTYPE_IS_NUMERIC(UCHAR d)
|
||||
@ -163,7 +163,12 @@ typedef struct dsc
|
||||
|
||||
bool isDecFloat() const
|
||||
{
|
||||
return DTYPE_IS_DECFLOAT(dsc_dtype);
|
||||
return dsc_dtype == dtype_dec128 || dsc_dtype == dtype_dec64;
|
||||
}
|
||||
|
||||
bool isDecFixed() const
|
||||
{
|
||||
return dsc_dtype == dtype_dec_fixed;
|
||||
}
|
||||
|
||||
bool isDecOrInt() const
|
||||
|
@ -63,7 +63,8 @@
|
||||
#define dtype_boolean 21
|
||||
#define dtype_dec64 22
|
||||
#define dtype_dec128 23
|
||||
#define DTYPE_TYPE_MAX 24
|
||||
#define dtype_dec_fixed 24
|
||||
#define DTYPE_TYPE_MAX 25
|
||||
|
||||
#define ISC_TIME_SECONDS_PRECISION 10000
|
||||
#define ISC_TIME_SECONDS_PRECISION_SCALE (-4)
|
||||
|
@ -855,6 +855,11 @@ static const UCHAR* sdl_desc(const UCHAR* ptr, DSC* desc)
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
break;
|
||||
|
||||
case blr_dec_fixed:
|
||||
desc->dsc_dtype = dtype_dec_fixed;
|
||||
desc->dsc_length = sizeof(DecimalFixed);
|
||||
break;
|
||||
|
||||
case blr_timestamp:
|
||||
desc->dsc_dtype = dtype_timestamp;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
|
@ -1520,6 +1520,8 @@ UCHAR sqlTypeToDscType(SSHORT sqlType)
|
||||
return dtype_dec64;
|
||||
case SQL_DEC34:
|
||||
return dtype_dec128;
|
||||
case SQL_DEC_FIXED:
|
||||
return dtype_dec_fixed;
|
||||
default:
|
||||
return dtype_unknown;
|
||||
}
|
||||
|
@ -260,6 +260,7 @@ bool_t xdr_datum( XDR* xdrs, const dsc* desc, UCHAR* buffer)
|
||||
break;
|
||||
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
fb_assert(desc->dsc_length >= sizeof(Firebird::Decimal128));
|
||||
if (!xdr_dec128(xdrs, reinterpret_cast<Firebird::Decimal128*>(p)))
|
||||
return FALSE;
|
||||
|
@ -4462,6 +4462,7 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
|
||||
case blr_float:
|
||||
case blr_dec64:
|
||||
case blr_dec128:
|
||||
case blr_dec_fixed:
|
||||
switch (newFld.dyn_dtype)
|
||||
{
|
||||
case blr_blob:
|
||||
@ -4587,6 +4588,23 @@ void AlterDomainNode::checkUpdate(const dyn_fld& origFld, const dyn_fld& newFld)
|
||||
case blr_double:
|
||||
case blr_dec64:
|
||||
case blr_dec128:
|
||||
case blr_dec_fixed:
|
||||
break;
|
||||
|
||||
default:
|
||||
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
|
||||
errorCode = isc_dyn_invalid_dtype_conversion;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case blr_dec_fixed:
|
||||
switch (origFld.dyn_dtype)
|
||||
{
|
||||
case blr_short:
|
||||
case blr_long:
|
||||
case blr_int64:
|
||||
case blr_dec_fixed:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -467,6 +467,82 @@ void ArithmeticNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
||||
GEN_expr(dsqlScratch, arg2);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const UCHAR DSC_ZTYPE_FLT64 = 0;
|
||||
const UCHAR DSC_ZTYPE_FLT128 = 1;
|
||||
const UCHAR DSC_ZTYPE_FIXED = 2;
|
||||
const UCHAR DSC_ZTYPE_INT = 3;
|
||||
const UCHAR DSC_ZTYPE_OTHER = 4;
|
||||
const UCHAR DSC_ZTYPE_BAD = 5;
|
||||
|
||||
const UCHAR decimalDescTable[5][5] = {
|
||||
/* DSC_ZTYPE_FLT64 DSC_ZTYPE_FLT128 DSC_ZTYPE_FIXED DSC_ZTYPE_INT DSC_ZTYPE_OTHER */
|
||||
/* DSC_ZTYPE_FLT64 */ {DSC_ZTYPE_FLT64, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128},
|
||||
/* DSC_ZTYPE_FLT128 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128},
|
||||
/* DSC_ZTYPE_FIXED */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FLT128},
|
||||
/* DSC_ZTYPE_INT */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD},
|
||||
/* DSC_ZTYPE_OTHER */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD}
|
||||
};
|
||||
|
||||
UCHAR getFType(const dsc& desc)
|
||||
{
|
||||
switch (desc.dsc_dtype)
|
||||
{
|
||||
case dtype_dec64:
|
||||
return DSC_ZTYPE_FLT64;
|
||||
case dtype_dec128:
|
||||
return DSC_ZTYPE_FLT128;
|
||||
case dtype_dec_fixed:
|
||||
return DSC_ZTYPE_FIXED;
|
||||
}
|
||||
|
||||
if (DTYPE_IS_EXACT(desc.dsc_dtype))
|
||||
return DSC_ZTYPE_INT;
|
||||
|
||||
return DSC_ZTYPE_OTHER;
|
||||
}
|
||||
|
||||
enum Scaling { SCALE_MIN, SCALE_SUM };
|
||||
|
||||
unsigned setDecDesc(dsc* desc, const dsc& desc1, const dsc& desc2, Scaling sc, SCHAR* nodScale = nullptr)
|
||||
{
|
||||
UCHAR zipType = decimalDescTable[getFType(desc1)][getFType(desc2)];
|
||||
fb_assert(zipType <= DSC_ZTYPE_FIXED);
|
||||
if (zipType > DSC_ZTYPE_FIXED)
|
||||
zipType = DSC_ZTYPE_FLT128; // In production case fallback to Decimal128
|
||||
|
||||
desc->dsc_dtype = zipType == DSC_ZTYPE_FLT64 ? dtype_dec64 :
|
||||
zipType == DSC_ZTYPE_FLT128 ? dtype_dec128 : dtype_dec_fixed;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
||||
desc->dsc_scale = 0;
|
||||
|
||||
if (zipType == DSC_ZTYPE_FIXED)
|
||||
{
|
||||
switch (sc)
|
||||
{
|
||||
case SCALE_MIN:
|
||||
desc->dsc_scale = MIN(NUMERIC_SCALE(desc1), NUMERIC_SCALE(desc2));
|
||||
break;
|
||||
case SCALE_SUM:
|
||||
desc->dsc_scale = NUMERIC_SCALE(desc1) + NUMERIC_SCALE(desc2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodScale)
|
||||
*nodScale = desc->dsc_scale;
|
||||
|
||||
desc->dsc_length = zipType == DSC_ZTYPE_FLT64 ? sizeof(Decimal64) :
|
||||
zipType == DSC_ZTYPE_FLT128 ? sizeof(Decimal128) : sizeof(DecimalFixed);
|
||||
|
||||
return zipType == DSC_ZTYPE_FIXED ? ExprNode::FLAG_DECFIXED : ExprNode::FLAG_DECFLOAT;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
void ArithmeticNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
|
||||
{
|
||||
dsc desc1, desc2;
|
||||
@ -650,10 +726,8 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
case dtype_dec_fixed:
|
||||
setDecDesc(desc, desc1, desc2, SCALE_MIN);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -680,10 +754,8 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
switch (dtype)
|
||||
{
|
||||
case dtype_dec128:
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
case dtype_dec_fixed:
|
||||
setDecDesc(desc, desc1, desc2, SCALE_SUM);
|
||||
break;
|
||||
|
||||
case dtype_double:
|
||||
@ -727,10 +799,7 @@ void ArithmeticNode::makeDialect1(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
|
||||
if (DTYPE_IS_DECFLOAT(dtype))
|
||||
{
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_flags = (desc1.dsc_flags | desc2.dsc_flags) & DSC_nullable;
|
||||
setDecDesc(desc, desc1, desc2, SCALE_SUM);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -779,7 +848,12 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
// the operation, as <timestamp>-<timestamp> uses
|
||||
// <timestamp> arithmetic, but returns a <double>
|
||||
if (DTYPE_IS_EXACT(dtype1) && DTYPE_IS_EXACT(dtype2))
|
||||
dtype = dtype_int64;
|
||||
{
|
||||
if (desc1.isDecFixed() || desc2.isDecFixed())
|
||||
dtype = dtype_dec_fixed;
|
||||
else
|
||||
dtype = dtype_int64;
|
||||
}
|
||||
else if (desc1.isDecOrInt() && desc2.isDecOrInt())
|
||||
dtype = dtype_dec128;
|
||||
else if (DTYPE_IS_NUMERIC(dtype1) && DTYPE_IS_NUMERIC(dtype2))
|
||||
@ -904,10 +978,8 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
case dtype_dec_fixed:
|
||||
setDecDesc(desc, desc1, desc2, SCALE_MIN);
|
||||
break;
|
||||
|
||||
case dtype_short:
|
||||
@ -955,11 +1027,9 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
|
||||
switch (dtype)
|
||||
{
|
||||
case dtype_dec_fixed:
|
||||
case dtype_dec128:
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
setDecDesc(desc, desc1, desc2, SCALE_SUM);
|
||||
break;
|
||||
|
||||
case dtype_double:
|
||||
@ -1016,8 +1086,8 @@ void ArithmeticNode::makeDialect3(dsc* desc, dsc& desc1, dsc& desc2)
|
||||
break;
|
||||
|
||||
case dtype_dec128:
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
case dtype_dec_fixed:
|
||||
setDecDesc(desc, desc1, desc2, SCALE_SUM);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1217,12 +1287,8 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
nodFlags |= FLAG_DECFLOAT;
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
case dtype_dec_fixed:
|
||||
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_MIN, &nodScale);
|
||||
break;
|
||||
|
||||
case dtype_unknown:
|
||||
@ -1268,12 +1334,8 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
return;
|
||||
|
||||
case dtype_dec128:
|
||||
nodFlags |= FLAG_DECFLOAT;
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
case dtype_dec_fixed:
|
||||
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_SUM, &nodScale);
|
||||
break;
|
||||
|
||||
case dtype_unknown:
|
||||
@ -1357,8 +1419,13 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
// the result dtype. The rule is that two exact numeric operands yield an int64
|
||||
// result, while an approximate numeric and anything yield a double result.
|
||||
|
||||
if (DTYPE_IS_EXACT(desc1.dsc_dtype) && DTYPE_IS_EXACT(desc2.dsc_dtype))
|
||||
dtype = dtype_int64;
|
||||
if (DTYPE_IS_EXACT(dtype1) && DTYPE_IS_EXACT(dtype2))
|
||||
{
|
||||
if (desc1.isDecFixed() || desc2.isDecFixed())
|
||||
dtype = dtype_dec_fixed;
|
||||
else
|
||||
dtype = dtype_int64;
|
||||
}
|
||||
else if (desc1.isDecOrInt() && desc2.isDecOrInt())
|
||||
dtype = dtype_dec128;
|
||||
else if (DTYPE_IS_NUMERIC(desc1.dsc_dtype) && DTYPE_IS_NUMERIC(desc2.dsc_dtype))
|
||||
@ -1493,12 +1560,8 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
nodFlags |= FLAG_DECFLOAT;
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
case dtype_dec_fixed:
|
||||
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_MIN, &nodScale);
|
||||
return;
|
||||
|
||||
case dtype_short:
|
||||
@ -1551,12 +1614,8 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
return;
|
||||
|
||||
case dtype_dec128:
|
||||
nodFlags |= FLAG_DECFLOAT;
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
case dtype_dec_fixed:
|
||||
nodFlags |= setDecDesc(desc, desc1, desc2, SCALE_SUM, &nodScale);
|
||||
return;
|
||||
|
||||
case dtype_int64:
|
||||
@ -1737,7 +1796,7 @@ dsc* ArithmeticNode::execute(thread_db* tdbb, jrd_req* request) const
|
||||
}
|
||||
|
||||
// Add (or subtract) the contents of a descriptor to value block, with dialect-1 semantics.
|
||||
// This function can be removed when dialect-3 becomes the lowest supported dialect. (Version 7.0?)
|
||||
// This function can be removed when dialect-3 becomes the lowest supported dialect. (Version 7.0?)
|
||||
dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNode* node, const UCHAR blrOp)
|
||||
{
|
||||
const ArithmeticNode* arithmeticNode = nodeAs<ArithmeticNode>(node);
|
||||
@ -1781,6 +1840,23 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const ValueExprNo
|
||||
return result;
|
||||
}
|
||||
|
||||
if (node->nodFlags & FLAG_DECFIXED)
|
||||
{
|
||||
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, node->nodScale);
|
||||
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, node->nodScale);
|
||||
|
||||
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
|
||||
value->vlu_misc.vlu_dec_fixed = (blrOp == blr_subtract) ? d2.sub(decSt, d1) : d1.add(decSt, d2);
|
||||
|
||||
result->dsc_dtype = dtype_dec_fixed;
|
||||
result->dsc_length = sizeof(DecimalFixed);
|
||||
result->dsc_scale = node->nodScale;
|
||||
result->dsc_sub_type = 0;
|
||||
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Handle floating arithmetic
|
||||
|
||||
if (node->nodFlags & FLAG_DOUBLE)
|
||||
@ -1861,6 +1937,23 @@ dsc* ArithmeticNode::add2(const dsc* desc, impure_value* value, const ValueExprN
|
||||
return result;
|
||||
}
|
||||
|
||||
if (node->nodFlags & FLAG_DECFIXED)
|
||||
{
|
||||
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, node->nodScale);
|
||||
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, node->nodScale);
|
||||
|
||||
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
|
||||
value->vlu_misc.vlu_dec_fixed = (blrOp == blr_subtract) ? d2.sub(decSt, d1) : d1.add(decSt, d2);
|
||||
|
||||
result->dsc_dtype = dtype_dec_fixed;
|
||||
result->dsc_length = sizeof(DecimalFixed);
|
||||
result->dsc_scale = node->nodScale;
|
||||
result->dsc_sub_type = 0;
|
||||
result->dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Handle floating arithmetic
|
||||
|
||||
if (node->nodFlags & FLAG_DOUBLE)
|
||||
@ -1947,6 +2040,23 @@ dsc* ArithmeticNode::multiply(const dsc* desc, impure_value* value) const
|
||||
return &value->vlu_desc;
|
||||
}
|
||||
|
||||
if (nodFlags & FLAG_DECFIXED)
|
||||
{
|
||||
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, nodScale);
|
||||
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, nodScale);
|
||||
|
||||
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
|
||||
value->vlu_misc.vlu_dec_fixed = d1.mul(decSt, d2);
|
||||
|
||||
value->vlu_desc.dsc_dtype = dtype_dec_fixed;
|
||||
value->vlu_desc.dsc_length = sizeof(DecimalFixed);
|
||||
value->vlu_desc.dsc_scale = nodScale;
|
||||
value->vlu_desc.dsc_sub_type = 0;
|
||||
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
|
||||
|
||||
return &value->vlu_desc;
|
||||
}
|
||||
|
||||
// Handle floating arithmetic
|
||||
|
||||
if (nodFlags & FLAG_DOUBLE)
|
||||
@ -2041,6 +2151,24 @@ dsc* ArithmeticNode::multiply2(const dsc* desc, impure_value* value) const
|
||||
return &value->vlu_desc;
|
||||
}
|
||||
|
||||
if (nodFlags & FLAG_DECFIXED)
|
||||
{
|
||||
const SSHORT scale = NUMERIC_SCALE(*desc);
|
||||
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, desc, scale);
|
||||
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, nodScale - scale);
|
||||
|
||||
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
|
||||
value->vlu_misc.vlu_dec_fixed = d1.mul(decSt, d2);
|
||||
|
||||
value->vlu_desc.dsc_dtype = dtype_dec_fixed;
|
||||
value->vlu_desc.dsc_length = sizeof(DecimalFixed);
|
||||
value->vlu_desc.dsc_scale = nodScale;
|
||||
value->vlu_desc.dsc_sub_type = 0;
|
||||
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
|
||||
|
||||
return &value->vlu_desc;
|
||||
}
|
||||
|
||||
// Handle floating arithmetic
|
||||
|
||||
if (nodFlags & FLAG_DOUBLE)
|
||||
@ -2137,6 +2265,24 @@ dsc* ArithmeticNode::divide2(const dsc* desc, impure_value* value) const
|
||||
return &value->vlu_desc;
|
||||
}
|
||||
|
||||
if (nodFlags & FLAG_DECFIXED)
|
||||
{
|
||||
const SSHORT scale = NUMERIC_SCALE(*desc);
|
||||
const DecimalFixed d2 = MOV_get_dec_fixed(tdbb, desc, scale);
|
||||
const DecimalFixed d1 = MOV_get_dec_fixed(tdbb, &value->vlu_desc, nodScale - scale);
|
||||
|
||||
DecimalStatus decSt = tdbb->getAttachment()->att_dec_status;
|
||||
value->vlu_misc.vlu_dec_fixed = d1.div(decSt, d2, scale * 2);
|
||||
|
||||
value->vlu_desc.dsc_dtype = dtype_dec_fixed;
|
||||
value->vlu_desc.dsc_length = sizeof(DecimalFixed);
|
||||
value->vlu_desc.dsc_scale = nodScale;
|
||||
value->vlu_desc.dsc_sub_type = 0;
|
||||
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc.vlu_dec_fixed;
|
||||
|
||||
return &value->vlu_desc;
|
||||
}
|
||||
|
||||
// Handle floating arithmetic
|
||||
|
||||
if (nodFlags & FLAG_DOUBLE)
|
||||
@ -7829,6 +7975,10 @@ dsc* NegateNode::execute(thread_db* tdbb, jrd_req* request) const
|
||||
impure->vlu_misc.vlu_dec128 = impure->vlu_misc.vlu_dec128.neg();
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
impure->vlu_misc.vlu_dec_fixed = impure->vlu_misc.vlu_dec_fixed.neg();
|
||||
break;
|
||||
|
||||
case dtype_int64:
|
||||
if (impure->vlu_misc.vlu_int64 == MIN_SINT64)
|
||||
ERR_post(Arg::Gds(isc_exception_integer_overflow));
|
||||
@ -10158,6 +10308,7 @@ void SubQueryNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
|
||||
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
desc->dsc_dtype = dtype_dec128;
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
desc->dsc_scale = 0;
|
||||
|
@ -526,6 +526,7 @@ public:
|
||||
static const unsigned FLAG_DATE = 0x20;
|
||||
static const unsigned FLAG_DECFLOAT = 0x40;
|
||||
static const unsigned FLAG_VALUE = 0x80; // Full value area required in impure space.
|
||||
static const unsigned FLAG_DECFIXED = 0x100;
|
||||
|
||||
explicit ExprNode(Type aType, MemoryPool& pool, Kind aKind)
|
||||
: DmlNode(pool, aKind),
|
||||
|
@ -59,7 +59,8 @@ const USHORT blr_dtypes[] = {
|
||||
0, // DB_KEY
|
||||
blr_bool, // dtype_boolean
|
||||
blr_dec64, // dtype_dec64
|
||||
blr_dec128 // dtype_dec128
|
||||
blr_dec128, // dtype_dec128
|
||||
blr_dec_fixed // dtype_dec_fixed
|
||||
};
|
||||
|
||||
bool DDL_ids(const Jrd::DsqlCompilerScratch*);
|
||||
|
@ -257,6 +257,10 @@ public:
|
||||
precision = 18;
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
precision = 34;
|
||||
break;
|
||||
|
||||
default:
|
||||
fb_assert(!DTYPE_IS_EXACT(dtype));
|
||||
}
|
||||
|
@ -393,6 +393,11 @@ void GEN_descriptor( DsqlCompilerScratch* dsqlScratch, const dsc* desc, bool tex
|
||||
dsqlScratch->appendUChar(blr_dec128);
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
dsqlScratch->appendUChar(blr_dec_fixed);
|
||||
dsqlScratch->appendUChar(desc->dsc_scale);
|
||||
break;
|
||||
|
||||
case dtype_sql_date:
|
||||
dsqlScratch->appendUChar(blr_sql_date);
|
||||
break;
|
||||
|
@ -4842,10 +4842,15 @@ prec_scale
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
|
||||
if ($2 < 1 || $2 > 18)
|
||||
yyabandon(YYPOSNARG(2), -842, isc_precision_err); // Precision must be between 1 and 18.
|
||||
if ($2 < 1 || $2 > 34)
|
||||
yyabandon(YYPOSNARG(2), -842, isc_precision_err/*2!!!!!*/); // Precision must be between 1 and 34.
|
||||
|
||||
if ($2 > 9)
|
||||
if ($2 > 18)
|
||||
{
|
||||
$$->dtype = dtype_dec_fixed;
|
||||
$$->length = sizeof(DecimalFixed);
|
||||
}
|
||||
else if ($2 > 9)
|
||||
{
|
||||
if ( ( (client_dialect <= SQL_DIALECT_V5) && (db_dialect > SQL_DIALECT_V5) ) ||
|
||||
( (client_dialect > SQL_DIALECT_V5) && (db_dialect <= SQL_DIALECT_V5) ) )
|
||||
@ -4892,13 +4897,18 @@ prec_scale
|
||||
{
|
||||
$$ = newNode<dsql_fld>();
|
||||
|
||||
if ($2 < 1 || $2 > 18)
|
||||
yyabandon(YYPOSNARG(2), -842, isc_precision_err); // Precision should be between 1 and 18
|
||||
if ($2 < 1 || $2 > 34)
|
||||
yyabandon(YYPOSNARG(2), -842, isc_precision_err/*2!!!!!*/); // Precision must be between 1 and 34.
|
||||
|
||||
if ($4 > $2 || $4 < 0)
|
||||
yyabandon(YYPOSNARG(4), -842, isc_scale_nogt); // Scale must be between 0 and precision
|
||||
|
||||
if ($2 > 9)
|
||||
if ($2 > 18)
|
||||
{
|
||||
$$->dtype = dtype_dec_fixed;
|
||||
$$->length = sizeof(DecimalFixed);
|
||||
}
|
||||
else if ($2 > 9)
|
||||
{
|
||||
if ( ( (client_dialect <= SQL_DIALECT_V5) && (db_dialect > SQL_DIALECT_V5) ) ||
|
||||
( (client_dialect > SQL_DIALECT_V5) && (db_dialect <= SQL_DIALECT_V5) ) )
|
||||
|
@ -78,6 +78,7 @@ typedef struct
|
||||
#define SQL_TYPE_TIME 560
|
||||
#define SQL_TYPE_DATE 570
|
||||
#define SQL_INT64 580
|
||||
#define SQL_DEC_FIXED 32758
|
||||
#define SQL_DEC16 32760
|
||||
#define SQL_DEC34 32762
|
||||
#define SQL_BOOLEAN 32764
|
||||
|
@ -31,6 +31,7 @@ typedef ISC_QUAD;
|
||||
typedef ISC_TIME;
|
||||
typedef FB_DEC16;
|
||||
typedef FB_DEC34;
|
||||
typedef FB_DEC_FIXED;
|
||||
|
||||
// Versioned interface - base for all FB interfaces
|
||||
interface Versioned
|
||||
@ -989,6 +990,7 @@ version: // 3.0 => 4.0
|
||||
EventBlock createEventBlock(Status status, const string* events);
|
||||
DecFloat16 getDecFloat16(Status status);
|
||||
DecFloat34 getDecFloat34(Status status);
|
||||
DecFixed getDecFixed(Status status);
|
||||
}
|
||||
|
||||
interface OffsetsCallback : Versioned
|
||||
@ -1392,3 +1394,13 @@ interface DecFloat34 : Versioned
|
||||
void fromBcd(int sign, const uchar* bcd, int exp, FB_DEC34* to);
|
||||
void fromString(Status status, const string from, FB_DEC34* to);
|
||||
}
|
||||
|
||||
interface DecFixed : Versioned
|
||||
{
|
||||
const uint BCD_SIZE = 34;
|
||||
const uint STRING_SIZE = 41; // may include exponent not more than 3 digits
|
||||
void toBcd(const FB_DEC_FIXED* from, int* sign, uchar* bcd);
|
||||
void toString(Status status, const FB_DEC_FIXED* from, int scale, uint bufferLength, string buffer);
|
||||
void fromBcd(int sign, const uchar* bcd, FB_DEC_FIXED* to);
|
||||
void fromString(Status status, const string from, int scale, FB_DEC_FIXED* to);
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ namespace Firebird
|
||||
class IUdrPlugin;
|
||||
class IDecFloat16;
|
||||
class IDecFloat34;
|
||||
class IDecFixed;
|
||||
|
||||
// Interfaces declarations
|
||||
|
||||
@ -3699,6 +3700,7 @@ namespace Firebird
|
||||
IEventBlock* (CLOOP_CARG *createEventBlock)(IUtil* self, IStatus* status, const char** events) throw();
|
||||
IDecFloat16* (CLOOP_CARG *getDecFloat16)(IUtil* self, IStatus* status) throw();
|
||||
IDecFloat34* (CLOOP_CARG *getDecFloat34)(IUtil* self, IStatus* status) throw();
|
||||
IDecFixed* (CLOOP_CARG *getDecFixed)(IUtil* self, IStatus* status) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -3841,6 +3843,20 @@ namespace Firebird
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> IDecFixed* getDecFixed(StatusType* status)
|
||||
{
|
||||
if (cloopVTable->version < 3)
|
||||
{
|
||||
StatusType::setVersionError(status, "IUtil", cloopVTable->version, 3);
|
||||
StatusType::checkException(status);
|
||||
return 0;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
IDecFixed* ret = static_cast<VTable*>(this->cloopVTable)->getDecFixed(this, status);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class IOffsetsCallback : public IVersioned
|
||||
@ -5420,6 +5436,58 @@ namespace Firebird
|
||||
}
|
||||
};
|
||||
|
||||
class IDecFixed : public IVersioned
|
||||
{
|
||||
public:
|
||||
struct VTable : public IVersioned::VTable
|
||||
{
|
||||
void (CLOOP_CARG *toBcd)(IDecFixed* self, const FB_DEC_FIXED* from, int* sign, unsigned char* bcd) throw();
|
||||
void (CLOOP_CARG *toString)(IDecFixed* self, IStatus* status, const FB_DEC_FIXED* from, int scale, unsigned bufferLength, char* buffer) throw();
|
||||
void (CLOOP_CARG *fromBcd)(IDecFixed* self, int sign, const unsigned char* bcd, FB_DEC_FIXED* to) throw();
|
||||
void (CLOOP_CARG *fromString)(IDecFixed* self, IStatus* status, const char* from, int scale, FB_DEC_FIXED* to) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
IDecFixed(DoNotInherit)
|
||||
: IVersioned(DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
~IDecFixed()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 2;
|
||||
|
||||
static const unsigned BCD_SIZE = 34;
|
||||
static const unsigned STRING_SIZE = 41;
|
||||
|
||||
void toBcd(const FB_DEC_FIXED* from, int* sign, unsigned char* bcd)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->toBcd(this, from, sign, bcd);
|
||||
}
|
||||
|
||||
template <typename StatusType> void toString(StatusType* status, const FB_DEC_FIXED* from, int scale, unsigned bufferLength, char* buffer)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->toString(this, status, from, scale, bufferLength, buffer);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
void fromBcd(int sign, const unsigned char* bcd, FB_DEC_FIXED* to)
|
||||
{
|
||||
static_cast<VTable*>(this->cloopVTable)->fromBcd(this, sign, bcd, to);
|
||||
}
|
||||
|
||||
template <typename StatusType> void fromString(StatusType* status, const char* from, int scale, FB_DEC_FIXED* to)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->fromString(this, status, from, scale, to);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
};
|
||||
|
||||
// Interfaces implementations
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
@ -13093,6 +13161,7 @@ namespace Firebird
|
||||
this->createEventBlock = &Name::cloopcreateEventBlockDispatcher;
|
||||
this->getDecFloat16 = &Name::cloopgetDecFloat16Dispatcher;
|
||||
this->getDecFloat34 = &Name::cloopgetDecFloat34Dispatcher;
|
||||
this->getDecFixed = &Name::cloopgetDecFixedDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -13320,6 +13389,21 @@ namespace Firebird
|
||||
return static_cast<IDecFloat34*>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static IDecFixed* CLOOP_CARG cloopgetDecFixedDispatcher(IUtil* self, IStatus* status) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::getDecFixed(&status2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<IDecFixed*>(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IUtil> > >
|
||||
@ -13351,6 +13435,7 @@ namespace Firebird
|
||||
virtual IEventBlock* createEventBlock(StatusType* status, const char** events) = 0;
|
||||
virtual IDecFloat16* getDecFloat16(StatusType* status) = 0;
|
||||
virtual IDecFloat34* getDecFloat34(StatusType* status) = 0;
|
||||
virtual IDecFixed* getDecFixed(StatusType* status) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
@ -16748,6 +16833,101 @@ namespace Firebird
|
||||
virtual void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC34* to) = 0;
|
||||
virtual void fromString(StatusType* status, const char* from, FB_DEC34* to) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
class IDecFixedBaseImpl : public Base
|
||||
{
|
||||
public:
|
||||
typedef IDecFixed Declaration;
|
||||
|
||||
IDecFixedBaseImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
static struct VTableImpl : Base::VTable
|
||||
{
|
||||
VTableImpl()
|
||||
{
|
||||
this->version = Base::VERSION;
|
||||
this->toBcd = &Name::clooptoBcdDispatcher;
|
||||
this->toString = &Name::clooptoStringDispatcher;
|
||||
this->fromBcd = &Name::cloopfromBcdDispatcher;
|
||||
this->fromString = &Name::cloopfromStringDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
this->cloopVTable = &vTable;
|
||||
}
|
||||
|
||||
static void CLOOP_CARG clooptoBcdDispatcher(IDecFixed* self, const FB_DEC_FIXED* from, int* sign, unsigned char* bcd) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::toBcd(from, sign, bcd);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG clooptoStringDispatcher(IDecFixed* self, IStatus* status, const FB_DEC_FIXED* from, int scale, unsigned bufferLength, char* buffer) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::toString(&status2, from, scale, bufferLength, buffer);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopfromBcdDispatcher(IDecFixed* self, int sign, const unsigned char* bcd, FB_DEC_FIXED* to) throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::fromBcd(sign, bcd, to);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopfromStringDispatcher(IDecFixed* self, IStatus* status, const char* from, int scale, FB_DEC_FIXED* to) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::fromString(&status2, from, scale, to);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<IDecFixed> > >
|
||||
class IDecFixedImpl : public IDecFixedBaseImpl<Name, StatusType, Base>
|
||||
{
|
||||
protected:
|
||||
IDecFixedImpl(DoNotInherit = DoNotInherit())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~IDecFixedImpl()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void toBcd(const FB_DEC_FIXED* from, int* sign, unsigned char* bcd) = 0;
|
||||
virtual void toString(StatusType* status, const FB_DEC_FIXED* from, int scale, unsigned bufferLength, char* buffer) = 0;
|
||||
virtual void fromBcd(int sign, const unsigned char* bcd, FB_DEC_FIXED* to) = 0;
|
||||
virtual void fromString(StatusType* status, const char* from, int scale, FB_DEC_FIXED* to) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
@ -141,6 +141,11 @@
|
||||
builder->setType(status, index, SQL_DEC34); \
|
||||
builder->setLength(status, index, sizeof(FB_DEC34));
|
||||
|
||||
#define FB__META_FB_DEC_FIXED(scale) \
|
||||
builder->setType(status, index, SQL_DEC_FIXED); \
|
||||
builder->setLength(status, index, sizeof(FB_DEC_FIXED)); \
|
||||
builder->setScale(status, index, scale);
|
||||
|
||||
#define FB__META_FB_BLOB \
|
||||
builder->setType(status, index, SQL_BLOB); \
|
||||
builder->setLength(status, index, sizeof(ISC_QUAD));
|
||||
@ -195,6 +200,7 @@
|
||||
#define FB__TYPE_FB_DOUBLE double
|
||||
#define FB__TYPE_FB_DECFLOAT16 FB_DEC16
|
||||
#define FB__TYPE_FB_DECFLOAT34 FB_DEC34
|
||||
#define FB__TYPE_FB_DEC_FIXED FB_DEC_FIXED
|
||||
#define FB__TYPE_FB_BLOB ISC_QUAD
|
||||
#define FB__TYPE_FB_BOOLEAN ISC_UCHAR
|
||||
#define FB__TYPE_FB_DATE ::Firebird::FbDate
|
||||
|
@ -178,7 +178,12 @@ struct FB_DEC34_t {
|
||||
ISC_UINT64 fb_data[2];
|
||||
};
|
||||
|
||||
struct FB_DEC_FIXED_t {
|
||||
ISC_UINT64 fb_data[2];
|
||||
};
|
||||
|
||||
typedef struct FB_DEC16_t FB_DEC16;
|
||||
typedef struct FB_DEC34_t FB_DEC34;
|
||||
typedef struct FB_DEC_FIXED_t FB_DEC_FIXED;
|
||||
|
||||
#endif /* INCLUDE_TYPES_PUB_H */
|
||||
|
@ -317,6 +317,7 @@ IsqlGlobals::IsqlGlobals()
|
||||
|
||||
df16 = Firebird::UtilInterfacePtr()->getDecFloat16(&statusWrapper);
|
||||
df34 = Firebird::UtilInterfacePtr()->getDecFloat34(&statusWrapper);
|
||||
dfix = Firebird::UtilInterfacePtr()->getDecFixed(&statusWrapper);
|
||||
}
|
||||
|
||||
// I s q l G l o b a l s : : p r i n t f
|
||||
@ -1835,6 +1836,7 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
|
||||
case INTEGER:
|
||||
case BIGINT:
|
||||
case DOUBLE_PRECISION:
|
||||
case DEC_FIXED_TYPE:
|
||||
// Handle Integral subtypes NUMERIC and DECIMAL
|
||||
// We are ODS >= 10 and could be any Dialect
|
||||
|
||||
@ -1868,6 +1870,9 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
|
||||
case DOUBLE_PRECISION:
|
||||
isqlGlob.printf("NUMERIC(15, %d)", -fieldScale);
|
||||
break;
|
||||
case DEC_FIXED_TYPE:
|
||||
isqlGlob.printf("NUMERIC(34, %d)", -fieldScale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1981,6 +1986,50 @@ void ISQL_print_validation(FILE* fp,
|
||||
}
|
||||
|
||||
|
||||
static Firebird::string get_numeric_value(const char* fromStr)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g e t _ n u m e r i c _ v a l u e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Prepares data for converting into decfloat by interface function.
|
||||
*
|
||||
**************************************/
|
||||
Firebird::string val;
|
||||
for (const char* q = fromStr; *q; ++q)
|
||||
{
|
||||
switch (*q)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '.':
|
||||
case '+':
|
||||
case '-':
|
||||
case 'e':
|
||||
case 'E':
|
||||
val += *q;
|
||||
break;
|
||||
|
||||
default:
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static processing_state add_row(TEXT* tabname)
|
||||
{
|
||||
/**************************************
|
||||
@ -2237,6 +2286,7 @@ static processing_state add_row(TEXT* tabname)
|
||||
double* dvalue;
|
||||
FB_DEC16* d64value;
|
||||
FB_DEC34* d128value;
|
||||
FB_DEC_FIXED* dfixvalue;
|
||||
UCHAR* boolean;
|
||||
ISC_QUAD* blobid;
|
||||
vary* avary;
|
||||
@ -2325,6 +2375,23 @@ static processing_state add_row(TEXT* tabname)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_DEC_FIXED:
|
||||
scale = msg->getScale(fbStatus, i);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
return (SKIP);
|
||||
|
||||
dfixvalue = (FB_DEC_FIXED*) datap;
|
||||
|
||||
if (isqlGlob.dfix)
|
||||
isqlGlob.dfix->fromString(fbStatus, lastInputLine, scale, dfixvalue);
|
||||
|
||||
if ((!isqlGlob.dfix) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
|
||||
{
|
||||
STDERROUT("Input parsing problem");
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TYPE_DATE:
|
||||
if (3 != sscanf(lastInputLine, "%d/%d/%d", ×.tm_year,
|
||||
×.tm_mon, ×.tm_mday) ||
|
||||
@ -3016,6 +3083,7 @@ static processing_state bulk_insert_hack(const char* command)
|
||||
tm times;
|
||||
FB_DEC16* d64value;
|
||||
FB_DEC34* d128value;
|
||||
FB_DEC_FIXED* dfixvalue;
|
||||
// Initialize the time structure.
|
||||
memset(×, 0, sizeof(times));
|
||||
char msec_str[5] = "";
|
||||
@ -3078,7 +3146,7 @@ static processing_state bulk_insert_hack(const char* command)
|
||||
case SQL_DEC16:
|
||||
d64value = (FB_DEC16*) datap;
|
||||
if (isqlGlob.df16)
|
||||
isqlGlob.df16->fromString(fbStatus, lastInputLine, d64value);
|
||||
isqlGlob.df16->fromString(fbStatus, get_numeric_value(lastPos).c_str(), d64value);
|
||||
if ((!isqlGlob.df16) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
|
||||
{
|
||||
STDERROUT("Input parsing problem");
|
||||
@ -3089,7 +3157,7 @@ static processing_state bulk_insert_hack(const char* command)
|
||||
case SQL_DEC34:
|
||||
d128value = (FB_DEC34*) datap;
|
||||
if (isqlGlob.df34)
|
||||
isqlGlob.df34->fromString(fbStatus, lastInputLine, d128value);
|
||||
isqlGlob.df34->fromString(fbStatus, get_numeric_value(lastPos).c_str(), d128value);
|
||||
if ((!isqlGlob.df34) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
|
||||
{
|
||||
STDERROUT("Input parsing problem");
|
||||
@ -3097,6 +3165,23 @@ static processing_state bulk_insert_hack(const char* command)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_DEC_FIXED:
|
||||
scale = message->getScale(fbStatus, i);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
return (SKIP);
|
||||
|
||||
dfixvalue = (FB_DEC_FIXED*) datap;
|
||||
if (isqlGlob.dfix)
|
||||
{
|
||||
isqlGlob.dfix->fromString(fbStatus, get_numeric_value(lastPos).c_str(), scale, dfixvalue);
|
||||
}
|
||||
if ((!isqlGlob.dfix) || (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS))
|
||||
{
|
||||
STDERROUT("Input parsing problem");
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TYPE_DATE:
|
||||
if (3 != sscanf(lastPos, "%d-%d-%d", ×.tm_year,
|
||||
×.tm_mon, ×.tm_mday) ||
|
||||
@ -7272,6 +7357,25 @@ static unsigned print_item(TEXT** s, const IsqlVar* var, const unsigned length)
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_DEC_FIXED:
|
||||
{
|
||||
char decStr[Firebird::IDecFixed::STRING_SIZE];
|
||||
if (isqlGlob.dfix)
|
||||
{
|
||||
isqlGlob.dfix->toString(fbStatus, var->value.asDecFixed, dscale, sizeof(decStr), decStr);
|
||||
if (ISQL_errmsg(fbStatus))
|
||||
strcpy(decStr, convErr);
|
||||
}
|
||||
else
|
||||
strcpy(decStr, convErr);
|
||||
|
||||
if (setValues.List)
|
||||
isqlGlob.printf("%*.*s%s", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr, NEWLINE);
|
||||
else
|
||||
sprintf(p, "%*.*s ", sizeof(decStr) - 1, sizeof(decStr) - 1, decStr);
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_TEXT:
|
||||
str2 = var->value.asChar;
|
||||
// See if it is character set OCTETS
|
||||
@ -8054,6 +8158,9 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns
|
||||
case SQL_DEC34:
|
||||
disp_length = Firebird::IDecFloat34::STRING_SIZE - 1;
|
||||
break;
|
||||
case SQL_DEC_FIXED:
|
||||
disp_length = Firebird::IDecFixed::STRING_SIZE - 1;
|
||||
break;
|
||||
case SQL_TEXT:
|
||||
alignment = 1;
|
||||
data_length++;
|
||||
@ -8710,6 +8817,8 @@ static const char* sqltype_to_string(unsigned sqltype)
|
||||
return "DECFLOAT(16)";
|
||||
case SQL_DEC34:
|
||||
return "DECFLOAT(34)";
|
||||
case SQL_DEC_FIXED:
|
||||
return "DECIMAL FIXED";
|
||||
case SQL_D_FLOAT:
|
||||
return "D_FLOAT";
|
||||
case SQL_TIMESTAMP:
|
||||
|
@ -297,6 +297,7 @@ const int BIGINT = 16;
|
||||
const int BOOLEAN_TYPE = 23;
|
||||
const int DEC64_TYPE = 24;
|
||||
const int DEC128_TYPE = 25;
|
||||
const int DEC_FIXED_TYPE = 26;
|
||||
|
||||
static const sqltypes Column_types[] = {
|
||||
{SMALLINT, "SMALLINT"}, // keyword
|
||||
@ -316,6 +317,7 @@ static const sqltypes Column_types[] = {
|
||||
{BOOLEAN_TYPE, "BOOLEAN"}, // keyword
|
||||
{DEC64_TYPE, "DECFLOAT(16)"},
|
||||
{DEC128_TYPE, "DECFLOAT(34)"},
|
||||
{DEC_FIXED_TYPE, "<Should not be shown>"},
|
||||
{0, ""}
|
||||
};
|
||||
|
||||
@ -404,6 +406,7 @@ public:
|
||||
USHORT att_charset;
|
||||
Firebird::IDecFloat16* df16;
|
||||
Firebird::IDecFloat34* df34;
|
||||
Firebird::IDecFixed* dfix;
|
||||
void printf(const char* buffer, ...);
|
||||
void prints(const char* buffer);
|
||||
|
||||
@ -463,6 +466,7 @@ struct IsqlVar
|
||||
char* asChar;
|
||||
FB_DEC16* asDec16;
|
||||
FB_DEC34* asDec34;
|
||||
FB_DEC_FIXED* asDecFixed;
|
||||
void* setPtr;
|
||||
};
|
||||
TypeMix value;
|
||||
|
@ -109,6 +109,12 @@ namespace
|
||||
item.length = sizeof(Decimal128);
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
item.type = SQL_DEC_FIXED;
|
||||
item.scale = desc->dsc_scale;
|
||||
item.length = sizeof(DecimalFixed);
|
||||
break;
|
||||
|
||||
case dtype_sql_date:
|
||||
item.type = SQL_TYPE_DATE;
|
||||
item.length = sizeof(SLONG);
|
||||
|
@ -70,7 +70,7 @@ static const USHORT gds_cvt_blr_dtype[DTYPE_BLR_MAX + 1] =
|
||||
dtype_boolean, // blr_bool == 23
|
||||
dtype_dec64, /* blr_dec64 == 24 */
|
||||
dtype_dec128, /* blr_dec128 == 25 */
|
||||
0,
|
||||
dtype_dec_fixed, /* blr_dec_fixed == 26 */
|
||||
dtype_double, /* blr_double == 27 */
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
dtype_timestamp, /* blr_timestamp == 35 */
|
||||
@ -108,7 +108,8 @@ static const USHORT type_alignments[DTYPE_TYPE_MAX] =
|
||||
sizeof(ULONG), /* dtype_dbkey */
|
||||
sizeof(UCHAR), /* dtype_boolean */
|
||||
sizeof(Firebird::Decimal64),/* dtype_dec64 */
|
||||
sizeof(Firebird::Decimal64) /* dtype_dec128 */
|
||||
sizeof(Firebird::Decimal64),/* dtype_dec128 */
|
||||
sizeof(Firebird::Decimal64) /* dtype_dec_fixed */
|
||||
};
|
||||
|
||||
static const USHORT type_lengths[DTYPE_TYPE_MAX] =
|
||||
@ -133,10 +134,11 @@ static const USHORT type_lengths[DTYPE_TYPE_MAX] =
|
||||
sizeof(ISC_QUAD), /* dtype_blob */
|
||||
sizeof(ISC_QUAD), /* dtype_array */
|
||||
sizeof(SINT64), /* dtype_int64 */
|
||||
sizeof(RecordNumber::Packed), /*dtype_dbkey */
|
||||
sizeof(RecordNumber::Packed),/*dtype_dbkey */
|
||||
sizeof(UCHAR), /* dtype_boolean */
|
||||
sizeof(Firebird::Decimal64),/* dtype_dec64 */
|
||||
sizeof(Firebird::Decimal128)/* dtype_dec128 */
|
||||
sizeof(Firebird::Decimal128),/*dtype_dec128 */
|
||||
sizeof(Firebird::DecimalFixed) /* dtype_dec_fixed */
|
||||
};
|
||||
|
||||
|
||||
@ -167,7 +169,8 @@ static const USHORT type_significant_bits[DTYPE_TYPE_MAX] =
|
||||
0, // dtype_dbkey
|
||||
0, // dtype_boolean
|
||||
0, // dtype_dec64
|
||||
0 // dtype_dec128
|
||||
0, // dtype_dec128
|
||||
0 // dtype_dec_fixed
|
||||
};
|
||||
|
||||
#endif /* JRD_ALIGN_H */
|
||||
|
@ -69,6 +69,7 @@
|
||||
#define blr_bool (unsigned char)23
|
||||
#define blr_dec64 (unsigned char)24
|
||||
#define blr_dec128 (unsigned char)25
|
||||
#define blr_dec_fixed (unsigned char)26
|
||||
|
||||
// first sub parameter for blr_domain_name[2]
|
||||
#define blr_domain_type_of (unsigned char)0
|
||||
|
@ -292,6 +292,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
case dtype_dec128:
|
||||
return ((Decimal128*) p1)->compare(decSt, *(Decimal128*) p2);
|
||||
|
||||
case dtype_dec_fixed:
|
||||
return ((DecimalFixed*) p1)->compare(decSt, *(DecimalFixed*) p2);
|
||||
|
||||
case dtype_boolean:
|
||||
return *p1 == *p2 ? 0 : *p1 < *p2 ? -1 : 1;
|
||||
|
||||
@ -524,6 +527,19 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
|
||||
return temp1.compare(decSt, temp2);
|
||||
}
|
||||
|
||||
case dtype_dec_fixed:
|
||||
{
|
||||
SSHORT scale;
|
||||
if (arg2->dsc_dtype > dtype_varying)
|
||||
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
||||
else
|
||||
scale = arg1->dsc_scale;
|
||||
|
||||
const DecimalFixed temp1 = CVT_get_dec_fixed(arg1, scale, decSt, ERR_post);
|
||||
const DecimalFixed temp2 = CVT_get_dec_fixed(arg2, scale, decSt, ERR_post);
|
||||
return temp1.compare(decSt, temp2);
|
||||
}
|
||||
|
||||
case dtype_blob:
|
||||
return CVT2_blob_compare(arg1, arg2, decSt);
|
||||
|
||||
|
@ -1243,6 +1243,7 @@ USHORT DFW_assign_index_type(thread_db* tdbb, const Firebird::MetaName& name, SS
|
||||
return idx_boolean;
|
||||
case dtype_dec64:
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
return idx_decimal;
|
||||
default:
|
||||
return idx_numeric;
|
||||
|
@ -434,6 +434,10 @@ void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, Memor
|
||||
value->vlu_misc.vlu_dec128 = *((Decimal128*) from.dsc_address);
|
||||
return;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
value->vlu_misc.vlu_dec_fixed = *((DecimalFixed*) from.dsc_address);
|
||||
return;
|
||||
|
||||
case dtype_timestamp:
|
||||
case dtype_quad:
|
||||
value->vlu_misc.vlu_dbkey[0] = ((SLONG*) from.dsc_address)[0];
|
||||
|
@ -605,6 +605,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
|
||||
break;
|
||||
|
||||
case dtype_dec128:
|
||||
case dtype_dec_fixed:
|
||||
{
|
||||
const Decimal128 d = MOV_get_dec128(tdbb, input);
|
||||
if (parameter->prm_fun_mechanism == FUN_value)
|
||||
@ -818,6 +819,21 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra
|
||||
Arg::Str(function->getName().toString()));
|
||||
}
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
if (value->vlu_misc.vlu_dec_fixed.isInf())
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_expression_eval_err) <<
|
||||
Arg::Gds(isc_udf_fp_overflow) <<
|
||||
Arg::Str(function->getName().toString()));
|
||||
}
|
||||
else if (value->vlu_misc.vlu_dec_fixed.isNan())
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_expression_eval_err) <<
|
||||
Arg::Gds(isc_udf_fp_nan) <<
|
||||
Arg::Str(function->getName().toString()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
request->req_flags &= ~req_null;
|
||||
@ -1120,6 +1136,10 @@ static void invoke(thread_db* tdbb,
|
||||
value->vlu_misc.vlu_dec128 = CALL_UDF<Decimal128>(tdbb, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
value->vlu_misc.vlu_dec_fixed = CALL_UDF<DecimalFixed>(tdbb, function->fun_entrypoint, args);
|
||||
break;
|
||||
|
||||
case dtype_timestamp:
|
||||
default:
|
||||
udfError = UeUnsupDtype;
|
||||
|
@ -440,6 +440,18 @@ Decimal128 MOV_get_dec128(Jrd::thread_db* tdbb, const dsc* desc)
|
||||
}
|
||||
|
||||
|
||||
DecimalFixed MOV_get_dec_fixed(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* M O V _ g e t _ d e c _ f i x e d
|
||||
*
|
||||
**************************************/
|
||||
|
||||
return CVT_get_dec_fixed(desc, scale, tdbb->getAttachment()->att_dec_status, ERR_post);
|
||||
}
|
||||
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
|
||||
|
@ -52,6 +52,7 @@ Firebird::string MOV_make_string2(Jrd::thread_db* tdbb, const dsc* desc, USHORT
|
||||
void MOV_move(Jrd::thread_db*, /*const*/ dsc*, dsc*);
|
||||
Firebird::Decimal64 MOV_get_dec64(Jrd::thread_db*, const dsc*);
|
||||
Firebird::Decimal128 MOV_get_dec128(Jrd::thread_db*, const dsc*);
|
||||
Firebird::DecimalFixed MOV_get_dec_fixed(Jrd::thread_db*, const dsc*, SSHORT);
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
|
@ -396,7 +396,8 @@ static const UCHAR sort_dtypes[] =
|
||||
SKD_text, // dtype_dbkey - use text sort for backward compatibility
|
||||
SKD_bytes, // dtype_boolean
|
||||
SKD_dec64, // dtype_dec64
|
||||
SKD_dec128 // dtype_dec128
|
||||
SKD_dec128, // dtype_dec128
|
||||
SKD_dec_fixed // dtype_dec_fixed
|
||||
};
|
||||
|
||||
|
||||
|
@ -395,6 +395,12 @@ USHORT PAR_datatype(BlrReader& blrReader, dsc* desc)
|
||||
desc->dsc_length = sizeof(Decimal128);
|
||||
break;
|
||||
|
||||
case blr_dec_fixed:
|
||||
desc->dsc_dtype = dtype_dec_fixed;
|
||||
desc->dsc_length = sizeof(DecimalFixed);
|
||||
desc->dsc_scale = (int) blrReader.getByte();
|
||||
break;
|
||||
|
||||
case blr_blob2:
|
||||
desc->dsc_dtype = dtype_blob;
|
||||
desc->dsc_length = sizeof(ISC_QUAD);
|
||||
|
@ -143,6 +143,7 @@ const int SKD_sql_date = 14;
|
||||
const int SKD_int64 = 15;
|
||||
const int SKD_dec64 = 16;
|
||||
const int SKD_dec128 = 17;
|
||||
const int SKD_dec_fixed = 18;
|
||||
|
||||
// skd_flags
|
||||
const UCHAR SKD_ascending = 0; // default initializer
|
||||
|
@ -84,6 +84,7 @@ struct impure_value
|
||||
double vlu_double;
|
||||
Firebird::Decimal64 vlu_dec64;
|
||||
Firebird::Decimal128 vlu_dec128;
|
||||
Firebird::DecimalFixed vlu_dec_fixed;
|
||||
GDS_TIMESTAMP vlu_timestamp;
|
||||
GDS_TIME vlu_sql_time;
|
||||
GDS_DATE vlu_sql_date;
|
||||
@ -97,6 +98,7 @@ struct impure_value
|
||||
void make_int64(const SINT64 val, const signed char scale = 0);
|
||||
void make_double(const double val);
|
||||
void make_decimal128(const Firebird::Decimal128 val);
|
||||
void make_decimal_fixed(const Firebird::DecimalFixed val, const signed char scale);
|
||||
};
|
||||
|
||||
// Do not use these methods where dsc_sub_type is not explicitly set to zero.
|
||||
@ -140,6 +142,16 @@ inline void impure_value::make_decimal128(const Firebird::Decimal128 val)
|
||||
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_dec128);
|
||||
}
|
||||
|
||||
inline void impure_value::make_decimal_fixed(const Firebird::DecimalFixed val, const signed char scale)
|
||||
{
|
||||
this->vlu_misc.vlu_dec_fixed = val;
|
||||
this->vlu_desc.dsc_dtype = dtype_dec_fixed;
|
||||
this->vlu_desc.dsc_length = sizeof(Firebird::DecimalFixed);
|
||||
this->vlu_desc.dsc_scale = scale;
|
||||
this->vlu_desc.dsc_sub_type = 0;
|
||||
this->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(&this->vlu_misc.vlu_dec_fixed);
|
||||
}
|
||||
|
||||
struct impure_value_ex : public impure_value
|
||||
{
|
||||
SINT64 vlux_count;
|
||||
|
@ -17,6 +17,7 @@
|
||||
ISC_QUAD = array [1..2] of Integer;
|
||||
FB_DEC16 = array [1..1] of Int64;
|
||||
FB_DEC34 = array [1..2] of Int64;
|
||||
FB_DEC_FIXED = array [1..2] of Int64;
|
||||
|
||||
ntrace_relation_t = Integer;
|
||||
TraceCounts = Record
|
||||
|
@ -127,6 +127,12 @@ void BlrFromMessage::buildBlr(IMessageMetadata* metadata)
|
||||
dtype = dtype_dec128;
|
||||
break;
|
||||
|
||||
case SQL_DEC_FIXED:
|
||||
appendUChar(blr_dec_fixed);
|
||||
appendUChar(scale);
|
||||
dtype = dtype_dec_fixed;
|
||||
break;
|
||||
|
||||
case SQL_DOUBLE:
|
||||
appendUChar(blr_double);
|
||||
dtype = dtype_double;
|
||||
|
@ -300,6 +300,13 @@ static rem_fmt* parse_format(const UCHAR*& blr, size_t& blr_length)
|
||||
align = type_alignments[dtype_dec128];
|
||||
break;
|
||||
|
||||
case blr_dec_fixed:
|
||||
desc->dsc_dtype = dtype_dec_fixed;
|
||||
desc->dsc_length = sizeof(DecimalFixed);
|
||||
desc->dsc_scale = *blr++;
|
||||
align = type_alignments[dtype_dec_fixed];
|
||||
break;
|
||||
|
||||
// this case cannot occur as switch paramater is char and blr_blob
|
||||
// is 261. blob_ids are actually passed around as blr_quad.
|
||||
|
||||
|
@ -755,6 +755,9 @@ void TracePluginImpl::appendParams(ITraceParams* params)
|
||||
case dtype_dec128:
|
||||
paramtype = "decfloat(34)";
|
||||
break;
|
||||
case dtype_dec_fixed:
|
||||
paramtype = "decimal";
|
||||
break;
|
||||
|
||||
case dtype_sql_date:
|
||||
paramtype = "date";
|
||||
@ -877,6 +880,20 @@ void TracePluginImpl::appendParams(ITraceParams* params)
|
||||
((Decimal128*) parameters->dsc_address)->toString(paramvalue);
|
||||
break;
|
||||
|
||||
case dtype_dec_fixed:
|
||||
try
|
||||
{
|
||||
DecimalStatus decSt(DEC_Errors);
|
||||
((DecimalFixed*) parameters->dsc_address)->toString(decSt, parameters->dsc_scale, paramvalue);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
StaticStatusVector status;
|
||||
ex.stuffException(status);
|
||||
paramvalue.printf("Conversion error %d\n", status[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case dtype_sql_date:
|
||||
{
|
||||
struct tm times;
|
||||
|
@ -590,6 +590,7 @@ public:
|
||||
Firebird::IEventBlock* createEventBlock(Firebird::CheckStatusWrapper* status, const char** events);
|
||||
Firebird::IDecFloat16* getDecFloat16(Firebird::CheckStatusWrapper* status);
|
||||
Firebird::IDecFloat34* getDecFloat34(Firebird::CheckStatusWrapper* status);
|
||||
Firebird::IDecFixed* getDecFixed(Firebird::CheckStatusWrapper* status);
|
||||
};
|
||||
|
||||
} // namespace Why
|
||||
|
@ -1076,7 +1076,7 @@ public:
|
||||
{
|
||||
char temp[STRING_SIZE];
|
||||
decDoubleToString(reinterpret_cast<const decDouble*>(from), temp);
|
||||
int len = strlen(temp);
|
||||
unsigned int len = strlen(temp);
|
||||
if (len < bufSize)
|
||||
strncpy(buffer, temp, bufSize);
|
||||
else
|
||||
@ -1137,7 +1137,7 @@ public:
|
||||
{
|
||||
char temp[STRING_SIZE];
|
||||
decQuadToString(reinterpret_cast<const decQuad*>(from), temp);
|
||||
int len = strlen(temp);
|
||||
unsigned int len = strlen(temp);
|
||||
if (len < bufSize)
|
||||
strncpy(buffer, temp, bufSize);
|
||||
else
|
||||
@ -1179,6 +1179,56 @@ IDecFloat34* UtilInterface::getDecFloat34(CheckStatusWrapper* status)
|
||||
return &decFloat34;
|
||||
}
|
||||
|
||||
class DecFixed FB_FINAL : public AutoIface<IDecFixedImpl<DecFixed, CheckStatusWrapper> >
|
||||
{
|
||||
public:
|
||||
// IDecFixed implementation
|
||||
void toBcd(const FB_DEC_FIXED* from, int* sign, unsigned char* bcd)
|
||||
{
|
||||
int exp = 0;
|
||||
*sign = decQuadToBCD(reinterpret_cast<const decQuad*>(from), &exp, bcd);
|
||||
fb_assert(exp == 0);
|
||||
}
|
||||
|
||||
void toString(CheckStatusWrapper* status, const FB_DEC_FIXED* from, int scale, unsigned bufSize, char* buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
DecimalStatus decSt(DEC_Errors);
|
||||
reinterpret_cast<const DecimalFixed*>(from)->toString(decSt, scale, bufSize, buffer);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(status);
|
||||
}
|
||||
}
|
||||
|
||||
void fromBcd(int sign, const unsigned char* bcd, FB_DEC_FIXED* to)
|
||||
{
|
||||
decQuadFromBCD(reinterpret_cast<decQuad*>(to), 0, bcd, sign ? DECFLOAT_Sign : 0);
|
||||
}
|
||||
|
||||
void fromString(CheckStatusWrapper* status, const char* from, int scale, FB_DEC_FIXED* to)
|
||||
{
|
||||
try
|
||||
{
|
||||
DecimalStatus decSt(DEC_Errors);
|
||||
DecimalFixed* val = reinterpret_cast<DecimalFixed*>(to);
|
||||
val->set(from, scale, decSt);
|
||||
}
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
IDecFixed* UtilInterface::getDecFixed(CheckStatusWrapper* /*status*/)
|
||||
{
|
||||
static DecFixed decFixed;
|
||||
return &decFixed;
|
||||
}
|
||||
|
||||
unsigned UtilInterface::setOffsets(CheckStatusWrapper* status, IMessageMetadata* metadata,
|
||||
IOffsetsCallback* callback)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user