diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 322138dd0cd6e9be5fa3617a31b77b3b454ffa95..2045774f24f074c39c7aebdfe45808968dae7087 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -116,7 +116,6 @@ static void deparseReturningList(StringInfo buf, PlannerInfo *root,
 static void deparseColumnRef(StringInfo buf, int varno, int varattno,
 				 PlannerInfo *root);
 static void deparseRelation(StringInfo buf, Relation rel);
-static void deparseStringLiteral(StringInfo buf, const char *val);
 static void deparseExpr(Expr *expr, deparse_expr_cxt *context);
 static void deparseVar(Var *node, deparse_expr_cxt *context);
 static void deparseConst(Const *node, deparse_expr_cxt *context);
@@ -1160,7 +1159,7 @@ deparseRelation(StringInfo buf, Relation rel)
 /*
  * Append a SQL string literal representing "val" to buf.
  */
-static void
+void
 deparseStringLiteral(StringInfo buf, const char *val)
 {
 	const char *valptr;
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2e49ee317a2901af6107b5e4f8bd940c392b9fa4..7eead58cffbbdb09deb0d4a05eb6c039eb61e76a 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -2834,3 +2834,233 @@ NOTICE:  NEW: (13,"test triggered !")
  (0,27)
 (1 row)
 
+-- ===================================================================
+-- test IMPORT FOREIGN SCHEMA
+-- ===================================================================
+CREATE SCHEMA import_source;
+CREATE TABLE import_source.t1 (c1 int, c2 varchar NOT NULL);
+CREATE TABLE import_source.t2 (c1 int default 42, c2 varchar NULL, c3 text collate "POSIX");
+CREATE TYPE typ1 AS (m1 int, m2 varchar);
+CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
+CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
+CREATE TABLE import_source."x 5" (c1 float8);
+ALTER TABLE import_source."x 5" DROP COLUMN c1;
+CREATE SCHEMA import_dest1;
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
+\det+ import_dest1
+                                     List of foreign tables
+    Schema    | Table |  Server  |                   FDW Options                   | Description 
+--------------+-------+----------+-------------------------------------------------+-------------
+ import_dest1 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
+ import_dest1 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
+ import_dest1 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
+ import_dest1 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
+ import_dest1 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
+(5 rows)
+
+\d import_dest1.*
+               Foreign table "import_dest1.t1"
+ Column |       Type        | Modifiers |    FDW Options     
+--------+-------------------+-----------+--------------------
+ c1     | integer           |           | (column_name 'c1')
+ c2     | character varying | not null  | (column_name 'c2')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't1')
+
+                 Foreign table "import_dest1.t2"
+ Column |       Type        |   Modifiers   |    FDW Options     
+--------+-------------------+---------------+--------------------
+ c1     | integer           |               | (column_name 'c1')
+ c2     | character varying |               | (column_name 'c2')
+ c3     | text              | collate POSIX | (column_name 'c3')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't2')
+
+                  Foreign table "import_dest1.t3"
+ Column |           Type           | Modifiers |    FDW Options     
+--------+--------------------------+-----------+--------------------
+ c1     | timestamp with time zone |           | (column_name 'c1')
+ c2     | typ1                     |           | (column_name 'c2')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't3')
+
+                 Foreign table "import_dest1.x 4"
+ Column |         Type          | Modifiers |     FDW Options     
+--------+-----------------------+-----------+---------------------
+ c1     | double precision      |           | (column_name 'c1')
+ C 2    | text                  |           | (column_name 'C 2')
+ c3     | character varying(42) |           | (column_name 'c3')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 'x 4')
+
+    Foreign table "import_dest1.x 5"
+ Column | Type | Modifiers | FDW Options 
+--------+------+-----------+-------------
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 'x 5')
+
+-- Options
+CREATE SCHEMA import_dest2;
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2
+  OPTIONS (import_default 'true');
+\det+ import_dest2
+                                     List of foreign tables
+    Schema    | Table |  Server  |                   FDW Options                   | Description 
+--------------+-------+----------+-------------------------------------------------+-------------
+ import_dest2 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
+ import_dest2 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
+ import_dest2 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
+ import_dest2 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
+ import_dest2 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
+(5 rows)
+
+\d import_dest2.*
+               Foreign table "import_dest2.t1"
+ Column |       Type        | Modifiers |    FDW Options     
+--------+-------------------+-----------+--------------------
+ c1     | integer           |           | (column_name 'c1')
+ c2     | character varying | not null  | (column_name 'c2')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't1')
+
+                 Foreign table "import_dest2.t2"
+ Column |       Type        |   Modifiers   |    FDW Options     
+--------+-------------------+---------------+--------------------
+ c1     | integer           | default 42    | (column_name 'c1')
+ c2     | character varying |               | (column_name 'c2')
+ c3     | text              | collate POSIX | (column_name 'c3')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't2')
+
+                    Foreign table "import_dest2.t3"
+ Column |           Type           |   Modifiers   |    FDW Options     
+--------+--------------------------+---------------+--------------------
+ c1     | timestamp with time zone | default now() | (column_name 'c1')
+ c2     | typ1                     |               | (column_name 'c2')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't3')
+
+                 Foreign table "import_dest2.x 4"
+ Column |         Type          | Modifiers |     FDW Options     
+--------+-----------------------+-----------+---------------------
+ c1     | double precision      |           | (column_name 'c1')
+ C 2    | text                  |           | (column_name 'C 2')
+ c3     | character varying(42) |           | (column_name 'c3')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 'x 4')
+
+    Foreign table "import_dest2.x 5"
+ Column | Type | Modifiers | FDW Options 
+--------+------+-----------+-------------
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 'x 5')
+
+CREATE SCHEMA import_dest3;
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
+  OPTIONS (import_collate 'false', import_not_null 'false');
+\det+ import_dest3
+                                     List of foreign tables
+    Schema    | Table |  Server  |                   FDW Options                   | Description 
+--------------+-------+----------+-------------------------------------------------+-------------
+ import_dest3 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
+ import_dest3 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
+ import_dest3 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
+ import_dest3 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
+ import_dest3 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
+(5 rows)
+
+\d import_dest3.*
+               Foreign table "import_dest3.t1"
+ Column |       Type        | Modifiers |    FDW Options     
+--------+-------------------+-----------+--------------------
+ c1     | integer           |           | (column_name 'c1')
+ c2     | character varying |           | (column_name 'c2')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't1')
+
+               Foreign table "import_dest3.t2"
+ Column |       Type        | Modifiers |    FDW Options     
+--------+-------------------+-----------+--------------------
+ c1     | integer           |           | (column_name 'c1')
+ c2     | character varying |           | (column_name 'c2')
+ c3     | text              |           | (column_name 'c3')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't2')
+
+                  Foreign table "import_dest3.t3"
+ Column |           Type           | Modifiers |    FDW Options     
+--------+--------------------------+-----------+--------------------
+ c1     | timestamp with time zone |           | (column_name 'c1')
+ c2     | typ1                     |           | (column_name 'c2')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 't3')
+
+                 Foreign table "import_dest3.x 4"
+ Column |         Type          | Modifiers |     FDW Options     
+--------+-----------------------+-----------+---------------------
+ c1     | double precision      |           | (column_name 'c1')
+ C 2    | text                  |           | (column_name 'C 2')
+ c3     | character varying(42) |           | (column_name 'c3')
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 'x 4')
+
+    Foreign table "import_dest3.x 5"
+ Column | Type | Modifiers | FDW Options 
+--------+------+-----------+-------------
+Server: loopback
+FDW Options: (schema_name 'import_source', table_name 'x 5')
+
+-- Check LIMIT TO and EXCEPT
+CREATE SCHEMA import_dest4;
+IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch)
+  FROM SERVER loopback INTO import_dest4;
+\det+ import_dest4
+                                     List of foreign tables
+    Schema    | Table |  Server  |                  FDW Options                   | Description 
+--------------+-------+----------+------------------------------------------------+-------------
+ import_dest4 | t1    | loopback | (schema_name 'import_source', table_name 't1') | 
+(1 row)
+
+IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch)
+  FROM SERVER loopback INTO import_dest4;
+\det+ import_dest4
+                                     List of foreign tables
+    Schema    | Table |  Server  |                   FDW Options                   | Description 
+--------------+-------+----------+-------------------------------------------------+-------------
+ import_dest4 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
+ import_dest4 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
+ import_dest4 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
+ import_dest4 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
+(4 rows)
+
+-- Assorted error cases
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;
+ERROR:  relation "t1" already exists
+CONTEXT:  importing foreign table "t1"
+IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO import_dest4;
+ERROR:  schema "nonesuch" is not present on foreign server "loopback"
+IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO notthere;
+ERROR:  schema "notthere" does not exist
+IMPORT FOREIGN SCHEMA nonesuch FROM SERVER nowhere INTO notthere;
+ERROR:  server "nowhere" does not exist
+-- Check case of a type present only on the remote server.
+-- We can fake this by dropping the type locally in our transaction.
+CREATE TYPE "Colors" AS ENUM ('red', 'green', 'blue');
+CREATE TABLE import_source.t5 (c1 int, c2 text collate "C", "Col" "Colors");
+CREATE SCHEMA import_dest5;
+BEGIN;
+DROP TYPE "Colors" CASCADE;
+NOTICE:  drop cascades to table import_source.t5 column Col
+IMPORT FOREIGN SCHEMA import_source LIMIT TO (t5)
+  FROM SERVER loopback INTO import_dest5;  -- ERROR
+ERROR:  type "public.Colors" does not exist
+LINE 4:   "Col" public."Colors" OPTIONS (column_name 'Col')
+                ^
+QUERY:  CREATE FOREIGN TABLE t5 (
+  c1 integer OPTIONS (column_name 'c1'),
+  c2 text OPTIONS (column_name 'c2') COLLATE pg_catalog."C",
+  "Col" public."Colors" OPTIONS (column_name 'Col')
+) SERVER loopback
+OPTIONS (schema_name 'import_source', table_name 't5');
+CONTEXT:  importing foreign table "t5"
+ROLLBACK;
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 56374905f5b26ed407699795ccd56619527d379a..19debfb5c9ef1d8c9d2b22d6b93c2ff91e74699e 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -285,6 +285,8 @@ static void postgresExplainForeignModify(ModifyTableState *mtstate,
 static bool postgresAnalyzeForeignTable(Relation relation,
 							AcquireSampleRowsFunc *func,
 							BlockNumber *totalpages);
+static List *postgresImportForeignSchema(ImportForeignSchemaStmt *stmt,
+							Oid serverOid);
 
 /*
  * Helper functions
@@ -362,6 +364,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);
 }
 
@@ -2563,6 +2568,270 @@ analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
 	}
 }
 
+/*
+ * Import a foreign schema
+ */
+static List *
+postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
+{
+	List	   *commands = NIL;
+	bool		import_collate = true;
+	bool		import_default = false;
+	bool		import_not_null = true;
+	ForeignServer *server;
+	UserMapping *mapping;
+	PGconn	   *conn;
+	StringInfoData buf;
+	PGresult   *volatile res = NULL;
+	int			numrows,
+				i;
+	ListCell   *lc;
+
+	/* Parse statement options */
+	foreach(lc, stmt->options)
+	{
+		DefElem    *def = (DefElem *) lfirst(lc);
+
+		if (strcmp(def->defname, "import_collate") == 0)
+			import_collate = defGetBoolean(def);
+		else if (strcmp(def->defname, "import_default") == 0)
+			import_default = defGetBoolean(def);
+		else if (strcmp(def->defname, "import_not_null") == 0)
+			import_not_null = defGetBoolean(def);
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
+					 errmsg("invalid option \"%s\"", def->defname)));
+	}
+
+	/*
+	 * Get connection to the foreign server.  Connection manager will
+	 * establish new connection if necessary.
+	 */
+	server = GetForeignServer(serverOid);
+	mapping = GetUserMapping(GetUserId(), server->serverid);
+	conn = GetConnection(server, mapping, false);
+
+	/* Don't attempt to import collation if remote server hasn't got it */
+	if (PQserverVersion(conn) < 90100)
+		import_collate = false;
+
+	/* Create workspace for strings */
+	initStringInfo(&buf);
+
+	/* In what follows, do not risk leaking any PGresults. */
+	PG_TRY();
+	{
+		/* Check that the schema really exists */
+		appendStringInfoString(&buf, "SELECT 1 FROM pg_catalog.pg_namespace WHERE nspname = ");
+		deparseStringLiteral(&buf, stmt->remote_schema);
+
+		res = PQexec(conn, buf.data);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+			pgfdw_report_error(ERROR, res, conn, false, buf.data);
+
+		if (PQntuples(res) != 1)
+			ereport(ERROR,
+					(errcode(ERRCODE_FDW_SCHEMA_NOT_FOUND),
+			  errmsg("schema \"%s\" is not present on foreign server \"%s\"",
+					 stmt->remote_schema, server->servername)));
+
+		PQclear(res);
+		res = NULL;
+		resetStringInfo(&buf);
+
+		/*
+		 * Fetch all table data from this schema, possibly restricted by
+		 * EXCEPT or LIMIT TO.
+		 *
+		 * Note: because we run the connection with search_path restricted to
+		 * pg_catalog, the format_type() and pg_get_expr() outputs will always
+		 * include a schema name for types/functions in other schemas, which
+		 * is what we want.
+		 */
+		if (import_collate)
+			appendStringInfoString(&buf,
+								   "SELECT relname, "
+								   "  attname, "
+								   "  format_type(atttypid, atttypmod), "
+								   "  attnotnull, "
+								   "  pg_get_expr(adbin, adrelid), "
+								   "  collname, "
+								   "  collnsp.nspname "
+								   "FROM pg_class c "
+								   "  JOIN pg_namespace n ON "
+								   "    relnamespace = n.oid "
+								   "  LEFT JOIN pg_attribute a ON "
+								   "    attrelid = c.oid AND attnum > 0 "
+								   "      AND NOT attisdropped "
+								   "  LEFT JOIN pg_attrdef ad ON "
+								   "    adrelid = c.oid AND adnum = attnum "
+								   "  LEFT JOIN pg_collation coll ON "
+								   "    coll.oid = attcollation "
+								   "  LEFT JOIN pg_namespace collnsp ON "
+								   "    collnsp.oid = collnamespace ");
+		else
+			appendStringInfoString(&buf,
+								   "SELECT relname, "
+								   "  attname, "
+								   "  format_type(atttypid, atttypmod), "
+								   "  attnotnull, "
+								   "  pg_get_expr(adbin, adrelid), "
+								   "  NULL, NULL "
+								   "FROM pg_class c "
+								   "  JOIN pg_namespace n ON "
+								   "    relnamespace = n.oid "
+								   "  LEFT JOIN pg_attribute a ON "
+								   "    attrelid = c.oid AND attnum > 0 "
+								   "      AND NOT attisdropped "
+								   "  LEFT JOIN pg_attrdef ad ON "
+								   "    adrelid = c.oid AND adnum = attnum ");
+
+		appendStringInfoString(&buf,
+							   "WHERE c.relkind IN ('r', 'v', 'f', 'm') "
+							   "  AND n.nspname = ");
+		deparseStringLiteral(&buf, stmt->remote_schema);
+
+		/* Apply restrictions for LIMIT TO and EXCEPT */
+		if (stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO ||
+			stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT)
+		{
+			bool		first_item = true;
+
+			appendStringInfoString(&buf, " AND c.relname ");
+			if (stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT)
+				appendStringInfoString(&buf, "NOT ");
+			appendStringInfoString(&buf, "IN (");
+
+			/* Append list of table names within IN clause */
+			foreach(lc, stmt->table_list)
+			{
+				RangeVar   *rv = (RangeVar *) lfirst(lc);
+
+				if (first_item)
+					first_item = false;
+				else
+					appendStringInfoString(&buf, ", ");
+				deparseStringLiteral(&buf, rv->relname);
+			}
+			appendStringInfoString(&buf, ")");
+		}
+
+		/* Append ORDER BY at the end of query to ensure output ordering */
+		appendStringInfo(&buf, " ORDER BY c.relname, a.attnum");
+
+		/* Fetch the data */
+		res = PQexec(conn, buf.data);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+			pgfdw_report_error(ERROR, res, conn, false, buf.data);
+
+		/* Process results */
+		numrows = PQntuples(res);
+		/* note: incrementation of i happens in inner loop's while() test */
+		for (i = 0; i < numrows;)
+		{
+			char	   *tablename = PQgetvalue(res, i, 0);
+			bool		first_item = true;
+
+			resetStringInfo(&buf);
+			appendStringInfo(&buf, "CREATE FOREIGN TABLE %s (\n",
+							 quote_identifier(tablename));
+
+			/* Scan all rows for this table */
+			do
+			{
+				char	   *attname;
+				char	   *typename;
+				char	   *attnotnull;
+				char	   *attdefault;
+				char	   *collname;
+				char	   *collnamespace;
+
+				/* If table has no columns, we'll see nulls here */
+				if (PQgetisnull(res, i, 1))
+					continue;
+
+				attname = PQgetvalue(res, i, 1);
+				typename = PQgetvalue(res, i, 2);
+				attnotnull = PQgetvalue(res, i, 3);
+				attdefault = PQgetisnull(res, i, 4) ? (char *) NULL :
+					PQgetvalue(res, i, 4);
+				collname = PQgetisnull(res, i, 5) ? (char *) NULL :
+					PQgetvalue(res, i, 5);
+				collnamespace = PQgetisnull(res, i, 6) ? (char *) NULL :
+					PQgetvalue(res, i, 6);
+
+				if (first_item)
+					first_item = false;
+				else
+					appendStringInfoString(&buf, ",\n");
+
+				/* Print column name and type */
+				appendStringInfo(&buf, "  %s %s",
+								 quote_identifier(attname),
+								 typename);
+
+				/*
+				 * Add column_name option so that renaming the foreign table's
+				 * column doesn't break the association to the underlying
+				 * column.
+				 */
+				appendStringInfoString(&buf, " OPTIONS (column_name ");
+				deparseStringLiteral(&buf, attname);
+				appendStringInfoString(&buf, ")");
+
+				/* Add COLLATE if needed */
+				if (import_collate && collname != NULL && collnamespace != NULL)
+					appendStringInfo(&buf, " COLLATE %s.%s",
+									 quote_identifier(collnamespace),
+									 quote_identifier(collname));
+
+				/* Add DEFAULT if needed */
+				if (import_default && attdefault != NULL)
+					appendStringInfo(&buf, " DEFAULT %s", attdefault);
+
+				/* Add NOT NULL if needed */
+				if (import_not_null && attnotnull[0] == 't')
+					appendStringInfoString(&buf, " NOT NULL");
+			}
+			while (++i < numrows &&
+				   strcmp(PQgetvalue(res, i, 0), tablename) == 0);
+
+			/*
+			 * Add server name and table-level options.  We specify remote
+			 * schema and table name as options (the latter to ensure that
+			 * renaming the foreign table doesn't break the association).
+			 */
+			appendStringInfo(&buf, "\n) SERVER %s\nOPTIONS (",
+							 quote_identifier(server->servername));
+
+			appendStringInfoString(&buf, "schema_name ");
+			deparseStringLiteral(&buf, stmt->remote_schema);
+			appendStringInfoString(&buf, ", table_name ");
+			deparseStringLiteral(&buf, tablename);
+
+			appendStringInfoString(&buf, ");");
+
+			commands = lappend(commands, pstrdup(buf.data));
+		}
+
+		/* Clean up */
+		PQclear(res);
+		res = NULL;
+	}
+	PG_CATCH();
+	{
+		if (res)
+			PQclear(res);
+		PG_RE_THROW();
+	}
+	PG_END_TRY();
+
+	ReleaseConnection(conn);
+
+	return commands;
+}
+
 /*
  * Create a tuple from the specified row of the PGresult.
  *
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 8aa8f1a1b58fcb41f21950e32eff01a76af3f59b..94eadae891650cde2747fbf6a2ff85d41e056484 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -73,5 +73,6 @@ extern void deparseDeleteSql(StringInfo buf, PlannerInfo *root,
 extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
 extern void deparseAnalyzeSql(StringInfo buf, Relation rel,
 				  List **retrieved_attrs);
+extern void deparseStringLiteral(StringInfo buf, const char *val);
 
 #endif   /* POSTGRES_FDW_H */
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 6187839453c0aa6cf30e561773e1e84d3b4d4e29..9f54359be5842f025f5e429905503219177a97b2 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -609,3 +609,60 @@ UPDATE rem1 SET f2 = 'testo';
 
 -- Test returning a system attribute
 INSERT INTO rem1(f2) VALUES ('test') RETURNING ctid;
