From 8a5af28e7c41055cfbcedd9aa07cf6714b60c178 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 20 Oct 2020 09:28:48 +0200 Subject: [PATCH] Add select_common_typmod() This accompanies select_common_type() and select_common_collation(). Typmods were previously combined using hand-coded logic in several places. The logic in select_common_typmod() isn't very exciting, but it makes the code more compact and readable in a few locations, and in the future we can perhaps do more complicated things if desired. --- src/backend/parser/analyze.c | 26 +++++----------------- src/backend/parser/parse_clause.c | 23 +++++-------------- src/backend/parser/parse_coerce.c | 37 +++++++++++++++++++++++++++++++ src/backend/parser/parse_func.c | 8 +++++-- src/include/parser/parse_coerce.h | 2 ++ 5 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index c159fb2957..98a83db8b5 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1434,9 +1434,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) for (i = 0; i < sublist_length; i++) { Oid coltype; - int32 coltypmod = -1; + int32 coltypmod; Oid colcoll; - bool first = true; coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL); @@ -1446,19 +1445,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) col = coerce_to_common_type(pstate, col, coltype, "VALUES"); lfirst(lc) = (void *) col; - if (first) - { - coltypmod = exprTypmod(col); - first = false; - } - else - { - /* As soon as we see a non-matching typmod, fall back to -1 */ - if (coltypmod >= 0 && coltypmod != exprTypmod(col)) - coltypmod = -1; - } } + coltypmod = select_common_typmod(pstate, colexprs[i], coltype); colcoll = select_common_collation(pstate, colexprs[i], true); coltypes = lappend_oid(coltypes, coltype); @@ -2020,8 +2009,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, Node *rcolnode = (Node *) rtle->expr; Oid lcoltype = exprType(lcolnode); Oid rcoltype = exprType(rcolnode); - int32 lcoltypmod = exprTypmod(lcolnode); - int32 rcoltypmod = exprTypmod(rcolnode); Node *bestexpr; int bestlocation; Oid rescoltype; @@ -2034,11 +2021,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, context, &bestexpr); bestlocation = exprLocation(bestexpr); - /* if same type and same typmod, use typmod; else default */ - if (lcoltype == rcoltype && lcoltypmod == rcoltypmod) - rescoltypmod = lcoltypmod; - else - rescoltypmod = -1; /* * Verify the coercions are actually possible. If not, we'd fail @@ -2089,6 +2071,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, rtle->expr = (Expr *) rcolnode; } + rescoltypmod = select_common_typmod(pstate, + list_make2(lcolnode, rcolnode), + rescoltype); + /* * Select common collation. A common collation is required for * all set operators except UNION ALL; see SQL:2008 7.13 vartype; - outcoltypmod = l_colvar->vartypmod; - if (outcoltype != r_colvar->vartype) - { - outcoltype = select_common_type(pstate, + outcoltype = select_common_type(pstate, + list_make2(l_colvar, r_colvar), + "JOIN/USING", + NULL); + outcoltypmod = select_common_typmod(pstate, list_make2(l_colvar, r_colvar), - "JOIN/USING", - NULL); - outcoltypmod = -1; /* ie, unknown */ - } - else if (outcoltypmod != r_colvar->vartypmod) - { - /* same type, but not same typmod */ - outcoltypmod = -1; /* ie, unknown */ - } + outcoltype); /* * Insert coercion functions if needed. Note that a difference in typmod diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 2ffe47026b..38482d24fd 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -1522,6 +1522,43 @@ coerce_to_common_type(ParseState *pstate, Node *node, return node; } +/* + * select_common_typmod() + * Determine the common typmod of a list of input expressions. + * + * common_type is the selected common type of the expressions, presumbably + * computed using select_common_type(). + */ +int32 +select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) +{ + ListCell *lc; + bool first = true; + int32 result = -1; + + foreach(lc, exprs) + { + Node *expr = (Node *) lfirst(lc); + + /* Types must match */ + if (exprType(expr) != common_type) + return -1; + else if (first) + { + result = exprTypmod(expr); + first = false; + } + else + { + /* As soon as we see a non-matching typmod, fall back to -1 */ + if (result != exprTypmod(expr)) + return -1; + } + } + + return result; +} + /* * check_generic_type_consistency() * Are the actual arguments potentially compatible with a diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 9c3b6ad916..a7a31704fb 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -1750,6 +1750,7 @@ unify_hypothetical_args(ParseState *pstate, ListCell *harg = list_nth_cell(fargs, hargpos); ListCell *aarg = list_nth_cell(fargs, aargpos); Oid commontype; + int32 commontypmod; /* A mismatch means AggregateCreate didn't check properly ... */ if (declared_arg_types[hargpos] != declared_arg_types[aargpos]) @@ -1768,6 +1769,9 @@ unify_hypothetical_args(ParseState *pstate, list_make2(lfirst(aarg), lfirst(harg)), "WITHIN GROUP", NULL); + commontypmod = select_common_typmod(pstate, + list_make2(lfirst(aarg), lfirst(harg)), + commontype); /* * Perform the coercions. We don't need to worry about NamedArgExprs @@ -1776,7 +1780,7 @@ unify_hypothetical_args(ParseState *pstate, lfirst(harg) = coerce_type(pstate, (Node *) lfirst(harg), actual_arg_types[hargpos], - commontype, -1, + commontype, commontypmod, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); @@ -1784,7 +1788,7 @@ unify_hypothetical_args(ParseState *pstate, lfirst(aarg) = coerce_type(pstate, (Node *) lfirst(aarg), actual_arg_types[aargpos], - commontype, -1, + commontype, commontypmod, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 8686eaacbc..33d7cfc8b6 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -71,6 +71,8 @@ extern Node *coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context); +extern int32 select_common_typmod(ParseState *pstate, List *exprs, Oid common_type); + extern bool check_generic_type_consistency(const Oid *actual_arg_types, const Oid *declared_arg_types, int nargs); -- 2.28.0