Hello,

The SQL-MED specification defines the IMPORT FOREIGN SCHEMA statement.

This adds discoverability to foreign servers. The structure of the statement
as I understand it is simple enough:

IMPORT FOREIGN SCHEMA remote_schema FROM SERVER some_server [ (LIMIT TO |
EXCEPT) table_list ] INTO local_schema.

Is anyone working on this? I found a reference to this from 2010 in the
archive, stating that work should be focused on core functionality, but
nothing more recent.

This would be very useful for postgres_fdw and other RDBMS-backed fdws, but I
think even file_fdw could benefit from it if it was able to create a foreign
table for every csv-with-header file in a directory.

I can see a simple API working for that.  A new function would be added to the
fdw routine, which is responsible for crafting CreateForeignTableStmt. It
could have the following signature:

typedef List *(*ImportForeignSchema_function) (ForeignServer *server,
ImportForeignSchemaStmt * parsetree);


I experimented with this idea, and came up with the attached two patches: one
for the core, and the other for actually implementing the API in postgres_fdw.

Maybe those can serve as a proof-of-concept for discussing the design?


--
Ronan Dunklau
http://dalibo.com - http://dalibo.org
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 024a477..40a2540 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -250,7 +250,8 @@ check_ddl_tag(const char *tag)
 		pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
 		pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
 		pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||
-		pg_strcasecmp(tag, "DROP OWNED") == 0)
+		pg_strcasecmp(tag, "DROP OWNED") == 0 ||
+		pg_strcasecmp(tag, "IMPORT FOREIGN SCHEMA") == 0)
 		return EVENT_TRIGGER_COMMAND_TAG_OK;

 	/*
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 7f007d7..719c674 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -27,7 +27,9 @@
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
 #include "commands/defrem.h"
+#include "commands/tablecmds.h"
 #include "foreign/foreign.h"
+#include "foreign/fdwapi.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
 #include "utils/acl.h"
@@ -1427,3 +1429,48 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)

 	heap_close(ftrel, RowExclusiveLock);
 }
+
+/*
+ * Import a foreign schema
+ */
+void
+ImportForeignSchema(ImportForeignSchemaStmt * stmt)
+{
+	Oid			ownerId;
+	ForeignDataWrapper *fdw;
+	ForeignServer *server;
+	FdwRoutine *fdw_routine;
+	AclResult	aclresult;
+	List	   *table_list = NULL;
+	ListCell   *lc;
+	char * local_schema = strdup(stmt->local_schema);
+
+	ownerId = GetUserId();
+	server = GetForeignServerByName(stmt->servername, false);
+	aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);
+
+	/* Check the permissions on the schema */
+	LookupCreationNamespace(local_schema);
+
+	fdw = GetForeignDataWrapper(server->fdwid);
+	fdw_routine = GetFdwRoutine(fdw->fdwhandler);
+	if (fdw_routine->ImportForeignSchema == NULL)
+	{
+		ereport(ERROR,
+				(errcode(ERRCODE_FDW_NO_SCHEMAS),
+				 errmsg("This FDW does not support schema importation")));
+	}
+	table_list = fdw_routine->ImportForeignSchema(server, stmt);
+	foreach(lc, table_list)
+	{
+		CreateForeignTableStmt *create_stmt = lfirst(lc);
+		Oid			relOid = DefineRelation((CreateStmt *) create_stmt,
+											RELKIND_FOREIGN_TABLE,
+											InvalidOid);
+		/* Override whatever the fdw set for the schema */
+		create_stmt->base.relation->schemaname = local_schema;
+		CreateForeignTable(create_stmt, relOid);
+	}
+}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 81169a4..80c18cc 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -235,8 +235,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
 		DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
 		DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
-		GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
-		LockStmt NotifyStmt ExplainableStmt PreparableStmt
+		GrantStmt GrantRoleStmt IndexStmt ImportForeignSchemaStmt InsertStmt
+		ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt
 		CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
 		RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
 		RuleActionStmt RuleActionStmtOrEmpty RuleStmt
@@ -319,6 +319,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <ival>	defacl_privilege_target
 %type <defelt>	DefACLOption
 %type <list>	DefACLOptionList
