Add select_common_typmod()
authorPeter Eisentraut <[email protected]>
Tue, 27 Oct 2020 16:39:23 +0000 (17:39 +0100)
committerPeter Eisentraut <[email protected]>
Tue, 27 Oct 2020 17:10:42 +0000 (18:10 +0100)
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 <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/97df3af9-8b5e-fb7f-a029-3eb7e80d7af9@2ndquadrant.com

src/backend/parser/analyze.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_func.c
src/include/parser/parse_coerce.h

index c159fb2957bad1a2a2cd4001e2082a5d3734edf3..98a83db8b5cfe531906be731a06b712ae1c9cb3d 100644 (file)
@@ -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
index edcaf276c0ad391407da453d8fe2ce7c0d3f2783..7460e611604715af5ac2428dc44136bf0f8d5fb3 100644 (file)
@@ -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
index 2ffe47026b9b4427aef520fd652013fbe11cfdd1..a2924e3d1ce0c6f97d0a482e7411253f5f81970e 100644 (file)
@@ -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, 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()
  *     Are the actual arguments potentially compatible with a
index 9c3b6ad9166254d37d35c56d3a35c7ab3c1058a3..a7a31704fb4f92ad81389a48606f74dcfe4dfa58 100644 (file)
@@ -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);
index 8686eaacbc9bbd9b870157ca8d47d56793e7206d..33d7cfc8b646cf051f89f8b2a1465e33252a9198 100644 (file)
@@ -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);