+ errhint("Use DROP FUNCTION %s first.",
+ format_procedure(HeapTupleGetOid(oldtup)))));
+ }
+
+ /*
+ * If there were any named input parameters, check to make sure the
+ * names have not been changed, as this could break existing calls. We
+ * allow adding names to formerly unnamed parameters, though.
+ */
+ proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
+ Anum_pg_proc_proargnames,
+ &isnull);
+ if (!isnull)
+ {
+ Datum proargmodes;
+ char **old_arg_names;
+ char **new_arg_names;
+ int n_old_arg_names;
+ int n_new_arg_names;
+ int j;
+
+ proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup,
+ Anum_pg_proc_proargmodes,
+ &isnull);
+ if (isnull)
+ proargmodes = PointerGetDatum(NULL); /* just to be sure */
+
+ n_old_arg_names = get_func_input_arg_names(proargnames,
+ proargmodes,
+ &old_arg_names);
+ n_new_arg_names = get_func_input_arg_names(parameterNames,
+ parameterModes,
+ &new_arg_names);
+ for (j = 0; j < n_old_arg_names; j++)
+ {
+ if (old_arg_names[j] == NULL)
+ continue;
+ if (j >= n_new_arg_names || new_arg_names[j] == NULL ||
+ strcmp(old_arg_names[j], new_arg_names[j]) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("cannot change name of input parameter \"%s\"",
+ old_arg_names[j]),
+ errhint("Use DROP FUNCTION %s first.",
+ format_procedure(HeapTupleGetOid(oldtup)))));
+ }
+ }
+
+ /*
+ * 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;
+ 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 %s first.",
+ format_procedure(HeapTupleGetOid(oldtup)))));
+
+ 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 %s first.",
+ format_procedure(HeapTupleGetOid(oldtup)))));
+ newlc = lnext(newlc);
+ }