Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wNQ2W-000nJb-0q for pgsql-hackers@arkaria.postgresql.org; Thu, 14 May 2026 06:59:24 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wNQ2U-00BADV-2g for pgsql-hackers@arkaria.postgresql.org; Thu, 14 May 2026 06:59:22 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wNQ2U-00BADN-0z for pgsql-hackers@lists.postgresql.org; Thu, 14 May 2026 06:59:22 +0000 Received: from mail-pg1-x532.google.com ([2607:f8b0:4864:20::532]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wNQ2R-00000000UZ2-1Msk for pgsql-hackers@postgresql.org; Thu, 14 May 2026 06:59:21 +0000 Received: by mail-pg1-x532.google.com with SMTP id 41be03b00d2f7-c80170db7d6so3041737a12.0 for ; Wed, 13 May 2026 23:59:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778741959; x=1779346759; darn=postgresql.org; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=926e0M3/7cJe3q3zhfp8qJ86+ligWL4URsgIbgCVBcc=; b=M/Br/R5Gvn8K3LqcVqtZttcTyl3AV2+bUsaIVmoErMwFUq/6OwcVbPjZLLEq/n6jL3 kGIKsxXYBXBy3Q+WHWZUKQo3tOyQ6CVlNI3yAOu8vkTNOgWLsRwvBaetrs+lPDSTLwXu tzkwIlB4coADKlNBbV1hJfqLlT2TB3T6HlAzv8dOjS6fa3wykXc0oG7ocWcE4reW84lv wLd13IM59VIq/2M7yfW9PoQA+a/I5gT6NNSMobcb4Vn2Xew3PYxXqO1ZxOSLqNor1UJ7 XuMwl1fQHp4Je9/1daStnveuZKiHdjBSIs3Gksn12mRYQV+WbOAlfP7m7PU/HZs7z7Ti sViA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778741959; x=1779346759; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=926e0M3/7cJe3q3zhfp8qJ86+ligWL4URsgIbgCVBcc=; b=o2ORg2YWG4LYUfliaPb18zm/9rjnR/SRZUiSNKVNiT/tZOAcRyYAhgsaIZZVuUPzxm AFOLt/m3DXjszJfgoogM5xipLdx42da/02No5Z5B33hKSMAB70SBpZC+vHwRhvveROe5 7FDzskETGbdb0WpyHbGbxm9EiUMsiGil+EDy7aGoWG26KW0kLM9cYpE6HWkPym1ucDXY XXxI62VCctp6YwpiMG+JS8Lecb2f6gsZ8+PB1UwbmwW7V+OWm/QrA69bkNrA7NpPaZGI Ol9pFkV9Kj154yuy5E2UhnO42775XV3IKhFuhcdvuCZm7nDg1VMJmNgL6LSSvfxQkwjL qJcQ== X-Gm-Message-State: AOJu0YyxAKpXpHbHhAm42s5dKX5fuMHCiQWJliqmUugB26Tk6PbqIihA JuRz5U0IvTmt261+mQ4tjDK46o9i3JCiGZ5TTQMKiyd69v0CTx9gtOzb0PFNPxWtB4Y= X-Gm-Gg: Acq92OETarnYqGQ4aRaFfGvs424dnniz2sHiYhdbuRiw+zJg7dnUSYb+jlhJBNVYdhF 12K7NwcOcJus0zxATnuWJAxoEEHVJoiuxTgqUIu3+9KQvvp0oZRESWoEU0wYJL5HJI9sdu7g7k7 88vWHX/NYm4G4b/VI6bHQvlJguUKPyeqWwAApJPchfnnaXhhwB1d8JCB1r76lrPQWw/ZdrHU510 uC63U5R7O1spnNS18OZ6mUlvoX5v1aJzTIfjbYBECrYn5AEoiGSgmYVfa2iJT3Lw+WwNO9qOPDb P0HHkpixjRqlLduUm/vZkT/v0rjr3k0tH2py+P+oYOOG2oncaooC7VqwGKfUp86VujhX7btGuXX lPqpqtYI3Rm0ji3SMm5e11zHHt611R2y9TVYo6fp6iR1sKVjbpBZAwWWm6dThstqs7751YeU0Ey citiU+oYC8NKEevNLYtgcNU39ykbRSl4k= X-Received: by 2002:a17:902:cf10:b0:2bc:ebb1:e3a7 with SMTP id d9443c01a7336-2bd276dc3c5mr70744575ad.32.1778741958478; Wed, 13 May 2026 23:59:18 -0700 (PDT) Received: from smtpclient.apple ([45.32.121.103]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c26355csm13554115ad.35.2026.05.13.23.59.15 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 13 May 2026 23:59:17 -0700 (PDT) From: Chao Li Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.400.21\)) Subject: Re: Fix SPLIT PARTITION bound-overlap bug and other improvements Date: Thu, 14 May 2026 14:58:38 +0800 In-Reply-To: <4df20e70-a083-4334-9548-5f8b9025847c@postgrespro.ru> Cc: PostgreSQL-development , Alexander Korotkov To: Dmitry Koval References: <4df20e70-a083-4334-9548-5f8b9025847c@postgrespro.ru> X-Mailer: Apple Mail (2.3864.400.21) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On May 14, 2026, at 04:47, Dmitry Koval = wrote: >=20 > Hi, Chao Li! >=20 > Thank you for the bug report, test script, and fix! >=20 > >> 0. A bound-overlap bug >=20 > I think this fix should be applied without much discussion: > = ------------------------------------------------------------------------ > diff --git a/src/backend/partitioning/partbounds.c = b/src/backend/partitioning/partbounds.c > index 9b4277a4987..8b8f90569fe 100644 > --- a/src/backend/partitioning/partbounds.c > +++ b/src/backend/partitioning/partbounds.c > @@ -5419,7 +5419,8 @@ check_partition_bounds_for_split_range(Relation = parent, > "ALTER = TABLE ... SPLIT PARTITION"), > parser_errposition(pstate, exprLocation((Node *) datum))); > } > - else > + > + if (last) > { > PartitionRangeBound *split_upper; > = ------------------------------------------------------------------------ Thanks for your confirmation. >=20 > >> 1. The documentation about splitting with a DEFAULT partition is a = bit unclear > >> ... > >> 2. I found this hint message confusing: > >> ... >=20 > Unfortunately, I cannot comment on these points; it would be good to = get the opinion of people who know English well. I want to add one more point about these two changes. There is a code comment saying that when a DEFAULT partition is = specified, the new partition's lower bound may be greater than the = original lower bound: ``` /* * The lower bound of "spec" must equal the lower bound of the * split partition. However, if one of the new partitions is * DEFAULT, then it is ok for the new partition's lower bound to * be greater than that of the split partition. */=09 ``` This also indicates that the original hint message mentioning =E2=80=9Cexa= ctly match" is wrong for the DEFAULT case. >=20 >=20 > >> 3. SPLIT PARTITION currently provides another way to add a DEFAULT = partition: > >> ... >=20 > Agreed, this is another way to add a DEFAULT partition. But I'm not = sure that this way should be disabled (using the special function = check_split_partition_not_same_bound)... > Maybe it's better to keep it "as is"? >=20 Yeah, this may be worth more discussion. But I think we should either = reject this usage or add a fast path to avoid unnecessary creation of a = new partition, data movement, etc. Otherwise, it feels more like a = misuse of SPLIT PARTITION rather than a useful new alternative. To make this patch easier to process, I split it into 4 commits: 0001 - Fixes the bound-overlap bug 0002 - Fix the incorrect HINT message for the DEFAULT case 0003 - Fix the incorrect description about combined bound in the SGML = doc 0004 - Reject only-create-default-partition usage Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19 Content-Disposition: attachment; filename=v2-0001-Fix-SPLIT-PARTITION-range-bound-validation-with-D.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0001-Fix-SPLIT-PARTITION-range-bound-validation-with-D.patch" Content-Transfer-Encoding: quoted-printable =46rom=200f296d8bef250e38eee74d58cbfc04e6c9c5ea7b=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Thu,=2014=20May=202026=2013:49:43=20+0800=0ASubject:=20[PATCH=20= v2=201/4]=20Fix=20SPLIT=20PARTITION=20range=20bound=20validation=20with=0A= =20DEFAULT=0A=0AWhen=20splitting=20a=20range=20partition=20and=20= defining=20a=20new=20DEFAULT=20partition,=20the=0Avalidation=20checked=20= the=20lower=20bound=20of=20the=20first=20explicit=20partition=20and=20= the=0Aupper=20bound=20of=20explicit=20partitions=20only=20when=20they=20= were=20not=20first.=20=20If=20there=0Awas=20exactly=20one=20explicit=20= non-DEFAULT=20partition,=20its=20upper=20bound=20was=20therefore=0Anot=20= checked.=0A=0AThis=20could=20allow=20the=20replacement=20partition=20to=20= extend=20beyond=20the=20upper=20bound=0Aof=20the=20partition=20being=20= split,=20potentially=20overlapping=20another=20existing=0Apartition.=0A=0A= Fix=20this=20by=20checking=20the=20upper=20bound=20whenever=20the=20= explicit=20partition=20is=20the=0Alast=20one.=20=20Add=20a=20regression=20= test=20covering=20the=20single=20explicit=20partition=20plus=0ADEFAULT=20= case.=0A=0AAuthor:=20Chao=20Li=20=0AReviewed-by:=20= Kirill=20Reshke=20=0AReviewed-by:=20Zhenwei=20= Shang=20=0AReviewed-by:=20Dmitry=20Koval=20= =0ADiscussion:=20= https://postgr.es/m/C18878AB-DEB2-4A61-9995-A035DD644B81@gmail.com=0A---=0A= =20src/backend/partitioning/partbounds.c=20=20=20=20=20=20=20=20=20|=20=20= 3=20++-=0A=20src/test/regress/expected/partition_split.out=20|=2016=20= ++++++++++++++++=0A=20src/test/regress/sql/partition_split.sql=20=20=20=20= =20=20|=2015=20+++++++++++++++=0A=203=20files=20changed,=2033=20= insertions(+),=201=20deletion(-)=0A=0Adiff=20--git=20= a/src/backend/partitioning/partbounds.c=20= b/src/backend/partitioning/partbounds.c=0Aindex=20= a09beec34d8..73dea0375be=20100644=0A---=20= a/src/backend/partitioning/partbounds.c=0A+++=20= b/src/backend/partitioning/partbounds.c=0A@@=20-5419,7=20+5419,8=20@@=20= check_partition_bounds_for_split_range(Relation=20parent,=0A=20=09=09=09=09= =09=09=09=09"ALTER=20TABLE=20...=20SPLIT=20PARTITION"),=0A=20=09=09=09=09= =09=09parser_errposition(pstate,=20exprLocation((Node=20*)=20datum)));=0A= =20=09=09}=0A-=09=09else=0A+=0A+=09=09if=20(last)=0A=20=09=09{=0A=20=09=09= =09PartitionRangeBound=20*split_upper;=0A=20=0Adiff=20--git=20= a/src/test/regress/expected/partition_split.out=20= b/src/test/regress/expected/partition_split.out=0Aindex=20= 961b37953c8..a2ccbe5138b=20100644=0A---=20= a/src/test/regress/expected/partition_split.out=0A+++=20= b/src/test/regress/expected/partition_split.out=0A@@=20-1188,6=20= +1188,22=20@@=20SELECT=20tableoid::regclass,=20*=20FROM=20sales_range=20= ORDER=20BY=20tableoid::regclass::text=0A=20=0A=20DROP=20TABLE=20= sales_range;=0A=20--=0A+--=20Test=20that=20the=20explicit=20partition=20= bound=20cannot=20extend=20outside=20the=20split=0A+--=20partition's=20= bound=20when=20a=20DEFAULT=20partition=20is=20specified.=0A+--=0A+CREATE=20= TABLE=20t=20(i=20int)=20PARTITION=20BY=20RANGE=20(i);=0A+CREATE=20TABLE=20= tp_0_51=20PARTITION=20OF=20t=20FOR=20VALUES=20FROM=20(0)=20TO=20(51);=0A= +CREATE=20TABLE=20tp_51_100=20PARTITION=20OF=20t=20FOR=20VALUES=20FROM=20= (51)=20TO=20(100);=0A+--=20ERROR=0A+ALTER=20TABLE=20t=20SPLIT=20= PARTITION=20tp_0_51=20INTO=0A+=20=20(PARTITION=20tp_0_51=20FOR=20VALUES=20= FROM=20(0)=20TO=20(53),=0A+=20=20=20PARTITION=20tp_default=20DEFAULT);=0A= +ERROR:=20=20upper=20bound=20of=20partition=20"tp_0_51"=20is=20greater=20= than=20upper=20bound=20of=20split=20partition=20"tp_0_51"=0A+LINE=202:=20= =20=20(PARTITION=20tp_0_51=20FOR=20VALUES=20FROM=20(0)=20TO=20(53),=0A+=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20^=0A+HINT:=20=20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20require=20= combined=20bounds=20of=20new=20partitions=20must=20exactly=20match=20the=20= bound=20of=20the=20split=20partition.=0A+DROP=20TABLE=20t;=0A+--=0A=20--=20= Try=20to=20SPLIT=20partition=20of=20another=20table.=0A=20--=0A=20CREATE=20= TABLE=20t1(i=20int,=20t=20text)=20PARTITION=20BY=20LIST=20(t);=0Adiff=20= --git=20a/src/test/regress/sql/partition_split.sql=20= b/src/test/regress/sql/partition_split.sql=0Aindex=20= a110fc87867..d9821c5e2a3=20100644=0A---=20= a/src/test/regress/sql/partition_split.sql=0A+++=20= b/src/test/regress/sql/partition_split.sql=0A@@=20-834,6=20+834,21=20@@=20= SELECT=20tableoid::regclass,=20*=20FROM=20sales_range=20ORDER=20BY=20= tableoid::regclass::text=0A=20=0A=20DROP=20TABLE=20sales_range;=0A=20=0A= +--=0A+--=20Test=20that=20the=20explicit=20partition=20bound=20cannot=20= extend=20outside=20the=20split=0A+--=20partition's=20bound=20when=20a=20= DEFAULT=20partition=20is=20specified.=0A+--=0A+CREATE=20TABLE=20t=20(i=20= int)=20PARTITION=20BY=20RANGE=20(i);=0A+CREATE=20TABLE=20tp_0_51=20= PARTITION=20OF=20t=20FOR=20VALUES=20FROM=20(0)=20TO=20(51);=0A+CREATE=20= TABLE=20tp_51_100=20PARTITION=20OF=20t=20FOR=20VALUES=20FROM=20(51)=20TO=20= (100);=0A+=0A+--=20ERROR=0A+ALTER=20TABLE=20t=20SPLIT=20PARTITION=20= tp_0_51=20INTO=0A+=20=20(PARTITION=20tp_0_51=20FOR=20VALUES=20FROM=20(0)=20= TO=20(53),=0A+=20=20=20PARTITION=20tp_default=20DEFAULT);=0A+=0A+DROP=20= TABLE=20t;=0A+=0A=20--=0A=20--=20Try=20to=20SPLIT=20partition=20of=20= another=20table.=0A=20--=0A--=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19 Content-Disposition: attachment; filename=v2-0002-Fix-SPLIT-PARTITION-hint-for-DEFAULT-partition-bo.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0002-Fix-SPLIT-PARTITION-hint-for-DEFAULT-partition-bo.patch" Content-Transfer-Encoding: quoted-printable =46rom=201a30c86cdc81482793298602f89d03821207339c=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Thu,=2014=20May=202026=2013:53:25=20+0800=0ASubject:=20[PATCH=20= v2=202/4]=20Fix=20SPLIT=20PARTITION=20hint=20for=20DEFAULT=20partition=20= bounds=0A=0AWhen=20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20specifies=20= a=20DEFAULT=20partition,=20the=0Aexplicit=20partitions=20do=20not=20need=20= to=20cover=20the=20split=20partition's=20bound=0Aexactly.=20=20They=20= may=20cover=20only=20part=20of=20it,=20with=20the=20DEFAULT=20partition=0A= covering=20the=20remaining=20range.=0A=0AHowever,=20the=20existing=20= hint=20said=20that=20the=20combined=20bounds=20of=20the=20new=0A= partitions=20must=20exactly=20match=20the=20bound=20of=20the=20split=20= partition,=20which=20is=0Amisleading=20for=20this=20case=20and=20= inconsistent=20with=20the=20code=20comment.=0A=0AFix=20the=20hint=20to=20= state=20the=20actual=20requirement:=20explicit=20partition=20bounds=0A= must=20stay=20within=20the=20bounds=20of=20the=20split=20partition=20= when=20a=20DEFAULT=0Apartition=20is=20specified.=0A=0AAuthor:=20Chao=20= Li=20=0AReviewed-by:=0ADiscussion:=20= https://postgr.es/m/C18878AB-DEB2-4A61-9995-A035DD644B81@gmail.com=0A---=0A= =20src/backend/partitioning/partbounds.c=20=20=20=20=20=20=20=20=20|=206=20= ++----=0A=20src/test/regress/expected/partition_split.out=20|=202=20+-=0A= =202=20files=20changed,=203=20insertions(+),=205=20deletions(-)=0A=0A= diff=20--git=20a/src/backend/partitioning/partbounds.c=20= b/src/backend/partitioning/partbounds.c=0Aindex=20= 73dea0375be..19589dc687f=20100644=0A---=20= a/src/backend/partitioning/partbounds.c=0A+++=20= b/src/backend/partitioning/partbounds.c=0A@@=20-5415,8=20+5415,7=20@@=20= check_partition_bounds_for_split_range(Relation=20parent,=0A=20=09=09=09=09= =09=09errmsg("lower=20bound=20of=20partition=20\"%s\"=20is=20less=20than=20= lower=20bound=20of=20split=20partition=20\"%s\"",=0A=20=09=09=09=09=09=09= =09=20=20=20relname,=0A=20=09=09=09=09=09=09=09=20=20=20= get_rel_name(splitPartOid)),=0A-=09=09=09=09=09=09errhint("%s=20require=20= combined=20bounds=20of=20new=20partitions=20must=20exactly=20match=20the=20= bound=20of=20the=20split=20partition.",=0A-=09=09=09=09=09=09=09=09= "ALTER=20TABLE=20...=20SPLIT=20PARTITION"),=0A+=09=09=09=09=09=09= errhint("Explicit=20partition=20bounds=20must=20be=20contained=20within=20= the=20bounds=20of=20the=20split=20partition=20when=20a=20DEFAULT=20= partition=20is=20specified."),=0A=20=09=09=09=09=09=09= parser_errposition(pstate,=20exprLocation((Node=20*)=20datum)));=0A=20=09= =09}=0A=20=0A@@=20-5458,8=20+5457,7=20@@=20= check_partition_bounds_for_split_range(Relation=20parent,=0A=20=09=09=09=09= =09=09errmsg("upper=20bound=20of=20partition=20\"%s\"=20is=20greater=20= than=20upper=20bound=20of=20split=20partition=20\"%s\"",=0A=20=09=09=09=09= =09=09=09=20=20=20relname,=0A=20=09=09=09=09=09=09=09=20=20=20= get_rel_name(splitPartOid)),=0A-=09=09=09=09=09=09errhint("%s=20require=20= combined=20bounds=20of=20new=20partitions=20must=20exactly=20match=20the=20= bound=20of=20the=20split=20partition.",=0A-=09=09=09=09=09=09=09=09= "ALTER=20TABLE=20...=20SPLIT=20PARTITION"),=0A+=09=09=09=09=09=09= errhint("Explicit=20partition=20bounds=20must=20be=20contained=20within=20= the=20bounds=20of=20the=20split=20partition=20when=20a=20DEFAULT=20= partition=20is=20specified."),=0A=20=09=09=09=09=09=09= parser_errposition(pstate,=20exprLocation((Node=20*)=20datum)));=0A=20=09= =09}=0A=20=09}=0Adiff=20--git=20= a/src/test/regress/expected/partition_split.out=20= b/src/test/regress/expected/partition_split.out=0Aindex=20= a2ccbe5138b..d4f536c5e00=20100644=0A---=20= a/src/test/regress/expected/partition_split.out=0A+++=20= b/src/test/regress/expected/partition_split.out=0A@@=20-1201,7=20+1201,7=20= @@=20ALTER=20TABLE=20t=20SPLIT=20PARTITION=20tp_0_51=20INTO=0A=20ERROR:=20= =20upper=20bound=20of=20partition=20"tp_0_51"=20is=20greater=20than=20= upper=20bound=20of=20split=20partition=20"tp_0_51"=0A=20LINE=202:=20=20=20= (PARTITION=20tp_0_51=20FOR=20VALUES=20FROM=20(0)=20TO=20(53),=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20^=0A-HINT:=20=20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20require=20= combined=20bounds=20of=20new=20partitions=20must=20exactly=20match=20the=20= bound=20of=20the=20split=20partition.=0A+HINT:=20=20Explicit=20partition=20= bounds=20must=20be=20contained=20within=20the=20bounds=20of=20the=20= split=20partition=20when=20a=20DEFAULT=20partition=20is=20specified.=0A=20= DROP=20TABLE=20t;=0A=20--=0A=20--=20Try=20to=20SPLIT=20partition=20of=20= another=20table.=0A--=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19 Content-Disposition: attachment; filename=v2-0003-Clarify-SPLIT-PARTITION-bound-requirements-in-doc.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0003-Clarify-SPLIT-PARTITION-bound-requirements-in-doc.patch" Content-Transfer-Encoding: quoted-printable =46rom=20d2e41d07334bca65820d7840c68bfafac2eac6fd=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Thu,=2014=20May=202026=2013:51:19=20+0800=0ASubject:=20[PATCH=20= v2=203/4]=20Clarify=20SPLIT=20PARTITION=20bound=20requirements=20in=20= docs=0A=0AThe=20documentation=20said=20that=20the=20bounds=20of=20new=20= partitions=20should=20not=0Aoverlap=20and=20that=20their=20combined=20= bounds=20should=20equal=20the=20bounds=20of=20the=0Asplit=20partition.=20= =20That=20is=20misleading=20when=20a=20new=20DEFAULT=20partition=20is=0A= specified,=20because=20the=20explicit=20partitions=20may=20cover=20only=20= part=20of=20the=0Asplit=20partition=20while=20the=20DEFAULT=20partition=20= covers=20the=20rest.=0A=0AClarify=20that=20new=20non-DEFAULT=20partition=20= bounds=20must=20not=20overlap=20with=0Aother=20new=20or=20existing=20= partitions=20and=20must=20be=20contained=20within=20the=20bounds=0Aof=20= the=20split=20partition.=20=20Also=20state=20that=20the=20combined=20= bounds=20must=20exactly=0Amatch=20the=20split=20partition=20only=20when=20= no=20new=20DEFAULT=20partition=20is=20specified.=0A=0AWhile=20here,=20= improve=20nearby=20wording=20about=20hash-partitioned=20target=20tables=0A= and=20splitting=20a=20DEFAULT=20partition=20with=20the=20same=20= partition=20name.=0A=0AAuthor:=20Chao=20Li=20=0A= Reviewed-by:=0ADiscussion:=20= https://postgr.es/m/C18878AB-DEB2-4A61-9995-A035DD644B81@gmail.com=0A---=0A= =20doc/src/sgml/ref/alter_table.sgml=20|=2023=20++++++++++++++---------=0A= =201=20file=20changed,=2014=20insertions(+),=209=20deletions(-)=0A=0A= diff=20--git=20a/doc/src/sgml/ref/alter_table.sgml=20= b/doc/src/sgml/ref/alter_table.sgml=0Aindex=201f9a456fd33..dec34337d1a=20= 100644=0A---=20a/doc/src/sgml/ref/alter_table.sgml=0A+++=20= b/doc/src/sgml/ref/alter_table.sgml=0A@@=20-1293,7=20+1293,7=20@@=20WITH=20= (=20MODULUS=20numeric_literal,=20REM=0A=20=20=20=20=20= =0A=20=20=20=20=20=20=0A=20=20=20=20=20=20=20This=20form=20= splits=20a=20single=20partition=20of=20the=20target=20table=20into=20new=0A= -=20=20=20=20=20=20partitions.=20Hash-partitioned=20target=20table=20is=20= not=20supported.=0A+=20=20=20=20=20=20partitions.=20=20Hash-partitioned=20= target=20tables=20are=20not=20supported.=0A=20=20=20=20=20=20=20Only=20a=20= simple,=20non-partitioned=20partition=20can=20be=20split.=0A=20=20=20=20=20= =20=20If=20the=20split=20partition=20is=20the=20= DEFAULT=20partition,=0A=20=20=20=20=20=20=20one=20of=20= the=20new=20partitions=20must=20be=20DEFAULT.=0A@@=20= -1303,18=20+1303,23=20@@=20WITH=20(=20MODULUS=20numeric_literal,=20REM=0A=20=20=20=20=20= =20=0A=20=0A=20=20=20=20=20=20=0A-=20=20=20=20=20=20The=20= bounds=20of=20new=20partitions=20should=20not=20overlap=20with=20those=20= of=20new=20or=0A-=20=20=20=20=20=20existing=20partitions=20(except=20= partition_name).=0A-=20=20= =20=20=20=20The=20combined=20bounds=20of=20new=20partitions=20=0A= +=20=20=20=20=20=20The=20bounds=20of=20new=20= non-DEFAULT=20partitions=20must=20not=0A+=20=20=20=20=20= =20overlap=20with=20those=20of=20new=20or=20existing=20partitions,=20= except=0A+=20=20=20=20=20=20partition_name,=20and=20must=20be=0A+=20= =20=20=20=20=20contained=20within=20the=20bounds=20of=20the=20split=20= partition=0A+=20=20=20=20=20=20partition_name.=0A+=20=20=20=20=20=20= If=20no=20new=20DEFAULT=20partition=20is=20specified,=20= the=0A+=20=20=20=20=20=20combined=20bounds=20of=20the=20new=20partitions=0A= +=20=20=20=20=20=20=0A=20=20=20=20=20=20=20partition_name1,=0A=20=20=20=20=20=20=20= partition_name2[,=20= ...]=0A-=20=20=20=20=20=20=20should=20be=20equal=20to=20the=20= bounds=20of=20the=20split=20partition=0A+=20=20=20=20=20=20=20= must=20exactly=20match=20the=20bounds=20of=20the=20split=20partition=0A=20= =20=20=20=20=20=20partition_name.=0A=20=20=20=20=20=20=20= One=20of=20the=20new=20partitions=20can=20have=20the=20same=20name=20as=20= the=20split=20partition=0A-=20=20=20=20=20=20partition_name=0A-=20=20=20=20=20=20= (this=20is=20suitable=20in=20case=20of=20splitting=20the=20= DEFAULT=0A-=20=20=20=20=20=20partition:=20after=20the=20= split,=20the=20DEFAULT=20partition=0A-=20=20=20=20=20=20= remains=20with=20the=20same=20name,=20but=20its=20partition=20bound=20= changes).=0A+=20=20=20=20=20=20partition_name.=0A+=20=20=20=20=20=20= This=20is=20useful=20when=20splitting=20the=20DEFAULT=20= partition,=0A+=20=20=20=20=20=20so=20that=20after=20the=20split,=20the=20= DEFAULT=20partition=0A+=20=20=20=20=20=20keeps=20the=20= same=20name=20but=20its=20partition=20bound=20changes.=0A=20=20=20=20=20=20= =0A=20=0A=20=20=20=20=20=20=0A--=20=0A2.50.1=20(Apple=20= Git-155)=0A=0A= --Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19 Content-Disposition: attachment; filename=v2-0004-Reject-degenerate-SPLIT-PARTITION-with-DEFAULT-pa.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0004-Reject-degenerate-SPLIT-PARTITION-with-DEFAULT-pa.patch" Content-Transfer-Encoding: quoted-printable =46rom=2095cb0af42d75d23050b2f5ce01325863b7583e5c=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Thu,=2014=20May=202026=2013:55:37=20+0800=0ASubject:=20[PATCH=20= v2=204/4]=20Reject=20degenerate=20SPLIT=20PARTITION=20with=20DEFAULT=0A=20= partition=0A=0AALTER=20TABLE=20...=20SPLIT=20PARTITION=20allows=20a=20= DEFAULT=20partition=20to=20be=20created=0Aas=20one=20of=20the=20= replacement=20partitions=20when=20the=20parent=20table=20does=20not=0A= already=20have=20one.=20=20However,=20it=20should=20not=20allow=20the=20= degenerate=20case=20where=0Aa=20non-DEFAULT=20partition=20keeps=20= exactly=20the=20same=20bound=20as=20the=20split=0Apartition=20and=20the=20= command=20merely=20adds=20a=20DEFAULT=20partition=20through=20the=0A= SPLIT=20PARTITION=20path.=0A=0ADetect=20that=20case=20by=20comparing=20= the=20bound=20of=20the=20split=20partition=20with=20the=0Abound=20of=20= the=20only=20non-DEFAULT=20replacement=20partition,=20and=20raise=20an=20= error=0Awhen=20they=20are=20the=20same.=20=20Users=20should=20add=20a=20= DEFAULT=20partition=20directly=0Awith=20CREATE=20TABLE=20...=20PARTITION=20= OF=20...=20DEFAULT=20or=20ALTER=20TABLE=20...=20ATTACH=0APARTITION=20...=20= DEFAULT=20instead.=0A=0AAuthor:=20Chao=20Li=20=0A= Reviewed-by:=0ADiscussion:=20= https://postgr.es/m/C18878AB-DEB2-4A61-9995-A035DD644B81@gmail.com=0A---=0A= =20src/backend/partitioning/partbounds.c=20=20=20=20=20=20=20=20=20|=20= 69=20+++++++++++++++++++=0A=20= src/test/regress/expected/partition_split.out=20|=2018=20+++++=0A=20= src/test/regress/sql/partition_split.sql=20=20=20=20=20=20|=2016=20+++++=0A= =203=20files=20changed,=20103=20insertions(+)=0A=0Adiff=20--git=20= a/src/backend/partitioning/partbounds.c=20= b/src/backend/partitioning/partbounds.c=0Aindex=20= 19589dc687f..5c1919e6d10=20100644=0A---=20= a/src/backend/partitioning/partbounds.c=0A+++=20= b/src/backend/partitioning/partbounds.c=0A@@=20-36,6=20+36,7=20@@=0A=20= #include=20"utils/datum.h"=0A=20#include=20"utils/fmgroids.h"=0A=20= #include=20"utils/lsyscache.h"=0A+#include=20"utils/memutils.h"=0A=20= #include=20"utils/partcache.h"=0A=20#include=20"utils/ruleutils.h"=0A=20= #include=20"utils/snapmgr.h"=0A@@=20-5700,6=20+5701,70=20@@=20= check_parent_values_in_new_partitions(Relation=20parent,=0A=20=09}=0A=20= }=0A=20=0A+/*=0A+=20*=20check_split_partition_not_same_bound=0A+=20*=0A+=20= *=20Reject=20splitting=20a=20non-DEFAULT=20partition=20into=20one=20= non-DEFAULT=20partition=0A+=20*=20with=20the=20original=20bound=20plus=20= a=20DEFAULT=20partition.=20=20That=20form=20does=20not=0A+=20*=20perform=20= a=20real=20split;=20it=20merely=20adds=20a=20DEFAULT=20partition=20to=20= the=20parent=0A+=20*=20table=20through=20the=20split-partition=20path.=20= =20Users=20should=20use=0A+=20*=20CREATE=20TABLE=20...=20PARTITION=20OF=20= ...=20DEFAULT=20or=20ALTER=20TABLE=20...=20ATTACH=0A+=20*=20PARTITION=20= ...=20DEFAULT=20for=20that.=0A+=20*/=0A+static=20void=0A= +check_split_partition_not_same_bound(Relation=20parent,=0A+=09=09=09=09=09= =09=09=09=09=20Oid=20splitPartOid,=0A+=09=09=09=09=09=09=09=09=09=20= SinglePartitionSpec=20**parts,=0A+=09=09=09=09=09=09=09=09=09=20int=20= nparts,=0A+=09=09=09=09=09=09=09=09=09=20ParseState=20*pstate)=0A+{=0A+=09= PartitionKey=20key=20=3D=20RelationGetPartitionKey(parent);=0A+=09= PartitionBoundSpec=20*split_spec;=0A+=09PartitionBoundSpec=20= *new_specs[1];=0A+=09PartitionBoundSpec=20*old_specs[1];=0A+=09= PartitionBoundInfo=20new_boundinfo;=0A+=09PartitionBoundInfo=20= old_boundinfo;=0A+=09int=09=09=20=20=20*new_mapping;=0A+=09int=09=09=20=20= =20*old_mapping;=0A+=09MemoryContext=20old_cxt;=0A+=09MemoryContext=20= tmp_cxt;=0A+=09bool=09=09same_bound;=0A+=0A+=09if=20(nparts=20!=3D=201)=0A= +=09=09return;=0A+=0A+=09tmp_cxt=20=3D=20= AllocSetContextCreate(CurrentMemoryContext,=0A+=09=09=09=09=09=09=09=09=09= "split=20partition=20bound=20comparison",=0A+=09=09=09=09=09=09=09=09=09= ALLOCSET_SMALL_SIZES);=0A+=09old_cxt=20=3D=20= MemoryContextSwitchTo(tmp_cxt);=0A+=0A+=09split_spec=20=3D=20= get_partition_bound_spec(splitPartOid);=0A+=0A+=09new_specs[0]=20=3D=20= parts[0]->bound;=0A+=09new_boundinfo=20=3D=20= partition_bounds_create(new_specs,=201,=20key,=20&new_mapping);=0A+=0A+=09= old_specs[0]=20=3D=20split_spec;=0A+=09old_boundinfo=20=3D=20= partition_bounds_create(old_specs,=201,=20key,=20&old_mapping);=0A+=0A+=09= same_bound=20=3D=20partition_bounds_equal(key->partnatts,=20= key->parttyplen,=0A+=09=09=09=09=09=09=09=09=09=09key->parttypbyval,=0A+=09= =09=09=09=09=09=09=09=09=09new_boundinfo,=20old_boundinfo);=0A+=0A+=09= MemoryContextSwitchTo(old_cxt);=0A+=09MemoryContextDelete(tmp_cxt);=0A+=0A= +=09if=20(!same_bound)=0A+=09=09return;=0A+=0A+=09ereport(ERROR,=0A+=09=09= =09errcode(ERRCODE_INVALID_OBJECT_DEFINITION),=0A+=09=09=09= errmsg("cannot=20split=20partition=20\"%s\"=20only=20to=20add=20a=20= DEFAULT=20partition",=0A+=09=09=09=09=20=20=20= get_rel_name(splitPartOid)),=0A+=09=09=09errdetail("The=20non-DEFAULT=20= partition=20would=20keep=20the=20same=20partition=20bound."),=0A+=09=09=09= errhint("Use=20CREATE=20TABLE=20...=20PARTITION=20OF=20...=20DEFAULT=20= to=20add=20a=20DEFAULT=20partition."),=0A+=09=09=09= parser_errposition(pstate,=20parts[0]->name->location));=0A+}=0A+=0A=20= /*=0A=20=20*=20check_partitions_for_split=0A=20=20*=0A@@=20-5774,6=20= +5839,10=20@@=20check_partitions_for_split(Relation=20parent,=0A=20=09=09= Assert(nparts=20=3D=3D=20list_length(partlist)=20-=201);=0A=20=09}=0A=20=0A= +=09if=20(!isSplitPartDefault=20&&=20createDefaultPart)=0A+=09=09= check_split_partition_not_same_bound(parent,=20splitPartOid,=20= new_parts,=0A+=09=09=09=09=09=09=09=09=09=09=09=20nparts,=20pstate);=0A+=0A= =20=09if=20(strategy=20=3D=3D=20PARTITION_STRATEGY_RANGE)=0A=20=09{=0A=20= =09=09PartitionRangeBound=20**lower_bounds;=0Adiff=20--git=20= a/src/test/regress/expected/partition_split.out=20= b/src/test/regress/expected/partition_split.out=0Aindex=20= d4f536c5e00..6869a65badb=20100644=0A---=20= a/src/test/regress/expected/partition_split.out=0A+++=20= b/src/test/regress/expected/partition_split.out=0A@@=20-1188,6=20= +1188,24=20@@=20SELECT=20tableoid::regclass,=20*=20FROM=20sales_range=20= ORDER=20BY=20tableoid::regclass::text=0A=20=0A=20DROP=20TABLE=20= sales_range;=0A=20--=0A+--=20Test=20that=20SPLIT=20PARTITION=20rejects=20= the=20degenerate=20case=20where=20the=20only=0A+--=20non-DEFAULT=20= replacement=20partition=20keeps=20the=20original=20bound=20and=20the=20= command=0A+--=20merely=20adds=20a=20DEFAULT=20partition.=0A+--=0A+CREATE=20= TABLE=20t=20(i=20int)=20PARTITION=20BY=20RANGE=20(i);=0A+CREATE=20TABLE=20= tp_0_50=20PARTITION=20OF=20t=20FOR=20VALUES=20FROM=20(0)=20TO=20(50);=0A= +INSERT=20INTO=20t=20VALUES=20(1);=0A+--=20ERROR=0A+ALTER=20TABLE=20t=20= SPLIT=20PARTITION=20tp_0_50=20INTO=0A+=20=20(PARTITION=20tp_0_50=20FOR=20= VALUES=20FROM=20(0)=20TO=20(50),=0A+=20=20=20PARTITION=20tp_default=20= DEFAULT);=0A+ERROR:=20=20cannot=20split=20partition=20"tp_0_50"=20only=20= to=20add=20a=20DEFAULT=20partition=0A+LINE=202:=20=20=20(PARTITION=20= tp_0_50=20FOR=20VALUES=20FROM=20(0)=20TO=20(50),=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20^=0A+DETAIL:=20=20The=20= non-DEFAULT=20partition=20would=20keep=20the=20same=20partition=20bound.=0A= +HINT:=20=20Use=20CREATE=20TABLE=20...=20PARTITION=20OF=20...=20DEFAULT=20= to=20add=20a=20DEFAULT=20partition.=0A+DROP=20TABLE=20t;=0A+--=0A=20--=20= Test=20that=20the=20explicit=20partition=20bound=20cannot=20extend=20= outside=20the=20split=0A=20--=20partition's=20bound=20when=20a=20DEFAULT=20= partition=20is=20specified.=0A=20--=0Adiff=20--git=20= a/src/test/regress/sql/partition_split.sql=20= b/src/test/regress/sql/partition_split.sql=0Aindex=20= d9821c5e2a3..e7bbcc9f054=20100644=0A---=20= a/src/test/regress/sql/partition_split.sql=0A+++=20= b/src/test/regress/sql/partition_split.sql=0A@@=20-834,6=20+834,22=20@@=20= SELECT=20tableoid::regclass,=20*=20FROM=20sales_range=20ORDER=20BY=20= tableoid::regclass::text=0A=20=0A=20DROP=20TABLE=20sales_range;=0A=20=0A= +--=0A+--=20Test=20that=20SPLIT=20PARTITION=20rejects=20the=20degenerate=20= case=20where=20the=20only=0A+--=20non-DEFAULT=20replacement=20partition=20= keeps=20the=20original=20bound=20and=20the=20command=0A+--=20merely=20= adds=20a=20DEFAULT=20partition.=0A+--=0A+CREATE=20TABLE=20t=20(i=20int)=20= PARTITION=20BY=20RANGE=20(i);=0A+CREATE=20TABLE=20tp_0_50=20PARTITION=20= OF=20t=20FOR=20VALUES=20FROM=20(0)=20TO=20(50);=0A+INSERT=20INTO=20t=20= VALUES=20(1);=0A+=0A+--=20ERROR=0A+ALTER=20TABLE=20t=20SPLIT=20PARTITION=20= tp_0_50=20INTO=0A+=20=20(PARTITION=20tp_0_50=20FOR=20VALUES=20FROM=20(0)=20= TO=20(50),=0A+=20=20=20PARTITION=20tp_default=20DEFAULT);=0A+=0A+DROP=20= TABLE=20t;=0A+=0A=20--=0A=20--=20Test=20that=20the=20explicit=20= partition=20bound=20cannot=20extend=20outside=20the=20split=0A=20--=20= partition's=20bound=20when=20a=20DEFAULT=20partition=20is=20specified.=0A= --=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_A251707E-B1BD-45D4-BAA8-8D0C6ADEFB19--