mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 22: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
|
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.
|
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
|
Changing bind of any NUMERIC/DECIMAL does not affect appropriate underlying integer type. On contrary,
|
||||||
does not affect appropriate underlying integer type. On contrary, changing bind of integer datatype also affects
|
changing bind of integer datatype also affects appropriate NUMERICs/DECIMALs.
|
||||||
appropriate NUMERICs.
|
|
||||||
|
|
||||||
Special `TO` part format `LEGACY` is used when datatype, missing in previous FB version, should be represented in
|
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
|
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) |
|
| BOOLEAN | CHAR(5) |
|
||||||
| DECFLOAT | DOUBLE PRECISION |
|
| DECFLOAT | DOUBLE PRECISION |
|
||||||
| NUMERIC(38) | NUMERIC(18) |
|
| INT128 | BIGINT |
|
||||||
| TIME WITH TIME ZONE | TIME WITHOUT TIME ZONE |
|
| TIME WITH TIME ZONE | TIME WITHOUT TIME ZONE |
|
||||||
| TIMESTAMP WITH TIME ZONE | TIMESTAMP 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
|
Currently it works only for TIME/TIMESTAMP WITH TIME ZONE - they are coerced to EXTENDED TIME/TIMESTAMP WITH TIME ZONE
|
||||||
appropriately.
|
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
|
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
|
and `DataTypeCompatibility` parameter in firebird.conf & databases.conf. The later the rule is introduced
|
||||||
(.conf->DPB->SQL) the higher priotiy it has.
|
(.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
|
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.
|
formed SET BIND statements, i.e. with prefix SET BIND OF is omitted, separated by semicolons.
|
||||||
For example:
|
For example:
|
||||||
```c++
|
```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
|
`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
|
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:`
|
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
|
DECFLOAT, INT128 and TIME(STAMP) WITH TIME ZONE. When `DataTypeCompatibility=2.5` in addition to this list
|
||||||
list BOOLEAN will be described as legacy type as well.
|
BOOLEAN will be described as legacy type as well.
|
||||||
|
|
||||||
|
|
||||||
### SQL Samples:
|
### SQL Samples:
|
||||||
|
@ -103,7 +103,7 @@ static const TEXT* const DSC_dtype_names[] =
|
|||||||
"BOOLEAN",
|
"BOOLEAN",
|
||||||
"DECFLOAT(16)",
|
"DECFLOAT(16)",
|
||||||
"DECFLOAT(34)",
|
"DECFLOAT(34)",
|
||||||
"DECIMAL(34)",
|
"INT128",
|
||||||
"TIME WITH TIMEZONE",
|
"TIME WITH TIMEZONE",
|
||||||
"TIMESTAMP WITH TIMEZONE"
|
"TIMESTAMP WITH TIMEZONE"
|
||||||
};
|
};
|
||||||
@ -1653,7 +1653,7 @@ const char* dsc::typeToText() const
|
|||||||
case dtype_dec128:
|
case dtype_dec128:
|
||||||
return "decfloat(34)";
|
return "decfloat(34)";
|
||||||
case dtype_int128:
|
case dtype_int128:
|
||||||
return "decimal";
|
return "int128";
|
||||||
case dtype_sql_time_tz:
|
case dtype_sql_time_tz:
|
||||||
return "time with timezone";
|
return "time with timezone";
|
||||||
case dtype_timestamp_tz:
|
case dtype_timestamp_tz:
|
||||||
|
@ -255,6 +255,7 @@ static const TOK tokens[] =
|
|||||||
{TOK_INSERT, "INSERT", false},
|
{TOK_INSERT, "INSERT", false},
|
||||||
{TOK_INSERTING, "INSERTING", false},
|
{TOK_INSERTING, "INSERTING", false},
|
||||||
{TOK_INT, "INT", false},
|
{TOK_INT, "INT", false},
|
||||||
|
{TOK_INT128, "INT128", false},
|
||||||
{TOK_INTEGER, "INTEGER", false},
|
{TOK_INTEGER, "INTEGER", false},
|
||||||
{TOK_INTO, "INTO", false},
|
{TOK_INTO, "INTO", false},
|
||||||
{TOK_INVOKER, "INVOKER", true},
|
{TOK_INVOKER, "INVOKER", true},
|
||||||
|
@ -615,6 +615,7 @@ using namespace Firebird;
|
|||||||
%token <metaNamePtr> HEX_DECODE
|
%token <metaNamePtr> HEX_DECODE
|
||||||
%token <metaNamePtr> HEX_ENCODE
|
%token <metaNamePtr> HEX_ENCODE
|
||||||
%token <metaNamePtr> IDLE
|
%token <metaNamePtr> IDLE
|
||||||
|
%token <metaNamePtr> INT128
|
||||||
%token <metaNamePtr> INVOKER
|
%token <metaNamePtr> INVOKER
|
||||||
%token <metaNamePtr> IV
|
%token <metaNamePtr> IV
|
||||||
%token <metaNamePtr> LAST_DAY
|
%token <metaNamePtr> LAST_DAY
|
||||||
@ -4270,6 +4271,7 @@ keyword_or_column
|
|||||||
| VAR_POP
|
| VAR_POP
|
||||||
| BINARY // added in FB 4.0
|
| BINARY // added in FB 4.0
|
||||||
| DECFLOAT
|
| DECFLOAT
|
||||||
|
| INT128
|
||||||
| LATERAL
|
| LATERAL
|
||||||
| LOCAL
|
| LOCAL
|
||||||
| LOCALTIME
|
| LOCALTIME
|
||||||
@ -4725,6 +4727,13 @@ non_charset_simple_type
|
|||||||
$$->length = sizeof(SINT64);
|
$$->length = sizeof(SINT64);
|
||||||
$$->flags |= FLD_has_len;
|
$$->flags |= FLD_has_len;
|
||||||
}
|
}
|
||||||
|
| INT128
|
||||||
|
{
|
||||||
|
$$ = newNode<dsql_fld>();
|
||||||
|
$$->dtype = dtype_int128;
|
||||||
|
$$->length = sizeof(Int128);
|
||||||
|
$$->flags |= FLD_has_len;
|
||||||
|
}
|
||||||
| integer_keyword
|
| integer_keyword
|
||||||
{
|
{
|
||||||
$$ = newNode<dsql_fld>();
|
$$ = newNode<dsql_fld>();
|
||||||
|
@ -2992,7 +2992,8 @@ static void list_functions_legacy()
|
|||||||
if (isqlGlob.major_ods >= ODS_VERSION10 &&
|
if (isqlGlob.major_ods >= ODS_VERSION10 &&
|
||||||
(FNA.RDB$FIELD_TYPE == SMALLINT ||
|
(FNA.RDB$FIELD_TYPE == SMALLINT ||
|
||||||
FNA.RDB$FIELD_TYPE == INTEGER ||
|
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 ODS >= 10 and could be any Dialect
|
||||||
// We are Dialect >=3 since FIELD_PRECISION is non-NULL
|
// 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:
|
case SQL_DEC34:
|
||||||
return "DECFLOAT(34)";
|
return "DECFLOAT(34)";
|
||||||
case SQL_INT128:
|
case SQL_INT128:
|
||||||
return "NUMERIC(38)";
|
return "INT128";
|
||||||
case SQL_D_FLOAT:
|
case SQL_D_FLOAT:
|
||||||
return "D_FLOAT";
|
return "D_FLOAT";
|
||||||
case SQL_TIMESTAMP:
|
case SQL_TIMESTAMP:
|
||||||
|
@ -325,7 +325,7 @@ static const sqltypes Column_types[] = {
|
|||||||
{BOOLEAN_TYPE, "BOOLEAN"}, // keyword
|
{BOOLEAN_TYPE, "BOOLEAN"}, // keyword
|
||||||
{DEC64_TYPE, "DECFLOAT(16)"},
|
{DEC64_TYPE, "DECFLOAT(16)"},
|
||||||
{DEC128_TYPE, "DECFLOAT(34)"},
|
{DEC128_TYPE, "DECFLOAT(34)"},
|
||||||
{blr_int128, "INT64"},
|
{blr_int128, "INT128"},
|
||||||
{blr_sql_time_tz, "TIME WITH TIME ZONE"}, // keyword
|
{blr_sql_time_tz, "TIME WITH TIME ZONE"}, // keyword
|
||||||
{blr_timestamp_tz, "TIMESTAMP WITH TIME ZONE"}, // keyword
|
{blr_timestamp_tz, "TIMESTAMP WITH TIME ZONE"}, // keyword
|
||||||
{blr_ex_time_tz, "TIME WITH TIME ZONE"},
|
{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) &&
|
if ( (isqlGlob.major_ods >= ODS_VERSION10) &&
|
||||||
((FNA.RDB$FIELD_TYPE == SMALLINT) ||
|
((FNA.RDB$FIELD_TYPE == SMALLINT) ||
|
||||||
(FNA.RDB$FIELD_TYPE == INTEGER) ||
|
(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
|
// We are Dialect >=3 since FIELD_PRECISION is non-NULL
|
||||||
if (!FNA.RDB$FIELD_PRECISION.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;
|
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
|
bool CoercionRule::coerce(dsc* d) const
|
||||||
{
|
{
|
||||||
// check does descriptor match FROM clause
|
// check does descriptor match FROM clause
|
||||||
@ -263,42 +293,55 @@ bool CoercionRule::coerce(dsc* d) const
|
|||||||
|
|
||||||
// final pass - order is important
|
// 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
|
// scale
|
||||||
if (toMask & FLD_has_scale)
|
if (toMask & FLD_has_scale)
|
||||||
d->dsc_scale = toDsc.dsc_scale;
|
d->dsc_scale = toDsc.dsc_scale;
|
||||||
else if (!(DTYPE_IS_EXACT(d->dsc_dtype) && DTYPE_IS_EXACT(toDsc.dsc_dtype)))
|
else if (!(DTYPE_IS_EXACT(d->dsc_dtype) && DTYPE_IS_EXACT(toDsc.dsc_dtype)))
|
||||||
d->dsc_scale = 0;
|
d->dsc_scale = 0;
|
||||||
|
|
||||||
// type
|
// subtype
|
||||||
d->dsc_dtype = toDsc.dsc_dtype;
|
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;
|
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
|
// charset
|
||||||
if (toMask & FLD_has_chset)
|
if (toMask & FLD_has_chset)
|
||||||
d->setTextType(toDsc.getTextType());
|
d->setTextType(toDsc.getTextType());
|
||||||
|
|
||||||
// subtype
|
// subtype - special processing for BLOBs
|
||||||
if (toMask & FLD_has_sub)
|
if (toMask & FLD_has_sub)
|
||||||
d->setBlobSubType(toDsc.getBlobSubType());
|
d->setBlobSubType(toDsc.getBlobSubType());
|
||||||
|
|
||||||
// varchar
|
|
||||||
if (d->dsc_dtype == dtype_varying)
|
|
||||||
d->dsc_length += sizeof(USHORT);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ static const TEXT dtypes[DTYPE_TYPE_MAX][36] =
|
|||||||
"BOOLEAN",
|
"BOOLEAN",
|
||||||
"DECFLOAT(16)",
|
"DECFLOAT(16)",
|
||||||
"DECFLOAT(34)",
|
"DECFLOAT(34)",
|
||||||
"DECIMAL(34)",
|
"INT128",
|
||||||
"TIME WITH TIME ZONE",
|
"TIME WITH TIME ZONE",
|
||||||
"TIMESTAMP WITH TIME ZONE"
|
"TIMESTAMP WITH TIME ZONE"
|
||||||
};
|
};
|
||||||
|
@ -747,6 +747,12 @@ void TracePluginImpl::appendParams(ITraceParams* params)
|
|||||||
else
|
else
|
||||||
paramtype = "bigint";
|
paramtype = "bigint";
|
||||||
break;
|
break;
|
||||||
|
case dtype_int128:
|
||||||
|
if (parameters->dsc_scale)
|
||||||
|
paramtype.printf("int128(*, %d)", parameters->dsc_scale);
|
||||||
|
else
|
||||||
|
paramtype = "int128";
|
||||||
|
break;
|
||||||
|
|
||||||
case dtype_real:
|
case dtype_real:
|
||||||
paramtype = "float";
|
paramtype = "float";
|
||||||
@ -764,9 +770,6 @@ void TracePluginImpl::appendParams(ITraceParams* params)
|
|||||||
case dtype_dec128:
|
case dtype_dec128:
|
||||||
paramtype = "decfloat(34)";
|
paramtype = "decfloat(34)";
|
||||||
break;
|
break;
|
||||||
case dtype_int128:
|
|
||||||
paramtype = "decimal";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dtype_sql_date:
|
case dtype_sql_date:
|
||||||
paramtype = "date";
|
paramtype = "date";
|
||||||
|
Loading…
Reference in New Issue
Block a user