+%type <node>	OptImportForeignSchemaRestriction
+%type <ival>	ImportForeignSchemaRestrictionType

 %type <list>	stmtblock stmtmulti
 				OptTableElementList TableElementList OptInherit definition
@@ -552,7 +554,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);

 	HANDLER HAVING HEADER_P HOLD HOUR_P

-	IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
+	IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P IMPORT
 	INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
 	INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
 	INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
@@ -797,6 +799,7 @@ stmt :
 			| FetchStmt
 			| GrantStmt
 			| GrantRoleStmt
+			| ImportForeignSchemaStmt
 			| IndexStmt
 			| InsertStmt
 			| ListenStmt
@@ -1286,6 +1289,40 @@ schema_stmt:
 		;


+/*
+ * IMPORT FOREIGN SCHEMA statement
+ */
+ImportForeignSchemaStmt:
+			IMPORT FOREIGN SCHEMA name FROM SERVER name
+			OptImportForeignSchemaRestriction INTO name {
+				ImportForeignSchemaStmt *n = makeNode(ImportForeignSchemaStmt);
+					n->remote_schema = $4;
+					n->servername = $7;
+					n->restriction = (ImportForeignSchemaRestriction * ) $8;
+					n->local_schema = $10;
+					$$ = (Node *) n;
+			};
+
+ImportForeignSchemaRestrictionType:
+			LIMIT TO 							{ $$ = IMPORT_LIMIT_TO; }
+			| EXCEPT 						{ $$ = IMPORT_EXCEPT; };
+
+OptImportForeignSchemaRestriction:
+			ImportForeignSchemaRestrictionType '(' relation_expr_list ')' {
+				ImportForeignSchemaRestriction * restriction = makeNode(ImportForeignSchemaRestriction);
+				restriction->restriction_type = $1;
+				restriction->table_list = $3;
+				$$ = (Node *) restriction;
+			}
+			| /*EMPTY*/ {
+				ImportForeignSchemaRestriction * restriction = makeNode(ImportForeignSchemaRestriction);
+				restriction->restriction_type = IMPORT_ALL;
+				restriction->table_list = NULL;
+				$$ = (Node *) restriction;
+			};
+
+
+
 /*****************************************************************************
  *
  * Set PG internal variable
@@ -2701,6 +2738,7 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 				}
 		;

+
 /*
  * Redundancy here is needed to avoid shift/reduce conflicts,
  * since TEMP is not a reserved word.  See also OptTempTableName.
@@ -12881,6 +12919,7 @@ unreserved_keyword:
 			| IMMEDIATE
 			| IMMUTABLE
 			| IMPLICIT_P
+			| IMPORT
 			| INCLUDING
 			| INCREMENT
 			| INDEX
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index d1621ad..8d8b9b9 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -202,6 +202,7 @@ check_xact_readonly(Node *parsetree)
 		case T_AlterTableSpaceOptionsStmt:
 		case T_AlterTableSpaceMoveStmt:
 		case T_CreateForeignTableStmt:
+		case T_ImportForeignSchemaStmt:
 		case T_SecLabelStmt:
 			PreventCommandIfReadOnly(CreateCommandTag(parsetree));
 			break;
@@ -1316,6 +1317,10 @@ ProcessUtilitySlow(Node *parsetree,
 				ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
 				break;

+			case T_ImportForeignSchemaStmt:
+				ImportForeignSchema((ImportForeignSchemaStmt *) parsetree);
+				break;
+
 			default:
 				elog(ERROR, "unrecognized node type: %d",
 					 (int) nodeTag(parsetree));
@@ -1853,6 +1858,10 @@ CreateCommandTag(Node *parsetree)
 			tag = "CREATE FOREIGN TABLE";
 			break;

+		case T_ImportForeignSchemaStmt:
+			tag = "IMPORT FOREIGN SCHEMA";
+			break;
+
 		case T_DropStmt:
 			switch (((DropStmt *) parsetree)->removeType)
 			{
@@ -2518,6 +2527,7 @@ GetCommandLogLevel(Node *parsetree)
 		case T_CreateUserMappingStmt:
 		case T_AlterUserMappingStmt:
 		case T_DropUserMappingStmt:
+		case T_ImportForeignSchemaStmt:
 			lev = LOGSTMT_DDL;
 			break;

diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 5ec9374..ea7967f 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -124,6 +124,7 @@ extern Oid	AlterUserMapping(AlterUserMappingStmt *stmt);
 extern Oid	RemoveUserMapping(DropUserMappingStmt *stmt);
 extern void RemoveUserMappingById(Oid umId);
 extern void CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid);
+extern void ImportForeignSchema(ImportForeignSchemaStmt * stmt);
 extern Datum transformGenericOptions(Oid catalogId,
 						Datum oldOptions,
 						List *options,
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 1b735da..adc9569 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -14,6 +14,7 @@

 #include "nodes/execnodes.h"
 #include "nodes/relation.h"
+#include "foreign/foreign.h"

 /* To avoid including explain.h here, reference ExplainState thus: */
 struct ExplainState;
