aboutsummaryrefslogtreecommitdiff
path: root/src/backend/catalog/pg_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/pg_proc.c')
-rw-r--r--src/backend/catalog/pg_proc.c63
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)
{