diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 25edfa26601..66e28c44f3e 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -35,6 +35,7 @@ find_coercion_pathway_hook_type find_coercion_pathway_hook = NULL; determine_datatype_precedence_hook_type determine_datatype_precedence_hook = NULL; +is_tsql_base_datatype_hook_type is_tsql_base_datatype_hook = NULL; coerce_string_literal_hook_type coerce_string_literal_hook = NULL; validate_implicit_conversion_from_string_literal_hook_type validate_implicit_conversion_from_string_literal_hook = NULL; select_common_type_hook_type select_common_type_hook = NULL; @@ -1504,9 +1505,38 @@ select_common_type(ParseState *pstate, List *exprs, const char *context, pcategory = ncategory; pispreferred = nispreferred; } + } else if (sql_dialect == SQL_DIALECT_TSQL && ntype == ptype) + { + /* + * For the columns which have the same base type, we choose the + * expression with higher precedence type in T-SQL. + * For example, smallmoney UNION money, the base type of + * them are both fixeddecimal. But we shouldn't use smallmoney as + * the result type, it could loss precision. + * Here we don't need to update other variables since they are the + * same. + */ + if (is_tsql_base_datatype_hook && + (*is_tsql_base_datatype_hook)(exprType(nexpr)) && + determine_datatype_precedence_hook && + determine_datatype_precedence_hook(exprType(nexpr), + exprType(pexpr))) + pexpr = nexpr; } } + /* + * If the preferred type is not the result type of corresponding + * expression, it means the result type is a domain type in Postgres. Some + * base data types in T-SQL are implemented as domain types in Babelfish. + * From SQL Server's perspective, we should try to retain those types as + * result types. + */ + if (sql_dialect == SQL_DIALECT_TSQL && ptype != exprType(pexpr) && + is_tsql_base_datatype_hook && + (*is_tsql_base_datatype_hook)(exprType(pexpr))) + ptype = exprType(pexpr); + /* * If all the inputs were UNKNOWN type --- ie, unknown-type literals --- * then resolve as type TEXT. This situation comes up with constructs diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index c6fe31621dd..9055aaaf474 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -113,6 +113,11 @@ typedef CoercionPathType (*find_coercion_pathway_hook_type) (Oid sourceTypeId, */ typedef bool (*determine_datatype_precedence_hook_type) (Oid typeId1, Oid typeId2); +/* + * Hook interface to determine if a data type is a base type in T-SQL + */ +typedef bool (*is_tsql_base_datatype_hook_type) (Oid typeId); + /* * T-SQL has different rules for string literal datatype coercions */