diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 7accea0f76..83be70ca66 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-
+
@@ -3569,6 +3569,14 @@
Estimated number of result rows (zero if not proretset>)
+
+ provariadic
+ oid
+ pg_type.oid
+ Data type of the variadic array parameter's elements,
+ or zero if the function does not have a variadic parameter
+
+
proisagg
bool
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 48b8ee45e6..c6db3d16b9 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.108 2008/07/16 01:30:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.109 2008/07/16 16:55:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -619,50 +619,23 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
int pronargs = procform->pronargs;
int effective_nargs;
int pathpos = 0;
- bool variadic = false;
- Oid va_elem_type = InvalidOid;
+ bool variadic;
+ Oid va_elem_type;
FuncCandidateList newResult;
/*
* Check if function is variadic, and get variadic element type if so.
- * If expand_variadic is false, we can just ignore variadic-ness.
- *
- * XXX it's annoying to inject something as expensive as this even
- * when there are no variadic functions involved. Find a better way.
+ * If expand_variadic is false, we should just ignore variadic-ness.
*/
if (expand_variadic)
{
- Datum proargmodes;
- bool isnull;
-
- proargmodes = SysCacheGetAttr(PROCOID, proctup,
- Anum_pg_proc_proargmodes, &isnull);
- if (!isnull)
- {
- ArrayType *ar = DatumGetArrayTypeP(proargmodes);
- char *argmodes;
- int j;
-
- argmodes = ARR_DATA_PTR(ar);
- j = ARR_DIMS(ar)[0] - 1;
- if (j >= 0 && argmodes[j] == PROARGMODE_VARIADIC)
- {
- variadic = any_variadic = true;
- switch (procform->proargtypes.values[j])
- {
- case ANYOID:
- va_elem_type = ANYOID;
- break;
- case ANYARRAYOID:
- va_elem_type = ANYELEMENTOID;
- break;
- default:
- va_elem_type = get_element_type(procform->proargtypes.values[j]);
- Assert(OidIsValid(va_elem_type));
- break;
- }
- }
- }
+ va_elem_type = procform->provariadic;
+ variadic = OidIsValid(va_elem_type);
+ }
+ else
+ {
+ va_elem_type = InvalidOid;
+ variadic = false;
}
/* Ignore if it doesn't match requested argument count */
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e1c67ce5cd..42eadca1e2 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.94 2008/07/16 01:30:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.95 2008/07/16 16:55:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -202,7 +202,7 @@ AggregateCreate(const char *aggName,
INTERNALlanguageId, /* languageObjectId */
InvalidOid, /* no validator */
"aggregate_dummy", /* placeholder proc */
- "-", /* probin */
+ NULL, /* probin */
true, /* isAgg */
false, /* security invoker (currently not
* definable for agg) */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 1f11f82a30..37e7ed4343 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.151 2008/03/27 03:57:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.152 2008/07/16 16:55:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -85,6 +85,7 @@ ProcedureCreate(const char *procedureName,
bool genericOutParam = false;
bool internalInParam = false;
bool internalOutParam = false;
+ Oid variadicType = InvalidOid;
Relation rel;
HeapTuple tup;
HeapTuple oldtup;
@@ -103,7 +104,6 @@ ProcedureCreate(const char *procedureName,
* sanity checks
*/
Assert(PointerIsValid(prosrc));
- Assert(PointerIsValid(probin));
parameterCount = parameterTypes->dim1;
if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
@@ -211,6 +211,64 @@ ProcedureCreate(const char *procedureName,
procedureName,
format_type_be(parameterTypes->values[0]))));
+ if (parameterModes != PointerGetDatum(NULL))
+ {
+ /*
+ * We expect the array to be a 1-D CHAR array; verify that. We don't
+ * need to use deconstruct_array() since the array data is just going
+ * to look like a C array of char values.
+ */
+ ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
+ char *modes;
+
+ if (ARR_NDIM(modesArray) != 1 ||
+ ARR_DIMS(modesArray)[0] != allParamCount ||
+ ARR_HASNULL(modesArray) ||
+ ARR_ELEMTYPE(modesArray) != CHAROID)
+ elog(ERROR, "parameterModes is not a 1-D char array");
+ modes = (char *) ARR_DATA_PTR(modesArray);
+ /*
+ * Only the last input parameter can be variadic; if it is, save
+ * its element type. Errors here are just elog since caller should
+ * have checked this already.
+ */
+ for (i = 0; i < allParamCount; i++)
+ {
+ switch (modes[i])
+ {
+ case PROARGMODE_IN:
+ case PROARGMODE_INOUT:
+ if (OidIsValid(variadicType))
+ elog(ERROR, "variadic parameter must be last");
+ break;
+ case PROARGMODE_OUT:
+ /* okay */
+ break;
+ case PROARGMODE_VARIADIC:
+ if (OidIsValid(variadicType))
+ elog(ERROR, "variadic parameter must be last");
+ switch (allParams[i])
+ {
+ case ANYOID:
+ variadicType = ANYOID;
+ break;
+ case ANYARRAYOID:
+ variadicType = ANYELEMENTOID;
+ break;
+ default:
+ variadicType = get_element_type(allParams[i]);
+ if (!OidIsValid(variadicType))
+ elog(ERROR, "variadic parameter is not an array");
+ break;
+ }
+ break;
+ default:
+ elog(ERROR, "invalid parameter mode '%c'", modes[i]);
+ break;
+ }
+ }
+ }
+
/*
* All seems OK; prepare the data to be inserted into pg_proc.
*/
@@ -229,6 +287,7 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
+ values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
@@ -250,7 +309,10 @@ ProcedureCreate(const char *procedureName,
else
nulls[Anum_pg_proc_proargnames - 1] = 'n';
values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
- values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
+ if (probin)
+ values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
+ else
+ nulls[Anum_pg_proc_probin - 1] = 'n';
if (proconfig != PointerGetDatum(NULL))
values[Anum_pg_proc_proconfig - 1] = proconfig;
else
@@ -497,12 +559,12 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
if (isnull)
- elog(ERROR, "null prosrc");
+ elog(ERROR, "null prosrc for C function %u", funcoid);
prosrc = TextDatumGetCString(tmp);
tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
if (isnull)
- elog(ERROR, "null probin");
+ elog(ERROR, "null probin for C function %u", funcoid);
probin = TextDatumGetCString(tmp);
(void) load_external_function(probin, prosrc, true, &libraryhandle);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index cb249d9c7d..d03de8bff1 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.96 2008/07/16 01:30:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.97 2008/07/16 16:55:23 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@@ -590,7 +590,8 @@ compute_attributes_with_style(List *parameters, bool *isStrict_p, char *volatili
* AS