Re: variadic function support

"Pavel Stehule" <[email protected]>
Newsgroups gmane.comp.db.postgresql.devel.patches
Message-ID <[email protected]>
Hello

this version is WIP - I have to clean comments, and will do some
documentation. But I am sure, I am not able explain this feature in
english well. Please, can some body help me with documentation? So
now, plpgsql is more/less ruby :)

postgres=# select myleast(variadic array[1,2,3,4,-1]);
 myleast
---------
      -1
(1 row)

postgres=# select myleast(variadic array[1.1, -5.5]);
 myleast
---------
    -5.5
(1 row)

postgres=# --test with empty variadic call parameter
postgres=# select myleast(variadic array[]::int[]);
 myleast
---------

(1 row)
postgres=# select myleast(1.1,-5.5);
 myleast
---------
    -5.5

regards
Pavel

2008/7/14 Pavel Stehule <[email protected]>:
> 2008/7/14 Tom Lane <[email protected]>:
>> "Pavel Stehule" <[email protected]> writes:
>>> 2008/7/14 Tom Lane <[email protected]>:
>>>> Are you intending to change this right now and resubmit, or is it
>>>> work for later?
>>
>>> I prefer separate it to other patch.
>>
>> It seems a fairly important part of the feature, especially given the
>> connection to the zero-argument issue.
>
> ok tomorrow I have some work, but I can do it to Friday.
>
> regards
> Pavel Stehule
>>
>>                        regards, tom lane
>>
>


-- 
Sent via pgsql-patches mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches
variadic.2.0.2.diff (text/x-patch, 42.4 KB)
*** ./doc/src/sgml/ref/create_function.sgml.orig	2008-07-14 09:11:54.000000000 +0200
--- ./doc/src/sgml/ref/create_function.sgml	2008-07-14 09:14:37.000000000 +0200
***************
*** 102,108 ****
       <listitem>
        <para>
         The mode of an argument: either <literal>IN</>, <literal>OUT</>,
!        or <literal>INOUT</>.  If omitted, the default is <literal>IN</>.
        </para>
       </listitem>
      </varlistentry>
--- 102,109 ----
       <listitem>
        <para>
         The mode of an argument: either <literal>IN</>, <literal>OUT</>,
!        <literal>INOUT</> or <literal>VARIADIC</literal>.  If omitted, 
!        the default is <literal>IN</>.
        </para>
       </listitem>
      </varlistentry>
*** ./doc/src/sgml/xfunc.sgml.orig	2008-07-14 09:12:00.000000000 +0200
--- ./doc/src/sgml/xfunc.sgml	2008-07-14 09:14:37.000000000 +0200
***************
*** 578,584 ****
  
      <para>
       Parameters can be marked as <literal>IN</> (the default),
!      <literal>OUT</>, or <literal>INOUT</>.  An <literal>INOUT</>
       parameter serves as both an input parameter (part of the calling
       argument list) and an output parameter (part of the result record type).
      </para>
--- 578,585 ----
  
      <para>
       Parameters can be marked as <literal>IN</> (the default),
!      <literal>OUT</>, <literal>INOUT</>, or <literal>VARIADIC</literal>.  
!      An <literal>INOUT</>
       parameter serves as both an input parameter (part of the calling
       argument list) and an output parameter (part of the result record type).
      </para>
***************
*** 805,810 ****
--- 806,833 ----
  </screen>
      </para>
     </sect2>
+ 
+    <sect2>
+     <title>Variadic <acronym>SQL</acronym> Functions</title>
+ 
+     <para>
+      <acronym>SQL</acronym> functions can be declared to accept
+      variable number of arguments.
+ <screen>
+ CREATE FUNCTION mleast(variadic numeric[]) RETURNS numeric AS $$
+     SELECT min($1[i])
+        FROM generate_subscripts($1,1) g(i);
+ $$ LANGUAGE SQL;
+ 
+ SELECT mleast(10, -1, 5, 4);
+  mleast 
+ --------
+      -1
+ (1 row)
+ </screen>
+     </para>
+    </sect2>
+ 
    </sect1>
  
    <sect1 id="xfunc-overload">
*** ./src/backend/catalog/namespace.c.orig	2008-07-14 09:12:08.000000000 +0200
--- ./src/backend/catalog/namespace.c	2008-07-14 14:58:31.000000000 +0200
***************
*** 38,43 ****
--- 38,44 ----
  #include "commands/dbcommands.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
+ #include "parser/parse_func.h"
  #include "storage/backendid.h"
  #include "storage/ipc.h"
  #include "utils/acl.h"
***************
*** 570,576 ****
   * identical entries in later namespaces.
   */
  FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs)
  {
  	FuncCandidateList resultList = NULL;
  	char	   *schemaname;
--- 571,577 ----
   * identical entries in later namespaces.
   */
  FuncCandidateList
! FuncnameGetCandidates(List *names, int nargs, bool transform_variadic)
  {
  	FuncCandidateList resultList = NULL;
  	char	   *schemaname;
***************
*** 606,614 ****
  		int			pronargs = procform->pronargs;
  		int			pathpos = 0;
  		FuncCandidateList newResult;
  
  		/* Ignore if it doesn't match requested argument count */
! 		if (nargs >= 0 && pronargs != nargs)
  			continue;
  
  		if (OidIsValid(namespaceId))
--- 607,656 ----
  		int			pronargs = procform->pronargs;
  		int			pathpos = 0;
  		FuncCandidateList newResult;
+ 		Oid	va_oid = InvalidOid;
+ 		bool	variadic = false;		/* true when arglist contains PROARGMODE_VARIADIC parameter */ 
+ 		bool	isnull;
+ 		Datum 		proargmodes;
+ 		
+ 		/* 
+ 		 * Search type of variadic argument,
+ 		 */
+ 		proargmodes = SysCacheGetAttr(PROCOID, proctup,
+ 								Anum_pg_proc_proargmodes, &isnull);
+ 		if (!isnull)
+ 		{
+ 			ArrayType	*ar = DatumGetArrayTypeP(proargmodes);
+ 			char		*argmodes;
+ 			int	j;
+ 
+ 			argmodes = ARR_DATA_PTR(ar);
+ 			for (j = 0; j < ARR_DIMS(ar)[0]; j++)
+ 				if (argmodes[j] == PROARGMODE_VARIADIC)
+ 				{
+ 					variadic = true;
+ 					switch (procform->proargtypes.values[j])
+ 					{
+ 						case ANYOID:
+ 							va_oid = ANYOID;
+ 							break;
+ 						case ANYARRAYOID:
+ 							va_oid = ANYELEMENTOID;
+ 							break;
+ 						default:
+ 							va_oid = get_element_type(procform->proargtypes.values[j]);
+ 							Assert(OidIsValid(va_oid));
+ 					}
+ 
+ 					break;
+ 				}
+ 		}
  
  		/* Ignore if it doesn't match requested argument count */
! 		if (nargs >= 0 && pronargs != nargs && !variadic)
! 			continue;
! 
! 		/* Ignore variadic function with less arguments */
! 		if (nargs >= 0 && pronargs > nargs && variadic)
  			continue;
  
  		if (OidIsValid(namespaceId))
***************
*** 676,683 ****
  				}
  				if (prevResult)
  				{
! 					/* We have a match with a previous result */
! 					Assert(pathpos != prevResult->pathpos);
  					if (pathpos > prevResult->pathpos)
  						continue;		/* keep previous result */
  					/* replace previous result */
--- 718,734 ----
  				}
  				if (prevResult)
  				{
! 					/* 
! 					 * We have a match with a previous result. Variadic functions should 
! 					 * be not unique - foo(numeric), foo(variadic numeric[]).
! 					 */
! 					if (pathpos == prevResult->pathpos)
! 						ereport(ERROR,
! 							(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
! 							 errmsg("function %s is not unique",
! 								func_signature_string(names, nargs,
! 												  procform->proargtypes.values))));
! 
  					if (pathpos > prevResult->pathpos)
  						continue;		/* keep previous result */
  					/* replace previous result */
***************
*** 689,706 ****
  		}
  
  		/*
! 		 * Okay to add it to result list
  		 */
! 		newResult = (FuncCandidateList)
! 			palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
! 				   + pronargs * sizeof(Oid));
  		newResult->pathpos = pathpos;
  		newResult->oid = HeapTupleGetOid(proctup);
