diff --git a/doc/sql.extensions/README.set_bind.md b/doc/sql.extensions/README.set_bind.md index b722386caa..585e669128 100644 --- a/doc/sql.extensions/README.set_bind.md +++ b/doc/sql.extensions/README.set_bind.md @@ -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: diff --git a/src/common/dsc.cpp b/src/common/dsc.cpp index b34cf65abb..d2b10f46c6 100644 --- a/src/common/dsc.cpp +++ b/src/common/dsc.cpp @@ -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: diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp index d33419a0e9..70167769a8 100644 --- a/src/common/keywords.cpp +++ b/src/common/keywords.cpp @@ -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}, diff --git a/src/dsql/parse.y b/src/dsql/parse.y index b0c645bd9b..ad4f49bae6 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -615,6 +615,7 @@ using namespace Firebird; %token HEX_DECODE %token HEX_ENCODE %token IDLE +%token INT128 %token INVOKER %token IV %token 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(); + $$->dtype = dtype_int128; + $$->length = sizeof(Int128); + $$->flags |= FLD_has_len; + } | integer_keyword { $$ = newNode(); diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 1b720d6822..4ea6f6a4ef 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -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 diff --git a/src/isql/isql.epp b/src/isql/isql.epp index 1fef945dd4..91f92be1ff 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -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: diff --git a/src/isql/isql.h b/src/isql/isql.h index 7fdd887e00..ebfb61dded 100644 --- a/src/isql/isql.h +++ b/src/isql/isql.h @@ -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"}, diff --git a/src/isql/show.epp b/src/isql/show.epp index 0c49d15ec5..7a229ddc9f 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -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 && diff --git a/src/jrd/Coercion.cpp b/src/jrd/Coercion.cpp index 690737cc8b..4384154f7b 100644 --- a/src/jrd/Coercion.cpp +++ b/src/jrd/Coercion.cpp @@ -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; } diff --git a/src/jrd/filters.cpp b/src/jrd/filters.cpp index 2e8257d7d5..1738af2cf5 100644 --- a/src/jrd/filters.cpp +++ b/src/jrd/filters.cpp @@ -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" }; diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index 6a4c58731e..8052be441b 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -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";