2008/6/25 Tom Lane <[EMAIL PROTECTED]>:
> "Pavel Stehule" <[EMAIL PROTECTED]> writes:
>>> Tom Lane wrote:
>>>> Your point about the syntax is good though.  It would be better if
>>>> the syntax were like
>>>> create function foo (a text, variadic b int[])
>>>> or maybe even better
>>>> create function foo (a text, variadic b int)
>
>> I don't see problem with your syntax. It well block combination OUT
>> and VARIADIC parameter - my one request, variadic parameter have to be
>> array.
>
> Well, we should certainly store the parameter type as an array in
> proargtypes, because that makes this feature transparent to all the
> PLs.  However, it doesn't follow that the CREATE FUNCTION syntax
> has to specify the array type rather than the element type.  I think
> the Java precedent might be good reason to go with using the element
> type in the function declaration.
>
>                        regards, tom lane
>
Hello

this is third variant with variadic argumen as scalar. But I still
strongly prefer second variant with conformance declared variadic
array with used array variable.

Regards
Pavel Stehule
*** ./doc/src/sgml/ref/create_function.sgml.orig	2008-06-24 16:46:47.000000000 +0200
--- ./doc/src/sgml/ref/create_function.sgml	2008-06-24 16:47:46.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-06-24 16:53:58.000000000 +0200
--- ./doc/src/sgml/xfunc.sgml	2008-06-26 13:34:20.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 args 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-06-24 11:24:34.000000000 +0200
--- ./src/backend/catalog/namespace.c	2008-06-26 16:41:06.000000000 +0200
***************
*** 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))
--- 606,645 ----
  		int			pronargs = procform->pronargs;
  		int			pathpos = 0;
  		FuncCandidateList newResult;
+ 		Oid	va_oid = InvalidOid;
+ 		bool	variadic = false;
+ 		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;
+ 					va_oid = get_variadic_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))
***************
*** 691,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;
  	}
  
--- 722,762 ----
  		/*
  		 * Okay to add it to result list
  		 */
! 		if (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;
  	}
  
***************
*** 759,771 ****
  
  		for (; clist; clist = clist->next)
  		{
! 			if (memcmp(clist->args, procform->proargtypes.values,
! 					   nargs * sizeof(Oid)) == 0)
  			{
! 				/* Found the expected entry; is it the right proc? */
! 				visible = (clist->oid == funcid);
! 				break;
! 			}
  		}
  	}
  
--- 815,848 ----
  
  		for (; clist; clist = clist->next)
  		{
! 			/* 
! 			 * Oid of expanded variadic argument is different than record
! 			 * in proargtypes.values.
! 			 */
! 			if (clist->nvargs > 0)
  			{
! 				Oid	va_oid;
! 
! 				if (memcmp(clist->args, procform->proargtypes.values,
! 					    (nargs - 1) * sizeof(Oid)) != 0)
! 					continue;
! 				va_oid = get_variadic_element_type(
! 								    procform->proargtypes.values[nargs - 1]);
! 
! 				if (clist->args[nargs - 1] == va_oid)
! 				{
! 					visible = (clist->oid == funcid);
! 					break;
! 				}				
! 			} 
! 			else
! 				if (memcmp(clist->args, procform->proargtypes.values,
! 					   nargs * sizeof(Oid)) == 0)
! 				{
! 					/* Found the expected entry; is it the right proc? */
! 					visible = (clist->oid == funcid);
! 					break;
! 				}
  		}
  	}
  
*** ./src/backend/catalog/pg_aggregate.c.orig	2008-06-24 14:17:42.000000000 +0200
--- ./src/backend/catalog/pg_aggregate.c	2008-06-24 15:58:27.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("aggregate function has variadic argument %d %d", nvargs, va_oid)));
+ 
  	/*
  	 * 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-06-24 10:36:44.000000000 +0200
--- ./src/backend/commands/functioncmds.c	2008-06-25 16:30:29.000000000 +0200
***************
*** 173,178 ****
--- 173,179 ----
  	Datum	   *paramNames;
  	int			outCount = 0;
  	bool		have_names = false;
+ 	int			varCount = 0; 	
  	ListCell   *x;
  	int			i;
  
***************
*** 227,235 ****
  					 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;
--- 228,270 ----
  					 errmsg("functions cannot accept set arguments")));
  
  		if (fp->mode != FUNC_PARAM_OUT)
+ 		{
+ 			if (fp->mode == FUNC_PARAM_VARIADIC)
+ 			{
+ 				if (varCount++ > 0)
+ 					ereport(ERROR,
+ 						    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 						     errmsg("function cannot accept two or more variadic arguments")));
+ 				/* 
+ 				 * type of declared variadic variable is cecked and changed to 
+ 		    		 * array.
+ 				 */  
+ 				switch (toid)
+ 				{
+ 					case ANYOID:
+ 						break;
+ 					case ANYELEMENTOID:
+ 						toid = ANYARRAYOID;
+ 						break;
+ 					default:
+ 						toid = get_array_type(toid);
+ 						if (!OidIsValid(toid))
+ 							ereport(ERROR,
+ 								    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 								    errmsg("variadic argument isn't array")));
+ 				}
+ 			}
+ 			else
+ 				/* 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 argument isn't last function's argument")));
+ 
  			inTypes[inCount++] = toid;
+ 		}
  
! 		if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
  		{
  			if (outCount == 0)	/* save first OUT param's type */
  				*requiredResultType = toid;
***************
*** 252,258 ****
  	/* Now construct the proper outputs as needed */
  	*parameterTypes = buildoidvector(inTypes, inCount);
  
! 	if (outCount > 0)
  	{
  		*allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
  											 sizeof(Oid), true, 'i');
--- 287,293 ----
  	/* 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/parser/gram.y.orig	2008-06-24 10:30:01.000000000 +0200
--- ./src/backend/parser/gram.y	2008-06-25 18:03:20.000000000 +0200
***************
*** 53,58 ****
--- 53,59 ----
  
  #include "catalog/index.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_type.h"
  #include "commands/defrem.h"
  #include "nodes/makefuncs.h"
  #include "parser/gramparse.h"
***************
*** 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
--- 445,451 ----
  	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 ****
--- 4205,4211 ----
  			| OUT_P									{ $$ = FUNC_PARAM_OUT; }
  			| INOUT									{ $$ = FUNC_PARAM_INOUT; }
  			| IN_P OUT_P							{ $$ = FUNC_PARAM_INOUT; }
+ 			| VARIADIC							{ $$ = FUNC_PARAM_VARIADIC; }
  		;
  
  /*
*** ./src/backend/parser/keywords.c.orig	2008-06-24 10:29:58.000000000 +0200
--- ./src/backend/parser/keywords.c	2008-06-24 10:30:50.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_func.c.orig	2008-06-24 13:09:17.000000000 +0200
--- ./src/backend/parser/parse_func.c	2008-06-26 14:47:10.000000000 +0200
***************
*** 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
***************
*** 158,164 ****
  	 */
  	fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
  							   &funcid, &rettype, &retset,
! 							   &declared_arg_types);
  	if (fdresult == FUNCDETAIL_COERCION)
  	{
  		/*
--- 160,167 ----
  	 */
  	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 ****
--- 232,279 ----
  	}
  
  	/*
+ 	 * 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;
+ 
+ 		if (nvargs < nargs)
+ 		{
+ 			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
+ 		{
+ 			/* array from all argumenst */
+ 			n->elements = fargs;
+ 			tn= transformExpr(pstate, (Node *) n);
+ 			fargs = list_make1(tn);
+ 		}
+ 
+ 		/* 
+ 		 * 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;
+ 		actual_arg_types[nargs - 1] = ((ArrayExpr *) tn)->array_typeid;
+ 		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,703 ****
  				Oid *funcid,	/* return value */
  				Oid *rettype,	/* return value */
  				bool *retset,	/* return value */
! 				Oid **true_typeids)		/* return value */
  {
  	FuncCandidateList raw_candidates;
  	FuncCandidateList best_candidate;
--- 742,750 ----
  				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;
***************
*** 787,792 ****
--- 834,841 ----
  					*rettype = targetType;
  					*retset = false;
  					*true_typeids = argtypes;
+ 					*nvargs = 0;
+ 					*va_oid = InvalidOid;
  					return FUNCDETAIL_COERCION;
  				}
  			}
***************
*** 836,841 ****
--- 885,892 ----
  
  		*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),
***************
*** 1190,1200 ****
  	FuncCandidateList clist;
  
  	clist = FuncnameGetCandidates(funcname, nargs);