- 		newResult->nargs = pronargs;
- 		memcpy(newResult->args, procform->proargtypes.values,
- 			   pronargs * sizeof(Oid));
- 
  		newResult->next = resultList;
  		resultList = newResult;
  	}
  
--- 740,784 ----
  		}
  
  		/*
! 		 * Okay to add it to result list - VARIADIC parameter isn't transformed when 
! 		 * we would show and work with function signature, etc pg_function_is_visible, 
! 		 * DROP FUNCTION (transform_variadic = false).
  		 */
! 		if (variadic && transform_variadic)
! 		{
! 			int	i;
! 
! 			Assert(nargs >= pronargs);
! 
! 			newResult = (FuncCandidateList)
! 				palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
! 					    + nargs * sizeof(Oid));
! 			newResult->nargs = nargs;
! 			newResult->nvargs = nargs - pronargs + 1;
! 			newResult->variadic_oid = va_oid;
! 			memcpy(newResult->args, procform->proargtypes.values,
! 				    (pronargs - 1) * sizeof(Oid));
! 
! 			/* Multiply variadic argument */
! 			for (i = pronargs - 1; i < nargs; i++)
! 				newResult->args[i] = va_oid;
! 		}
! 		else
! 		{
! 			newResult = (FuncCandidateList)
! 				palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
! 					   + pronargs * sizeof(Oid));
! 			newResult->nargs = pronargs;
! 			newResult->nvargs = 0;
! 			newResult->variadic_oid = 0;
! 			memcpy(newResult->args, procform->proargtypes.values,
! 				   pronargs * sizeof(Oid));
! 		}
! 
  		newResult->pathpos = pathpos;
  		newResult->oid = HeapTupleGetOid(proctup);
  		newResult->next = resultList;
+ 
  		resultList = newResult;
  	}
  
***************
*** 755,761 ****
  
  		visible = false;
  
! 		clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs);
  
  		for (; clist; clist = clist->next)
  		{
--- 833,839 ----
  
  		visible = false;
  
! 		clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs, false);
  
  		for (; clist; clist = clist->next)
  		{
*** ./src/backend/catalog/pg_aggregate.c.orig	2008-07-14 09:12:15.000000000 +0200
--- ./src/backend/catalog/pg_aggregate.c	2008-07-14 13:10:59.000000000 +0200
***************
*** 297,302 ****
--- 297,304 ----
  	FuncDetailCode fdresult;
  	AclResult	aclresult;
  	int			i;
+ 	int	nvargs;
+ 	Oid	va_oid;
  
  	/*
  	 * func_get_detail looks up the function in the catalogs, does
***************
*** 307,313 ****
  	 */
  	fdresult = func_get_detail(fnName, NIL, nargs, input_types,
  							   &fnOid, rettype, &retset,
! 							   &true_oid_array);
  
  	/* only valid case is a normal function not returning a set */
  	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
--- 309,316 ----
  	 */
  	fdresult = func_get_detail(fnName, NIL, nargs, input_types,
  							   &fnOid, rettype, &retset,
! 							   &true_oid_array,
! 							   &nvargs, &va_oid);
  
  	/* only valid case is a normal function not returning a set */
  	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
***************
*** 321,326 ****
--- 324,334 ----
  				 errmsg("function %s returns a set",
  						func_signature_string(fnName, nargs, input_types))));
  
+ 	if (nvargs > 0)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("variadic parameters not supported for aggregate functions")));
+ 
  	/*
  	 * If there are any polymorphic types involved, enforce consistency, and
  	 * possibly refine the result type.  It's OK if the result is still
*** ./src/backend/commands/functioncmds.c.orig	2008-07-12 12:44:56.000000000 +0200
--- ./src/backend/commands/functioncmds.c	2008-07-14 14:10:18.000000000 +0200
***************
*** 174,179 ****
--- 174,180 ----
  	Datum	   *paramNames;
  	int			outCount = 0;
  	bool		have_names = false;
+ 	int			varCount = 0; 	
  	ListCell   *x;
  	int			i;
  
***************
*** 228,242 ****
  					 errmsg("functions cannot accept set arguments")));
  
  		if (fp->mode != FUNC_PARAM_OUT)
  			inTypes[inCount++] = toid;
  
! 		if (fp->mode != FUNC_PARAM_IN)
  		{
  			if (outCount == 0)	/* save first OUT param's type */
  				*requiredResultType = toid;
  			outCount++;
  		}
  
  		allTypes[i] = ObjectIdGetDatum(toid);
  
  		paramModes[i] = CharGetDatum(fp->mode);
