Inherit parent's AM for partition MERGE/SPLIT operations
authorAlexander Korotkov <akorotkov@postgresql.org>
Tue, 30 Apr 2024 08:55:13 +0000 (11:55 +0300)
committerAlexander Korotkov <akorotkov@postgresql.org>
Tue, 30 Apr 2024 09:00:39 +0000 (12:00 +0300)
This commit makes new partitions created by ALTER TABLE ... SPLIT PARTITION
and ALTER TABLE ... MERGE PARTITIONS commands inherit the paret table access
method.

Reported-by: Alexander Lakhin
Discussion: https://postgr.es/m/84ada05b-be5c-473e-6d1c-ebe5dd21b190%40gmail.com
Reviewed-by: Pavel Borisov
doc/src/sgml/ref/alter_table.sgml
src/backend/commands/tablecmds.c
src/test/regress/expected/partition_merge.out
src/test/regress/expected/partition_split.out
src/test/regress/sql/partition_merge.sql
src/test/regress/sql/partition_split.sql

index a7fed8a60100ea92304a6ed638cffef2764cf312..ebd8c62038ce755f986b2b3441ff7bb66019ae40 100644 (file)
@@ -1158,6 +1158,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
       SQL command <literal>CREATE TABLE <replaceable class="parameter">partition_nameN</replaceable> (LIKE <replaceable class="parameter">name</replaceable> INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)</literal>.
       The indexes and identity are created later, after moving the data
       into the new partitions.
+      New partitions will have the same table access method as the parent.
       If the parent table is persistent then new partitions are created
       persistent.  If the parent table is temporary then new partitions
       are also created temporary.
@@ -1227,6 +1228,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
       SQL command <literal>CREATE TABLE <replaceable class="parameter">partition_name</replaceable> (LIKE <replaceable class="parameter">name</replaceable> INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)</literal>.
       The indexes and identity are created later, after moving the data
       into the new partition.
+      The new partition will have the same table access method as the parent.
       If the parent table is persistent then the new partition is created
       persistent.  If the parent table is temporary then the new partition
       is also created temporary.
index c312d9d19755eecedece44cc8ba1a1fddc2fe387..08c87e60293a7e5aa780986f47ec3340324b95b2 100644 (file)
@@ -21213,6 +21213,11 @@ moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPar
  *
  * Emulates command: CREATE [TEMP] TABLE <newPartName> (LIKE <modelRel's name>
  * INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)
+ *
+ * Also, this function sets the new partition access method same as parent
+ * table access methods (similarly to CREATE TABLE ... PARTITION OF).  It
+ * checks that parent and child tables have compatible persistence.
+ *
  * Function returns the created relation (locked in AccessExclusiveLock mode).
  */
 static Relation
