Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lR17u-00018r-Qc for pgsql-hackers@arkaria.postgresql.org; Mon, 29 Mar 2021 23:16:55 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1lR17t-0003gI-Og for pgsql-hackers@arkaria.postgresql.org; Mon, 29 Mar 2021 23:16:53 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lR17t-0003gB-Bk for pgsql-hackers@lists.postgresql.org; Mon, 29 Mar 2021 23:16:53 +0000 Received: from mail-pj1-x1029.google.com ([2607:f8b0:4864:20::1029]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1lR17p-0008P8-If for pgsql-hackers@postgresql.org; Mon, 29 Mar 2021 23:16:52 +0000 Received: by mail-pj1-x1029.google.com with SMTP id k23-20020a17090a5917b02901043e35ad4aso8475893pji.3 for ; Mon, 29 Mar 2021 16:16:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb-com.20150623.gappssmtp.com; s=20150623; h=from:message-id:mime-version:subject:date:in-reply-to:cc:to :references; bh=RXmyUkruW7JRSwROtPIDhzIqSxgxNHeXYsatQWmDfb0=; b=dr/Wzh8yBPiuYaT6gREisv+chqg4hR+kmUEpTyVitwr1S5e54VmUToRi2glOLjl6fn DsVywMhyqB+fncHxmAnnJl0nZ8sNBfzTeco8UBQbAoeBFDE7+74sduiPeH4AJV2aR5pu I48pTT/N9qfm8T9Xni3HCJU3a9ZA8DYpbG/o6c9KKQK3ttkqDmcYn7xqB+z4plKA5xad ghsK5PKAWxAcU3H3OOmVK3sugxfRocmt2e6skVhIjxQhGy6YlYKZFMkq/YmsZYGG5wo4 BbhUsECfqwegWHtNvk//J3CDLbFcsmTgQ9fvfBkU0ubdDUDKviSivrUeQmBxIidzJT6o j7Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=RXmyUkruW7JRSwROtPIDhzIqSxgxNHeXYsatQWmDfb0=; b=oL/M9UJmg75wiDND36E8wXHhSfWmB0+XyN/+y/0wI2w3bvpTzpkLqe5RyvPAj/GRI6 M+9ZoO9o+K3zthzVAGUTDkuGlJXVLIjq3s2FdYCwopaGQNvHBKGSyAbsX6vUolxZXs+1 rBCA/bt9dXzvfxcxKowZg2RwrR9OldbSsQqMA+4AaVwzfprk0qUajhuuCLhEEr1UWU93 ZwArWLTR6bNiCtfvtz499FJx5cqYZD92W0CSaXNQmGbJr1XH9F0ohbVYOVTMvNMM2oCT SxSNFPtHkIXhjH55qXayMjV9WPr3FAFosdX6Y4OnSddk8dlTcZ18zIAvvy6IQXqkXNHl iAIQ== X-Gm-Message-State: AOAM531fF8oDByT8/A36wpmZZrzLSFeBwaE2Pji8B9YUGQV3zkLf7DYW cpgUWyFQ6n4RhzeKVrAVmOAJfqBKgdnb9+AS3LRVyY7i1wrv5cJevQOnl0mYbm4l3mgOuhFiQGx xNCaim3a8aHIWJt3TUhZMyAktFnib1H2JpSqNiAGL+3+0TPho7276/rHM3fvtX7CbtxHnto3RtI xHdtYFluTX/Q2mylZrx3hny5a7BdM3aSBeIzCl X-Google-Smtp-Source: ABdhPJyOReE+NWhmaYJA1cNdj2tCjokycq/P+ODT4nktlzdtdUSK9nBmAHN90JXebcXiNOIOdWTOjQ== X-Received: by 2002:a17:90b:4b08:: with SMTP id lx8mr1350930pjb.135.1617059807013; Mon, 29 Mar 2021 16:16:47 -0700 (PDT) Received: from laptop280-ma-us.hitronhub.home (24-113-193-150.wavecable.com. [24.113.193.150]) by smtp.gmail.com with ESMTPSA id 8sm658622pjj.53.2021.03.29.16.16.44 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 29 Mar 2021 16:16:45 -0700 (PDT) From: Mark Dilger Message-Id: <6915B9B2-B551-4DBC-89DB-C12D9AF985B8@enterprisedb.com> Content-Type: multipart/mixed; boundary="Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4" Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.1\)) Subject: Re: pg_amcheck contrib application Date: Mon, 29 Mar 2021 16:16:44 -0700 In-Reply-To: Cc: Tom Lane , Noah Misch , Peter Geoghegan , Thomas Munro , "Andrey M. Borodin" , Stephen Frost , Michael Paquier , Amul Sul , Dilip Kumar , Andres Freund , PostgreSQL-development To: Robert Haas References: <9E76E46A-48B2-4869-BD0C-422204C1F767@enterprisedb.com> <20210313184612.GA3195145@rfd.leadboat.com> <930621E5-5D10-456D-8CE4-CF629A6C4669@enterprisedb.com> <20210313191841.GB3195145@rfd.leadboat.com> <3012106.1615827854@sss.pgh.pa.us> <3053552.1615834640@sss.pgh.pa.us> <4F10540A-9022-49EE-A6FC-7FE90797793E@enterprisedb.com> <0D48534A-F511-405D-8645-84B0A1DA1E11@enterprisedb.com> X-Mailer: Apple Mail (2.3608.120.23.2.1) X-CLOUD-SEC-AV-Info: enterprisedb,google_mail,monitor X-CLOUD-SEC-AV-Sent: true X-Gm-Spam: 0 X-Gm-Phishy: 0 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii > On Mar 29, 2021, at 1:06 PM, Robert Haas wrote: > > Hmm, so this got ~10x bigger from my version. Could you perhaps > separate it out into a series of patches for easier review? Say, one > that just fixes the visibility logic, and then a second to avoid doing > the TOAST check with a buffer lock held, and then more than that if > there are other pieces that make sense to separate out? Sure, here are four patches which do the same as the single v12 patch did. --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4 Content-Disposition: attachment; filename=v13-0001-Refactoring-function-check_tuple_header_and_visi.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v13-0001-Refactoring-function-check_tuple_header_and_visi.patch" Content-Transfer-Encoding: quoted-printable =46rom=20acee08646354ddb001d7b31a1b8932237bd40405=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Wed,=2024=20Mar=202021=2018:18:56=20-0700=0ASubject:=20[PATCH=20= v13=201/4]=20Refactoring=20function=0A=20= check_tuple_header_and_visibility=0A=0AExtending=20enum=20= XidCommitStatus=20to=20include=20XID_IS_CURRENT_XID.=20=20The=0A= visibility=20code=20for=20verify_heapam()=20was=20conflating=20= XID_IN_PROGRESS=0Aand=20XID_IS_CURRENT_XID=20under=20just=20one=20enum,=20= making=20it=20harder=20to=0Acompare=20the=20logic=20to=20that=20used=20= by=20vacuum's=20visibility=20function,=0Awhich=20treats=20those=20two=20= cases=20separately.=0A=0ASimplifying=20check_tuple_header_and_visibilty=20= signature.=20=20It=20was=0Ataking=20both=20tuphdr=20and=20ctx=20= arguments,=20but=20the=20tuphdr=20is=20just=0Actx->tuphdr,=20so=20it=20= is=20a=20bit=20absurd=20to=20pass=20two=20arguments=20for=20this.=0A=0A= Splitting=20check_tuple_header_and_visibilty()=20into=20two=20functions.=0A= check_tuple_header()=20and=20check_tuple_visibility()=20are=20split=20= out=20as=0Aseparate=20functions,=20but=20otherwise=20behave=20exactly=20= as=20before.=0A---=0A=20contrib/amcheck/verify_heapam.c=20|=2082=20= +++++++++++++++++++--------------=0A=201=20file=20changed,=2047=20= insertions(+),=2035=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/amcheck/verify_heapam.c=20b/contrib/amcheck/verify_heapam.c=0A= index=206f972e630a..9172b5fd81=20100644=0A---=20= a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-46,6=20+46,7=20@@=20typedef=20= enum=20XidBoundsViolation=0A=20typedef=20enum=20XidCommitStatus=0A=20{=0A= =20=09XID_COMMITTED,=0A+=09XID_IS_CURRENT_XID,=0A=20=09XID_IN_PROGRESS,=0A= =20=09XID_ABORTED=0A=20}=20XidCommitStatus;=0A@@=20-133,8=20+134,8=20@@=20= static=20void=20check_tuple(HeapCheckContext=20*ctx);=0A=20static=20void=20= check_toast_tuple(HeapTuple=20toasttup,=20HeapCheckContext=20*ctx);=0A=20= =0A=20static=20bool=20check_tuple_attribute(HeapCheckContext=20*ctx);=0A= -static=20bool=20check_tuple_header_and_visibilty(HeapTupleHeader=20= tuphdr,=0A-=09=09=09=09=09=09=09=09=09=09=09=20HeapCheckContext=20*ctx);=0A= +static=20bool=20check_tuple_header(HeapCheckContext=20*ctx);=0A+static=20= bool=20check_tuple_visibility(HeapCheckContext=20*ctx);=0A=20=0A=20= static=20void=20report_corruption(HeapCheckContext=20*ctx,=20char=20= *msg);=0A=20static=20TupleDesc=20verify_heapam_tupdesc(void);=0A@@=20= -555,16=20+556,11=20@@=20verify_heapam_tupdesc(void)=0A=20}=0A=20=0A=20= /*=0A-=20*=20Check=20for=20tuple=20header=20corruption=20and=20tuple=20= visibility.=0A-=20*=0A-=20*=20Since=20we=20do=20not=20hold=20a=20= snapshot,=20tuple=20visibility=20is=20not=20a=20question=20of=0A-=20*=20= whether=20we=20should=20be=20able=20to=20see=20the=20tuple=20relative=20= to=20any=20particular=0A-=20*=20snapshot,=20but=20rather=20a=20question=20= of=20whether=20it=20is=20safe=20and=20reasonable=20to=0A-=20*=20check=20= the=20tuple=20attributes.=0A+=20*=20Check=20for=20tuple=20header=20= corruption.=0A=20=20*=0A=20=20*=20Some=20kinds=20of=20corruption=20make=20= it=20unsafe=20to=20check=20the=20tuple=20attributes,=20for=0A=20=20*=20= example=20when=20the=20line=20pointer=20refers=20to=20a=20range=20of=20= bytes=20outside=20the=20page.=0A-=20*=20In=20such=20cases,=20we=20return=20= false=20(not=20visible)=20after=20recording=20appropriate=0A+=20*=20In=20= such=20cases,=20we=20return=20false=20(not=20checkable)=20after=20= recording=20appropriate=0A=20=20*=20corruption=20messages.=0A=20=20*=0A=20= =20*=20Some=20other=20kinds=20of=20tuple=20header=20corruption=20confuse=20= the=20question=20of=20where=0A@@=20-576,27=20+572,16=20@@=20= verify_heapam_tupdesc(void)=0A=20=20*=0A=20=20*=20Other=20kinds=20of=20= tuple=20header=20corruption=20do=20not=20bear=20on=20the=20question=20of=0A= =20=20*=20whether=20the=20tuple=20attributes=20can=20be=20checked,=20so=20= we=20record=20corruption=0A-=20*=20messages=20for=20them=20but=20do=20= not=20base=20our=20visibility=20determination=20on=20them.=20=20(In=0A-=20= *=20other=20words,=20we=20do=20not=20return=20false=20merely=20because=20= we=20detected=20them.)=0A-=20*=0A-=20*=20For=20visibility=20= determination=20not=20specifically=20related=20to=20corruption,=20what=20= we=0A-=20*=20want=20to=20know=20is=20if=20a=20tuple=20is=20potentially=20= visible=20to=20any=20running=0A-=20*=20transaction.=20=20If=20you=20are=20= tempted=20to=20replace=20this=20function's=20visibility=20logic=0A-=20*=20= with=20a=20call=20to=20another=20visibility=20checking=20function,=20= keep=20in=20mind=20that=20this=0A-=20*=20function=20does=20not=20update=20= hint=20bits,=20as=20it=20seems=20imprudent=20to=20write=20hint=20bits=0A= -=20*=20(or=20anything=20at=20all)=20to=20a=20table=20during=20a=20= corruption=20check.=20=20Nor=20does=20this=0A-=20*=20function=20bother=20= classifying=20tuple=20visibility=20beyond=20a=20boolean=20visible=20vs.=0A= -=20*=20not=20visible.=0A+=20*=20messages=20for=20them=20but=20we=20do=20= not=20return=20false=20merely=20because=20we=20detected=0A+=20*=20them.=0A= =20=20*=0A-=20*=20The=20caller=20should=20already=20have=20checked=20= that=20xmin=20and=20xmax=20are=20not=20out=20of=0A-=20*=20bounds=20for=20= the=20relation.=0A-=20*=0A-=20*=20Returns=20whether=20the=20tuple=20is=20= both=20visible=20and=20sufficiently=20sensible=20to=0A-=20*=20undergo=20= attribute=20checks.=0A+=20*=20Returns=20whether=20the=20tuple=20is=20= sufficiently=20sensible=20to=20undergo=20visibility=20and=0A+=20*=20= attribute=20checks.=0A=20=20*/=0A=20static=20bool=0A= -check_tuple_header_and_visibilty(HeapTupleHeader=20tuphdr,=20= HeapCheckContext=20*ctx)=0A+check_tuple_header(HeapCheckContext=20*ctx)=0A= =20{=0A+=09HeapTupleHeader=20tuphdr=20=3D=20ctx->tuphdr;=0A=20=09uint16=09= =09infomask=20=3D=20tuphdr->t_infomask;=0A=20=09bool=09=09header_garbled=20= =3D=20false;=0A=20=09unsigned=09expected_hoff;=0A@@=20-651,13=20+636,34=20= @@=20check_tuple_header_and_visibilty(HeapTupleHeader=20tuphdr,=20= HeapCheckContext=20*ctx)=0A=20=09if=20(header_garbled)=0A=20=09=09return=20= false;=09=09=09/*=20checking=20of=20this=20tuple=20should=20not=20= continue=20*/=0A=20=0A-=09/*=0A-=09=20*=20Ok,=20we=20can=20examine=20the=20= header=20for=20tuple=20visibility=20purposes,=20though=20we=0A-=09=20*=20= still=20need=20to=20be=20careful=20about=20a=20few=20remaining=20types=20= of=20header=0A-=09=20*=20corruption.=20=20This=20logic=20roughly=20= follows=20that=20of=0A-=09=20*=20HeapTupleSatisfiesVacuum.=20=20Where=20= possible=20the=20comments=20indicate=20which=0A-=09=20*=20HTSV_Result=20= we=20think=20that=20function=20might=20return=20for=20this=20tuple.=0A-=09= =20*/=0A+=09return=20true;=09=09=09=09/*=20header=20ok=20*/=0A+}=0A+=0A= +/*=0A+=20*=20Checks=20whether=20a=20tuple=20is=20visible=20for=20= checking.=0A+=20*=0A+=20*=20Since=20we=20do=20not=20hold=20a=20snapshot,=20= tuple=20visibility=20is=20not=20a=20question=20of=0A+=20*=20whether=20we=20= should=20be=20able=20to=20see=20the=20tuple=20relative=20to=20any=20= particular=0A+=20*=20snapshot,=20but=20rather=20a=20question=20of=20= whether=20it=20is=20safe=20and=20reasonable=20to=0A+=20*=20check=20the=20= tuple=20attributes.=0A+=20*=0A+=20*=20For=20visibility=20determination=20= not=20specifically=20related=20to=20corruption,=20what=20we=0A+=20*=20= want=20to=20know=20is=20if=20a=20tuple=20is=20potentially=20visible=20to=20= any=20running=0A+=20*=20transaction.=20=20If=20you=20are=20tempted=20to=20= replace=20this=20function's=20visibility=20logic=0A+=20*=20with=20a=20= call=20to=20another=20visibility=20checking=20function,=20keep=20in=20= mind=20that=20this=0A+=20*=20function=20does=20not=20update=20hint=20= bits,=20as=20it=20seems=20imprudent=20to=20write=20hint=20bits=0A+=20*=20= (or=20anything=20at=20all)=20to=20a=20table=20during=20a=20corruption=20= check.=20=20Nor=20does=20this=0A+=20*=20function=20bother=20classifying=20= tuple=20visibility=20beyond=20a=20boolean=20visible=20vs.=0A+=20*=20not=20= visible.=0A+=20*=0A+=20*=20Returns=20whether=20the=20tuple=20is=20= visible=20for=20checking.=0A+=20*/=0A+static=20bool=0A= +check_tuple_visibility(HeapCheckContext=20*ctx)=0A+{=0A+=09= HeapTupleHeader=20tuphdr=20=3D=20ctx->tuphdr;=0A+=09uint16=09=09infomask=20= =3D=20tuphdr->t_infomask;=0A+=0A=20=09if=20= (!HeapTupleHeaderXminCommitted(tuphdr))=0A=20=09{=0A=20=09=09= TransactionId=20raw_xmin=20=3D=20HeapTupleHeaderGetRawXmin(tuphdr);=0A@@=20= -704,6=20+710,7=20@@=20check_tuple_header_and_visibilty(HeapTupleHeader=20= tuphdr,=20HeapCheckContext=20*ctx)=0A=20=09=09=09=09=09switch=20(status)=0A= =20=09=09=09=09=09{=0A=20=09=09=09=09=09=09case=20XID_IN_PROGRESS:=0A+=09= =09=09=09=09=09case=20XID_IS_CURRENT_XID:=0A=20=09=09=09=09=09=09=09= return=20true;=09/*=20HEAPTUPLE_DELETE_IN_PROGRESS=20*/=0A=20=09=09=09=09= =09=09case=20XID_COMMITTED:=0A=20=09=09=09=09=09=09case=20XID_ABORTED:=0A= @@=20-748,6=20+755,7=20@@=20= check_tuple_header_and_visibilty(HeapTupleHeader=20tuphdr,=20= HeapCheckContext=20*ctx)=0A=20=09=09=09=09=09=09case=20XID_COMMITTED:=0A=20= =09=09=09=09=09=09=09break;=0A=20=09=09=09=09=09=09case=20= XID_IN_PROGRESS:=0A+=09=09=09=09=09=09case=20XID_IS_CURRENT_XID:=0A=20=09= =09=09=09=09=09=09return=20true;=09/*=20insert=20or=20delete=20in=20= progress=20*/=0A=20=09=09=09=09=09=09case=20XID_ABORTED:=0A=20=09=09=09=09= =09=09=09return=20false;=09/*=20HEAPTUPLE_DEAD=20*/=0A@@=20-795,6=20= +803,7=20@@=20check_tuple_header_and_visibilty(HeapTupleHeader=20tuphdr,=20= HeapCheckContext=20*ctx)=0A=20=09=09=09=09=09switch=20(status)=0A=20=09=09= =09=09=09{=0A=20=09=09=09=09=09=09case=20XID_IN_PROGRESS:=0A+=09=09=09=09= =09=09case=20XID_IS_CURRENT_XID:=0A=20=09=09=09=09=09=09=09return=20= true;=09/*=20HEAPTUPLE_DELETE_IN_PROGRESS=20*/=0A=20=09=09=09=09=09=09= case=20XID_COMMITTED:=0A=20=09=09=09=09=09=09case=20XID_ABORTED:=0A@@=20= -1247,7=20+1256,10=20@@=20check_tuple(HeapCheckContext=20*ctx)=0A=20=09=20= *=20corrupt=20to=20continue=20checking,=20or=20if=20the=20tuple=20is=20= not=20visible=20to=20anyone,=0A=20=09=20*=20we=20cannot=20continue=20= with=20other=20checks.=0A=20=09=20*/=0A-=09if=20= (!check_tuple_header_and_visibilty(ctx->tuphdr,=20ctx))=0A+=09if=20= (!check_tuple_header(ctx))=0A+=09=09return;=0A+=0A+=09if=20= (!check_tuple_visibility(ctx))=0A=20=09=09return;=0A=20=0A=20=09/*=0A@@=20= -1448,7=20+1460,7=20@@=20get_xid_status(TransactionId=20xid,=20= HeapCheckContext=20*ctx,=0A=20=09if=20= (FullTransactionIdPrecedesOrEquals(clog_horizon,=20fxid))=0A=20=09{=0A=20= =09=09if=20(TransactionIdIsCurrentTransactionId(xid))=0A-=09=09=09= *status=20=3D=20XID_IN_PROGRESS;=0A+=09=09=09*status=20=3D=20= XID_IS_CURRENT_XID;=0A=20=09=09else=20if=20(TransactionIdDidCommit(xid))=0A= =20=09=09=09*status=20=3D=20XID_COMMITTED;=0A=20=09=09else=20if=20= (TransactionIdDidAbort(xid))=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4 Content-Disposition: attachment; filename=v13-0002-Replacing-implementation-of-check_tuple_visibili.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v13-0002-Replacing-implementation-of-check_tuple_visibili.patch" Content-Transfer-Encoding: quoted-printable =46rom=204838129ccdf3917f71f52035330752e3b5d7416a=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Mon,=2029=20Mar=202021=2014:31:13=20-0700=0ASubject:=20[PATCH=20= v13=202/4]=20Replacing=20implementation=20of=20check_tuple_visibility=0A=0A= Using=20a=20modified=20version=20of=20HeapTupleSatisfiesVacuumHorizon.=0A= ---=0A=20contrib/amcheck/verify_heapam.c=20|=20480=20= +++++++++++++++++++++++++-------=0A=201=20file=20changed,=20372=20= insertions(+),=20108=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/amcheck/verify_heapam.c=20b/contrib/amcheck/verify_heapam.c=0A= index=209172b5fd81..59b13180d9=20100644=0A---=20= a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-73,6=20+73,8=20@@=20typedef=20= struct=20HeapCheckContext=0A=20=09TransactionId=20oldest_xid;=09/*=20= ShmemVariableCache->oldestXid=20*/=0A=20=09FullTransactionId=20= oldest_fxid;=09/*=2064-bit=20version=20of=20oldest_xid,=20computed=0A=20=09= =09=09=09=09=09=09=09=09=20*=20relative=20to=20next_fxid=20*/=0A+=09= TransactionId=20safe_xmin;=09/*=20this=20XID=20and=20newer=20ones=20= can't=20become=0A+=09=09=09=09=09=09=09=09=20*=20all-visible=20while=20= we're=20running=20*/=0A=20=0A=20=09/*=0A=20=09=20*=20Cached=20copy=20of=20= value=20from=20MultiXactState=0A@@=20-114,6=20+116,9=20@@=20typedef=20= struct=20HeapCheckContext=0A=20=09uint32=09=09offset;=09=09=09/*=20= offset=20in=20tuple=20data=20*/=0A=20=09AttrNumber=09attnum;=0A=20=0A+=09= /*=20True=20if=20toast=20for=20this=20tuple=20could=20be=20vacuumed=20= away=20*/=0A+=09bool=09=09tuple_is_volatile;=0A+=0A=20=09/*=20Values=20= for=20iterating=20over=20toast=20for=20the=20attribute=20*/=0A=20=09= int32=09=09chunkno;=0A=20=09int32=09=09attrsize;=0A@@=20-249,6=20+254,12=20= @@=20verify_heapam(PG_FUNCTION_ARGS)=0A=20=09memset(&ctx,=200,=20= sizeof(HeapCheckContext));=0A=20=09ctx.cached_xid=20=3D=20= InvalidTransactionId;=0A=20=0A+=09/*=0A+=09=20*=20Any=20xmin=20newer=20= than=20the=20xmin=20of=20our=20snapshot=20can't=20become=20all-visible=0A= +=09=20*=20while=20we're=20running.=0A+=09=20*/=0A+=09ctx.safe_xmin=20=3D=20= GetTransactionSnapshot()->xmin;=0A+=0A=20=09/*=0A=20=09=20*=20If=20we=20= report=20corruption=20when=20not=20examining=20some=20individual=20= attribute,=0A=20=09=20*=20we=20need=20attnum=20to=20be=20reported=20as=20= NULL.=20=20Set=20that=20up=20before=20any=0A@@=20-640,189=20+651,442=20= @@=20check_tuple_header(HeapCheckContext=20*ctx)=0A=20}=0A=20=0A=20/*=0A= -=20*=20Checks=20whether=20a=20tuple=20is=20visible=20for=20checking.=0A= +=20*=20Checks=20whether=20a=20tuple=20is=20visible=20to=20our=20= transaction=20for=20checking,=20which=20is=0A+=20*=20not=20a=20question=20= of=20whether=20we=20should=20be=20able=20to=20see=20the=20tuple=20= relative=20to=20any=0A+=20*=20particular=20snapshot,=20but=20rather=20a=20= question=20of=20whether=20it=20is=20safe=20and=0A+=20*=20reasonable=20to=20= check=20the=20tuple=20attributes.=20=20The=20caller=20should=20already=20= have=0A+=20*=20checked=20that=20the=20tuple=20is=20sufficiently=20= sensible=20for=20us=20to=20evaluate.=0A=20=20*=0A-=20*=20Since=20we=20do=20= not=20hold=20a=20snapshot,=20tuple=20visibility=20is=20not=20a=20= question=20of=0A-=20*=20whether=20we=20should=20be=20able=20to=20see=20= the=20tuple=20relative=20to=20any=20particular=0A-=20*=20snapshot,=20but=20= rather=20a=20question=20of=20whether=20it=20is=20safe=20and=20reasonable=20= to=0A-=20*=20check=20the=20tuple=20attributes.=0A+=20*=20If=20a=20tuple=20= could=20have=20been=20inserted=20by=20a=20transaction=20that=20also=20= added=20a=0A+=20*=20column=20to=20the=20table,=20but=20which=20= ultimately=20did=20not=20commit,=20or=20which=20has=20not=0A+=20*=20yet=20= committed,=20then=20the=20table's=20current=20TupleDesc=20might=20differ=20= from=20the=20one=0A+=20*=20used=20to=20construct=20this=20tuple,=20so=20= we=20must=20not=20check=20it.=0A=20=20*=0A-=20*=20For=20visibility=20= determination=20not=20specifically=20related=20to=20corruption,=20what=20= we=0A-=20*=20want=20to=20know=20is=20if=20a=20tuple=20is=20potentially=20= visible=20to=20any=20running=0A-=20*=20transaction.=20=20If=20you=20are=20= tempted=20to=20replace=20this=20function's=20visibility=20logic=0A-=20*=20= with=20a=20call=20to=20another=20visibility=20checking=20function,=20= keep=20in=20mind=20that=20this=0A-=20*=20function=20does=20not=20update=20= hint=20bits,=20as=20it=20seems=20imprudent=20to=20write=20hint=20bits=0A= -=20*=20(or=20anything=20at=20all)=20to=20a=20table=20during=20a=20= corruption=20check.=20=20Nor=20does=20this=0A-=20*=20function=20bother=20= classifying=20tuple=20visibility=20beyond=20a=20boolean=20visible=20vs.=0A= -=20*=20not=20visible.=0A+=20*=20As=20a=20special=20case,=20if=20our=20= own=20transaction=20inserted=20the=20tuple,=20even=20if=20we=0A+=20*=20= added=20a=20column=20to=20the=20table,=20our=20TupleDesc=20should=20= match.=20=20We=20could=20check=20the=0A+=20*=20tuple,=20but=20choose=20= not=20to=20do=20so.=0A=20=20*=0A-=20*=20Returns=20whether=20the=20tuple=20= is=20visible=20for=20checking.=0A+=20*=20If=20a=20tuple=20has=20been=20= updated=20or=20deleted,=20we=20can=20still=20read=20the=20old=20tuple=20= for=0A+=20*=20corruption=20checking=20purposes,=20as=20long=20as=20we=20= are=20careful=20about=20concurrent=0A+=20*=20vacuums.=20=20The=20main=20= table=20tuple=20itself=20cannot=20be=20vacuumed=20away=20because=20we=0A= +=20*=20hold=20a=20buffer=20lock=20on=20the=20page,=20but=20if=20the=20= deleting=20transaction=20is=20older=0A+=20*=20than=20our=20transaction=20= snapshot's=20xmin,=20then=20vacuum=20could=20remove=20the=20toast=20at=0A= +=20*=20any=20time,=20so=20we=20must=20not=20check=20the=20toast.=0A+=20= *=0A+=20*=20If=20xmin=20or=20xmax=20values=20are=20older=20than=20can=20= be=20checked=20against=20clog,=20or=20appear=0A+=20*=20to=20be=20in=20= the=20future=20(possibly=20due=20to=20wrap-around),=20then=20we=20cannot=20= make=20a=0A+=20*=20determination=20about=20the=20visibility=20of=20the=20= tuple,=20so=20we=20must=20not=20check=20it.=0A+=20*=0A+=20*=20Returns=20= true=20if=20the=20tuple=20should=20be=20checked,=20false=20otherwise.=20=20= Sets=0A+=20*=20ctx->toast_is_volatile=20true=20if=20the=20toast=20might=20= be=20vacuumed=20away,=20false=0A+=20*=20otherwise.=0A=20=20*/=0A=20= static=20bool=0A=20check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20= {=0A+=09TransactionId=20xmin;=0A+=09TransactionId=20xvac;=0A+=09= TransactionId=20xmax;=0A+=09XidCommitStatus=20xmin_status;=0A+=09= XidCommitStatus=20xvac_status;=0A+=09XidCommitStatus=20xmax_status;=0A=20= =09HeapTupleHeader=20tuphdr=20=3D=20ctx->tuphdr;=0A-=09uint16=09=09= infomask=20=3D=20tuphdr->t_infomask;=0A=20=0A-=09if=20= (!HeapTupleHeaderXminCommitted(tuphdr))=0A+=09ctx->tuple_is_volatile=20=3D= =20true;=09/*=20have=20not=20yet=20proven=20otherwise=20*/=0A+=0A+=09/*=20= If=20xmin=20is=20normal,=20it=20should=20be=20within=20valid=20range=20= */=0A+=09xmin=20=3D=20HeapTupleHeaderGetXmin(tuphdr);=0A+=09switch=20= (get_xid_status(xmin,=20ctx,=20&xmin_status))=0A=20=09{=0A-=09=09= TransactionId=20raw_xmin=20=3D=20HeapTupleHeaderGetRawXmin(tuphdr);=0A+=09= =09case=20XID_INVALID:=0A+=09=09case=20XID_BOUNDS_OK:=0A+=09=09=09break;=0A= +=09=09case=20XID_IN_FUTURE:=0A+=09=09=09report_corruption(ctx,=0A+=09=09= =09=09=09=09=09=20=20psprintf("xmin=20%u=20equals=20or=20exceeds=20next=20= valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=20=20=20= xmin,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09return=20= false;=09=09/*=20corrupt=20*/=0A+=09=09case=20XID_PRECEDES_CLUSTERMIN:=0A= +=09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20= psprintf("xmin=20%u=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A+=09=09=09=09=09=09= =09=09=09=20=20=20EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09= =09=09=09=09=09=09=09=20=20=20= XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09return=20= false;=09=09/*=20corrupt=20*/=0A+=09=09case=20XID_PRECEDES_RELMIN:=0A+=09= =09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20= psprintf("xmin=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A+=09=09=09=09=09=09=09=09=09= =20=20=20EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09= =09=09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09= =09=09return=20false;=09=09/*=20corrupt=20*/=0A+=09}=0A=20=0A+=09/*=0A+=09= =20*=20Has=20inserting=20transaction=20committed?=0A+=09=20*/=0A+=09if=20= (!HeapTupleHeaderXminCommitted(tuphdr))=0A+=09{=0A=20=09=09if=20= (HeapTupleHeaderXminInvalid(tuphdr))=0A-=09=09=09return=20false;=09=09/*=20= HEAPTUPLE_DEAD=20*/=0A+=0A+=09=09=09/*=0A+=09=09=09=20*=20The=20= inserting=20transaction=20aborted.=20=20The=20structure=20of=20the=20= tuple=0A+=09=09=09=20*=20may=20not=20match=20our=20relation=20= description,=20so=20we=20cannot=20check=20it.=0A+=09=09=09=20*/=0A+=09=09= =09return=20false;=09=09/*=20uncheckable=20*/=0A=20=09=09/*=20Used=20by=20= pre-9.0=20binary=20upgrades=20*/=0A-=09=09else=20if=20(infomask=20&=20= HEAP_MOVED_OFF=20||=0A-=09=09=09=09=20infomask=20&=20HEAP_MOVED_IN)=0A+=09= =09else=20if=20(tuphdr->t_infomask=20&=20HEAP_MOVED_OFF)=0A=20=09=09{=0A= -=09=09=09XidCommitStatus=20status;=0A-=09=09=09TransactionId=20xvac=20=3D= =20HeapTupleHeaderGetXvac(tuphdr);=0A+=09=09=09xvac=20=3D=20= HeapTupleHeaderGetXvac(tuphdr);=0A=20=0A-=09=09=09switch=20= (get_xid_status(xvac,=20ctx,=20&status))=0A+=09=09=09switch=20= (get_xid_status(xvac,=20ctx,=20&xvac_status))=0A=20=09=09=09{=0A=20=09=09= =09=09case=20XID_INVALID:=0A=20=09=09=09=09=09report_corruption(ctx,=0A-=09= =09=09=09=09=09=09=09=09=20=20pstrdup("old-style=20VACUUM=20FULL=20= transaction=20ID=20is=20invalid"));=0A+=09=09=09=09=09=09=09=09=09=20=20= pstrdup("old-style=20VACUUM=20FULL=20transaction=20ID=20for=20moved=20= off=20tuple=20is=20invalid"));=0A=20=09=09=09=09=09return=20false;=09/*=20= corrupt=20*/=0A=20=09=09=09=09case=20XID_IN_FUTURE:=0A=20=09=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20equals=20= or=20exceeds=20next=20valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09= =09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20= %u=20for=20moved=20off=20tuple=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A=20=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A=20=09=09= =09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_RELMIN:=0A=20=09=09=09=09=09report_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20precedes=20relation=20freeze=20threshold=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20= FULL=20transaction=20ID=20%u=20for=20moved=20off=20tuple=20precedes=20= relation=20freeze=20threshold=20%u:%u",=0A=20=09=09=09=09=09=09=09=09=09=09= =09=20=20=20xvac,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A=20=09=09=09=09=09=09=09= =09=09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A-=09=09=09=09=09= break;=0A=20=09=09=09=09case=20XID_PRECEDES_CLUSTERMIN:=0A=20=09=09=09=09= =09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20precedes=20= oldest=20valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09= =20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20off=20tuple=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20xvac,=0A=20=09=09=09= =09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A=20=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09=09= =09=09=09return=20false;=09/*=20corrupt=20*/=0A-=09=09=09=09=09break;=0A=20= =09=09=09=09case=20XID_BOUNDS_OK:=0A-=09=09=09=09=09switch=20(status)=0A= -=09=09=09=09=09{=0A-=09=09=09=09=09=09case=20XID_IN_PROGRESS:=0A-=09=09=09= =09=09=09case=20XID_IS_CURRENT_XID:=0A-=09=09=09=09=09=09=09return=20= true;=09/*=20HEAPTUPLE_DELETE_IN_PROGRESS=20*/=0A-=09=09=09=09=09=09case=20= XID_COMMITTED:=0A-=09=09=09=09=09=09case=20XID_ABORTED:=0A-=09=09=09=09=09= =09=09return=20false;=09/*=20HEAPTUPLE_DEAD=20*/=0A-=09=09=09=09=09}=0A+=09= =09=09=09=09break;=0A=20=09=09=09}=0A-=09=09}=0A-=09=09else=0A-=09=09{=0A= -=09=09=09XidCommitStatus=20status;=0A=20=0A-=09=09=09switch=20= (get_xid_status(raw_xmin,=20ctx,=20&status))=0A+=09=09=09switch=20= (xvac_status)=0A=20=09=09=09{=0A-=09=09=09=09case=20XID_INVALID:=0A-=09=09= =09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= pstrdup("raw=20xmin=20is=20invalid"));=0A-=09=09=09=09=09return=20false;=0A= -=09=09=09=09case=20XID_IN_FUTURE:=0A+=09=09=09=09case=20= XID_IS_CURRENT_XID:=0A=20=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=09=09=09=20=20psprintf("raw=20xmin=20%u=20equals=20or=20= exceeds=20next=20valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09= =09=09=09=09=09=20=20=20raw_xmin,=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09= =09=09=09=09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09= =09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20off=20tuple=20matches=20our=20= current=20transaction=20ID",=0A+=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac));=0A=20=09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A-=09=09= =09=09case=20XID_PRECEDES_RELMIN:=0A+=09=09=09=09case=20XID_IN_PROGRESS:=0A= =20=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20= =20psprintf("raw=20xmin=20%u=20precedes=20relation=20freeze=20threshold=20= %u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20raw_xmin,=0A-=09=09=09= =09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09= =09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20off=20tuple=20appears=20to=20be=20= in=20progress",=0A+=09=09=09=09=09=09=09=09=09=09=09=20=20=20xvac));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A-=09=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20psprintf("raw=20xmin=20%u=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20raw_xmin,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A-=09=09= =09=09=09return=20false;=09/*=20corrupt=20*/=0A-=09=09=09=09case=20= XID_BOUNDS_OK:=0A-=09=09=09=09=09switch=20(status)=0A-=09=09=09=09=09{=0A= -=09=09=09=09=09=09case=20XID_COMMITTED:=0A-=09=09=09=09=09=09=09break;=0A= -=09=09=09=09=09=09case=20XID_IN_PROGRESS:=0A-=09=09=09=09=09=09case=20= XID_IS_CURRENT_XID:=0A-=09=09=09=09=09=09=09return=20true;=09/*=20insert=20= or=20delete=20in=20progress=20*/=0A-=09=09=09=09=09=09case=20= XID_ABORTED:=0A-=09=09=09=09=09=09=09return=20false;=09/*=20= HEAPTUPLE_DEAD=20*/=0A-=09=09=09=09=09}=0A+=0A+=09=09=09=09case=20= XID_COMMITTED:=0A+=0A+=09=09=09=09=09/*=0A+=09=09=09=09=09=20*=20The=20= VACUUM=20FULL=20committed,=20so=20this=20tuple=20is=20dead=20and=0A+=09=09= =09=09=09=20*=20could=20be=20vacuumed=20away=20at=20any=20time.=20=20= It's=20ok=20to=20check=0A+=09=09=09=09=09=20*=20the=20tuple=20because=20= we=20have=20a=20buffer=20lock=20for=20the=20page,=0A+=09=09=09=09=09=20*=20= but=20not=20safe=20to=20check=20the=20toast.=20=20We=20don't=20bother=0A= +=09=09=09=09=09=20*=20comparing=20against=20safe_xmin=20because=20the=20= VACUUM=20FULL=0A+=09=09=09=09=09=20*=20must=20have=20committed=20prior=20= to=20an=20upgrade=20and=20can't=20still=0A+=09=09=09=09=09=20*=20be=20= running.=0A+=09=09=09=09=09=20*/=0A+=09=09=09=09=09return=20true;=09/*=20= checkable=20*/=0A+=0A+=09=09=09=09case=20XID_ABORTED:=0A+=09=09=09=09=09= break;=0A=20=09=09=09}=0A=20=09=09}=0A-=09}=0A-=0A-=09if=20(!(infomask=20= &=20HEAP_XMAX_INVALID)=20&&=20!HEAP_XMAX_IS_LOCKED_ONLY(infomask))=0A-=09= {=0A-=09=09if=20(infomask=20&=20HEAP_XMAX_IS_MULTI)=0A+=09=09/*=20Used=20= by=20pre-9.0=20binary=20upgrades=20*/=0A+=09=09else=20if=20= (tuphdr->t_infomask=20&=20HEAP_MOVED_IN)=0A=20=09=09{=0A-=09=09=09= XidCommitStatus=20status;=0A-=09=09=09TransactionId=20xmax=20=3D=20= HeapTupleGetUpdateXid(tuphdr);=0A+=09=09=09xvac=20=3D=20= HeapTupleHeaderGetXvac(tuphdr);=0A=20=0A-=09=09=09switch=20= (get_xid_status(xmax,=20ctx,=20&status))=0A+=09=09=09switch=20= (get_xid_status(xvac,=20ctx,=20&xvac_status))=0A=20=09=09=09{=0A-=09=09=09= =09=09/*=20not=20LOCKED_ONLY,=20so=20it=20has=20to=20have=20an=20xmax=20= */=0A=20=09=09=09=09case=20XID_INVALID:=0A=20=09=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20pstrdup("xmax=20= is=20invalid"));=0A+=09=09=09=09=09=09=09=09=09=20=20pstrdup("old-style=20= VACUUM=20FULL=20transaction=20ID=20for=20moved=20in=20tuple=20is=20= invalid"));=0A=20=09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20= =09=09=09=09case=20XID_IN_FUTURE:=0A=20=09=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= psprintf("xmax=20%u=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A+=09=09= =09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20in=20tuple=20equals=20or=20exceeds=20= next=20valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09= =09=20=20=20xvac,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A=20=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A=20=09=09= =09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_RELMIN:=0A=20=09=09=09=09=09report_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20psprintf("xmax=20%u=20precedes=20relation=20= freeze=20threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xmax,=0A+=09=09=09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20= FULL=20transaction=20ID=20%u=20for=20moved=20in=20tuple=20precedes=20= relation=20freeze=20threshold=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09= =09=20=20=20xvac,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A=20=09=09=09=09=09=09=09= =09=09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A=20=09=09=09=09=09report_corruption(ctx,=0A-=09= =09=09=09=09=09=09=09=09=20=20psprintf("xmax=20%u=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20xmax,=0A+=09=09=09=09=09=09=09=09=09=20=20psprintf("old-style=20= VACUUM=20FULL=20transaction=20ID=20%u=20for=20moved=20in=20tuple=20= precedes=20oldest=20valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09= =09=09=09=09=09=09=20=20=20xvac,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20= =20=20EpochFromFullTransactionId(ctx->oldest_fxid),=0A=20=09=09=09=09=09=09= =09=09=09=09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_BOUNDS_OK:=0A-=09=09=09=09=09switch=20(status)=0A-=09=09=09=09=09{=0A= -=09=09=09=09=09=09case=20XID_IN_PROGRESS:=0A-=09=09=09=09=09=09case=20= XID_IS_CURRENT_XID:=0A-=09=09=09=09=09=09=09return=20true;=09/*=20= HEAPTUPLE_DELETE_IN_PROGRESS=20*/=0A-=09=09=09=09=09=09case=20= XID_COMMITTED:=0A-=09=09=09=09=09=09case=20XID_ABORTED:=0A-=09=09=09=09=09= =09=09return=20false;=09/*=20HEAPTUPLE_RECENTLY_DEAD=20or=0A-=09=09=09=09= =09=09=09=09=09=09=09=20*=20HEAPTUPLE_DEAD=20*/=0A-=09=09=09=09=09}=0A+=09= =09=09=09=09break;=0A=20=09=09=09}=0A=20=0A-=09=09=09/*=20Ok,=20the=20= tuple=20is=20live=20*/=0A+=09=09=09switch=20(xvac_status)=0A+=09=09=09{=0A= +=09=09=09=09case=20XID_IS_CURRENT_XID:=0A+=09=09=09=09=09= report_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20in=20tuple=20matches=20our=20current=20transaction=20ID",=0A+=09=09= =09=09=09=09=09=09=09=09=09=20=20=20xvac));=0A+=09=09=09=09=09return=20= false;=09/*=20corrupt=20*/=0A+=09=09=09=09case=20XID_IN_PROGRESS:=0A+=09=09= =09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20in=20tuple=20appears=20to=20be=20in=20progress",=0A+=09=09=09=09=09= =09=09=09=09=09=09=20=20=20xvac));=0A+=09=09=09=09=09return=20false;=09= /*=20corrupt=20*/=0A+=0A+=09=09=09=09case=20XID_COMMITTED:=0A+=09=09=09=09= =09break;=0A+=0A+=09=09=09=09case=20XID_ABORTED:=0A+=0A+=09=09=09=09=09= /*=0A+=09=09=09=09=09=20*=20The=20VACUUM=20FULL=20aborted,=20so=20this=20= tuple=20is=20dead=20and=0A+=09=09=09=09=09=20*=20could=20be=20vacuumed=20= away=20at=20any=20time.=20=20It's=20ok=20to=20check=0A+=09=09=09=09=09=20= *=20the=20tuple=20because=20we=20have=20a=20buffer=20lock=20for=20the=20= page,=0A+=09=09=09=09=09=20*=20but=20not=20safe=20to=20check=20the=20= toast.=0A+=09=09=09=09=09=20*/=0A+=09=09=09=09=09return=20true;=09/*=20= checkable=20*/=0A+=09=09=09}=0A+=09=09}=0A+=09=09else=20if=20= (xmin_status=20=3D=3D=20XID_IS_CURRENT_XID)=0A+=09=09{=0A+=09=09=09/*=0A= +=09=09=09=20*=20Don't=20check=20tuples=20from=20currently=20running=20= transactions,=20not=0A+=09=09=09=20*=20even=20our=20own.=0A+=09=09=09=20= */=0A+=09=09=09return=20false;=09=09/*=20checkable,=20but=20don't=20= check=20*/=0A+=09=09}=0A+=09=09else=20if=20(xmin_status=20=3D=3D=20= XID_IN_PROGRESS)=0A+=09=09{=0A+=09=09=09/*=20Don't=20check=20tuples=20= from=20currently=20running=20transactions=20*/=0A+=09=09=09return=20= false;=09=09/*=20uncheckable=20*/=0A+=09=09}=0A+=09=09else=20if=20= (xmin_status=20!=3D=20XID_COMMITTED)=0A+=09=09{=0A+=09=09=09/*=0A+=09=09=09= =20*=20Inserting=20transaction=20is=20not=20in=20progress,=20and=20not=20= committed,=20so=0A+=09=09=09=20*=20it=20either=20aborted=20or=20crashed.=20= We=20cannot=20check.=0A+=09=09=09=20*/=0A+=09=09=09return=20false;=09=09= /*=20uncheckable=20*/=0A=20=09=09}=0A-=09=09else=20if=20(!(infomask=20&=20= HEAP_XMAX_COMMITTED))=0A-=09=09=09return=20true;=09=09/*=20= HEAPTUPLE_DELETE_IN_PROGRESS=20or=0A-=09=09=09=09=09=09=09=09=20*=20= HEAPTUPLE_LIVE=20*/=0A-=09=09else=0A-=09=09=09return=20false;=09=09/*=20= HEAPTUPLE_RECENTLY_DEAD=20or=20HEAPTUPLE_DEAD=20*/=0A=20=09}=0A-=09= return=20true;=09=09=09=09/*=20not=20dead=20*/=0A+=0A+=09/*=0A+=09=20*=20= Okay,=20the=20inserter=20committed,=20so=20it=20was=20good=20at=20some=20= point.=20=20Now=20what=0A+=09=20*=20about=20the=20deleting=20= transaction?=0A+=09=20*/=0A+=0A+=09if=20(tuphdr->t_infomask=20&=20= HEAP_XMAX_IS_MULTI)=0A+=09{=0A+=09=09/*=0A+=09=09=20*=20xmax=20is=20a=20= multixact,=20so=20it=20should=20be=20within=20valid=20MXID=20range.=20=20= We=0A+=09=09=20*=20cannot=20safely=20look=20up=20the=20update=20xid=20if=20= the=20multixact=20is=20out=20of=0A+=09=09=20*=20bounds,=20and=20must=20= stop=20checking=20this=20tuple.=0A+=09=09=20*/=0A+=09=09xmax=20=3D=20= HeapTupleHeaderGetRawXmax(tuphdr);=0A+=09=09switch=20= (check_mxid_valid_in_rel(xmax,=20ctx))=0A+=09=09{=0A+=09=09=09case=20= XID_INVALID:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09= =09=20=20pstrdup("multitransaction=20ID=20is=20invalid"));=0A+=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20= XID_PRECEDES_RELMIN:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09=09=09= =09=09=09=09=20=20psprintf("multitransaction=20ID=20%u=20precedes=20= relation=20minimum=20multitransaction=20ID=20threshold=20%u",=0A+=09=09=09= =09=09=09=09=09=09=09=20=20=20xmax,=20ctx->relminmxid));=0A+=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09=09= =09=09=09=09=09=20=20psprintf("multitransaction=20ID=20%u=20precedes=20= oldest=20valid=20multitransaction=20ID=20threshold=20%u",=0A+=09=09=09=09= =09=09=09=09=09=09=20=20=20xmax,=20ctx->oldest_mxact));=0A+=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20XID_IN_FUTURE:=0A= +=09=09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20= psprintf("multitransaction=20ID=20%u=20equals=20or=20exceeds=20next=20= valid=20multitransaction=20ID=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=20= =20=20xmax,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20ctx->next_mxact));=0A= +=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20= XID_BOUNDS_OK:=0A+=09=09=09=09break;=0A+=09=09}=0A+=09}=0A+=0A+=09if=20= (tuphdr->t_infomask=20&=20HEAP_XMAX_INVALID)=0A+=09{=0A+=09=09/*=0A+=09=09= =20*=20This=20tuple=20is=20live.=20=20A=20concurrently=20running=20= transaction=20could=0A+=09=09=20*=20delete=20it=20before=20we=20get=20= around=20to=20checking=20the=20toast,=20but=20any=20such=0A+=09=09=20*=20= running=20transaction=20is=20surely=20not=20less=20than=20our=20= safe_xmin,=20so=20the=0A+=09=09=20*=20toast=20cannot=20be=20vacuumed=20= out=20from=20under=20us.=0A+=09=09=20*/=0A+=09=09ctx->tuple_is_volatile=20= =3D=20false;=0A+=09=09return=20true;=09=09=09/*=20checkable=20*/=0A+=09}=0A= +=0A+=09if=20(HEAP_XMAX_IS_LOCKED_ONLY(tuphdr->t_infomask))=0A+=09{=0A+=09= =09/*=0A+=09=09=20*=20"Deleting"=20xact=20really=20only=20locked=20it,=20= so=20the=20tuple=20is=20live=20in=20any=0A+=09=09=20*=20case.=20=20As=20= above,=20a=20concurrently=20running=20transaction=20could=20delete=0A+=09= =09=20*=20it,=20but=20it=20cannot=20be=20vacuumed=20out=20from=20under=20= us.=0A+=09=09=20*/=0A+=09=09ctx->tuple_is_volatile=20=3D=20false;=0A+=09=09= return=20true;=09=09=09/*=20checkable=20*/=0A+=09}=0A+=0A+=09if=20= (tuphdr->t_infomask=20&=20HEAP_XMAX_IS_MULTI)=0A+=09{=0A+=09=09/*=0A+=09=09= =20*=20We=20already=20checked=20above=20that=20this=20multixact=20is=20= within=20limits=20for=0A+=09=09=20*=20this=20table.=20=20Now=20check=20= the=20update=20xid=20from=20this=20multixact.=0A+=09=09=20*/=0A+=09=09= xmax=20=3D=20HeapTupleGetUpdateXid(tuphdr);=0A+=09=09switch=20= (get_xid_status(xmax,=20ctx,=20&xmax_status))=0A+=09=09{=0A+=09=09=09=09= /*=20not=20LOCKED_ONLY,=20so=20it=20has=20to=20have=20an=20xmax=20*/=0A+=09= =09=09case=20XID_INVALID:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09= =09=09=09=09=09=09=20=20pstrdup("update=20xid=20is=20invalid"));=0A+=09=09= =09=09return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20= XID_IN_FUTURE:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09= =09=09=20=20psprintf("update=20xid=20%u=20equals=20or=20exceeds=20next=20= valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=20=20= =20xmax,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20= XID_PRECEDES_RELMIN:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09=09=09= =09=09=09=09=20=20psprintf("update=20xid=20%u=20precedes=20relation=20= freeze=20threshold=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= xmax,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09=09= =09return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A+=09=09=09=09report_corruption(ctx,=0A+=09=09=09= =09=09=09=09=09=20=20psprintf("update=20xid=20%u=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=20=20= =20xmax,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= =09return=20false;=09/*=20corrupt=20*/=0A+=09=09=09case=20XID_BOUNDS_OK:=0A= +=09=09=09=09break;=0A+=09=09}=0A+=0A+=09=09switch=20(xmax_status)=0A+=09= =09{=0A+=09=09=09case=20XID_IS_CURRENT_XID:=0A+=09=09=09case=20= XID_IN_PROGRESS:=0A+=0A+=09=09=09=09/*=0A+=09=09=09=09=20*=20The=20= delete=20is=20in=20progress,=20so=20it=20cannot=20be=20visible=20to=20= our=0A+=09=09=09=09=20*=20snapshot.=0A+=09=09=09=09=20*/=0A+=09=09=09=09= ctx->tuple_is_volatile=20=3D=20false;=0A+=09=09=09=09return=20true;=09/*=20= checkable=20*/=0A+=09=09=09case=20XID_COMMITTED:=0A+=0A+=09=09=09=09/*=0A= +=09=09=09=09=20*=20The=20delete=20committed.=20=20Whether=20the=20toast=20= can=20be=20vacuumed=0A+=09=09=09=09=20*=20away=20depends=20on=20how=20= old=20the=20deleting=20transaction=20is.=0A+=09=09=09=09=20*/=0A+=09=09=09= =09ctx->tuple_is_volatile=20=3D=20TransactionIdPrecedes(xmax,=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09=09=09=20=20=20ctx->safe_xmin);=0A+=09=09=09= =09return=20true;=09/*=20checkable=20*/=0A+=09=09=09case=20XID_ABORTED:=0A= +=0A+=09=09=09=09/*=0A+=09=09=09=09=20*=20The=20delete=20aborted=20or=20= crashed.=20=20The=20tuple=20is=20still=20live.=0A+=09=09=09=09=20*/=0A+=09= =09=09=09ctx->tuple_is_volatile=20=3D=20false;=0A+=09=09=09=09return=20= true;=09/*=20checkable=20*/=0A+=09=09}=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= The=20tuple=20is=20deleted.=20=20Whether=20the=20toast=20can=20be=20= vacuumed=20away=20depends=0A+=09=20*=20on=20how=20old=20the=20deleting=20= transaction=20is.=0A+=09=20*/=0A+=09xmax=20=3D=20= HeapTupleHeaderGetRawXmax(tuphdr);=0A+=0A+=09switch=20= (get_xid_status(xmax,=20ctx,=20&xmax_status))=0A+=09{=0A+=09=09case=20= XID_IN_FUTURE:=0A+=09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09= =20=20psprintf("xmax=20%u=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A= +=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09return=20= false;=09=09/*=20corrupt=20*/=0A+=09=09case=20XID_PRECEDES_RELMIN:=0A+=09= =09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20= psprintf("xmax=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A+=09=09=09=09=09=09=09=09=09= =20=20=20EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09= =09=09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09= =09=09return=20false;=09=09/*=20corrupt=20*/=0A+=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A+=09=09=09report_corruption(ctx,=0A+=09=09=09=09= =09=09=09=20=20psprintf("xmax=20%u=20precedes=20oldest=20valid=20= transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A= +=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= return=20false;=09=09/*=20corrupt=20*/=0A+=09=09case=20XID_BOUNDS_OK:=0A= +=09=09case=20XID_INVALID:=0A+=09=09=09break;=0A+=09}=0A+=0A+=09switch=20= (xmax_status)=0A+=09{=0A+=09=09case=20XID_IS_CURRENT_XID:=0A+=09=09case=20= XID_IN_PROGRESS:=0A+=0A+=09=09=09/*=0A+=09=09=09=20*=20The=20delete=20is=20= in=20progress,=20so=20it=20cannot=20be=20visible=20to=20our=0A+=09=09=09=20= *=20snapshot.=0A+=09=09=09=20*/=0A+=09=09=09ctx->tuple_is_volatile=20=3D=20= false;=0A+=09=09=09return=20true;=09=09/*=20checkable=20*/=0A+=09=09case=20= XID_COMMITTED:=0A+=0A+=09=09=09/*=0A+=09=09=09=20*=20The=20delete=20= committed.=20=20Whether=20the=20toast=20can=20be=20vacuumed=20away=0A+=09= =09=09=20*=20depends=20on=20how=20old=20the=20deleting=20transaction=20= is.=0A+=09=09=09=20*/=0A+=09=09=09ctx->tuple_is_volatile=20=3D=20= TransactionIdPrecedes(xmax,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09=09= =20=20=20ctx->safe_xmin);=0A+=09=09=09return=20true;=09=09/*=20checkable=20= */=0A+=09=09case=20XID_ABORTED:=0A+=0A+=09=09=09/*=0A+=09=09=09=20*=20= The=20delete=20aborted=20or=20crashed.=20=20The=20tuple=20is=20still=20= live.=0A+=09=09=09=20*/=0A+=09=09=09ctx->tuple_is_volatile=20=3D=20= false;=0A+=09=09=09return=20true;=09=09/*=20checkable=20*/=0A+=09}=0A+=0A= +=09return=20false;=09=09=09=09/*=20not=20reached=20*/=0A=20}=0A=20=0A+=0A= =20/*=0A=20=20*=20Check=20the=20current=20toast=20tuple=20against=20the=20= state=20tracked=20in=20ctx,=20recording=0A=20=20*=20any=20corruption=20= found=20in=20ctx->tupstore.=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4 Content-Disposition: attachment; filename=v13-0003-Renaming-report_corruption-as-report_main_corrup.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v13-0003-Renaming-report_corruption-as-report_main_corrup.patch" Content-Transfer-Encoding: quoted-printable =46rom=20293c1e8c1a398bdea10a1e9d769e08177a0b75dd=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Mon,=2029=20Mar=202021=2014:37:20=20-0700=0ASubject:=20[PATCH=20= v13=203/4]=20Renaming=20report_corruption=20as=20report_main_corruption=0A= =0AIn=20preparation=20for=20checking=20toast=20as=20a=20separate=20pass=20= from=20checking=0Athe=20main=20heap,=20renaming=20report_corruption=20so=20= that=20the=20name=0Areport_toast_corruption=20can=20be=20added=20in=20= the=20next=20commit=20and=20fit=20in=0Anicely=20with=20this=20name.=0A=0A= This=20patch=20can=20probably=20be=20left=20out=20if=20the=20committer=20= believes=20it=0Acreates=20more=20git=20churn=20than=20it=20is=20worth.=0A= ---=0A=20contrib/amcheck/verify_heapam.c=20|=20486=20= ++++++++++++++++----------------=0A=201=20file=20changed,=20243=20= insertions(+),=20243=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/amcheck/verify_heapam.c=20b/contrib/amcheck/verify_heapam.c=0A= index=2059b13180d9..c5bde63ea7=20100644=0A---=20= a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-142,7=20+142,7=20@@=20static=20= bool=20check_tuple_attribute(HeapCheckContext=20*ctx);=0A=20static=20= bool=20check_tuple_header(HeapCheckContext=20*ctx);=0A=20static=20bool=20= check_tuple_visibility(HeapCheckContext=20*ctx);=0A=20=0A-static=20void=20= report_corruption(HeapCheckContext=20*ctx,=20char=20*msg);=0A+static=20= void=20report_main_corruption(HeapCheckContext=20*ctx,=20char=20*msg);=0A= =20static=20TupleDesc=20verify_heapam_tupdesc(void);=0A=20static=20= FullTransactionId=20FullTransactionIdFromXidAndCtx(TransactionId=20xid,=0A= =20=09=09=09=09=09=09=09=09=09=09=09=09=09=09const=20HeapCheckContext=20= *ctx);=0A@@=20-407,25=20+407,25=20@@=20verify_heapam(PG_FUNCTION_ARGS)=0A= =20=0A=20=09=09=09=09if=20(rdoffnum=20<=20FirstOffsetNumber)=0A=20=09=09=09= =09{=0A-=09=09=09=09=09report_corruption(&ctx,=0A-=09=09=09=09=09=09=09=09= =09=20=20psprintf("line=20pointer=20redirection=20to=20item=20at=20= offset=20%u=20precedes=20minimum=20offset=20%u",=0A-=09=09=09=09=09=09=09= =09=09=09=09=20=20=20(unsigned)=20rdoffnum,=0A-=09=09=09=09=09=09=09=09=09= =09=09=20=20=20(unsigned)=20FirstOffsetNumber));=0A+=09=09=09=09=09= report_main_corruption(&ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("line=20pointer=20redirection=20to=20item=20at=20offset=20%u=20= precedes=20minimum=20offset=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09= =09(unsigned)=20rdoffnum,=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09= (unsigned)=20FirstOffsetNumber));=0A=20=09=09=09=09=09continue;=0A=20=09=09= =09=09}=0A=20=09=09=09=09if=20(rdoffnum=20>=20maxoff)=0A=20=09=09=09=09{=0A= -=09=09=09=09=09report_corruption(&ctx,=0A-=09=09=09=09=09=09=09=09=09=20= =20psprintf("line=20pointer=20redirection=20to=20item=20at=20offset=20%u=20= exceeds=20maximum=20offset=20%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20(unsigned)=20rdoffnum,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= (unsigned)=20maxoff));=0A+=09=09=09=09=09report_main_corruption(&ctx,=0A= +=09=09=09=09=09=09=09=09=09=09=20=20=20psprintf("line=20pointer=20= redirection=20to=20item=20at=20offset=20%u=20exceeds=20maximum=20offset=20= %u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09(unsigned)=20rdoffnum,=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09(unsigned)=20maxoff));=0A=20=09=09= =09=09=09continue;=0A=20=09=09=09=09}=0A=20=09=09=09=09rditem=20=3D=20= PageGetItemId(ctx.page,=20rdoffnum);=0A=20=09=09=09=09if=20= (!ItemIdIsUsed(rditem))=0A-=09=09=09=09=09report_corruption(&ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20psprintf("line=20pointer=20redirection=20to=20= unused=20item=20at=20offset=20%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20(unsigned)=20rdoffnum));=0A+=09=09=09=09=09= report_main_corruption(&ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("line=20pointer=20redirection=20to=20unused=20item=20at=20= offset=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09(unsigned)=20= rdoffnum));=0A=20=09=09=09=09continue;=0A=20=09=09=09}=0A=20=0A@@=20= -435,26=20+435,26=20@@=20verify_heapam(PG_FUNCTION_ARGS)=0A=20=0A=20=09=09= =09if=20(ctx.lp_off=20!=3D=20MAXALIGN(ctx.lp_off))=0A=20=09=09=09{=0A-=09= =09=09=09report_corruption(&ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("line=20pointer=20to=20page=20offset=20%u=20is=20not=20= maximally=20aligned",=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= ctx.lp_off));=0A+=09=09=09=09report_main_corruption(&ctx,=0A+=09=09=09=09= =09=09=09=09=09=20=20=20psprintf("line=20pointer=20to=20page=20offset=20= %u=20is=20not=20maximally=20aligned",=0A+=09=09=09=09=09=09=09=09=09=09=09= =09ctx.lp_off));=0A=20=09=09=09=09continue;=0A=20=09=09=09}=0A=20=09=09=09= if=20(ctx.lp_len=20<=20MAXALIGN(SizeofHeapTupleHeader))=0A=20=09=09=09{=0A= -=09=09=09=09report_corruption(&ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("line=20pointer=20length=20%u=20is=20less=20than=20the=20= minimum=20tuple=20header=20size=20%u",=0A-=09=09=09=09=09=09=09=09=09=09=20= =20=20ctx.lp_len,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20(unsigned)=20= MAXALIGN(SizeofHeapTupleHeader)));=0A+=09=09=09=09= report_main_corruption(&ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("line=20pointer=20length=20%u=20is=20less=20than=20the=20= minimum=20tuple=20header=20size=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=09= =09ctx.lp_len,=0A+=09=09=09=09=09=09=09=09=09=09=09=09(unsigned)=20= MAXALIGN(SizeofHeapTupleHeader)));=0A=20=09=09=09=09continue;=0A=20=09=09= =09}=0A=20=09=09=09if=20(ctx.lp_off=20+=20ctx.lp_len=20>=20BLCKSZ)=0A=20=09= =09=09{=0A-=09=09=09=09report_corruption(&ctx,=0A-=09=09=09=09=09=09=09=09= =20=20psprintf("line=20pointer=20to=20page=20offset=20%u=20with=20length=20= %u=20ends=20beyond=20maximum=20page=20offset=20%u",=0A-=09=09=09=09=09=09= =09=09=09=09=20=20=20ctx.lp_off,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= ctx.lp_len,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20(unsigned)=20= BLCKSZ));=0A+=09=09=09=09report_main_corruption(&ctx,=0A+=09=09=09=09=09=09= =09=09=09=20=20=20psprintf("line=20pointer=20to=20page=20offset=20%u=20= with=20length=20%u=20ends=20beyond=20maximum=20page=20offset=20%u",=0A+=09= =09=09=09=09=09=09=09=09=09=09=09ctx.lp_off,=0A+=09=09=09=09=09=09=09=09=09= =09=09=09ctx.lp_len,=0A+=09=09=09=09=09=09=09=09=09=09=09=09(unsigned)=20= BLCKSZ));=0A=20=09=09=09=09continue;=0A=20=09=09=09}=0A=20=0A@@=20-517,7=20= +517,7=20@@=20sanity_check_relation(Relation=20rel)=0A=20=20*=20The=20= msg=20argument=20is=20pfree'd=20by=20this=20function.=0A=20=20*/=0A=20= static=20void=0A-report_corruption(HeapCheckContext=20*ctx,=20char=20= *msg)=0A+report_main_corruption(HeapCheckContext=20*ctx,=20char=20*msg)=0A= =20{=0A=20=09Datum=09=09values[HEAPCHECK_RELATION_COLS];=0A=20=09bool=09=09= nulls[HEAPCHECK_RELATION_COLS];=0A@@=20-599,17=20+599,17=20@@=20= check_tuple_header(HeapCheckContext=20*ctx)=0A=20=0A=20=09if=20= (ctx->tuphdr->t_hoff=20>=20ctx->lp_len)=0A=20=09{=0A-=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("data=20= begins=20at=20offset=20%u=20beyond=20the=20tuple=20length=20%u",=0A-=09=09= =09=09=09=09=09=09=20=20=20ctx->tuphdr->t_hoff,=20ctx->lp_len));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("data=20begins=20at=20offset=20%u=20beyond=20the=20tuple=20= length=20%u",=0A+=09=09=09=09=09=09=09=09=09=09ctx->tuphdr->t_hoff,=20= ctx->lp_len));=0A=20=09=09header_garbled=20=3D=20true;=0A=20=09}=0A=20=0A= =20=09if=20((ctx->tuphdr->t_infomask=20&=20HEAP_XMAX_COMMITTED)=20&&=0A=20= =09=09(ctx->tuphdr->t_infomask=20&=20HEAP_XMAX_IS_MULTI))=0A=20=09{=0A-=09= =09report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20pstrdup("multixact=20= should=20not=20be=20marked=20committed"));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= pstrdup("multixact=20should=20not=20be=20marked=20committed"));=0A=20=0A=20= =09=09/*=0A=20=09=09=20*=20This=20condition=20is=20clearly=20wrong,=20= but=20we=20do=20not=20consider=20the=20header=0A@@=20-626,21=20+626,21=20= @@=20check_tuple_header(HeapCheckContext=20*ctx)=0A=20=09if=20= (ctx->tuphdr->t_hoff=20!=3D=20expected_hoff)=0A=20=09{=0A=20=09=09if=20= ((infomask=20&=20HEAP_HASNULL)=20&&=20ctx->natts=20=3D=3D=201)=0A-=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20psprintf("tuple=20= data=20should=20begin=20at=20byte=20%u,=20but=20actually=20begins=20at=20= byte=20%u=20(1=20attribute,=20has=20nulls)",=0A-=09=09=09=09=09=09=09=09=09= =20=20=20expected_hoff,=20ctx->tuphdr->t_hoff));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("tuple=20data=20should=20begin=20at=20byte=20%u,=20but=20= actually=20begins=20at=20byte=20%u=20(1=20attribute,=20has=20nulls)",=0A= +=09=09=09=09=09=09=09=09=09=09=09expected_hoff,=20= ctx->tuphdr->t_hoff));=0A=20=09=09else=20if=20((infomask=20&=20= HEAP_HASNULL))=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09= =20=20psprintf("tuple=20data=20should=20begin=20at=20byte=20%u,=20but=20= actually=20begins=20at=20byte=20%u=20(%u=20attributes,=20has=20nulls)",=0A= -=09=09=09=09=09=09=09=09=09=20=20=20expected_hoff,=20= ctx->tuphdr->t_hoff,=20ctx->natts));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("tuple=20data=20should=20begin=20at=20byte=20%u,=20but=20= actually=20begins=20at=20byte=20%u=20(%u=20attributes,=20has=20nulls)",=0A= +=09=09=09=09=09=09=09=09=09=09=09expected_hoff,=20ctx->tuphdr->t_hoff,=20= ctx->natts));=0A=20=09=09else=20if=20(ctx->natts=20=3D=3D=201)=0A-=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20psprintf("tuple=20= data=20should=20begin=20at=20byte=20%u,=20but=20actually=20begins=20at=20= byte=20%u=20(1=20attribute,=20no=20nulls)",=0A-=09=09=09=09=09=09=09=09=09= =20=20=20expected_hoff,=20ctx->tuphdr->t_hoff));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("tuple=20data=20should=20begin=20at=20byte=20%u,=20but=20= actually=20begins=20at=20byte=20%u=20(1=20attribute,=20no=20nulls)",=0A+=09= =09=09=09=09=09=09=09=09=09=09expected_hoff,=20ctx->tuphdr->t_hoff));=0A=20= =09=09else=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=20= =20psprintf("tuple=20data=20should=20begin=20at=20byte=20%u,=20but=20= actually=20begins=20at=20byte=20%u=20(%u=20attributes,=20no=20nulls)",=0A= -=09=09=09=09=09=09=09=09=09=20=20=20expected_hoff,=20= ctx->tuphdr->t_hoff,=20ctx->natts));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("tuple=20data=20should=20begin=20at=20byte=20%u,=20but=20= actually=20begins=20at=20byte=20%u=20(%u=20attributes,=20no=20nulls)",=0A= +=09=09=09=09=09=09=09=09=09=09=09expected_hoff,=20ctx->tuphdr->t_hoff,=20= ctx->natts));=0A=20=09=09header_garbled=20=3D=20true;=0A=20=09}=0A=20=0A= @@=20-702,25=20+702,25=20@@=20check_tuple_visibility(HeapCheckContext=20= *ctx)=0A=20=09=09case=20XID_BOUNDS_OK:=0A=20=09=09=09break;=0A=20=09=09= case=20XID_IN_FUTURE:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09= =09=09=20=20psprintf("xmin=20%u=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09xmin,=0A+=09=09=09=09=09= =09=09=09=09=09=09EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09= =09=09=09=09=09=09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20= =09=09=09return=20false;=09=09/*=20corrupt=20*/=0A=20=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=20=20psprintf("xmin=20%u=20precedes=20oldest=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09xmin,=0A+=09=09=09=09=09=09=09= =09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09=09=09= =09=09=09=09=09=09=09XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09= =09=09return=20false;=09=09/*=20corrupt=20*/=0A=20=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09= =09=09=20=20psprintf("xmin=20%u=20precedes=20relation=20freeze=20= threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A-=09=09= =09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=09=09xmin,=0A+=09=09=09=09=09=09=09=09=09=09= =09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20=09=09=09= return=20false;=09=09/*=20corrupt=20*/=0A=20=09}=0A=20=0A@@=20-744,29=20= +744,29=20@@=20check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09=09= =09switch=20(get_xid_status(xvac,=20ctx,=20&xvac_status))=0A=20=09=09=09= {=0A=20=09=09=09=09case=20XID_INVALID:=0A-=09=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= pstrdup("old-style=20VACUUM=20FULL=20transaction=20ID=20for=20moved=20= off=20tuple=20is=20invalid"));=0A+=09=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= pstrdup("old-style=20VACUUM=20FULL=20transaction=20ID=20for=20moved=20= off=20tuple=20is=20invalid"));=0A=20=09=09=09=09=09return=20false;=09/*=20= corrupt=20*/=0A=20=09=09=09=09case=20XID_IN_FUTURE:=0A-=09=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20off=20tuple=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20xvac,=0A-=09=09= =09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09=09= =09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20off=20tuple=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09xvac,=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20=09=09=09=09= =09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20off=20tuple=20precedes=20relation=20= freeze=20threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09= =09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20off=20tuple=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09xvac,=0A+=09=09=09=09=09=09=09=09= =09=09=09=09=09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20=09=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20off=20tuple=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20xvac,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09= =09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20off=20tuple=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09xvac,=0A+=09=09=09=09=09= =09=09=09=09=09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09=09=09=09=09return=20= false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20XID_BOUNDS_OK:=0A=20=09= =09=09=09=09break;=0A@@=20-775,14=20+775,14=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09=09=09switch=20= (xvac_status)=0A=20=09=09=09{=0A=20=09=09=09=09case=20= XID_IS_CURRENT_XID:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20off=20tuple=20matches=20our=20= current=20transaction=20ID",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac));=0A+=09=09=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09= =09=09=09=09=20=20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20= ID=20%u=20for=20moved=20off=20tuple=20matches=20our=20current=20= transaction=20ID",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09xvac));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_IN_PROGRESS:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20= ID=20%u=20for=20moved=20off=20tuple=20appears=20to=20be=20in=20= progress",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20xvac));=0A+=09=09= =09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20off=20tuple=20appears=20to=20be=20in=20progress",=0A+=09=09=09=09= =09=09=09=09=09=09=09=09=09xvac));=0A=20=09=09=09=09=09return=20false;=09= /*=20corrupt=20*/=0A=20=0A=20=09=09=09=09case=20XID_COMMITTED:=0A@@=20= -810,29=20+810,29=20@@=20check_tuple_visibility(HeapCheckContext=20*ctx)=0A= =20=09=09=09switch=20(get_xid_status(xvac,=20ctx,=20&xvac_status))=0A=20=09= =09=09{=0A=20=09=09=09=09case=20XID_INVALID:=0A-=09=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20= pstrdup("old-style=20VACUUM=20FULL=20transaction=20ID=20for=20moved=20in=20= tuple=20is=20invalid"));=0A+=09=09=09=09=09report_main_corruption(ctx,=0A= +=09=09=09=09=09=09=09=09=09=09=20=20=20pstrdup("old-style=20VACUUM=20= FULL=20transaction=20ID=20for=20moved=20in=20tuple=20is=20invalid"));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_IN_FUTURE:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09= =09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20= %u=20for=20moved=20in=20tuple=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09=09= =09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20in=20tuple=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09xvac,=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20=09=09=09=09= =09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20in=20tuple=20precedes=20relation=20= freeze=20threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09= =09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20in=20tuple=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09xvac,=0A+=09=09=09=09=09=09=09=09= =09=09=09=09=09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20=09=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20in=20tuple=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=20= =20=20xvac,=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09= =09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20in=20tuple=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09xvac,=0A+=09=09=09=09=09= =09=09=09=09=09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09=09=09=09=09return=20= false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20XID_BOUNDS_OK:=0A=20=09= =09=09=09=09break;=0A@@=20-841,14=20+841,14=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09=09=09switch=20= (xvac_status)=0A=20=09=09=09{=0A=20=09=09=09=09case=20= XID_IS_CURRENT_XID:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20= transaction=20ID=20%u=20for=20moved=20in=20tuple=20matches=20our=20= current=20transaction=20ID",=0A-=09=09=09=09=09=09=09=09=09=09=09=20=20=20= xvac));=0A+=09=09=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09= =09=09=09=09=20=20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20= ID=20%u=20for=20moved=20in=20tuple=20matches=20our=20current=20= transaction=20ID",=0A+=09=09=09=09=09=09=09=09=09=09=09=09=09xvac));=0A=20= =09=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09=09case=20= XID_IN_PROGRESS:=0A-=09=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=09=20=20psprintf("old-style=20VACUUM=20FULL=20transaction=20= ID=20%u=20for=20moved=20in=20tuple=20appears=20to=20be=20in=20progress",=0A= -=09=09=09=09=09=09=09=09=09=09=09=20=20=20xvac));=0A+=09=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("old-style=20VACUUM=20FULL=20transaction=20ID=20%u=20for=20= moved=20in=20tuple=20appears=20to=20be=20in=20progress",=0A+=09=09=09=09=09= =09=09=09=09=09=09=09=09xvac));=0A=20=09=09=09=09=09return=20false;=09/*=20= corrupt=20*/=0A=20=0A=20=09=09=09=09case=20XID_COMMITTED:=0A@@=20-904,24=20= +904,24=20@@=20check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09=09= switch=20(check_mxid_valid_in_rel(xmax,=20ctx))=0A=20=09=09{=0A=20=09=09=09= case=20XID_INVALID:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=20=20pstrdup("multitransaction=20ID=20is=20invalid"));=0A+=09= =09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20= =20pstrdup("multitransaction=20ID=20is=20invalid"));=0A=20=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=20=20psprintf("multitransaction=20ID=20%u=20precedes=20= relation=20minimum=20multitransaction=20ID=20threshold=20%u",=0A-=09=09=09= =09=09=09=09=09=09=09=20=20=20xmax,=20ctx->relminmxid));=0A+=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20relation=20minimum=20= multitransaction=20ID=20threshold=20%u",=0A+=09=09=09=09=09=09=09=09=09=09= =09=09xmax,=20ctx->relminmxid));=0A=20=09=09=09=09return=20false;=09/*=20= corrupt=20*/=0A=20=09=09=09case=20XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20oldest=20valid=20= multitransaction=20ID=20threshold=20%u",=0A-=09=09=09=09=09=09=09=09=09=09= =20=20=20xmax,=20ctx->oldest_mxact));=0A+=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20oldest=20valid=20= multitransaction=20ID=20threshold=20%u",=0A+=09=09=09=09=09=09=09=09=09=09= =09=09xmax,=20ctx->oldest_mxact));=0A=20=09=09=09=09return=20false;=09/*=20= corrupt=20*/=0A=20=09=09=09case=20XID_IN_FUTURE:=0A-=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("multitransaction=20ID=20%u=20equals=20or=20exceeds=20next=20= valid=20multitransaction=20ID=20%u",=0A-=09=09=09=09=09=09=09=09=09=09=20= =20=20xmax,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20ctx->next_mxact));=0A= +=09=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("multitransaction=20ID=20%u=20equals=20or=20exceeds=20= next=20valid=20multitransaction=20ID=20%u",=0A+=09=09=09=09=09=09=09=09=09= =09=09=09xmax,=0A+=09=09=09=09=09=09=09=09=09=09=09=09ctx->next_mxact));=0A= =20=09=09=09=09return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09case=20= XID_BOUNDS_OK:=0A=20=09=09=09=09break;=0A@@=20-962,29=20+962,29=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09=09{=0A=20=09=09=09= =09/*=20not=20LOCKED_ONLY,=20so=20it=20has=20to=20have=20an=20xmax=20*/=0A= =20=09=09=09case=20XID_INVALID:=0A-=09=09=09=09report_corruption(ctx,=0A= -=09=09=09=09=09=09=09=09=20=20pstrdup("update=20xid=20is=20invalid"));=0A= +=09=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20= =20=20pstrdup("update=20xid=20is=20invalid"));=0A=20=09=09=09=09return=20= false;=09/*=20corrupt=20*/=0A=20=09=09=09case=20XID_IN_FUTURE:=0A-=09=09=09= =09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("update=20xid=20%u=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= xmax,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("update=20xid=20%u=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09xmax,=0A= +=09=09=09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20=09=09=09=09= return=20false;=09/*=20corrupt=20*/=0A=20=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=20=20psprintf("update=20xid=20%u=20precedes=20relation=20= freeze=20threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= xmax,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09=09= =09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("update=20xid=20%u=20precedes=20relation=20freeze=20threshold=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09=09=09= =09=09=09=09=09=09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09= =09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20=09=09=09=09return=20= false;=09/*=20corrupt=20*/=0A=20=09=09=09case=20XID_PRECEDES_CLUSTERMIN:=0A= -=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("update=20xid=20%u=20precedes=20oldest=20valid=20transaction=20= ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A-=09=09=09= =09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= =09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("update=20xid=20%u=20precedes=20oldest=20valid=20transaction=20= ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09= =09=09=09=09=09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A= +=09=09=09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09=09=09=09return=20= false;=09/*=20corrupt=20*/=0A=20=09=09=09case=20XID_BOUNDS_OK:=0A=20=09=09= =09=09break;=0A@@=20-1029,25=20+1029,25=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09switch=20= (get_xid_status(xmax,=20ctx,=20&xmax_status))=0A=20=09{=0A=20=09=09case=20= XID_IN_FUTURE:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09= =20=20psprintf("xmax=20%u=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmax=20%u=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09=09= =09=09=09=09=09=09EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09= =09=09=09=09=09=09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20= =09=09=09return=20false;=09=09/*=20corrupt=20*/=0A=20=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09= =09=09=20=20psprintf("xmax=20%u=20precedes=20relation=20freeze=20= threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A-=09=09= =09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmax=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09=09=09=09=09=09=09= =09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20=09=09=09= return=20false;=09=09/*=20corrupt=20*/=0A=20=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=20=20psprintf("xmax=20%u=20precedes=20oldest=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmax=20%u=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09=09=09=09= =09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09=09=09= =09=09=09=09=09=09=09XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09= =09=09return=20false;=09=09/*=20corrupt=20*/=0A=20=09=09case=20= XID_BOUNDS_OK:=0A=20=09=09case=20XID_INVALID:=0A@@=20-1114,16=20+1114,16=20= @@=20check_toast_tuple(HeapTuple=20toasttup,=20HeapCheckContext=20*ctx)=0A= =20=09=09=09=09=09=09=09=09=09=09=20ctx->toast_rel->rd_att,=20&isnull));=0A= =20=09if=20(isnull)=0A=20=09{=0A-=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=20=20pstrdup("toast=20chunk=20sequence=20number=20is=20= null"));=0A+=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20= =20=20pstrdup("toast=20chunk=20sequence=20number=20is=20null"));=0A=20=09= =09return;=0A=20=09}=0A=20=09chunk=20=3D=20= DatumGetPointer(fastgetattr(toasttup,=203,=0A=20=09=09=09=09=09=09=09=09=09= =09ctx->toast_rel->rd_att,=20&isnull));=0A=20=09if=20(isnull)=0A=20=09{=0A= -=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20pstrdup("toast=20= chunk=20data=20is=20null"));=0A+=09=09report_main_corruption(ctx,=0A+=09=09= =09=09=09=09=09=20=20=20pstrdup("toast=20chunk=20data=20is=20null"));=0A=20= =09=09return;=0A=20=09}=0A=20=09if=20(!VARATT_IS_EXTENDED(chunk))=0A@@=20= -1140,9=20+1140,9=20@@=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A=20=09=09/*=20should=20never=20happen=20*/=0A=20= =09=09uint32=09=09header=20=3D=20((varattrib_4b=20*)=20= chunk)->va_4byte.va_header;=0A=20=0A-=09=09report_corruption(ctx,=0A-=09=09= =09=09=09=09=20=20psprintf("corrupt=20extended=20toast=20chunk=20has=20= invalid=20varlena=20header:=20%0x=20(sequence=20number=20%d)",=0A-=09=09=09= =09=09=09=09=09=20=20=20header,=20curchunk));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("corrupt=20extended=20toast=20chunk=20has=20invalid=20varlena=20= header:=20%0x=20(sequence=20number=20%d)",=0A+=09=09=09=09=09=09=09=09=09= =09header,=20curchunk));=0A=20=09=09return;=0A=20=09}=0A=20=0A@@=20= -1151,16=20+1151,16=20@@=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A=20=09=20*/=0A=20=09if=20(curchunk=20!=3D=20= ctx->chunkno)=0A=20=09{=0A-=09=09report_corruption(ctx,=0A-=09=09=09=09=09= =09=20=20psprintf("toast=20chunk=20sequence=20number=20%u=20does=20not=20= match=20the=20expected=20sequence=20number=20%u",=0A-=09=09=09=09=09=09=09= =09=20=20=20curchunk,=20ctx->chunkno));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("toast=20chunk=20sequence=20number=20%u=20does=20not=20match=20= the=20expected=20sequence=20number=20%u",=0A+=09=09=09=09=09=09=09=09=09=09= curchunk,=20ctx->chunkno));=0A=20=09=09return;=0A=20=09}=0A=20=09if=20= (curchunk=20>=20ctx->endchunk)=0A=20=09{=0A-=09=09report_corruption(ctx,=0A= -=09=09=09=09=09=09=20=20psprintf("toast=20chunk=20sequence=20number=20= %u=20exceeds=20the=20end=20chunk=20sequence=20number=20%u",=0A-=09=09=09=09= =09=09=09=09=20=20=20curchunk,=20ctx->endchunk));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("toast=20chunk=20sequence=20number=20%u=20exceeds=20the=20end=20= chunk=20sequence=20number=20%u",=0A+=09=09=09=09=09=09=09=09=09=09= curchunk,=20ctx->endchunk));=0A=20=09=09return;=0A=20=09}=0A=20=0A@@=20= -1168,9=20+1168,9=20@@=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A=20=09=09:=20ctx->attrsize=20-=20= ((ctx->totalchunks=20-=201)=20*=20TOAST_MAX_CHUNK_SIZE);=0A=20=09if=20= (chunksize=20!=3D=20expected_size)=0A=20=09{=0A-=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("toast=20= chunk=20size=20%u=20differs=20from=20the=20expected=20size=20%u",=0A-=09=09= =09=09=09=09=09=09=20=20=20chunksize,=20expected_size));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("toast=20chunk=20size=20%u=20differs=20from=20the=20expected=20= size=20%u",=0A+=09=09=09=09=09=09=09=09=09=09chunksize,=20= expected_size));=0A=20=09=09return;=0A=20=09}=0A=20}=0A@@=20-1217,12=20= +1217,12=20@@=20check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=0A=20= =09if=20(ctx->tuphdr->t_hoff=20+=20ctx->offset=20>=20ctx->lp_len)=0A=20=09= {=0A-=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20= psprintf("attribute=20%u=20with=20length=20%u=20starts=20at=20offset=20= %u=20beyond=20total=20tuple=20length=20%u",=0A-=09=09=09=09=09=09=09=09=20= =20=20ctx->attnum,=0A-=09=09=09=09=09=09=09=09=20=20=20thisatt->attlen,=0A= -=09=09=09=09=09=09=09=09=20=20=20ctx->tuphdr->t_hoff=20+=20ctx->offset,=0A= -=09=09=09=09=09=09=09=09=20=20=20ctx->lp_len));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("attribute=20%u=20with=20length=20%u=20starts=20at=20offset=20= %u=20beyond=20total=20tuple=20length=20%u",=0A+=09=09=09=09=09=09=09=09=09= =09ctx->attnum,=0A+=09=09=09=09=09=09=09=09=09=09thisatt->attlen,=0A+=09=09= =09=09=09=09=09=09=09=09ctx->tuphdr->t_hoff=20+=20ctx->offset,=0A+=09=09=09= =09=09=09=09=09=09=09ctx->lp_len));=0A=20=09=09return=20false;=0A=20=09}=0A= =20=0A@@=20-1238,12=20+1238,12=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=09=09=09=09=09=09=09= =09=09=09=09tp=20+=20ctx->offset);=0A=20=09=09if=20(ctx->tuphdr->t_hoff=20= +=20ctx->offset=20>=20ctx->lp_len)=0A=20=09=09{=0A-=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20psprintf("attribute=20= %u=20with=20length=20%u=20ends=20at=20offset=20%u=20beyond=20total=20= tuple=20length=20%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20= ctx->attnum,=0A-=09=09=09=09=09=09=09=09=09=20=20=20thisatt->attlen,=0A-=09= =09=09=09=09=09=09=09=09=20=20=20ctx->tuphdr->t_hoff=20+=20ctx->offset,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20ctx->lp_len));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("attribute=20%u=20with=20length=20%u=20ends=20at=20offset=20%u=20= beyond=20total=20tuple=20length=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=09= ctx->attnum,=0A+=09=09=09=09=09=09=09=09=09=09=09thisatt->attlen,=0A+=09=09= =09=09=09=09=09=09=09=09=09ctx->tuphdr->t_hoff=20+=20ctx->offset,=0A+=09=09= =09=09=09=09=09=09=09=09=09ctx->lp_len));=0A=20=09=09=09return=20false;=0A= =20=09=09}=0A=20=09=09return=20true;=0A@@=20-1271,10=20+1271,10=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=0A=20=09=09if=20= (va_tag=20!=3D=20VARTAG_ONDISK)=0A=20=09=09{=0A-=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20psprintf("toasted=20= attribute=20%u=20has=20unexpected=20TOAST=20tag=20%u",=0A-=09=09=09=09=09= =09=09=09=09=20=20=20ctx->attnum,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= va_tag));=0A+=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09= =09=20=20=20psprintf("toasted=20attribute=20%u=20has=20unexpected=20= TOAST=20tag=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=09ctx->attnum,=0A+=09= =09=09=09=09=09=09=09=09=09=09va_tag));=0A=20=09=09=09/*=20We=20can't=20= know=20where=20the=20next=20attribute=20begins=20*/=0A=20=09=09=09return=20= false;=0A=20=09=09}=0A@@=20-1286,12=20+1286,12=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=0A=20=09if=20= (ctx->tuphdr->t_hoff=20+=20ctx->offset=20>=20ctx->lp_len)=0A=20=09{=0A-=09= =09report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("attribute=20= %u=20with=20length=20%u=20ends=20at=20offset=20%u=20beyond=20total=20= tuple=20length=20%u",=0A-=09=09=09=09=09=09=09=09=20=20=20ctx->attnum,=0A= -=09=09=09=09=09=09=09=09=20=20=20thisatt->attlen,=0A-=09=09=09=09=09=09=09= =09=20=20=20ctx->tuphdr->t_hoff=20+=20ctx->offset,=0A-=09=09=09=09=09=09=09= =09=20=20=20ctx->lp_len));=0A+=09=09report_main_corruption(ctx,=0A+=09=09= =09=09=09=09=09=20=20=20psprintf("attribute=20%u=20with=20length=20%u=20= ends=20at=20offset=20%u=20beyond=20total=20tuple=20length=20%u",=0A+=09=09= =09=09=09=09=09=09=09=09ctx->attnum,=0A+=09=09=09=09=09=09=09=09=09=09= thisatt->attlen,=0A+=09=09=09=09=09=09=09=09=09=09ctx->tuphdr->t_hoff=20= +=20ctx->offset,=0A+=09=09=09=09=09=09=09=09=09=09ctx->lp_len));=0A=20=0A= =20=09=09return=20false;=0A=20=09}=0A@@=20-1318,18=20+1318,18=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=09/*=20The=20tuple=20= header=20better=20claim=20to=20contain=20toasted=20values=20*/=0A=20=09= if=20(!(infomask=20&=20HEAP_HASEXTERNAL))=0A=20=09{=0A-=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("attribute=20= %u=20is=20external=20but=20tuple=20header=20flag=20HEAP_HASEXTERNAL=20= not=20set",=0A-=09=09=09=09=09=09=09=09=20=20=20ctx->attnum));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("attribute=20%u=20is=20external=20but=20tuple=20header=20flag=20= HEAP_HASEXTERNAL=20not=20set",=0A+=09=09=09=09=09=09=09=09=09=09= ctx->attnum));=0A=20=09=09return=20true;=0A=20=09}=0A=20=0A=20=09/*=20= The=20relation=20better=20have=20a=20toast=20table=20*/=0A=20=09if=20= (!ctx->rel->rd_rel->reltoastrelid)=0A=20=09{=0A-=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("attribute=20= %u=20is=20external=20but=20relation=20has=20no=20toast=20relation",=0A-=09= =09=09=09=09=09=09=09=20=20=20ctx->attnum));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("attribute=20%u=20is=20external=20but=20relation=20has=20no=20= toast=20relation",=0A+=09=09=09=09=09=09=09=09=09=09ctx->attnum));=0A=20=09= =09return=20true;=0A=20=09}=0A=20=0A@@=20-1374,13=20+1374,13=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=09=09= ctx->chunkno++;=0A=20=09}=0A=20=09if=20(!found_toasttup)=0A-=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("toasted=20= value=20for=20attribute=20%u=20missing=20from=20toast=20table",=0A-=09=09= =09=09=09=09=09=09=20=20=20ctx->attnum));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("toasted=20value=20for=20attribute=20%u=20missing=20from=20= toast=20table",=0A+=09=09=09=09=09=09=09=09=09=09ctx->attnum));=0A=20=09= else=20if=20(ctx->chunkno=20!=3D=20(ctx->endchunk=20+=201))=0A-=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("final=20= toast=20chunk=20number=20%u=20differs=20from=20expected=20value=20%u",=0A= -=09=09=09=09=09=09=09=09=20=20=20ctx->chunkno,=20(ctx->endchunk=20+=20= 1)));=0A+=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20= =20psprintf("final=20toast=20chunk=20number=20%u=20differs=20from=20= expected=20value=20%u",=0A+=09=09=09=09=09=09=09=09=09=09ctx->chunkno,=20= (ctx->endchunk=20+=201)));=0A=20=09systable_endscan_ordered(toastscan);=0A= =20=0A=20=09return=20true;=0A@@=20-1406,27=20+1406,27=20@@=20= check_tuple(HeapCheckContext=20*ctx)=0A=20=09=09case=20XID_BOUNDS_OK:=0A=20= =09=09=09break;=0A=20=09=09case=20XID_IN_FUTURE:=0A-=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20psprintf("xmin=20%u=20= equals=20or=20exceeds=20next=20valid=20transaction=20ID=20%u:%u",=0A-=09=09= =09=09=09=09=09=09=09=20=20=20xmin,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09xmin,=0A+=09=09=09=09=09= =09=09=09=09=09=09EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09= =09=09=09=09=09=09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20= =09=09=09fatal=20=3D=20true;=0A=20=09=09=09break;=0A=20=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=20=20psprintf("xmin=20%u=20precedes=20oldest=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09xmin,=0A+=09=09=09=09=09=09=09= =09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09=09=09= =09=09=09=09=09=09=09XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09= =09=09fatal=20=3D=20true;=0A=20=09=09=09break;=0A=20=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09= =09=09=20=20psprintf("xmin=20%u=20precedes=20relation=20freeze=20= threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=20=20=20xmin,=0A-=09=09= =09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=09=09xmin,=0A+=09=09=09=09=09=09=09=09=09=09= =09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20=09=09=09= fatal=20=3D=20true;=0A=20=09=09=09break;=0A=20=09}=0A@@=20-1439,27=20= +1439,27=20@@=20check_tuple(HeapCheckContext=20*ctx)=0A=20=09=09switch=20= (check_mxid_valid_in_rel(xmax,=20ctx))=0A=20=09=09{=0A=20=09=09=09case=20= XID_INVALID:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09= =09=20=20pstrdup("multitransaction=20ID=20is=20invalid"));=0A+=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= pstrdup("multitransaction=20ID=20is=20invalid"));=0A=20=09=09=09=09fatal=20= =3D=20true;=0A=20=09=09=09=09break;=0A=20=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=20=20psprintf("multitransaction=20ID=20%u=20precedes=20= relation=20minimum=20multitransaction=20ID=20threshold=20%u",=0A-=09=09=09= =09=09=09=09=09=09=09=20=20=20xmax,=20ctx->relminmxid));=0A+=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20relation=20minimum=20= multitransaction=20ID=20threshold=20%u",=0A+=09=09=09=09=09=09=09=09=09=09= =09=09xmax,=20ctx->relminmxid));=0A=20=09=09=09=09fatal=20=3D=20true;=0A=20= =09=09=09=09break;=0A=20=09=09=09case=20XID_PRECEDES_CLUSTERMIN:=0A-=09=09= =09=09report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20oldest=20valid=20= multitransaction=20ID=20threshold=20%u",=0A-=09=09=09=09=09=09=09=09=09=09= =20=20=20xmax,=20ctx->oldest_mxact));=0A+=09=09=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20oldest=20valid=20= multitransaction=20ID=20threshold=20%u",=0A+=09=09=09=09=09=09=09=09=09=09= =09=09xmax,=20ctx->oldest_mxact));=0A=20=09=09=09=09fatal=20=3D=20true;=0A= =20=09=09=09=09break;=0A=20=09=09=09case=20XID_IN_FUTURE:=0A-=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20= psprintf("multitransaction=20ID=20%u=20equals=20or=20exceeds=20next=20= valid=20multitransaction=20ID=20%u",=0A-=09=09=09=09=09=09=09=09=09=09=20= =20=20xmax,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20ctx->next_mxact));=0A= +=09=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("multitransaction=20ID=20%u=20equals=20or=20exceeds=20= next=20valid=20multitransaction=20ID=20%u",=0A+=09=09=09=09=09=09=09=09=09= =09=09=09xmax,=0A+=09=09=09=09=09=09=09=09=09=09=09=09ctx->next_mxact));=0A= =20=09=09=09=09fatal=20=3D=20true;=0A=20=09=09=09=09break;=0A=20=09=09=09= case=20XID_BOUNDS_OK:=0A@@=20-1478,27=20+1478,27=20@@=20= check_tuple(HeapCheckContext=20*ctx)=0A=20=09=09=09case=20XID_BOUNDS_OK:=0A= =20=09=09=09=09break;=0A=20=09=09=09case=20XID_IN_FUTURE:=0A-=09=09=09=09= report_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20psprintf("xmax=20= %u=20equals=20or=20exceeds=20next=20valid=20transaction=20ID=20%u:%u",=0A= -=09=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A-=09=09=09=09=09=09=09=09= =09=09=20=20=20EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09= =09=09=09=09=09=09=20=20=20XidFromFullTransactionId(ctx->next_fxid)));=0A= +=09=09=09=09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20= =20=20psprintf("xmax=20%u=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=20%u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09xmax,=0A= +=09=09=09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->next_fxid),=0A+=09=09=09=09=09=09=09=09=09= =09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A=20=09=09=09=09= fatal=20=3D=20true;=0A=20=09=09=09=09break;=0A=20=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09= =09=09=09=09=09=20=20psprintf("xmax=20%u=20precedes=20oldest=20valid=20= transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= xmax,=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->oldest_fxid)));=0A+=09=09=09= =09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmax=20%u=20precedes=20oldest=20valid=20transaction=20ID=20= %u:%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09=09=09= =09=09=09=09=09=09EpochFromFullTransactionId(ctx->oldest_fxid),=0A+=09=09= =09=09=09=09=09=09=09=09=09=09= XidFromFullTransactionId(ctx->oldest_fxid)));=0A=20=09=09=09=09fatal=20=3D= =20true;=0A=20=09=09=09=09break;=0A=20=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09report_corruption(ctx,=0A-=09=09=09=09= =09=09=09=09=20=20psprintf("xmax=20%u=20precedes=20relation=20freeze=20= threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=20=20=20xmax,=0A-=09= =09=09=09=09=09=09=09=09=09=20=20=20= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=09=20=20=20XidFromFullTransactionId(ctx->relfrozenfxid)));=0A+=09=09=09= =09report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmax=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= +=09=09=09=09=09=09=09=09=09=09=09=09xmax,=0A+=09=09=09=09=09=09=09=09=09= =09=09=09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A+=09=09=09=09=09= =09=09=09=09=09=09=09XidFromFullTransactionId(ctx->relfrozenfxid)));=0A=20= =09=09=09=09fatal=20=3D=20true;=0A=20=09=09}=0A=20=09}=0A@@=20-1533,10=20= +1533,10=20@@=20check_tuple(HeapCheckContext=20*ctx)=0A=20=09=20*/=0A=20=09= if=20(RelationGetDescr(ctx->rel)->natts=20<=20ctx->natts)=0A=20=09{=0A-=09= =09report_corruption(ctx,=0A-=09=09=09=09=09=09=20=20psprintf("number=20= of=20attributes=20%u=20exceeds=20maximum=20expected=20for=20table=20%u",=0A= -=09=09=09=09=09=09=09=09=20=20=20ctx->natts,=0A-=09=09=09=09=09=09=09=09= =20=20=20RelationGetDescr(ctx->rel)->natts));=0A+=09=09= report_main_corruption(ctx,=0A+=09=09=09=09=09=09=09=20=20=20= psprintf("number=20of=20attributes=20%u=20exceeds=20maximum=20expected=20= for=20table=20%u",=0A+=09=09=09=09=09=09=09=09=09=09ctx->natts,=0A+=09=09= =09=09=09=09=09=09=09=09RelationGetDescr(ctx->rel)->natts));=0A=20=09=09= return;=0A=20=09}=0A=20=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4 Content-Disposition: attachment; filename=v13-0004-Checking-toast-separately-from-the-main-table.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v13-0004-Checking-toast-separately-from-the-main-table.patch" Content-Transfer-Encoding: quoted-printable =46rom=20f6399dcd6e37cd29d3df03eeca5c557843d97db5=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Mon,=2029=20Mar=202021=2014:40:45=20-0700=0ASubject:=20[PATCH=20= v13=204/4]=20Checking=20toast=20separately=20from=20the=20main=20table.=0A= =0ARather=20than=20checking=20toasted=20attributes=20as=20we=20find=20= them,=20creating=20a=0Alist=20of=20them=20and=20checking=20all=20the=20= toast=20in=20the=20list=20after=20releasing=0Athe=20buffer=20lock=20for=20= each=20main=20table=20page.=0A---=0A=20contrib/amcheck/verify_heapam.c=20= =20|=20415=20+++++++++++++++----------------=0A=20= src/tools/pgindent/typedefs.list=20|=20=20=201=20+=0A=202=20files=20= changed,=20201=20insertions(+),=20215=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/amcheck/verify_heapam.c=20b/contrib/amcheck/verify_heapam.c=0A= index=20c5bde63ea7..e3163e4bfa=20100644=0A---=20= a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-58,6=20+58,26=20@@=20typedef=20= enum=20SkipPages=0A=20=09SKIP_PAGES_NONE=0A=20}=20SkipPages;=0A=20=0A+/*=0A= +=20*=20Struct=20holding=20information=20necessary=20to=20check=20a=20= toasted=20attribute,=20including=0A+=20*=20the=20toast=20pointer,=20= state=20about=20the=20current=20toast=20chunk=20being=20checked,=20and=0A= +=20*=20the=20location=20in=20the=20main=20table=20of=20the=20toasted=20= attribute.=20=20We=20have=20to=20track=0A+=20*=20the=20tuple's=20= location=20in=20the=20main=20table=20for=20reporting=20purposes=20= because=20by=20the=0A+=20*=20time=20the=20toast=20is=20checked=20our=20= HeapCheckContext=20will=20no=20longer=20be=20pointing=20to=0A+=20*=20the=20= relevant=20tuple.=0A+=20*/=0A+typedef=20struct=20ToastCheckContext=0A+{=0A= +=09struct=20varatt_external=20toast_pointer;=0A+=09BlockNumber=20blkno;=09= =09=09/*=20block=20in=20main=20table=20*/=0A+=09OffsetNumber=20offnum;=09= =09/*=20offset=20in=20main=20table=20*/=0A+=09AttrNumber=09attnum;=09=09=09= /*=20attribute=20in=20main=20table=20*/=0A+=09int32=09=09chunkno;=09=09= /*=20chunk=20number=20in=20toast=20table=20*/=0A+=09int32=09=09attrsize;=09= =09/*=20size=20of=20toasted=20attribute=20*/=0A+=09int32=09=09endchunk;=09= =09/*=20last=20chunk=20number=20in=20toast=20table=20*/=0A+=09int32=09=09= totalchunks;=09/*=20total=20chunks=20in=20toast=20table=20*/=0A+}=20= ToastCheckContext;=0A+=0A=20/*=0A=20=20*=20Struct=20holding=20the=20= running=20context=20information=20during=0A=20=20*=20a=20lifetime=20of=20= a=20verify_heapam=20execution.=0A@@=20-119,11=20+139,11=20@@=20typedef=20= struct=20HeapCheckContext=0A=20=09/*=20True=20if=20toast=20for=20this=20= tuple=20could=20be=20vacuumed=20away=20*/=0A=20=09bool=09=09= tuple_is_volatile;=0A=20=0A-=09/*=20Values=20for=20iterating=20over=20= toast=20for=20the=20attribute=20*/=0A-=09int32=09=09chunkno;=0A-=09int32=09= =09attrsize;=0A-=09int32=09=09endchunk;=0A-=09int32=09=09totalchunks;=0A= +=09/*=0A+=09=20*=20List=20of=20ToastCheckContext=20structs=20for=20= toasted=20attributes=20which=20are=20not=0A+=09=20*=20in=20danger=20of=20= being=20vacuumed=20way=20and=20should=20be=20checked=0A+=09=20*/=0A+=09= List=09=20=20=20*toasted_attributes;=0A=20=0A=20=09/*=20Whether=20= verify_heapam=20has=20yet=20encountered=20any=20corrupt=20tuples=20*/=0A=20= =09bool=09=09is_corrupt;=0A@@=20-136,13=20+156,18=20@@=20typedef=20= struct=20HeapCheckContext=0A=20/*=20Internal=20implementation=20*/=0A=20= static=20void=20sanity_check_relation(Relation=20rel);=0A=20static=20= void=20check_tuple(HeapCheckContext=20*ctx);=0A-static=20void=20= check_toast_tuple(HeapTuple=20toasttup,=20HeapCheckContext=20*ctx);=0A= +static=20void=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx,=0A+=09=09=09=09=09=09=09=20=20ToastCheckContext=20= *tctx);=0A=20=0A-static=20bool=20check_tuple_attribute(HeapCheckContext=20= *ctx);=0A=20static=20bool=20check_tuple_header(HeapCheckContext=20*ctx);=0A= =20static=20bool=20check_tuple_visibility(HeapCheckContext=20*ctx);=0A=20= =0A+static=20bool=20check_tuple_attribute(HeapCheckContext=20*ctx);=0A= +static=20void=20check_toasted_attributes(HeapCheckContext=20*ctx);=0A+=0A= =20static=20void=20report_main_corruption(HeapCheckContext=20*ctx,=20= char=20*msg);=0A+static=20void=20= report_toast_corruption(HeapCheckContext=20*ctx,=0A+=09=09=09=09=09=09=09= =09=09ToastCheckContext=20*tctx,=20char=20*msg);=0A=20static=20TupleDesc=20= verify_heapam_tupdesc(void);=0A=20static=20FullTransactionId=20= FullTransactionIdFromXidAndCtx(TransactionId=20xid,=0A=20=09=09=09=09=09=09= =09=09=09=09=09=09=09=09const=20HeapCheckContext=20*ctx);=0A@@=20-253,6=20= +278,7=20@@=20verify_heapam(PG_FUNCTION_ARGS)=0A=20=0A=20=09memset(&ctx,=20= 0,=20sizeof(HeapCheckContext));=0A=20=09ctx.cached_xid=20=3D=20= InvalidTransactionId;=0A+=09ctx.toasted_attributes=20=3D=20NIL;=0A=20=0A=20= =09/*=0A=20=09=20*=20Any=20xmin=20newer=20than=20the=20xmin=20of=20our=20= snapshot=20can't=20become=20all-visible=0A@@=20-469,6=20+495,14=20@@=20= verify_heapam(PG_FUNCTION_ARGS)=0A=20=09=09/*=20clean=20up=20*/=0A=20=09=09= UnlockReleaseBuffer(ctx.buffer);=0A=20=0A+=09=09/*=0A+=09=09=20*=20Check=20= any=20toast=20pointers=20from=20the=20page=20whose=20lock=20we=20just=20= released=0A+=09=09=20*=20and=20reset=20the=20list=20to=20NIL.=0A+=09=09=20= */=0A+=09=09if=20(ctx.toasted_attributes=20!=3D=20NIL)=0A+=09=09=09= check_toasted_attributes(&ctx);=0A+=09=09Assert(ctx.toasted_attributes=20= =3D=3D=20NIL);=0A+=0A=20=09=09if=20(on_error_stop=20&&=20ctx.is_corrupt)=0A= =20=09=09=09break;=0A=20=09}=0A@@=20-510,14=20+544,13=20@@=20= sanity_check_relation(Relation=20rel)=0A=20}=0A=20=0A=20/*=0A-=20*=20= Record=20a=20single=20corruption=20found=20in=20the=20table.=20=20The=20= values=20in=20ctx=20should=0A-=20*=20reflect=20the=20location=20of=20the=20= corruption,=20and=20the=20msg=20argument=20should=20contain=0A-=20*=20a=20= human-readable=20description=20of=20the=20corruption.=0A-=20*=0A-=20*=20= The=20msg=20argument=20is=20pfree'd=20by=20this=20function.=0A+=20*=20= Shared=20internal=20implementation=20for=20report_main_corruption=20and=0A= +=20*=20report_toast_corruption.=0A=20=20*/=0A=20static=20void=0A= -report_main_corruption(HeapCheckContext=20*ctx,=20char=20*msg)=0A= +report_corruption(Tuplestorestate=20*tupstore,=20TupleDesc=20tupdesc,=0A= +=09=09=09=09=20=20BlockNumber=20blkno,=20OffsetNumber=20offnum,=20= AttrNumber=20attnum,=0A+=09=09=09=09=20=20char=20*msg)=0A=20{=0A=20=09= Datum=09=09values[HEAPCHECK_RELATION_COLS];=0A=20=09bool=09=09= nulls[HEAPCHECK_RELATION_COLS];=0A@@=20-525,10=20+558,10=20@@=20= report_main_corruption(HeapCheckContext=20*ctx,=20char=20*msg)=0A=20=0A=20= =09MemSet(values,=200,=20sizeof(values));=0A=20=09MemSet(nulls,=200,=20= sizeof(nulls));=0A-=09values[0]=20=3D=20Int64GetDatum(ctx->blkno);=0A-=09= values[1]=20=3D=20Int32GetDatum(ctx->offnum);=0A-=09values[2]=20=3D=20= Int32GetDatum(ctx->attnum);=0A-=09nulls[2]=20=3D=20(ctx->attnum=20<=20= 0);=0A+=09values[0]=20=3D=20Int64GetDatum(blkno);=0A+=09values[1]=20=3D=20= Int32GetDatum(offnum);=0A+=09values[2]=20=3D=20Int32GetDatum(attnum);=0A= +=09nulls[2]=20=3D=20(attnum=20<=200);=0A=20=09values[3]=20=3D=20= CStringGetTextDatum(msg);=0A=20=0A=20=09/*=0A@@=20-541,8=20+574,39=20@@=20= report_main_corruption(HeapCheckContext=20*ctx,=20char=20*msg)=0A=20=09=20= */=0A=20=09pfree(msg);=0A=20=0A-=09tuple=20=3D=20= heap_form_tuple(ctx->tupdesc,=20values,=20nulls);=0A-=09= tuplestore_puttuple(ctx->tupstore,=20tuple);=0A+=09tuple=20=3D=20= heap_form_tuple(tupdesc,=20values,=20nulls);=0A+=09= tuplestore_puttuple(tupstore,=20tuple);=0A+}=0A+=0A+/*=0A+=20*=20Record=20= a=20single=20corruption=20found=20in=20the=20main=20table.=20=20The=20= values=20in=20ctx=20should=0A+=20*=20indicate=20the=20location=20of=20= the=20corruption,=20and=20the=20msg=20argument=20should=20contain=0A+=20= *=20a=20human-readable=20description=20of=20the=20corruption.=0A+=20*=0A= +=20*=20The=20msg=20argument=20is=20pfree'd=20by=20this=20function.=0A+=20= */=0A+static=20void=0A+report_main_corruption(HeapCheckContext=20*ctx,=20= char=20*msg)=0A+{=0A+=09report_corruption(ctx->tupstore,=20ctx->tupdesc,=20= ctx->blkno,=20ctx->offnum,=0A+=09=09=09=09=09=20=20ctx->attnum,=20msg);=0A= +=09ctx->is_corrupt=20=3D=20true;=0A+}=0A+=0A+/*=0A+=20*=20Record=20= corruption=20found=20in=20the=20toast=20table.=20=20The=20values=20in=20= tctx=20should=0A+=20*=20indicate=20the=20location=20in=20the=20main=20= table=20where=20the=20toast=20pointer=20was=0A+=20*=20encountered,=20and=20= the=20msg=20argument=20should=20contain=20a=20human-readable=0A+=20*=20= description=20of=20the=20toast=20table=20corruption.=0A+=20*=0A+=20*=20= As=20above,=20the=20msg=20argument=20is=20pfree'd=20by=20this=20= function.=0A+=20*/=0A+static=20void=0A= +report_toast_corruption(HeapCheckContext=20*ctx,=20ToastCheckContext=20= *tctx,=0A+=09=09=09=09=09=09char=20*msg)=0A+{=0A+=09= report_corruption(ctx->tupstore,=20ctx->tupdesc,=20tctx->blkno,=20= tctx->offnum,=0A+=09=09=09=09=09=20=20tctx->attnum,=20msg);=0A=20=09= ctx->is_corrupt=20=3D=20true;=0A=20}=0A=20=0A@@=20-1086,7=20+1150,6=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09return=20false;=09= =09=09=09/*=20not=20reached=20*/=0A=20}=0A=20=0A-=0A=20/*=0A=20=20*=20= Check=20the=20current=20toast=20tuple=20against=20the=20state=20tracked=20= in=20ctx,=20recording=0A=20=20*=20any=20corruption=20found=20in=20= ctx->tupstore.=0A@@=20-1099,7=20+1162,8=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=20*=20as=20each=20= toast=20tuple=20having=20its=20varlena=20structure=20sanity=20checked.=0A= =20=20*/=0A=20static=20void=0A-check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A+check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx,=0A+=09=09=09=09=20=20ToastCheckContext=20*tctx)=0A= =20{=0A=20=09int32=09=09curchunk;=0A=20=09Pointer=09=09chunk;=0A@@=20= -1114,16=20+1178,16=20@@=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A=20=09=09=09=09=09=09=09=09=09=09=20= ctx->toast_rel->rd_att,=20&isnull));=0A=20=09if=20(isnull)=0A=20=09{=0A-=09= =09report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= pstrdup("toast=20chunk=20sequence=20number=20is=20null"));=0A+=09=09= report_toast_corruption(ctx,=20tctx,=0A+=09=09=09=09=09=09=09=09= pstrdup("toast=20chunk=20sequence=20number=20is=20null"));=0A=20=09=09= return;=0A=20=09}=0A=20=09chunk=20=3D=20= DatumGetPointer(fastgetattr(toasttup,=203,=0A=20=09=09=09=09=09=09=09=09=09= =09ctx->toast_rel->rd_att,=20&isnull));=0A=20=09if=20(isnull)=0A=20=09{=0A= -=09=09report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= pstrdup("toast=20chunk=20data=20is=20null"));=0A+=09=09= report_toast_corruption(ctx,=20tctx,=0A+=09=09=09=09=09=09=09=09= pstrdup("toast=20chunk=20data=20is=20null"));=0A=20=09=09return;=0A=20=09= }=0A=20=09if=20(!VARATT_IS_EXTENDED(chunk))=0A@@=20-1140,37=20+1204,37=20= @@=20check_toast_tuple(HeapTuple=20toasttup,=20HeapCheckContext=20*ctx)=0A= =20=09=09/*=20should=20never=20happen=20*/=0A=20=09=09uint32=09=09header=20= =3D=20((varattrib_4b=20*)=20chunk)->va_4byte.va_header;=0A=20=0A-=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= psprintf("corrupt=20extended=20toast=20chunk=20has=20invalid=20varlena=20= header:=20%0x=20(sequence=20number=20%d)",=0A-=09=09=09=09=09=09=09=09=09= =09header,=20curchunk));=0A+=09=09report_toast_corruption(ctx,=20tctx,=0A= +=09=09=09=09=09=09=09=09psprintf("corrupt=20extended=20toast=20chunk=20= has=20invalid=20varlena=20header:=20%0x=20(sequence=20number=20%d)",=0A+=09= =09=09=09=09=09=09=09=09=09=20header,=20curchunk));=0A=20=09=09return;=0A= =20=09}=0A=20=0A=20=09/*=0A=20=09=20*=20Some=20checks=20on=20the=20data=20= we've=20found=0A=20=09=20*/=0A-=09if=20(curchunk=20!=3D=20ctx->chunkno)=0A= +=09if=20(curchunk=20!=3D=20tctx->chunkno)=0A=20=09{=0A-=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= psprintf("toast=20chunk=20sequence=20number=20%u=20does=20not=20match=20= the=20expected=20sequence=20number=20%u",=0A-=09=09=09=09=09=09=09=09=09=09= curchunk,=20ctx->chunkno));=0A+=09=09report_toast_corruption(ctx,=20= tctx,=0A+=09=09=09=09=09=09=09=09psprintf("toast=20chunk=20sequence=20= number=20%u=20does=20not=20match=20the=20expected=20sequence=20number=20= %u",=0A+=09=09=09=09=09=09=09=09=09=09=20curchunk,=20tctx->chunkno));=0A=20= =09=09return;=0A=20=09}=0A-=09if=20(curchunk=20>=20ctx->endchunk)=0A+=09= if=20(curchunk=20>=20tctx->endchunk)=0A=20=09{=0A-=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= psprintf("toast=20chunk=20sequence=20number=20%u=20exceeds=20the=20end=20= chunk=20sequence=20number=20%u",=0A-=09=09=09=09=09=09=09=09=09=09= curchunk,=20ctx->endchunk));=0A+=09=09report_toast_corruption(ctx,=20= tctx,=0A+=09=09=09=09=09=09=09=09psprintf("toast=20chunk=20sequence=20= number=20%u=20exceeds=20the=20end=20chunk=20sequence=20number=20%u",=0A+=09= =09=09=09=09=09=09=09=09=09=20curchunk,=20tctx->endchunk));=0A=20=09=09= return;=0A=20=09}=0A=20=0A-=09expected_size=20=3D=20curchunk=20<=20= ctx->totalchunks=20-=201=20?=20TOAST_MAX_CHUNK_SIZE=0A-=09=09:=20= ctx->attrsize=20-=20((ctx->totalchunks=20-=201)=20*=20= TOAST_MAX_CHUNK_SIZE);=0A+=09expected_size=20=3D=20curchunk=20<=20= tctx->totalchunks=20-=201=20?=20TOAST_MAX_CHUNK_SIZE=0A+=09=09:=20= tctx->attrsize=20-=20((tctx->totalchunks=20-=201)=20*=20= TOAST_MAX_CHUNK_SIZE);=0A=20=09if=20(chunksize=20!=3D=20expected_size)=0A= =20=09{=0A-=09=09report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20= =20psprintf("toast=20chunk=20size=20%u=20differs=20from=20the=20expected=20= size=20%u",=0A-=09=09=09=09=09=09=09=09=09=09chunksize,=20= expected_size));=0A+=09=09report_toast_corruption(ctx,=20tctx,=0A+=09=09=09= =09=09=09=09=09psprintf("toast=20chunk=20size=20%u=20differs=20from=20= the=20expected=20size=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=20= chunksize,=20expected_size));=0A=20=09=09return;=0A=20=09}=0A=20}=0A@@=20= -1180,17=20+1244,17=20@@=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A=20=20*=20found=20in=20ctx->tupstore.=0A=20=20= *=0A=20=20*=20This=20function=20follows=20the=20logic=20performed=20by=20= heap_deform_tuple(),=20and=20in=20the=0A-=20*=20case=20of=20a=20toasted=20= value,=20optionally=20continues=20along=20the=20logic=20of=0A-=20*=20= detoast_external_attr(),=20checking=20for=20any=20conditions=20that=20= would=20result=20in=0A-=20*=20either=20of=20those=20functions=20= Asserting=20or=20crashing=20the=20backend.=20=20The=20checks=0A-=20*=20= performed=20by=20Asserts=20present=20in=20those=20two=20functions=20are=20= also=20performed=20here.=0A-=20*=20In=20cases=20where=20those=20two=20= functions=20are=20a=20bit=20cavalier=20in=20their=20assumptions=0A-=20*=20= about=20data=20being=20correct,=20we=20perform=20additional=20checks=20= not=20present=20in=20either=0A-=20*=20of=20those=20two=20functions.=20=20= Where=20some=20condition=20is=20checked=20in=20both=20of=20those=0A-=20*=20= functions,=20we=20perform=20it=20here=20twice,=20as=20we=20parallel=20= the=20logical=20flow=20of=0A-=20*=20those=20two=20functions.=20=20The=20= presence=20of=20duplicate=20checks=20seems=20a=20reasonable=0A-=20*=20= price=20to=20pay=20for=20keeping=20this=20code=20tightly=20coupled=20= with=20the=20code=20it=0A-=20*=20protects.=0A+=20*=20case=20of=20a=20= toasted=20value,=20optionally=20stores=20the=20toast=20pointer=20so=20= later=20it=20can=0A+=20*=20be=20checked=20following=20the=20logic=20of=20= detoast_external_attr(),=20checking=20for=20any=0A+=20*=20conditions=20= that=20would=20result=20in=20either=20of=20those=20functions=20Asserting=20= or=0A+=20*=20crashing=20the=20backend.=20=20The=20checks=20performed=20= by=20Asserts=20present=20in=20those=20two=0A+=20*=20functions=20are=20= also=20performed=20here=20and=20in=20check_toasted_attributes.=20=20In=20= cases=0A+=20*=20where=20those=20two=20functions=20are=20a=20bit=20= cavalier=20in=20their=20assumptions=20about=20data=0A+=20*=20being=20= correct,=20we=20perform=20additional=20checks=20not=20present=20in=20= either=20of=20those=0A+=20*=20two=20functions.=20=20Where=20some=20= condition=20is=20checked=20in=20both=20of=20those=20functions,=0A+=20*=20= we=20perform=20it=20here=20twice,=20as=20we=20parallel=20the=20logical=20= flow=20of=20those=20two=0A+=20*=20functions.=20=20The=20presence=20of=20= duplicate=20checks=20seems=20a=20reasonable=20price=20to=20pay=0A+=20*=20= for=20keeping=20this=20code=20tightly=20coupled=20with=20the=20code=20it=20= protects.=0A=20=20*=0A=20=20*=20Returns=20true=20if=20the=20tuple=20= attribute=20is=20sane=20enough=20for=20processing=20to=0A=20=20*=20= continue=20on=20to=20the=20next=20attribute,=20false=20otherwise.=0A@@=20= -1198,12=20+1262,6=20@@=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx)=0A=20static=20bool=0A=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20{=0A-=09struct=20= varatt_external=20toast_pointer;=0A-=09ScanKeyData=20toastkey;=0A-=09= SysScanDesc=20toastscan;=0A-=09SnapshotData=20SnapshotToast;=0A-=09= HeapTuple=09toasttup;=0A-=09bool=09=09found_toasttup;=0A=20=09Datum=09=09= attdatum;=0A=20=09struct=20varlena=20*attr;=0A=20=09char=09=20=20=20*tp;=09= =09=09=09/*=20pointer=20to=20the=20tuple=20data=20*/=0A@@=20-1338,191=20= +1396,114=20@@=20check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=09=09= return=20true;=0A=20=0A=20=09/*=0A-=09=20*=20Must=20copy=20attr=20into=20= toast_pointer=20for=20alignment=20considerations=0A+=09=20*=20If=20this=20= tuple=20is=20at=20risk=20of=20being=20vacuumed=20away,=20we=20cannot=20= check=20the=0A+=09=20*=20toast.=20=20Otherwise,=20we=20push=20a=20copy=20= of=20the=20toast=20tuple=20so=20we=20can=20check=20it=0A+=09=20*=20after=20= releasing=20the=20main=20table=20buffer=20lock.=0A=20=09=20*/=0A-=09= VARATT_EXTERNAL_GET_POINTER(toast_pointer,=20attr);=0A+=09if=20= (!ctx->tuple_is_volatile)=0A+=09{=0A+=09=09ToastCheckContext=20*tctx;=0A=20= =0A-=09ctx->attrsize=20=3D=20VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer);=0A= -=09ctx->endchunk=20=3D=20(ctx->attrsize=20-=201)=20/=20= TOAST_MAX_CHUNK_SIZE;=0A-=09ctx->totalchunks=20=3D=20ctx->endchunk=20+=20= 1;=0A+=09=09tctx=20=3D=20(ToastCheckContext=20*)=20= palloc0fast(sizeof(ToastCheckContext));=0A=20=0A-=09/*=0A-=09=20*=20= Setup=20a=20scan=20key=20to=20find=20chunks=20in=20toast=20table=20with=20= matching=20va_valueid=0A-=09=20*/=0A-=09ScanKeyInit(&toastkey,=0A-=09=09=09= =09(AttrNumber)=201,=0A-=09=09=09=09BTEqualStrategyNumber,=20F_OIDEQ,=0A= -=09=09=09=09ObjectIdGetDatum(toast_pointer.va_valueid));=0A-=0A-=09/*=0A= -=09=20*=20Check=20if=20any=20chunks=20for=20this=20toasted=20object=20= exist=20in=20the=20toast=20table,=0A-=09=20*=20accessible=20via=20the=20= index.=0A-=09=20*/=0A-=09init_toast_snapshot(&SnapshotToast);=0A-=09= toastscan=20=3D=20systable_beginscan_ordered(ctx->toast_rel,=0A-=09=09=09= =09=09=09=09=09=09=09=20=20=20ctx->valid_toast_index,=0A-=09=09=09=09=09=09= =09=09=09=09=20=20=20&SnapshotToast,=201,=0A-=09=09=09=09=09=09=09=09=09=09= =20=20=20&toastkey);=0A-=09ctx->chunkno=20=3D=200;=0A-=09found_toasttup=20= =3D=20false;=0A-=09while=20((toasttup=20=3D=0A-=09=09=09= systable_getnext_ordered(toastscan,=0A-=09=09=09=09=09=09=09=09=09=20= ForwardScanDirection))=20!=3D=20NULL)=0A-=09{=0A-=09=09found_toasttup=20= =3D=20true;=0A-=09=09check_toast_tuple(toasttup,=20ctx);=0A-=09=09= ctx->chunkno++;=0A+=09=09= VARATT_EXTERNAL_GET_POINTER(tctx->toast_pointer,=20attr);=0A+=09=09= tctx->blkno=20=3D=20ctx->blkno;=0A+=09=09tctx->offnum=20=3D=20= ctx->offnum;=0A+=09=09tctx->attnum=20=3D=20ctx->attnum;=0A+=09=09= ctx->toasted_attributes=20=3D=20lappend(ctx->toasted_attributes,=20= tctx);=0A=20=09}=0A-=09if=20(!found_toasttup)=0A-=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= psprintf("toasted=20value=20for=20attribute=20%u=20missing=20from=20= toast=20table",=0A-=09=09=09=09=09=09=09=09=09=09ctx->attnum));=0A-=09= else=20if=20(ctx->chunkno=20!=3D=20(ctx->endchunk=20+=201))=0A-=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=20=20=20= psprintf("final=20toast=20chunk=20number=20%u=20differs=20from=20= expected=20value=20%u",=0A-=09=09=09=09=09=09=09=09=09=09ctx->chunkno,=20= (ctx->endchunk=20+=201)));=0A-=09systable_endscan_ordered(toastscan);=0A=20= =0A=20=09return=20true;=0A=20}=0A=20=0A=20/*=0A-=20*=20Check=20the=20= current=20tuple=20as=20tracked=20in=20ctx,=20recording=20any=20= corruption=20found=20in=0A-=20*=20ctx->tupstore.=0A+=20*=20For=20each=20= attribute=20collected=20in=20ctx->toasted_attributes,=20look=20up=20the=20= value=0A+=20*=20in=20the=20toast=20table=20and=20perform=20checks=20on=20= it.=20=20This=20function=20should=20only=20be=0A+=20*=20called=20on=20= toast=20pointers=20which=20cannot=20be=20vacuumed=20away=20during=20our=0A= +=20*=20processing.=0A=20=20*/=0A=20static=20void=0A= -check_tuple(HeapCheckContext=20*ctx)=0A= +check_toasted_attributes(HeapCheckContext=20*ctx)=0A=20{=0A-=09= TransactionId=20xmin;=0A-=09TransactionId=20xmax;=0A-=09bool=09=09fatal=20= =3D=20false;=0A-=09uint16=09=09infomask=20=3D=20ctx->tuphdr->t_infomask;=0A= +=09ListCell=20=20=20*cell;=0A=20=0A-=09/*=20If=20xmin=20is=20normal,=20= it=20should=20be=20within=20valid=20range=20*/=0A-=09xmin=20=3D=20= HeapTupleHeaderGetXmin(ctx->tuphdr);=0A-=09switch=20= (get_xid_status(xmin,=20ctx,=20NULL))=0A+=09foreach(cell,=20= ctx->toasted_attributes)=0A=20=09{=0A-=09=09case=20XID_INVALID:=0A-=09=09= case=20XID_BOUNDS_OK:=0A-=09=09=09break;=0A-=09=09case=20XID_IN_FUTURE:=0A= -=09=09=09report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20equals=20or=20exceeds=20next=20valid=20transaction=20= ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09xmin,=0A-=09=09=09=09=09= =09=09=09=09=09=09EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09= =09=09=09=09=09=09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A-=09= =09=09fatal=20=3D=20true;=0A-=09=09=09break;=0A-=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09report_main_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=20=20=20psprintf("xmin=20%u=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09= xmin,=0A-=09=09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09XidFromFullTransactionId(ctx->oldest_fxid)));=0A-=09=09=09fatal=20= =3D=20true;=0A-=09=09=09break;=0A-=09=09case=20XID_PRECEDES_RELMIN:=0A-=09= =09=09report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=20=20=20= psprintf("xmin=20%u=20precedes=20relation=20freeze=20threshold=20%u:%u",=0A= -=09=09=09=09=09=09=09=09=09=09=09xmin,=0A-=09=09=09=09=09=09=09=09=09=09= =09EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->relfrozenfxid)));=0A-=09=09=09= fatal=20=3D=20true;=0A-=09=09=09break;=0A-=09}=0A+=09=09= ToastCheckContext=20*tctx;=0A+=09=09SnapshotData=20SnapshotToast;=0A+=09=09= ScanKeyData=20toastkey;=0A+=09=09SysScanDesc=20toastscan;=0A+=09=09bool=09= =09found_toasttup;=0A+=09=09HeapTuple=09toasttup;=0A+=0A+=09=09tctx=20=3D=20= lfirst(cell);=0A+=09=09tctx->attrsize=20=3D=20= VARATT_EXTERNAL_GET_EXTSIZE(tctx->toast_pointer);=0A+=09=09= tctx->endchunk=20=3D=20(tctx->attrsize=20-=201)=20/=20= TOAST_MAX_CHUNK_SIZE;=0A+=09=09tctx->totalchunks=20=3D=20tctx->endchunk=20= +=201;=0A=20=0A-=09xmax=20=3D=20HeapTupleHeaderGetRawXmax(ctx->tuphdr);=0A= +=09=09/*=0A+=09=09=20*=20Setup=20a=20scan=20key=20to=20find=20chunks=20= in=20toast=20table=20with=20matching=0A+=09=09=20*=20va_valueid=0A+=09=09= =20*/=0A+=09=09ScanKeyInit(&toastkey,=0A+=09=09=09=09=09(AttrNumber)=20= 1,=0A+=09=09=09=09=09BTEqualStrategyNumber,=20F_OIDEQ,=0A+=09=09=09=09=09= ObjectIdGetDatum(tctx->toast_pointer.va_valueid));=0A=20=0A-=09if=20= (infomask=20&=20HEAP_XMAX_IS_MULTI)=0A-=09{=0A-=09=09/*=20xmax=20is=20a=20= multixact,=20so=20it=20should=20be=20within=20valid=20MXID=20range=20*/=0A= -=09=09switch=20(check_mxid_valid_in_rel(xmax,=20ctx))=0A-=09=09{=0A-=09=09= =09case=20XID_INVALID:=0A-=09=09=09=09report_main_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20=20pstrdup("multitransaction=20ID=20is=20= invalid"));=0A-=09=09=09=09fatal=20=3D=20true;=0A-=09=09=09=09break;=0A-=09= =09=09case=20XID_PRECEDES_RELMIN:=0A-=09=09=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20relation=20minimum=20= multitransaction=20ID=20threshold=20%u",=0A-=09=09=09=09=09=09=09=09=09=09= =09=09xmax,=20ctx->relminmxid));=0A-=09=09=09=09fatal=20=3D=20true;=0A-=09= =09=09=09break;=0A-=09=09=09case=20XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20precedes=20oldest=20valid=20= multitransaction=20ID=20threshold=20%u",=0A-=09=09=09=09=09=09=09=09=09=09= =09=09xmax,=20ctx->oldest_mxact));=0A-=09=09=09=09fatal=20=3D=20true;=0A= -=09=09=09=09break;=0A-=09=09=09case=20XID_IN_FUTURE:=0A-=09=09=09=09= report_main_corruption(ctx,=0A-=09=09=09=09=09=09=09=09=09=20=20=20= psprintf("multitransaction=20ID=20%u=20equals=20or=20exceeds=20next=20= valid=20multitransaction=20ID=20%u",=0A-=09=09=09=09=09=09=09=09=09=09=09= =09xmax,=0A-=09=09=09=09=09=09=09=09=09=09=09=09ctx->next_mxact));=0A-=09= =09=09=09fatal=20=3D=20true;=0A-=09=09=09=09break;=0A-=09=09=09case=20= XID_BOUNDS_OK:=0A-=09=09=09=09break;=0A-=09=09}=0A-=09}=0A-=09else=0A-=09= {=0A=20=09=09/*=0A-=09=09=20*=20xmax=20is=20not=20a=20multixact=20and=20= is=20normal,=20so=20it=20should=20be=20within=20the=0A-=09=09=20*=20= valid=20XID=20range.=0A+=09=09=20*=20Check=20if=20any=20chunks=20for=20= this=20toasted=20object=20exist=20in=20the=20toast=0A+=09=09=20*=20= table,=20accessible=20via=20the=20index.=0A=20=09=09=20*/=0A-=09=09= switch=20(get_xid_status(xmax,=20ctx,=20NULL))=0A+=09=09= init_toast_snapshot(&SnapshotToast);=0A+=09=09toastscan=20=3D=20= systable_beginscan_ordered(ctx->toast_rel,=0A+=09=09=09=09=09=09=09=09=09= =09=09=20=20=20ctx->valid_toast_index,=0A+=09=09=09=09=09=09=09=09=09=09=09= =20=20=20&SnapshotToast,=201,=0A+=09=09=09=09=09=09=09=09=09=09=09=20=20=20= &toastkey);=0A+=09=09tctx->chunkno=20=3D=200;=0A+=09=09found_toasttup=20= =3D=20false;=0A+=09=09while=20((toasttup=20=3D=0A+=09=09=09=09= systable_getnext_ordered(toastscan,=0A+=09=09=09=09=09=09=09=09=09=09=20= ForwardScanDirection))=20!=3D=20NULL)=0A=20=09=09{=0A-=09=09=09case=20= XID_INVALID:=0A-=09=09=09case=20XID_BOUNDS_OK:=0A-=09=09=09=09break;=0A-=09= =09=09case=20XID_IN_FUTURE:=0A-=09=09=09=09report_main_corruption(ctx,=0A= -=09=09=09=09=09=09=09=09=09=20=20=20psprintf("xmax=20%u=20equals=20or=20= exceeds=20next=20valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09= =09=09=09=09=09=09xmax,=0A-=09=09=09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->next_fxid),=0A-=09=09=09=09=09=09=09=09=09= =09=09=09XidFromFullTransactionId(ctx->next_fxid)));=0A-=09=09=09=09= fatal=20=3D=20true;=0A-=09=09=09=09break;=0A-=09=09=09case=20= XID_PRECEDES_CLUSTERMIN:=0A-=09=09=09=09report_main_corruption(ctx,=0A-=09= =09=09=09=09=09=09=09=09=20=20=20psprintf("xmax=20%u=20precedes=20oldest=20= valid=20transaction=20ID=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=09= xmax,=0A-=09=09=09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->oldest_fxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->oldest_fxid)));=0A-=09=09=09=09= fatal=20=3D=20true;=0A-=09=09=09=09break;=0A-=09=09=09case=20= XID_PRECEDES_RELMIN:=0A-=09=09=09=09report_main_corruption(ctx,=0A-=09=09= =09=09=09=09=09=09=09=20=20=20psprintf("xmax=20%u=20precedes=20relation=20= freeze=20threshold=20%u:%u",=0A-=09=09=09=09=09=09=09=09=09=09=09=09= xmax,=0A-=09=09=09=09=09=09=09=09=09=09=09=09= EpochFromFullTransactionId(ctx->relfrozenfxid),=0A-=09=09=09=09=09=09=09=09= =09=09=09=09XidFromFullTransactionId(ctx->relfrozenfxid)));=0A-=09=09=09=09= fatal=20=3D=20true;=0A+=09=09=09found_toasttup=20=3D=20true;=0A+=09=09=09= check_toast_tuple(toasttup,=20ctx,=20tctx);=0A+=09=09=09tctx->chunkno++;=0A= =20=09=09}=0A+=09=09if=20(!found_toasttup)=0A+=09=09=09= report_toast_corruption(ctx,=20tctx,=0A+=09=09=09=09=09=09=09=09=09= psprintf("toasted=20value=20for=20attribute=20%u=20missing=20from=20= toast=20table",=0A+=09=09=09=09=09=09=09=09=09=09=09=20tctx->attnum));=0A= +=09=09else=20if=20(tctx->chunkno=20!=3D=20(tctx->endchunk=20+=201))=0A+=09= =09=09report_toast_corruption(ctx,=20tctx,=0A+=09=09=09=09=09=09=09=09=09= psprintf("final=20toast=20chunk=20number=20%u=20differs=20from=20= expected=20value=20%u",=0A+=09=09=09=09=09=09=09=09=09=09=09=20= tctx->chunkno,=20(tctx->endchunk=20+=201)));=0A+=09=09= systable_endscan_ordered(toastscan);=0A+=0A+=09=09pfree(tctx);=0A=20=09}=0A= +=09list_free(ctx->toasted_attributes);=0A+=09ctx->toasted_attributes=20= =3D=20NIL;=0A+}=0A=20=0A-=09/*=0A-=09=20*=20Cannot=20process=20tuple=20= data=20if=20tuple=20header=20was=20corrupt,=20as=20the=20offsets=0A-=09=20= *=20within=20the=20page=20cannot=20be=20trusted,=20leaving=20too=20much=20= risk=20of=20reading=0A-=09=20*=20garbage=20if=20we=20continue.=0A-=09=20= *=0A-=09=20*=20We=20also=20cannot=20process=20the=20tuple=20if=20the=20= xmin=20or=20xmax=20were=20invalid=0A-=09=20*=20relative=20to=20= relfrozenxid=20or=20relminmxid,=20as=20clog=20entries=20for=20the=20xids=0A= -=09=20*=20may=20already=20be=20gone.=0A-=09=20*/=0A-=09if=20(fatal)=0A-=09= =09return;=0A-=0A+/*=0A+=20*=20Check=20the=20current=20tuple=20as=20= tracked=20in=20ctx,=20recording=20any=20corruption=20found=20in=0A+=20*=20= ctx->tupstore.=0A+=20*/=0A+static=20void=0A+check_tuple(HeapCheckContext=20= *ctx)=0A+{=0A=20=09/*=0A=20=09=20*=20Check=20various=20forms=20of=20= tuple=20header=20corruption.=20=20If=20the=20header=20is=20too=0A-=09=20= *=20corrupt=20to=20continue=20checking,=20or=20if=20the=20tuple=20is=20= not=20visible=20to=20anyone,=0A-=09=20*=20we=20cannot=20continue=20with=20= other=20checks.=0A+=09=20*=20corrupt=20to=20continue=20checking,=20we=20= cannot=20continue=20with=20other=20checks.=0A=20=09=20*/=0A=20=09if=20= (!check_tuple_header(ctx))=0A=20=09=09return;=0A=20=0A+=09/*=0A+=09=20*=20= Check=20tuple=20visibility.=20=20If=20the=20inserting=20transaction=20= aborted,=20we=0A+=09=20*=20cannot=20assume=20our=20relation=20= description=20matches=20the=20tuple=20structure,=20and=0A+=09=20*=20= therefore=20cannot=20check=20it.=0A+=09=20*/=0A=20=09if=20= (!check_tuple_visibility(ctx))=0A=20=09=09return;=0A=20=0A@@=20-1545,6=20= +1526,10=20@@=20check_tuple(HeapCheckContext=20*ctx)=0A=20=09=20*=20= next,=20at=20which=20point=20we=20abort=20further=20attribute=20checks=20= for=20this=20tuple.=0A=20=09=20*=20Note=20that=20we=20don't=20abort=20= for=20all=20types=20of=20corruption,=20only=20for=20those=0A=20=09=20*=20= types=20where=20we=20don't=20know=20how=20to=20continue.=0A+=09=20*=0A+=09= =20*=20While=20checking=20the=20tuple=20attributes,=20we=20build=20a=20= list=20of=20toast=20pointers=0A+=09=20*=20we=20encounter,=20to=20be=20= checked=20later.=20=20If=20further=20attribute=20checking=20is=0A+=09=20= *=20aborted,=20we=20still=20have=20the=20pointers=20collected=20prior=20= to=20aborting.=0A=20=09=20*/=0A=20=09ctx->offset=20=3D=200;=0A=20=09for=20= (ctx->attnum=20=3D=200;=20ctx->attnum=20<=20ctx->natts;=20ctx->attnum++)=0A= diff=20--git=20a/src/tools/pgindent/typedefs.list=20= b/src/tools/pgindent/typedefs.list=0Aindex=209e6777e9d0..0ce261e2a2=20= 100644=0A---=20a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-2557,6=20+2557,7=20@@=20= TimestampTz=0A=20TmFromChar=0A=20TmToChar=0A=20ToastAttrInfo=0A= +ToastCheckContext=0A=20ToastTupleContext=0A=20TocEntry=0A=20= TokenAuxData=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 =E2=80=94 Mark Dilger EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company --Apple-Mail=_D817EED5-85BF-4BE6-88A9-03C14B3110D4--