diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 38c6cf8..eab48fe 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -72,6 +72,20 @@ CREATE FOREIGN TABLE ft2 (
c8 user_enum
) SERVER loopback;
ALTER FOREIGN TABLE ft2 DROP COLUMN cx;
+CREATE FOREIGN TABLE ft_tables (
+ LIKE information_schema.tables
+) SERVER loopback
+OPTIONS (
+ schema_name 'information_schema',
+ table_name 'tables'
+);
+CREATE FOREIGN TABLE ft_columns (
+ LIKE information_schema.columns
+) SERVER loopback
+OPTIONS (
+ schema_name 'information_schema',
+ table_name 'columns'
+);
-- ===================================================================
-- tests for validator
-- ===================================================================
@@ -113,12 +127,14 @@ ALTER FOREIGN TABLE ft2 OPTIONS (schema_name 'S 1', table_name 'T 1');
ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (column_name 'C 1');
ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1');
\det+
- List of foreign tables
- Schema | Table | Server | FDW Options | Description
---------+-------+----------+---------------------------------------+-------------
- public | ft1 | loopback | (schema_name 'S 1', table_name 'T 1') |
- public | ft2 | loopback | (schema_name 'S 1', table_name 'T 1') |
-(2 rows)
+ List of foreign tables
+ Schema | Table | Server | FDW Options | Description
+--------+------------+----------+----------------------------------------------------------+-------------
+ public | ft1 | loopback | (schema_name 'S 1', table_name 'T 1') |
+ public | ft2 | loopback | (schema_name 'S 1', table_name 'T 1') |
+ public | ft_columns | loopback | (schema_name 'information_schema', table_name 'columns') |
+ public | ft_tables | loopback | (schema_name 'information_schema', table_name 'tables') |
+(4 rows)
-- Now we should be able to run ANALYZE.
-- To exercise multiple code paths, we use local stats on ft1
@@ -231,13 +247,25 @@ SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
101 | 1 | 00101 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo
(1 row)
--- aggregate
+-- aggregates
SELECT COUNT(*) FROM ft1 t1;
count
-------
1000
(1 row)
+SELECT t.table_name, COUNT(*)
+FROM ft_tables t JOIN ft_columns c USING (table_catalog, table_schema, table_name)
+WHERE t.table_type = 'FOREIGN TABLE'
+GROUP BY t.table_name;
+ table_name | count
+------------+-------
+ ft_columns | 44
+ ft2 | 8
+ ft_tables | 12
+ ft1 | 8
+(4 rows)
+
-- join two tables
SELECT t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
c1
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index ce8bb75..c5d2fde 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -81,6 +81,22 @@ CREATE FOREIGN TABLE ft2 (
) SERVER loopback;
ALTER FOREIGN TABLE ft2 DROP COLUMN cx;
+CREATE FOREIGN TABLE ft_tables (
+ LIKE information_schema.tables
+) SERVER loopback
+OPTIONS (
+ schema_name 'information_schema',
+ table_name 'tables'
+);
+
+CREATE FOREIGN TABLE ft_columns (
+ LIKE information_schema.columns
+) SERVER loopback
+OPTIONS (
+ schema_name 'information_schema',
+ table_name 'columns'
+);
+
-- ===================================================================
-- tests for validator
-- ===================================================================
@@ -145,8 +161,12 @@ SELECT * FROM ft1 WHERE false;
-- with WHERE clause
EXPLAIN (VERBOSE, COSTS false) SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
--- aggregate
+-- aggregates
SELECT COUNT(*) FROM ft1 t1;
+SELECT t.table_name, COUNT(*)
+FROM ft_tables t JOIN ft_columns c USING (table_catalog, table_schema, table_name)
+WHERE t.table_type = 'FOREIGN TABLE'
+GROUP BY t.table_name;
-- join two tables
SELECT t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
-- subquery
diff --git a/doc/src/sgml/ref/create_foreign_table.sgml b/doc/src/sgml/ref/create_foreign_table.sgml
index 1ef4b5e..375bd1a 100644
--- a/doc/src/sgml/ref/create_foreign_table.sgml
+++ b/doc/src/sgml/ref/create_foreign_table.sgml
@@ -20,6 +20,7 @@
CREATE FOREIGN TABLE [ IF NOT EXISTS ] table_name ( [
column_name data_type [ OPTIONS ( option 'value' [, ... ] ) ] [ COLLATE collation ] [ column_constraint [ ... ] ]
+ | LIKE source_table [ like_option ... ] }
[, ... ]
] )
SERVER server_name
@@ -31,6 +32,8 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] table_name
{ NOT NULL |
NULL |
DEFAULT default_expr }
+
+ and like_option is the same as for .
@@ -114,6 +117,19 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] table_name
+ LIKE source_table [ like_option ... ]
+
+
+ The LIKE clause specifies a table from which
+ the new foreign table automatically copies all column names and their data types.
+
+
+ Inapplicable options like INCLUDING STORAGE are ignored.
+
+
+
+
+
NOT NULL>
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index eb07ca3..82c77eb 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -649,7 +649,7 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
/*
* transformTableLikeClause
*
- * Change the LIKE portion of a CREATE TABLE statement into
+ * Change the LIKE portion of a CREATE [FOREIGN] TABLE statement into
* column definitions which recreate the user defined column portions of
* .
*/
@@ -668,12 +668,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
setup_parser_errposition_callback(&pcbstate, cxt->pstate,
table_like_clause->relation->location);
- /* we could support LIKE in many cases, but worry about it another day */
- if (cxt->isforeign)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("LIKE is not supported for creating foreign tables")));
-
relation = relation_openrv(table_like_clause->relation, AccessShareLock);
if (relation->rd_rel->relkind != RELKIND_RELATION &&
@@ -689,6 +683,12 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
cancel_parser_errposition_callback(&pcbstate);
/*
+ * For foreign tables, ignore all but applicable options.
+ */
+ if (cxt->isforeign)
+ table_like_clause->options &= CREATE_TABLE_LIKE_DEFAULTS | CREATE_TABLE_LIKE_COMMENTS;
+
+ /*
* Check for privileges
*/
if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 60506e0..2df1c60 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -699,6 +699,13 @@ SELECT * FROM ft1; -- ERROR
ERROR: foreign-data wrapper "dummy" has no handler
EXPLAIN SELECT * FROM ft1; -- ERROR
ERROR: foreign-data wrapper "dummy" has no handler
+CREATE FOREIGN TABLE foreign_schema.ft_columns (LIKE information_schema.columns)
+ SERVER s0 OPTIONS (delimiter ',', quote '"');
+CREATE FOREIGN TABLE doesnt_exist_ft1 (LIKE doesnt_exist_lt1) -- ERROR
+ SERVER s0 OPTIONS (delimiter ',', quote '"');
+ERROR: relation "doesnt_exist_lt1" does not exist
+LINE 1: CREATE FOREIGN TABLE doesnt_exist_ft1 (LIKE doesnt_exist_lt1...
+ ^
-- ALTER FOREIGN TABLE
COMMENT ON FOREIGN TABLE ft1 IS 'foreign table';
COMMENT ON FOREIGN TABLE ft1 IS NULL;
@@ -919,7 +926,8 @@ SELECT * FROM information_schema.foreign_tables ORDER BY 1, 2, 3;
foreign_table_catalog | foreign_table_schema | foreign_table_name | foreign_server_catalog | foreign_server_name
-----------------------+----------------------+--------------------+------------------------+---------------------
regression | foreign_schema | foreign_table_1 | regression | s0
-(1 row)
+ regression | foreign_schema | ft_columns | regression | s0
+(2 rows)
SELECT * FROM information_schema.foreign_table_options ORDER BY 1, 2, 3, 4;
foreign_table_catalog | foreign_table_schema | foreign_table_name | option_name | option_value
@@ -927,7 +935,9 @@ SELECT * FROM information_schema.foreign_table_options ORDER BY 1, 2, 3, 4;
regression | foreign_schema | foreign_table_1 | be quoted | value
regression | foreign_schema | foreign_table_1 | escape | @
regression | foreign_schema | foreign_table_1 | quote | ~
-(3 rows)
+ regression | foreign_schema | ft_columns | delimiter | ,
+ regression | foreign_schema | ft_columns | quote | "
+(5 rows)
SET ROLE regress_test_role;
SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
@@ -1166,6 +1176,7 @@ NOTICE: foreign table "no_table" does not exist, skipping
DROP FOREIGN TABLE foreign_schema.foreign_table_1;
-- Cleanup
DROP SCHEMA foreign_schema CASCADE;
+NOTICE: drop cascades to foreign table foreign_schema.ft_columns
DROP ROLE regress_test_role; -- ERROR
ERROR: role "regress_test_role" cannot be dropped because some objects depend on it
DETAIL: privileges for server s4
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index f819eb1..54475d8 100644
--- a/src/test/regress/sql/foreign_data.sql
+++ b/src/test/regress/sql/foreign_data.sql
@@ -280,6 +280,10 @@ COMMENT ON COLUMN ft1.c1 IS 'ft1.c1';
CREATE INDEX id_ft1_c2 ON ft1 (c2); -- ERROR
SELECT * FROM ft1; -- ERROR
EXPLAIN SELECT * FROM ft1; -- ERROR
+CREATE FOREIGN TABLE foreign_schema.ft_columns (LIKE information_schema.columns)
+ SERVER s0 OPTIONS (delimiter ',', quote '"');
+CREATE FOREIGN TABLE doesnt_exist_ft1 (LIKE doesnt_exist_lt1) -- ERROR
+ SERVER s0 OPTIONS (delimiter ',', quote '"');
-- ALTER FOREIGN TABLE
COMMENT ON FOREIGN TABLE ft1 IS 'foreign table';