]> granicus.if.org Git - postgresql/commitdiff
Even if some partitions are foreign, allow tuple routing.
authorRobert Haas <rhaas@postgresql.org>
Thu, 7 Sep 2017 14:55:45 +0000 (10:55 -0400)
committerRobert Haas <rhaas@postgresql.org>
Thu, 7 Sep 2017 14:58:21 +0000 (10:58 -0400)
This doesn't allow routing tuple to the foreign partitions themselves,
but it permits tuples to be routed to regular partitions despite the
presence of foreign partitions in the same inheritance hierarchy.

Etsuro Fujita, reviewed by Amit Langote and by me.

Discussion: http://postgr.es/m/bc3db4c1-1693-3b8a-559f-33ad2b50b7ad@lab.ntt.co.jp

contrib/file_fdw/input/file_fdw.source
contrib/file_fdw/output/file_fdw.source
src/backend/executor/execMain.c
src/backend/executor/nodeModifyTable.c
src/include/executor/executor.h

index 685561fc2a0fd64282ed1276911ae5e150488421..e6821d64d4416b177faa35914b63236ab5b122e3 100644 (file)
@@ -162,6 +162,27 @@ SELECT tableoid::regclass, * FROM agg FOR UPDATE;
 ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
 DROP TABLE agg;
 
+-- declarative partitioning tests
+SET ROLE regress_file_fdw_superuser;
+CREATE TABLE pt (a int, b text) partition by list (a);
+CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+CREATE TABLE p2 partition of pt for values in (2);
+SELECT tableoid::regclass, * FROM pt;
+SELECT tableoid::regclass, * FROM p1;
+SELECT tableoid::regclass, * FROM p2;
+COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter ','); -- ERROR
+COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+SELECT tableoid::regclass, * FROM pt;
+SELECT tableoid::regclass, * FROM p1;
+SELECT tableoid::regclass, * FROM p2;
+INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+INSERT INTO pt VALUES (2, 'xyzzy');
+SELECT tableoid::regclass, * FROM pt;
+SELECT tableoid::regclass, * FROM p1;
+SELECT tableoid::regclass, * FROM p2;
+DROP TABLE pt;
+
 -- privilege tests
 SET ROLE regress_file_fdw_superuser;
 SELECT * FROM agg_text ORDER BY a;
index 01e2690a8254435eaf866232cc7eb486749429d7..709c43ec804426eb0e7176f02f1726851acbef2c 100644 (file)
@@ -289,6 +289,87 @@ SELECT tableoid::regclass, * FROM agg FOR UPDATE;
 
 ALTER FOREIGN TABLE agg_csv NO INHERIT agg;
 DROP TABLE agg;
+-- declarative partitioning tests
+SET ROLE regress_file_fdw_superuser;
+CREATE TABLE pt (a int, b text) partition by list (a);
+CREATE FOREIGN TABLE p1 partition of pt for values in (1) SERVER file_server
+OPTIONS (format 'csv', filename '@abs_srcdir@/data/list1.csv', delimiter ',');
+CREATE TABLE p2 partition of pt for values in (2);
+SELECT tableoid::regclass, * FROM pt;
+ tableoid | a |  b  
+----------+---+-----
+ p1       | 1 | foo
+ p1       | 1 | bar
+(2 rows)
+
+SELECT tableoid::regclass, * FROM p1;
+ tableoid | a |  b  
+----------+---+-----
+ p1       | 1 | foo
+ p1       | 1 | bar
+(2 rows)
+
+SELECT tableoid::regclass, * FROM p2;
+ tableoid | a | b 
+----------+---+---
+(0 rows)
+
+COPY pt FROM '@abs_srcdir@/data/list2.bad' with (format 'csv', delimiter ','); -- ERROR
+ERROR:  cannot route inserted tuples to a foreign table
+CONTEXT:  COPY pt, line 2: "1,qux"
+COPY pt FROM '@abs_srcdir@/data/list2.csv' with (format 'csv', delimiter ',');
+SELECT tableoid::regclass, * FROM pt;
+ tableoid | a |  b  
+----------+---+-----
+ p1       | 1 | foo
+ p1       | 1 | bar
+ p2       | 2 | baz
+ p2       | 2 | qux
+(4 rows)
+
+SELECT tableoid::regclass, * FROM p1;
+ tableoid | a |  b  
+----------+---+-----
+ p1       | 1 | foo
+ p1       | 1 | bar
+(2 rows)
+
+SELECT tableoid::regclass, * FROM p2;
+ tableoid | a |  b  
+----------+---+-----
+ p2       | 2 | baz
+ p2       | 2 | qux
+(2 rows)
+
+INSERT INTO pt VALUES (1, 'xyzzy'); -- ERROR
+ERROR:  cannot route inserted tuples to a foreign table
+INSERT INTO pt VALUES (2, 'xyzzy');
+SELECT tableoid::regclass, * FROM pt;
+ tableoid | a |   b   
+----------+---+-------
+ p1       | 1 | foo
+ p1       | 1 | bar
+ p2       | 2 | baz
+ p2       | 2 | qux
+ p2       | 2 | xyzzy
+(5 rows)
+
+SELECT tableoid::regclass, * FROM p1;
+ tableoid | a |  b  
+----------+---+-----
+ p1       | 1 | foo
+ p1       | 1 | bar
+(2 rows)
+
+SELECT tableoid::regclass, * FROM p2;
+ tableoid | a |   b   
+----------+---+-------
+ p2       | 2 | baz
+ p2       | 2 | qux
+ p2       | 2 | xyzzy
+(3 rows)
+
+DROP TABLE pt;
 -- privilege tests
 SET ROLE regress_file_fdw_superuser;
 SELECT * FROM agg_text ORDER BY a;