+
+-- ===================================================================
+-- test IMPORT FOREIGN SCHEMA
+-- ===================================================================
+
+CREATE SCHEMA import_source;
+CREATE TABLE import_source.t1 (c1 int, c2 varchar NOT NULL);
+CREATE TABLE import_source.t2 (c1 int default 42, c2 varchar NULL, c3 text collate "POSIX");
+CREATE TYPE typ1 AS (m1 int, m2 varchar);
+CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
+CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
+CREATE TABLE import_source."x 5" (c1 float8);
+ALTER TABLE import_source."x 5" DROP COLUMN c1;
+
+CREATE SCHEMA import_dest1;
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
+\det+ import_dest1
+\d import_dest1.*
+
+-- Options
+CREATE SCHEMA import_dest2;
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2
+  OPTIONS (import_default 'true');
+\det+ import_dest2
+\d import_dest2.*
+CREATE SCHEMA import_dest3;
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
+  OPTIONS (import_collate 'false', import_not_null 'false');
+\det+ import_dest3
+\d import_dest3.*
+
+-- Check LIMIT TO and EXCEPT
+CREATE SCHEMA import_dest4;
+IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch)
+  FROM SERVER loopback INTO import_dest4;
+\det+ import_dest4
+IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch)
+  FROM SERVER loopback INTO import_dest4;
+\det+ import_dest4
+
+-- Assorted error cases
+IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;
+IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO import_dest4;
+IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO notthere;
+IMPORT FOREIGN SCHEMA nonesuch FROM SERVER nowhere INTO notthere;
+
+-- Check case of a type present only on the remote server.
+-- We can fake this by dropping the type locally in our transaction.
+CREATE TYPE "Colors" AS ENUM ('red', 'green', 'blue');
+CREATE TABLE import_source.t5 (c1 int, c2 text collate "C", "Col" "Colors");
+
+CREATE SCHEMA import_dest5;
+BEGIN;
+DROP TYPE "Colors" CASCADE;
+IMPORT FOREIGN SCHEMA import_source LIMIT TO (t5)
+  FROM SERVER loopback INTO import_dest5;  -- ERROR
+ROLLBACK;
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 8ace8bd3a2537849cdaac52b620baa8ed97a9095..3b7fff4846c85abc731e670c9f24a9ab9e3ee883 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3069,8 +3069,9 @@ ANALYZE measurement;
     For additional information, see
     <xref linkend="sql-createforeigndatawrapper">,
     <xref linkend="sql-createserver">,
