aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_func.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r--src/backend/parser/parse_func.c75
1 files changed, 52 insertions, 23 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 3d44c2520be..3bb5c452a8e 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.202 2008/03/26 21:10:38 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.203 2008/07/16 01:30:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,14 +56,14 @@ static void unknown_attribute(ParseState *pstate, Node *relref, char *attname,
* intended to be used only to deliver an appropriate error message,
* not to affect the semantics. When is_column is true, we should have
* a single argument (the putative table), unqualified function name
- * equal to the column name, and no aggregate decoration.
+ * equal to the column name, and no aggregate or variadic decoration.
*
* The argument expressions (in fargs) must have been transformed already.
*/
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
- bool agg_star, bool agg_distinct, bool is_column,
- int location)
+ bool agg_star, bool agg_distinct, bool func_variadic,
+ bool is_column, int location)
{
Oid rettype;
Oid funcid;
@@ -75,6 +75,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
Oid *declared_arg_types;
Node *retval;
bool retset;
+ int nvargs;
FuncDetailCode fdresult;
/*
@@ -126,9 +127,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* Check for column projection: if function has one argument, and that
* argument is of complex type, and function name is not qualified, then
* the "function call" could be a projection. We also check that there
- * wasn't any aggregate decoration.
+ * wasn't any aggregate or variadic decoration.
*/
- if (nargs == 1 && !agg_star && !agg_distinct && list_length(funcname) == 1)
+ if (nargs == 1 && !agg_star && !agg_distinct && !func_variadic &&
+ list_length(funcname) == 1)
{
Oid argtype = actual_arg_types[0];
@@ -153,11 +155,15 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* func_get_detail looks up the function in the catalogs, does
* disambiguation for polymorphic functions, handles inheritance, and
* returns the funcid and type and set or singleton status of the
- * function's return value. it also returns the true argument types to
- * the function.
+ * function's return value. It also returns the true argument types to
+ * the function. (In the case of a variadic function call, the reported
+ * "true" types aren't really what is in pg_proc: the variadic argument is
+ * replaced by a suitable number of copies of its element type. We'll fix
+ * it up below.)
*/
fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
- &funcid, &rettype, &retset,
+ !func_variadic,
+ &funcid, &rettype, &retset, &nvargs,
&declared_arg_types);
if (fdresult == FUNCDETAIL_COERCION)
{
@@ -242,6 +248,34 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
/* perform the necessary typecasting of arguments */
make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types);
+ /*
+ * If it's a variadic function call, transform the last nvargs arguments
+ * into an array --- unless it's an "any" variadic.
+ */
+ if (nvargs > 0 && declared_arg_types[nargs - 1] != ANYOID)
+ {
+ ArrayExpr *newa = makeNode(ArrayExpr);
+ int non_var_args = nargs - nvargs;
+ List *vargs;
+
+ Assert(non_var_args >= 0);
+ vargs = list_copy_tail(fargs, non_var_args);
+ fargs = list_truncate(fargs, non_var_args);
+
+ newa->elements = vargs;
+ /* assume all the variadic arguments were coerced to the same type */
+ newa->element_typeid = exprType((Node *) linitial(vargs));
+ newa->array_typeid = get_array_type(newa->element_typeid);
+ if (!OidIsValid(newa->array_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(newa->element_typeid))));
+ newa->multidims = false;
+
+ fargs = lappend(fargs, newa);
+ }
+
/* build the appropriate output structure */
if (fdresult == FUNCDETAIL_NORMAL)
{
@@ -668,21 +702,12 @@ func_select_candidate(int nargs,
* Find the named function in the system catalogs.
*
* Attempt to find the named function in the system catalogs with
- * arguments exactly as specified, so that the normal case
- * (exact match) is as quick as possible.
+ * arguments exactly as specified, so that the normal case (exact match)
+ * is as quick as possible.
*
* If an exact match isn't found:
* 1) check for possible interpretation as a type coercion request
- * 2) get a vector of all possible input arg type arrays constructed
- * from the superclasses of the original input arg types
- * 3) get a list of all possible argument type arrays to the function
- * with given name and number of arguments
- * 4) for each input arg type array from vector #1:
- * a) find how many of the function arg type arrays from list #2
- * it can be coerced to
- * b) if the answer is one, we have our function
- * c) if the answer is more than one, attempt to resolve the conflict
- * d) if the answer is zero, try the next array from vector #1
+ * 2) apply the ambiguous-function resolution rules
*
* Note: we rely primarily on nargs/argtypes as the argument description.
* The actual expression node list is passed in fargs so that we can check
@@ -694,16 +719,18 @@ func_get_detail(List *funcname,
List *fargs,
int nargs,
Oid *argtypes,
+ bool expand_variadic,
Oid *funcid, /* return value */
Oid *rettype, /* return value */
bool *retset, /* return value */
+ int *nvargs, /* return value */
Oid **true_typeids) /* return value */
{
FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
/* Get list of possible candidates from namespace search */
- raw_candidates = FuncnameGetCandidates(funcname, nargs);
+ raw_candidates = FuncnameGetCandidates(funcname, nargs, expand_variadic);
/*
* Quickly check if there is an exact match to the input datatypes (there
@@ -786,6 +813,7 @@ func_get_detail(List *funcname,
*funcid = InvalidOid;
*rettype = targetType;
*retset = false;
+ *nvargs = 0;
*true_typeids = argtypes;
return FUNCDETAIL_COERCION;
}
@@ -835,6 +863,7 @@ func_get_detail(List *funcname,
FuncDetailCode result;
*funcid = best_candidate->oid;
+ *nvargs = best_candidate->nvargs;
*true_typeids = best_candidate->args;
ftup = SearchSysCache(PROCOID,
@@ -1189,7 +1218,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
{
FuncCandidateList clist;
- clist = FuncnameGetCandidates(funcname, nargs);
+ clist = FuncnameGetCandidates(funcname, nargs, false);
while (clist)
{