mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
Support "variadic" functions, which can accept a variable number of arguments
so long as all the trailing arguments are of the same (non-array) type. The function receives them as a single array argument (which is why they have to all be the same type). It might be useful to extend this facility to aggregates, but this patch doesn't do that. This patch imposes a noticeable slowdown on function lookup --- a follow-on patch will fix that by adding a redundant column to pg_proc. Pavel Stehule
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.275 2008/06/06 17:59:29 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.276 2008/07/16 01:30:22 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -193,7 +193,8 @@ static Node *processIndirection(Node *node, deparse_context *context,
|
||||
bool printit);
|
||||
static void printSubscripts(ArrayRef *aref, deparse_context *context);
|
||||
static char *generate_relation_name(Oid relid);
|
||||
static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);
|
||||
static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes,
|
||||
bool *is_variadic);
|
||||
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
|
||||
static text *string_to_text(char *str);
|
||||
static char *flatten_reloptions(Oid relid);
|
||||
@ -531,7 +532,7 @@ pg_get_triggerdef(PG_FUNCTION_ARGS)
|
||||
appendStringInfo(&buf, "FOR EACH STATEMENT ");
|
||||
|
||||
appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
|
||||
generate_function_name(trigrec->tgfoid, 0, NULL));
|
||||
generate_function_name(trigrec->tgfoid, 0, NULL, NULL));
|
||||
|
||||
if (trigrec->tgnargs > 0)
|
||||
{
|
||||
@ -4293,6 +4294,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
|
||||
Oid funcoid = expr->funcid;
|
||||
Oid argtypes[FUNC_MAX_ARGS];
|
||||
int nargs;
|
||||
bool is_variadic;
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
@ -4343,8 +4345,17 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
|
||||
}
|
||||
|
||||
appendStringInfo(buf, "%s(",
|
||||
generate_function_name(funcoid, nargs, argtypes));
|
||||
get_rule_expr((Node *) expr->args, context, true);
|
||||
generate_function_name(funcoid, nargs, argtypes,
|
||||
&is_variadic));
|
||||
nargs = 0;
|
||||
foreach(l, expr->args)
|
||||
{
|
||||
if (nargs++ > 0)
|
||||
appendStringInfoString(buf, ", ");
|
||||
if (is_variadic && lnext(l) == NULL)
|
||||
appendStringInfoString(buf, "VARIADIC ");
|
||||
get_rule_expr((Node *) lfirst(l), context, true);
|
||||
}
|
||||
appendStringInfoChar(buf, ')');
|
||||
}
|
||||
|
||||
@ -4371,7 +4382,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
|
||||
}
|
||||
|
||||
appendStringInfo(buf, "%s(%s",
|
||||
generate_function_name(aggref->aggfnoid, nargs, argtypes),
|
||||
generate_function_name(aggref->aggfnoid,
|
||||
nargs, argtypes, NULL),
|
||||
aggref->aggdistinct ? "DISTINCT " : "");
|
||||
/* aggstar can be set only in zero-argument aggregates */
|
||||
if (aggref->aggstar)
|
||||
@ -5329,10 +5341,12 @@ generate_relation_name(Oid relid)
|
||||
* given that it is being called with the specified actual arg types.
|
||||
* (Arg types matter because of ambiguous-function resolution rules.)
|
||||
*
|
||||
* The result includes all necessary quoting and schema-prefixing.
|
||||
* The result includes all necessary quoting and schema-prefixing. We can
|
||||
* also pass back an indication of whether the function is variadic.
|
||||
*/
|
||||
static char *
|
||||
generate_function_name(Oid funcid, int nargs, Oid *argtypes)
|
||||
generate_function_name(Oid funcid, int nargs, Oid *argtypes,
|
||||
bool *is_variadic)
|
||||
{
|
||||
HeapTuple proctup;
|
||||
Form_pg_proc procform;
|
||||
@ -5343,6 +5357,7 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes)
|
||||
Oid p_funcid;
|
||||
Oid p_rettype;
|
||||
bool p_retset;
|
||||
int p_nvargs;
|
||||
Oid *p_true_typeids;
|
||||
|
||||
proctup = SearchSysCache(PROCOID,
|
||||
@ -5352,7 +5367,7 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes)
|
||||
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||
procform = (Form_pg_proc) GETSTRUCT(proctup);
|
||||
proname = NameStr(procform->proname);
|
||||
Assert(nargs == procform->pronargs);
|
||||
Assert(nargs >= procform->pronargs);
|
||||
|
||||
/*
|
||||
* The idea here is to schema-qualify only if the parser would fail to
|
||||
@ -5360,9 +5375,9 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes)
|
||||
* specified argtypes.
|
||||
*/
|
||||
p_result = func_get_detail(list_make1(makeString(proname)),
|
||||
NIL, nargs, argtypes,
|
||||
NIL, nargs, argtypes, false,
|
||||
&p_funcid, &p_rettype,
|
||||
&p_retset, &p_true_typeids);
|
||||
&p_retset, &p_nvargs, &p_true_typeids);
|
||||
if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) &&
|
||||
p_funcid == funcid)
|
||||
nspname = NULL;
|
||||
@ -5371,6 +5386,34 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes)
|
||||
|
||||
result = quote_qualified_identifier(nspname, proname);
|
||||
|
||||
/* Check variadic-ness if caller cares */
|
||||
if (is_variadic)
|
||||
{
|
||||
/* XXX change this if we simplify code in FuncnameGetCandidates */
|
||||
Datum proargmodes;
|
||||
bool isnull;
|
||||
|
||||
*is_variadic = false;
|
||||
|
||||
proargmodes = SysCacheGetAttr(PROCOID, proctup,
|
||||
Anum_pg_proc_proargmodes, &isnull);
|
||||
if (!isnull)
|
||||
{
|
||||
ArrayType *ar = DatumGetArrayTypeP(proargmodes);
|
||||
char *argmodes;
|
||||
int j;
|
||||
|
||||
argmodes = ARR_DATA_PTR(ar);
|
||||
j = ARR_DIMS(ar)[0] - 1;
|
||||
if (j >= 0 && argmodes[j] == PROARGMODE_VARIADIC)
|
||||
{
|
||||
/* "any" variadics are not treated as variadics for listing */
|
||||
if (procform->proargtypes.values[j] != ANYOID)
|
||||
*is_variadic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSysCache(proctup);
|
||||
|
||||
return result;
|
||||
|
Reference in New Issue
Block a user