From e3a1973a82e418b5b646a990b246c12978ccfe1f Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Tue, 24 Feb 2015 14:10:05 -0300
Subject: [PATCH 44/44] fixup! deparse: Support for ALTER <OBJECT> RENAME

Use another method to determine a function's identity, per Andres.
---
 src/backend/tcop/deparse_utility.c |  47 +++++++----------
 src/backend/utils/adt/regproc.c    | 101 +++++++++++++++++++++++++++----------
 src/include/utils/builtins.h       |   1 +
 3 files changed, 93 insertions(+), 56 deletions(-)

diff --git a/src/backend/tcop/deparse_utility.c b/src/backend/tcop/deparse_utility.c
index 34ca4dd..f8d94a4 100644
--- a/src/backend/tcop/deparse_utility.c
+++ b/src/backend/tcop/deparse_utility.c
@@ -3531,39 +3531,28 @@ deparse_RenameStmt(Oid objectId, Node *parsetree)
 		case OBJECT_AGGREGATE:
 		case OBJECT_FUNCTION:
 			{
-				char	   *newident;
-				ObjectAddress objaddr;
-				const char	   *quoted_newname;
-				StringInfoData old_ident;
-				char	   *start;
-
-				/*
-				 * Generating a function/aggregate identity is altogether too
-				 * messy, so instead of doing it ourselves, we generate one for
-				 * the renamed object, then strip out the name and replace it
-				 * with the original name from the parse node.  This is so ugly
-				 * that we don't dare do it for any other object kind.
-				 */
-
-				objaddr.classId = get_objtype_catalog_oid(node->renameType);
-				objaddr.objectId = objectId;
-				objaddr.objectSubId = 0;
-				newident = getObjectIdentity(&objaddr);
-
-				quoted_newname = quote_identifier(node->newname);
-				start = strstr(newident, quoted_newname);
-				if (!start)
-					elog(ERROR, "could not find %s in %s", start, newident);
-				initStringInfo(&old_ident);
-				appendBinaryStringInfo(&old_ident, newident, start - newident);
-				appendStringInfoString(&old_ident,
-									   quote_identifier(strVal(llast(node->object))));
-				appendStringInfoString(&old_ident, start + strlen(quoted_newname));
+				char	*ident;
+				HeapTuple proctup;
+				Form_pg_proc procform;
+
+				proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(objectId));
+				if (!HeapTupleIsValid(proctup))
+					elog(ERROR, "cache lookup failed for procedure %u",
+						 objectId);
+				procform = (Form_pg_proc) GETSTRUCT(proctup);
+
+				/* XXX does this work for ordered-set aggregates? */
+				ident = psprintf("%s%s",
+								 quote_qualified_identifier(get_namespace_name(procform->pronamespace),
+															NameStr(procform->proname)),
+								 format_procedure_args(objectId, true));
 
 				fmtstr = psprintf("ALTER %s %%{identity}s RENAME TO %%{newname}I",
 								  stringify_objtype(node->renameType));
 				renameStmt = new_objtree_VA(fmtstr, 1,
-											"identity", ObjTypeString, old_ident.data);
+											"identity", ObjTypeString, ident);
+
+				ReleaseSysCache(proctup);
 			}
 			break;
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 3d1bb32..68447ca 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -42,7 +42,11 @@
 #include "utils/tqual.h"
 
 static char *format_operator_internal(Oid operator_oid, bool force_qualify);
-static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
+static char *format_procedure_internal(Oid procedure_oid, bool force_qualify,
+						  bool args_only);
+static void format_procedure_args_internal(Form_pg_proc procform,
+							   StringInfo buf, bool force_qualify);
+
 static void parseNameAndArgTypes(const char *string, bool allowNone,
 					 List **names, int *nargs, Oid *argtypes);
 
