Subject: Re: Add SPLIT PARTITION/MERGE PARTITIONS commands

From: Justin Pryzby <[email-masked]>
Date: Wed, 8 May 2024 16:37:46 -0500

On Wed, May 08, 2024 at 09:00:10PM +0300, Alexander Korotkov wrote:
> On Fri, May 3, 2024 at 4:32 PM Alexander Korotkov <[email-masked]> wrote:
> > On Fri, May 3, 2024 at 4:23 PM Justin Pryzby <[email-masked]> wrote:
> > > On Wed, May 01, 2024 at 10:51:24PM +0300, Dmitry Koval wrote:
> > > > 30.04.2024 23:15, Justin Pryzby пишет:
> > > > > Is this issue already fixed ?
> > > > > I wasn't able to reproduce it.  Maybe it only happened with earlier
> > > > > patch versions applied ?
> > > >
> > > > I think this was fixed in commit [1].
> > > >
> > > > [1] https://github.com/postgres/postgres/commit/fcf80c5d5f0f3787e70fca8fd029d2e08a923f91
> > >
> > > I tried to reproduce it at fcf80c5d5f~, but couldn't.
> > > I don't see how that patch would fix it anyway.
> > > I'm hoping Alexander can confirm what happened.
> >
> > This problem is only relevant for an old version of fix [1], which
> > overrides schemas for new partitions.  That version was never
> > committed.
> 
> Here are the patches.
> 0002 Skips copying extended statistics while creating new partitions in MERGE/SPLIT
> 
> For 0002 I'd like to hear some feedback on wordings used in docs and comments.

commit message:

Currenlty => Currently
partiions => partitios
copying => by copying

> However, parent's table extended statistics already covers all its
> children.

=> That's the wrong explanation.  It's not that "stats on the parent
table cover its children".  It's that there are two types of stats:
stats for the "table hierarchy" and stats for the individual table.
That's true for single-column stats as well as for extended stats.
In both cases, that's indicated by the inh flag in the code and in the
catalog.

The right explanation is that extended stats on partitioned tables are
not similar to indexes.  Indexes on parent table are nothing other than
a mechanism to create indexes on the child tables.  That's not true for
stats.

See also my prior messages
ZiJW1g2nbQs9ekwK@pryzbyj2023
Zi5Msg74C61DjJKW@pryzbyj2023

I think EXCLUDE IDENTITY can/should now also be removed - see 509199587.
I'm not able to reproduce that problem anyway, even before that...

-- 
Justin

---

From: Alexander Korotkov <[email-masked]>
Date: Thu, 9 May 2024 00:51:32 +0300

> > For 0002 I'd like to hear some feedback on wordings used in docs and comments.

Thank you!

> Zi5Msg74C61DjJKW@pryzbyj2023

Yes, I understand that parents pg_statistic entry with stainherit ==
true includes statistics for the children.  I tried to express this by
word "covers".  But you're right, this is the wrong explanation.

Can I, please, ask you to revise the patch?

> I'm not able to reproduce that problem anyway, even before that...

I will check this.

------
Regards,
Alexander Korotkov
Supabase

---

From: Justin Pryzby <[email-masked]>
Date: Tue, 14 May 2024 09:49:53 -0500

> Can I, please, ask you to revise the patch?

I tried to make this clear but it'd be nice if someone (Tomas/Alvaro?)
would check that this says what's wanted.

-- 
Justin
>From 265207e5bdb215600ce5d7b45f627bc41fc2bc26 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <[email-masked]>
Date: Wed, 8 May 2024 20:32:20 +0300
Subject: [PATCH] Don't copy extended statistics during MERGE/SPLIT partition
 operations

When MERGE/SPLIT created new partitions, it was cloning the extended
statistics of the parent table.

However, extended stats on partitioned tables are not analgous to
indexes on partitioned tables (which exist only to create physical
indexes on child tables).  Rather, extended stats on a parent 1) cause
extended stats to be collected and computed across the whole partition
heirarchy, and 2) do not cause extended stats to be computed for the
individual partitions.

