diff options
Diffstat (limited to 'src/backend/catalog/pg_proc.c')
-rw-r--r-- | src/backend/catalog/pg_proc.c | 63 |
1 files changed, 56 insertions, 7 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 1b414e3e5a6..f9339fd2ce9 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.155 2008/12/04 17:51:26 petere Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.156 2008/12/18 18:20:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,7 @@ #include "funcapi.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "nodes/nodeFuncs.h" #include "parser/parse_type.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" @@ -73,10 +74,10 @@ ProcedureCreate(const char *procedureName, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, + List *parameterDefaults, Datum proconfig, float4 procost, - float4 prorows, - List *parameterDefaults) + float4 prorows) { Oid retval; int parameterCount; @@ -311,11 +312,8 @@ ProcedureCreate(const char *procedureName, values[Anum_pg_proc_proargnames - 1] = parameterNames; else nulls[Anum_pg_proc_proargnames - 1] = true; - if (parameterDefaults != PointerGetDatum(NULL)) - { - Assert(list_length(parameterDefaults) > 0); + if (parameterDefaults != NIL) values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults)); - } else nulls[Anum_pg_proc_proargdefaults - 1] = true; values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); @@ -389,6 +387,57 @@ ProcedureCreate(const char *procedureName, errhint("Use DROP FUNCTION first."))); } + /* + * If there are existing defaults, check compatibility: redefinition + * must not remove any defaults nor change their types. (Removing + * a default might cause a function to fail to satisfy an existing + * call. Changing type would only be possible if the associated + * parameter is polymorphic, and in such cases a change of default + * type might alter the resolved output type of existing calls.) + */ + if (oldproc->pronargdefaults != 0) + { + Datum proargdefaults; + bool isnull; + List *oldDefaults; + ListCell *oldlc; + ListCell *newlc; + + if (list_length(parameterDefaults) < oldproc->pronargdefaults) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot remove parameter defaults from existing function"), + errhint("Use DROP FUNCTION first."))); + + proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, + Anum_pg_proc_proargdefaults, + &isnull); + Assert(!isnull); + oldDefaults = (List *) stringToNode(TextDatumGetCString(proargdefaults)); + Assert(IsA(oldDefaults, List)); + Assert(list_length(oldDefaults) == oldproc->pronargdefaults); + + /* new list can have more defaults than old, advance over 'em */ + newlc = list_head(parameterDefaults); + for (i = list_length(parameterDefaults) - oldproc->pronargdefaults; + i > 0; + i--) + newlc = lnext(newlc); + + foreach(oldlc, oldDefaults) + { + Node *oldDef = (Node *) lfirst(oldlc); + Node *newDef = (Node *) lfirst(newlc); + + if (exprType(oldDef) != exprType(newDef)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot change data type of existing parameter default value"), + errhint("Use DROP FUNCTION first."))); + newlc = lnext(newlc); + } + } + /* Can't change aggregate status, either */ if (oldproc->proisagg != isAgg) { |