@@ -100,6 +101,10 @@ typedef bool (*AnalyzeForeignTable_function) (Relation relation,
 												 AcquireSampleRowsFunc *func,
 													BlockNumber *totalpages);

+typedef List *(*ImportForeignSchema_function) (ForeignServer *server,
+										ImportForeignSchemaStmt * parsetree);
+
+
 /*
  * FdwRoutine is the struct returned by a foreign-data wrapper's handler
  * function.  It provides pointers to the callback functions needed by the
@@ -144,6 +149,9 @@ typedef struct FdwRoutine

 	/* Support functions for ANALYZE */
 	AnalyzeForeignTable_function AnalyzeForeignTable;
+
+	/* Support functions for IMPORT FOREIGN SCHEMA */
+	ImportForeignSchema_function ImportForeignSchema;
 } FdwRoutine;


diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 5b8df59..474f25d 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -365,6 +365,7 @@ typedef enum NodeTag
 	T_RefreshMatViewStmt,
 	T_ReplicaIdentityStmt,
 	T_AlterSystemStmt,
+	T_ImportForeignSchemaStmt,

 	/*
 	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
@@ -406,6 +407,8 @@ typedef enum NodeTag
 	T_XmlSerialize,
 	T_WithClause,
 	T_CommonTableExpr,
+	T_ImportForeignSchemaRestriction,
+	T_ImportForeignSchemaRestrictionType,

 	/*
 	 * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b5011af..39044ef 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1248,6 +1248,34 @@ typedef enum DropBehavior
 } DropBehavior;

 /* ----------------------
+ * Import Foreign Schema statement
+ * ----------------------
+ */
+
+typedef enum ImportForeignSchemaRestrictionType
+{
+	IMPORT_ALL,
+	IMPORT_LIMIT_TO,
+	IMPORT_EXCEPT
+}	ImportForeignSchemaRestrictionType;
+
+typedef struct ImportForeignSchemaRestriction
+{
+	ImportForeignSchemaRestrictionType restriction_type;
+	List	   *table_list;
+}	ImportForeignSchemaRestriction;
+
+typedef struct ImportForeignSchemaStmt
+{
+	NodeTag		type;
+	char	   *remote_schema;
+	char	   *servername;
+	char	   *local_schema;
+	ImportForeignSchemaRestriction * restriction;
+	List	   *table_names;
+}	ImportForeignSchemaStmt;
+
+/* ----------------------
  *	Alter Table
  * ----------------------
  */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 61fae22..74a94e4 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -184,6 +184,7 @@ PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD)
 PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD)
 PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD)
+PG_KEYWORD("import", IMPORT, UNRESERVED_KEYWORD)
 PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
 PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
 PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index fde1ec1..6c522ae 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -288,6 +288,7 @@ static void postgresExplainForeignModify(ModifyTableState *mtstate,
 static bool postgresAnalyzeForeignTable(Relation relation,
 							AcquireSampleRowsFunc *func,
 							BlockNumber *totalpages);
+static List *postgresImportForeignSchema(ForeignServer *server, ImportForeignSchemaStmt * parsetree);

 /*
  * Helper functions
@@ -328,6 +329,7 @@ static HeapTuple make_tuple_from_result_row(PGresult *res,
 						   List *retrieved_attrs,
 						   MemoryContext temp_context);
 static void conversion_error_callback(void *arg);
+static PGresult *fetch_remote_tables(PGconn *conn, ImportForeignSchemaStmt * stmt);


 /*
@@ -365,6 +367,9 @@ postgres_fdw_handler(PG_FUNCTION_ARGS)
 	/* Support functions for ANALYZE */
 	routine->AnalyzeForeignTable = postgresAnalyzeForeignTable;

+	/* Support functions for IMPORT FOREIGN SCHEMA */
+	routine->ImportForeignSchema = postgresImportForeignSchema;
+
 	PG_RETURN_POINTER(routine);
 }

