]> granicus.if.org Git - postgresql/commitdiff
Add infrastructure for storing a VARIADIC ANY function's VARIADIC flag.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 22 Jan 2013 01:25:26 +0000 (20:25 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 22 Jan 2013 01:26:15 +0000 (20:26 -0500)
Originally we didn't bother to mark FuncExprs with any indication whether
VARIADIC had been given in the source text, because there didn't seem to be
any need for it at runtime.  However, because we cannot fold a VARIADIC ANY
function's arguments into an array (since they're not necessarily all the
same type), we do actually need that information at runtime if VARIADIC ANY
functions are to respond unsurprisingly to use of the VARIADIC keyword.
Add the missing field, and also fix ruleutils.c so that VARIADIC ANY
function calls are dumped properly.

Extracted from a larger patch that also fixes concat() and format() (the
only two extant VARIADIC ANY functions) to behave properly when VARIADIC is
specified.  This portion seems appropriate to review and commit separately.

Pavel Stehule

12 files changed:
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/parse_func.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/fmgr/fmgr.c
src/include/catalog/catversion.h
src/include/fmgr.h
src/include/nodes/primnodes.h

index 51fdb63cbdaa546fcce236e5df52639ee659d0ed..9a01ec6d5991277edbab458ef156b84de5e174e9 100644 (file)
@@ -1194,6 +1194,7 @@ _copyFuncExpr(const FuncExpr *from)
        COPY_SCALAR_FIELD(funcid);
        COPY_SCALAR_FIELD(funcresulttype);
        COPY_SCALAR_FIELD(funcretset);
+       COPY_SCALAR_FIELD(funcvariadic);
        COPY_SCALAR_FIELD(funcformat);
        COPY_SCALAR_FIELD(funccollid);
        COPY_SCALAR_FIELD(inputcollid);
index 4b219b35ba6d118c9a9291e84485c2d3844b6388..034159da31ddfcc9f226234d85e52c16871d89f4 100644 (file)
@@ -239,6 +239,7 @@ _equalFuncExpr(const FuncExpr *a, const FuncExpr *b)
        COMPARE_SCALAR_FIELD(funcid);
        COMPARE_SCALAR_FIELD(funcresulttype);
        COMPARE_SCALAR_FIELD(funcretset);
+       COMPARE_SCALAR_FIELD(funcvariadic);
        COMPARE_COERCIONFORM_FIELD(funcformat);
        COMPARE_SCALAR_FIELD(funccollid);
        COMPARE_SCALAR_FIELD(inputcollid);
index 7b8ac57cd6cf580c6b1b4f0ec59aca66d82e5c96..c487db96d816bc7bc06b98618ef72d88135417d6 100644 (file)
@@ -461,6 +461,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args,
        funcexpr->funcid = funcid;
        funcexpr->funcresulttype = rettype;
        funcexpr->funcretset = false;           /* only allowed case here */
+       funcexpr->funcvariadic = false;         /* only allowed case here */
        funcexpr->funcformat = fformat;
        funcexpr->funccollid = funccollid;
        funcexpr->inputcollid = inputcollid;
index 3cce5f517e665cfd275c67db73a60b005833e74c..484e426489eb8d9a9b045062eb14c01d2b7f0183 100644 (file)
@@ -1000,6 +1000,7 @@ _outFuncExpr(StringInfo str, const FuncExpr *node)
        WRITE_OID_FIELD(funcid);
        WRITE_OID_FIELD(funcresulttype);
        WRITE_BOOL_FIELD(funcretset);
+       WRITE_BOOL_FIELD(funcvariadic);
        WRITE_ENUM_FIELD(funcformat, CoercionForm);
        WRITE_OID_FIELD(funccollid);
        WRITE_OID_FIELD(inputcollid);
index e7c6ad67e917eb1441bcfc3151b40f3b36790ad9..ed2354144c4bbe6eb34c20a3abe3bfad65e4ccae 100644 (file)
@@ -537,6 +537,7 @@ _readFuncExpr(void)
        READ_OID_FIELD(funcid);
        READ_OID_FIELD(funcresulttype);
        READ_BOOL_FIELD(funcretset);