@@ -363,13 +367,36 @@ to_regprocedure(PG_FUNCTION_ARGS)
 char *
 format_procedure(Oid procedure_oid)
 {
-	return format_procedure_internal(procedure_oid, false);
+	return format_procedure_internal(procedure_oid, false, false);
 }
 
 char *
 format_procedure_qualified(Oid procedure_oid)
 {
-	return format_procedure_internal(procedure_oid, true);
+	return format_procedure_internal(procedure_oid, true, false);
+}
+
+/*
+ * format_procedure_args	- converts proc OID to "(args)"
+ */
+char *
+format_procedure_args(Oid procedure_oid, bool force_qualify)
+{
+	StringInfoData buf;
+	HeapTuple	proctup;
+	Form_pg_proc procform;
+
+	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
+	if (!HeapTupleIsValid(proctup))
+		elog(ERROR, "cache lookup failed for procedure %u", procedure_oid);
+	procform = (Form_pg_proc) GETSTRUCT(proctup);
+
+	initStringInfo(&buf);
+	format_procedure_args_internal(procform, &buf, force_qualify);
+
+	ReleaseSysCache(proctup);
+
+	return buf.data;
 }
 
 /*
@@ -380,7 +407,7 @@ format_procedure_qualified(Oid procedure_oid)
  * qualified if the function is not in path.
  */
 static char *
-format_procedure_internal(Oid procedure_oid, bool force_qualify)
+format_procedure_internal(Oid procedure_oid, bool force_qualify, bool args_only)
 {
 	char	   *result;
 	HeapTuple	proctup;
@@ -391,8 +418,6 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify)
 	{
 		Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
 		char	   *proname = NameStr(procform->proname);
-		int			nargs = procform->pronargs;
-		int			i;
 		char	   *nspname;
 		StringInfoData buf;
 
@@ -400,29 +425,24 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify)
 
 		initStringInfo(&buf);
 
-		/*
-		 * Would this proc be found (given the right args) by regprocedurein?
-		 * If not, or if caller requests it, we need to qualify it.
-		 */
-		if (!force_qualify && FunctionIsVisible(procedure_oid))
-			nspname = NULL;
-		else
-			nspname = get_namespace_name(procform->pronamespace);
-
-		appendStringInfo(&buf, "%s(",
-						 quote_qualified_identifier(nspname, proname));
-		for (i = 0; i < nargs; i++)
+		if (!args_only)
 		{
-			Oid			thisargtype = procform->proargtypes.values[i];
-
-			if (i > 0)
-				appendStringInfoChar(&buf, ',');
-			appendStringInfoString(&buf,
-								   force_qualify ?
-								   format_type_be_qualified(thisargtype) :
-								   format_type_be(thisargtype));
+			/*
+			 * Would this proc be found (given the right args) by
+			 * regprocedurein?  If not, or if caller requests it, we need to
+			 * qualify it.
+			 */
+			if (!force_qualify && FunctionIsVisible(procedure_oid))
+				nspname = NULL;
+			else
+				nspname = get_namespace_name(procform->pronamespace);
+
+			appendStringInfo(&buf, "%s",
+							 quote_qualified_identifier(nspname, proname));
 		}
-		appendStringInfoChar(&buf, ')');
+
+		/* add the attributes */
+		format_procedure_args_internal(procform, &buf, force_qualify);
 
 		result = buf.data;
 
@@ -439,6 +459,33 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify)
 }
 
 /*
+ * Append the parenthised arguments of the given pg_proc row into the output
+ * buffer.  force_qualify indicates whether to schema-qualify type names
+ * regardless of visibility.
+ */
+static void
+format_procedure_args_internal(Form_pg_proc procform, StringInfo buf,
+							   bool force_qualify)
+{
+	int			i;
+	int			nargs = procform->pronargs;
+
+	appendStringInfoChar(buf, '(');
+	for (i = 0; i < nargs; i++)
+	{
+		Oid			thisargtype = procform->proargtypes.values[i];
+
+		if (i > 0)
+			appendStringInfoChar(buf, ',');
+		appendStringInfoString(buf,
+							   force_qualify ?
+							   format_type_be_qualified(thisargtype) :
+							   format_type_be(thisargtype));
+	}
+	appendStringInfoChar(buf, ')');
+}
+
+/*
  * Output a objname/objargs representation for the procedure with the
  * given OID.  If it doesn't exist, an error is thrown.
  *
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 470a325..dd539fe 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -644,6 +644,7 @@ extern char *format_procedure(Oid procedure_oid);
 extern char *format_procedure_qualified(Oid procedure_oid);
 extern void format_procedure_parts(Oid operator_oid, List **objnames,
 					  List **objargs);
+extern char *format_procedure_args(Oid procedure_oid, bool force_qualify);
 extern char *format_operator(Oid operator_oid);
 extern char *format_operator_qualified(Oid operator_oid);
 extern void format_operator_parts(Oid operator_oid, List **objnames,
-- 
2.1.4