@@ -21243,6 +21248,7 @@ createPartitionTable(RangeVar *newPartName, Relation modelRel,
    createStmt->oncommit = ONCOMMIT_NOOP;
    createStmt->tablespacename = NULL;
    createStmt->if_not_exists = false;
+   createStmt->accessMethod = get_am_name(modelRel->rd_rel->relam);
 
    tlc = makeNode(TableLikeClause);
    tlc->relation = makeRangeVar(get_namespace_name(RelationGetNamespace(modelRel)),
index a92a270c59182857a2e84c9b10ad078abc0a010e..92999703217e32c7b1fb8fa9a3b43bb4d5ae1552 100644 (file)
@@ -862,6 +862,24 @@ SET search_path = partitions_merge_schema, pg_temp, public;
 -- Can't merge temporary partitions into a persistent partition
 ALTER TABLE t MERGE PARTITIONS (tp_0_1, tp_1_2) INTO tp_0_2;
 ROLLBACK;
+-- Check the new partition inherits parent's table access method
+SET search_path = partitions_merge_schema, public;
+CREATE ACCESS METHOD partitions_merge_heap TYPE TABLE HANDLER heap_tableam_handler;
+CREATE TABLE t (i int) PARTITION BY RANGE (i) USING partitions_merge_heap;
+CREATE TABLE tp_0_1 PARTITION OF t FOR VALUES FROM (0) TO (1);
+CREATE TABLE tp_1_2 PARTITION OF t FOR VALUES FROM (1) TO (2);
+ALTER TABLE t MERGE PARTITIONS (tp_0_1, tp_1_2) INTO tp_0_2;
+SELECT c.relname, a.amname
+FROM pg_class c JOIN pg_am a ON c.relam = a.oid
+WHERE c.oid IN ('t'::regclass, 'tp_0_2'::regclass);
+ relname |        amname         
+---------+-----------------------
+ tp_0_2  | partitions_merge_heap
+ t       | partitions_merge_heap
+(2 rows)
+
+DROP TABLE t;
+DROP ACCESS METHOD partitions_merge_heap;
 RESET search_path;
 --
 DROP SCHEMA partitions_merge_schema;
index 55ae37ad3703dde332c14ad2896ceb320f4e129a..326fa1bd4003a97f24ead23055f99d34710ca24b 100644 (file)
@@ -85,8 +85,8 @@ ALTER TABLE sales_range SPLIT PARTITION sales_feb_mar_apr2022 INTO
    PARTITION sales_mar2022 FOR VALUES FROM ('2022-03-01') TO ('2022-04-01'),
    PARTITION sales_apr2022 FOR VALUES FROM ('2022-04-01') TO ('2022-06-01'));
 ERROR:  upper bound of partition "sales_apr2022" is greater than upper bound of split partition
-LINE 4:    PARTITION sales_apr2022 FOR VALUES FROM ('2022-04-01') TO...
-                                                    ^
+LINE 4: ... sales_apr2022 FOR VALUES FROM ('2022-04-01') TO ('2022-06-0...
+                                                             ^
 -- ERROR:  lower bound of partition "sales_mar2022" conflicts with upper bound of previous partition "sales_feb2022"
 ALTER TABLE sales_range SPLIT PARTITION sales_feb_mar_apr2022 INTO
   (PARTITION sales_feb2022 FOR VALUES FROM ('2022-02-01') TO ('2022-03-01'),
@@ -1494,6 +1494,25 @@ SELECT c.oid::pg_catalog.regclass, pg_catalog.pg_get_expr(c.relpartbound, c.oid)
 (2 rows)
 
 DROP TABLE t;
+-- Check new partitions inherits parent's table access method
+CREATE ACCESS METHOD partition_split_heap TYPE TABLE HANDLER heap_tableam_handler;
+CREATE TABLE t (i int) PARTITION BY RANGE (i) USING partition_split_heap;
+CREATE TABLE tp_0_2 PARTITION OF t FOR VALUES FROM (0) TO (2);
+ALTER TABLE t SPLIT PARTITION tp_0_2 INTO
+  (PARTITION tp_0_1 FOR VALUES FROM (0) TO (1),
+   PARTITION tp_1_2 FOR VALUES FROM (1) TO (2));
+SELECT c.relname, a.amname
+FROM pg_class c JOIN pg_am a ON c.relam = a.oid
+WHERE c.oid IN ('t'::regclass, 'tp_0_1'::regclass, 'tp_1_2'::regclass);
+ relname |        amname        
+---------+----------------------
+ t       | partition_split_heap
+ tp_0_1  | partition_split_heap
+ tp_1_2  | partition_split_heap
+(3 rows)
+
+DROP TABLE t;
+DROP ACCESS METHOD partition_split_heap;
 --
 DROP SCHEMA partition_split_schema;
 DROP SCHEMA partition_split_schema2;
index 085c422d540aa0738e8400ac2c95984f1ce09901..23795cf9d946a21e11f59661f548e1f657751bba 100644 (file)
@@ -535,6 +535,19 @@ SET search_path = partitions_merge_schema, pg_temp, public;
 ALTER TABLE t MERGE PARTITIONS (tp_0_1, tp_1_2) INTO tp_0_2;
 ROLLBACK;
 
+-- Check the new partition inherits parent's table access method
+SET search_path = partitions_merge_schema, public;
+CREATE ACCESS METHOD partitions_merge_heap TYPE TABLE HANDLER heap_tableam_handler;
+CREATE TABLE t (i int) PARTITION BY RANGE (i) USING partitions_merge_heap;
+CREATE TABLE tp_0_1 PARTITION OF t FOR VALUES FROM (0) TO (1);
+CREATE TABLE tp_1_2 PARTITION OF t FOR VALUES FROM (1) TO (2);
+ALTER TABLE t MERGE PARTITIONS (tp_0_1, tp_1_2) INTO tp_0_2;
+SELECT c.relname, a.amname
+FROM pg_class c JOIN pg_am a ON c.relam = a.oid
+WHERE c.oid IN ('t'::regclass, 'tp_0_2'::regclass);
+DROP TABLE t;
+DROP ACCESS METHOD partitions_merge_heap;
+
 RESET search_path;
 
 --
index 3a7f2f9c294b0626a377de6c891dd88d817eccab..73e8c2fbeb9a3c62390302633e4277f5325a2a70 100644 (file)
@@ -880,6 +880,20 @@ SELECT c.oid::pg_catalog.regclass, pg_catalog.pg_get_expr(c.relpartbound, c.oid)
 
 DROP TABLE t;
 
+-- Check new partitions inherits parent's table access method
+CREATE ACCESS METHOD partition_split_heap TYPE TABLE HANDLER heap_tableam_handler;
+CREATE TABLE t (i int) PARTITION BY RANGE (i) USING partition_split_heap;
+CREATE TABLE tp_0_2 PARTITION OF t FOR VALUES FROM (0) TO (2);
+ALTER TABLE t SPLIT PARTITION tp_0_2 INTO
+  (PARTITION tp_0_1 FOR VALUES FROM (0) TO (1),
+   PARTITION tp_1_2 FOR VALUES FROM (1) TO (2));
+SELECT c.relname, a.amname
+FROM pg_class c JOIN pg_am a ON c.relam = a.oid
+WHERE c.oid IN ('t'::regclass, 'tp_0_1'::regclass, 'tp_1_2'::regclass);
+DROP TABLE t;
+DROP ACCESS METHOD partition_split_heap;
+
+
 --
 DROP SCHEMA partition_split_schema;
 DROP SCHEMA partition_split_schema2;