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

Added explicit datatype INT128 (base type for high precision numeric/decimal), enhanced processing of SET BIND for exact digital datatypes

This commit is contained in:
AlexPeshkoff 2020-06-24 12:57:18 +03:00
parent 4868b9c9ae
commit c2692c6cee
11 changed files with 105 additions and 48 deletions

View File

@ -25,9 +25,8 @@ stands for all types (namely TIME & TIMESTAMP) WITH TIME ZONE.
When incomplete type definiton is used in right side of the statement (TO part) firebird engine will define missing
details about that type automatically based on source column.
From this statement POV there is no difference between NUMERIC and DECIMAL datatypes. Changing bind of any NUMERIC
does not affect appropriate underlying integer type. On contrary, changing bind of integer datatype also affects
appropriate NUMERICs.
Changing bind of any NUMERIC/DECIMAL does not affect appropriate underlying integer type. On contrary,
changing bind of integer datatype also affects appropriate NUMERICs/DECIMALs.
Special `TO` part format `LEGACY` is used when datatype, missing in previous FB version, should be represented in
a way, understandable by old client software (may be with some data losses). The following coercions are done for
@ -37,11 +36,11 @@ legacy datatypes:
|--------------------------|-----------------------------|
| BOOLEAN | CHAR(5) |
| DECFLOAT | DOUBLE PRECISION |
| NUMERIC(38) | NUMERIC(18) |
| INT128 | BIGINT |
| TIME WITH TIME ZONE | TIME WITHOUT TIME ZONE |
| TIMESTAMP WITH TIME ZONE | TIMESTAMP WITHOUT TIME ZONE |
Using `EXTENDED` in the `TO` part directs firebird engine to use extended form of `FROM` datatype.
Using `EXTENDED` in the `TO` part directs firebird engine to coerce to extended form of `FROM` datatype.
Currently it works only for TIME/TIMESTAMP WITH TIME ZONE - they are coerced to EXTENDED TIME/TIMESTAMP WITH TIME ZONE
appropriately.
@ -50,20 +49,20 @@ Setting `NATIVE` means `type` will be used as if there were no previous rules fo
Except SQL-statement there are two more ways to specify data coercion - tag `isc_dpb_set_bind` in DPB
and `DataTypeCompatibility` parameter in firebird.conf & databases.conf. The later the rule is introduced
(.conf->DPB->SQL) the higher priotiy it has.
I.e. one can override .conf in any other way any DPB from SQL statement.
I.e. one can override .conf in any other way and DPB from SQL statement.
Value of clumplet with `isc_dpb_set_bind` tag in DPB should be specified as a set of partially
formed SET BIND statements, i.e. with prefix SET BIND OF is omitted, separated by semicolons.
For example:
```c++
dpb->insertString(&status, isc_dpb_set_bind, "decfloat to char; numeric(38) to char");
dpb->insertString(&status, isc_dpb_set_bind, "decfloat to char; int128 to char");
```
`DataTypeCompatibility` is minor firebird version for which we want to provide some compatibility
regarding data types. That compatibility may be not absolute - for example SET BIND can't care about type
of particular SQL functions. The following types will be described in legacy form when `DataTypeCompatibility=3.0:`
DECFLOAT, NUMERIC(38) and TIME(STAMP) WITH TIME ZONE. When `DataTypeCompatibility=2.5` in addition to this
list BOOLEAN will be described as legacy type as well.
of particular SQL functions. The following types will be described in legacy form when `DataTypeCompatibility=3.0`:
DECFLOAT, INT128 and TIME(STAMP) WITH TIME ZONE. When `DataTypeCompatibility=2.5` in addition to this list
BOOLEAN will be described as legacy type as well.
### SQL Samples:

View File

@ -103,7 +103,7 @@ static const TEXT* const DSC_dtype_names[] =
"BOOLEAN",
"DECFLOAT(16)",
"DECFLOAT(34)",
"DECIMAL(34)",
"INT128",
"TIME WITH TIMEZONE",
"TIMESTAMP WITH TIMEZONE"
};
@ -1653,7 +1653,7 @@ const char* dsc::typeToText() const
case dtype_dec128:
return "decfloat(34)";
case dtype_int128:
return "decimal";
return "int128";
case dtype_sql_time_tz:
return "time with timezone";
case dtype_timestamp_tz:

View File

