mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +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:
parent
4868b9c9ae
commit
c2692c6cee
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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},
|
||||
|
@ -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>();
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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"},
|
||||
|
@ -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 &&
|
||||
|
@ -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;
|
||||
|
||||
// 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
|
||||
d->dsc_dtype = toDsc.dsc_dtype;
|
||||
d->dsc_sub_type = toDsc.dsc_sub_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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
};
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user