--- 229,271 ----
  					 errmsg("functions cannot accept set arguments")));
  
  		if (fp->mode != FUNC_PARAM_OUT)
+ 		{
  			inTypes[inCount++] = toid;
+ 			/* check if variadic argument is last IN argument */
+ 			if (varCount > 0 && fp->mode != FUNC_PARAM_OUT)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 						 errmsg("variadic parameter must be the last parameter to the function")));
+ 		}
  
! 		if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
  		{
  			if (outCount == 0)	/* save first OUT param's type */
  				*requiredResultType = toid;
  			outCount++;
  		}
  
+ 		if (fp->mode == FUNC_PARAM_VARIADIC)
+ 		{
+ 			if (varCount++ > 0)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 						 errmsg("function cannot accept two or more variadic parameters")));
+ 
+ 			/* check variadic parameter type */
+ 			switch (toid)
+ 			{
+ 				case ANYARRAYOID:
+ 				case ANYOID:
+ 					break;
+ 				default:
+ 					if (!OidIsValid(get_element_type(toid)))
+ 						ereport(ERROR,
+ 								(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 								 errmsg("variadic parameter must be an array")));
+ 			}
+ 		}
+ 
  		allTypes[i] = ObjectIdGetDatum(toid);
  
  		paramModes[i] = CharGetDatum(fp->mode);
***************
*** 253,259 ****
  	/* Now construct the proper outputs as needed */
  	*parameterTypes = buildoidvector(inTypes, inCount);
  
! 	if (outCount > 0)
  	{
  		*allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
  											 sizeof(Oid), true, 'i');
--- 282,288 ----
  	/* Now construct the proper outputs as needed */
  	*parameterTypes = buildoidvector(inTypes, inCount);
  
! 	if (outCount > 0 || varCount > 0)
  	{
  		*allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
  											 sizeof(Oid), true, 'i');
*** ./src/backend/nodes/copyfuncs.c.orig	2008-07-14 21:43:28.000000000 +0200
--- ./src/backend/nodes/copyfuncs.c	2008-07-14 21:49:49.000000000 +0200
***************
*** 1652,1657 ****
--- 1652,1658 ----
  	COPY_SCALAR_FIELD(agg_star);
  	COPY_SCALAR_FIELD(agg_distinct);
  	COPY_SCALAR_FIELD(location);
+ 	COPY_SCALAR_FIELD(variadic_expr);
  
  	return newnode;
  }
*** ./src/backend/nodes/equalfuncs.c.orig	2008-07-14 21:43:43.000000000 +0200
--- ./src/backend/nodes/equalfuncs.c	2008-07-14 21:49:57.000000000 +0200
***************
*** 1706,1711 ****
--- 1706,1712 ----
  	COMPARE_SCALAR_FIELD(agg_star);
  	COMPARE_SCALAR_FIELD(agg_distinct);
  	COMPARE_SCALAR_FIELD(location);
+ 	COMPARE_SCALAR_FIELD(variadic_expr);
  
  	return true;
  }
*** ./src/backend/nodes/outfuncs.c.orig	2008-07-14 21:44:16.000000000 +0200
--- ./src/backend/nodes/outfuncs.c	2008-07-14 21:54:37.000000000 +0200
***************
*** 1611,1616 ****
--- 1611,1617 ----
  	WRITE_BOOL_FIELD(agg_star);
  	WRITE_BOOL_FIELD(agg_distinct);
  	WRITE_INT_FIELD(location);
+ 	WRITE_NODE_FIELD(variadic_expr);
  }
  
  static void
*** ./src/backend/parser/gram.y.orig	2008-07-14 09:12:28.000000000 +0200
--- ./src/backend/parser/gram.y	2008-07-14 22:14:22.000000000 +0200
***************
*** 444,450 ****
  	UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
  	UPDATE USER USING
  
! 	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARYING
  	VERBOSE VERSION_P VIEW VOLATILE
  
  	WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
--- 444,450 ----
  	UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
  	UPDATE USER USING
  
! 	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
  	VERBOSE VERSION_P VIEW VOLATILE
  
  	WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
***************
*** 4204,4209 ****
--- 4204,4210 ----
  			| OUT_P									{ $$ = FUNC_PARAM_OUT; }
  			| INOUT									{ $$ = FUNC_PARAM_INOUT; }
  			| IN_P OUT_P							{ $$ = FUNC_PARAM_INOUT; }
+ 			| VARIADIC							{ $$ = FUNC_PARAM_VARIADIC; }
  		;
  
  /*
***************
*** 7863,7868 ****
--- 7864,7870 ----
  					n->agg_star = FALSE;
  					n->agg_distinct = FALSE;
  					n->location = @1;
+ 					n->variadic_expr = NULL;
  					$$ = (Node *)n;
  				}
  			| func_name '(' expr_list ')'
***************
*** 7873,7878 ****
--- 7875,7903 ----
  					n->agg_star = FALSE;
  					n->agg_distinct = FALSE;
  					n->location = @1;
+ 					n->variadic_expr = NULL;
+ 					$$ = (Node *)n;
+ 				}
+ 			| func_name '(' VARIADIC a_expr ')'
+ 				{
+ 					FuncCall *n = makeNode(FuncCall);
+ 					n->funcname = $1;
+ 					n->args = NIL;
+ 					n->agg_star = FALSE;
+ 					n->agg_distinct = FALSE;
+ 					n->location = @1;
+ 					n->variadic_expr = $4;
+ 					$$ = (Node *)n;
+ 				}
+ 			| func_name '(' expr_list VARIADIC a_expr ')'
+ 				{
+ 					FuncCall *n = makeNode(FuncCall);
+ 					n->funcname = $1;
+ 					n->args = $3;
+ 					n->agg_star = FALSE;
+ 					n->agg_distinct = FALSE;
+ 					n->location = @1;
+ 					n->variadic_expr = $5;
  					$$ = (Node *)n;
  				}
  			| func_name '(' ALL expr_list ')'
***************
*** 7887,7892 ****
--- 7912,7918 ----
  					 * for that in FuncCall at the moment.
  					 */
  					n->location = @1;
+ 					n->variadic_expr = NULL;
  					$$ = (Node *)n;
  				}
  			| func_name '(' DISTINCT expr_list ')'
***************
*** 7897,7902 ****
--- 7923,7929 ----
  					n->agg_star = FALSE;
  					n->agg_distinct = TRUE;
  					n->location = @1;
+ 					n->variadic_expr = NULL;
  					$$ = (Node *)n;
  				}
  			| func_name '(' '*' ')'