-    <xref linkend="sql-createusermapping">, and
-    <xref linkend="sql-createforeigntable">.
+    <xref linkend="sql-createusermapping">,
+    <xref linkend="sql-createforeigntable">, and
+    <xref linkend="sql-importforeignschema">.
    </para>
  </sect1>
 
diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml
index e5b9e6618530471bc956b7f47682198046ee72ba..3db8ef1a132d1df8664be27ed9691b994d03f952 100644
--- a/doc/src/sgml/event-trigger.sgml
+++ b/doc/src/sgml/event-trigger.sgml
@@ -603,6 +603,12 @@
         <entry align="center"><literal>X</literal></entry>
         <entry align="center"><literal>X</literal></entry>
        </row>
+       <row>
+        <entry align="left"><literal>IMPORT FOREIGN SCHEMA</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>-</literal></entry>
+       </row>
        <row>
         <entry align="left"><literal>SELECT INTO</literal></entry>
         <entry align="center"><literal>X</literal></entry>
diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index 6b5c8b7e97b3a6f2091e20892af67ac41fdeb088..5fd8d6fbbe9fbdb2da055c37d67ba8f99cd34e61 100644
--- a/doc/src/sgml/fdwhandler.sgml
+++ b/doc/src/sgml/fdwhandler.sgml
@@ -696,6 +696,66 @@ AcquireSampleRowsFunc (Relation relation, int elevel,
 
    </sect2>
 
+   <sect2 id="fdw-callbacks-import">
+    <title>FDW Routines For <command>IMPORT FOREIGN SCHEMA</></title>
+
+    <para>
+<programlisting>
+List *
+ImportForeignSchema (ImportForeignSchemaStmt *stmt, Oid serverOid);
+</programlisting>
+
+     Obtain a list of foreign table creation commands.  This function is
+     called when executing <xref linkend="sql-importforeignschema">, and is
+     passed the parse tree for that statement, as well as the OID of the
+     foreign server to use.  It should return a list of C strings, each of
+     which must contain a <xref linkend="sql-createforeigntable"> command.
+     These strings will be parsed and executed by the core server.
+    </para>
+
+    <para>
+     Within the <structname>ImportForeignSchemaStmt</> struct,
+     <structfield>remote_schema</> is the name of the remote schema from
+     which tables are to be imported.
+     <structfield>list_type</> identifies how to filter table names:
+     <literal>FDW_IMPORT_SCHEMA_ALL</> means that all tables in the remote
+     schema should be imported (in this case <structfield>table_list</> is
+     empty), <literal>FDW_IMPORT_SCHEMA_LIMIT_TO</> means to include only
+     tables listed in <structfield>table_list</>,
+     and <literal>FDW_IMPORT_SCHEMA_EXCEPT</> means to exclude the tables
+     listed in <structfield>table_list</>.
+     <structfield>options</> is a list of options used for the import process.
+     The meanings of the options are up to the FDW.
+     For example, an FDW could use an option to define whether the
+     <literal>NOT NULL</> attributes of columns should be imported.
+     These options need not have anything to do with those supported by the
+     FDW as database object options.
+    </para>
+
+    <para>
+     The FDW may ignore the <structfield>local_schema</> field of
+     the <structname>ImportForeignSchemaStmt</>, because the core server
+     will automatically insert that name into the parsed <command>CREATE
+     FOREIGN TABLE</> commands.
+    </para>
+
+    <para>
+     The FDW does not have to concern itself with implementing the filtering
+     specified by <structfield>list_type</> and <structfield>table_list</>,
+     either, as the core server will automatically skip any returned commands
+     for tables excluded according to those options.  However, it's often
+     useful to avoid the work of creating commands for excluded tables in the
+     first place.  The function <function>IsImportableForeignTable()</> may be
+     useful to test whether a given foreign-table name will pass the filter.
+    </para>
+
+    <para>
+     If the FDW does not support importing table definitions, the
+     <function>ImportForeignSchema</> pointer can be set to <literal>NULL</>.
+    </para>
+
+   </sect2>
+
    </sect1>
 
    <sect1 id="fdw-helpers">
diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml
index e6f6e205815cae003f3554d1b8df0f5885d28deb..43adb61455d919eae10c3debae954e4111b95296 100644
--- a/doc/src/sgml/postgres-fdw.sgml
+++ b/doc/src/sgml/postgres-fdw.sgml
@@ -49,7 +49,8 @@
    </listitem>
    <listitem>
     <para>
-     Create a foreign table, using <xref linkend="sql-createforeigntable">,
+     Create a foreign table, using <xref linkend="sql-createforeigntable">
+     or <xref linkend="sql-importforeignschema">,
      for each remote table you want to access.  The columns of the foreign
      table must match the referenced remote table.  You can, however, use
      table and/or column names different from the remote table's, if you
@@ -99,7 +100,7 @@
      <listitem>
       <para>
        <literal>user</literal> and <literal>password</literal> (specify these
-       for a user mapping, instead)
+       in a user mapping, instead)
       </para>
      </listitem>
      <listitem>
