Commit f893e68d authored by Peter Eisentraut's avatar Peter Eisentraut

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.

As a small enhancement, the type unification of the direct and
aggregate arguments of hypothetical-set aggregates now unifies the
typmod as well using this new function, instead of just dropping it.
Reviewed-by: default avatarHeikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://www.postgresql.org/message-id/flat/97df3af9-8b5e-fb7f-a029-3eb7e80d7af9@2ndquadrant.com
parent 59ab4ac3
...@@ -1434,9 +1434,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) ...@@ -1434,9 +1434,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
for (i = 0; i < sublist_length; i++) for (i = 0; i < sublist_length; i++)
{ {
Oid coltype; Oid coltype;
int32 coltypmod = -1; int32 coltypmod;
Oid colcoll; Oid colcoll;
bool first = true;
coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL); coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
...@@ -1446,19 +1445,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt) ...@@ -1446,19 +1445,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
col = coerce_to_common_type(pstate, col, coltype, "VALUES"); col = coerce_to_common_type(pstate, col, coltype, "VALUES");
lfirst(lc) = (void *) col; 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); colcoll = select_common_collation(pstate, colexprs[i], true);
coltypes = lappend_oid(coltypes, coltype); coltypes = lappend_oid(coltypes, coltype);
...@@ -2020,8 +2009,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, ...@@ -2020,8 +2009,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
Node *rcolnode = (Node *) rtle->expr; Node *rcolnode = (Node *) rtle->expr;
Oid lcoltype = exprType(lcolnode); Oid lcoltype = exprType(lcolnode);
Oid rcoltype = exprType(rcolnode); Oid rcoltype = exprType(rcolnode);
int32 lcoltypmod = exprTypmod(lcolnode);
int32 rcoltypmod = exprTypmod(rcolnode);
Node *bestexpr; Node *bestexpr;
int bestlocation; int bestlocation;
Oid rescoltype; Oid rescoltype;
...@@ -2034,11 +2021,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, ...@@ -2034,11 +2021,6 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
context, context,
&bestexpr); &bestexpr);
bestlocation = exprLocation(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 * Verify the coercions are actually possible. If not, we'd fail
...@@ -2089,6 +2071,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt, ...@@ -2089,6 +2071,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
rtle->expr = (Expr *) rcolnode; rtle->expr = (Expr *) rcolnode;
} }
rescoltypmod = select_common_typmod(pstate,
list_make2(lcolnode, rcolnode),
rescoltype);
/* /*
* Select common collation. A common collation is required for * Select common collation. A common collation is required for
* all set operators except UNION ALL; see SQL:2008 7.13 <query * all set operators except UNION ALL; see SQL:2008 7.13 <query
......
...@@ -1568,24 +1568,13 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, ...@@ -1568,24 +1568,13 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
*r_node, *r_node,
*res_node; *res_node;
/*
* Choose output type if input types are dissimilar.
*/
outcoltype = l_colvar->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), list_make2(l_colvar, r_colvar),
"JOIN/USING", "JOIN/USING",
NULL); NULL);
outcoltypmod = -1; /* ie, unknown */ outcoltypmod = select_common_typmod(pstate,
} list_make2(l_colvar, r_colvar),
else if (outcoltypmod != r_colvar->vartypmod) outcoltype);
{
/* same type, but not same typmod */
outcoltypmod = -1; /* ie, unknown */
}
/* /*
* Insert coercion functions if needed. Note that a difference in typmod * Insert coercion functions if needed. Note that a difference in typmod
......
...@@ -1522,6 +1522,43 @@ coerce_to_common_type(ParseState *pstate, Node *node, ...@@ -1522,6 +1522,43 @@ coerce_to_common_type(ParseState *pstate, Node *node,
return 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, typically
* 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() * check_generic_type_consistency()
* Are the actual arguments potentially compatible with a * Are the actual arguments potentially compatible with a
......
...@@ -1750,6 +1750,7 @@ unify_hypothetical_args(ParseState *pstate, ...@@ -1750,6 +1750,7 @@ unify_hypothetical_args(ParseState *pstate,
ListCell *harg = list_nth_cell(fargs, hargpos); ListCell *harg = list_nth_cell(fargs, hargpos);
ListCell *aarg = list_nth_cell(fargs, aargpos); ListCell *aarg = list_nth_cell(fargs, aargpos);
Oid commontype; Oid commontype;
int32 commontypmod;
/* A mismatch means AggregateCreate didn't check properly ... */ /* A mismatch means AggregateCreate didn't check properly ... */
if (declared_arg_types[hargpos] != declared_arg_types[aargpos]) if (declared_arg_types[hargpos] != declared_arg_types[aargpos])
...@@ -1768,6 +1769,9 @@ unify_hypothetical_args(ParseState *pstate, ...@@ -1768,6 +1769,9 @@ unify_hypothetical_args(ParseState *pstate,
list_make2(lfirst(aarg), lfirst(harg)), list_make2(lfirst(aarg), lfirst(harg)),
"WITHIN GROUP", "WITHIN GROUP",
NULL); NULL);
commontypmod = select_common_typmod(pstate,
list_make2(lfirst(aarg), lfirst(harg)),
commontype);
/* /*
* Perform the coercions. We don't need to worry about NamedArgExprs * Perform the coercions. We don't need to worry about NamedArgExprs
...@@ -1776,7 +1780,7 @@ unify_hypothetical_args(ParseState *pstate, ...@@ -1776,7 +1780,7 @@ unify_hypothetical_args(ParseState *pstate,
lfirst(harg) = coerce_type(pstate, lfirst(harg) = coerce_type(pstate,
(Node *) lfirst(harg), (Node *) lfirst(harg),
actual_arg_types[hargpos], actual_arg_types[hargpos],
commontype, -1, commontype, commontypmod,
COERCION_IMPLICIT, COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST, COERCE_IMPLICIT_CAST,
-1); -1);
...@@ -1784,7 +1788,7 @@ unify_hypothetical_args(ParseState *pstate, ...@@ -1784,7 +1788,7 @@ unify_hypothetical_args(ParseState *pstate,
lfirst(aarg) = coerce_type(pstate, lfirst(aarg) = coerce_type(pstate,
(Node *) lfirst(aarg), (Node *) lfirst(aarg),
actual_arg_types[aargpos], actual_arg_types[aargpos],
commontype, -1, commontype, commontypmod,
COERCION_IMPLICIT, COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST, COERCE_IMPLICIT_CAST,
-1); -1);
......
...@@ -71,6 +71,8 @@ extern Node *coerce_to_common_type(ParseState *pstate, Node *node, ...@@ -71,6 +71,8 @@ extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
Oid targetTypeId, Oid targetTypeId,
const char *context); 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, extern bool check_generic_type_consistency(const Oid *actual_arg_types,
const Oid *declared_arg_types, const Oid *declared_arg_types,
int nargs); int nargs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment