*** ./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 ****
The mode of an argument: either IN>, OUT>,
! or INOUT>. If omitted, the default is IN>.
--- 102,109 ----
The mode of an argument: either IN>, OUT>,
! INOUT> or VARIADIC. If omitted,
! the default is IN>.
*** ./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 ****
Parameters can be marked as IN> (the default),
! OUT>, or INOUT>. An INOUT>
parameter serves as both an input parameter (part of the calling
argument list) and an output parameter (part of the result record type).
--- 578,585 ----
Parameters can be marked as IN> (the default),
! OUT>, INOUT>, or VARIADIC.
! An INOUT>
parameter serves as both an input parameter (part of the calling
argument list) and an output parameter (part of the result record type).
***************
*** 805,810 ****
--- 806,833 ----
+
+
+ Variadic SQL Functions
+
+
+ SQL functions can be declared to accept
+ variable number of arguments.
+
+ 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)
+
+
+
+
*** ./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);
+