- 
  	while (clist)
  	{
  		if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0)
  			return clist->oid;
  		clist = clist->next;
  	}
  
--- 1241,1251 ----
  	FuncCandidateList clist;
  
  	clist = FuncnameGetCandidates(funcname, nargs);
  	while (clist)
  	{
  		if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0)
  			return clist->oid;
+ 
  		clist = clist->next;
  	}
  
*** ./src/backend/utils/adt/oid.c.orig	2008-06-25 15:22:20.000000000 +0200
--- ./src/backend/utils/adt/oid.c	2008-06-26 16:19:41.000000000 +0200
***************
*** 21,27 ****
  #include "libpq/pqformat.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
! 
  
  #define OidVectorSize(n)	(offsetof(oidvector, values) + (n) * sizeof(Oid))
  
--- 21,27 ----
  #include "libpq/pqformat.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
! #include "utils/lsyscache.h"
  
  #define OidVectorSize(n)	(offsetof(oidvector, values) + (n) * sizeof(Oid))
  
***************
*** 419,421 ****
--- 419,451 ----
  
  	PG_RETURN_BOOL(cmp > 0);
  }
+ 
+ /*
+  * pg_get_element_type function is used for overwriting real variadic type
+  */
+ Oid 
+ get_variadic_element_type(Oid oid)
+ {
+ 	Oid	result;
+ 
+ 	switch (oid)
+ 	{
+ 		case ANYOID:
+ 			result = ANYOID;
+ 			break;
+ 		case ANYARRAYOID:
+ 			result = ANYELEMENTOID;
+ 			break;
+ 		default:
+ 			result = get_element_type(oid);
+ 	}
+ 	return result;
+ }
+ 
+ Datum
+ pg_get_element_type(PG_FUNCTION_ARGS)
+ {
+ 	Oid	oid = PG_GETARG_OID(0);
+ 
+ 	PG_RETURN_OID(get_variadic_element_type(oid));
+ }
*** ./src/backend/utils/adt/regproc.c.orig	2008-06-24 13:12:03.000000000 +0200
--- ./src/backend/utils/adt/regproc.c	2008-06-26 16:32:54.000000000 +0200
***************
*** 38,43 ****
--- 38,44 ----
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "utils/array.h"
  
  static void parseNameAndArgTypes(const char *string, bool allowNone,
  					 List **names, int *nargs, Oid *argtypes);
***************
*** 318,325 ****
--- 319,347 ----
  		int			i;
  		char	   *nspname;
  		StringInfoData buf;
+ 		Datum 		proargmodes;
+ 		bool		isnull;
+ 		bool		variadic = false;
  
  		/* XXX no support here for bootstrap mode */
+ 		
+ 		/*
+ 		 * variadic function detection
+ 		 */
+ 		proargmodes = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proargmodes, &isnull);
+ 		if (!isnull)
+ 		{
+  			ArrayType	*ar = DatumGetArrayTypeP(proargmodes);
+  			char		*argmodes;
+  
+  			argmodes = ARR_DATA_PTR(ar);
+ 			for (i = 0; i < ARR_DIMS(ar)[0]; i++)
+ 				if (argmodes[i] == PROARGMODE_VARIADIC)
+ 				{
+ 					variadic = true;
+ 					break;
+ 				}
+ 		}
  
  		initStringInfo(&buf);
  
***************
*** 340,345 ****
--- 362,374 ----
  
  			if (i > 0)
  				appendStringInfoChar(&buf, ',');
+ 			/* last variadic argument */
+ 			if (variadic && i == (nargs - 1))
+ 			{
+ 				appendStringInfoString(&buf, "VARIADIC ");
+ 				thisargtype = get_variadic_element_type(thisargtype);
+ 			}
+ 			
  			appendStringInfoString(&buf, format_type_be(thisargtype));
  		}
  		appendStringInfoChar(&buf, ')');
*** ./src/backend/utils/adt/ruleutils.c.orig	2008-06-24 14:37:19.000000000 +0200
--- ./src/backend/utils/adt/ruleutils.c	2008-06-24 14:38:28.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-06-24 16:18:51.000000000 +0200
--- ./src/backend/utils/fmgr/funcapi.c	2008-06-24 16:21:54.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-06-24 15:05:21.000000000 +0200
--- ./src/bin/pg_dump/pg_dump.c	2008-06-25 17:15:08.000000000 +0200
***************
*** 6429,6449 ****
  		const char *argname;
  
  		typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
