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

Fixed use of very long DECFLOAT literals

This commit is contained in:
AlexPeshkoff 2017-05-03 19:58:56 +03:00
parent 529ef3d4f0
commit 5302ee1fdd
6 changed files with 37 additions and 16 deletions

View File

@ -179,3 +179,7 @@ DECFLOAT (FB 4.0)
but poor precision) or scaled integers (good support for further processing and but poor precision) or scaled integers (good support for further processing and
required precision but range of values is very limited). When using is a tool like required precision but range of values is very limited). When using is a tool like
generic purporse GUI client choice of CHAR binding is OK in most cases. generic purporse GUI client choice of CHAR binding is OK in most cases.
4. Although length of DECFLOAT(34) literal can exceed 6000 bytes (0.000<6000 zeros>00123)
implementation limit exists - length of such literal should not exceed 1024 bytes.

View File

@ -2103,8 +2103,13 @@ void CVT_make_null_string(const dsc* desc,
if (*address != temp->vary_string) if (*address != temp->vary_string)
{ {
length -= sizeof(USHORT); // Take into an account VaryStr specifics
if (len > length) if (len > length)
len = length; {
err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) <<
Arg::Gds(isc_imp_exc) <<
Arg::Gds(isc_trunc_limits) << Arg::Num(length) << Arg::Num(len));
}
memcpy(temp->vary_string, *address, len); memcpy(temp->vary_string, *address, len);
temp->vary_length = len; temp->vary_length = len;
} }
@ -2534,7 +2539,7 @@ Decimal64 CVT_get_dec64(const dsc* desc, DecimalStatus decSt, ErrorFunction err)
* Convert something arbitrary to a DecFloat(16) / (64 bit). * Convert something arbitrary to a DecFloat(16) / (64 bit).
* *
**************************************/ **************************************/
VaryStr<50> buffer; // long enough to represent largest decimal float in ASCII VaryStr<512> buffer; // long enough to represent largest decimal float in ASCII
Decimal64 d64; Decimal64 d64;
// adjust exact numeric values to same scaling // adjust exact numeric values to same scaling
@ -2618,7 +2623,7 @@ Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction er
* Convert something arbitrary to a DecFloat(34) / (128 bit). * Convert something arbitrary to a DecFloat(34) / (128 bit).
* *
**************************************/ **************************************/
VaryStr<50> buffer; // long enough to represent largest decimal float in ASCII VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII
Decimal128 d128; Decimal128 d128;
// adjust exact numeric values to same scaling // adjust exact numeric values to same scaling

View File

@ -6797,7 +6797,7 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
l = csb->csb_blr_reader.getWord(); l = csb->csb_blr_reader.getWord();
q = csb->csb_blr_reader.getPos(); q = csb->csb_blr_reader.getPos();
dtype = CVT_get_numeric(q, l, &scale, p); // use decfloat to pass literal ??? dtype = CVT_get_numeric(q, l, &scale, p);
node->litDesc.dsc_dtype = dtype; node->litDesc.dsc_dtype = dtype;
switch (dtype) switch (dtype)
@ -6881,8 +6881,9 @@ void LiteralNode::genConstant(DsqlCompilerScratch* dsqlScratch, const dsc* desc,
// which is transmitted to the engine as a string. // which is transmitted to the engine as a string.
GEN_descriptor(dsqlScratch, desc, true); GEN_descriptor(dsqlScratch, desc, true);
// Length of string literal, cast because it could be > 127 bytes.
const USHORT l = (USHORT)(UCHAR) desc->dsc_scale; // Length of string literal
const USHORT l = desc->dsc_length;
if (negateValue) if (negateValue)
{ {

View File

@ -941,7 +941,7 @@ int Parser::yylexAux()
FB_UINT64 number = 0; FB_UINT64 number = 0;
FB_UINT64 expVal = 0; FB_UINT64 expVal = 0;
FB_UINT64 limit_by_10 = MAX_SINT64 / 10; FB_UINT64 limit_by_10 = MAX_SINT64 / 10;
SCHAR scale = 0; int scale = 0;
for (--lex.ptr; lex.ptr < lex.end; lex.ptr++) for (--lex.ptr; lex.ptr < lex.end; lex.ptr++)
{ {
@ -1030,6 +1030,9 @@ int Parser::yylexAux()
{ {
fb_assert(have_digit); fb_assert(have_digit);
if (scale < MIN_SCHAR || scale > MAX_SCHAR)
have_overflow = true;
if (have_exp_digit || have_overflow) if (have_exp_digit || have_overflow)
{ {
yylval.stringPtr = newString( yylval.stringPtr = newString(

View File

@ -122,16 +122,21 @@ ValueExprNode* MAKE_constant(const char* str, dsql_constant_type numeric_flag)
// This is a numeric value which is transported to the engine as // This is a numeric value which is transported to the engine as
// a string. The engine will convert it. Use dtype_double so that // a string. The engine will convert it. Use dtype_double so that
// the engine can distinguish it from an actual string. // the engine can distinguish it from an actual string.
// Note: Due to the size of dsc_scale we are limited to numeric // Note: Due to the size of dsc_sub_type we are limited to numeric
// constants of less than 256 bytes. // constants of less than 64K - 1 bytes.
{
literal->litDesc.dsc_dtype = numeric_flag == CONSTANT_DOUBLE ? dtype_double : dtype_dec128; literal->litDesc.dsc_dtype = numeric_flag == CONSTANT_DOUBLE ? dtype_double : dtype_dec128;
// Scale has no use for double literal->litDesc.dsc_scale = 0;
literal->litDesc.dsc_scale = static_cast<signed char>(strlen(str)); size_t l = strlen(str);
literal->litDesc.dsc_sub_type = 0; if (l > MAX_USHORT)
literal->litDesc.dsc_length = sizeof(double); {
ERRD_post(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_random) << "Numeric literal too long");
}
literal->litDesc.dsc_length = static_cast<SSHORT>(l);
literal->litDesc.dsc_address = (UCHAR*) str; literal->litDesc.dsc_address = (UCHAR*) str;
literal->litDesc.dsc_ttype() = ttype_ascii; literal->litDesc.dsc_ttype() = ttype_ascii;
}
break; break;
case CONSTANT_DATE: case CONSTANT_DATE:

View File

@ -258,6 +258,9 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v
if (!digit_seen) if (!digit_seen)
CVT_conversion_error(&desc, ERR_post); CVT_conversion_error(&desc, ERR_post);
if ((local_scale > MAX_SCHAR) || (local_scale < MIN_SCHAR))
over = true;
if ((!over) && ((p < end) || // there is an exponent if ((!over) && ((p < end) || // there is an exponent
((value < 0) && (sign != -1)))) // MAX_SINT64+1 wrapped around ((value < 0) && (sign != -1)))) // MAX_SINT64+1 wrapped around
{ {