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 1wPAXk-000Upo-0c for pgsql-hackers@arkaria.postgresql.org; Tue, 19 May 2026 02:50:52 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wPAXg-003eKG-1e for pgsql-hackers@arkaria.postgresql.org; Tue, 19 May 2026 02:50:49 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wPAXg-003eK7-0Q for pgsql-hackers@lists.postgresql.org; Tue, 19 May 2026 02:50:49 +0000 Received: from mail-pl1-x634.google.com ([2607:f8b0:4864:20::634]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wPAXe-00000000IJg-2A9d for pgsql-hackers@postgresql.org; Tue, 19 May 2026 02:50:48 +0000 Received: by mail-pl1-x634.google.com with SMTP id d9443c01a7336-2ba6485d219so20656115ad.3 for ; Mon, 18 May 2026 19:50:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779159044; x=1779763844; 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=+mClX7QQt0L599qqHG1bnlVhDbBqizV8wRXQt0nJHAk=; b=HHnBep7bJDeUI8Gqek1icUg48Ww09T94vkm0+QFPlVCjG4FqEQTIEo6xTLiBDu5faS Jqgvc6vTyWiInY7+7RmMpsk3rwi7JBb+dVXJiWMQd9MBBa6UzK0sbTJGJqydhk4k5jQj oAk7GWD1iF6GEpGaR3GvGWUUCHqdLQ3hhr9VeOUa8u3Mf+rg7+8t+64xIg/Mvi8uFNoo aWYPf8JMnQoU3dq/IHEi3eORb1ljZnBJch/so+Adb+8TCjXS1twCnP82uZaamjIGl8oP /VIpIJ8d/XvWY4MO06jeugzE5BAQAqTTYPH3rThFtVob+GY+LP/eNcvKdAO5TTYyjg70 887g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779159044; x=1779763844; 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=+mClX7QQt0L599qqHG1bnlVhDbBqizV8wRXQt0nJHAk=; b=d91hBzoN3CzFX6QkntHFKJsCHXAWUpwDRkBv3Tprz5x38qHpMxkZfLYIL1riK0RXrd c0S62Y+Q4BKWXwQZTYZ2DMw4XdEHSewaUVph/GNCq1ss8cFT/P5F3KeoI3Kjvf3tOItF guIyRltarGpoAQz2Ck0YBkYqrK1Pvh5b6nLVOa7J0bf9NCOWtSg2O8QnHvrwUJVetaUY 9v96RhqvzFc4qVcCeHXjbf7Yunlo3893duNz6j9kkWDj8LJ3g8vmZJ/fjyiTYuHt2fXp qFvWVL3X7gZv0w4qCuH6YXbwNBY6Oceo7pQHomICnpszI3YoO2ozNZIsmaFgyR125gIT dEcQ== X-Forwarded-Encrypted: i=1; AFNElJ8xSANaAWdyOZVFzDG1FFNnCOaZ2WM82fxF224jf/T/cAqBmFfk514CYLWPy32KUf9n31dZVe32FzdGKFbj@postgresql.org X-Gm-Message-State: AOJu0YyxLY6igDQ0mfjAddIXxyFSCAMovsoUi7BC/ig5BoRXMUaiUXYg pbVEO0OOznLeDEMIQLDvCzhskXokTCzHJx9FmNONIeY+pNnvzsWvwzC3 X-Gm-Gg: Acq92OGo13/IYP1nHTm8AoBDkNWZFvgK8RmwbhVjnXxdY2+WdKJIKQmBD8lqMucECps z7rFOHY36e+aEFU0CNEYJeRFzlCyy7PK0zvgKxZOA09+nL8T6bwJSM8nv5ZIOteM5dKokaAMp2F aGPFD9oe1g6rOalUlvkcl6aMRwknIMzUfDcBMt06Ag7ulvE78GF9XvdndonSRZ3ArOVpuioTRCB //ghVZtwB3Snw+yrJVlrhYqnPJPos7kO1kZ2cGn3We2eWrwGEQL2DocyyuUHn6SRjYTggWYMdaL MX7Zw73F7sFfKUrCp0RSK8gMIlqmCynUQ9zGno7GzTaO0TdUZSFYuKC3yASnKnAu2T01fVIuJTr 8ljZ8aXzEjajj6Il++4LIBy0NM3gHmEUs+Zhjz/IJK1Qp6orIzCq73B0bTZsCzt6WI+NIf0LOvf /Ghi3305DhK/yuKegaslTLvRYvcfFrJDY= X-Received: by 2002:a17:903:3c65:b0:2b7:88d8:efde with SMTP id d9443c01a7336-2bd7e860112mr176918925ad.7.1779159044059; Mon, 18 May 2026 19:50:44 -0700 (PDT) Received: from smtpclient.apple ([45.32.121.103]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5c05ffbesm170612235ad.27.2026.05.18.19.50.41 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 18 May 2026 19:50:43 -0700 (PDT) From: Chao Li Message-Id: <09307DC2-64A1-4D6A-9EAF-9A86A173A7FC@gmail.com> Content-Type: multipart/mixed; boundary="Apple-Mail=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA" 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: Tue, 19 May 2026 10:50:03 +0800 In-Reply-To: Cc: Dmitry Koval , PostgreSQL-development To: Alexander Korotkov References: <4df20e70-a083-4334-9548-5f8b9025847c@postgrespro.ru> <4B04275C-E044-4EEE-BE64-6FEEE73DCBB0@gmail.com> 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=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On May 18, 2026, at 20:04, Alexander Korotkov = wrote: >=20 > On Mon, May 18, 2026 at 2:57=E2=80=AFPM Chao Li = wrote: >>> = >>=20 >> v3-0001 through v3-0003 look good to me. >>=20 >> For v3-0004, I have a suspicion, but it's late here and my brain is = getting slow, so I would like to study it more tomorrow. >=20 > Sure, take your time. >=20 > ------ > Regards, > Alexander Korotkov > Supabase My suspicion was that check_split_partition_not_same_bound() now has two = paths. The RANGE path honors collation, while the LIST path does not. So = I spent some time creating a test that uses a case-insensitive = collation: ``` evantest=3D# create collation case_insensitive (provider=3Dicu, = locale=3D'und-u-ks-level2', deterministic =3D false); CREATE COLLATION evantest=3D# create table t (b text collate case_insensitive) partition = by list (b); CREATE TABLE evantest=3D# create table tp_ab partition of t for values in ('a', 'b'); CREATE TABLE evantest=3D# alter table t split partition tp_ab into evantest-# (partition tp_a for values in ('a', 'A'), evantest(# partition tp_default default); ERROR: cannot split partition "tp_ab" only to add a DEFAULT partition LINE 2: (partition tp_a for values in ('a', 'A'), ^ DETAIL: The non-DEFAULT partition would keep the same partition bound. HINT: Use CREATE TABLE ... PARTITION OF ... DEFAULT to add a DEFAULT = partition. ``` In this test, the split partition=E2=80=99s bound is ('a', 'b'), and the = new partition=E2=80=99s bound is ('a', 'A'). Their list lengths are both = 2, but the two bounds are actually different, because 'a' and 'A' are = considered equal by the collation. So, in the LIST path, since check_partition_bounds_for_split_list() has = already ensured that the new partition=E2=80=99s bound is contained = within the split partition=E2=80=99s bound, we need to check the reverse = direction as well. Whether the split partition=E2=80=99s bound is also = contained in the new partition=E2=80=99s bound. If yes, the two bounds = are identical. See the attached v4 for my changes for 0004. 0001-0003 are unchanged. = Since 0001 and 0003 are independent of 0004, maybe they can be pushed = first. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA Content-Disposition: attachment; filename=v4-0001-Fix-SPLIT-PARTITION-range-bound-validation-with-D.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v4-0001-Fix-SPLIT-PARTITION-range-bound-validation-with-D.patch" Content-Transfer-Encoding: quoted-printable =46rom=20cc401a3a77bc84e6e890ce4cef3e28ece8f284e0=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Alexander=20Korotkov=20= =0ADate:=20Mon,=2018=20May=202026=2000:36:23=20= +0300=0ASubject:=20[PATCH=20v4=201/4]=20Fix=20SPLIT=20PARTITION=20range=20= bound=20validation=20with=0A=20DEFAULT=0A=0AWhen=20splitting=20a=20range=20= partition=20and=20defining=20a=20new=20DEFAULT=20partition,=20the=0A= validation=20checked=20the=20lower=20bound=20of=20the=20first=20explicit=20= partition=20and=20the=0Aupper=20bound=20of=20explicit=20partitions=20= only=20when=20they=20were=20not=20first.=20=20If=20there=0Awas=20exactly=20= one=20explicit=20non-DEFAULT=20partition,=20its=20upper=20bound=20was=20= therefore=0Anot=20checked.=0A=0AThis=20could=20allow=20the=20replacement=20= partition=20to=20extend=20beyond=20the=20upper=20bound=0Aof=20the=20= partition=20being=20split,=20potentially=20overlapping=20another=20= existing=0Apartition.=0A=0AFix=20this=20by=20checking=20the=20upper=20= bound=20whenever=20the=20explicit=20partition=20is=20the=0Alast=20one.=20= =20Add=20a=20regression=20test=20covering=20the=20single=20explicit=20= partition=20plus=0ADEFAULT=20case.=0A=0AAuthor:=20Chao=20Li=20= =0AReviewed-by:=20Kirill=20Reshke=20= =0AReviewed-by:=20Zhenwei=20Shang=20= =0AReviewed-by:=20Dmitry=20Koval=20= =0AReviewed-by:=20Alexander=20Korotkov=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=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA Content-Disposition: attachment; filename=v4-0002-Fix-SPLIT-PARTITION-hint-for-DEFAULT-partition-bo.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v4-0002-Fix-SPLIT-PARTITION-hint-for-DEFAULT-partition-bo.patch" Content-Transfer-Encoding: quoted-printable =46rom=2057dea552776e487dc3a10858238e33ed2aa94700=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Alexander=20Korotkov=20= =0ADate:=20Mon,=2018=20May=202026=2000:36:44=20= +0300=0ASubject:=20[PATCH=20v4=202/4]=20Fix=20SPLIT=20PARTITION=20hint=20= for=20DEFAULT=20partition=20bounds=0A=0AWhen=20ALTER=20TABLE=20...=20= SPLIT=20PARTITION=20specifies=20a=20DEFAULT=20partition,=20the=0A= explicit=20partitions=20do=20not=20need=20to=20cover=20the=20split=20= partition's=20bound=0Aexactly.=20=20They=20may=20cover=20only=20part=20= of=20it,=20with=20the=20DEFAULT=20partition=0Acovering=20the=20remaining=20= range.=0A=0AHowever,=20the=20existing=20hint=20said=20that=20the=20= combined=20bounds=20of=20the=20new=0Apartitions=20must=20exactly=20match=20= the=20bound=20of=20the=20split=20partition,=20which=20is=0Amisleading=20= for=20this=20case=20and=20inconsistent=20with=20the=20code=20comment.=0A=0A= Fix=20the=20hint=20to=20state=20the=20actual=20requirement:=20explicit=20= partition=20bounds=0Amust=20stay=20within=20the=20bounds=20of=20the=20= split=20partition=20when=20a=20DEFAULT=0Apartition=20is=20specified.=0A=0A= Author:=20Chao=20Li=20=0AReviewed-by:=20Alexander=20= Korotkov=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= 14=20++++++--------=0A=20src/test/regress/expected/partition_split.out=20= |=2014=20+++++++-------=0A=202=20files=20changed,=2013=20insertions(+),=20= 15=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/partitioning/partbounds.c=20= b/src/backend/partitioning/partbounds.c=0Aindex=20= 73dea0375be..7d3580cbc10=20100644=0A---=20= a/src/backend/partitioning/partbounds.c=0A+++=20= b/src/backend/partitioning/partbounds.c=0A@@=20-5405,7=20+5405,7=20@@=20= check_partition_bounds_for_split_range(Relation=20parent,=0A=20=09=09=09=09= =09=09=09errmsg("lower=20bound=20of=20partition=20\"%s\"=20is=20not=20= equal=20to=20lower=20bound=20of=20split=20partition=20\"%s\"",=0A=20=09=09= =09=09=09=09=09=09=20=20=20relname,=0A=20=09=09=09=09=09=09=09=09=20=20=20= get_rel_name(splitPartOid)),=0A-=09=09=09=09=09=09=09errhint("%s=20= require=20combined=20bounds=20of=20new=20partitions=20must=20exactly=20= match=20the=20bound=20of=20the=20split=20partition.",=0A+=09=09=09=09=09=09= =09errhint("%s=20requires=20the=20combined=20bounds=20of=20the=20new=20= partitions=20to=20exactly=20match=20the=20bound=20of=20the=20split=20= partition.",=0A=20=09=09=09=09=09=09=09=09=09"ALTER=20TABLE=20...=20= SPLIT=20PARTITION"),=0A=20=09=09=09=09=09=09=09= parser_errposition(pstate,=20exprLocation((Node=20*)=20datum)));=0A=20=09= =09=09}=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-5448,7=20+5447,7=20@@=20= check_partition_bounds_for_split_range(Relation=20parent,=0A=20=09=09=09=09= =09=09=09errmsg("upper=20bound=20of=20partition=20\"%s\"=20is=20not=20= equal=20to=20upper=20bound=20of=20split=20partition=20\"%s\"",=0A=20=09=09= =09=09=09=09=09=09=20=20=20relname,=0A=20=09=09=09=09=09=09=09=09=20=20=20= get_rel_name(splitPartOid)),=0A-=09=09=09=09=09=09=09errhint("%s=20= require=20combined=20bounds=20of=20new=20partitions=20must=20exactly=20= match=20the=20bound=20of=20the=20split=20partition.",=0A+=09=09=09=09=09=09= =09errhint("%s=20requires=20the=20combined=20bounds=20of=20the=20new=20= partitions=20to=20exactly=20match=20the=20bound=20of=20the=20split=20= partition.",=0A=20=09=09=09=09=09=09=09=09=09"ALTER=20TABLE=20...=20= SPLIT=20PARTITION"),=0A=20=09=09=09=09=09=09=09= parser_errposition(pstate,=20exprLocation((Node=20*)=20datum)));=0A=20=09= =09=09}=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}=0A@@=20-5654,7=20+5652,7=20@@=20= check_parent_values_in_new_partitions(Relation=20parent,=0A=20=09=09=09=09= errmsg("new=20partitions'=20combined=20partition=20bounds=20do=20not=20= contain=20value=20(%s)=20but=20split=20partition=20\"%s\"=20does",=0A=20=09= =09=09=09=09=20=20=20"NULL",=0A=20=09=09=09=09=09=20=20=20= get_rel_name(partOid)),=0A-=09=09=09=09errhint("%s=20require=20combined=20= bounds=20of=20new=20partitions=20must=20exactly=20match=20the=20bound=20= of=20the=20split=20partition.",=0A+=09=09=09=09errhint("%s=20requires=20= the=20combined=20bounds=20of=20the=20new=20partitions=20to=20exactly=20= match=20the=20bound=20of=20the=20split=20partition.",=0A=20=09=09=09=09=09= =09"ALTER=20TABLE=20...=20SPLIT=20PARTITION"));=0A=20=0A=20=09/*=0A@@=20= -5697,7=20+5695,7=20@@=20check_parent_values_in_new_partitions(Relation=20= parent,=0A=20=09=09=09=09errmsg("new=20partitions'=20combined=20= partition=20bounds=20do=20not=20contain=20value=20(%s)=20but=20split=20= partition=20\"%s\"=20does",=0A=20=09=09=09=09=09=20=20=20= deparse_expression((Node=20*)=20notFoundVal,=20NIL,=20false,=20false),=0A= =20=09=09=09=09=09=20=20=20get_rel_name(partOid)),=0A-=09=09=09=09= errhint("%s=20require=20combined=20bounds=20of=20new=20partitions=20must=20= exactly=20match=20the=20bound=20of=20the=20split=20partition.",=0A+=09=09= =09=09errhint("%s=20requires=20the=20combined=20bounds=20of=20the=20new=20= partitions=20to=20exactly=20match=20the=20bound=20of=20the=20split=20= partition.",=0A=20=09=09=09=09=09=09"ALTER=20TABLE=20...=20SPLIT=20= PARTITION"));=0A=20=09}=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= a2ccbe5138b..2b9a6aa50ed=20100644=0A---=20= a/src/test/regress/expected/partition_split.out=0A+++=20= b/src/test/regress/expected/partition_split.out=0A@@=20-56,7=20+56,7=20= @@=20ALTER=20TABLE=20sales_range=20SPLIT=20PARTITION=20= sales_feb_mar_apr2022=20INTO=0A=20ERROR:=20=20lower=20bound=20of=20= partition=20"sales_feb2022"=20is=20not=20equal=20to=20lower=20bound=20of=20= split=20partition=20"sales_feb_mar_apr2022"=0A=20LINE=202:=20=20=20= (PARTITION=20sales_feb2022=20FOR=20VALUES=20FROM=20('2022-01-01')=20= TO...=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=20= PARTITION=20require=20combined=20bounds=20of=20new=20partitions=20must=20= exactly=20match=20the=20bound=20of=20the=20split=20partition.=0A+HINT:=20= =20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20requires=20the=20combined=20= bounds=20of=20the=20new=20partitions=20to=20exactly=20match=20the=20= bound=20of=20the=20split=20partition.=0A=20--=20ERROR=0A=20--=20(We=20= can=20create=20partition=20with=20the=20same=20name=20as=20split=20= partition,=20but=20can't=20create=20two=20partitions=20with=20the=20same=20= name)=0A=20ALTER=20TABLE=20sales_range=20SPLIT=20PARTITION=20= sales_feb_mar_apr2022=20INTO=0A@@=20-97,7=20+97,7=20@@=20ALTER=20TABLE=20= sales_range=20SPLIT=20PARTITION=20sales_feb_mar_apr2022=20INTO=0A=20= ERROR:=20=20upper=20bound=20of=20partition=20"sales_apr2022"=20is=20not=20= equal=20to=20upper=20bound=20of=20split=20partition=20= "sales_feb_mar_apr2022"=0A=20LINE=204:=20...=20sales_apr2022=20FOR=20= VALUES=20FROM=20('2022-04-01')=20TO=20('2022-06-0...=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=20=20= =20=20=20=20=20=20^=0A-HINT:=20=20ALTER=20TABLE=20...=20SPLIT=20= PARTITION=20require=20combined=20bounds=20of=20new=20partitions=20must=20= exactly=20match=20the=20bound=20of=20the=20split=20partition.=0A+HINT:=20= =20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20requires=20the=20combined=20= bounds=20of=20the=20new=20partitions=20to=20exactly=20match=20the=20= bound=20of=20the=20split=20partition.=0A=20--=20ERROR=0A=20ALTER=20TABLE=20= sales_range=20SPLIT=20PARTITION=20sales_feb_mar_apr2022=20INTO=0A=20=20=20= (PARTITION=20sales_feb2022=20FOR=20VALUES=20FROM=20('2022-02-01')=20TO=20= ('2022-03-01'),=0A@@=20-118,7=20+118,7=20@@=20ALTER=20TABLE=20= sales_range=20SPLIT=20PARTITION=20sales_feb_mar_apr2022=20INTO=0A=20= ERROR:=20=20lower=20bound=20of=20partition=20"sales_feb2022"=20is=20not=20= equal=20to=20lower=20bound=20of=20split=20partition=20= "sales_feb_mar_apr2022"=0A=20LINE=202:=20=20=20(PARTITION=20= sales_feb2022=20FOR=20VALUES=20FROM=20('2022-02-02')=20TO...=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+HINT:=20=20ALTER=20TABLE=20...=20= SPLIT=20PARTITION=20requires=20the=20combined=20bounds=20of=20the=20new=20= partitions=20to=20exactly=20match=20the=20bound=20of=20the=20split=20= partition.=0A=20--=20Check=20the=20source=20partition=20not=20in=20the=20= search=20path=0A=20SET=20search_path=20=3D=20partition_split_schema2,=20= public;=0A=20ALTER=20TABLE=20partition_split_schema.sales_range=0A@@=20= -154,7=20+154,7=20@@=20ALTER=20TABLE=20sales_range=20SPLIT=20PARTITION=20= sales_feb_mar_apr2022=20INTO=0A=20ERROR:=20=20upper=20bound=20of=20= partition=20"sales_apr2022"=20is=20not=20equal=20to=20upper=20bound=20of=20= split=20partition=20"sales_feb_mar_apr2022"=0A=20LINE=204:=20...=20= sales_apr2022=20FOR=20VALUES=20FROM=20('2022-04-01')=20TO=20= ('2022-06-0...=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=20=20=20=20=20=20=20=20^=0A-HINT:=20=20= ALTER=20TABLE=20...=20SPLIT=20PARTITION=20require=20combined=20bounds=20= of=20new=20partitions=20must=20exactly=20match=20the=20bound=20of=20the=20= split=20partition.=0A+HINT:=20=20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20= requires=20the=20combined=20bounds=20of=20the=20new=20partitions=20to=20= exactly=20match=20the=20bound=20of=20the=20split=20partition.=0A=20DROP=20= TABLE=20sales_range;=0A=20--=0A=20--=20Add=20rows=20into=20partitioned=20= table=20then=20split=20partition=0A@@=20-917,14=20+917,14=20@@=20ALTER=20= TABLE=20sales_list=20SPLIT=20PARTITION=20sales_all=20INTO=0A=20=20=20=20= PARTITION=20sales_east=20FOR=20VALUES=20IN=20('Beijing',=20'Delhi',=20= 'Vladivostok'),=0A=20=20=20=20PARTITION=20sales_central=20FOR=20VALUES=20= IN=20('Warsaw',=20'Berlin',=20'Kyiv'));=0A=20ERROR:=20=20new=20= partitions'=20combined=20partition=20bounds=20do=20not=20contain=20value=20= (NULL)=20but=20split=20partition=20"sales_all"=20does=0A-HINT:=20=20= ALTER=20TABLE=20...=20SPLIT=20PARTITION=20require=20combined=20bounds=20= of=20new=20partitions=20must=20exactly=20match=20the=20bound=20of=20the=20= split=20partition.=0A+HINT:=20=20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20= requires=20the=20combined=20bounds=20of=20the=20new=20partitions=20to=20= exactly=20match=20the=20bound=20of=20the=20split=20partition.=0A=20--=20= ERROR=0A=20ALTER=20TABLE=20sales_list=20SPLIT=20PARTITION=20sales_all=20= INTO=0A=20=20=20(PARTITION=20sales_west=20FOR=20VALUES=20IN=20('Lisbon',=20= 'New=20York',=20'Madrid'),=0A=20=20=20=20PARTITION=20sales_east=20FOR=20= VALUES=20IN=20('Beijing',=20'Delhi',=20'Vladivostok'),=0A=20=20=20=20= PARTITION=20sales_central=20FOR=20VALUES=20IN=20('Warsaw',=20'Berlin',=20= NULL));=0A=20ERROR:=20=20new=20partitions'=20combined=20partition=20= bounds=20do=20not=20contain=20value=20('Kyiv'::character=20varying(20))=20= but=20split=20partition=20"sales_all"=20does=0A-HINT:=20=20ALTER=20TABLE=20= ...=20SPLIT=20PARTITION=20require=20combined=20bounds=20of=20new=20= partitions=20must=20exactly=20match=20the=20bound=20of=20the=20split=20= partition.=0A+HINT:=20=20ALTER=20TABLE=20...=20SPLIT=20PARTITION=20= requires=20the=20combined=20bounds=20of=20the=20new=20partitions=20to=20= exactly=20match=20the=20bound=20of=20the=20split=20partition.=0A=20--=20= ERROR=0A=20ALTER=20TABLE=20sales_list=20SPLIT=20PARTITION=20sales_all=20= INTO=0A=20=20=20(PARTITION=20sales_west=20FOR=20VALUES=20IN=20('Lisbon',=20= 'New=20York',=20'Madrid'),=0A@@=20-1201,7=20+1201,7=20@@=20ALTER=20TABLE=20= t=20SPLIT=20PARTITION=20tp_0_51=20INTO=0A=20ERROR:=20=20upper=20bound=20= of=20partition=20"tp_0_51"=20is=20greater=20than=20upper=20bound=20of=20= split=20partition=20"tp_0_51"=0A=20LINE=202:=20=20=20(PARTITION=20= tp_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=20combined=20= bounds=20of=20new=20partitions=20must=20exactly=20match=20the=20bound=20= of=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=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA Content-Disposition: attachment; filename=v4-0003-Clarify-SPLIT-PARTITION-bound-requirements-in-doc.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v4-0003-Clarify-SPLIT-PARTITION-bound-requirements-in-doc.patch" Content-Transfer-Encoding: quoted-printable =46rom=204c1be7b104c4dc507384e7e63de8b491d6ae3f37=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Alexander=20Korotkov=20= =0ADate:=20Mon,=2018=20May=202026=2000:37:06=20= +0300=0ASubject:=20[PATCH=20v4=203/4]=20Clarify=20SPLIT=20PARTITION=20= bound=20requirements=20in=20docs=0A=0AThe=20documentation=20said=20that=20= the=20bounds=20of=20new=20partitions=20should=20not=0Aoverlap=20and=20= that=20their=20combined=20bounds=20should=20equal=20the=20bounds=20of=20= the=0Asplit=20partition.=20=20That=20is=20misleading=20when=20a=20new=20= DEFAULT=20partition=20is=0Aspecified,=20because=20the=20explicit=20= partitions=20may=20cover=20only=20part=20of=20the=0Asplit=20partition=20= while=20the=20DEFAULT=20partition=20covers=20the=20rest.=0A=0AClarify=20= that=20new=20non-DEFAULT=20partition=20bounds=20must=20not=20overlap=20= with=0Aother=20new=20or=20existing=20partitions=20and=20must=20be=20= contained=20within=20the=20bounds=0Aof=20the=20split=20partition.=20=20= Also=20state=20that=20the=20combined=20bounds=20must=20exactly=0Amatch=20= the=20split=20partition=20only=20when=20no=20new=20DEFAULT=20partition=20= is=20specified.=0A=0AWhile=20here,=20improve=20nearby=20wording=20about=20= hash-partitioned=20target=20tables=0Aand=20splitting=20a=20DEFAULT=20= partition=20with=20the=20same=20partition=20name.=0A=0AAuthor:=20Chao=20= Li=20=0AReviewed-by:=20Alexander=20Korotkov=20= =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=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA Content-Disposition: attachment; filename=v4-0004-Reject-degenerate-SPLIT-PARTITION-with-DEFAULT-pa.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v4-0004-Reject-degenerate-SPLIT-PARTITION-with-DEFAULT-pa.patch" Content-Transfer-Encoding: quoted-printable =46rom=203c033ade957420ffcc5fcac8f925a6c9a7a9f009=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Alexander=20Korotkov=20= =0ADate:=20Mon,=2018=20May=202026=2000:37:52=20= +0300=0ASubject:=20[PATCH=20v4=204/4]=20Reject=20degenerate=20SPLIT=20= PARTITION=20with=20DEFAULT=0A=20partition=0A=0AALTER=20TABLE=20...=20= SPLIT=20PARTITION=20allows=20a=20DEFAULT=20partition=20to=20be=20created=0A= as=20one=20of=20the=20replacement=20partitions=20when=20the=20parent=20= table=20does=20not=0Aalready=20have=20one.=20=20However,=20it=20should=20= not=20allow=20the=20degenerate=20case=20where=0Aa=20non-DEFAULT=20= partition=20keeps=20exactly=20the=20same=20bound=20as=20the=20split=0A= partition=20and=20the=20command=20merely=20adds=20a=20DEFAULT=20= partition=20through=20the=0ASPLIT=20PARTITION=20path.=0A=0ADetect=20that=20= case=20by=20comparing=20the=20bound=20of=20the=20split=20partition=20= with=20the=0Abound=20of=20the=20only=20non-DEFAULT=20replacement=20= partition,=20and=20raise=20an=20error=0Awhen=20they=20are=20the=20same.=20= =20Users=20should=20add=20a=20DEFAULT=20partition=20directly=0Awith=20= CREATE=20TABLE=20...=20PARTITION=20OF=20...=20DEFAULT=20or=20ALTER=20= TABLE=20...=20ATTACH=0APARTITION=20...=20DEFAULT=20instead.=0A=0AAuthor:=20= Chao=20Li=20=0AReviewed-by:=20Alexander=20Korotkov=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= 145=20++++++++++++++++++=0A=20= src/test/regress/expected/partition_split.out=20|=20=2059=20+++++++=0A=20= src/test/regress/sql/partition_split.sql=20=20=20=20=20=20|=20=2052=20= +++++++=0A=203=20files=20changed,=20256=20insertions(+)=0A=0Adiff=20= --git=20a/src/backend/partitioning/partbounds.c=20= b/src/backend/partitioning/partbounds.c=0Aindex=20= 7d3580cbc10..126a9be15ba=20100644=0A---=20= a/src/backend/partitioning/partbounds.c=0A+++=20= b/src/backend/partitioning/partbounds.c=0A@@=20-5700,6=20+5700,141=20@@=20= check_parent_values_in_new_partitions(Relation=20parent,=0A=20=09}=0A=20= }=0A=20=0A+/*=0A+=20*=20split_partition_values_contained_in_new_part=0A+=20= *=0A+=20*=20(function=20for=20BY=20LIST=20partitioning)=0A+=20*=0A+=20*=20= Returns=20true=20if=20all=20values=20in=20the=20LIST=20bound=20of=20the=20= partition=20being=20split=0A+=20*=20are=20contained=20in=20the=20= specified=20non-DEFAULT=20replacement=20partition's=20bound.=0A+=20*=0A+=20= *=20The=20caller=20must=20already=20have=20verified=20containment=20in=20= the=20other=20direction,=0A+=20*=20so=20this=20check=20is=20sufficient=20= to=20prove=20that=20the=20two=20LIST=20bounds=20are=20equal.=0A+=20*/=0A= +static=20bool=0A+split_partition_values_contained_in_new_part(Relation=20= parent,=0A+=09=09=09=09=09=09=09=09=09=09=09=20Oid=20splitPartOid,=0A+=09= =09=09=09=09=09=09=09=09=09=09=20SinglePartitionSpec=20*part)=0A+{=0A+=09= PartitionKey=20key=20=3D=20RelationGetPartitionKey(parent);=0A+=09= PartitionDesc=20partdesc=20=3D=20RelationGetPartitionDesc(parent,=20= false);=0A+=09PartitionBoundInfo=20boundinfo=20=3D=20= partdesc->boundinfo;=0A+=09SinglePartitionSpec=20*parts[1];=0A+=09Datum=09= =09datum=20=3D=20PointerGetDatum(NULL);=0A+=0A+=09Assert(key->strategy=20= =3D=3D=20PARTITION_STRATEGY_LIST);=0A+=0A+=09parts[0]=20=3D=20part;=0A+=0A= +=09/*=0A+=09=20*=20Special=20processing=20for=20NULL=20value.=20=20= Search=20for=20a=20NULL=20value=20if=20the=0A+=09=20*=20split=20= partition=20contains=20it.=0A+=09=20*/=0A+=09if=20= (partition_bound_accepts_nulls(boundinfo)=20&&=0A+=09=09= partdesc->oids[boundinfo->null_index]=20=3D=3D=20splitPartOid)=0A+=09{=0A= +=09=09if=20(!find_value_in_new_partitions_list(&key->partsupfunc[0],=0A= +=09=09=09=09=09=09=09=09=09=09=09=20=20=20key->partcollation,=20parts,=20= 1,=0A+=09=09=09=09=09=09=09=09=09=09=09=20=20=20datum,=20true))=0A+=09=09= =09return=20false;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Search=20all=20= values=20of=20the=20split=20partition=20in=20the=20single=20non-DEFAULT=0A= +=09=20*=20replacement=20partition.=0A+=09=20*/=0A+=09for=20(int=20i=20=3D= =200;=20i=20<=20boundinfo->ndatums;=20i++)=0A+=09{=0A+=09=09if=20= (partdesc->oids[boundinfo->indexes[i]]=20=3D=3D=20splitPartOid)=0A+=09=09= {=0A+=09=09=09datum=20=3D=20boundinfo->datums[i][0];=0A+=0A+=09=09=09if=20= (!find_value_in_new_partitions_list(&key->partsupfunc[0],=0A+=09=09=09=09= =09=09=09=09=09=09=09=09=20=20=20key->partcollation,=20parts,=201,=0A+=09= =09=09=09=09=09=09=09=09=09=09=09=20=20=20datum,=20false))=0A+=09=09=09=09= return=20false;=0A+=09=09}=0A+=09}=0A+=0A+=09return=20true;=0A+}=0A+=0A= +/*=0A+=20*=20check_split_partition_not_same_bound=0A+=20*=0A+=20*=20= Reject=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+=20*=20Must=20be=20called=20after=20= the=20per-partition=20bound=20validation=20in=0A+=20*=20= check_partitions_for_split()=20so=20that=20containment=20of=20new=20= bounds=20within=20the=0A+=20*=20split=20partition=20is=20already=20= established.=20=20Given=20containment,=20RANGE=20bounds=0A+=20*=20are=20= equal=20iff=20their=20lower=20and=20upper=20rbounds=20match;=20LIST=20= bound=20sets=20are=0A+=20*=20equal=20iff=20the=20split=20partition's=20= values=20are=20also=20contained=20in=20the=20new=0A+=20*=20partition.=0A= +=20*/=0A+static=20void=0A+check_split_partition_not_same_bound(Relation=20= parent,=0A+=09=09=09=09=09=09=09=09=09=20Oid=20splitPartOid,=0A+=09=09=09= =09=09=09=09=09=09=20SinglePartitionSpec=20**parts,=0A+=09=09=09=09=09=09= =09=09=09=20int=20nparts,=0A+=09=09=09=09=09=09=09=09=09=20ParseState=20= *pstate)=0A+{=0A+=09PartitionKey=20key=20=3D=20= RelationGetPartitionKey(parent);=0A+=09PartitionBoundSpec=20*new_spec;=0A= +=09PartitionBoundSpec=20*split_spec;=0A+=0A+=09if=20(nparts=20!=3D=201)=0A= +=09=09return;=0A+=0A+=09new_spec=20=3D=20parts[0]->bound;=0A+=09= split_spec=20=3D=20get_partition_bound_spec(splitPartOid);=0A+=0A+=09= Assert(new_spec->strategy=20=3D=3D=20split_spec->strategy);=0A+=0A+=09if=20= (key->strategy=20=3D=3D=20PARTITION_STRATEGY_RANGE)=0A+=09{=0A+=09=09= PartitionRangeBound=20*new_lower;=0A+=09=09PartitionRangeBound=20= *new_upper;=0A+=09=09PartitionRangeBound=20*split_lower;=0A+=09=09= PartitionRangeBound=20*split_upper;=0A+=0A+=09=09new_lower=20=3D=20= make_one_partition_rbound(key,=20-1,=20new_spec->lowerdatums,=20true);=0A= +=09=09new_upper=20=3D=20make_one_partition_rbound(key,=20-1,=20= new_spec->upperdatums,=20false);=0A+=09=09split_lower=20=3D=20= make_one_partition_rbound(key,=20-1,=20split_spec->lowerdatums,=20true);=0A= +=09=09split_upper=20=3D=20make_one_partition_rbound(key,=20-1,=20= split_spec->upperdatums,=20false);=0A+=0A+=09=09if=20= (partition_rbound_cmp(key->partnatts,=20key->partsupfunc,=0A+=09=09=09=09= =09=09=09=09=20key->partcollation,=0A+=09=09=09=09=09=09=09=09=20= new_lower->datums,=20new_lower->kind,=20true,=0A+=09=09=09=09=09=09=09=09= =20split_lower)=20!=3D=200)=0A+=09=09=09return;=0A+=09=09if=20= (partition_rbound_cmp(key->partnatts,=20key->partsupfunc,=0A+=09=09=09=09= =09=09=09=09=20key->partcollation,=0A+=09=09=09=09=09=09=09=09=20= new_upper->datums,=20new_upper->kind,=20false,=0A+=09=09=09=09=09=09=09=09= =20split_upper)=20!=3D=200)=0A+=09=09=09return;=0A+=09}=0A+=09else=0A+=09= {=0A+=09=09Assert(key->strategy=20=3D=3D=20PARTITION_STRATEGY_LIST);=0A+=0A= +=09=09if=20(!split_partition_values_contained_in_new_part(parent,=20= splitPartOid,=20parts[0]))=0A+=09=09=09return;=0A+=09}=0A+=0A+=09= ereport(ERROR,=0A+=09=09=09errcode(ERRCODE_INVALID_OBJECT_DEFINITION),=0A= +=09=09=09errmsg("cannot=20split=20partition=20\"%s\"=20only=20to=20add=20= a=20DEFAULT=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-5871,5=20= +6006,15=20@@=20check_partitions_for_split(Relation=20parent,=0A=20=09=09= =09=09=09=09=09=09=09=09=09=09=20=20new_parts,=20nparts,=20pstate);=0A=20= =09}=0A=20=0A+=09/*=0A+=09=20*=20Reject=20the=20degenerate=20form=20= where=20the=20single=20non-DEFAULT=20replacement=0A+=09=20*=20partition=20= keeps=20the=20bound=20of=20the=20split=20partition;=20the=20command=20= then=20does=0A+=09=20*=20nothing=20beyond=20adding=20a=20DEFAULT=20= partition.=20=20Containment=20was=20established=0A+=09=20*=20by=20the=20= per-partition=20validation=20above,=20so=20an=20equality=20check=20is=20= enough.=0A+=09=20*/=0A+=09if=20(!isSplitPartDefault=20&&=20= createDefaultPart)=0A+=09=09check_split_partition_not_same_bound(parent,=20= splitPartOid,=20new_parts,=0A+=09=09=09=09=09=09=09=09=09=09=09=20= nparts,=20pstate);=0A+=0A=20=09pfree(new_parts);=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= 2b9a6aa50ed..2fd9aee1dcc=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,65=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= Test=20that=20a=20LIST=20split=20with=20DEFAULT=20is=20not=20considered=20= degenerate=20when=0A+--=20only=20NULL=20is=20removed=20from=20the=20= explicit=20replacement=20partition.=0A+--=0A+CREATE=20TABLE=20t=20(i=20= int)=20PARTITION=20BY=20LIST=20(i);=0A+CREATE=20TABLE=20tp_null_1=20= PARTITION=20OF=20t=20FOR=20VALUES=20IN=20(NULL,=201);=0A+ALTER=20TABLE=20= t=20SPLIT=20PARTITION=20tp_null_1=20INTO=0A+=20=20(PARTITION=20tp_1=20= FOR=20VALUES=20IN=20(1),=0A+=20=20=20PARTITION=20tp_default=20DEFAULT);=0A= +INSERT=20INTO=20t=20VALUES=20(NULL),=20(1),=20(2);=0A+SELECT=20= tableoid::regclass,=20i=20FROM=20t=20ORDER=20BY=20= tableoid::regclass::text=20COLLATE=20"C",=20i=20NULLS=20FIRST;=0A+=20=20= tableoid=20=20|=20i=20=0A+------------+---=0A+=20tp_1=20=20=20=20=20=20=20= |=201=0A+=20tp_default=20|=20=20=0A+=20tp_default=20|=202=0A+(3=20rows)=0A= +=0A+DROP=20TABLE=20t;=0A+--=0A+--=20Test=20that=20the=20same-bound=20= check=20for=20LIST=20partitioning=20uses=20partition=0A+--=20comparison=20= semantics,=20not=20raw=20list=20length.=20=20The=20case-insensitive=20= collation=0A+--=20treats=20'a'=20and=20'A'=20as=20equal,=20so=20the=20= non-DEFAULT=20replacement=20partition=0A+--=20covers=20only=20the=20'a'=20= group=20and=20the=20DEFAULT=20partition=20covers=20the=20rest.=0A+--=0A= +CREATE=20COLLATION=20case_insensitive=20(provider=20=3D=20icu,=20locale=20= =3D=20'und-u-ks-level2',=20deterministic=20=3D=20false);=0A+CREATE=20= TABLE=20t=20(b=20text=20COLLATE=20case_insensitive)=20PARTITION=20BY=20= LIST=20(b);=0A+CREATE=20TABLE=20tp_ab=20PARTITION=20OF=20t=20FOR=20= VALUES=20IN=20('a',=20'b');=0A+ALTER=20TABLE=20t=20SPLIT=20PARTITION=20= tp_ab=20INTO=0A+=20=20(PARTITION=20tp_a=20FOR=20VALUES=20IN=20('a',=20= 'A'),=0A+=20=20=20PARTITION=20tp_default=20DEFAULT);=0A+INSERT=20INTO=20= t=20VALUES=20('a'),=20('A'),=20('b'),=20('c');=0A+SELECT=20= tableoid::regclass,=20count(*)=20FROM=20t=20GROUP=20BY=201=20ORDER=20BY=20= 1;=0A+=20=20tableoid=20=20|=20count=20=0A+------------+-------=0A+=20= tp_a=20=20=20=20=20=20=20|=20=20=20=20=202=0A+=20tp_default=20|=20=20=20=20= =202=0A+(2=20rows)=0A+=0A+DROP=20TABLE=20t;=0A+DROP=20COLLATION=20= case_insensitive;=0A+--=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--=0Adiff=20--git=20a/src/test/regress/sql/partition_split.sql=20= b/src/test/regress/sql/partition_split.sql=0Aindex=20= d9821c5e2a3..ede89ad0228=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,58=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+--=0A+--=20Test=20that=20a=20LIST=20split=20with=20= DEFAULT=20is=20not=20considered=20degenerate=20when=0A+--=20only=20NULL=20= is=20removed=20from=20the=20explicit=20replacement=20partition.=0A+--=0A= +CREATE=20TABLE=20t=20(i=20int)=20PARTITION=20BY=20LIST=20(i);=0A+CREATE=20= TABLE=20tp_null_1=20PARTITION=20OF=20t=20FOR=20VALUES=20IN=20(NULL,=20= 1);=0A+=0A+ALTER=20TABLE=20t=20SPLIT=20PARTITION=20tp_null_1=20INTO=0A+=20= =20(PARTITION=20tp_1=20FOR=20VALUES=20IN=20(1),=0A+=20=20=20PARTITION=20= tp_default=20DEFAULT);=0A+=0A+INSERT=20INTO=20t=20VALUES=20(NULL),=20= (1),=20(2);=0A+SELECT=20tableoid::regclass,=20i=20FROM=20t=20ORDER=20BY=20= tableoid::regclass::text=20COLLATE=20"C",=20i=20NULLS=20FIRST;=0A+=0A= +DROP=20TABLE=20t;=0A+=0A+--=0A+--=20Test=20that=20the=20same-bound=20= check=20for=20LIST=20partitioning=20uses=20partition=0A+--=20comparison=20= semantics,=20not=20raw=20list=20length.=20=20The=20case-insensitive=20= collation=0A+--=20treats=20'a'=20and=20'A'=20as=20equal,=20so=20the=20= non-DEFAULT=20replacement=20partition=0A+--=20covers=20only=20the=20'a'=20= group=20and=20the=20DEFAULT=20partition=20covers=20the=20rest.=0A+--=0A= +CREATE=20COLLATION=20case_insensitive=20(provider=20=3D=20icu,=20locale=20= =3D=20'und-u-ks-level2',=20deterministic=20=3D=20false);=0A+CREATE=20= TABLE=20t=20(b=20text=20COLLATE=20case_insensitive)=20PARTITION=20BY=20= LIST=20(b);=0A+CREATE=20TABLE=20tp_ab=20PARTITION=20OF=20t=20FOR=20= VALUES=20IN=20('a',=20'b');=0A+=0A+ALTER=20TABLE=20t=20SPLIT=20PARTITION=20= tp_ab=20INTO=0A+=20=20(PARTITION=20tp_a=20FOR=20VALUES=20IN=20('a',=20= 'A'),=0A+=20=20=20PARTITION=20tp_default=20DEFAULT);=0A+=0A+INSERT=20= INTO=20t=20VALUES=20('a'),=20('A'),=20('b'),=20('c');=0A+SELECT=20= tableoid::regclass,=20count(*)=20FROM=20t=20GROUP=20BY=201=20ORDER=20BY=20= 1;=0A+=0A+DROP=20TABLE=20t;=0A+DROP=20COLLATION=20case_insensitive;=0A+=0A= =20--=0A=20--=20Test=20that=20the=20explicit=20partition=20bound=20= cannot=20extend=20outside=20the=20split=0A=20--=20partition's=20bound=20= when=20a=20DEFAULT=20partition=20is=20specified.=0A--=20=0A2.50.1=20= (Apple=20Git-155)=0A=0A= --Apple-Mail=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii --Apple-Mail=_DC0AF63F-13F3-41B4-AEF6-B138C8B9CCDA--