@@ -2300,6 +2305,170 @@ postgresAnalyzeForeignTable(Relation relation,
 	return true;
 }

+static PGresult *
+fetch_remote_tables(PGconn *conn, ImportForeignSchemaStmt * stmt)
+{
+	StringInfoData buf;
+	int			numparams;
+	const char **params = palloc0(sizeof(char *) * 2);
+	PGresult   *res = NULL;
+
+	initStringInfo(&buf);
+	params[0] = strdup((stmt->remote_schema));
+
+	// Check that the schema really exists
+	appendStringInfo(&buf, "SELECT 1 FROM pg_namespace WHERE nspname = $1");
+	res = PQexecParams(conn, buf.data, 1, NULL, params, NULL, NULL, 0);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		pgfdw_report_error(ERROR, res, conn, true, buf.data);
+	if(PQntuples(res) != 1)
+	{
+		ereport(ERROR,
+				(errcode(ERRCODE_FDW_SCHEMA_NOT_FOUND),
+					errmsg("The schema %s does not exist on the server", params[0])));
+	}
+
+
+	// Fetch all tables from this schema
+	resetStringInfo(&buf);
+	appendStringInfo(&buf,
+		"SELECT relname, "
+			"array_agg(attname::name) as colnames, "
+			"array_agg(atttypid::regtype) as coltypes, "
+			"array_agg(atttypmod::int4) as coltypmod "
+		"FROM pg_class "
+		"INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
+		"LEFT  JOIN pg_attribute ON pg_class.oid = pg_attribute.attrelid "
+			 "  AND pg_attribute.attnum >= 0 AND NOT pg_attribute.attisdropped "
+		"WHERE relkind IN ('r', 'v', 'f') "
+		"AND pg_namespace.nspname = $1 ");
+	if (stmt->restriction->restriction_type != IMPORT_ALL)
+	{
+		/* Add conditions */
+		Oid			outfuncoid;
+		bool		isvarlena;
+		Datum	   *elems = palloc0(list_length(stmt->restriction->table_list) * sizeof(Datum));
+		ArrayType  *array;
+		int			i = 0;
+		ListCell   *lc;
+		FmgrInfo   *fmout = palloc0(sizeof(FmgrInfo));
+		getTypeOutputInfo(CSTRINGARRAYOID, &outfuncoid, &isvarlena);
+		fmgr_info(outfuncoid, fmout);
+		foreach(lc, stmt->restriction->table_list)
+		{
+			elems[i] = CStringGetDatum(((RangeVar *) lfirst(lc))->relname);
+			i++;
+		}
+		array = construct_array(elems, i, CSTRINGOID, -2, false, 'c');
+		params[1] = OutputFunctionCall(fmout, PointerGetDatum(array));
+		appendStringInfo(&buf, "AND ");
+		if (stmt->restriction->restriction_type == IMPORT_EXCEPT)
+		{
+			appendStringInfo(&buf, "NOT ");
+		}
+		appendStringInfo(&buf, "pg_class.relname = ANY($2)");
+		numparams = 2;
+		pfree(fmout);
+		pfree(elems);
+	}
+	else
+	{
+		numparams = 1;
+	}
+	appendStringInfo(&buf, "GROUP BY pg_class.oid, pg_class.relname");
+	res = PQexecParams(conn, buf.data, numparams, NULL, params, NULL, NULL, 0);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		pgfdw_report_error(ERROR, res, conn, true, buf.data);
+	pfree(params);
+	return res;
+}
+
+/*
+ * Map a remote schema to a local one.
+ */
+static List *
+postgresImportForeignSchema(ForeignServer *server,
+							ImportForeignSchemaStmt * parsetree)
+{
+	List	   *tables = NULL;
+	Oid			userid = GetUserId();
+	UserMapping *mapping = GetUserMapping(userid, server->serverid);
+	PGconn	   *conn = GetConnection(server, mapping, false);
+	PGresult   *res;
+	int			numrows,
+				i;
+
+	/* Initialize FmgrInfo for parsing arrays */
+	FmgrInfo   *fmgr_infos = palloc0(sizeof(FmgrInfo) * 3);
+	Oid			typoid,
+			   *typioparam = palloc0(sizeof(Oid) * 3);
+	ArrayIterator *arrays = palloc0(sizeof(ArrayIterator) * 3);
+	Oid			column_types[3] = {NAMEARRAYOID, REGTYPEARRAYOID, INT4ARRAYOID};
+	Datum	   *array_item = palloc0(sizeof(Datum) * 3);
+	bool	   *isnull = palloc0(sizeof(bool) * 3);
+
+	for (i = 0; i < 3; i++)
+	{
+		getTypeInputInfo(column_types[i], &typoid, &typioparam[i]);
+		fmgr_info(typoid, &fmgr_infos[i]);
+	}
+	res = fetch_remote_tables(conn, parsetree);
+	numrows = PQntuples(res);
+	for (i = 0; i < numrows; i++)
+	{
+		CreateForeignTableStmt *stmt = makeNode(CreateForeignTableStmt);
+		char	   *tablename;
+		int			colindex;
+
+		tablename = PQgetvalue(res, i, 0);
+		/* setup the base relation information */
+		stmt->base.relation = makeRangeVar(NULL, tablename, 0);
+		stmt->base.relation->schemaname = strdup(parsetree->local_schema);
+		stmt->servername = server->servername;
+		/* Parse arrays of columns from the result */
+		for (colindex = 0; colindex < 3; colindex++)
+		{
+			Datum		array_datum = InputFunctionCall(&fmgr_infos[colindex],
+											PQgetvalue(res, i, colindex + 1),
+												   typioparam[colindex], -1);
+
+			arrays[colindex] = array_create_iterator(DatumGetArrayTypeP(array_datum), 0);
+		}
+		/* add the individual columns */
+		while (array_iterate(arrays[0], &array_item[0], &isnull[0]) &&
+			   array_iterate(arrays[1], &array_item[1], &isnull[1]) &&
+			   array_iterate(arrays[2], &array_item[2], &isnull[2]))
+		{
+			ColumnDef  *new_column = makeNode(ColumnDef);
+
+			new_column->colname = DatumGetCString(array_item[0]);
+			new_column->typeName = makeTypeNameFromOid(DatumGetObjectId(array_item[1]),
+											   DatumGetInt32(array_item[2]));
+			stmt->base.tableElts = lappend(stmt->base.tableElts, new_column);
+		}
+
+		/*
+		 * Add schema_name and table_name options table_name is added to
+		 * survive a foreign table rename.
+		 */
+		stmt->options = lappend(stmt->options,
+								makeDefElem("schema_name", (Node *) makeString(parsetree->remote_schema)));
+		stmt->options = lappend(stmt->options,
+				  makeDefElem("table_name", (Node *) makeString(tablename)));
+		tables = lappend(tables, stmt);
+	}
+	/* Cleanup */
+	PQclear(res);
+	ReleaseConnection(conn);
+	pfree(array_item);
+	pfree(fmgr_infos);
+	pfree(arrays);
+	pfree(typioparam);
+	pfree(isnull);
+
+	return tables;
+}
+
 /*
  * Acquire a random sample of rows from foreign table managed by postgres_fdw.
  *
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index db18a23..47efb2f 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -445,6 +445,7 @@ DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1002 (  _char		 PGNSP PGUID -1 f b A f t \054 0	18 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1003 (  _name		 PGNSP PGUID -1 f b A f t \054 0	19 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+#define NAMEARRAYOID 1003
 DATA(insert OID = 1005 (  _int2		 PGNSP PGUID -1 f b A f t \054 0	21 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 #define INT2ARRAYOID		1005
 DATA(insert OID = 1006 (  _int2vector PGNSP PGUID -1 f b A f t \054 0	22 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to