@@ -291,6 +292,72 @@
 
    </variablelist>
   </sect3>
+
+  <sect3>
+   <title>Importing Options</title>
+
+   <para>
+    <filename>postgres_fdw</> is able to import foreign table definitions
+    using <xref linkend="sql-importforeignschema">.  This command creates
+    foreign table definitions on the local server that match tables or
+    views present on the remote server.  If the remote tables to be imported
+    have columns of user-defined data types, the local server must have types
+    of the same names.
+   </para>
+
+   <para>
+    Importing behavior can be customized with the following options
+    (given in the <command>IMPORT FOREIGN SCHEMA</> command):
+   </para>
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>import_collate</literal></term>
+     <listitem>
+      <para>
+       This option controls whether column <literal>COLLATE</> options
+       are included in the definitions of foreign tables imported
+       from a foreign server. The default is <literal>true</>.  You might
+       need to turn this off if the remote server has a different set of
+       collation names than the local server does, which is likely to be the
+       case if it's running on a different operating system.
+      </para>
+     </listitem>
+    </varlistentry>
+    <varlistentry>
+     <term><literal>import_default</literal></term>
+     <listitem>
+      <para>
+       This option controls whether column <literal>DEFAULT</> expressions
+       are included in the definitions of foreign tables imported
+       from a foreign server. The default is <literal>false</>.  If you
+       enable this option, be wary of defaults that might get computed
+       differently on the local server than they would be on the remote
+       server; <function>nextval()</> is a common source of problems.
+       The <command>IMPORT</> will fail altogether if an imported default
+       expression uses a function or operator that does not exist locally.
+      </para>
+     </listitem>
+    </varlistentry>
+    <varlistentry>
+     <term><literal>import_not_null</literal></term>
+     <listitem>
+      <para>
+       This option controls whether column <literal>NOT NULL</>
+       constraints are included in the definitions of foreign tables imported
+       from a foreign server. The default is <literal>true</>.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+
+   <para>
+    Note that constraints other than <literal>NOT NULL</> will never be
+    imported from the remote tables, since <productname>PostgreSQL</>
+    does not support any other type of constraint on a foreign table.
+    Checking other types of constraints is always left to the remote server.
+   </para>
+  </sect3>
  </sect2>
 
  <sect2>