***************
*** 7917,7922 ****
--- 7944,7950 ----
  					n->agg_star = TRUE;
  					n->agg_distinct = FALSE;
  					n->location = @1;
+ 					n->variadic_expr = NULL;
  					$$ = (Node *)n;
  				}
  			| CURRENT_DATE
*** ./src/backend/parser/keywords.c.orig	2008-07-14 09:12:34.000000000 +0200
--- ./src/backend/parser/keywords.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 393,398 ****
--- 393,399 ----
  	{"value", VALUE_P, UNRESERVED_KEYWORD},
  	{"values", VALUES, COL_NAME_KEYWORD},
  	{"varchar", VARCHAR, COL_NAME_KEYWORD},
+ 	{"variadic", VARIADIC, UNRESERVED_KEYWORD},
  	{"varying", VARYING, UNRESERVED_KEYWORD},
  	{"verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD},
  	{"version", VERSION_P, UNRESERVED_KEYWORD},
*** ./src/backend/parser/parse_expr.c.orig	2008-07-14 22:17:06.000000000 +0200
--- ./src/backend/parser/parse_expr.c	2008-07-14 23:01:35.000000000 +0200
***************
*** 359,365 ****
  									   list_make1(n),
  									   list_make1(result),
  									   false, false, true,
! 									   -1);
  		}
  	}
  	/* process trailing subscripts, if any */
--- 359,365 ----
  									   list_make1(n),
  									   list_make1(result),
  									   false, false, true,
! 									   -1, NULL);
  		}
  	}
  	/* process trailing subscripts, if any */
***************
*** 482,488 ****
  											 list_make1(makeString(name2)),
  											 list_make1(node),
  											 false, false, true,
! 											 cref->location);
  				}
  				break;
  			}
--- 482,489 ----
  											 list_make1(makeString(name2)),
  											 list_make1(node),
  											 false, false, true,
! 											 cref->location,
! 											 NULL);
  				}
  				break;
  			}
***************
*** 512,518 ****
  											 list_make1(makeString(name3)),
  											 list_make1(node),
  											 false, false, true,
! 											 cref->location);
  				}
  				break;
  			}
--- 513,520 ----
  											 list_make1(makeString(name3)),
  											 list_make1(node),
  											 false, false, true,
! 											 cref->location,
! 											 NULL);
  				}
  				break;
  			}
***************
*** 553,559 ****
  											 list_make1(makeString(name4)),
  											 list_make1(node),
  											 false, false, true,
! 											 cref->location);
  				}
  				break;
  			}
--- 555,562 ----
  											 list_make1(makeString(name4)),
  											 list_make1(node),
  											 false, false, true,
! 											 cref->location,
! 											 NULL);
  				}
  				break;
  			}
