postgres_fdw: Teach IMPORT FOREIGN SCHEMA about partitioning.

Don't import partitions.  Do import partitioned tables which are
not themselves partitions.

Report by Stephen Frost.  Design and patch by Michael Paquier,
reviewed by Amit Langote.  Documentation revised by me.

Discussion: http://postgr.es/m/20170309141531.GD9812@tamriel.snowman.net
This commit is contained in:
Robert Haas 2017-03-31 15:01:35 -04:00
parent e306df7f9c
commit f49bcd4ef3
4 changed files with 55 additions and 5 deletions

View file

@ -6907,6 +6907,9 @@ 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 TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
FOR VALUES FROM (1) TO (100);
CREATE SCHEMA import_dest1;
IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
\det+ import_dest1.*
@ -6916,9 +6919,10 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
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 | t4 | loopback | (schema_name 'import_source', table_name 't4') |
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)
(6 rows)
\d import_dest1.*
Foreign table "import_dest1.t1"
@ -6946,6 +6950,13 @@ FDW Options: (schema_name 'import_source', table_name 't2')
Server: loopback
FDW Options: (schema_name 'import_source', table_name 't3')
Foreign table "import_dest1.t4"
Column | Type | Collation | Nullable | Default | FDW Options
--------+---------+-----------+----------+---------+--------------------
c1 | integer | | not null | | (column_name 'c1')
Server: loopback
FDW Options: (schema_name 'import_source', table_name 't4')
Foreign table "import_dest1.x 4"
Column | Type | Collation | Nullable | Default | FDW Options
--------+-----------------------+-----------+----------+---------+---------------------
@ -6972,9 +6983,10 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2
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 | t4 | loopback | (schema_name 'import_source', table_name 't4') |
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)
(6 rows)
\d import_dest2.*
Foreign table "import_dest2.t1"
@ -7002,6 +7014,13 @@ FDW Options: (schema_name 'import_source', table_name 't2')
Server: loopback
FDW Options: (schema_name 'import_source', table_name 't3')
Foreign table "import_dest2.t4"
Column | Type | Collation | Nullable | Default | FDW Options
--------+---------+-----------+----------+---------+--------------------
c1 | integer | | not null | | (column_name 'c1')
Server: loopback
FDW Options: (schema_name 'import_source', table_name 't4')
Foreign table "import_dest2.x 4"
Column | Type | Collation | Nullable | Default | FDW Options
--------+-----------------------+-----------+----------+---------+---------------------
@ -7027,9 +7046,10 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
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 | t4 | loopback | (schema_name 'import_source', table_name 't4') |
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)
(6 rows)
\d import_dest3.*
Foreign table "import_dest3.t1"
@ -7057,6 +7077,13 @@ FDW Options: (schema_name 'import_source', table_name 't2')
Server: loopback
FDW Options: (schema_name 'import_source', table_name 't3')
Foreign table "import_dest3.t4"
Column | Type | Collation | Nullable | Default | FDW Options
--------+---------+-----------+----------+---------+--------------------
c1 | integer | | | | (column_name 'c1')
Server: loopback
FDW Options: (schema_name 'import_source', table_name 't4')
Foreign table "import_dest3.x 4"
Column | Type | Collation | Nullable | Default | FDW Options
--------+-----------------------+-----------+----------+---------+---------------------
@ -7092,8 +7119,9 @@ IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch)
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 | t4 | loopback | (schema_name 'import_source', table_name 't4') |
import_dest4 | x 5 | loopback | (schema_name 'import_source', table_name 'x 5') |
(4 rows)
(5 rows)
-- Assorted error cases
IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;

View file

@ -3849,6 +3849,10 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
* should save a few cycles to not process excluded tables in the
* first place.)
*
* Ignore table data for partitions and only include the definitions
* of the root partitioned tables to allow access to the complete
* remote data set locally in the schema imported.
*
* 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
@ -3897,10 +3901,15 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
CppAsString2(RELKIND_RELATION) ","
CppAsString2(RELKIND_VIEW) ","
CppAsString2(RELKIND_FOREIGN_TABLE) ","
CppAsString2(RELKIND_MATVIEW) ") "
CppAsString2(RELKIND_MATVIEW) ","
CppAsString2(RELKIND_PARTITIONED_TABLE) ") "
" AND n.nspname = ");
deparseStringLiteral(&buf, stmt->remote_schema);
/* Partitions are supported since Postgres 10 */
if (PQserverVersion(conn) >= 100000)
appendStringInfoString(&buf, " AND NOT c.relispartition ");
/* Apply restrictions for LIMIT TO and EXCEPT */
if (stmt->list_type == FDW_IMPORT_SCHEMA_LIMIT_TO ||
stmt->list_type == FDW_IMPORT_SCHEMA_EXCEPT)

View file

@ -1618,6 +1618,9 @@ 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 TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
FOR VALUES FROM (1) TO (100);
CREATE SCHEMA import_dest1;
IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;

View file

@ -425,6 +425,16 @@
For more detail about the treatment of <literal>CHECK</> constraints on
foreign tables, see <xref linkend="sql-createforeigntable">.
</para>
<para>
Tables or foreign tables which are partitions of some other table are
automatically excluded. Partitioned tables are imported, unless they
are a partition of some other table. Since all data can be accessed
through the partitioned table which is the root of the partitioning
hierarchy, this approach should allow access to all the data without
creating extra objects.
</para>
</sect3>
</sect2>