@@ -422,7 +489,7 @@ CREATE USER MAPPING FOR local_user
 
 <programlisting>
 CREATE FOREIGN TABLE foreign_table (
-        id serial NOT NULL,
+        id integer NOT NULL,
         data text
 )
         SERVER foreign_server
@@ -434,6 +501,8 @@ CREATE FOREIGN TABLE foreign_table (
    Column names must match as well, unless you attach <literal>column_name</>
    options to the individual columns to show how they are named in the remote
    table.
+   In many cases, use of <xref linkend="sql-importforeignschema"> is
+   preferable to constructing foreign table definitions manually.
   </para>
  </sect2>
 
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index 1b0962c253d8f7be11a87c1c8324c28d84e100c6..b685e16a0fa0a524cf45aebbf428619241c579b3 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -131,6 +131,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY explain            SYSTEM "explain.sgml">
 <!ENTITY fetch              SYSTEM "fetch.sgml">
 <!ENTITY grant              SYSTEM "grant.sgml">
+<!ENTITY importForeignSchema SYSTEM "import_foreign_schema.sgml">
 <!ENTITY insert             SYSTEM "insert.sgml">
 <!ENTITY listen             SYSTEM "listen.sgml">
 <!ENTITY load               SYSTEM "load.sgml">
diff --git a/doc/src/sgml/ref/create_foreign_table.sgml b/doc/src/sgml/ref/create_foreign_table.sgml
index 4a8cf3889c29bddcca3aa6d6bad3a5aff2f0b8e1..46a20eff14f8f25220a50fa23f1e311fe40f6a65 100644
--- a/doc/src/sgml/ref/create_foreign_table.sgml
+++ b/doc/src/sgml/ref/create_foreign_table.sgml
@@ -231,6 +231,7 @@ SERVER film_server;
    <member><xref linkend="sql-dropforeigntable"></member>
    <member><xref linkend="sql-createtable"></member>
    <member><xref linkend="sql-createserver"></member>
+   <member><xref linkend="sql-importforeignschema"></member>
   </simplelist>
  </refsect1>
 </refentry>
diff --git a/doc/src/sgml/ref/import_foreign_schema.sgml b/doc/src/sgml/ref/import_foreign_schema.sgml
new file mode 100644
index 0000000000000000000000000000000000000000..bdcc26558acf0f1c52877ddefcd81c98e3d82ae3
--- /dev/null
+++ b/doc/src/sgml/ref/import_foreign_schema.sgml
@@ -0,0 +1,168 @@
+<!--
+doc/src/sgml/ref/import_foreign_schema.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-IMPORTFOREIGNSCHEMA">
+ <indexterm zone="sql-importforeignschema">
+  <primary>IMPORT FOREIGN SCHEMA</primary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle>IMPORT FOREIGN SCHEMA</refentrytitle>
+  <manvolnum>7</manvolnum>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>IMPORT FOREIGN SCHEMA</refname>
+  <refpurpose>import table definitions from a foreign server</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+IMPORT FOREIGN SCHEMA <replaceable class="PARAMETER">remote_schema</replaceable>
+[ { LIMIT TO | EXCEPT } ( <replaceable class="PARAMETER">table_name</replaceable> [, ...] ) ]
+FROM SERVER <replaceable class="PARAMETER">server_name</replaceable>
+INTO <replaceable class="PARAMETER">local_schema</replaceable>
+[ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="SQL-IMPORTFOREIGNSCHEMA-description">
+  <title>Description</title>
+
+  <para>
+   <command>IMPORT FOREIGN SCHEMA</command> creates foreign tables that
+   represent tables existing on a foreign server.  The new foreign tables
+   will be owned by the user issuing the command and are created with
+   the correct column definitions and options to match the remote tables.
+  </para>
+
+  <para>
+   By default, all tables and views existing in a particular schema on the
+   foreign server are imported.  Optionally, the list of tables can be limited
+   to a specified subset, or specific tables can be excluded.  The new foreign
+   tables are all created in the target schema, which must already exist.
+  </para>
+
+  <para>
+   To use <command>IMPORT FOREIGN SCHEMA</command>, the user must have
+   <literal>USAGE</literal> privilege on the foreign server, as well as
+   <literal>CREATE</literal> privilege on the target schema.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Parameters</title>
+
+  <variablelist>
+
+   <varlistentry>
+    <term><replaceable class="PARAMETER">remote_schema</replaceable></term>
+    <listitem>
+     <para>
+      The remote schema to import from. The specific meaning of a remote schema
+      depends on the foreign data wrapper in use.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>LIMIT TO ( <replaceable class="PARAMETER">table_name</replaceable> [, ...] )</literal></term>
+    <listitem>
+     <para>
+      Import only foreign tables matching one of the given table names.
+      Other tables existing in the foreign schema will be ignored.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>EXCEPT ( <replaceable class="PARAMETER">table_name</replaceable> [, ...] )</literal></term>
+    <listitem>
+     <para>
+      Exclude specified foreign tables from the import.  All tables
+      existing in the foreign schema will be imported except the
+      ones listed here.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="PARAMETER">server_name</replaceable></term>
+    <listitem>
+     <para>
+      The foreign server to import from.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="PARAMETER">local_schema</replaceable></term>
+    <listitem>
+     <para>
+      The schema in which the imported foreign tables will be created.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ...] )</literal></term>
+    <listitem>
+     <para>
+      Options to be used during the import.
+      The allowed option names and values are specific to each foreign
+      data wrapper.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </refsect1>
+
+ <refsect1 id="SQL-IMPORTFOREIGNSCHEMA-examples">
+  <title>Examples</title>
+
+  <para>
+   Import table definitions from a remote schema <structname>foreign_films</>
+   on server <structname>film_server</>, creating the foreign tables in
+   local schema <structname>films</>:
+
+<programlisting>
+IMPORT FOREIGN SCHEMA foreign_films
+    FROM SERVER film_server INTO films;
+</programlisting>
+   </para>
+
+  <para>
+   As above, but import only the two tables <structname>actors</> and
+   <literal>directors</> (if they exist):
+
+<programlisting>
+IMPORT FOREIGN SCHEMA foreign_films LIMIT TO (actors, directors)
+    FROM SERVER film_server INTO films;
+</programlisting>
+   </para>
+
+ </refsect1>
+
+ <refsect1 id="SQL-IMPORTFOREIGNSCHEMA-compatibility">
+  <title>Compatibility</title>
+
+  <para>
+   The <command>IMPORT FOREIGN SCHEMA</command> command conforms to the
+   <acronym>SQL</acronym> standard, except that the <literal>OPTIONS</>
+   clause is a <productname>PostgreSQL</> extension.
+  </para>
+
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-createforeigntable"></member>
+   <member><xref linkend="sql-createserver"></member>
+  </simplelist>
+ </refsect1>
+</refentry>
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index a6575f52ac08ef6db43fc4d73c5eb61db0f2992d..6ec126381c3b5ffbe484759ed702ce145f60c009 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -159,6 +159,7 @@
    &explain;
    &fetch;
    &grant;
+   &importForeignSchema;
    &insert;
    &listen;
    &load;
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 110fe004a464fcbbb5001d31a26b1c85e586e602..754264eb3eea0b9ebbae51d3aeae943451703ffd 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 8ab9c439db25487932d793895a2b12ce8b798b44..ab4ed6c78ece0a3e6e377ce62b102a63108f946f 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -15,8 +15,8 @@
 
 #include "access/heapam.h"
 #include "access/htup_details.h"
-#include "access/xact.h"
 #include "access/reloptions.h"
+#include "access/xact.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/objectaccess.h"
@@ -27,9 +27,11 @@
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
 #include "commands/defrem.h"
