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: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://www.postgresql.org/message-id/flat/97df3af9-8b5e-fb7f-a029-3eb7e80d7af9@2ndquadrant.com
This commit is contained in:
parent
59ab4ac324
commit
f893e68d76
@ -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)
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
*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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user