aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/equalfuncs.c1
-rw-r--r--src/backend/nodes/makefuncs.c1
-rw-r--r--src/backend/nodes/outfuncs.c1
-rw-r--r--src/backend/nodes/readfuncs.c1
-rw-r--r--src/backend/optimizer/util/clauses.c22
-rw-r--r--src/backend/parser/parse_func.c1
-rw-r--r--src/backend/utils/adt/ruleutils.c87
-rw-r--r--src/backend/utils/fmgr/fmgr.c26
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/fmgr.h1
-rw-r--r--src/include/nodes/primnodes.h1
12 files changed, 113 insertions, 32 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 51fdb63cbda..9a01ec6d599 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 4b219b35ba6..034159da31d 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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);
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 7b8ac57cd6c..c487db96d81 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -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;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3cce5f517e6..484e426489e 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -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);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index e7c6ad67e91..ed2354144c4 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -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);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 55c4a136441..657a18b1be4 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -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;
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index c7a2a22465a..ae7d195a3ea 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -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;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 266cec5ffa2..af104715817 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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;
@@ -8533,14 +8545,46 @@ generate_function_name(Oid funcid, int nargs, List *argnames,
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;
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index e21bed83e39..42de04c60a8 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -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;
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index cd562ef40cb..a676793566d 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201301171
+#define CATALOG_VERSION_NO 201301211
#endif
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index fe4a41ba096..1f72e1bd48f 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -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
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index ac53e463fc6..1d657669e13 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -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 */