+#include "foreign/fdwapi.h"
 #include "foreign/foreign.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
+#include "tcop/utility.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -37,6 +39,16 @@
 #include "utils/syscache.h"
 
 
+typedef struct
+{
+	char	   *tablename;
+	char	   *cmd;
+} import_error_callback_arg;
+
+/* Internal functions */
+static void import_error_callback(void *arg);
+
+
 /*
  * Convert a DefElem list to the text array format that is used in
  * pg_foreign_data_wrapper, pg_foreign_server, pg_user_mapping, and
@@ -1427,3 +1439,133 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
 
 	heap_close(ftrel, RowExclusiveLock);
 }
+
+/*
+ * Import a foreign schema
+ */
+void
+ImportForeignSchema(ImportForeignSchemaStmt *stmt)
+{
+	ForeignServer *server;
+	ForeignDataWrapper *fdw;
+	FdwRoutine *fdw_routine;
+	AclResult	aclresult;
+	List	   *cmd_list;
+	ListCell   *lc;
+
+	/* Check that the foreign server exists and that we have USAGE on it */
+	server = GetForeignServerByName(stmt->server_name, false);
+	aclresult = pg_foreign_server_aclcheck(server->serverid, GetUserId(), ACL_USAGE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);
+
+	/* Check that the schema exists and we have CREATE permissions on it */
+	(void) LookupCreationNamespace(stmt->local_schema);
+
+	/* Get the FDW and check it supports IMPORT */
+	fdw = GetForeignDataWrapper(server->fdwid);
+	if (!OidIsValid(fdw->fdwhandler))
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("foreign-data wrapper \"%s\" has no handler",
+						fdw->fdwname)));
+	fdw_routine = GetFdwRoutine(fdw->fdwhandler);
+	if (fdw_routine->ImportForeignSchema == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_FDW_NO_SCHEMAS),
+				 errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA",
+						fdw->fdwname)));
+
+	/* Call FDW to get a list of commands */
+	cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid);
+
+	/* Parse and execute each command */
+	foreach(lc, cmd_list)
+	{
+		char	   *cmd = (char *) lfirst(lc);
+		import_error_callback_arg callback_arg;
+		ErrorContextCallback sqlerrcontext;
+		List	   *raw_parsetree_list;
+		ListCell   *lc2;
+
+		/*
+		 * Setup error traceback support for ereport().  This is so that any
+		 * error in the generated SQL will be displayed nicely.
+		 */
+		callback_arg.tablename = NULL;	/* not known yet */
+		callback_arg.cmd = cmd;
+		sqlerrcontext.callback = import_error_callback;
+		sqlerrcontext.arg = (void *) &callback_arg;
+		sqlerrcontext.previous = error_context_stack;
+		error_context_stack = &sqlerrcontext;
+
+		/*
+		 * Parse the SQL string into a list of raw parse trees.
+		 */
+		raw_parsetree_list = pg_parse_query(cmd);
+
+		/*
+		 * Process each parse tree (we allow the FDW to put more than one
+		 * command per string, though this isn't really advised).
+		 */
+		foreach(lc2, raw_parsetree_list)
+		{
+			CreateForeignTableStmt *cstmt = lfirst(lc2);
+
+			/*
+			 * Because we only allow CreateForeignTableStmt, we can skip parse
+			 * analysis, rewrite, and planning steps here.
+			 */
+			if (!IsA(cstmt, CreateForeignTableStmt))
+				elog(ERROR,
+					 "foreign-data wrapper \"%s\" returned incorrect statement type %d",
+					 fdw->fdwname, (int) nodeTag(cstmt));
+
+			/* Ignore commands for tables excluded by filter options */
+			if (!IsImportableForeignTable(cstmt->base.relation->relname, stmt))
+				continue;
+
+			/* Enable reporting of current table's name on error */
+			callback_arg.tablename = cstmt->base.relation->relname;
+
+			/* Ensure creation schema is the one given in IMPORT statement */
+			cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
+
+			/* Execute statement */
+			ProcessUtility((Node *) cstmt,
+						   cmd,
+						   PROCESS_UTILITY_SUBCOMMAND, NULL,
+						   None_Receiver, NULL);
+
+			/* Be sure to advance the command counter between subcommands */
+			CommandCounterIncrement();
+
+			callback_arg.tablename = NULL;
+		}
+
+		error_context_stack = sqlerrcontext.previous;
+	}
+}
+
+/*
+ * error context callback to let us supply the failing SQL statement's text
+ */
+static void
+import_error_callback(void *arg)
+{
+	import_error_callback_arg *callback_arg = (import_error_callback_arg *) arg;
+	int			syntaxerrposition;
+
+	/* If it's a syntax error, convert to internal syntax error report */
+	syntaxerrposition = geterrposition();
+	if (syntaxerrposition > 0)
+	{
+		errposition(0);
+		internalerrposition(syntaxerrposition);
+		internalerrquery(callback_arg->cmd);
+	}
+
+	if (callback_arg->tablename)
+		errcontext("importing foreign table \"%s\"",
+				   callback_arg->tablename);
+}
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index 6d548b7d08b7be04a34b969a69a47ed1f79ccfe4..4f5f6ae362b565fb48f1eb1991b88c4aaf40b033 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -399,6 +399,47 @@ GetFdwRoutineForRelation(Relation relation, bool makecopy)
 }
 
 