index 2946a0edee3b8f51d0a9794b758a765514e53abb..b6f9f1b65f67d7bcd16c63d227431a5c4aae6ea9 100644 (file)
@@ -1097,8 +1097,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
  * CheckValidRowMarkRel.
  */
 void
-CheckValidResultRel(Relation resultRel, CmdType operation)
+CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 {
+       Relation        resultRel = resultRelInfo->ri_RelationDesc;
        TriggerDesc *trigDesc = resultRel->trigdesc;
        FdwRoutine *fdwroutine;
 
@@ -1169,10 +1170,16 @@ CheckValidResultRel(Relation resultRel, CmdType operation)
                        break;
                case RELKIND_FOREIGN_TABLE:
                        /* Okay only if the FDW supports it */
-                       fdwroutine = GetFdwRoutineForRelation(resultRel, false);
+                       fdwroutine = resultRelInfo->ri_FdwRoutine;
                        switch (operation)
                        {
                                case CMD_INSERT:
+                                       /*
+                                        * If foreign partition to do tuple-routing for, skip the
+                                        * check; it's disallowed elsewhere.
+                                        */
+                                       if (resultRelInfo->ri_PartitionRoot)
+                                               break;
                                        if (fdwroutine->ExecForeignInsert == NULL)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -3307,11 +3314,6 @@ ExecSetupPartitionTupleRouting(Relation rel,
                partrel = heap_open(lfirst_oid(cell), NoLock);
                part_tupdesc = RelationGetDescr(partrel);
 
-               /*
-                * Verify result relation is a valid target for the current operation.
-                */
-               CheckValidResultRel(partrel, CMD_INSERT);
-
                /*
                 * Save a tuple conversion map to convert a tuple routed to this
                 * partition from the parent's type to the partition's.
@@ -3325,8 +3327,10 @@ ExecSetupPartitionTupleRouting(Relation rel,
                                                  rel,
                                                  estate->es_instrument);
 
-               estate->es_leaf_result_relations =
-                       lappend(estate->es_leaf_result_relations, leaf_part_rri);
+               /*
+                * Verify result relation is a valid target for INSERT.
+                */
+               CheckValidResultRel(leaf_part_rri, CMD_INSERT);
 
                /*
                 * Open partition indices (remember we do not support ON CONFLICT in
@@ -3337,6 +3341,9 @@ ExecSetupPartitionTupleRouting(Relation rel,
                        leaf_part_rri->ri_IndexRelationDescs == NULL)
                        ExecOpenIndices(leaf_part_rri, false);
 
+               estate->es_leaf_result_relations =
+                       lappend(estate->es_leaf_result_relations, leaf_part_rri);
+
                leaf_part_rri++;
                i++;
        }
index e12721a9b6ae56a0615062a371cd00ef29d280bd..bd84778739824a192de303ed9f9c29d44544db7c 100644 (file)
@@ -1854,7 +1854,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                /*
                 * Verify result relation is a valid target for the current operation
                 */
-               CheckValidResultRel(resultRelInfo->ri_RelationDesc, operation);
+               CheckValidResultRel(resultRelInfo, operation);
 
                /*
                 * If there are indices on the result relation, open them and save
index f48a603daebe34bb1befa3b823c91df8e2bd57e5..ad228d1394bd182c9422dd690cac9c21ce08c84a 100644 (file)
@@ -177,7 +177,7 @@ extern void ExecutorEnd(QueryDesc *queryDesc);
 extern void standard_ExecutorEnd(QueryDesc *queryDesc);
 extern void ExecutorRewind(QueryDesc *queryDesc);
 extern bool ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation);
-extern void CheckValidResultRel(Relation resultRel, CmdType operation);
+extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation);
 extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
                                  Relation resultRelationDesc,
                                  Index resultRelationIndex,