+       READ_BOOL_FIELD(funcvariadic);
        READ_ENUM_FIELD(funcformat, CoercionForm);
        READ_OID_FIELD(funccollid);
        READ_OID_FIELD(inputcollid);
index 55c4a136441bec77c92a50ad81e1e0042ddff85e..657a18b1be4e2727bff5852badea05035318ecca 100644 (file)
@@ -110,7 +110,7 @@ static Node *simplify_boolean_equality(Oid opno, List *args);
 static Expr *simplify_function(Oid funcid,
                                  Oid result_type, int32 result_typmod,
                                  Oid result_collid, Oid input_collid, List **args_p,
-                                 bool process_args, bool allow_non_const,
+                                 bool funcvariadic, bool process_args, bool allow_non_const,
                                  eval_const_expressions_context *context);
 static List *expand_function_arguments(List *args, Oid result_type,
                                                  HeapTuple func_tuple);
@@ -121,10 +121,12 @@ static void recheck_cast_function_args(List *args, Oid result_type,
                                                   HeapTuple func_tuple);
 static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
                                  Oid result_collid, Oid input_collid, List *args,
+                                 bool funcvariadic,
                                  HeapTuple func_tuple,
                                  eval_const_expressions_context *context);
 static Expr *inline_function(Oid funcid, Oid result_type, Oid result_collid,
                                Oid input_collid, List *args,
+                               bool funcvariadic,
                                HeapTuple func_tuple,
                                eval_const_expressions_context *context);
 static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
@@ -2314,6 +2316,7 @@ eval_const_expressions_mutator(Node *node,
                                                                                   expr->funccollid,
                                                                                   expr->inputcollid,
                                                                                   &args,
+                                                                                  expr->funcvariadic,
                                                                                   true,
                                                                                   true,
                                                                                   context);
