]> granicus.if.org Git - postgresql/commitdiff
Clarify use of temporary tables within partition trees
authorMichael Paquier <michael@paquier.xyz>
Wed, 20 Jun 2018 01:48:28 +0000 (10:48 +0900)
committerMichael Paquier <michael@paquier.xyz>
Wed, 20 Jun 2018 01:48:28 +0000 (10:48 +0900)
Since their introduction, partition trees have been a bit lossy
regarding temporary relations.  Inheritance trees respect the following
patterns:
1) a child relation can be temporary if the parent is permanent.
2) a child relation can be temporary if the parent is temporary.
3) a child relation cannot be permanent if the parent is temporary.
4) The use of temporary relations also imply that when both parent and
child need to be from the same sessions.

Partitions share many similar patterns with inheritance, however the
handling of the partition bounds make the situation a bit tricky for
case 1) as the partition code bases a lot of its lookup code upon
PartitionDesc which does not really look after relpersistence.  This
causes for example a temporary partition created by session A to be
visible by another session B, preventing this session B to create an
extra partition which overlaps with the temporary one created by A with
a non-intuitive error message.  There could be use-cases where mixing
permanent partitioned tables with temporary partitions make sense, but
that would be a new feature.  Partitions respect 2), 3) and 4) already.

It is a bit depressing to see those error checks happening in
MergeAttributes() whose purpose is different, but that's left as future
refactoring work.

Back-patch down to 10, which is where partitioning has been introduced,
except that default partitions do not apply there.  Documentation also
includes limitations related to the use of temporary tables with
partition trees.

Reported-by: David Rowley
Author: Amit Langote, Michael Paquier
Reviewed-by: Ashutosh Bapat, Amit Langote, Michael Paquier
Discussion: https://postgr.es/m/CAKJS1f94Ojk0og9GMkRHGt8wHTW=ijq5KzJKuoBoqWLwSVwGmw@mail.gmail.com

doc/src/sgml/ddl.sgml
src/backend/commands/tablecmds.c
src/test/regress/expected/alter_table.out
src/test/regress/expected/create_table.out
src/test/regress/expected/foreign_data.out
src/test/regress/sql/alter_table.sql
src/test/regress/sql/create_table.sql
src/test/regress/sql/foreign_data.sql

index 77e2ff70215c35443edb087165a7f0a5ca308b25..3765547cd22db8fc338f911896cfd501b740e899 100644 (file)
@@ -3337,6 +3337,16 @@ ALTER TABLE measurement ATTACH PARTITION measurement_y2008m02
        not the partitioned table.
       </para>
      </listitem>
+
+     <listitem>
+      <para>
+       Mixing temporary and permanent relations in the same partition tree is
+       not allowed.  Hence, if the partitioned table is permanent, so must be
+       its partitions and likewise if the partitioned table is temporary.  When
+       using temporary relations, all members of the partition tree have to be
+       from the same session.
+      </para>
+     </listitem>
     </itemizedlist>
     </para>
     </sect3>
index 215c2b47c8e019179f3f9d0afff2b27f75bb4d40..81c384509549d7761f3efacf13ffd901fe337a45 100644 (file)
@@ -1773,6 +1773,19 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                         errmsg("inherited relation \"%s\" is not a table or foreign table",
                                                        parent->relname)));
+
+               /*
+                * If the parent is permanent, so must be all of its partitions.  Note
+                * that inheritance allows that case.
+                */
+               if (is_partition &&
+                       relation->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
+                       relpersistence == RELPERSISTENCE_TEMP)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("cannot create a temporary relation as partition of permanent relation \"%s\"",
+                                                       RelationGetRelationName(relation))));
+
                /* Permanent rels cannot inherit from temporary ones */
                if (relpersistence != RELPERSISTENCE_TEMP &&
                        relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
@@ -13539,6 +13552,14 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
                                                   RelationGetRelationName(rel),
                                                   RelationGetRelationName(attachrel))));
 
+       /* If the parent is permanent, so must be all of its partitions. */
+       if (rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP &&
+               attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                errmsg("cannot attach a temporary relation as partition of permanent relation \"%s\"",
+                                               RelationGetRelationName(rel))));
+
        /* Temp parent cannot have a partition that is itself not a temp */
        if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
                attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
index 7b35d5c1bd7345eea6af04f2dd97c84e00b0c0c3..86127ce0df93c40a53c1c56ed69f59f65a911efa 100644 (file)
@@ -3653,3 +3653,19 @@ create table parted_validate_test_1 partition of parted_validate_test for values
 alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
 alter table parted_validate_test validate constraint parted_validate_test_chka;
 drop table parted_validate_test;
+-- check combinations of temporary and permanent relations when attaching
+-- partitions.
+create table perm_part_parent (a int) partition by list (a);
+create temp table temp_part_parent (a int) partition by list (a);
+create table perm_part_child (a int);
+create temp table temp_part_child (a int);
+alter table temp_part_parent attach partition perm_part_child
+  for values in (1, 2); -- error
+ERROR:  cannot attach a permanent relation as partition of temporary relation "temp_part_parent"
+alter table perm_part_parent attach partition temp_part_child
+  for values in (1, 2); -- error
+ERROR:  cannot attach a temporary relation as partition of permanent relation "perm_part_parent"
+alter table temp_part_parent attach partition temp_part_child
+  for values in (1, 2); -- ok
+drop table perm_part_parent cascade;
+drop table temp_part_parent cascade;
index 68dda4c0db974c1997567c4323e0a7ee444137cb..ab1d4ecaee653a13bdf0dec105d88de8c337b7b4 100644 (file)
@@ -825,3 +825,13 @@ Partitions: boolspart_f FOR VALUES IN (false),
             boolspart_t FOR VALUES IN (true)
 
 drop table boolspart;
