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 1wW3oQ-002Mbq-0b for pgsql-hackers@arkaria.postgresql.org; Sun, 07 Jun 2026 03:04:34 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wW3oN-00GqTS-01 for pgsql-hackers@arkaria.postgresql.org; Sun, 07 Jun 2026 03:04:31 +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 1wW3oM-00GqTK-0s for pgsql-hackers@lists.postgresql.org; Sun, 07 Jun 2026 03:04:30 +0000 Received: from mail-pl1-x62c.google.com ([2607:f8b0:4864:20::62c]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wW3oK-00000001Ts1-0sqy for pgsql-hackers@lists.postgresql.org; Sun, 07 Jun 2026 03:04:29 +0000 Received: by mail-pl1-x62c.google.com with SMTP id d9443c01a7336-2bea7176c72so20530995ad.0 for ; Sat, 06 Jun 2026 20:04:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780801467; x=1781406267; darn=lists.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=2ox/0t9hsfX46LtQP/gke52vkS7UHjAe3j88fOl6cGU=; b=S+PsGsvE61oXnuqdIcpOkem1ONJOQDXWiDurupSQhblh6bUEQK6QkWrBKEaiEBaEgB cRhsDqU6dKiD1XOOmNabLCy3JRI2DglTCz3lVn44yi1FvyXDO2B55n9IlVX/Y5gvvPIC XP3KOSmnuQL0+K0zpWq4tneWm91O+wwC8gIueVHHIxH1NkJCSkCGXOGa35986GEqed7O vbQXKs/i+O+Mw42CyoxM/UKkv/8kuDPcI7VuX/bCxiXW0PLRLabDVlJBYa0vjXO4uWV7 kLpqNJVAvJqcYP939LyHIpou17rBoqcpqweIl+v/yHldVWZv1cgzjyGHdx4uvhi93nf8 tPYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780801467; x=1781406267; 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=2ox/0t9hsfX46LtQP/gke52vkS7UHjAe3j88fOl6cGU=; b=BCTPQEM7pM5uztMqsyRwLTYUqkH58kmaDIGXLEUZqeMljALmwa5qspQhLkp8e2o8Ze 26KPIeV/z8H569iMhi02+W1t8Cz56PHaXCFyyq3bwljW3IT4X8/ADHg2vlkew3P3XwKs eHItyPpf69BD1KDBGuOwO+L0ekdCxU7rkhfQFZ0tpB0+qP5geFgp8RlpedndhyaUX8tp S53LnXgGUEGk4cfBEQXeQ/FiUI22J2oL5+lYEn4PLYbxkkSXLrRIKBqiMBJtDQ9Ssmwa 3INT2c102DafI5r0jTq+IFIhS5zy0ZY05nOUMcPNted4j4zxCuo2zPik8xnEQRNhuy70 GqvQ== X-Gm-Message-State: AOJu0Ywh/g0lq+m88F6aW1dezxfEoE3+R2bx4Y50nJRCvsrBHRshjcql yUBDXqq+XaCvPIDR8Ct9vNk/CfVw6xD/5PjfNoQjxpZpEK5pfu6f6Bet X-Gm-Gg: Acq92OFIw1w3CqxI6tOh5EZprgJGpV/WnNA3qXYMQLoEoflwwSs1IcIJn4c+4u803xf 5rzsASf3ZROedOO7Ijjy0Ggj27n8317kiFhsA2Tyy1xlfMo2YF+cjQilT5h9Fe5CvQcVmDbJYOV uDNfoStOGHEpSN/XF3OvTDJjtRWuM3AREfTjzWPftXwkZJPyAwPWfsnAM/88i5RDV759PbXYq/C IpKc81E4EeNA6IkE44GwMgAncfiY0mRlNJX/L0PUNc0U8YJrUiDZ0b/qlpVzx5cyINChd/3AuRf ptnapT/Mt+wUkDJDHaLhhwXOi6jCimY78EdoZ0ExXJIciNTW1z3iRPAUa5Urvgd41oNUgGsqpfF cvMThx4pJGk81rfHIe8zRlEuULnC0DpiPz+ILxSAkZ3yIOti71KSwakVkd+chOofNTUXWLm95BM PeGElLsssMauK51nh3a65HL6aXOSFxODsDlkJapPNnTA== X-Received: by 2002:a17:903:248:b0:2bf:27b2:4b80 with SMTP id d9443c01a7336-2c1e7b457femr117152255ad.14.1780801467163; Sat, 06 Jun 2026 20:04:27 -0700 (PDT) Received: from smtpclient.apple ([45.32.121.103]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2c16629d240sm144659755ad.58.2026.06.06.20.04.24 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 06 Jun 2026 20:04:26 -0700 (PDT) From: Chao Li Message-Id: <2E50622C-7714-49D9-89F7-0E3334D4433D@gmail.com> Content-Type: multipart/mixed; boundary="Apple-Mail=_EB393630-045F-4C10-B588-BB5DDAE5E5AC" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: Fix bug of UPDATE/DELETE FOR PORTION OF with inheritance tables Date: Sun, 7 Jun 2026 11:03:49 +0800 In-Reply-To: <5E0A0FF4-3E57-415E-A1C7-F1184F1EDC32@gmail.com> Cc: PostgreSQL Hackers , jian he , Peter Eisentraut To: Paul A Jungwirth References: <4245F94D-84F1-4E05-BF81-C458A6CF9901@gmail.com> <260A544F-FBD6-40CC-9449-5987049DD2D4@gmail.com> <5E0A0FF4-3E57-415E-A1C7-F1184F1EDC32@gmail.com> X-Mailer: Apple Mail (2.3864.600.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_EB393630-045F-4C10-B588-BB5DDAE5E5AC Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On May 27, 2026, at 15:55, Chao Li wrote: >=20 >=20 >=20 >> On May 27, 2026, at 09:28, Paul A Jungwirth = wrote: >>=20 >> On Tue, May 26, 2026 at 9:14=E2=80=AFAM Paul A Jungwirth >> wrote: >>>=20 >>> I thought the ExecInitForPortionOf refactoring was still nice to = keep, >>> and it seemed to fit better here. (I should have updated the commit >>> message not to mention UPDATE OF though.) >>=20 >> I looked at the original v1 patch again. I thought the commit message >> was excellent, so I pulled that into the latest patch, also some >> comment changes and the partitionRouting boolean and some test >> double-checks. I still like how ExecInitForPortionOf cuts down on the >> branchiness and the variables used to track attnums, and also how it >> gathers a lot of the child table setup in one place. The v1 seemed >> hard to trace all the cases from top to bottom. For instance it >> initialized map for all child tables, but then only used it for >> partitions. >>=20 >>> But thinking about it this morning, I realized: the planner already >>> prunes partitions before we get here. Lazily initializing the = structs >>> is trying too hard. Is there some scenario where that actually saves >>> work? >>=20 >> Never mind, of course you can filter rows (and whole tables) besides >> just by partition pruning/constraint exclusion. >>=20 >> I'm not sure whom to list as author/co-author/reviewer for this = patch, >> but I took a stab at it. I think most of the current code is from = jian >> he's version, but all three of us have contributed a lot by this >> point. >>=20 >> Yours, >>=20 >> --=20 >> Paul ~{:-) >> pj@illuminatedcomputing.com >=20 > Hi Paul, >=20 > I just tested v3 with my original repro, and it has resolved the bug I = reported. > ``` > evantest=3D# create table p (id int, valid_at daterange, name text); > CREATE TABLE > evantest=3D# create table c (extra text) inherits (p); > CREATE TABLE > evantest=3D# insert into c values (1, daterange('2000-01-01', = '2010-01-01'), 'old', 'x'); > INSERT 0 1 > evantest=3D# update p for portion of valid_at from '2001-01-01' to = '2002-01-01' set name =3D 'new' where id =3D 1; > UPDATE 1 > evantest=3D# select * from only p; > id | valid_at | name > ----+----------+------ > (0 rows) > evantest=3D# select * from c; > id | valid_at | name | extra > ----+-------------------------+------+------- > 1 | [2001-01-01,2002-01-01) | new | x > 1 | [2000-01-01,2001-01-01) | old | x > 1 | [2002-01-01,2010-01-01) | old | x > (3 rows) > ``` >=20 > I also noticed that the =E2=80=9CUPDATE OF=E2=80=9D related = information has been removed from the commit message. I can still = reproduce the UPDATE OF issue with v3, but I think that is expected, and = that issue will be resolved by the other patch. >=20 > So v3 looks clean and good to me. Thanks for updating the patch and = making the two patches decoupled. >=20 > Best regards, > -- > Chao Li (Evan) > HighGo Software Co., Ltd. > https://www.highgo.com/ Rebased as requested by the CF. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_EB393630-045F-4C10-B588-BB5DDAE5E5AC Content-Disposition: attachment; filename=v4-0001-Fix-FOR-PORTION-OF-for-inheritance-children.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v4-0001-Fix-FOR-PORTION-OF-for-inheritance-children.patch" Content-Transfer-Encoding: quoted-printable =46rom=208c2ef9deb464796976ac42b2fb2abc8127f4a3b2=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Paul=20A.=20Jungwirth"=20= =0ADate:=20Mon,=2025=20May=202026=20= 15:44:33=20-0700=0ASubject:=20[PATCH=20v4]=20Fix=20FOR=20PORTION=20OF=20= for=20inheritance=20children=0A=0AExecForPortionOfLeftovers()=20assumed=20= that=20any=20result=20relation=20with=0Ari_RootResultRelInfo=20should=20= reinsert=20temporal=20leftovers=20through=20the=20root=0Arelation.=20=20= That=20is=20correct=20for=20partitioned=20tables,=20where=20tuple=20= routing=20is=0Aneeded,=20but=20it=20is=20wrong=20for=20plain=20= inheritance.=0A=0AWhen=20UPDATE/DELETE=20FOR=20PORTION=20OF=20is=20run=20= on=20an=20inheritance=20parent=20and=20a=0Achild=20row=20is=20split,=20= the=20leftover=20rows=20must=20be=20inserted=20back=20into=20the=20child=0A= relation.=20=20Reinserting=20through=20the=20parent=20can=20lose=20= child-only=20columns=20and=0Aplace=20the=20leftover=20rows=20in=20the=20= wrong=20relation.=0A=0AFix=20this=20by=20distinguishing=20= partitioned-table=20routing=20from=20plain=0Ainheritance.=20=20For=20= partitioned=20tables,=20keep=20using=20the=20root=20leftover=20slot=20= and=0Ainsert=20through=20the=20root=20relation.=20=20For=20plain=20= inheritance=20children,=20use=20a=0Aleftover=20slot=20matching=20the=20= child=20relation=20and=20insert=20directly=20into=20the=0Achild.=20=20= Also=20keep=20translating=20the=20application-time=20column=20attno=20= for=20child=0Arelations,=20so=20multiple-inheritance=20cases=20with=20= different=20attribute=20numbers=0Aare=20handled=20correctly.=0A=0AAdded=20= an=20ExecInitForPortionOf=20function=20to=20set=20up=20the=20= ForPortionOfState=20for=20each=0Achild=20table,=20which=20keeps=20most=20= of=20these=20decisions=20localized=20instead=20of=20spread=0Aout=20= through=20ExecForPortionOfLeftovers.=20=20Incidentally=20clarified=20a=20= comment=20about=0Athe=20rangetype=20stored=20in=20ForPortionOfState.=0A=0A= Add=20regression=20tests=20for=20UPDATE=20and=20DELETE=20FOR=20PORTION=20= OF=20on=20inheritance=0Achildren,=20including=20a=20multiple-inheritance=20= case=20where=20the=20range=20column=20has=0Aa=20different=20attnum=20in=20= the=20parent=20and=20child.=0A=0AAuthor:=20jian=20he=20= =0ACo-authored-by:=20Chao=20Li=20= =0AReviewed-by:=20Paul=20A.=20Jungwirth=20= =0ADiscussion:=20= https://www.postgresql.org/message-id/4245F94D-84F1-4E05-BF81-C458A6CF9901= @gmail.com=0A---=0A=20src/backend/executor/nodeModifyTable.c=20=20=20=20=20= =20=20|=20158=20+++++++++++++------=0A=20src/include/nodes/execnodes.h=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=203=20+-=0A=20= src/test/regress/expected/for_portion_of.out=20|=20158=20= +++++++++++++++++++=0A=20src/test/regress/sql/for_portion_of.sql=20=20=20= =20=20=20|=20=2085=20++++++++++=0A=204=20files=20changed,=20353=20= insertions(+),=2051=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/executor/nodeModifyTable.c=20= b/src/backend/executor/nodeModifyTable.c=0Aindex=20= 0344fc76371..33a6735f08d=20100644=0A---=20= a/src/backend/executor/nodeModifyTable.c=0A+++=20= b/src/backend/executor/nodeModifyTable.c=0A@@=20-199,6=20+199,8=20@@=20= static=20TupleTableSlot=20*ExecMergeNotMatched(ModifyTableContext=20= *context,=0A=20static=20void=20= ExecSetupTransitionCaptureState(ModifyTableState=20*mtstate,=20EState=20= *estate);=0A=20static=20void=20fireBSTriggers(ModifyTableState=20*node);=0A= =20static=20void=20fireASTriggers(ModifyTableState=20*node);=0A+static=20= void=20ExecInitForPortionOf(ModifyTableState=20*mtstate,=20EState=20= *estate,=0A+=09=09=09=09=09=09=09=09=20ResultRelInfo=20*resultRelInfo);=0A= =20=0A=20=0A=20/*=0A@@=20-1410,7=20+1412,6=20@@=20= ExecForPortionOfLeftovers(ModifyTableContext=20*context,=0A=20=09= ModifyTableState=20*mtstate=20=3D=20context->mtstate;=0A=20=09= ModifyTable=20*node=20=3D=20(ModifyTable=20*)=20mtstate->ps.plan;=0A=20=09= ForPortionOfExpr=20*forPortionOf=20=3D=20(ForPortionOfExpr=20*)=20= node->forPortionOf;=0A-=09AttrNumber=09rangeAttno;=0A=20=09Datum=09=09= oldRange;=0A=20=09TypeCacheEntry=20*typcache;=0A=20=09ForPortionOfState=20= *fpoState;=0A@@=20-1425,37=20+1426,13=20@@=20= ExecForPortionOfLeftovers(ModifyTableContext=20*context,=0A=20=09= ReturnSetInfo=20rsi;=0A=20=09bool=09=09didInit=20=3D=20false;=0A=20=09= bool=09=09shouldFree=20=3D=20false;=0A+=09ResultRelInfo=20*rootRelInfo=20= =3D=20mtstate->rootResultRelInfo;=0A+=09bool=09=09partitionRouting=20=3D=0A= +=09=09rootRelInfo=20&&=0A+=09=09= rootRelInfo->ri_RelationDesc->rd_rel->relkind=20=3D=3D=20= RELKIND_PARTITIONED_TABLE;=0A=20=0A=20=09LOCAL_FCINFO(fcinfo,=202);=0A=20= =0A-=09if=20(!resultRelInfo->ri_forPortionOf)=0A-=09{=0A-=09=09/*=0A-=09=09= =20*=20If=20we=20don't=20have=20a=20ForPortionOfState=20yet,=20we=20must=20= be=20a=20partition=0A-=09=09=20*=20child=20being=20hit=20for=20the=20= first=20time.=20Make=20a=20copy=20from=20the=20root,=20with=0A-=09=09=20= *=20our=20own=20TupleTableSlot.=20We=20do=20this=20lazily=20so=20that=20= we=20don't=20pay=20the=0A-=09=09=20*=20price=20of=20unused=20partitions.=0A= -=09=09=20*/=0A-=09=09ForPortionOfState=20*leafState=20=3D=20= makeNode(ForPortionOfState);=0A-=0A-=09=09if=20= (!mtstate->rootResultRelInfo)=0A-=09=09=09elog(ERROR,=20"no=20root=20= relation=20but=20ri_forPortionOf=20is=20uninitialized");=0A-=0A-=09=09= fpoState=20=3D=20mtstate->rootResultRelInfo->ri_forPortionOf;=0A-=09=09= Assert(fpoState);=0A-=0A-=09=09leafState->fp_rangeName=20=3D=20= fpoState->fp_rangeName;=0A-=09=09leafState->fp_rangeType=20=3D=20= fpoState->fp_rangeType;=0A-=09=09leafState->fp_rangeAttno=20=3D=20= fpoState->fp_rangeAttno;=0A-=09=09leafState->fp_targetRange=20=3D=20= fpoState->fp_targetRange;=0A-=09=09leafState->fp_Leftover=20=3D=20= fpoState->fp_Leftover;=0A-=09=09/*=20Each=20partition=20needs=20a=20slot=20= matching=20its=20tuple=20descriptor=20*/=0A-=09=09leafState->fp_Existing=20= =3D=0A-=09=09=09table_slot_create(resultRelInfo->ri_RelationDesc,=0A-=09=09= =09=09=09=09=09=20=20&mtstate->ps.state->es_tupleTable);=0A-=0A-=09=09= resultRelInfo->ri_forPortionOf=20=3D=20leafState;=0A-=09}=0A=20=09= fpoState=20=3D=20resultRelInfo->ri_forPortionOf;=0A=20=09oldtupleSlot=20= =3D=20fpoState->fp_Existing;=0A=20=09leftoverSlot=20=3D=20= fpoState->fp_Leftover;=0A@@=20-1476,21=20+1453,12=20@@=20= ExecForPortionOfLeftovers(ModifyTableContext=20*context,=0A=20=09if=20= (!table_tuple_fetch_row_version(resultRelInfo->ri_RelationDesc,=20= tupleid,=20SnapshotAny,=20oldtupleSlot))=0A=20=09=09elog(ERROR,=20= "failed=20to=20fetch=20tuple=20for=20FOR=20PORTION=20OF");=0A=20=0A-=09= /*=0A-=09=20*=20Get=20the=20old=20range=20of=20the=20record=20being=20= updated/deleted.=20Must=20read=20with=0A-=09=20*=20the=20attno=20of=20= the=20leaf=20partition=20being=20updated.=0A-=09=20*/=0A-=0A-=09= rangeAttno=20=3D=20forPortionOf->rangeVar->varattno;=0A-=09if=20= (resultRelInfo->ri_RootResultRelInfo)=0A-=09=09map=20=3D=20= ExecGetChildToRootMap(resultRelInfo);=0A-=09if=20(map=20!=3D=20NULL)=0A-=09= =09rangeAttno=20=3D=20map->attrMap->attnums[rangeAttno=20-=201];=0A=20=09= slot_getallattrs(oldtupleSlot);=0A=20=0A-=09if=20= (oldtupleSlot->tts_isnull[rangeAttno=20-=201])=0A+=09/*=20Get=20the=20= old=20range=20of=20the=20record=20being=20updated/deleted.=20*/=0A+=09if=20= (oldtupleSlot->tts_isnull[fpoState->fp_rangeAttno=20-=201])=0A=20=09=09= elog(ERROR,=20"found=20a=20NULL=20range=20in=20a=20temporal=20table");=0A= -=09oldRange=20=3D=20oldtupleSlot->tts_values[rangeAttno=20-=201];=0A+=09= oldRange=20=3D=20oldtupleSlot->tts_values[fpoState->fp_rangeAttno=20-=20= 1];=0A=20=0A=20=09/*=0A=20=09=20*=20Get=20the=20range's=20type=20cache=20= entry.=20This=20is=20worth=20caching=20for=20the=20whole=0A@@=20-1528,12=20= +1496,19=20@@=20ExecForPortionOfLeftovers(ModifyTableContext=20*context,=0A= =20=09fcinfo->args[1].isnull=20=3D=20false;=0A=20=0A=20=09/*=0A-=09=20*=20= If=20there=20are=20partitions,=20we=20must=20insert=20into=20the=20root=20= table,=20so=20we=20get=0A-=09=20*=20tuple=20routing.=20We=20already=20= set=20up=20leftoverSlot=20with=20the=20root=20tuple=0A-=09=20*=20= descriptor.=0A+=09=20*=20For=20partitioned=20tables,=20we=20must=20read=20= leftovers=20with=20the=20tuple=0A+=09=20*=20descriptor=20of=20the=20= child=20table,=20but=20insert=20into=20the=20root=20table=20to=20enable=0A= +=09=20*=20tuple=20routing.=20So=20leftoverSlot=20is=20configured=20with=20= the=20root's=20tuple=0A+=09=20*=20descriptor.=20But=20for=20traditional=20= table=20inheritance,=20we=20don't=20need=20tuple=0A+=09=20*=20routing=20= and=20just=20insert=20directly=20into=20the=20child=20table=20to=20= preserve=0A+=09=20*=20child-specific=20columns.=20In=20that=20case,=20= leftoverSlot=20uses=20the=20child's=0A+=09=20*=20(resultRelInfo)=20tuple=20= descriptor.=0A=20=09=20*/=0A-=09if=20= (resultRelInfo->ri_RootResultRelInfo)=0A+=09if=20(partitionRouting)=0A+=09= {=0A+=09=09map=20=3D=20ExecGetChildToRootMap(resultRelInfo);=0A=20=09=09= resultRelInfo=20=3D=20resultRelInfo->ri_RootResultRelInfo;=0A+=09}=0A=20=0A= =20=09/*=0A=20=09=20*=20Insert=20a=20leftover=20for=20each=20value=20= returned=20by=20the=20without_portion=20helper=0A@@=20-1575,9=20+1550,9=20= @@=20ExecForPortionOfLeftovers(ModifyTableContext=20*context,=0A=20=09=09= {=0A=20=09=09=09/*=0A=20=09=09=09=20*=20Make=20a=20copy=20of=20the=20= pre-UPDATE=20row.=20Then=20we'll=20overwrite=20the=0A-=09=09=09=20*=20= range=20column=20below.=20Convert=20oldtuple=20to=20the=20base=20table's=20= format=0A-=09=09=09=20*=20if=20necessary.=20We=20need=20to=20insert=20= temporal=20leftovers=20through=20the=0A-=09=09=09=20*=20root=20partition=20= so=20they=20get=20routed=20correctly.=0A+=09=09=09=20*=20range=20column=20= below.=20Only=20partitioned=20targets=20need=20conversion=20to=0A+=09=09=09= =20*=20the=20root=20table's=20format,=20because=20they=20reinsert=20= through=20the=20root=0A+=09=09=09=20*=20relation=20for=20tuple=20= routing.=0A=20=09=09=09=20*/=0A=20=09=09=09if=20(map=20!=3D=20NULL)=0A=20= =09=09=09{=0A@@=20-1614,8=20+1589,8=20@@=20= ExecForPortionOfLeftovers(ModifyTableContext=20*context,=0A=20=09=09=09=09= ExecForceStoreHeapTuple(oldtuple,=20leftoverSlot,=20false);=0A=20=09=09}=0A= =20=0A-=09=09leftoverSlot->tts_values[forPortionOf->rangeVar->varattno=20= -=201]=20=3D=20leftover;=0A-=09=09= leftoverSlot->tts_isnull[forPortionOf->rangeVar->varattno=20-=201]=20=3D=20= false;=0A+=09=09= leftoverSlot->tts_values[resultRelInfo->ri_forPortionOf->fp_rangeAttno=20= -=201]=20=3D=20leftover;=0A+=09=09= leftoverSlot->tts_isnull[resultRelInfo->ri_forPortionOf->fp_rangeAttno=20= -=201]=20=3D=20false;=0A=20=09=09ExecMaterializeSlot(leftoverSlot);=0A=20= =0A=20=09=09/*=0A@@=20-4790,6=20+4765,16=20@@=20= ExecModifyTable(PlanState=20*pstate)=0A=20=09=09=09=09=09=09=09=09=09=09=09= =09=09=09=20false,=20true);=0A=20=09=09}=0A=20=0A+=09=09/*=0A+=09=09=20*=20= If=20we=20don't=20have=20a=20ForPortionOfState=20yet,=20we=20must=20be=20= a=20partition=20or=0A+=09=09=20*=20inheritance=20child=20being=20hit=20= for=20the=20first=20time.=20Make=20a=20copy=20from=0A+=09=09=20*=20the=20= root,=20with=20our=20own=20TupleTableSlot.=20We=20do=20this=20lazily=20= so=20that=20we=0A+=09=09=20*=20don't=20pay=20the=20price=20of=20unused=20= partitions.=0A+=09=09=20*/=0A+=09=09if=20(((ModifyTable=20*)=20= context.mtstate->ps.plan)->forPortionOf=20&&=0A+=09=09=09= !resultRelInfo->ri_forPortionOf)=0A+=09=09=09= ExecInitForPortionOf(context.mtstate,=20estate,=20resultRelInfo);=0A+=0A=20= =09=09/*=0A=20=09=09=20*=20If=20resultRelInfo->ri_usesFdwDirectModify=20= is=20true,=20all=20we=20need=20to=20do=0A=20=09=09=20*=20here=20is=20= compute=20the=20RETURNING=20expressions.=0A@@=20-5873,3=20+5858,76=20@@=20= ExecReScanModifyTable(ModifyTableState=20*node)=0A=20=09=20*/=0A=20=09= elog(ERROR,=20"ExecReScanModifyTable=20is=20not=20implemented");=0A=20}=0A= +=0A+/*=20= ----------------------------------------------------------------=0A+=20*=09= =09ExecInitForPortionOf=0A+=20*=0A+=20*=09=09Initializes=20= resultRelInfo->ri_forPortionOf=20for=20child=20tables.=0A+=20*=0A+=20*=09= =09Partitions=20share=20the=20root=20leftover=20slot,=20since=20they=20= must=20insert=20via=0A+=20*=09=09the=20root=20relation=20to=20get=20= tuple=20routing.=20Plain=20inheritance=20children=0A+=20*=09=09must=20= keep=20their=20own=20leftover=20slot=20and=20insert=20back=20into=20the=20= child,=20or=0A+=20*=09=09else=20child-only=20column=20values=20and=20= physical=20placement=20would=20be=20lost.=0A+=20*=20= ----------------------------------------------------------------=0A+=20= */=0A+static=20void=0A+ExecInitForPortionOf(ModifyTableState=20*mtstate,=20= EState=20*estate,=0A+=09=09=09=09=09=20ResultRelInfo=20*resultRelInfo)=0A= +{=0A+=09MemoryContext=20oldcxt;=0A+=09ForPortionOfState=20*leafState;=0A= +=09ResultRelInfo=20*rootRelInfo=20=3D=20mtstate->rootResultRelInfo;=0A+=09= ForPortionOfState=20*fpoState;=0A+=09TupleConversionMap=20*map;=0A+=0A+=09= if=20(!rootRelInfo)=0A+=09=09elog(ERROR,=20"no=20root=20relation=20but=20= ri_forPortionOf=20is=20uninitialized");=0A+=0A+=09fpoState=20=3D=20= rootRelInfo->ri_forPortionOf;=0A+=09Assert(fpoState);=0A+=0A+=09/*=20= Things=20built=20here=20have=20to=20last=20for=20the=20query=20duration.=20= */=0A+=09oldcxt=20=3D=20MemoryContextSwitchTo(estate->es_query_cxt);=0A+=0A= +=09leafState=20=3D=20makeNode(ForPortionOfState);=0A+=0A+=09= leafState->fp_rangeName=20=3D=20fpoState->fp_rangeName;=0A+=09= leafState->fp_rangeType=20=3D=20fpoState->fp_rangeType;=0A+=09= leafState->fp_targetRange=20=3D=20fpoState->fp_targetRange;=0A+=09map=20= =3D=20ExecGetChildToRootMap(resultRelInfo);=0A+=0A+=09/*=0A+=09=20*=20= fp_rangeAttno=20must=20match=20the=20tuple=20layout=20used=20for=20= reading=20the=20old=0A+=09=20*=20range=20value.=20The=20query=20uses=20= the=20target=20relation's=20attno,=20so=20translate=0A+=09=20*=20it=20to=20= the=20child=20attno=20when=20the=20child=20has=20a=20different=20column=20= layout.=0A+=09=20*/=0A+=09if=20(map)=0A+=09=09leafState->fp_rangeAttno=20= =3D=20map->attrMap->attnums[fpoState->fp_rangeAttno=20-=201];=0A+=09else=0A= +=09=09leafState->fp_rangeAttno=20=3D=20fpoState->fp_rangeAttno;=0A+=0A+=09= /*=0A+=09=20*=20For=20partitioned=20tables=20we=20must=20read=20the=20= leftovers=20using=20the=20child=0A+=09=20*=20table's=20tuple=20= descriptor,=20but=20then=20insert=20them=20into=20the=20root=20table=0A+=09= =20*=20(using=20its=20tuple=20descriptor)=20so=20we=20get=20tuple=20= routing.=0A+=09=20*=0A+=09=20*=20For=20traditional=20table=20= inheritance,=20we=20read=20and=20insert=20directly=20into=0A+=09=20*=20= this=20resultRelInfo;=20no=20tuple=20routing=20via=20the=20parent=20is=20= required.=0A+=09=20*/=0A+=09if=20= (rootRelInfo->ri_RelationDesc->rd_rel->relkind=20=3D=3D=20= RELKIND_PARTITIONED_TABLE)=0A+=09=09leafState->fp_Leftover=20=3D=20= fpoState->fp_Leftover;=0A+=09else=0A+=09=09leafState->fp_Leftover=20=3D=0A= +=09=09=09ExecInitExtraTupleSlot(mtstate->ps.state,=0A+=09=09=09=09=09=09= =09=09=20=20=20RelationGetDescr(resultRelInfo->ri_RelationDesc),=0A+=09=09= =09=09=09=09=09=09=20=20=20&TTSOpsVirtual);=0A+=0A+=09/*=20Each=20child=20= relation=20needs=20a=20slot=20matching=20its=20tuple=20descriptor.=20*/=0A= +=09leafState->fp_Existing=20=3D=0A+=09=09= table_slot_create(resultRelInfo->ri_RelationDesc,=0A+=09=09=09=09=09=09=20= =20&mtstate->ps.state->es_tupleTable);=0A+=0A+=09= resultRelInfo->ri_forPortionOf=20=3D=20leafState;=0A+=0A+=09= MemoryContextSwitchTo(oldcxt);=0A+}=0Adiff=20--git=20= a/src/include/nodes/execnodes.h=20b/src/include/nodes/execnodes.h=0A= index=2013359180d25..53c138310db=20100644=0A---=20= a/src/include/nodes/execnodes.h=0A+++=20b/src/include/nodes/execnodes.h=0A= @@=20-477,7=20+477,8=20@@=20typedef=20struct=20ForPortionOfState=0A=20=09= NodeTag=09=09type;=0A=20=0A=20=09char=09=20=20=20*fp_rangeName;=09/*=20= the=20column=20named=20in=20FOR=20PORTION=20OF=20*/=0A-=09Oid=09=09=09= fp_rangeType;=09/*=20the=20type=20of=20the=20FOR=20PORTION=20OF=20= expression=20*/=0A+=09Oid=09=09=09fp_rangeType;=09/*=20the=20base=20type=20= (not=20domain)=20of=20the=20FOR=0A+=09=09=09=09=09=09=09=09=20*=20= PORTION=20OF=20expression=20*/=0A=20=09int=09=09=09fp_rangeAttno;=09/*=20= the=20attno=20of=20the=20range=20column=20*/=0A=20=09Datum=09=09= fp_targetRange;=20/*=20the=20range/multirange=20from=20FOR=20PORTION=20= OF=20*/=0A=20=09TypeCacheEntry=20*fp_leftoverstypcache;=09/*=20type=20= cache=20entry=20of=20the=20range=20*/=0Adiff=20--git=20= a/src/test/regress/expected/for_portion_of.out=20= b/src/test/regress/expected/for_portion_of.out=0Aindex=20= ff88879857e..43408972117=20100644=0A---=20= a/src/test/regress/expected/for_portion_of.out=0A+++=20= b/src/test/regress/expected/for_portion_of.out=0A@@=20-2208,6=20= +2208,164=20@@=20SELECT=20*=20FROM=20fpo_rule=20ORDER=20BY=20f1;=0A=20(2=20= rows)=0A=20=0A=20DROP=20TABLE=20fpo_rule;=0A+--=20UPDATE/DELETE=20FOR=20= PORTION=20OF=20with=20table=20inheritance=0A+--=20Leftover=20rows=20must=20= stay=20in=20the=20child=20table,=20preserving=20child-specific=20= columns.=0A+CREATE=20TABLE=20fpo_inh_parent=20(=0A+=20=20id=20int4range,=0A= +=20=20valid_at=20daterange,=0A+=20=20name=20text=0A+);=0A+CREATE=20= TABLE=20fpo_inh_child=20(=0A+=20=20description=20text=0A+)=20INHERITS=20= (fpo_inh_parent);=0A+--=20Update=20targets=20the=20parent;=20the=20= matching=20row=20lives=20in=20the=20child.=0A+INSERT=20INTO=20= fpo_inh_child=20(id,=20valid_at,=20name,=20description)=20VALUES=0A+=20=20= ('[1,2)',=20'[2018-01-01,2019-01-01)',=20'one',=20'initial');=0A+UPDATE=20= fpo_inh_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20'2018-04-01'=20= TO=20'2018-10-01'=0A+=20=20SET=20name=20=3D=20'one^1';=0A+--=20All=20= three=20rows=20should=20be=20in=20the=20child,=20with=20description=20= preserved.=0A+SELECT=20tableoid::regclass,=20*=20FROM=20fpo_inh_parent=20= ORDER=20BY=20valid_at;=0A+=20=20=20tableoid=20=20=20=20|=20=20id=20=20=20= |=20=20=20=20=20=20=20=20valid_at=20=20=20=20=20=20=20=20=20|=20name=20=20= =0A+---------------+-------+-------------------------+-------=0A+=20= fpo_inh_child=20|=20[1,2)=20|=20[2018-01-01,2018-04-01)=20|=20one=0A+=20= fpo_inh_child=20|=20[1,2)=20|=20[2018-04-01,2018-10-01)=20|=20one^1=0A+=20= fpo_inh_child=20|=20[1,2)=20|=20[2018-10-01,2019-01-01)=20|=20one=0A+(3=20= rows)=0A+=0A+SELECT=20*=20FROM=20fpo_inh_child=20ORDER=20BY=20valid_at;=0A= +=20=20id=20=20=20|=20=20=20=20=20=20=20=20valid_at=20=20=20=20=20=20=20=20= =20|=20name=20=20|=20description=20=0A= +-------+-------------------------+-------+-------------=0A+=20[1,2)=20|=20= [2018-01-01,2018-04-01)=20|=20one=20=20=20|=20initial=0A+=20[1,2)=20|=20= [2018-04-01,2018-10-01)=20|=20one^1=20|=20initial=0A+=20[1,2)=20|=20= [2018-10-01,2019-01-01)=20|=20one=20=20=20|=20initial=0A+(3=20rows)=0A+=0A= +--=20No=20rows=20should=20have=20leaked=20into=20the=20parent.=0A= +SELECT=20*=20FROM=20ONLY=20fpo_inh_parent=20ORDER=20BY=20valid_at;=0A+=20= id=20|=20valid_at=20|=20name=20=0A+----+----------+------=0A+(0=20rows)=0A= +=0A+--=20Same=20test=20for=20DELETE=20instead=20of=20UPDATE:=0A= +TRUNCATE=20fpo_inh_child,=20fpo_inh_parent;=0A+INSERT=20INTO=20= fpo_inh_child=20(id,=20valid_at,=20name,=20description)=20VALUES=0A+=20=20= ('[1,2)',=20'[2018-01-01,2019-01-01)',=20'one',=20'initial');=0A+DELETE=20= FROM=20fpo_inh_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20= '2018-04-01'=20TO=20'2018-10-01';=0A+--=20Both=20rows=20should=20be=20in=20= the=20child,=20with=20description=20preserved.=0A+SELECT=20= tableoid::regclass,=20*=20FROM=20fpo_inh_parent=20ORDER=20BY=20valid_at;=0A= +=20=20=20tableoid=20=20=20=20|=20=20id=20=20=20|=20=20=20=20=20=20=20=20= valid_at=20=20=20=20=20=20=20=20=20|=20name=20=0A= +---------------+-------+-------------------------+------=0A+=20= fpo_inh_child=20|=20[1,2)=20|=20[2018-01-01,2018-04-01)=20|=20one=0A+=20= fpo_inh_child=20|=20[1,2)=20|=20[2018-10-01,2019-01-01)=20|=20one=0A+(2=20= rows)=0A+=0A+SELECT=20*=20FROM=20fpo_inh_child=20ORDER=20BY=20valid_at;=0A= +=20=20id=20=20=20|=20=20=20=20=20=20=20=20valid_at=20=20=20=20=20=20=20=20= =20|=20name=20|=20description=20=0A= +-------+-------------------------+------+-------------=0A+=20[1,2)=20|=20= [2018-01-01,2018-04-01)=20|=20one=20=20|=20initial=0A+=20[1,2)=20|=20= [2018-10-01,2019-01-01)=20|=20one=20=20|=20initial=0A+(2=20rows)=0A+=0A= +--=20No=20rows=20should=20have=20leaked=20into=20the=20parent.=0A= +SELECT=20*=20FROM=20ONLY=20fpo_inh_parent=20ORDER=20BY=20valid_at;=0A+=20= id=20|=20valid_at=20|=20name=20=0A+----+----------+------=0A+(0=20rows)=0A= +=0A+DROP=20TABLE=20fpo_inh_parent=20CASCADE;=0A+NOTICE:=20=20drop=20= cascades=20to=20table=20fpo_inh_child=0A+--=20UPDATE=20FOR=20PORTION=20= OF=20with=20multiple=20inheritance=0A+--=20Leftover=20rows=20must=20stay=20= in=20the=20child=20table,=20even=20if=20the=20range=20column's=0A+--=20= attnum=20differs=20between=20the=20target=20parent=20and=20child.=0A= +CREATE=20TABLE=20temporal_parent=20(=0A+=20=20id=20int,=0A+=20=20= valid_at=20daterange,=0A+=20=20name=20text=0A+);=0A+CREATE=20TABLE=20= other_parent=20(=0A+=20=20prefix=20text,=0A+=20=20note=20text=0A+);=0A= +CREATE=20TABLE=20mi_child=20()=20INHERITS=20(other_parent,=20= temporal_parent);=0A+--=20attnum=20of=20the=20range=20column=20is=20= different=20in=20temporal_parent=20and=20mi_child=0A+SELECT=20attnum,=20= attname=0A+=20=20FROM=20pg_attribute=0A+=20=20WHERE=20attrelid=20=3D=20= 'temporal_parent'::regclass=0A+=20=20=20=20AND=20attnum=20>=200=20AND=20= NOT=20attisdropped=0A+=20=20ORDER=20BY=20attnum;=0A+=20attnum=20|=20= attname=20=20=0A+--------+----------=0A+=20=20=20=20=20=201=20|=20id=0A+=20= =20=20=20=20=202=20|=20valid_at=0A+=20=20=20=20=20=203=20|=20name=0A+(3=20= rows)=0A+=0A+SELECT=20attnum,=20attname=0A+=20=20FROM=20pg_attribute=0A+=20= =20WHERE=20attrelid=20=3D=20'mi_child'::regclass=0A+=20=20=20=20AND=20= attnum=20>=200=20AND=20NOT=20attisdropped=0A+=20=20ORDER=20BY=20attnum;=0A= +=20attnum=20|=20attname=20=20=0A+--------+----------=0A+=20=20=20=20=20=20= 1=20|=20prefix=0A+=20=20=20=20=20=202=20|=20note=0A+=20=20=20=20=20=203=20= |=20id=0A+=20=20=20=20=20=204=20|=20valid_at=0A+=20=20=20=20=20=205=20|=20= name=0A+(5=20rows)=0A+=0A+INSERT=20INTO=20mi_child=20(prefix,=20note,=20= id,=20valid_at,=20name)=20VALUES=0A+=20=20('pfx',=20'memo',=201,=20= daterange('2000-01-01',=20'2010-01-01'),=20'old');=0A+UPDATE=20= temporal_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20'2001-01-01'=20= TO=20'2002-01-01'=0A+=20=20SET=20name=20=3D=20'new'=0A+=20=20WHERE=20id=20= =3D=201;=0A+SELECT=20tableoid::regclass,=20*=20FROM=20temporal_parent=20= ORDER=20BY=20valid_at;=0A+=20tableoid=20|=20id=20|=20=20=20=20=20=20=20=20= valid_at=20=20=20=20=20=20=20=20=20|=20name=20=0A= +----------+----+-------------------------+------=0A+=20mi_child=20|=20=20= 1=20|=20[2000-01-01,2001-01-01)=20|=20old=0A+=20mi_child=20|=20=201=20|=20= [2001-01-01,2002-01-01)=20|=20new=0A+=20mi_child=20|=20=201=20|=20= [2002-01-01,2010-01-01)=20|=20old=0A+(3=20rows)=0A+=0A+SELECT=20*=20FROM=20= mi_child=20ORDER=20BY=20valid_at;=0A+=20prefix=20|=20note=20|=20id=20|=20= =20=20=20=20=20=20=20valid_at=20=20=20=20=20=20=20=20=20|=20name=20=0A= +--------+------+----+-------------------------+------=0A+=20pfx=20=20=20= =20|=20memo=20|=20=201=20|=20[2000-01-01,2001-01-01)=20|=20old=0A+=20pfx=20= =20=20=20|=20memo=20|=20=201=20|=20[2001-01-01,2002-01-01)=20|=20new=0A+=20= pfx=20=20=20=20|=20memo=20|=20=201=20|=20[2002-01-01,2010-01-01)=20|=20= old=0A+(3=20rows)=0A+=0A+SELECT=20*=20FROM=20ONLY=20temporal_parent=20= ORDER=20BY=20valid_at;=0A+=20id=20|=20valid_at=20|=20name=20=0A= +----+----------+------=0A+(0=20rows)=0A+=0A+TRUNCATE=20mi_child,=20= other_parent,=20temporal_parent;=0A+INSERT=20INTO=20mi_child=20(prefix,=20= note,=20id,=20valid_at,=20name)=20VALUES=0A+=20=20('pfx',=20'memo',=201,=20= daterange('2000-01-01',=20'2010-01-01'),=20'old');=0A+DELETE=20FROM=20= temporal_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20'2001-01-01'=20= TO=20'2002-01-01'=0A+=20=20WHERE=20id=20=3D=201;=0A+SELECT=20= tableoid::regclass,=20*=20FROM=20temporal_parent=20ORDER=20BY=20= valid_at;=0A+=20tableoid=20|=20id=20|=20=20=20=20=20=20=20=20valid_at=20=20= =20=20=20=20=20=20=20|=20name=20=0A= +----------+----+-------------------------+------=0A+=20mi_child=20|=20=20= 1=20|=20[2000-01-01,2001-01-01)=20|=20old=0A+=20mi_child=20|=20=201=20|=20= [2002-01-01,2010-01-01)=20|=20old=0A+(2=20rows)=0A+=0A+SELECT=20*=20FROM=20= mi_child=20ORDER=20BY=20valid_at;=0A+=20prefix=20|=20note=20|=20id=20|=20= =20=20=20=20=20=20=20valid_at=20=20=20=20=20=20=20=20=20|=20name=20=0A= +--------+------+----+-------------------------+------=0A+=20pfx=20=20=20= =20|=20memo=20|=20=201=20|=20[2000-01-01,2001-01-01)=20|=20old=0A+=20pfx=20= =20=20=20|=20memo=20|=20=201=20|=20[2002-01-01,2010-01-01)=20|=20old=0A= +(2=20rows)=0A+=0A+SELECT=20*=20FROM=20ONLY=20temporal_parent=20ORDER=20= BY=20valid_at;=0A+=20id=20|=20valid_at=20|=20name=20=0A= +----+----------+------=0A+(0=20rows)=0A+=0A+DROP=20TABLE=20= temporal_parent=20CASCADE;=0A+NOTICE:=20=20drop=20cascades=20to=20table=20= mi_child=0A=20--=20UPDATE=20FOR=20PORTION=20OF=20with=20generated=20= columns=0A=20--=20The=20generated=20column=20depends=20on=20the=20range=20= column,=20so=20it=20must=20be=0A=20--=20recomputed=20when=20FOR=20= PORTION=20OF=20narrows=20the=20range.=0Adiff=20--git=20= a/src/test/regress/sql/for_portion_of.sql=20= b/src/test/regress/sql/for_portion_of.sql=0Aindex=20= d61ad5dbe75..7b08f8cf45e=20100644=0A---=20= a/src/test/regress/sql/for_portion_of.sql=0A+++=20= b/src/test/regress/sql/for_portion_of.sql=0A@@=20-1448,6=20+1448,91=20@@=20= SELECT=20*=20FROM=20fpo_rule=20ORDER=20BY=20f1;=0A=20=0A=20DROP=20TABLE=20= fpo_rule;=0A=20=0A+--=20UPDATE/DELETE=20FOR=20PORTION=20OF=20with=20= table=20inheritance=0A+--=20Leftover=20rows=20must=20stay=20in=20the=20= child=20table,=20preserving=20child-specific=20columns.=0A+CREATE=20= TABLE=20fpo_inh_parent=20(=0A+=20=20id=20int4range,=0A+=20=20valid_at=20= daterange,=0A+=20=20name=20text=0A+);=0A+CREATE=20TABLE=20fpo_inh_child=20= (=0A+=20=20description=20text=0A+)=20INHERITS=20(fpo_inh_parent);=0A+=0A= +--=20Update=20targets=20the=20parent;=20the=20matching=20row=20lives=20= in=20the=20child.=0A+INSERT=20INTO=20fpo_inh_child=20(id,=20valid_at,=20= name,=20description)=20VALUES=0A+=20=20('[1,2)',=20= '[2018-01-01,2019-01-01)',=20'one',=20'initial');=0A+UPDATE=20= fpo_inh_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20'2018-04-01'=20= TO=20'2018-10-01'=0A+=20=20SET=20name=20=3D=20'one^1';=0A+--=20All=20= three=20rows=20should=20be=20in=20the=20child,=20with=20description=20= preserved.=0A+SELECT=20tableoid::regclass,=20*=20FROM=20fpo_inh_parent=20= ORDER=20BY=20valid_at;=0A+SELECT=20*=20FROM=20fpo_inh_child=20ORDER=20BY=20= valid_at;=0A+--=20No=20rows=20should=20have=20leaked=20into=20the=20= parent.=0A+SELECT=20*=20FROM=20ONLY=20fpo_inh_parent=20ORDER=20BY=20= valid_at;=0A+=0A+--=20Same=20test=20for=20DELETE=20instead=20of=20= UPDATE:=0A+TRUNCATE=20fpo_inh_child,=20fpo_inh_parent;=0A+INSERT=20INTO=20= fpo_inh_child=20(id,=20valid_at,=20name,=20description)=20VALUES=0A+=20=20= ('[1,2)',=20'[2018-01-01,2019-01-01)',=20'one',=20'initial');=0A+DELETE=20= FROM=20fpo_inh_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20= '2018-04-01'=20TO=20'2018-10-01';=0A+--=20Both=20rows=20should=20be=20in=20= the=20child,=20with=20description=20preserved.=0A+SELECT=20= tableoid::regclass,=20*=20FROM=20fpo_inh_parent=20ORDER=20BY=20valid_at;=0A= +SELECT=20*=20FROM=20fpo_inh_child=20ORDER=20BY=20valid_at;=0A+--=20No=20= rows=20should=20have=20leaked=20into=20the=20parent.=0A+SELECT=20*=20= FROM=20ONLY=20fpo_inh_parent=20ORDER=20BY=20valid_at;=0A+=0A+DROP=20= TABLE=20fpo_inh_parent=20CASCADE;=0A+=0A+--=20UPDATE=20FOR=20PORTION=20= OF=20with=20multiple=20inheritance=0A+--=20Leftover=20rows=20must=20stay=20= in=20the=20child=20table,=20even=20if=20the=20range=20column's=0A+--=20= attnum=20differs=20between=20the=20target=20parent=20and=20child.=0A= +CREATE=20TABLE=20temporal_parent=20(=0A+=20=20id=20int,=0A+=20=20= valid_at=20daterange,=0A+=20=20name=20text=0A+);=0A+CREATE=20TABLE=20= other_parent=20(=0A+=20=20prefix=20text,=0A+=20=20note=20text=0A+);=0A= +CREATE=20TABLE=20mi_child=20()=20INHERITS=20(other_parent,=20= temporal_parent);=0A+=0A+--=20attnum=20of=20the=20range=20column=20is=20= different=20in=20temporal_parent=20and=20mi_child=0A+SELECT=20attnum,=20= attname=0A+=20=20FROM=20pg_attribute=0A+=20=20WHERE=20attrelid=20=3D=20= 'temporal_parent'::regclass=0A+=20=20=20=20AND=20attnum=20>=200=20AND=20= NOT=20attisdropped=0A+=20=20ORDER=20BY=20attnum;=0A+SELECT=20attnum,=20= attname=0A+=20=20FROM=20pg_attribute=0A+=20=20WHERE=20attrelid=20=3D=20= 'mi_child'::regclass=0A+=20=20=20=20AND=20attnum=20>=200=20AND=20NOT=20= attisdropped=0A+=20=20ORDER=20BY=20attnum;=0A+=0A+INSERT=20INTO=20= mi_child=20(prefix,=20note,=20id,=20valid_at,=20name)=20VALUES=0A+=20=20= ('pfx',=20'memo',=201,=20daterange('2000-01-01',=20'2010-01-01'),=20= 'old');=0A+=0A+UPDATE=20temporal_parent=20FOR=20PORTION=20OF=20valid_at=20= FROM=20'2001-01-01'=20TO=20'2002-01-01'=0A+=20=20SET=20name=20=3D=20= 'new'=0A+=20=20WHERE=20id=20=3D=201;=0A+=0A+SELECT=20tableoid::regclass,=20= *=20FROM=20temporal_parent=20ORDER=20BY=20valid_at;=0A+SELECT=20*=20FROM=20= mi_child=20ORDER=20BY=20valid_at;=0A+SELECT=20*=20FROM=20ONLY=20= temporal_parent=20ORDER=20BY=20valid_at;=0A+=0A+TRUNCATE=20mi_child,=20= other_parent,=20temporal_parent;=0A+INSERT=20INTO=20mi_child=20(prefix,=20= note,=20id,=20valid_at,=20name)=20VALUES=0A+=20=20('pfx',=20'memo',=201,=20= daterange('2000-01-01',=20'2010-01-01'),=20'old');=0A+=0A+DELETE=20FROM=20= temporal_parent=20FOR=20PORTION=20OF=20valid_at=20FROM=20'2001-01-01'=20= TO=20'2002-01-01'=0A+=20=20WHERE=20id=20=3D=201;=0A+=0A+SELECT=20= tableoid::regclass,=20*=20FROM=20temporal_parent=20ORDER=20BY=20= valid_at;=0A+SELECT=20*=20FROM=20mi_child=20ORDER=20BY=20valid_at;=0A= +SELECT=20*=20FROM=20ONLY=20temporal_parent=20ORDER=20BY=20valid_at;=0A+=0A= +DROP=20TABLE=20temporal_parent=20CASCADE;=0A+=0A=20--=20UPDATE=20FOR=20= PORTION=20OF=20with=20generated=20columns=0A=20--=20The=20generated=20= column=20depends=20on=20the=20range=20column,=20so=20it=20must=20be=0A=20= --=20recomputed=20when=20FOR=20PORTION=20OF=20narrows=20the=20range.=0A= --=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_EB393630-045F-4C10-B588-BB5DDAE5E5AC--