From 7b9b408658e1f8c53bf8fba3c78394666f4677e4 Mon Sep 17 00:00:00 2001 From: Dimitry Sibiryakov Date: Wed, 11 Jan 2017 17:13:10 +0100 Subject: [PATCH] Implementation of CORE-5064 (#73) * Implementation of CORE-5064 * Use constants instead of magic numbers --- doc/sql.extensions/README.data_types | 27 ++++++++ src/dsql/parse.y | 45 +++++++++++++ src/include/consts_pub.h | 7 ++ src/isql/extract.epp | 28 ++++---- src/isql/isql.epp | 99 +++++++++++++++------------- src/isql/isql.h | 18 +++++ src/isql/isql_proto.h | 2 +- src/isql/show.epp | 27 ++++---- src/yvalve/keywords.cpp | 2 + src/yvalve/why.cpp | 2 +- 10 files changed, 184 insertions(+), 73 deletions(-) diff --git a/doc/sql.extensions/README.data_types b/doc/sql.extensions/README.data_types index e12142525b..050e702696 100644 --- a/doc/sql.extensions/README.data_types +++ b/doc/sql.extensions/README.data_types @@ -74,3 +74,30 @@ BOOLEAN (FB 3.0) 5. It's allowed to test booleans without compare with TRUE or FALSE. For example, "field1 OR field2" and "NOT field1" are valid expressions. It's also allowed to compare with others operators, including the new IS operator: "field1 IS FALSE". + + +BINARY, VARBINARY, BINARY VARYING (FB 4.0) +------------------------------------------ + + Function: + Alias for CHAR, VARCHAR, VARYING CHAR with CHARACTER SET OCTETS. + + Author: + Dimitry Sibiryakov + + Syntax rules: + BINARY[(length)] + VARBINARY(length) + BINARY VARYING(length) + + Example(s): + 1. DECLARE VARIABLE VAR1 VARBINARY(10); + 2. CREATE TABLE TABLE1 (FIELD1 BINARY(16), + FIELD2 VARBINARY(100), + FIELD3 BINARY VARYING(1000)); + + Note(s): + 1. If length is omitted for type BINARY, it is considered to be 1. + 2. Can be distinguished from text types by value 1 in RDB$FIELD_SUB_TYPE. + 3. Character set is set to OCTETS for backward compatibility. + 4. In API are similar to corresponding text types, getSubType() returns 0. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 491d0a9805..0655433fcd 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -591,6 +591,7 @@ using namespace Firebird; // tokens added for Firebird 4.0 +%token BINARY %token CUME_DIST %token DEFINER %token EXCLUDE @@ -611,6 +612,7 @@ using namespace Firebird; %token SYSTEM %token TIES %token UNBOUNDED +%token VARBINARY %token WINDOW // precedence declarations for expression evaluation @@ -4429,6 +4431,7 @@ simple_type %type non_charset_simple_type non_charset_simple_type : national_character_type + | binary_character_type | numeric_type | float_type | BIGINT @@ -4614,6 +4617,40 @@ national_character_type } ; +%type binary_character_type +binary_character_type + : binary_character_keyword '(' pos_short_integer ')' + { + $$ = newNode(); + $$->dtype = dtype_text; + $$->charLength = (USHORT) $3; + $$->length = (USHORT) $3; + $$->textType = ttype_binary; + $$->charSetId = CS_BINARY; + $$->subType = fb_text_subtype_binary; + } + | binary_character_keyword + { + $$ = newNode(); + $$->dtype = dtype_text; + $$->charLength = 1; + $$->length = 1; + $$->textType = ttype_binary; + $$->charSetId = CS_BINARY; + $$->subType = fb_text_subtype_binary; + } + | varbinary_character_keyword '(' pos_short_integer ')' + { + $$ = newNode(); + $$->dtype = dtype_varying; + $$->charLength = (USHORT) $3; + $$->length = (USHORT) $3 + sizeof(USHORT); + $$->textType = ttype_binary; + $$->charSetId = CS_BINARY; + $$->subType = fb_text_subtype_binary; + } + ; + %type character_type character_type : character_keyword '(' pos_short_integer ')' @@ -4653,6 +4690,14 @@ national_character_keyword | NATIONAL CHAR ; +binary_character_keyword + : BINARY + ; + +varbinary_character_keyword + : VARBINARY + | BINARY VARYING + ; // numeric type diff --git a/src/include/consts_pub.h b/src/include/consts_pub.h index 0c7731ae4b..0d6886e7b2 100644 --- a/src/include/consts_pub.h +++ b/src/include/consts_pub.h @@ -650,6 +650,13 @@ //#define isc_blob_dbase_ole 23 //#define isc_blob_typed_binary 24 +/*****************/ +/* Text Subtypes */ +/*****************/ + +#define fb_text_subtype_text 0 +#define fb_text_subtype_binary 1 + /* Deprecated definitions maintained for compatibility only */ //#define isc_info_db_SQL_dialect 62 diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 87362a0d03..e37f1ad065 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -410,7 +410,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return FINI_ERROR; if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) @@ -440,7 +440,7 @@ int EXTRACT_list_table(const SCHAR* relation_name, } // International character sets - if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR || + if ((((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) || FLD.RDB$FIELD_TYPE == BLOB) && !FLD.RDB$CHARACTER_SET_ID.NULL) { @@ -801,7 +801,7 @@ static void get_procedure_args(const char* proc_name) } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return; // ps_ERR; // Changed this to return RDB$CHARACTER_LENGTH if available @@ -816,7 +816,8 @@ static void get_procedure_args(const char* proc_name) } // Show international character sets and collations - if (!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) + if ((!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) && + !(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { char_sets[0] = 0; @@ -1017,7 +1018,7 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg) } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return; // ps_ERR; // Changed this to return RDB$CHARACTER_LENGTH if available @@ -1032,7 +1033,8 @@ static void get_function_args_ods12(const char* func_name, USHORT out_arg) } // Show international character sets and collations - if (!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) + if ((!FLD.RDB$COLLATION_ID.NULL || !FLD.RDB$CHARACTER_SET_ID.NULL) && + !(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { char_sets[0] = 0; @@ -2235,7 +2237,7 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME); - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return; // ps_ERR; if (FLD.RDB$FIELD_TYPE == BLOB) @@ -2265,7 +2267,8 @@ static void list_domain_table(const SCHAR* table_name, SSHORT default_char_set_i // do, then the domain syntax when printed is not correct. // Since the character set is part of the field type, display that information now. - if (!FLD.RDB$CHARACTER_SET_ID.NULL) + if (!FLD.RDB$CHARACTER_SET_ID.NULL && + !(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { char_sets[0] = 0; @@ -2357,7 +2360,7 @@ static void list_domains(SSHORT default_char_set_id) else isqlGlob.printf("CREATE DOMAIN %s AS ", FLD.RDB$FIELD_NAME); - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return; // ps_ERR; if (FLD.RDB$FIELD_TYPE == BLOB) @@ -2388,7 +2391,8 @@ static void list_domains(SSHORT default_char_set_id) // do, then the domain syntax when printed is not correct. // Since the character set is part of the field type, display that information now. - if (!FLD.RDB$CHARACTER_SET_ID.NULL) + if (!FLD.RDB$CHARACTER_SET_ID.NULL && + !(((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) && FLD.RDB$FIELD_SUB_TYPE != fb_text_subtype_text)) { char_sets[0] = 0; if ((FLD.RDB$CHARACTER_SET_ID != default_char_set_id) || @@ -2575,7 +2579,7 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) } else { - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return; if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) @@ -2605,7 +2609,7 @@ static void listRelationComputed(LegacyTables flag, SSHORT default_char_set_id) } // International character sets - if ((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR || + if ((((FLD.RDB$FIELD_TYPE == T_CHAR || FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) || FLD.RDB$FIELD_TYPE == BLOB) && !FLD.RDB$CHARACTER_SET_ID.NULL) { diff --git a/src/isql/isql.epp b/src/isql/isql.epp index ddab7cfc2f..8e8ce4b750 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -1808,7 +1808,7 @@ bool ISQL_is_domain(const TEXT* field_name) // Print the numeric type as accurately as possible, depending on the ODS. // If it isn't numeric/decimal or is another non-numeric data type, print only the type. -bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldScale) +bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldSubType, const int fieldPrecision, const int fieldScale) { // Look through types array int i = 0; @@ -1822,63 +1822,68 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int return false; } - bool precision_known = false; - - if (isqlGlob.major_ods >= ODS_VERSION10 && - (fieldType == SMALLINT || fieldType == INTEGER || fieldType == BIGINT)) + switch (fieldType) { + case SMALLINT: + case INTEGER: + case BIGINT: // Handle Integral subtypes NUMERIC and DECIMAL // We are ODS >= 10 and could be any Dialect - FOR FLD1 IN RDB$FIELDS WITH - FLD1.RDB$FIELD_NAME EQ fieldName - AND NOT FLD1.RDB$FIELD_PRECISION EQ 0 - // We are Dialect >=3 since FIELD_PRECISION is non-NULL - if (FLD1.RDB$FIELD_SUB_TYPE > 0 && FLD1.RDB$FIELD_SUB_TYPE <= MAX_INTSUBTYPES) - { - isqlGlob.printf("%s(%d, %d)", - Integral_subtypes[FLD1.RDB$FIELD_SUB_TYPE], - FLD1.RDB$FIELD_PRECISION, - -FLD1.RDB$FIELD_SCALE); - precision_known = true; - } - END_FOR - ON_ERROR - ISQL_errmsg (fbStatus); - return false; - END_ERROR; - } - - if (!precision_known) - { - if (fieldScale < 0) + // We are Dialect >=3 since FIELD_PRECISION is non-NULL + if (isqlGlob.major_ods >= ODS_VERSION10 && fieldPrecision != 0 && fieldSubType > 0 && fieldSubType <= MAX_INTSUBTYPES) { - // Take a stab at numerics and decimals - switch (fieldType) - { - case SMALLINT: - isqlGlob.printf("NUMERIC(4, %d)", -fieldScale); - break; - case INTEGER: - isqlGlob.printf("NUMERIC(9, %d)", -fieldScale); - break; - case BIGINT: - isqlGlob.printf("NUMERIC(18, %d)", -fieldScale); - break; - case DOUBLE_PRECISION: - isqlGlob.printf("NUMERIC(15, %d)", -fieldScale); - break; - default: - isqlGlob.printf("%s", Column_types[i].type_name); - } + isqlGlob.printf("%s(%d, %d)", + Integral_subtypes[fieldSubType], + fieldPrecision, + -fieldScale); } else { - // This is a non-numeric data type - isqlGlob.printf("%s", Column_types[i].type_name); + if (fieldScale < 0) + { + // Take a stab at numerics and decimals + switch (fieldType) + { + case SMALLINT: + isqlGlob.printf("NUMERIC(4, %d)", -fieldScale); + break; + case INTEGER: + isqlGlob.printf("NUMERIC(9, %d)", -fieldScale); + break; + case BIGINT: + isqlGlob.printf("NUMERIC(18, %d)", -fieldScale); + break; + case DOUBLE_PRECISION: + isqlGlob.printf("NUMERIC(15, %d)", -fieldScale); + break; + } + } + else + { + break; + } } + return true; + case T_CHAR: + if (fieldSubType >= 0 && fieldSubType <= MAX_TEXTSUBTYPES) + { + isqlGlob.printf("%s", Text_subtypes[fieldSubType]); + return true; + } + break; + case VARCHAR: + if (fieldSubType >= 0 && fieldSubType <= MAX_VARYINGSUBTYPES) + { + isqlGlob.printf("%s", Varying_subtypes[fieldSubType]); + return true; + } + break; } + // Field type without recognizable subtypes + isqlGlob.printf("%s", Column_types[i].type_name); + return true; } diff --git a/src/isql/isql.h b/src/isql/isql.h index 04bab894c8..37142759b8 100644 --- a/src/isql/isql.h +++ b/src/isql/isql.h @@ -324,6 +324,24 @@ static const SCHAR* Integral_subtypes[] = { "DECIMAL" // DECIMAL, keyword }; +// Text subtypes + +const int MAX_TEXTSUBTYPES = 1; + +static const SCHAR* Text_subtypes[] = { + "CHAR", + "BINARY" +}; + +// Varying subtypes + +const int MAX_VARYINGSUBTYPES = 1; + +static const SCHAR* Varying_subtypes[] = { + "VARCHAR", + "VARBINARY" +}; + // Blob subtypes const int MAX_BLOBSUBTYPES = 8; diff --git a/src/isql/isql_proto.h b/src/isql/isql_proto.h index b8039ed5f5..62103c7916 100644 --- a/src/isql/isql_proto.h +++ b/src/isql/isql_proto.h @@ -53,7 +53,7 @@ SSHORT ISQL_init(FILE*, FILE*); bool ISQL_is_domain(const TEXT*); #endif int ISQL_main(int, char**); -bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldScale); +bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int fieldSubType, const int fieldPrecision, const int fieldScale); void ISQL_print_validation(FILE*, ISC_QUAD*, bool, Firebird::ITransaction*); //void ISQL_query_database(SSHORT*, FILE*, FILE*, FILE*); //void ISQL_reset_settings(); diff --git a/src/isql/show.epp b/src/isql/show.epp index b474fd984b..5498035210 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -3855,7 +3855,7 @@ static processing_state show_domains(const SCHAR* domain_name) isqlGlob.printf("%s ", NEWLINE); } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return ps_ERR; // Length for CHARs @@ -3877,8 +3877,8 @@ static processing_state show_domains(const SCHAR* domain_name) } // Show international character sets - if (FLD.RDB$FIELD_TYPE == T_CHAR || - FLD.RDB$FIELD_TYPE == VARCHAR || + if (((FLD.RDB$FIELD_TYPE == T_CHAR || + FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) || FLD.RDB$FIELD_TYPE == BLOB) { show_charsets(NULL, FLD.RDB$FIELD_NAME, true, false, false, false); @@ -4351,7 +4351,7 @@ static processing_state show_func(const SCHAR* funcname) } } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return ps_ERR; // Use RDB$CHARACTER_LENGTH instead of RDB$FIELD_LENGTH @@ -4364,8 +4364,8 @@ static processing_state show_func(const SCHAR* funcname) // Show international character sets and collations - if (FLD.RDB$FIELD_TYPE == T_CHAR || - FLD.RDB$FIELD_TYPE == VARCHAR || + if (((FLD.RDB$FIELD_TYPE == T_CHAR || + FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) || FLD.RDB$FIELD_TYPE == BLOB) { SSHORT charset = 0, collation = 0; @@ -5244,7 +5244,7 @@ static processing_state show_proc(const SCHAR* procname) } } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return ps_ERR; // Use RDB$CHARACTER_LENGTH instead of RDB$FIELD_LENGTH @@ -5257,8 +5257,8 @@ static processing_state show_proc(const SCHAR* procname) // Show international character sets and collations - if (FLD.RDB$FIELD_TYPE == T_CHAR || - FLD.RDB$FIELD_TYPE == VARCHAR || + if (((FLD.RDB$FIELD_TYPE == T_CHAR || + FLD.RDB$FIELD_TYPE == VARCHAR) && FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) || FLD.RDB$FIELD_TYPE == BLOB) { SSHORT charset = 0; @@ -5775,14 +5775,17 @@ static processing_state show_table(const SCHAR* relation_name, bool isView) continue; } - if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SCALE)) + if (!ISQL_printNumericType(FLD.RDB$FIELD_NAME, FLD.RDB$FIELD_TYPE, FLD.RDB$FIELD_SUB_TYPE, FLD.RDB$FIELD_PRECISION, FLD.RDB$FIELD_SCALE)) return ps_ERR; if ((FLD.RDB$FIELD_TYPE == T_CHAR) || (FLD.RDB$FIELD_TYPE == VARCHAR)) { isqlGlob.printf("(%d)", ISQL_get_field_length(FLD.RDB$FIELD_NAME)); - // Show international character sets and collations - show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false); + if (FLD.RDB$FIELD_SUB_TYPE == fb_text_subtype_text) + { + // Show international character sets and collations + show_charsets(relation_name, RFR.RDB$FIELD_NAME, true, false, false, false); + } } if (FLD.RDB$FIELD_TYPE == BLOB) diff --git a/src/yvalve/keywords.cpp b/src/yvalve/keywords.cpp index 262008280b..838fe9a4b7 100644 --- a/src/yvalve/keywords.cpp +++ b/src/yvalve/keywords.cpp @@ -94,6 +94,7 @@ static const TOK tokens[] = {TOK_BIN_SHL, "BIN_SHL", true}, {TOK_BIN_SHR, "BIN_SHR", true}, {TOK_BIN_XOR, "BIN_XOR", true}, + {TOK_BINARY, "BINARY", false}, {TOK_BIT_LENGTH, "BIT_LENGTH", false}, {TOK_BLOB, "BLOB", false}, {TOK_BLOCK, "BLOCK", true}, @@ -462,6 +463,7 @@ static const TOK tokens[] = {TOK_VALUES, "VALUES", false}, {TOK_VAR_POP, "VAR_POP", false}, {TOK_VAR_SAMP, "VAR_SAMP", false}, + {TOK_VARBINARY, "VARBINARY", false}, {TOK_VARCHAR, "VARCHAR", false}, {TOK_VARIABLE, "VARIABLE", false}, {TOK_VARYING, "VARYING", false}, diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index 12d6fab838..8a703e35c8 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -330,7 +330,7 @@ int SQLDAMetadata::getSubType(CheckStatusWrapper* status, unsigned index) fb_assert(sqlda->sqld > (int) index); ISC_SHORT sqltype = sqlda->sqlvar[index].sqltype & ~1; if (sqltype == SQL_VARYING || sqltype == SQL_TEXT) - return 0; + return sqlda->sqlvar[index].sqlsubtype == CS_BINARY ? fb_text_subtype_binary : fb_text_subtype_text; return sqlda->sqlvar[index].sqlsubtype; }