aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/namespace.c49
-rw-r--r--src/backend/catalog/pg_aggregate.c4
-rw-r--r--src/backend/catalog/pg_proc.c72
-rw-r--r--src/backend/commands/functioncmds.c56
-rw-r--r--src/backend/utils/adt/ruleutils.c31
-rw-r--r--src/backend/utils/fmgr/fmgr.c10
6 files changed, 122 insertions, 100 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 48b8ee45e6b..c6db3d16b92 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 e1c67ce5cd4..42eadca1e2b 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 1f11f82a304..37e7ed4343e 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 cb249d9c7d1..d03de8bff17 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 <object reference, or sql code>
*/
static void
-interpret_AS_clause(Oid languageOid, const char *languageName, List *as,
+interpret_AS_clause(Oid languageOid, const char *languageName,
+ char *funcname, List *as,
char **prosrc_str_p, char **probin_str_p)
{
Assert(as != NIL);
@@ -599,25 +600,47 @@ interpret_AS_clause(Oid languageOid, const char *languageName, List *as,
{
/*
* For "C" language, store the file name in probin and, when given,
- * the link symbol name in prosrc.
+ * the link symbol name in prosrc. If link symbol is omitted,
+ * substitute procedure name. We also allow link symbol to be
+ * specified as "-", since that was the habit in PG versions before
+ * 8.4, and there might be dump files out there that don't translate
+ * that back to "omitted".
*/
*probin_str_p = strVal(linitial(as));
if (list_length(as) == 1)
- *prosrc_str_p = "-";
+ *prosrc_str_p = funcname;
else
+ {
*prosrc_str_p = strVal(lsecond(as));
+ if (strcmp(*prosrc_str_p, "-") == 0)
+ *prosrc_str_p = funcname;
+ }
}
else
{
/* Everything else wants the given string in prosrc. */
*prosrc_str_p = strVal(linitial(as));
- *probin_str_p = "-";
+ *probin_str_p = NULL;
if (list_length(as) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only one AS item needed for language \"%s\"",
languageName)));
+
+ if (languageOid == INTERNALlanguageId)
+ {
+ /*
+ * In PostgreSQL versions before 6.5, the SQL name of the created
+ * function could not be different from the internal name, and
+ * "prosrc" wasn't used. So there is code out there that does
+ * CREATE FUNCTION xyz AS '' LANGUAGE internal. To preserve some
+ * modicum of backwards compatibility, accept an empty "prosrc"
+ * value as meaning the supplied SQL function name.
+ */
+ if (strlen(*prosrc_str_p) == 0)
+ *prosrc_str_p = funcname;
+ }
}
}
@@ -759,30 +782,9 @@ CreateFunction(CreateFunctionStmt *stmt)
compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);
- interpret_AS_clause(languageOid, languageName, as_clause,
+ interpret_AS_clause(languageOid, languageName, funcname, as_clause,
&prosrc_str, &probin_str);
- if (languageOid == INTERNALlanguageId)
- {
- /*
- * In PostgreSQL versions before 6.5, the SQL name of the created
- * function could not be different from the internal name, and
- * "prosrc" wasn't used. So there is code out there that does CREATE
- * FUNCTION xyz AS '' LANGUAGE internal. To preserve some modicum of
- * backwards compatibility, accept an empty "prosrc" value as meaning
- * the supplied SQL function name.
- */
- if (strlen(prosrc_str) == 0)
- prosrc_str = funcname;
- }
-
- if (languageOid == ClanguageId)
- {
- /* If link symbol is specified as "-", substitute procedure name */
- if (strcmp(prosrc_str, "-") == 0)
- prosrc_str = funcname;
- }
-
/*
* Set default values for COST and ROWS depending on other parameters;
* reject ROWS if it's not returnsSet. NB: pg_dump knows these default
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index dc4a6cc4a8f..c7f896c524a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.276 2008/07/16 01:30:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.277 2008/07/16 16:55:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -5389,29 +5389,12 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes,
/* Check variadic-ness if caller cares */
if (is_variadic)
{
- /* XXX change this if we simplify code in FuncnameGetCandidates */
- Datum proargmodes;
- bool isnull;
-
- *is_variadic = false;
-
- 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)
- {
- /* "any" variadics are not treated as variadics for listing */
- if (procform->proargtypes.values[j] != ANYOID)
- *is_variadic = true;
- }
- }
+ /* "any" variadics are not treated as variadics for listing */
+ if (OidIsValid(procform->provariadic) &&
+ procform->provariadic != ANYOID)
+ *is_variadic = true;
+ else
+ *is_variadic = false;
}
ReleaseSysCache(proctup);
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index b0553b026b8..cd23bae0779 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.120 2008/06/06 22:35:22 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.121 2008/07/16 16:55:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -324,18 +324,20 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
void *libraryhandle;
/*
- * Get prosrc and probin strings (link symbol and library filename)
+ * Get prosrc and probin strings (link symbol and library filename).
+ * While in general these columns might be null, that's not allowed
+ * for C-language functions.
*/
prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple,
Anum_pg_proc_prosrc, &isnull);
if (isnull)
- elog(ERROR, "null prosrc for function %u", functionId);
+ elog(ERROR, "null prosrc for C function %u", functionId);
prosrcstring = TextDatumGetCString(prosrcattr);
probinattr = SysCacheGetAttr(PROCOID, procedureTuple,
Anum_pg_proc_probin, &isnull);
if (isnull)
- elog(ERROR, "null probin for function %u", functionId);
+ elog(ERROR, "null probin for C function %u", functionId);
probinstring = TextDatumGetCString(probinattr);
/* Look up the function itself */