+-- partitions mixing temporary and permanent relations
+create table perm_parted (a int) partition by list (a);
+create temporary table temp_parted (a int) partition by list (a);
+create table perm_part partition of temp_parted for values in (1, 2); -- error
+ERROR:  cannot create a permanent relation as partition of temporary relation "temp_parted"
+create temp table temp_part partition of perm_parted for values in (1, 2); -- error
+ERROR:  cannot create a temporary relation as partition of permanent relation "perm_parted"
+create temp table temp_part partition of temp_parted for values in (1, 2); -- ok
+drop table perm_parted cascade;
+drop table temp_parted cascade;
index 8b5a56a0d3e3591cf7529351abee7631209e5810..3418fefcca2ce5be03deb4747224217a7bde8a3e 100644 (file)
@@ -2019,6 +2019,18 @@ TRUNCATE pt2;  -- ERROR
 ERROR:  "pt2_1" is not a table
 DROP FOREIGN TABLE pt2_1;
 DROP TABLE pt2;
+-- foreign table cannot be part of partition tree made of temporary
+-- relations.
+CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a);
+CREATE FOREIGN TABLE foreign_part PARTITION OF temp_parted
+  FOR VALUES IN (1, 2) SERVER s0;  -- ERROR
+ERROR:  cannot create a permanent relation as partition of temporary relation "temp_parted"
+CREATE FOREIGN TABLE foreign_part (a int) SERVER s0;
+ALTER TABLE temp_parted ATTACH PARTITION foreign_part
+  FOR VALUES IN (1, 2);  -- ERROR
+ERROR:  cannot attach a permanent relation as partition of temporary relation "temp_parted"
+DROP FOREIGN TABLE foreign_part;
+DROP TABLE temp_parted;
 -- Cleanup
 DROP SCHEMA foreign_schema CASCADE;
 DROP ROLE regress_test_role;                                -- ERROR
index 60cd142e985f11c3a3bfdb906d496cc5500c259c..519d984fd9f9af2d87af81d122244d8494f71d03 100644 (file)
@@ -2373,3 +2373,18 @@ create table parted_validate_test_1 partition of parted_validate_test for values
 alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
 alter table parted_validate_test validate constraint parted_validate_test_chka;
 drop table parted_validate_test;
+
+-- check combinations of temporary and permanent relations when attaching
+-- partitions.
+create table perm_part_parent (a int) partition by list (a);
+create temp table temp_part_parent (a int) partition by list (a);
+create table perm_part_child (a int);
+create temp table temp_part_child (a int);
+alter table temp_part_parent attach partition perm_part_child
+  for values in (1, 2); -- error
+alter table perm_part_parent attach partition temp_part_child
+  for values in (1, 2); -- error
+alter table temp_part_parent attach partition temp_part_child
+  for values in (1, 2); -- ok
+drop table perm_part_parent cascade;
+drop table temp_part_parent cascade;
index 89e1059a71ef45359fe4b63fd92164237c49e712..ad836141379eb76bb20dc517144decc3359325e6 100644 (file)
@@ -675,3 +675,12 @@ create table boolspart_t partition of boolspart for values in (true);
 create table boolspart_f partition of boolspart for values in (false);
 \d+ boolspart
 drop table boolspart;
+
+-- partitions mixing temporary and permanent relations
+create table perm_parted (a int) partition by list (a);
+create temporary table temp_parted (a int) partition by list (a);
+create table perm_part partition of temp_parted for values in (1, 2); -- error
+create temp table temp_part partition of perm_parted for values in (1, 2); -- error
+create temp table temp_part partition of temp_parted for values in (1, 2); -- ok
+drop table perm_parted cascade;
+drop table temp_parted cascade;
index ebe8ffbffecbc990e86c8b3f5983b3ceff308433..fb04982a7ffa27cd210277fbdb3a85fcb0198bd1 100644 (file)
@@ -786,6 +786,17 @@ TRUNCATE pt2;  -- ERROR
 DROP FOREIGN TABLE pt2_1;
 DROP TABLE pt2;
 
+-- foreign table cannot be part of partition tree made of temporary
+-- relations.
+CREATE TEMP TABLE temp_parted (a int) PARTITION BY LIST (a);
+CREATE FOREIGN TABLE foreign_part PARTITION OF temp_parted
+  FOR VALUES IN (1, 2) SERVER s0;  -- ERROR
+CREATE FOREIGN TABLE foreign_part (a int) SERVER s0;
+ALTER TABLE temp_parted ATTACH PARTITION foreign_part
+  FOR VALUES IN (1, 2);  -- ERROR
+DROP FOREIGN TABLE foreign_part;
+DROP TABLE temp_parted;
+
 -- Cleanup
 DROP SCHEMA foreign_schema CASCADE;
 DROP ROLE regress_test_role;                                -- ERROR