@ -255,6 +255,7 @@ static const TOK tokens[] =
{TOK_INSERT, "INSERT", false},
{TOK_INSERTING, "INSERTING", false},
{TOK_INT, "INT", false},
{TOK_INT128, "INT128", false},
{TOK_INTEGER, "INTEGER", false},
{TOK_INTO, "INTO", false},
{TOK_INVOKER, "INVOKER", true},

View File

@ -615,6 +615,7 @@ using namespace Firebird;
%token <metaNamePtr> HEX_DECODE
%token <metaNamePtr> HEX_ENCODE
%token <metaNamePtr> IDLE
%token <metaNamePtr> INT128
%token <metaNamePtr> INVOKER
%token <metaNamePtr> IV
%token <metaNamePtr> LAST_DAY
@ -4270,6 +4271,7 @@ keyword_or_column
| VAR_POP
| BINARY // added in FB 4.0
| DECFLOAT
| INT128
| LATERAL
| LOCAL
| LOCALTIME
@ -4725,6 +4727,13 @@ non_charset_simple_type
$$->length = sizeof(SINT64);
$$->flags |= FLD_has_len;
}
| INT128
{
$$ = newNode<dsql_fld>();
$$->dtype = dtype_int128;
$$->length = sizeof(Int128);
$$->flags |= FLD_has_len;
}
| integer_keyword
{
$$ = newNode<dsql_fld>();

View File

@ -2992,7 +2992,8 @@ static void list_functions_legacy()
if (isqlGlob.major_ods >= ODS_VERSION10 &&
(FNA.RDB$FIELD_TYPE == SMALLINT ||
FNA.RDB$FIELD_TYPE == INTEGER ||
FNA.RDB$FIELD_TYPE == BIGINT))
FNA.RDB$FIELD_TYPE == BIGINT ||
FNA.RDB$FIELD_TYPE == blr_int128))
{
// We are ODS >= 10 and could be any Dialect
// We are Dialect >=3 since FIELD_PRECISION is non-NULL

View File

@ -9092,7 +9092,7 @@ static const char* sqltype_to_string(unsigned sqltype)
case SQL_DEC34:
return "DECFLOAT(34)";
case SQL_INT128:
return "NUMERIC(38)";
return "INT128";
case SQL_D_FLOAT:
return "D_FLOAT";
case SQL_TIMESTAMP:

View File

@ -325,7 +325,7 @@ static const sqltypes Column_types[] = {
{BOOLEAN_TYPE, "BOOLEAN"}, // keyword
{DEC64_TYPE, "DECFLOAT(16)"},
{DEC128_TYPE, "DECFLOAT(34)"},
{blr_int128, "INT64"},
{blr_int128, "INT128"},
{blr_sql_time_tz, "TIME WITH TIME ZONE"}, // keyword
{blr_timestamp_tz, "TIMESTAMP WITH TIME ZONE"}, // keyword
{blr_ex_time_tz, "TIME WITH TIME ZONE"},

View File

@ -4511,7 +4511,8 @@ static processing_state show_func_legacy(const SCHAR* object)
if ( (isqlGlob.major_ods >= ODS_VERSION10) &&
((FNA.RDB$FIELD_TYPE == SMALLINT) ||
(FNA.RDB$FIELD_TYPE == INTEGER) ||
(FNA.RDB$FIELD_TYPE == BIGINT)) )
(FNA.RDB$FIELD_TYPE == BIGINT) ||
(FNA.RDB$FIELD_TYPE == blr_int128)) )
{
// We are Dialect >=3 since FIELD_PRECISION is non-NULL
if (!FNA.RDB$FIELD_PRECISION.NULL &&

View File

@ -182,16 +182,46 @@ bool CoercionRule::match(const dsc* d) const
}
}
// ignore minor decimal/numeric difference
if (fromDsc.isExact() && (fromMask & FLD_has_sub) &&
(fromDsc.dsc_dtype == d->dsc_dtype) && (d->dsc_sub_type != dsc_num_type_none))
{
return true;
}
return false;
}
static const USHORT COMPATIBLE_TEXT = 1;
static const USHORT COMPATIBLE_INT = 2;
static const USHORT subTypeCompatibility[DTYPE_TYPE_MAX] =
{
0, // dtype_unknown
COMPATIBLE_TEXT, // dtype_text
0, // dtype_cstring
COMPATIBLE_TEXT, // dtype_varying
0,
0,
0, // dtype_packed
0, // dtype_byte
COMPATIBLE_INT, // dtype_short -32768
COMPATIBLE_INT, // dtype_long -2147483648
0, // dtype_quad -9223372036854775808
0, // dtype_real -1.23456789e+12
0, // dtype_double -1.2345678901234567e+123
0, // dtype_d_float (believed to have this range) -1.2345678901234567e+123
0, // dtype_sql_date YYYY-MM-DD
0, // dtype_sql_time HH:MM:SS.MMMM
0, // dtype_timestamp YYYY-MM-DD HH:MM:SS.MMMM
0, // dtype_blob FFFF:FFFF
0, // dtype_array FFFF:FFFF
COMPATIBLE_INT, // dtype_int64 -9223372036854775808
0, // dtype_dbkey
0, // dtype_boolean
0, // dtype_dec64 1 + 1 + 1 + 1 + 16(34) + 3(4)
0, // dtype_dec128 +- . e +- coeff + exp
COMPATIBLE_INT, // dtype_int128
0, // dtype_sql_time_tz HH:MM:SS.MMMM +NN:NN
0, // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN
0, // dtype_ex_time_tz HH:MM:SS.MMMM +NN:NN
0, // dtype_ex_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN
};
bool CoercionRule::coerce(dsc* d) const
{
// check does descriptor match FROM clause
@ -263,42 +293,55 @@ bool CoercionRule::coerce(dsc* d) const
// final pass - order is important
// length
if (toMask & FLD_has_len)
d->dsc_length = toDsc.dsc_length;
else
{
if (!type_lengths[toDsc.dsc_dtype])
{
fb_assert(toDsc.isText());
d->dsc_length = d->getStringLength();
}
else
d->dsc_length = type_lengths[toDsc.dsc_dtype];
}
// scale
if (toMask & FLD_has_scale)
d->dsc_scale = toDsc.dsc_scale;
else if (!(DTYPE_IS_EXACT(d->dsc_dtype) && DTYPE_IS_EXACT(toDsc.dsc_dtype)))
d->dsc_scale = 0;
// type
d->dsc_dtype = toDsc.dsc_dtype;
// subtype
if (toMask & FLD_has_sub ||
d->dsc_dtype >= DTYPE_TYPE_MAX || toDsc.dsc_dtype >= DTYPE_TYPE_MAX ||
subTypeCompatibility[d->dsc_dtype] == 0 ||
subTypeCompatibility[d->dsc_dtype] != subTypeCompatibility[toDsc.dsc_dtype])
{
d->dsc_sub_type = toDsc.dsc_sub_type;
}
// type
if (toMask & FLD_has_len ||
subTypeCompatibility[d->dsc_dtype] != COMPATIBLE_INT ||
subTypeCompatibility[toDsc.dsc_dtype] != COMPATIBLE_INT)
{
d->dsc_dtype = toDsc.dsc_dtype;
}
// length
if (toMask & FLD_has_len)
d->dsc_length = toDsc.dsc_length;
else
{
if (!type_lengths[d->dsc_dtype])
{
fb_assert(d->isText());
d->dsc_length = d->getStringLength();
}
else
d->dsc_length = type_lengths[d->dsc_dtype];
}
// varchar length
if (d->dsc_dtype == dtype_varying)
d->dsc_length += sizeof(USHORT);
// charset
if (toMask & FLD_has_chset)
d->setTextType(toDsc.getTextType());
// subtype
// subtype - special processing for BLOBs
if (toMask & FLD_has_sub)
d->setBlobSubType(toDsc.getBlobSubType());
// varchar
if (d->dsc_dtype == dtype_varying)
d->dsc_length += sizeof(USHORT);
return true;
}

View File

@ -145,7 +145,7 @@ static const TEXT dtypes[DTYPE_TYPE_MAX][36] =
"BOOLEAN",
"DECFLOAT(16)",
"DECFLOAT(34)",
"DECIMAL(34)",
"INT128",
"TIME WITH TIME ZONE",
"TIMESTAMP WITH TIME ZONE"
};

View File

@ -747,6 +747,12 @@ void TracePluginImpl::appendParams(ITraceParams* params)
else
paramtype = "bigint";
break;
case dtype_int128:
if (parameters->dsc_scale)
paramtype.printf("int128(*, %d)", parameters->dsc_scale);
else
paramtype = "int128";
break;
case dtype_real:
paramtype = "float";
@ -764,9 +770,6 @@ void TracePluginImpl::appendParams(ITraceParams* params)
case dtype_dec128:
paramtype = "decfloat(34)";
break;
case dtype_int128:
paramtype = "decimal";
break;
case dtype_sql_date:
paramtype = "date";