diff --git a/doc/sql.extensions/README.data_types b/doc/sql.extensions/README.data_types index b63c613534..e0ff71d56c 100644 --- a/doc/sql.extensions/README.data_types +++ b/doc/sql.extensions/README.data_types @@ -179,3 +179,7 @@ DECFLOAT (FB 4.0) 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 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. + diff --git a/src/common/cvt.cpp b/src/common/cvt.cpp index ca174e6060..93fa695120 100644 --- a/src/common/cvt.cpp +++ b/src/common/cvt.cpp @@ -2103,8 +2103,13 @@ void CVT_make_null_string(const dsc* desc, if (*address != temp->vary_string) { + length -= sizeof(USHORT); // Take into an account VaryStr specifics 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); 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). * **************************************/ - 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; // 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). * **************************************/ - VaryStr<50> buffer; // long enough to represent largest decimal float in ASCII + VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII Decimal128 d128; // adjust exact numeric values to same scaling diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 12cc7e884e..eafe542230 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -6797,7 +6797,7 @@ DmlNode* LiteralNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* l = csb->csb_blr_reader.getWord(); 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; switch (dtype) @@ -6881,8 +6881,9 @@ void LiteralNode::genConstant(DsqlCompilerScratch* dsqlScratch, const dsc* desc, // which is transmitted to the engine as a string. 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) { diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index 4c5de71a9b..769858e0b0 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -941,7 +941,7 @@ int Parser::yylexAux() FB_UINT64 number = 0; FB_UINT64 expVal = 0; FB_UINT64 limit_by_10 = MAX_SINT64 / 10; - SCHAR scale = 0; + int scale = 0; for (--lex.ptr; lex.ptr < lex.end; lex.ptr++) { @@ -1030,6 +1030,9 @@ int Parser::yylexAux() { fb_assert(have_digit); + if (scale < MIN_SCHAR || scale > MAX_SCHAR) + have_overflow = true; + if (have_exp_digit || have_overflow) { yylval.stringPtr = newString( diff --git a/src/dsql/make.cpp b/src/dsql/make.cpp index 8ddae36ba1..f5a3ab23a6 100644 --- a/src/dsql/make.cpp +++ b/src/dsql/make.cpp @@ -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 // a string. The engine will convert it. Use dtype_double so that // the engine can distinguish it from an actual string. - // Note: Due to the size of dsc_scale we are limited to numeric - // constants of less than 256 bytes. + // Note: Due to the size of dsc_sub_type we are limited to numeric + // constants of less than 64K - 1 bytes. - literal->litDesc.dsc_dtype = numeric_flag == CONSTANT_DOUBLE ? dtype_double : dtype_dec128; - // Scale has no use for double - literal->litDesc.dsc_scale = static_cast(strlen(str)); - literal->litDesc.dsc_sub_type = 0; - literal->litDesc.dsc_length = sizeof(double); - literal->litDesc.dsc_address = (UCHAR*) str; - literal->litDesc.dsc_ttype() = ttype_ascii; + { + literal->litDesc.dsc_dtype = numeric_flag == CONSTANT_DOUBLE ? dtype_double : dtype_dec128; + literal->litDesc.dsc_scale = 0; + size_t l = strlen(str); + if (l > MAX_USHORT) + { + ERRD_post(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_random) << "Numeric literal too long"); + } + literal->litDesc.dsc_length = static_cast(l); + literal->litDesc.dsc_address = (UCHAR*) str; + literal->litDesc.dsc_ttype() = ttype_ascii; + } break; case CONSTANT_DATE: diff --git a/src/jrd/cvt.cpp b/src/jrd/cvt.cpp index e37cfdd3a6..5fc470f5c2 100644 --- a/src/jrd/cvt.cpp +++ b/src/jrd/cvt.cpp @@ -258,6 +258,9 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v if (!digit_seen) 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 ((value < 0) && (sign != -1)))) // MAX_SINT64+1 wrapped around {