"CREATE TABLE ... PARTITION OF" command doesn't copy extended
statistics.  This commit makes createPartitionTable() behave
consistently.

Reported-by: Justin Pryzby
Discussion: https://postgr.es/m/ZiJW1g2nbQs9ekwK%40pryzbyj2023
---
 doc/src/sgml/ref/alter_table.sgml | 9 +++++++--
 src/backend/commands/tablecmds.c  | 8 +++++---
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index 891fa4a7a04..313c722ee7f 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -1154,9 +1154,12 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
      </para>
      <para>
       The new partitions will be created the same as tables created with the
-      SQL command <literal>CREATE TABLE <replaceable class="parameter">partition_nameN</replaceable> (LIKE <replaceable class="parameter">name</replaceable> INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)</literal>.
+      SQL command <literal>CREATE TABLE <replaceable class="parameter">partition_nameN</replaceable> (LIKE <replaceable class="parameter">name</replaceable> INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY EXCLUDING STATISTICS)</literal>.
       The indexes and identity are created later, after moving the data
       into the new partitions.
+      Extended statistics aren't copied from the parent table, for consistency with
+      <command>CREATE TABLE PARTITION OF</command>.
+
       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
@@ -1224,9 +1227,11 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
      </para>
      <para>
       The new partition will be created the same as a table created with the
-      SQL command <literal>CREATE TABLE <replaceable class="parameter">partition_name</replaceable> (LIKE <replaceable class="parameter">name</replaceable> INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)</literal>.
+      SQL command <literal>CREATE TABLE <replaceable class="parameter">partition_name</replaceable> (LIKE <replaceable class="parameter">name</replaceable> INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY EXCLUDING STATISTICS)</literal>.
       The indexes and identity are created later, after moving the data
       into the new partition.
+      Extended statistics aren't copied from the parent table, for consistency with
+      <command>CREATE TABLE PARTITION OF</command>.
       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
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 79c9c031833..50fc54cb309 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -20419,7 +20419,7 @@ moveSplitTableRows(Relation rel, Relation splitRel, List *partlist, List *newPar
  * (newPartName) like table (modelRel)
  *
  * Emulates command: CREATE [TEMP] TABLE <newPartName> (LIKE <modelRel's name>
- * INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY)
+ * INCLUDING ALL EXCLUDING INDEXES EXCLUDING IDENTITY EXCLUDING STATISTICS)
  *
  * Also, this function sets the new partition access method same as parent
  * table access methods (similarly to CREATE TABLE ... PARTITION OF).  It
