postgres_fdw: Allow partitions specified in LIMIT TO to be imported.
authorFujii Masao <fujii@postgresql.org>
Tue, 6 Apr 2021 17:32:10 +0000 (02:32 +0900)
committerFujii Masao <fujii@postgresql.org>
Tue, 6 Apr 2021 17:32:10 +0000 (02:32 +0900)
Commit f49bcd4ef3 disallowed postgres_fdw to import table partitions.
Because all data can be accessed through the partitioned table which
is the root of the partitioning hierarchy, importing only partitioned
table should allow access to all the data without creating extra objects.
This is a reasonable default when importing a whole schema. But there
may be the case where users want to explicitly import one of
a partitioned tables' partitions.

For that use case, this commit allows postgres_fdw to import tables or
foreign tables which are partitions of some other table only when they
are explicitly specified in LIMIT TO clause.  It doesn't change
the behavior that any partitions not specified in LIMIT TO are
automatically excluded in IMPORT FOREIGN SCHEMA command.

Author: Matthias van de Meent
Reviewed-by: Bernd Helmle, Amit Langote, Michael Paquier, Fujii Masao
Discussion: https://postgr.es/m/CAEze2Whwg4i=mzApMe+PXxCEfgoZmHGqdqQFW7J4bmj_5p6t1A@mail.gmail.com

contrib/postgres_fdw/expected/postgres_fdw.out
contrib/postgres_fdw/postgres_fdw.c
contrib/postgres_fdw/sql/postgres_fdw.sql
doc/src/sgml/postgres-fdw.sgml

index 59e4e27ffbef2be88dff87e028e17446c2a3d09a..9d472d2d3d6a8cd97fc384cf141d846e51d0cc84 100644 (file)
@@ -8228,6 +8228,8 @@ 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 TABLE import_source.t4_part2 PARTITION OF import_source.t4
+  FOR VALUES FROM (100) TO (200);
 CREATE SCHEMA import_dest1;
 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
 \det+ import_dest1.*
@@ -8419,27 +8421,29 @@ 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)
+IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch, t4_part)
   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)
+                                        List of foreign tables
+    Schema    |  Table  |  Server  |                     FDW options                     | Description 
+--------------+---------+----------+-----------------------------------------------------+-------------
+ import_dest4 | t1      | loopback | (schema_name 'import_source', table_name 't1')      | 
+ import_dest4 | t4_part | loopback | (schema_name 'import_source', table_name 't4_part') | 
+(2 rows)
 
-IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch)
+IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch, t4_part)
   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 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
- import_dest4 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
-(5 rows)
+                                        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 | t4      | loopback | (schema_name 'import_source', table_name 't4')      | 
+ import_dest4 | t4_part | loopback | (schema_name 'import_source', table_name 't4_part') | 
+ import_dest4 | x 5     | loopback | (schema_name 'import_source', table_name 'x 5')     | 
+(6 rows)
 
 -- Assorted error cases
 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;
index 16c2979f2d06879bf35d92327275a2ca2eccdf41..b6442070a350bc1c6192fa1fe059c0c4a02c3234 100644 (file)
@@ -5095,9 +5095,11 @@ 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.
+        * Import table data for partitions only when they are explicitly
+        * specified in LIMIT TO clause. Otherwise ignore them 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
@@ -5153,7 +5155,8 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
        deparseStringLiteral(&buf, stmt->remote_schema);
 
        /* Partitions are supported since Postgres 10 */
-       if (PQserverVersion(conn) >= 100000)
+       if (PQserverVersion(conn) >= 100000 &&
+           stmt->list_type != FDW_IMPORT_SCHEMA_LIMIT_TO)
            appendStringInfoString(&buf, " AND NOT c.relispartition ");
 
        /* Apply restrictions for LIMIT TO and EXCEPT */
index 107d1c0e030b3a19841385aeb30e3a445e83428e..3b4f90a99caff96d8168443a386b2415586d4537 100644 (file)
@@ -2366,6 +2366,8 @@ 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 TABLE import_source.t4_part2 PARTITION OF import_source.t4
+  FOR VALUES FROM (100) TO (200);
 
 CREATE SCHEMA import_dest1;
 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
@@ -2386,10 +2388,10 @@ IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
 
 -- Check LIMIT TO and EXCEPT
 CREATE SCHEMA import_dest4;
-IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch)
+IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch, t4_part)
   FROM SERVER loopback INTO import_dest4;
 \det+ import_dest4.*
-IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch)
+IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch, t4_part)
   FROM SERVER loopback INTO import_dest4;
 \det+ import_dest4.*
 
index a7c695b000ff6dbcb6c163a830e7d0d94385b69a..b0792a13b13ea1528c67eb0804b35bb7da10e0ec 100644 (file)
@@ -510,10 +510,12 @@ OPTIONS (ADD password_required 'false');
 
    <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
+    imported only when they are explicitly specified in
+    <literal>LIMIT TO</literal> clause.  Otherwise they are automatically
+    excluded from <xref linkend="sql-importforeignschema"/>.
+    Since all data can be accessed through the partitioned table
+    which is the root of the partitioning hierarchy, importing only
+    partitioned tables should allow access to all the data without
     creating extra objects.
    </para>