+/*
+ * IsImportableForeignTable - filter table names for IMPORT FOREIGN SCHEMA
+ *
+ * Returns TRUE if given table name should be imported according to the
+ * statement's import filter options.
+ */
+bool
+IsImportableForeignTable(const char *tablename,
+						 ImportForeignSchemaStmt *stmt)
+{
+	ListCell   *lc;
+
+	switch (stmt->list_type)
+	{
+		case FDW_IMPORT_SCHEMA_ALL:
+			return true;
+
+		case FDW_IMPORT_SCHEMA_LIMIT_TO:
+			foreach(lc, stmt->table_list)
+			{
+				RangeVar   *rv = (RangeVar *) lfirst(lc);
+
+				if (strcmp(tablename, rv->relname) == 0)
+					return true;
+			}
+			return false;
+
+		case FDW_IMPORT_SCHEMA_EXCEPT:
+			foreach(lc, stmt->table_list)
+			{
+				RangeVar   *rv = (RangeVar *) lfirst(lc);
+
+				if (strcmp(tablename, rv->relname) == 0)
+					return false;
+			}
+			return true;
+	}
+	return false;				/* shouldn't get here */
+}
+
+
 /*
  * deflist_to_tuplestore - Helper function to convert DefElem list to
  * tuplestore usable in SRF.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 8d3d5a7c7347a6c87ea42fe9064a4aa2c39ccd9d..30885789304f10affba9f1dedc19393a5698ceeb 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3567,6 +3567,21 @@ _copyCreateForeignTableStmt(const CreateForeignTableStmt *from)
 	return newnode;
 }
 
+static ImportForeignSchemaStmt *
+_copyImportForeignSchemaStmt(const ImportForeignSchemaStmt *from)
+{
+	ImportForeignSchemaStmt *newnode = makeNode(ImportForeignSchemaStmt);
+
+	COPY_STRING_FIELD(server_name);
+	COPY_STRING_FIELD(remote_schema);
+	COPY_STRING_FIELD(local_schema);
+	COPY_SCALAR_FIELD(list_type);
+	COPY_NODE_FIELD(table_list);
+	COPY_NODE_FIELD(options);
+
+	return newnode;
+}
+
 static CreateTrigStmt *
 _copyCreateTrigStmt(const CreateTrigStmt *from)
 {
@@ -4477,6 +4492,9 @@ copyObject(const void *from)
 		case T_CreateForeignTableStmt:
 			retval = _copyCreateForeignTableStmt(from);
 			break;
+		case T_ImportForeignSchemaStmt:
+			retval = _copyImportForeignSchemaStmt(from);
+			break;
 		case T_CreateTrigStmt:
 			retval = _copyCreateTrigStmt(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index e7b49f680cf01a1a8f6ca2a4aa4f26cc41bece72..1b07db69d732a797c26be12ae80c9d1cb58e5d82 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1768,6 +1768,19 @@ _equalCreateForeignTableStmt(const CreateForeignTableStmt *a, const CreateForeig
 	return true;
 }
 
+static bool
+_equalImportForeignSchemaStmt(const ImportForeignSchemaStmt *a, const ImportForeignSchemaStmt *b)
+{
+	COMPARE_STRING_FIELD(server_name);
+	COMPARE_STRING_FIELD(remote_schema);
+	COMPARE_STRING_FIELD(local_schema);
+	COMPARE_SCALAR_FIELD(list_type);
+	COMPARE_NODE_FIELD(table_list);
+	COMPARE_NODE_FIELD(options);
+
+	return true;
+}
+
 static bool
 _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b)
 {
@@ -2943,6 +2956,9 @@ equal(const void *a, const void *b)
 		case T_CreateForeignTableStmt:
 			retval = _equalCreateForeignTableStmt(a, b);
 			break;
+		case T_ImportForeignSchemaStmt:
+			retval = _equalImportForeignSchemaStmt(a, b);
+			break;
 		case T_CreateTrigStmt:
 			retval = _equalCreateTrigStmt(a, b);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c182212e62f76d0ad87c89235bea66cde9a389a9..9573a9bb0e6d9347b7fdfc3ef2c92fa9919ecd1c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2011,6 +2011,19 @@ _outCreateForeignTableStmt(StringInfo str, const CreateForeignTableStmt *node)
 	WRITE_NODE_FIELD(options);
 }
 
+static void
+_outImportForeignSchemaStmt(StringInfo str, const ImportForeignSchemaStmt *node)
+{
+	WRITE_NODE_TYPE("IMPORTFOREIGNSCHEMASTMT");
+
+	WRITE_STRING_FIELD(server_name);
+	WRITE_STRING_FIELD(remote_schema);
+	WRITE_STRING_FIELD(local_schema);
+	WRITE_ENUM_FIELD(list_type, ImportForeignSchemaType);
+	WRITE_NODE_FIELD(table_list);
+	WRITE_NODE_FIELD(options);
+}
+
 static void
 _outIndexStmt(StringInfo str, const IndexStmt *node)
 {
@@ -3119,6 +3132,9 @@ _outNode(StringInfo str, const void *obj)
 			case T_CreateForeignTableStmt:
 				_outCreateForeignTableStmt(str, obj);
 				break;
+			case T_ImportForeignSchemaStmt:
+				_outImportForeignSchemaStmt(str, obj);
+				break;
 			case T_IndexStmt:
 				_outIndexStmt(str, obj);
 				break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ba7d091dc793c079481a9a0fab05a110c8e98ce7..a113809ca6376214ff20a61b3b7053d6010172d3 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -111,6 +111,13 @@ typedef struct PrivTarget
 	List	   *objs;
 } PrivTarget;
 
+/* Private struct for the result of import_qualification production */
+typedef struct ImportQual
+{
+	ImportForeignSchemaType type;
+	List	   *table_names;
+} ImportQual;
+
 /* ConstraintAttributeSpec yields an integer bitmask of these flags: */
 #define CAS_NOT_DEFERRABLE			0x01
 #define CAS_DEFERRABLE				0x02
@@ -212,6 +219,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	ResTarget			*target;
 	struct PrivTarget	*privtarget;
 	AccessPriv			*accesspriv;
+	struct ImportQual	*importqual;
 	InsertStmt			*istmt;
 	VariableSetStmt		*vsetstmt;
 }
@@ -238,8 +246,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 ImportForeignSchemaStmt IndexStmt InsertStmt
+		ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt
 		CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
 		RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt
 		RuleActionStmt RuleActionStmtOrEmpty RuleStmt
@@ -322,6 +330,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <ival>	defacl_privilege_target
 %type <defelt>	DefACLOption
 %type <list>	DefACLOptionList
+%type <ival>	import_qualification_type
+%type <importqual> import_qualification
 
 %type <list>	stmtblock stmtmulti
 				OptTableElementList TableElementList OptInherit definition
@@ -556,7 +566,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 IMPORT_P IN_P
 	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
@@ -802,6 +812,7 @@ stmt :
 			| FetchStmt
 			| GrantStmt
 			| GrantRoleStmt
+			| ImportForeignSchemaStmt
 			| IndexStmt
 			| InsertStmt
 			| ListenStmt
@@ -4272,6 +4283,52 @@ AlterForeignTableStmt:
 				}
 		;
 
