From 7132313f42c71b75405e34cdac3db6126229b549 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Fri, 31 Aug 2018 16:55:16 +0900
Subject: [PATCH 2/2] Poc: postgres_fdw support routine mappings.

---
 contrib/postgres_fdw/deparse.c | 68 +++++++++++++++++++++++++++++++++---------
 contrib/postgres_fdw/option.c  |  4 +++
 2 files changed, 58 insertions(+), 14 deletions(-)

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 6001f4d..d5a673a 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -185,6 +185,8 @@ static void appendAggOrderBy(List *orderList, List *targetList,
 static void appendFunctionName(Oid funcid, deparse_expr_cxt *context);
 static Node *deparseSortGroupClause(Index ref, List *tlist, bool force_colno,
 					   deparse_expr_cxt *context);
+static void ExtractRoutineMappingOptions(List *defelems, char **remote_func_schema,
+										 char **remote_func_name);
 
 /*
  * Helper functions
@@ -3177,30 +3179,51 @@ appendOrderByClause(List *pathkeys, deparse_expr_cxt *context)
 static void
 appendFunctionName(Oid funcid, deparse_expr_cxt *context)
 {
+	PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) context->foreignrel->fdw_private;
+	ForeignServer	*server = fpinfo->server;
 	StringInfo	buf = context->buf;
-	HeapTuple	proctup;
+	HeapTuple	proctup = NULL;
 	Form_pg_proc procform;
-	const char *proname;
+	char *proname = NULL;
+	char *schemaname = NULL;
+	Oid			rmId;
 
-	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
-	if (!HeapTupleIsValid(proctup))
-		elog(ERROR, "cache lookup failed for function %u", funcid);
-	procform = (Form_pg_proc) GETSTRUCT(proctup);
+	rmId = GetSysCacheOid2(ROUTINEMAPPINGPROCSERVER,
+						   ObjectIdGetDatum(funcid),
+						   ObjectIdGetDatum(server->serverid));
 
-	/* Print schema name only if it's not pg_catalog */
-	if (procform->pronamespace != PG_CATALOG_NAMESPACE)
+	/* This function is mapped, get remote schema and function name */
+	if (OidIsValid(rmId))
 	{
-		const char *schemaname;
+		RoutineMapping *rm;
 
-		schemaname = get_namespace_name(procform->pronamespace);
-		appendStringInfo(buf, "%s.", quote_identifier(schemaname));
+		rm = GetRoutineMapping(rmId);
+		ExtractRoutineMappingOptions(rm->options, &schemaname, &proname);
 	}
 
+	if (!schemaname || !proname)
+	{
+		proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
+		if (!HeapTupleIsValid(proctup))
+			elog(ERROR, "cache lookup failed for function %u", funcid);
+		procform = (Form_pg_proc) GETSTRUCT(proctup);
+
+		/* Print schema name only if it's not pg_catalog */
+		if (!schemaname && procform->pronamespace != PG_CATALOG_NAMESPACE)
+			schemaname = get_namespace_name(procform->pronamespace);
+
+		if (!proname)
+			proname = NameStr(procform->proname);
+	}
+
+	if (schemaname)
+		appendStringInfo(buf, "%s.", quote_identifier(schemaname));
+
 	/* Always print the function name */
-	proname = NameStr(procform->proname);
-	appendStringInfoString(buf, quote_identifier(proname));
+	appendStringInfo(buf, "%s", quote_identifier(proname));
 
-	ReleaseSysCache(proctup);
+	if (HeapTupleIsValid(proctup))
+		ReleaseSysCache(proctup);
 }
 
 /*
@@ -3342,3 +3365,20 @@ get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
 	/* Shouldn't get here */
 	elog(ERROR, "unexpected expression in subquery output");
 }
+
+static void
+ExtractRoutineMappingOptions(List *defelems, char **remote_func_schema,
+							 char **remote_func_name)
+{
+	ListCell *lc;
+
+	foreach(lc, defelems)
+	{
+		DefElem *d = (DefElem *) lfirst(lc);
+
+		if (strcmp(d->defname, "remote_func_schema") == 0)
+			*remote_func_schema = defGetString(d);
+		else if (strcmp(d->defname, "remote_func_name") == 0)
+			*remote_func_name = defGetString(d);
+	}
+}
diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index 6854f1b..2d5e21c 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -17,6 +17,7 @@
 #include "access/reloptions.h"
 #include "catalog/pg_foreign_server.h"
 #include "catalog/pg_foreign_table.h"
+#include "catalog/pg_routine_mapping.h"
 #include "catalog/pg_user_mapping.h"
 #include "commands/defrem.h"
 #include "commands/extension.h"
@@ -177,6 +178,9 @@ InitPgFdwOptions(void)
 		/* fetch_size is available on both server and table */
 		{"fetch_size", ForeignServerRelationId, false},
 		{"fetch_size", ForeignTableRelationId, false},
+		/* Routine mapping */
+		{"remote_func_name", RoutineMappingRelationId, false},
+		{"remote_func_schema", RoutineMappingRelationId, false},
 		{NULL, InvalidOid, false}
 	};
 
-- 
2.10.5