@@ -20463,9 +20463,11 @@ createPartitionTable(RangeVar *newPartName, Relation modelRel,
 
 	/*
 	 * Indexes will be inherited on "attach new partitions" stage, after data
-	 * moving.
+	 * moving.  We also don't copy the extended statistics for consistency
+	 * with CREATE TABLE PARTITION OF.
 	 */
-	tlc->options = CREATE_TABLE_LIKE_ALL & ~(CREATE_TABLE_LIKE_INDEXES | CREATE_TABLE_LIKE_IDENTITY);
+	tlc->options = CREATE_TABLE_LIKE_ALL &
+		~(CREATE_TABLE_LIKE_INDEXES | CREATE_TABLE_LIKE_IDENTITY | CREATE_TABLE_LIKE_STATISTICS);
 	tlc->relationOid = InvalidOid;
 	createStmt->tableElts = lappend(createStmt->tableElts, tlc);
 
-- 
2.42.0

---

From: Alexander Korotkov <[email-masked]>
Date: Fri, 17 May 2024 13:05:01 +0300

Thank you!

I've assembled the patches with the pending fixes.
0001 – The patch by Dmitry Koval for fixing detection of name
collision in SPLIT partition operation.  Also, I found that name
collision detection doesn't work well for MERGE partitions.  I've
added fix for that to this patch as well.
0002 -– Patch for skipping copy of extended statistics.  I would
appreciate more feedback about wording, but I'd like to get a correct
behavior into the source tree sooner.  If the docs and/or comments
need further improvements, we can fix that later.

I'm going to push both if no objections.

Links.
1. https://www.postgresql.org/message-id/147426d9-b793-4571-a5e5-7438affeeb5a%40postgrespro.ru

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Fri, 17 May 2024 15:02:40 +0400

Hi, Alexander:

> I'm going to push both if no objections.
Thank you for working on this patch set!

Some minor things:
0001:
partition_split.sql
157 +-- Check that detection, that the new partition has the same name as
one of
158 +-- the merged partitions, works correctly for temporary partitions
Test for split with comment for merge. Maybe better something like:
"Split partition of a temporary table when one of the partitions after
split has the same name as the partition being split"

0002:
analgous -> analogous (maybe better using "like" instead of "analogous to")
heirarchy -> hierarchy

alter_table.sgml:
Maybe in documentation it's better not to provide reasoning, just state how
it works:
for consistency with <command>CREATE TABLE PARTITION OF</command> ->
similar to <command>CREATE TABLE PARTITION OF</command>

Regards,
Pavel Borisov

---

From: Alexander Korotkov <[email-masked]>
Date: Fri, 17 May 2024 14:33:40 +0300

Hi, Pavel!

On Fri, May 17, 2024 at 2:02 PM Pavel Borisov <[email-masked]> wrote:
> On Fri, 17 May 2024 at 14:05, Alexander Korotkov <[email-masked]> wrote:
>>
> 157 +-- Check that detection, that the new partition has the same name as one of
> "Split partition of a temporary table when one of the partitions after split has the same name as the partition being split"

Thank you, fixed as proposed.

> analgous -> analogous (maybe better using "like" instead of "analogous to")

Changed "are not analgous to" to "don't behave like".

> alter_table.sgml:
> Maybe in documentation it's better not to provide reasoning, just state how it works:
> for consistency with <command>CREATE TABLE PARTITION OF</command> -> similar to <command>CREATE TABLE PARTITION OF</command>

I'd like to keep this.  This is the question, which should naturally
arise when you read: "Why this is not just INCLUDING ALL?"

------
Regards,
Alexander Korotkov
Supabase

---

From: Tom Lane <[email-masked]>
Date: Fri, 24 May 2024 15:29:39 -0400

The partition_split test has unstable results, as shown at [1].
I suggest adding "ORDER BY conname" to the two queries shown
to fail there.  Better look at other queries in the test for
possible similar problems, too.

			regards, tom lane

[1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jackdaw&dt=2024-05-24%2015%3A58%3A17

---

From: Alexander Lakhin <[email-masked]>
Date: Fri, 24 May 2024 23:00:00 +0300

Hello,

> possible similar problems, too.

Yes, I've just reproduced it on an aarch64 device as follows:
echo "autovacuum_naptime = 1
autovacuum_vacuum_threshold = 1
autovacuum_analyze_threshold = 1
" > ~/temp.config
TEMP_CONFIG=~/temp.config TESTS="$(printf 'partition_split %.0s' `seq 100`)" make -s check-tests
...
ok 80        - partition_split                           749 ms
not ok 81    - partition_split                           728 ms
ok 82        - partition_split                           732 ms

$ cat src/test/regress/regression.diffs
diff -U3 .../src/test/regress/expected/partition_split.out .../src/test/regress/results/partition_split.out
--- .../src/test/regress/expected/partition_split.out   2024-05-15 17:15:57.171999830 +0000
+++ .../src/test/regress/results/partition_split.out    2024-05-24 19:28:37.329999749 +0000
@@ -625,8 +625,8 @@
  SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conrelid = 
'sales_feb_mar_apr2022'::regclass::oid;
pg_get_constraintdef                         | conname             | conkey
  ---------------------------------------------------------------------+---------------------------------+--------
- CHECK ((sales_amount > 1))                                          | sales_range_sales_amount_check  | {2}
   FOREIGN KEY (salesperson_id) REFERENCES salespeople(salesperson_id) | sales_range_salesperson_id_fkey | {1}
+ CHECK ((sales_amount > 1))                                          | sales_range_sales_amount_check  | {2}
  (2 rows)

  ALTER TABLE sales_range SPLIT PARTITION sales_feb_mar_apr2022 INTO

Best regards,
Alexander

---

From: Alexander Korotkov <[email-masked]>
Date: Sat, 25 May 2024 15:53:11 +0300

> +++ .../src/test/regress/results/partition_split.out    2024-05-24 19:28:37.329999749 +0000

Tom, Alexander, thank you for spotting this.
I'm going to care about it later today.

------
Regards,
Alexander Korotkov
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Sun, 26 May 2024 06:58:11 +0300

> I'm going to care about it later today.

ORDER BY is added in d53a4286d7 in these queries altogether with other
catalog queries with potentially unstable result.

------
Regards,
Alexander Korotkov
Supabase

---

From: Justin Pryzby <[email-masked]>
Date: Mon, 15 Jun 2026 06:07:15 -0500

I hit an error when I tried this patch.

CREATE TABLE a (a text) PARTITION BY RANGE(a);
CREATE TABLE a1 PARTITION OF a DEFAULT;
INSERT INTO a SELECT repeat('1', 9999999);
CREATE TABLE a2 PARTITION OF a FOR VALUES FROM (2)TO(3);
ALTER TABLE a MERGE PARTITIONS (a1, a2) INTO a1;
ERROR:  row is too big: size 39264, maximum size 8160

-- 
Justin

---

From: Alexander Korotkov <[email-masked]>
Date: Mon, 15 Jun 2026 23:50:07 +0300

> ERROR:  row is too big: size 39264, maximum size 8160

Thank you for your report.  It appears that createPartitionTable()
misses NewRelationCreateToastTable() call (for instance, DefineTable()
has this call).  The attached patch implements fix and has tests.  I'm
going to push it if no objections.

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Tue, 16 Jun 2026 01:36:08 +0400

Hi, Alexander!

> going to push it if no objections.

It looks like the patch is missing in the last message.

Regards,
Pavel Borisov,
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Tue, 16 Jun 2026 00:36:56 +0300

> It looks like the patch is missing in the last message.

Sorry, here it is.

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Tue, 16 Jun 2026 01:56:50 +0400

Hi, Alexander!

I looked into the patch. It's simple enough and looks good to me.
I have one question: is it correct to pass 0 reloptions to
NewRelationCreateToastTable or we need to use transformRelOptions +
heap_reloptions pair to derive toast_reloptions as it is done in
ProcessUtilitySlow() and create_ctas_internal()?

Regards,
Pavel Borisov

---

From: jian he <[email-masked]>
Date: Tue, 16 Jun 2026 16:08:39 +0800

> > It looks like the patch is missing in the last message.

src5=# explain (analyze, timing, costs off) SELECT repeat('1', 9999999);
                     QUERY PLAN
-----------------------------------------------------
 Result (actual time=0.002..0.003 rows=1.00 loops=1)
 Planning Time: 1454.745 ms
 Execution Time: 0.035 ms
(3 rows)

Time: 1458.413 ms (00:01.458)

The timing above is from an Assert-enabled build.
Could we optimize these tests to make them less expensive to run?

--
jian
https://www.enterprisedb.com/

---

From: Alexander Korotkov <[email-masked]>
Date: Tue, 16 Jun 2026 15:19:13 +0300

> src5=# explain (analyze, timing, costs off) SELECT repeat('1', 9999999);

Yes, we can.  Here is the second version of this patch.  Now it uses
just 10'000 bytes value with external storage.

------
Regards,
Alexander Korotkov
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Tue, 16 Jun 2026 15:22:02 +0300

Hi, Pavel!

> ProcessUtilitySlow() and create_ctas_internal()?

Yes, (Datum) 0 is correct here.  MERGE/SPLIT PARTITION grammar
provides no syntactic way for the user to specify reloptions for the
new partitions, so there is nothing to extract via
transformRelOptions.  This matches createPartitionTable() itself,
which already calls heap_create_with_catalog(... reloptions=(Datum) 0
...) for the main relation a few lines above; the TOAST table just
inherits that choice.

Extending the syntax to accept WITH (...) on new partitions would be a
separate, larger feature.  Out of scope for this bug fix.

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Tue, 16 Jun 2026 17:01:34 +0400

Hi, Alexander!

> separate, larger feature.  Out of scope for this bug fix.

I agree, this is out of scope of a fix.
Updated test in v2 and overall patch looks good to me.

A couple of wording proposals:
never gave it -> never gives it
Merged partitions need their own TOAST table -> A merged partition
needs its own TOAST table.
re-stored -> stored
a short string suffices -> a string over that threshold suffices

Regards,
Pavel Borisov,
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Thu, 18 Jun 2026 10:31:11 +0300

Hi, Pavel!

> a short string suffices -> a string over that threshold suffices

Pushed with your suggestions accepted.

------
Regards,
Alexander Korotkov
Supabase

---

From: Justin Pryzby <[email-masked]>
Date: Thu, 18 Jun 2026 10:49:38 -0500

> Pushed with your suggestions accepted.

Thanks.  When I went back to test this, I merged ~25 partitions that
were all on the same tablespace, but the merged table was created on the
default tablespace.

I tried again with default_tablespace set, but it was ignored.  I think
that's wrong.  It's good to follow the tablespace of the parent table,
but if it has no tablespace set, default_tablespace should be obeyed.
See surrounding logic in DefineRelation.

I see the docs say this:
+       <command>ALTER TABLE MERGE PARTITION</command> uses the partitioned
+       table itself as the template to construct the new partition.
+       The new partition will inherit the same table access method, persistence
+       type, and tablespace as the partitioned table.

-- 
Justin

---

From: Alexander Korotkov <[email-masked]>
Date: Sun, 21 Jun 2026 15:11:26 +0300

> +       type, and tablespace as the partitioned table.

Correct, please see the attached patch, it makes
createPartitionTable() deal with tablespaces the same was as
DefineRelation() does.

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Mon, 22 Jun 2026 14:44:33 +0400

Hi, Alexander!

> createPartitionTable() deal with tablespaces the same was as

Thank you for working on this feature!
I've looked into the last v1 patch.

Does it also worth inheriting DefineRelation()'s check and error for
the case if (tablespaceId == GLOBALTABLESPACE_OID)?
A brief look for default_tablespace GUC doesn't reveal a way why it
could not be set to global tablespace in a session.

Best regards,
Pavel Borisov
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Wed, 24 Jun 2026 13:24:49 +0300

> could not be set to global tablespace in a session.

Thank you for catching this.  I've added this check and corresponding tests.

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Wed, 24 Jun 2026 14:44:35 +0400

Hi, Alexander!

> Thank you for catching this.  I've added this check and corresponding tests.

Looked at the patch v2.
I think in test we'd better split comments for the failing block (SET
default_tablespace TO pg_global;) and for the successful block (after
RESET default_tablespace;). Otherwise, the comment paragraph looks a
little hard to read to me:
+-- Parent has no explicit tablespace and default_tablespace is empty: the
+-- new partition uses the database default (reltablespace = 0).  Also
+-- exercise the pg_global rejection path with default_tablespace pointing
+-- at the shared tablespace.

Overall the patch looks good to me.

Regards,
Pavel Borisov
Supabase

---

From: Justin Pryzby <[email-masked]>
Date: Fri, 26 Jun 2026 08:40:14 -0500

Thanks for addressing the tablespace issue.

One more thing -- merging non-contiguous tables is currently refused:

ts=# CREATE TABLE a(t timestamptz) PARTITION BY RANGE (t);
ts=# CREATE TABLE a_20260101 PARTITION OF a FOR VALUES FROM ('20260101')TO('20260102');
ts=# CREATE TABLE a_20260126 PARTITION OF a FOR VALUES FROM ('20260126')TO('20260127');
ts=# CREATE TABLE a_20260127 PARTITION OF a FOR VALUES FROM ('20260127')TO('20260128');
ts=# CREATE TABLE a_20260128 PARTITION OF a FOR VALUES FROM ('20260128')TO('20260129');

ts=# ALTER TABLE a MERGE PARTITIONS (a_20260101,a_20260126,a_20260127,a_20260128) INTO a_202601;
ERROR:  cannot merge partition "a_20260126" together with partition "a_20260101"
DETAIL:  The lower bound of partition "a_20260126" is not equal to the upper bound of partition "a_20260101".
HINT:  ALTER TABLE ... MERGE PARTITIONS requires the partition bounds to be adjacent.

The goal seems to be to avoid overlapping partition constaints.

If there's a default partition, that also avoids the possibility of
needing to move *some* (but not all) tuples from it into the merged
partition.

I think there should be separate logic depending on the existance of a
default partition:

- The existing logic seems to correctly handle the case of a default
  partition, which is being merged (gap is allowed).

- The case of a default partition which is not being merged is also
  handled: no gap is allowed.  Actually, this case was probably the
  motivation behind checking that the partitions are adjacent.

- If there's *no* default partition, then I think the check should be
  relaxed; it's sufficient to verify that the bounds of the merged
  partition do not overlap with any partition which is not being merged;

-- 
Justin

---

From: Pavel Borisov <[email-masked]>
Date: Fri, 26 Jun 2026 17:47:06 +0400

Hi, Justin!

>   partition do not overlap with any partition which is not being merged;

Thank you for reporting on this feature!
Yes, I think main motivation for not allowing a partition bounds gaps for
merge was the complication in case a DEFAULT partition exists.
Probably, this could be relaxed when there is no DEFAULT partition.

Regards,
Pavel Borisov
Supabase

---

From: Dmitry Koval <[email-masked]>
Date: Fri, 26 Jun 2026 18:20:18 +0300

Hi!

If we exclude case with DEFAULT partition, MERGE PARTITIONS command was
intended to be used when an incorrect table partitioning was chosen.
For example, a table was initially partitioned by month, but later we
needed to change table partitioning by quarter. In this case, MERGE
PARTITIONS command should merge several adjacent partitions into one.
Current checks are made for this case.

 >partition do not overlap with any partition which is not being merged;

It's probably possible to do this. But in this case, the command will
not exactly be "MERGE PARTITIONS" ("MERGE PARTITIONS & EXPAND"?).

-- 
With best regards,
Dmitry Koval

Postgres Professional: http://postgrespro.com

---

From: Alexander Korotkov <[email-masked]>
Date: Fri, 26 Jun 2026 22:50:36 +0300

> not exactly be "MERGE PARTITIONS" ("MERGE PARTITIONS & EXPAND"?).

+1,
We can implement a support for this for 20.  For 19, I propose to
state the restriction more explicit in the docs.  See the attached
patch.

------
Regards,
Alexander Korotkov
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Tue, 30 Jun 2026 14:06:53 +0300

> state the restriction more explicit in the docs.  See the attached

I'm going to push the docs patch if no objections.

------
Regards,
Alexander Korotkov
Supabase

---

From: Pavel Borisov <[email-masked]>
Date: Tue, 30 Jun 2026 15:25:31 +0400

Hi, Alexander!

> I'm going to push the docs patch if no objections.
I looked at the doc patch. IMO "in order to be merged" is redundant.
I'd propose following:
"For range-partitioned tables, the ranges of merged partitions must be
adjacent. This applies even if the partitioned table has no default
partition."

Regards,
Pavel Borisov
Supabase

---

From: Alexander Korotkov <[email-masked]>
Date: Tue, 30 Jun 2026 22:38:00 +0300

Hi, Pavel!

> adjacent. This applies even if the partitioned table has no default

I've included your suggestion.
Pushed and and backpatched to 19.

------
Regards,
Alexander Korotkov
Supabase