diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9ce36b06643..0c594655a8c 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -23024,8 +23024,10 @@ deleteSplitPartitionContext(SplitPartitionContext *pc, List **wqueue, int ti_opt * (rel) and move rows into new partitions. * * New partitions description: - * partlist: list of pointers to SinglePartitionSpec structures. - * newPartRels: list of Relations. + * partlist: list of pointers to SinglePartitionSpec structures. It contains + * the partition specification details for all new partitions. + * newPartRels: list of Relations, new partitions created in + * ATExecSplitPartition. * defaultPartOid: oid of DEFAULT partition, for table rel. */ static void @@ -23149,13 +23151,12 @@ SplitPartitionMoveRows(List **wqueue, Relation rel, Relation splitRel, { pc = (SplitPartitionContext *) lfirst(listptr); - if (pc->partqualstate /* skip DEFAULT partition */ && - ExecCheck(pc->partqualstate, econtext)) + /* skip DEFAULT partition */ + if (pc->partqualstate && ExecCheck(pc->partqualstate, econtext)) { found = true; break; } - ResetExprContext(econtext); } if (!found) { diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index bd045c154de..870712577ba 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -3517,9 +3517,11 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, * checkPartition * Check whether partRelOid is a leaf partition of the parent table (rel). * Partition with OID partRelOid must be locked before function call. + * is_merge: true indicates the operation is "ALTER TABLE ... MERGE PARTITIONS"; + * false indicates the operation is "ALTER TABLE ... SPLIT PARTITIONS". */ static void -checkPartition(Relation rel, Oid partRelOid) +checkPartition(Relation rel, Oid partRelOid, bool is_merge) { Relation partRel; @@ -3529,21 +3531,27 @@ checkPartition(Relation rel, Oid partRelOid) ereport(ERROR, errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", RelationGetRelationName(partRel)), - errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions")); + is_merge + ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions") + : errhint("ALTER TABLE ... SPLIT PARTITIONS can only split partitions don't have sub-partitions")); if (!partRel->rd_rel->relispartition) ereport(ERROR, errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a partition of partitioned table \"%s\"", RelationGetRelationName(partRel), RelationGetRelationName(rel)), - errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions")); + is_merge + ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions") + : errhint("ALTER TABLE ... SPLIT PARTITIONS can only split partitions don't have sub-partitions")); if (get_partition_parent(partRelOid, false) != RelationGetRelid(rel)) ereport(ERROR, errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" is not a partition of relation \"%s\"", RelationGetRelationName(partRel), RelationGetRelationName(rel)), - errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions")); + is_merge + ? errhint("ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions") + : errhint("ALTER TABLE ... SPLIT PARTITIONS can only split partitions don't have sub-partitions")); table_close(partRel, NoLock); } @@ -3581,7 +3589,7 @@ transformPartitionCmdForSplit(CreateStmtContext *cxt, PartitionCmd *partcmd) RangeVarCallbackOwnsRelation, NULL); - checkPartition(parent, splitPartOid); + checkPartition(parent, splitPartOid, false); /* Then we should check partitions with transformed bounds. */ check_partitions_for_split(parent, splitPartOid, partcmd->partlist, cxt->pstate); @@ -3666,7 +3674,7 @@ transformPartitionCmdForMerge(CreateStmtContext *cxt, PartitionCmd *partcmd) parser_errposition(cxt->pstate, name->location)); } - checkPartition(parent, partOid); + checkPartition(parent, partOid, true); partOids = lappend_oid(partOids, partOid); } diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index e1c1416b1ec..a2b5f23cea0 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -4998,6 +4998,8 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) * second_name: name of second partition * second_bound: bound of second partition * defaultPart: true if one of split partitions is DEFAULT + * merge_or_split: true indicate the opration is "ALTER TABLE ... MERGE PARTITIONS" + * false indicate the opration is "ALTER TABLE ... SPLIT PARTITIONS". * pstate: pointer to ParseState struct for determining error position */ static void @@ -5007,6 +5009,7 @@ check_two_partitions_bounds_range(Relation parent, RangeVar *second_name, PartitionBoundSpec *second_bound, bool defaultPart, + bool merge_split, ParseState *pstate) { PartitionKey key = RelationGetPartitionKey(parent); @@ -5036,7 +5039,9 @@ check_two_partitions_bounds_range(Relation parent, errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("lower bound of partition \"%s\" is not equal to the upper bound of partition \"%s\"", second_name->relname, first_name->relname), - errhint("ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent."), + merge_split + ? errhint("ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent.") + : errhint("ALTER TABLE ... SPLIT PARTITIONS requires the partition bounds to be adjacent."), parser_errposition(pstate, datum->location)); } } @@ -5140,7 +5145,9 @@ calculate_partition_bound_for_merge(Relation parent, (PartitionBoundSpec *) list_nth(bounds, prev_index), (RangeVar *) list_nth(partNames, index), (PartitionBoundSpec *) list_nth(bounds, index), - false, pstate); + false, + true, + pstate); } /* @@ -5813,7 +5820,10 @@ check_partitions_for_split(Relation parent, /* Ranges of new partitions should not overlap. */ if (strategy == PARTITION_STRATEGY_RANGE && spsPrev) check_two_partitions_bounds_range(parent, spsPrev->name, spsPrev->bound, - sps->name, sps->bound, existsDefaultPart, pstate); + sps->name, sps->bound, + existsDefaultPart, + false, + pstate); spsPrev = sps; diff --git a/src/test/regress/expected/partition_split.out b/src/test/regress/expected/partition_split.out index 3a8a5c41f31..b1844263524 100644 --- a/src/test/regress/expected/partition_split.out +++ b/src/test/regress/expected/partition_split.out @@ -96,7 +96,7 @@ ALTER TABLE sales_range SPLIT PARTITION sales_feb_mar_apr2022 INTO ERROR: lower bound of partition "sales_mar2022" is not equal to the upper bound of partition "sales_feb2022" LINE 3: PARTITION sales_mar2022 FOR VALUES FROM ('2022-02-01') TO... ^ -HINT: ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent. +HINT: ALTER TABLE ... SPLIT PARTITIONS requires the partition bounds to be adjacent. -- Tests for spaces between partitions, them should be executed without DEFAULT partition ALTER TABLE sales_range DETACH PARTITION sales_others; -- ERROR: lower bound of partition "sales_feb2022" is not equal to lower bound of split partition @@ -157,64 +157,25 @@ ALTER TABLE sales_range SPLIT PARTITION sales_feb_mar_apr2022 INTO (PARTITION sales_feb2022 FOR VALUES FROM ('2022-02-01') TO ('2022-03-01'), PARTITION sales_mar2022 FOR VALUES FROM ('2022-03-01') TO ('2022-04-01'), PARTITION sales_apr2022 FOR VALUES FROM ('2022-04-01') TO ('2022-05-01')); -SELECT * FROM sales_range; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 1 | May | 1000 | 01-31-2022 - 10 | Halder | 350 | 01-28-2022 - 13 | Gandi | 377 | 01-09-2022 - 2 | Smirnoff | 500 | 02-10-2022 - 6 | Poirot | 150 | 02-11-2022 - 8 | Ericsson | 185 | 02-23-2022 - 7 | Li | 175 | 03-08-2022 - 9 | Muller | 250 | 03-11-2022 - 12 | Plato | 350 | 03-19-2022 - 3 | Ford | 2000 | 04-30-2022 - 4 | Ivanov | 750 | 04-13-2022 - 5 | Deev | 250 | 04-07-2022 - 11 | Trump | 380 | 04-06-2022 - 14 | Smith | 510 | 05-04-2022 +SELECT tableoid, * FROM sales_range ORDER BY salesperson_id; + tableoid | salesperson_id | salesperson_name | sales_amount | sales_date +----------+----------------+------------------+--------------+------------ + 19614 | 1 | May | 1000 | 01-31-2022 + 19623 | 2 | Smirnoff | 500 | 02-10-2022 + 19629 | 3 | Ford | 2000 | 04-30-2022 + 19629 | 4 | Ivanov | 750 | 04-13-2022 + 19629 | 5 | Deev | 250 | 04-07-2022 + 19623 | 6 | Poirot | 150 | 02-11-2022 + 19626 | 7 | Li | 175 | 03-08-2022 + 19623 | 8 | Ericsson | 185 | 02-23-2022 + 19626 | 9 | Muller | 250 | 03-11-2022 + 19614 | 10 | Halder | 350 | 01-28-2022 + 19629 | 11 | Trump | 380 | 04-06-2022 + 19626 | 12 | Plato | 350 | 03-19-2022 + 19614 | 13 | Gandi | 377 | 01-09-2022 + 19620 | 14 | Smith | 510 | 05-04-2022 (14 rows) -SELECT * FROM sales_jan2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 1 | May | 1000 | 01-31-2022 - 10 | Halder | 350 | 01-28-2022 - 13 | Gandi | 377 | 01-09-2022 -(3 rows) - -SELECT * FROM sales_feb2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 2 | Smirnoff | 500 | 02-10-2022 - 6 | Poirot | 150 | 02-11-2022 - 8 | Ericsson | 185 | 02-23-2022 -(3 rows) - -SELECT * FROM sales_mar2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 7 | Li | 175 | 03-08-2022 - 9 | Muller | 250 | 03-11-2022 - 12 | Plato | 350 | 03-19-2022 -(3 rows) - -SELECT * FROM sales_apr2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 3 | Ford | 2000 | 04-30-2022 - 4 | Ivanov | 750 | 04-13-2022 - 5 | Deev | 250 | 04-07-2022 - 11 | Trump | 380 | 04-06-2022 -(4 rows) - -SELECT * FROM sales_others; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 14 | Smith | 510 | 05-04-2022 -(1 row) - DROP TABLE sales_range CASCADE; -- -- Add split partition, then add rows into partitioned table @@ -258,64 +219,25 @@ INSERT INTO sales_range VALUES (12, 'Plato', 350, '2022-03-19'), (13, 'Gandi', 377, '2022-01-09'), (14, 'Smith', 510, '2022-05-04'); -SELECT * FROM sales_range; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 1 | May | 1000 | 01-31-2022 - 10 | Halder | 350 | 01-28-2022 - 13 | Gandi | 377 | 01-09-2022 - 2 | Smirnoff | 500 | 02-10-2022 - 6 | Poirot | 150 | 02-11-2022 - 8 | Ericsson | 185 | 02-23-2022 - 7 | Li | 175 | 03-08-2022 - 9 | Muller | 250 | 03-11-2022 - 12 | Plato | 350 | 03-19-2022 - 3 | Ford | 2000 | 04-30-2022 - 4 | Ivanov | 750 | 04-13-2022 - 5 | Deev | 250 | 04-07-2022 - 11 | Trump | 380 | 04-06-2022 - 14 | Smith | 510 | 05-04-2022 +SELECT tableoid, * FROM sales_range ORDER BY salesperson_id; + tableoid | salesperson_id | salesperson_name | sales_amount | sales_date +----------+----------------+------------------+--------------+------------ + 19635 | 1 | May | 1000 | 01-31-2022 + 19644 | 2 | Smirnoff | 500 | 02-10-2022 + 19650 | 3 | Ford | 2000 | 04-30-2022 + 19650 | 4 | Ivanov | 750 | 04-13-2022 + 19650 | 5 | Deev | 250 | 04-07-2022 + 19644 | 6 | Poirot | 150 | 02-11-2022 + 19647 | 7 | Li | 175 | 03-08-2022 + 19644 | 8 | Ericsson | 185 | 02-23-2022 + 19647 | 9 | Muller | 250 | 03-11-2022 + 19635 | 10 | Halder | 350 | 01-28-2022 + 19650 | 11 | Trump | 380 | 04-06-2022 + 19647 | 12 | Plato | 350 | 03-19-2022 + 19635 | 13 | Gandi | 377 | 01-09-2022 + 19641 | 14 | Smith | 510 | 05-04-2022 (14 rows) -SELECT * FROM sales_jan2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 1 | May | 1000 | 01-31-2022 - 10 | Halder | 350 | 01-28-2022 - 13 | Gandi | 377 | 01-09-2022 -(3 rows) - -SELECT * FROM sales_feb2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 2 | Smirnoff | 500 | 02-10-2022 - 6 | Poirot | 150 | 02-11-2022 - 8 | Ericsson | 185 | 02-23-2022 -(3 rows) - -SELECT * FROM partition_split_schema2.sales_mar2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 7 | Li | 175 | 03-08-2022 - 9 | Muller | 250 | 03-11-2022 - 12 | Plato | 350 | 03-19-2022 -(3 rows) - -SELECT * FROM sales_apr2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 3 | Ford | 2000 | 04-30-2022 - 4 | Ivanov | 750 | 04-13-2022 - 5 | Deev | 250 | 04-07-2022 - 11 | Trump | 380 | 04-06-2022 -(4 rows) - -SELECT * FROM sales_others; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 14 | Smith | 510 | 05-04-2022 -(1 row) - DROP TABLE sales_range CASCADE; -- -- Test for: @@ -508,7 +430,7 @@ ALTER TABLE sales_range SPLIT PARTITION sales_others INTO ERROR: lower bound of partition "sales_error" is not equal to the upper bound of partition "sales_dec2021" LINE 3: PARTITION sales_error FOR VALUES FROM (20211230) TO (2022... ^ -HINT: ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent. +HINT: ALTER TABLE ... SPLIT PARTITIONS requires the partition bounds to be adjacent. -- sales_error intersects with sales_feb2022 (upper bound) -- ERROR: lower bound of partition "sales_feb2022" is not equal to the upper bound of partition "sales_error" ALTER TABLE sales_range SPLIT PARTITION sales_others INTO @@ -519,7 +441,7 @@ ALTER TABLE sales_range SPLIT PARTITION sales_others INTO ERROR: lower bound of partition "sales_feb2022" is not equal to the upper bound of partition "sales_error" LINE 4: PARTITION sales_feb2022 FOR VALUES FROM (20220201) TO (20... ^ -HINT: ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent. +HINT: ALTER TABLE ... SPLIT PARTITIONS requires the partition bounds to be adjacent. -- sales_error intersects with sales_dec2021 (inside bound) -- ERROR: lower bound of partition "sales_feb2022" is not equal to the upper bound of partition "sales_error" ALTER TABLE sales_range SPLIT PARTITION sales_others INTO @@ -530,7 +452,7 @@ ALTER TABLE sales_range SPLIT PARTITION sales_others INTO ERROR: lower bound of partition "sales_error" is not equal to the upper bound of partition "sales_dec2021" LINE 3: PARTITION sales_error FOR VALUES FROM (20211210) TO (2021... ^ -HINT: ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent. +HINT: ALTER TABLE ... SPLIT PARTITIONS requires the partition bounds to be adjacent. -- sales_error intersects with sales_dec2021 (exactly the same bounds) -- ERROR: lower bound of partition "sales_feb2022" is not equal to the upper bound of partition "sales_error" ALTER TABLE sales_range SPLIT PARTITION sales_others INTO @@ -541,7 +463,7 @@ ALTER TABLE sales_range SPLIT PARTITION sales_others INTO ERROR: lower bound of partition "sales_error" is not equal to the upper bound of partition "sales_dec2021" LINE 3: PARTITION sales_error FOR VALUES FROM (20211201) TO (2022... ^ -HINT: ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent. +HINT: ALTER TABLE ... SPLIT PARTITIONS requires the partition bounds to be adjacent. -- ERROR: one partition in the list should be DEFAULT because split partition is DEFAULT ALTER TABLE sales_range SPLIT PARTITION sales_others INTO (PARTITION sales_dec2021 FOR VALUES FROM (20211201) TO (20220101), @@ -873,34 +795,25 @@ INSERT INTO sales_range VALUES (12, 'Plato', 350, '2022-03-19'), (13, 'Gandi', 377, '2022-01-09'), (14, 'Smith', 510, '2022-05-04'); -SELECT * FROM sales_range; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 1 | May | 1000 | 01-31-2022 - 10 | Halder | 350 | 01-28-2022 - 13 | Gandi | 377 | 01-09-2022 - 2 | Smirnoff | 500 | 02-10-2022 - 6 | Poirot | 150 | 02-11-2022 - 8 | Ericsson | 185 | 02-23-2022 - 7 | Li | 175 | 03-08-2022 - 9 | Muller | 250 | 03-11-2022 - 12 | Plato | 350 | 03-19-2022 - 3 | Ford | 2000 | 04-30-2022 - 4 | Ivanov | 750 | 04-13-2022 - 5 | Deev | 250 | 04-07-2022 - 11 | Trump | 380 | 04-06-2022 - 14 | Smith | 510 | 05-04-2022 +SELECT tableoid, * FROM sales_range ORDER BY salesperson_id; + tableoid | salesperson_id | salesperson_name | sales_amount | sales_date +----------+----------------+------------------+--------------+------------ + 19985 | 1 | May | 1000 | 01-31-2022 + 19988 | 2 | Smirnoff | 500 | 02-10-2022 + 19997 | 3 | Ford | 2000 | 04-30-2022 + 19997 | 4 | Ivanov | 750 | 04-13-2022 + 19997 | 5 | Deev | 250 | 04-07-2022 + 19988 | 6 | Poirot | 150 | 02-11-2022 + 19991 | 7 | Li | 175 | 03-08-2022 + 19988 | 8 | Ericsson | 185 | 02-23-2022 + 19991 | 9 | Muller | 250 | 03-11-2022 + 19985 | 10 | Halder | 350 | 01-28-2022 + 19997 | 11 | Trump | 380 | 04-06-2022 + 19991 | 12 | Plato | 350 | 03-19-2022 + 19985 | 13 | Gandi | 377 | 01-09-2022 + 20000 | 14 | Smith | 510 | 05-04-2022 (14 rows) -SELECT * FROM sales_apr2022; - salesperson_id | salesperson_name | sales_amount | sales_date -----------------+------------------+--------------+------------ - 3 | Ford | 2000 | 04-30-2022 - 4 | Ivanov | 750 | 04-13-2022 - 5 | Deev | 250 | 04-07-2022 - 11 | Trump | 380 | 04-06-2022 -(4 rows) - ALTER TABLE sales_apr2022 SPLIT PARTITION sales_apr_all INTO (PARTITION sales_apr2022_01_10 FOR VALUES FROM ('2022-04-01') TO ('2022-04-10'), PARTITION sales_apr2022_10_20 FOR VALUES FROM ('2022-04-10') TO ('2022-04-20'), @@ -1252,7 +1165,7 @@ ALTER TABLE t2 SPLIT PARTITION t1pa INTO (PARTITION t2a FOR VALUES FROM ('A') TO ('B'), PARTITION t2b FOR VALUES FROM ('B') TO ('C')); ERROR: relation "t1pa" is not a partition of relation "t2" -HINT: ALTER TABLE ... MERGE PARTITIONS can only merge partitions don't have sub-partitions +HINT: ALTER TABLE ... SPLIT PARTITIONS can only split partitions don't have sub-partitions DROP TABLE t2; DROP TABLE t1; -- diff --git a/src/test/regress/sql/partition_split.sql b/src/test/regress/sql/partition_split.sql index 6466a4f978e..a718b44f686 100644 --- a/src/test/regress/sql/partition_split.sql +++ b/src/test/regress/sql/partition_split.sql @@ -135,13 +135,7 @@ 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-05-01')); -SELECT * FROM sales_range; -SELECT * FROM sales_jan2022; -SELECT * FROM sales_feb2022; -SELECT * FROM sales_mar2022; -SELECT * FROM sales_apr2022; -SELECT * FROM sales_others; - +SELECT tableoid, * FROM sales_range ORDER BY salesperson_id; DROP TABLE sales_range CASCADE; -- @@ -175,12 +169,7 @@ INSERT INTO sales_range VALUES (13, 'Gandi', 377, '2022-01-09'), (14, 'Smith', 510, '2022-05-04'); -SELECT * FROM sales_range; -SELECT * FROM sales_jan2022; -SELECT * FROM sales_feb2022; -SELECT * FROM partition_split_schema2.sales_mar2022; -SELECT * FROM sales_apr2022; -SELECT * FROM sales_others; +SELECT tableoid, * FROM sales_range ORDER BY salesperson_id; DROP TABLE sales_range CASCADE; @@ -575,8 +564,7 @@ INSERT INTO sales_range VALUES (13, 'Gandi', 377, '2022-01-09'), (14, 'Smith', 510, '2022-05-04'); -SELECT * FROM sales_range; -SELECT * FROM sales_apr2022; +SELECT tableoid, * FROM sales_range ORDER BY salesperson_id; ALTER TABLE sales_apr2022 SPLIT PARTITION sales_apr_all INTO (PARTITION sales_apr2022_01_10 FOR VALUES FROM ('2022-04-01') TO ('2022-04-10'),