+/*****************************************************************************
+ *
+ *		QUERY:
+ *				IMPORT FOREIGN SCHEMA remote_schema
+ *				[ { LIMIT TO | EXCEPT } ( table_list ) ]
+ *				FROM SERVER server_name INTO local_schema [ OPTIONS (...) ]
+ *
+ ****************************************************************************/
+
+ImportForeignSchemaStmt:
+		IMPORT_P FOREIGN SCHEMA name import_qualification
+		  FROM SERVER name INTO name create_generic_options
+			{
+				ImportForeignSchemaStmt *n = makeNode(ImportForeignSchemaStmt);
+				n->server_name = $8;
+				n->remote_schema = $4;
+				n->local_schema = $10;
+				n->list_type = $5->type;
+				n->table_list = $5->table_names;
+				n->options = $11;
+				$$ = (Node *) n;
+			}
+		;
+
+import_qualification_type:
+		LIMIT TO 				{ $$ = FDW_IMPORT_SCHEMA_LIMIT_TO; }
+		| EXCEPT 				{ $$ = FDW_IMPORT_SCHEMA_EXCEPT; }
+		;
+
+import_qualification:
+		import_qualification_type '(' relation_expr_list ')'
+			{
+				ImportQual *n = (ImportQual *) palloc(sizeof(ImportQual));
+				n->type = $1;
+				n->table_names = $3;
+				$$ = n;
+			}
+		| /*EMPTY*/
+			{
+				ImportQual *n = (ImportQual *) palloc(sizeof(ImportQual));
+				n->type = FDW_IMPORT_SCHEMA_ALL;
+				n->table_names = NIL;
+				$$ = n;
+			}
+		;
+
 /*****************************************************************************
  *
  *		QUERY:
@@ -12909,6 +12966,7 @@ unreserved_keyword:
 			| IMMEDIATE
 			| IMMUTABLE
 			| IMPLICIT_P
+			| IMPORT_P
 			| INCLUDING
 			| INCREMENT
 			| INDEX
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 3423898c1125cf64e292f0c1939e023cf408c2b5..07e0b987212fab60de65d7be81a4290afdad9be8 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;
@@ -1196,6 +1197,10 @@ ProcessUtilitySlow(Node *parsetree,
 				RemoveUserMapping((DropUserMappingStmt *) parsetree);
 				break;
 
+			case T_ImportForeignSchemaStmt:
+				ImportForeignSchema((ImportForeignSchemaStmt *) parsetree);
+				break;
+
 			case T_CompositeTypeStmt:	/* CREATE TYPE (composite) */
 				{
 					CompositeTypeStmt *stmt = (CompositeTypeStmt *) 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/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index bab03572352d1e5ba9b2b78a298de95065d929c4..6c2d431842c28dcc202e74047d70f6f79372a12d 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -876,8 +876,9 @@ psql_completion(const char *text, int start, int end)
 	static const char *const sql_commands[] = {
 		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
 		"COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
-		"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
-		"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
+		"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN",
+		"FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK",
+		"MOVE", "NOTIFY", "PREPARE",
 		"REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
 		"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
 		"TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
@@ -2947,6 +2948,13 @@ psql_completion(const char *text, int start, int end)
 			 pg_strcasecmp(prev_wd, "GROUP") == 0)
 		COMPLETE_WITH_CONST("BY");
 
+/* IMPORT FOREIGN SCHEMA */
+	else if (pg_strcasecmp(prev_wd, "IMPORT") == 0)
+		COMPLETE_WITH_CONST("FOREIGN SCHEMA");
+	else if (pg_strcasecmp(prev2_wd, "IMPORT") == 0 &&
+			 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
+		COMPLETE_WITH_CONST("SCHEMA");
+
 /* INSERT */
 	/* Complete INSERT with "INTO" */
 	else if (pg_strcasecmp(prev_wd, "INSERT") == 0)
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 5ec9374aad0df368af4ba39610972e3da4cb8c06..0ebdbc1c186f29a0fb29b4ebeaf3626ebe672956 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 1b735dacc6d5559bdad20b5a51b48f8a719a3635..dc0a7fc7235142b993baef71634fdd895d742ca6 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -100,6 +100,9 @@ typedef bool (*AnalyzeForeignTable_function) (Relation relation,
 												 AcquireSampleRowsFunc *func,
 													BlockNumber *totalpages);
 
+typedef List *(*ImportForeignSchema_function) (ImportForeignSchemaStmt *stmt,
+														   Oid serverOid);
+
 /*
  * 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 +147,9 @@ typedef struct FdwRoutine
 
 	/* Support functions for ANALYZE */
 	AnalyzeForeignTable_function AnalyzeForeignTable;
+
+	/* Support functions for IMPORT FOREIGN SCHEMA */
+	ImportForeignSchema_function ImportForeignSchema;
 } FdwRoutine;
 
 
@@ -151,5 +157,7 @@ typedef struct FdwRoutine
 extern FdwRoutine *GetFdwRoutine(Oid fdwhandler);
 extern FdwRoutine *GetFdwRoutineByRelId(Oid relid);
 extern FdwRoutine *GetFdwRoutineForRelation(Relation relation, bool makecopy);
+extern bool IsImportableForeignTable(const char *tablename,
+						 ImportForeignSchemaStmt *stmt);
 
 #endif   /* FDWAPI_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 7b0088fdb502d182825e84abaaceca88f6f6f19e..067c7685f0d2986c48f26d496cb089e881eaa085 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -357,6 +357,7 @@ typedef enum NodeTag
 	T_AlterTableSpaceMoveStmt,
 	T_SecLabelStmt,
 	T_CreateForeignTableStmt,
+	T_ImportForeignSchemaStmt,
 	T_CreateExtensionStmt,
 	T_AlterExtensionStmt,
 	T_AlterExtensionContentsStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ff126ebca4718263fd292f17473ca903b463068d..8364bef79f59c85fe02ea5330ca3a8a2af682dbb 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1791,7 +1791,7 @@ typedef struct AlterForeignServerStmt
 } AlterForeignServerStmt;
 
 /* ----------------------
- *		Create FOREIGN TABLE Statements
+ *		Create FOREIGN TABLE Statement
  * ----------------------
  */
 
@@ -1831,6 +1831,29 @@ typedef struct DropUserMappingStmt
 	bool		missing_ok;		/* ignore missing mappings */
 } DropUserMappingStmt;
 
+/* ----------------------
+ *		Import Foreign Schema Statement
+ * ----------------------
+ */
+
+typedef enum ImportForeignSchemaType
+{
+	FDW_IMPORT_SCHEMA_ALL,		/* all relations wanted */
+	FDW_IMPORT_SCHEMA_LIMIT_TO, /* include only listed tables in import */
+	FDW_IMPORT_SCHEMA_EXCEPT	/* exclude listed tables from import */
+} ImportForeignSchemaType;
+
+typedef struct ImportForeignSchemaStmt
+{
+	NodeTag		type;
+	char	   *server_name;	/* FDW server name */
+	char	   *remote_schema;	/* remote schema name to query */
+	char	   *local_schema;	/* local schema to create objects in */
+	ImportForeignSchemaType list_type;	/* type of table list */
+	List	   *table_list;		/* List of RangeVar */
+	List	   *options;		/* list of options to pass to FDW */
+} ImportForeignSchemaStmt;
+
 /* ----------------------
  *		Create TRIGGER Statement
  * ----------------------
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 04e98109635fa08a742557e59f285b25e796a1ca..b52e50757c8c4e51569294f01e507958fe9446d4 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_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("in", IN_P, RESERVED_KEYWORD)
 PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD)
 PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index ff203b201fd43e5b5955c8f7ba41cc3275275db0..e4dedb0c3ba2ca091da60a105d00f8185eeb27c3 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -1193,6 +1193,16 @@ DROP TRIGGER trigtest_before_row ON foreign_schema.foreign_table_1;
 DROP TRIGGER trigtest_after_stmt ON foreign_schema.foreign_table_1;
 DROP TRIGGER trigtest_after_row ON foreign_schema.foreign_table_1;
 DROP FUNCTION dummy_trigger();
+-- IMPORT FOREIGN SCHEMA
+IMPORT FOREIGN SCHEMA s1 FROM SERVER s9 INTO public; -- ERROR
+ERROR:  foreign-data wrapper "foo" has no handler
+IMPORT FOREIGN SCHEMA s1 LIMIT TO (t1) FROM SERVER s9 INTO public; --ERROR
+ERROR:  foreign-data wrapper "foo" has no handler
+IMPORT FOREIGN SCHEMA s1 EXCEPT (t1) FROM SERVER s9 INTO public; -- ERROR
+ERROR:  foreign-data wrapper "foo" has no handler
+IMPORT FOREIGN SCHEMA s1 EXCEPT (t1, t2) FROM SERVER s9 INTO public
+OPTIONS (option1 'value1', option2 'value2'); -- ERROR
+ERROR:  foreign-data wrapper "foo" has no handler
 -- DROP FOREIGN TABLE
 DROP FOREIGN TABLE no_table;                                    -- ERROR
 ERROR:  foreign table "no_table" does not exist
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index 0f0869ee268c3afb54defec8818ecb8941fabd34..de9dbc8f386c3f55ff37c19be54dd7586a1d7cd2 100644
--- a/src/test/regress/sql/foreign_data.sql
+++ b/src/test/regress/sql/foreign_data.sql
@@ -514,6 +514,13 @@ DROP TRIGGER trigtest_after_row ON foreign_schema.foreign_table_1;
 
 DROP FUNCTION dummy_trigger();
 
+-- IMPORT FOREIGN SCHEMA
+IMPORT FOREIGN SCHEMA s1 FROM SERVER s9 INTO public; -- ERROR
+IMPORT FOREIGN SCHEMA s1 LIMIT TO (t1) FROM SERVER s9 INTO public; --ERROR
+IMPORT FOREIGN SCHEMA s1 EXCEPT (t1) FROM SERVER s9 INTO public; -- ERROR
+IMPORT FOREIGN SCHEMA s1 EXCEPT (t1, t2) FROM SERVER s9 INTO public
+OPTIONS (option1 'value1', option2 'value2'); -- ERROR
+
 -- DROP FOREIGN TABLE
 DROP FOREIGN TABLE no_table;                                    -- ERROR
 DROP FOREIGN TABLE IF EXISTS no_table;