diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/makefuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/readfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 22 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 1 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 87 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 26 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/fmgr.h | 1 | ||||
-rw-r--r-- | src/include/nodes/primnodes.h | 1 |
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 */ |