***************
*** 1017,1022 ****
--- 1020,1026 ----
  {
  	List	   *targs;
  	ListCell   *args;
+ 	Node	   *variadic_expr;
  
  	/*
  	 * Transform the list of arguments.  We use a shallow list copy and then
***************
*** 1031,1036 ****
--- 1035,1042 ----
  		lfirst(args) = transformExpr(pstate,
  									 (Node *) lfirst(args));
  	}
+ 	
+ 	variadic_expr = transformExpr(pstate, fn->variadic_expr);
  
  	return ParseFuncOrColumn(pstate,
  							 fn->funcname,
***************
*** 1038,1044 ****
  							 fn->agg_star,
  							 fn->agg_distinct,
  							 false,
! 							 fn->location);
  }
  
  static Node *
--- 1044,1051 ----
  							 fn->agg_star,
  							 fn->agg_distinct,
  							 false,
! 							 fn->location,
! 							 variadic_expr);
  }
  
  static Node *
*** ./src/backend/parser/parse_func.c.orig	2008-07-14 09:12:41.000000000 +0200
--- ./src/backend/parser/parse_func.c	2008-07-14 23:54:45.000000000 +0200
***************
*** 63,69 ****
  Node *
  ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool is_column,
! 				  int location)
  {
  	Oid			rettype;
  	Oid			funcid;
--- 63,69 ----
  Node *
  ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool is_column,
! 				  int location, Node *variadic_expr)
  {
  	Oid			rettype;
  	Oid			funcid;
***************
*** 76,81 ****
--- 76,83 ----
  	Node	   *retval;
  	bool		retset;
  	FuncDetailCode fdresult;
+ 	int			nvargs;
+ 	Oid			va_oid;
  
  	/*
  	 * Most of the rest of the parser just assumes that functions do not have
***************
*** 83,89 ****
  	 * against array overruns, etc.  Of course, this may not be a function,
  	 * but the test doesn't hurt.
  	 */
! 	if (list_length(fargs) > FUNC_MAX_ARGS)
  		ereport(ERROR,
  				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
  				 errmsg("cannot pass more than %d arguments to a function",
--- 85,91 ----
  	 * against array overruns, etc.  Of course, this may not be a function,
  	 * but the test doesn't hurt.
  	 */
! 	if (list_length(fargs) + (variadic_expr != 0 ? 1:0) > FUNC_MAX_ARGS)
  		ereport(ERROR,
  				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
  				 errmsg("cannot pass more than %d arguments to a function",
***************
*** 139,145 ****
--- 141,152 ----
  											first_arg,
  											location);
  			if (retval)
+ 			{
+ 				if (variadic_expr)
+ 					elog(ERROR, "column projection must not have variadic parameter");
+ 
  				return retval;
+ 			}
  
  			/*
  			 * If ParseComplexProjection doesn't recognize it as a projection,
***************
*** 149,154 ****
--- 156,177 ----
  	}
  
  	/*
+ 	 * Magic with variadic_expr
+ 	 * 
+ 	 */
+ 	if (variadic_expr != NULL)
+ 	{
+ 		Oid va_el_oid = get_element_type(exprType(variadic_expr));		
+ 
+ 		if (!OidIsValid(va_el_oid))
+ 			elog(ERROR, "variadic parameter must be an array");
+ 
+ 		/* For this moment I emulate one variadic argument. */
+ 		actual_arg_types[nargs++] = va_el_oid;
+ 	}
+     
+ 
+ 	/*
  	 * Okay, it's not a column projection, so it must really be a function.
  	 * func_get_detail looks up the function in the catalogs, does
  	 * disambiguation for polymorphic functions, handles inheritance, and
***************
*** 158,164 ****
  	 */
  	fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
  							   &funcid, &rettype, &retset,
! 							   &declared_arg_types);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
  		/*
--- 181,188 ----
  	 */
  	fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
  							   &funcid, &rettype, &retset,
! 							   &declared_arg_types,
! 							   &nvargs, &va_oid);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
  		/*
***************
*** 229,234 ****
--- 253,337 ----
  	}
  
  	/*
+ 	 * variadic_expr implicates variadic_function, check it!
+ 	 */
+ 	if (variadic_expr != NULL)
+ 	{
+ 		if (nvargs == 0)
+ 			elog(ERROR, "using variadic call on non variadic function");
+ 	
+ 		/*
+ 		 * Executor hasn't enough information for unpacking 
+ 		 * variadic call arguments into variadic argumenents.
+ 		 * So I have to prohibit this call.
+ 		 */
+ 		if (va_oid == ANYOID)
+ 			elog(ERROR, "cannot unpack variadic call arguments to variadic any arguments");
+ 	}
+ 
+ 	/*
+ 	 * Last nvargs arguments are transformed to array when function is
+ 	 * non "any" variadic.
+ 	 */
+ 	if (nvargs > 0 && va_oid != ANYOID)
+ 	{
+ 		A_ArrayExpr *n = makeNode(A_ArrayExpr);
+ 		Node	*tn;
+ 
+ 		/*
+ 		 * without variadic call argument transform
+ 		 * arguments into variadic array parameter
+ 		 */
+ 		if (nvargs < nargs)
+ 		{
+ 			if (variadic_expr == NULL)
+ 			{
+ 				int 	non_var_args = nargs - nvargs;
+ 				List	*vargs;
+ 
+ 				vargs = list_copy_tail(fargs, non_var_args);
+ 				fargs = list_truncate(fargs, non_var_args);
+ 				n->elements = vargs;
+ 				tn = transformExpr(pstate, (Node *) n);
+ 				fargs = lappend(fargs, tn);
+ 			}	
+ 			else
+ 				/* attach variadic call argument */
+ 				fargs = lappend(fargs, variadic_expr);
+ 		}
+ 		else
+ 		{
+ 			if (variadic_expr == NULL)
+ 			{
+ 				/* array from all arguments */
+ 				n->elements = fargs;
+ 				tn= transformExpr(pstate, (Node *) n);
+ 				fargs = list_make1(tn);
+ 			}
+ 			else
+ 				/* forward variadic call argument */
+ 				fargs = list_make1(variadic_expr);
+ 		}
+ 
+ 		/* 
+ 		 * Now we have to correct argument's metadata used in
+ 		 * enforce_generic_type_consistency and make_fn_arguments. These
+ 		 * functions needs actual values of nargs, actual_arg_types and
+ 		 * real_arg_types.
+ 		 */
+ 		nargs = nargs - nvargs + 1;
+ 		if (variadic_expr == NULL)
+ 			actual_arg_types[nargs - 1] = ((ArrayExpr *) tn)->array_typeid;
+ 		else
+ 			actual_arg_types[nargs - 1] = exprType(variadic_expr);
+ 
+ 		if (va_oid != ANYELEMENTOID)
+ 			declared_arg_types[nargs - 1] = get_array_type(va_oid);
+ 		else
+ 			declared_arg_types[nargs - 1] = ANYARRAYOID;
+ 	} 
+ 
+ 	/*
  	 * enforce consistency with polymorphic argument and return types,
  	 * possibly adjusting return type or declared_arg_types (which will be
  	 * used as the cast destination by make_fn_arguments)
***************
*** 697,709 ****
  				Oid *funcid,	/* return value */
  				Oid *rettype,	/* return value */
  				bool *retset,	/* 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);
  
  	/*
  	 * Quickly check if there is an exact match to the input datatypes (there
--- 800,814 ----
  				Oid *funcid,	/* return value */
  				Oid *rettype,	/* return value */
  				bool *retset,	/* return value */
! 				Oid **true_typeids,		/* return value */
! 				int *nvargs,	/* return value */
! 				Oid *va_oid)	/* return value */
  {
  	FuncCandidateList raw_candidates;
  	FuncCandidateList best_candidate;
  
  	/* Get list of possible candidates from namespace search */
! 	raw_candidates = FuncnameGetCandidates(funcname, nargs, true);
  
  	/*
  	 * Quickly check if there is an exact match to the input datatypes (there
***************
*** 787,792 ****
--- 892,899 ----
  					*rettype = targetType;
  					*retset = false;
  					*true_typeids = argtypes;
+ 					*nvargs = 0;
+ 					*va_oid = InvalidOid;
  					return FUNCDETAIL_COERCION;
  				}
  			}
***************
*** 836,841 ****
--- 943,950 ----
  
  		*funcid = best_candidate->oid;
  		*true_typeids = best_candidate->args;
+ 		*nvargs = best_candidate->nvargs;
+ 		*va_oid = best_candidate->variadic_oid;
  
  		ftup = SearchSysCache(PROCOID,
  							  ObjectIdGetDatum(best_candidate->oid),
***************
*** 1189,1195 ****
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs);
  
  	while (clist)
  	{
--- 1298,1304 ----
  {
  	FuncCandidateList clist;
  
! 	clist = FuncnameGetCandidates(funcname, nargs, false);
  
  	while (clist)
  	{
*** ./src/backend/utils/adt/regproc.c.orig	2008-07-14 09:12:47.000000000 +0200
--- ./src/backend/utils/adt/regproc.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 131,137 ****
  	 * pg_proc entries in the current search path.
  	 */
  	names = stringToQualifiedNameList(pro_name_or_oid);
! 	clist = FuncnameGetCandidates(names, -1);
  
  	if (clist == NULL)
  		ereport(ERROR,
--- 131,137 ----
  	 * pg_proc entries in the current search path.
  	 */
  	names = stringToQualifiedNameList(pro_name_or_oid);
! 	clist = FuncnameGetCandidates(names, -1, false);
  
  	if (clist == NULL)
  		ereport(ERROR,
***************
*** 189,195 ****
  			 * Would this proc be found (uniquely!) by regprocin? If not,
  			 * qualify it.
  			 */
! 			clist = FuncnameGetCandidates(list_make1(makeString(proname)), -1);
  			if (clist != NULL && clist->next == NULL &&
  				clist->oid == proid)
  				nspname = NULL;
--- 189,195 ----
  			 * Would this proc be found (uniquely!) by regprocin? If not,
  			 * qualify it.
  			 */
! 			clist = FuncnameGetCandidates(list_make1(makeString(proname)), -1, false);
  			if (clist != NULL && clist->next == NULL &&
  				clist->oid == proid)
  				nspname = NULL;
***************
*** 276,282 ****
  	 */
  	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
  
! 	clist = FuncnameGetCandidates(names, nargs);
  
  	for (; clist; clist = clist->next)
  	{
--- 276,282 ----
  	 */
  	parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
  
! 	clist = FuncnameGetCandidates(names, nargs, false);
  
  	for (; clist; clist = clist->next)
  	{
*** ./src/backend/utils/adt/ruleutils.c.orig	2008-07-14 09:12:55.000000000 +0200
--- ./src/backend/utils/adt/ruleutils.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 5344,5349 ****
--- 5344,5351 ----
  	Oid			p_rettype;
  	bool		p_retset;
  	Oid		   *p_true_typeids;
+ 	int	nvargs;
+ 	Oid	va_oid;
  
  	proctup = SearchSysCache(PROCOID,
  							 ObjectIdGetDatum(funcid),
***************
*** 5362,5368 ****
  	p_result = func_get_detail(list_make1(makeString(proname)),
  							   NIL, nargs, argtypes,
  							   &p_funcid, &p_rettype,
! 							   &p_retset, &p_true_typeids);
  	if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) &&
  		p_funcid == funcid)
  		nspname = NULL;
--- 5364,5371 ----
  	p_result = func_get_detail(list_make1(makeString(proname)),
  							   NIL, nargs, argtypes,
  							   &p_funcid, &p_rettype,
! 							   &p_retset, &p_true_typeids,
! 							   &nvargs, &va_oid);
  	if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) &&
  		p_funcid == funcid)
  		nspname = NULL;
*** ./src/backend/utils/fmgr/funcapi.c.orig	2008-07-14 09:13:01.000000000 +0200
--- ./src/backend/utils/fmgr/funcapi.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 844,850 ****
  		numoutargs = 0;
  		for (i = 0; i < numargs; i++)
  		{
! 			if (argmodes[i] == PROARGMODE_IN)
  				continue;
  			Assert(argmodes[i] == PROARGMODE_OUT ||
  				   argmodes[i] == PROARGMODE_INOUT);
--- 844,850 ----
  		numoutargs = 0;
  		for (i = 0; i < numargs; i++)
  		{
! 			if (argmodes[i] == PROARGMODE_IN || argmodes[i] == PROARGMODE_VARIADIC)
  				continue;
  			Assert(argmodes[i] == PROARGMODE_OUT ||
  				   argmodes[i] == PROARGMODE_INOUT);
***************
*** 994,1000 ****
  	{
  		char	   *pname;
  
! 		if (argmodes[i] == PROARGMODE_IN)
  			continue;
  		Assert(argmodes[i] == PROARGMODE_OUT ||
  			   argmodes[i] == PROARGMODE_INOUT);
--- 994,1000 ----
  	{
  		char	   *pname;
  
! 		if (argmodes[i] == PROARGMODE_IN || argmodes[i] == PROARGMODE_VARIADIC)
  			continue;
  		Assert(argmodes[i] == PROARGMODE_OUT ||
  			   argmodes[i] == PROARGMODE_INOUT);
*** ./src/bin/pg_dump/pg_dump.c.orig	2008-07-14 09:13:08.000000000 +0200
--- ./src/bin/pg_dump/pg_dump.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 6435,6449 ****
  		{
  			switch (argmodes[j][0])
  			{
! 				case 'i':
  					argmode = "";
  					break;
! 				case 'o':
  					argmode = "OUT ";
  					break;
! 				case 'b':
  					argmode = "INOUT ";
  					break;
  				default:
  					write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
  					argmode = "";
--- 6435,6452 ----
  		{
  			switch (argmodes[j][0])
  			{
! 				case PROARGMODE_IN:
  					argmode = "";
  					break;
! 				case PROARGMODE_OUT:
  					argmode = "OUT ";
  					break;
! 				case PROARGMODE_INOUT:
  					argmode = "INOUT ";
  					break;
+ 				case PROARGMODE_VARIADIC:
+ 					argmode = "VARIADIC ";
+ 					break;
  				default:
  					write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
  					argmode = "";
*** ./src/bin/psql/describe.c.orig	2008-07-12 12:44:56.000000000 +0200
--- ./src/bin/psql/describe.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 205,210 ****
--- 205,211 ----
  					  "          WHEN p.proargmodes[s.i] = 'i' THEN ''\n"
  					  "          WHEN p.proargmodes[s.i] = 'o' THEN 'OUT '\n"
  					"          WHEN p.proargmodes[s.i] = 'b' THEN 'INOUT '\n"
+ 					"          WHEN p.proargmodes[s.i] = 'v' THEN 'VARIADIC '\n"
  					  "        END ||\n"
  					  "        CASE\n"
  			 "          WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
*** ./src/include/catalog/namespace.h.orig	2008-07-14 09:13:21.000000000 +0200
--- ./src/include/catalog/namespace.h	2008-07-14 09:14:37.000000000 +0200
***************
*** 29,34 ****
--- 29,36 ----
  	int			pathpos;		/* for internal use of namespace lookup */
  	Oid			oid;			/* the function or operator's OID */
  	int			nargs;			/* number of arg types returned */
+ 	int			nvargs;			/* number of variadic arguments */
+ 	Oid			variadic_oid;		/* Oid of variadic argument */
  	Oid			args[1];		/* arg types --- VARIABLE LENGTH ARRAY */
  }	*FuncCandidateList;	/* VARIABLE LENGTH STRUCT */
  
***************
*** 51,57 ****
  extern Oid	TypenameGetTypid(const char *typname);
  extern bool TypeIsVisible(Oid typid);
  
! extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs);
  extern bool FunctionIsVisible(Oid funcid);
  
  extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
--- 53,60 ----
  extern Oid	TypenameGetTypid(const char *typname);
  extern bool TypeIsVisible(Oid typid);
  
! extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs,
! 							    bool transform_variadic);
  extern bool FunctionIsVisible(Oid funcid);
  
  extern Oid	OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
*** ./src/include/catalog/pg_proc.h.orig	2008-07-14 02:51:45.000000000 +0200
--- ./src/include/catalog/pg_proc.h	2008-07-14 09:14:37.000000000 +0200
***************
*** 4472,4476 ****
--- 4472,4477 ----
  #define PROARGMODE_IN		'i'
  #define PROARGMODE_OUT		'o'
  #define PROARGMODE_INOUT	'b'
+ #define PROARGMODE_VARIADIC	'v'
  
  #endif   /* PG_PROC_H */
*** ./src/include/nodes/parsenodes.h.orig	2008-07-14 09:13:36.000000000 +0200
--- ./src/include/nodes/parsenodes.h	2008-07-14 21:57:18.000000000 +0200
***************
*** 262,267 ****
--- 262,268 ----
  	bool		agg_star;		/* argument was really '*' */
  	bool		agg_distinct;	/* arguments were labeled DISTINCT */
  	int			location;		/* token location, or -1 if unknown */
+ 	Node	   *variadic_expr;	/* when last parameter is array of variadic arguments */
  } FuncCall;
  
  /*
***************
*** 1568,1574 ****
  	/* the assigned enum values appear in pg_proc, don't change 'em! */
  	FUNC_PARAM_IN = 'i',		/* input only */
  	FUNC_PARAM_OUT = 'o',		/* output only */
! 	FUNC_PARAM_INOUT = 'b'		/* both */
  } FunctionParameterMode;
  
  typedef struct FunctionParameter
--- 1569,1576 ----
  	/* the assigned enum values appear in pg_proc, don't change 'em! */
  	FUNC_PARAM_IN = 'i',		/* input only */
  	FUNC_PARAM_OUT = 'o',		/* output only */
! 	FUNC_PARAM_INOUT = 'b',		/* both */
! 	FUNC_PARAM_VARIADIC = 'v'	/* variadic */
  } FunctionParameterMode;
  
  typedef struct FunctionParameter
*** ./src/include/parser/parse_func.h.orig	2008-07-14 09:13:43.000000000 +0200
--- ./src/include/parser/parse_func.h	2008-07-14 22:25:12.000000000 +0200
***************
*** 44,55 ****
  extern Node *ParseFuncOrColumn(ParseState *pstate,
  				  List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool is_column,
! 				  int location);
  
  extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
  				int nargs, Oid *argtypes,
  				Oid *funcid, Oid *rettype,
! 				bool *retset, Oid **true_typeids);
  
  extern int func_match_argtypes(int nargs,
  					Oid *input_typeids,
--- 44,56 ----
  extern Node *ParseFuncOrColumn(ParseState *pstate,
  				  List *funcname, List *fargs,
  				  bool agg_star, bool agg_distinct, bool is_column,
! 				  int location, Node *variadic_expr);
  
  extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
  				int nargs, Oid *argtypes,
  				Oid *funcid, Oid *rettype,
! 				bool *retset, Oid **true_typeids,
! 				int *nvargs, Oid *va_oid);
  
  extern int func_match_argtypes(int nargs,
  					Oid *input_typeids,
*** ./src/interfaces/ecpg/preproc/preproc.y.orig	2008-06-26 10:04:05.000000000 +0200
--- ./src/interfaces/ecpg/preproc/preproc.y	2008-07-14 09:14:37.000000000 +0200
***************
*** 489,495 ****
  	UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
  	UPDATE USER USING
  
! 	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARYING
  	VERBOSE VERSION_P VIEW VOLATILE
  	WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
  
--- 489,495 ----
  	UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
  	UPDATE USER USING
  
! 	VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
  	VERBOSE VERSION_P VIEW VOLATILE
  	WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
  
***************
*** 6667,6672 ****
--- 6667,6673 ----
  		| VALIDATOR			{ $$ = make_str("validator"); }
  		| VALUE_P			{ $$ = make_str("value"); }
  		| VARYING			{ $$ = make_str("varying"); }
+ 		| VARIADIC			{ $$ = make_str("variadic"); }
  		| VERSION_P			{ $$ = make_str("version"); }
  		| VIEW				{ $$ = make_str("view"); }
  		| VOLATILE			{ $$ = make_str("volatile"); }
*** ./src/pl/plpgsql/src/pl_comp.c.orig	2008-07-14 09:13:56.000000000 +0200
--- ./src/pl/plpgsql/src/pl_comp.c	2008-07-14 09:14:37.000000000 +0200
***************
*** 426,432 ****
  				{
  					argitemtype = PLPGSQL_NSTYPE_VAR;
  					/* input argument vars are forced to be CONSTANT */
! 					if (argmode == PROARGMODE_IN)
  						((PLpgSQL_var *) argvariable)->isconst = true;
  				}
  				else
--- 426,432 ----
  				{
  					argitemtype = PLPGSQL_NSTYPE_VAR;
  					/* input argument vars are forced to be CONSTANT */
! 					if (argmode == PROARGMODE_IN || argmode == PROARGMODE_VARIADIC)
  						((PLpgSQL_var *) argvariable)->isconst = true;
  				}
  				else
***************
*** 436,442 ****
  				}
  
  				/* Remember arguments in appropriate arrays */
! 				if (argmode == PROARGMODE_IN || argmode == PROARGMODE_INOUT)
  					in_arg_varnos[num_in_args++] = argvariable->dno;
  				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_INOUT)
  					out_arg_variables[num_out_args++] = argvariable;
--- 436,443 ----
  				}
  
  				/* Remember arguments in appropriate arrays */
! 				if (argmode == PROARGMODE_IN || argmode == PROARGMODE_INOUT
! 					    || argmode == PROARGMODE_VARIADIC)
  					in_arg_varnos[num_in_args++] = argvariable->dno;
  				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_INOUT)
  					out_arg_variables[num_out_args++] = argvariable;
*** ./src/test/regress/expected/plpgsql.out.orig	2008-07-14 09:14:03.000000000 +0200
--- ./src/test/regress/expected/plpgsql.out	2008-07-14 15:06:36.000000000 +0200
***************
*** 3544,3546 ****
--- 3544,3621 ----
  
  drop function catch();
  drop function case_test(bigint);
+ -- variadic fuction test
+ create or replace function vari(variadic int[]) 
+ returns void as $$
+ begin 
+   for i in array_lower($1,1)..array_upper($1,1) loop 
+     raise notice '%', $1[i]; 
+   end loop; end; 
+ $$ language plpgsql;
+ select vari(1,2,3,4,5);
+ NOTICE:  1
+ NOTICE:  2
+ NOTICE:  3
+ NOTICE:  4
+ NOTICE:  5
+  vari 
+ ------
+  
+ (1 row)
+ 
+ select vari(3,4,5);
+ NOTICE:  3
+ NOTICE:  4
+ NOTICE:  5
+  vari 
+ ------
+  
+ (1 row)
+ 
+ drop function vari(int[]);
+ -- coerce test
+ create or replace function pleast(variadic numeric[])
+ returns numeric as $$
+ declare aux numeric = $1[array_lower($1,1)];
+ begin
+   for i in array_lower($1,1)+1..array_upper($1,1) loop
+     if $1[i] < aux then aux := $1[i]; end if;
+   end loop;
+   return aux;
+ end;
+ $$ language plpgsql immutable strict;
+ select pleast(10,1,2,3,-16);
+  pleast 
+ --------
+     -16
+ (1 row)
+ 
+ select pleast(10.2,2.2,-1.1);
+  pleast 
+ --------
+    -1.1
+ (1 row)
+ 
+ select pleast(10.2,10, -20);
+  pleast 
+ --------
+     -20
+ (1 row)
+ 
+ select pleast(10,20, -1.0);
+  pleast 
+ --------
+    -1.0
+ (1 row)
+ 
+ -- we can't call variadic function with not unique signature
+ create or replace function pleast(numeric)
+ returns numeric as $$
+ begin
+   return $1;
+ end;
+ $$ language plpgsql immutable strict;
+ select pleast(10);
+ ERROR:  function pleast(numeric) is not unique
+ drop function pleast(numeric[]);
+ drop function pleast(numeric);
*** ./src/test/regress/expected/polymorphism.out.orig	2008-07-14 09:14:08.000000000 +0200
--- ./src/test/regress/expected/polymorphism.out	2008-07-15 00:03:30.000000000 +0200
***************
*** 613,615 ****
--- 613,678 ----
    SFUNC = add_group,
    STYPE = int8[]
  );