! 		typname = getFormattedTypeName(typid, zeroAsOpaque);
  
  		if (argmodes)
  		{
  			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 = "";
--- 6429,6452 ----
  		const char *argname;
  
  		typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
! 		typname = getFormattedTypeName(typid, zeroAsOpaque | (argmodes[j][0] == PROARGMODE_VARIADIC)? variadicArgument : 0);
  
  		if (argmodes)
  		{
  			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 = "";
***************
*** 10260,10266 ****
  	}
  
  	query = createPQExpBuffer();
! 	if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
  						  oid);
--- 10263,10274 ----
  	}
  
  	query = createPQExpBuffer();
! 	if ((opts & variadicArgument) != 0)
! 	{
! 		appendPQExpBuffer(query, "SELECT pg_catalog.format_type(pg_catalog.pg_get_element_type('%u'::pg_catalog.oid), NULL)",
! 						oid);	
! 	}
! 	else if (g_fout->remoteVersion >= 70300)
  	{
  		appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
  						  oid);
*** ./src/bin/pg_dump/pg_dump.h.orig	2008-06-25 17:07:25.000000000 +0200
--- ./src/bin/pg_dump/pg_dump.h	2008-06-25 17:13:18.000000000 +0200
***************
*** 436,442 ****
  	zeroAsOpaque = 1,
  	zeroAsAny = 2,
  	zeroAsStar = 4,
! 	zeroAsNone = 8
  } OidOptions;
  
  extern void AssignDumpId(DumpableObject *dobj);
--- 436,443 ----
  	zeroAsOpaque = 1,
  	zeroAsAny = 2,
  	zeroAsStar = 4,
! 	zeroAsNone = 8,
! 	variadicArgument = 16,
  } OidOptions;
  
  extern void AssignDumpId(DumpableObject *dobj);
*** ./src/bin/psql/describe.c.orig	2008-06-24 15:17:23.000000000 +0200
--- ./src/bin/psql/describe.c	2008-06-25 16:41:17.000000000 +0200
***************
*** 187,198 ****
  					  "          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"
  					  "        END ||\n"
  					  "        CASE\n"
  			 "          WHEN COALESCE(p.proargnames[s.i], '') = '' THEN ''\n"
  					  "          ELSE p.proargnames[s.i] || ' ' \n"
  					  "        END ||\n"
! 			  "        pg_catalog.format_type(p.proallargtypes[s.i], NULL)\n"
  					  "      FROM\n"
  					  "        pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
  					  "    ), ', ')\n"
--- 187,202 ----
  					  "          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"
  					  "          ELSE p.proargnames[s.i] || ' ' \n"
  					  "        END ||\n"
! 			  "        pg_catalog.format_type(CASE\n"
! 					"                   WHEN p.proargmodes[s.i] = 'v' THEN pg_catalog.pg_get_element_type(p.proallargtypes[s.i])\n"
!  					"                   ELSE p.proallargtypes[s.i]\n"
! 					"                 END, NULL)\n"
  					  "      FROM\n"
  					  "        pg_catalog.generate_series(1, pg_catalog.array_upper(p.proallargtypes, 1)) AS s(i)\n"
  					  "    ), ', ')\n"
*** ./src/include/catalog/namespace.h.orig	2008-06-24 12:48:23.000000000 +0200
--- ./src/include/catalog/namespace.h	2008-06-26 14:45:13.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 */
  
*** ./src/include/catalog/pg_proc.h.orig	2008-06-24 13:33:45.000000000 +0200
--- ./src/include/catalog/pg_proc.h	2008-06-25 16:10:41.000000000 +0200
***************
*** 2660,2665 ****
--- 2660,2668 ----
  DATA(insert OID = 1799 (  oidout		   PGNSP PGUID 12 1 0 f f t f i 1 2275 "26" _null_ _null_ _null_ oidout - _null_ _null_ ));
  DESCR("I/O");
  