@@ -2330,6 +2333,7 @@ eval_const_expressions_mutator(Node *node,
                                newexpr->funcid = expr->funcid;
                                newexpr->funcresulttype = expr->funcresulttype;
                                newexpr->funcretset = expr->funcretset;
+                               newexpr->funcvariadic = expr->funcvariadic;
                                newexpr->funcformat = expr->funcformat;
                                newexpr->funccollid = expr->funccollid;
                                newexpr->inputcollid = expr->inputcollid;
@@ -2359,6 +2363,7 @@ eval_const_expressions_mutator(Node *node,
                                                                                   expr->opcollid,
                                                                                   expr->inputcollid,
                                                                                   &args,
+                                                                                  false,
                                                                                   true,
                                                                                   true,
                                                                                   context);
@@ -2464,6 +2469,7 @@ eval_const_expressions_mutator(Node *node,
                                                                                           &args,
                                                                                           false,
                                                                                           false,
+                                                                                          false,
                                                                                           context);
                                        if (simple) /* successfully simplified it */
                                        {
@@ -2665,6 +2671,7 @@ eval_const_expressions_mutator(Node *node,
                                                                                   InvalidOid,
                                                                                   InvalidOid,
                                                                                   &args,
+                                                                                  false,
                                                                                   true,
                                                                                   true,
                                                                                   context);
@@ -2697,6 +2704,7 @@ eval_const_expressions_mutator(Node *node,
                                                                                           InvalidOid,
                                                                                           &args,
                                                                                           false,
+                                                                                          false,
                                                                                           true,
                                                                                           context);
                                        if (simple) /* successfully simplified input fn */
@@ -3565,7 +3573,7 @@ simplify_boolean_equality(Oid opno, List *args)
 static Expr *
 simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
                                  Oid result_collid, Oid input_collid, List **args_p,
-                                 bool process_args, bool allow_non_const,
+                                 bool funcvariadic, bool process_args, bool allow_non_const,
                                  eval_const_expressions_context *context)
 {
        List       *args = *args_p;
@@ -3609,7 +3617,8 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
        /* Now attempt simplification of the function call proper. */
 
        newexpr = evaluate_function(funcid, result_type, result_typmod,
-                                                               result_collid, input_collid, args,
+                                                               result_collid, input_collid,
+                                                               args, funcvariadic,
                                                                func_tuple, context);
 
        if (!newexpr && allow_non_const && OidIsValid(func_form->protransform))
@@ -3625,6 +3634,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
                fexpr.funcid = funcid;
                fexpr.funcresulttype = result_type;
                fexpr.funcretset = func_form->proretset;
+               fexpr.funcvariadic = funcvariadic;
                fexpr.funcformat = COERCE_EXPLICIT_CALL;
                fexpr.funccollid = result_collid;
                fexpr.inputcollid = input_collid;
@@ -3638,7 +3648,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
 
        if (!newexpr && allow_non_const)
                newexpr = inline_function(funcid, result_type, result_collid,
-                                                                 input_collid, args,
+                                                                 input_collid, args, funcvariadic,
                                                                  func_tuple, context);
 
        ReleaseSysCache(func_tuple);
@@ -3878,6 +3888,7 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
 static Expr *
 evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
                                  Oid result_collid, Oid input_collid, List *args,
+                                 bool funcvariadic,
                                  HeapTuple func_tuple,
                                  eval_const_expressions_context *context)
 {
@@ -3959,6 +3970,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
        newexpr->funcid = funcid;
        newexpr->funcresulttype = result_type;
        newexpr->funcretset = false;
+       newexpr->funcvariadic = funcvariadic;
        newexpr->funcformat = COERCE_EXPLICIT_CALL;     /* doesn't matter */
        newexpr->funccollid = result_collid;            /* doesn't matter */
        newexpr->inputcollid = input_collid;
@@ -4001,6 +4013,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
 static Expr *
 inline_function(Oid funcid, Oid result_type, Oid result_collid,
                                Oid input_collid, List *args,
+                               bool funcvariadic,
                                HeapTuple func_tuple,
                                eval_const_expressions_context *context)
 {
@@ -4089,6 +4102,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
        fexpr->funcid = funcid;
        fexpr->funcresulttype = result_type;
        fexpr->funcretset = false;
+       fexpr->funcvariadic = funcvariadic;
        fexpr->funcformat = COERCE_EXPLICIT_CALL;       /* doesn't matter */
        fexpr->funccollid = result_collid;      /* doesn't matter */
        fexpr->inputcollid = input_collid;
index c7a2a22465a60b56a4549d8d5058af5e7b0efeab..ae7d195a3ea45c1dca216d174216b07430157235 100644 (file)
@@ -384,6 +384,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                funcexpr->funcid = funcid;
                funcexpr->funcresulttype = rettype;
                funcexpr->funcretset = retset;
+               funcexpr->funcvariadic = func_variadic;
                funcexpr->funcformat = COERCE_EXPLICIT_CALL;
                /* funccollid and inputcollid will be set by parse_collate.c */
                funcexpr->args = fargs;
index 266cec5ffa2f19f7859d5cf95a0fec849b678fd6..af10471581795f91899c022ef927cd3362cbf530 100644 (file)
@@ -396,8 +396,9 @@ static Node *processIndirection(Node *node, deparse_context *context,
 static void printSubscripts(ArrayRef *aref, deparse_context *context);
 static char *get_relation_name(Oid relid);
 static char *generate_relation_name(Oid relid, List *namespaces);
-static char *generate_function_name(Oid funcid, int nargs, List *argnames,
-                                          Oid *argtypes, bool *is_variadic);
+static char *generate_function_name(Oid funcid, int nargs,
+                                          List *argnames, Oid *argtypes,
+                                          bool was_variadic, bool *use_variadic_p);
 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
 static text *string_to_text(char *str);
 static char *flatten_reloptions(Oid relid);
@@ -858,7 +859,8 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 
        appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
                                         generate_function_name(trigrec->tgfoid, 0,
-                                                                                       NIL, NULL, NULL));
+                                                                                       NIL, NULL,
+                                                                                       false, NULL));
 
        if (trigrec->tgnargs > 0)
        {
@@ -7269,7 +7271,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
        Oid                     argtypes[FUNC_MAX_ARGS];
        int                     nargs;
        List       *argnames;
-       bool            is_variadic;
+       bool            use_variadic;
        ListCell   *l;
 
        /*
@@ -7327,13 +7329,14 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
        appendStringInfo(buf, "%s(",
                                         generate_function_name(funcoid, nargs,
                                                                                        argnames, argtypes,
-                                                                                       &is_variadic));
+                                                                                       expr->funcvariadic,
+                                                                                       &use_variadic));
        nargs = 0;
        foreach(l, expr->args)
        {
                if (nargs++ > 0)
                        appendStringInfoString(buf, ", ");
-               if (is_variadic && lnext(l) == NULL)
+               if (use_variadic && lnext(l) == NULL)
                        appendStringInfoString(buf, "VARIADIC ");
                get_rule_expr((Node *) lfirst(l), context, true);
        }
@@ -7374,7 +7377,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
 
        appendStringInfo(buf, "%s(%s",
                                         generate_function_name(aggref->aggfnoid, nargs,
-                                                                                       NIL, argtypes, NULL),
+                                                                                       NIL, argtypes,
+                                                                                       false, NULL),
                                         (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
        /* aggstar can be set only in zero-argument aggregates */
        if (aggref->aggstar)
@@ -7416,7 +7420,8 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
 
        appendStringInfo(buf, "%s(",
                                         generate_function_name(wfunc->winfnoid, nargs,
-                                                                                       NIL, argtypes, NULL));
+                                                                                       NIL, argtypes,
+                                                                                       false, NULL));
        /* winstar can be set only in zero-argument aggregates */
        if (wfunc->winstar)
                appendStringInfoChar(buf, '*');
