From: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
To: pgsql-hackers <pgsql-hackers@postgresql.org>
Subject: select_common_typmod
Date: Tue, 20 Oct 2020 10:58:18 +0200
Message-ID: <97df3af9-8b5e-fb7f-a029-3eb7e80d7af9@2ndquadrant.com> (raw)
While working on another patch, I figured adding a
select_common_typmod() to go along with select_common_type() and
select_common_collation() would be handy. Typmods were previously
combined using hand-coded logic in several places, and not at all in
other 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.
There might have been a tiny bug in transformValuesClause() because
while consolidating the typmods it does not take into account whether
the types are actually the same (as more correctly done in
transformSetOperationTree() and buildMergedJoinVar()).
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:0001-Add-select_common_typmod.patch (text/plain, 7.4K) download
From 8a5af28e7c41055cfbcedd9aa07cf6714b60c178 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
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.cindex 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 <query
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.cindex edcaf276c0..7460e61160 100644--- a/src/backend/parser/parse_clause.c+++ b/src/backend/parser/parse_clause.c@@ -1568,24 +1568,13 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
*r_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),+ "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.cindex 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.cindex 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.hindex 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: peter.eisentraut@2ndquadrant.com
Subject: Re: select_common_typmod
In-Reply-To: <97df3af9-8b5e-fb7f-a029-3eb7e80d7af9@2ndquadrant.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox