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

Implementation of CORE-5064 (#73)

* Implementation of CORE-5064

* Use constants instead of magic numbers
This commit is contained in:
Dimitry Sibiryakov 2017-01-11 17:13:10 +01:00 committed by Dmitry Yemanov
parent 120a1d08a9
commit 7b9b408658
10 changed files with 184 additions and 73 deletions

View File

@ -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.

View File

@ -591,6 +591,7 @@ using namespace Firebird;
// tokens added for Firebird 4.0
%token <metaNamePtr> BINARY
%token <metaNamePtr> CUME_DIST
%token <metaNamePtr> DEFINER
%token <metaNamePtr> EXCLUDE
@ -611,6 +612,7 @@ using namespace Firebird;
%token <metaNamePtr> SYSTEM
%token <metaNamePtr> TIES
%token <metaNamePtr> UNBOUNDED
%token <metaNamePtr> VARBINARY
%token <metaNamePtr> WINDOW
// precedence declarations for expression evaluation
@ -4429,6 +4431,7 @@ simple_type
%type <legacyField> 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 <legacyField> binary_character_type
binary_character_type
: binary_character_keyword '(' pos_short_integer ')'
{
$$ = newNode<dsql_fld>();
$$->dtype = dtype_text;
$$->charLength = (USHORT) $3;
$$->length = (USHORT) $3;
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
}
| binary_character_keyword
{
$$ = newNode<dsql_fld>();
$$->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<dsql_fld>();
$$->dtype = dtype_varying;
$$->charLength = (USHORT) $3;
$$->length = (USHORT) $3 + sizeof(USHORT);
$$->textType = ttype_binary;
$$->charSetId = CS_BINARY;
$$->subType = fb_text_subtype_binary;
}
;
%type <legacyField> 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

View File

@ -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

View File

@ -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)
{

View File

@ -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,34 +1822,23 @@ 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)
if (isqlGlob.major_ods >= ODS_VERSION10 && fieldPrecision != 0 && fieldSubType > 0 && fieldSubType <= 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;
Integral_subtypes[fieldSubType],
fieldPrecision,
-fieldScale);
}
END_FOR
ON_ERROR
ISQL_errmsg (fbStatus);
return false;
END_ERROR;
}
if (!precision_known)
else
{
if (fieldScale < 0)
{
@ -1868,16 +1857,32 @@ bool ISQL_printNumericType(const char* fieldName, const int fieldType, const int
case DOUBLE_PRECISION:
isqlGlob.printf("NUMERIC(15, %d)", -fieldScale);
break;
default:
isqlGlob.printf("%s", Column_types[i].type_name);
}
}
else
{
// This is a non-numeric data type
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;
}

View File

@ -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;

View File

@ -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();

View File

@ -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,15 +5775,18 @@ 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));
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)
{

View File

@ -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},

View File

@ -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;
}