@@ -8507,18 +8512,25 @@ generate_relation_name(Oid relid, List *namespaces)
  *             given that it is being called with the specified actual arg names and
  *             types.  (Those matter because of ambiguous-function resolution rules.)
  *
- * The result includes all necessary quoting and schema-prefixing.     We can
- * also pass back an indication of whether the function is variadic.
+ * If we're dealing with a potentially variadic function (in practice, this
+ * means a FuncExpr and not some other way of calling the function), then
+ * was_variadic must specify whether VARIADIC appeared in the original call,
+ * and *use_variadic_p will be set to indicate whether to print VARIADIC in
+ * the output.  For non-FuncExpr cases, was_variadic should be FALSE and
+ * use_variadic_p can be NULL.
+ *
+ * The result includes all necessary quoting and schema-prefixing.
  */
 static char *
-generate_function_name(Oid funcid, int nargs, List *argnames,
-                                          Oid *argtypes, bool *is_variadic)
+generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
+                                          bool was_variadic, bool *use_variadic_p)
 {
+       char       *result;
        HeapTuple       proctup;
        Form_pg_proc procform;
        char       *proname;
+       bool            use_variadic;
        char       *nspname;
-       char       *result;
        FuncDetailCode p_result;
        Oid                     p_funcid;
        Oid                     p_rettype;
@@ -8532,15 +8544,47 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
        procform = (Form_pg_proc) GETSTRUCT(proctup);
        proname = NameStr(procform->proname);
 
+       /*
+        * Determine whether VARIADIC should be printed.  We must do this first
+        * since it affects the lookup rules in func_get_detail().
+        *
+        * Currently, we always print VARIADIC if the function is variadic and
+        * takes a variadic type other than ANY.  (In principle, if VARIADIC
+        * wasn't originally specified and the array actual argument is
+        * deconstructable, we could print the array elements separately and not
+        * print VARIADIC, thus more nearly reproducing the original input.  For
+        * the moment that seems like too much complication for the benefit.)
+        * However, if the function takes VARIADIC ANY, then the parser didn't
+        * fold the arguments together into an array, so we must print VARIADIC if
+        * and only if it was used originally.
+        */
+       if (use_variadic_p)
+       {
+               if (OidIsValid(procform->provariadic))
+               {
+                       if (procform->provariadic != ANYOID)
+                               use_variadic = true;
+                       else
+                               use_variadic = was_variadic;
+               }
+               else
+                       use_variadic = false;
+               *use_variadic_p = use_variadic;
+       }
+       else
+       {
+               Assert(!was_variadic);
+               use_variadic = false;
+       }
+
        /*
         * The idea here is to schema-qualify only if the parser would fail to
         * resolve the correct function given the unqualified func name with the
-        * specified argtypes.  If the function is variadic, we should presume
-        * that VARIADIC will be included in the call.
+        * specified argtypes and VARIADIC flag.
         */
        p_result = func_get_detail(list_make1(makeString(proname)),
                                                           NIL, argnames, nargs, argtypes,
-                                                          !OidIsValid(procform->provariadic), true,
+                                                          !use_variadic, true,
                                                           &p_funcid, &p_rettype,
                                                           &p_retset, &p_nvargs, &p_true_typeids, NULL);
        if ((p_result == FUNCDETAIL_NORMAL ||
@@ -8553,17 +8597,6 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
 
        result = quote_qualified_identifier(nspname, proname);
 
-       /* Check variadic-ness if caller cares */
-       if (is_variadic)
-       {
-               /* "any" variadics are not treated as variadics for listing */
-               if (OidIsValid(procform->provariadic) &&
-                       procform->provariadic != ANYOID)
-                       *is_variadic = true;
-               else
-                       *is_variadic = false;
-       }
-
        ReleaseSysCache(proctup);
 
        return result;
index e21bed83e39c93cd954ba140c4503ee58139028a..42de04c60a8368038d2afdd3cde849251fdcb283 100644 (file)
@@ -2281,6 +2281,7 @@ pg_detoast_datum_packed(struct varlena * datum)
  * These are needed by polymorphic functions, which accept multiple possible
  * input types and need help from the parser to know what they've got.
  * Also, some functions might be interested in whether a parameter is constant.
+ * Functions taking VARIADIC ANY also need to know about the VARIADIC keyword.
  *-------------------------------------------------------------------------
  */
 
@@ -2445,3 +2446,28 @@ get_call_expr_arg_stable(Node *expr, int argnum)
 
        return false;
 }
+
+/*
+ * Get the VARIADIC flag from the function invocation
+ *
+ * Returns false (the default assumption) if information is not available
+ */
+bool
+get_fn_expr_variadic(FmgrInfo *flinfo)
+{
+       Node       *expr;
+
+       /*
+        * can't return anything useful if we have no FmgrInfo or if its fn_expr
+        * node has not been initialized
+        */
+       if (!flinfo || !flinfo->fn_expr)
+               return false;
+
+       expr = flinfo->fn_expr;
+
+       if (IsA(expr, FuncExpr))
+               return ((FuncExpr *) expr)->funcvariadic;
+       else
+               return false;
+}
index cd562ef40cb41ce03a62a5e254d5ca5a02520e87..a676793566d54e4eefaba16098613928831b946b 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201301171
+#define CATALOG_VERSION_NO     201301211
 
 #endif
index fe4a41ba09684eca1e0077a96b7245cc973c74ec..1f72e1bd48f96d585cbe76d252a9765bbf4b3f41 100644 (file)
@@ -624,6 +624,7 @@ extern Oid  get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
 extern Oid     get_call_expr_argtype(fmNodePtr expr, int argnum);
 extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum);
 extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
+extern bool get_fn_expr_variadic(FmgrInfo *flinfo);
 
 /*
  * Routines in dfmgr.c
index ac53e463fc6053d3f282b0f66e4953bb0840bbfb..1d657669e132a25690ae1dbdad947cf262c1db22 100644 (file)
@@ -340,6 +340,7 @@ typedef struct FuncExpr
        Oid                     funcid;                 /* PG_PROC OID of the function */
        Oid                     funcresulttype; /* PG_TYPE OID of result value */
        bool            funcretset;             /* true if function returns set */
+       bool            funcvariadic;   /* true if VARIADIC was used in call */
        CoercionForm funcformat;        /* how to display this function call */
        Oid                     funccollid;             /* OID of collation of result */
        Oid                     inputcollid;    /* OID of collation that function should use */