+ --test for variadic polymorphic function 
+ create function myleast(variadic anyarray)
+ returns anyelement as $$
+   select min($1[i])
+      from generate_subscripts($1,1) g(i)
+ $$ language sql immutable strict;
+ select myleast(10, 1, 20, 33);
+  myleast 
+ ---------
+        1
+ (1 row)
+ 
+ select myleast(1.1, 0.22, 0.55);
+  myleast 
+ ---------
+     0.22
+ (1 row)
+ 
+ -- test with variadic call parameter
+ select myleast(variadic array[1,2,3,4,-1]);
+  myleast 
+ ---------
+       -1
+ (1 row)
+ 
+ select myleast(variadic array[1.1, -5.5]);
+  myleast 
+ ---------
+     -5.5
+ (1 row)
+ 
+ --test with empty variadic call parameter
+ select myleast(variadic array[]::int[]);
+  myleast 
+ ---------
+         
+ (1 row)
+ 
+ -- visibility test
+ select pg_catalog.pg_function_is_visible('myleast(anyarray)'::regprocedure::int);
+  pg_function_is_visible 
+ ------------------------
+  t
+ (1 row)
+ 
+ drop function myleast(anyarray);
+ create or replace function concat(varchar, variadic anyarray)
+ returns varchar as $$
+   select array_to_string($2, $1);
+ $$ language sql immutable strict;
+ select concat('%', 1, 2, 3, 4, 5);
+   concat   
+ -----------
+  1%2%3%4%5
+ (1 row)
+ 
+ select concat('|', 'a'::text, 'b', 'c');
+  concat 
+ --------
+  a|b|c
+ (1 row)
+ 
+ drop function concat(varchar, anyarray);
*** ./src/test/regress/sql/plpgsql.sql.orig	2008-07-14 09:14:16.000000000 +0200
--- ./src/test/regress/sql/plpgsql.sql	2008-07-14 15:05:17.000000000 +0200
***************
*** 2878,2880 ****
--- 2878,2924 ----
  
  drop function catch();
  drop function case_test(bigint);