+ DATA(insert OID = 2162 (  pg_get_element_type	   PGNSP PGUID 12 1 0 f f t f i 1 26 "26" _null_ _null_ _null_ pg_get_element_type - _null_ _null_ ));
+ DESCR("returns element type of array");
+ 
  
  DATA(insert OID = 1810 (  bit_length	   PGNSP PGUID 14 1 0 f f t f i 1 23 "17" _null_ _null_ _null_ "select pg_catalog.octet_length($1) * 8" - _null_ _null_ ));
  DESCR("length in bits");
***************
*** 4466,4470 ****
--- 4469,4474 ----
  #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-06-24 10:35:02.000000000 +0200
--- ./src/include/nodes/parsenodes.h	2008-06-24 10:35:09.000000000 +0200
***************
*** 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
--- 1568,1575 ----
  	/* 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-06-24 14:16:40.000000000 +0200
--- ./src/include/parser/parse_func.h	2008-06-24 14:17:13.000000000 +0200
***************
*** 49,55 ****
  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,
--- 49,56 ----
  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/include/utils/builtins.h.orig	2008-06-25 15:33:30.000000000 +0200
--- ./src/include/utils/builtins.h	2008-06-26 16:16:09.000000000 +0200
***************
*** 436,441 ****
--- 436,443 ----
  extern Datum oidvectorge(PG_FUNCTION_ARGS);
  extern Datum oidvectorgt(PG_FUNCTION_ARGS);
  extern oidvector *buildoidvector(const Oid *oids, int n);
+ extern Datum pg_get_element_type(PG_FUNCTION_ARGS);
+ extern Oid get_variadic_element_type(Oid oid);
  
  /* pseudotypes.c */
  extern Datum cstring_in(PG_FUNCTION_ARGS);
*** ./src/interfaces/ecpg/preproc/preproc.y.orig	2008-06-24 11:12:00.000000000 +0200
--- ./src/interfaces/ecpg/preproc/preproc.y	2008-06-24 11:13:52.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
  
***************
*** 6668,6673 ****
--- 6668,6674 ----
  		| 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-06-24 16:23:47.000000000 +0200
--- ./src/pl/plpgsql/src/pl_comp.c	2008-06-24 16:25:53.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-06-24 16:33:20.000000000 +0200
--- ./src/test/regress/expected/plpgsql.out	2008-06-26 16:45:05.000000000 +0200
***************
*** 3544,3546 ****
--- 3544,3611 ----
  
  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(variadic 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)
+ 
+ drop function pleast(variadic numeric);
*** ./src/test/regress/expected/polymorphism.out.orig	2008-06-24 16:10:52.000000000 +0200
--- ./src/test/regress/expected/polymorphism.out	2008-06-26 16:51:20.000000000 +0200
***************
*** 613,615 ****
--- 613,658 ----
    SFUNC = add_group,
    STYPE = int8[]
  );
+ --test for variadic polymorphic function 
+ create function myleast(variadic anyelement)
+ 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)
+ 
+ -- visibility test
+ select pg_catalog.pg_function_is_visible('myleast(anyelement)'::regprocedure::int);
+  pg_function_is_visible 
+ ------------------------
+  t
+ (1 row)
+ 
+ drop function myleast(anyelement);
+ create or replace function concat(varchar, variadic anyelement)
+ 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, variadic anyelement);
*** ./src/test/regress/sql/plpgsql.sql.orig	2008-06-24 16:01:55.000000000 +0200
--- ./src/test/regress/sql/plpgsql.sql	2008-06-25 17:23:16.000000000 +0200
***************
*** 2878,2880 ****
--- 2878,2913 ----
  
  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(variadic 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);
+ 
+ drop function pleast(variadic numeric);
*** ./src/test/regress/sql/polymorphism.sql.orig	2008-06-24 16:01:52.000000000 +0200
--- ./src/test/regress/sql/polymorphism.sql	2008-06-26 16:50:09.000000000 +0200
***************
*** 426,428 ****
--- 426,453 ----
    SFUNC = add_group,
    STYPE = int8[]
  );
+ 
+ --test for variadic polymorphic function 
+ create function myleast(variadic anyelement)
+ 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);
+ -- visibility test
+ select pg_catalog.pg_function_is_visible('myleast(anyelement)'::regprocedure::int);
+ 
+ drop function myleast(anyelement);
+ 
+ create or replace function concat(varchar, variadic anyelement)
+ 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, variadic anyelement);
+ 
-- 
Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches

Reply via email to