+ 
+ -- variadic fuction test
+ create or replace function vari(variadic int[]) 
+ returns void as $$
+ begin 
+   for i in array_lower($1,1)..array_upper($1,1) loop 
+     raise notice '%', $1[i]; 
+   end loop; end; 
+ $$ language plpgsql;
+ 
+ select vari(1,2,3,4,5);
+ select vari(3,4,5);
+ 
+ drop function vari(int[]);
+ 
+ -- coerce test
+ create or replace function pleast(variadic numeric[])
+ returns numeric as $$
+ declare aux numeric = $1[array_lower($1,1)];
+ begin
+   for i in array_lower($1,1)+1..array_upper($1,1) loop
+     if $1[i] < aux then aux := $1[i]; end if;
+   end loop;
+   return aux;
+ end;
+ $$ language plpgsql immutable strict;
+ 
+ select pleast(10,1,2,3,-16);
+ select pleast(10.2,2.2,-1.1);
+ select pleast(10.2,10, -20);
+ select pleast(10,20, -1.0);
+ 
+ -- we can't call variadic function with not unique signature
+ create or replace function pleast(numeric)
+ returns numeric as $$
+ begin
+   return $1;
+ end;
+ $$ language plpgsql immutable strict;
+ 
+ select pleast(10);
+ 
+ drop function pleast(numeric[]);
+ drop function pleast(numeric);
*** ./src/test/regress/sql/polymorphism.sql.orig	2008-07-14 09:14:26.000000000 +0200
--- ./src/test/regress/sql/polymorphism.sql	2008-07-15 00:02:27.000000000 +0200
***************
*** 426,428 ****
--- 426,461 ----
    SFUNC = add_group,
    STYPE = int8[]
  );
+ 
+ --test for variadic polymorphic function 
+ create function myleast(variadic anyarray)
+ returns anyelement as $$
+   select min($1[i])
+      from generate_subscripts($1,1) g(i)
+ $$ language sql immutable strict;
+ 
+ select myleast(10, 1, 20, 33);
+ select myleast(1.1, 0.22, 0.55);
+ 
+ -- test with variadic call parameter
+ select myleast(variadic array[1,2,3,4,-1]);
+ select myleast(variadic array[1.1, -5.5]);
+ 
+ --test with empty variadic call parameter
+ select myleast(variadic array[]::int[]);
+ 
+ -- visibility test
+ select pg_catalog.pg_function_is_visible('myleast(anyarray)'::regprocedure::int);
+ 
+ drop function myleast(anyarray);
+ 
+ create or replace function concat(varchar, variadic anyarray)
+ returns varchar as $$
+   select array_to_string($2, $1);
+ $$ language sql immutable strict;
+ 
+ select concat('%', 1, 2, 3, 4, 5);
+ select concat('|', 'a'::text, 'b', 'c');
+ 
+ drop function concat(varchar, anyarray);
+
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.