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 1lX5Si-0004t7-9j for pgsql-hackers@arkaria.postgresql.org; Thu, 15 Apr 2021 17:07:28 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1lX5Sh-0000kg-8Y for pgsql-hackers@arkaria.postgresql.org; Thu, 15 Apr 2021 17:07:27 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lX5Sg-0000kW-LR for pgsql-hackers@lists.postgresql.org; Thu, 15 Apr 2021 17:07:27 +0000 Received: from mail-pj1-x102b.google.com ([2607:f8b0:4864:20::102b]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1lX5Sb-0003eA-7v for pgsql-hackers@postgresql.org; Thu, 15 Apr 2021 17:07:25 +0000 Received: by mail-pj1-x102b.google.com with SMTP id s14so7597829pjl.5 for ; Thu, 15 Apr 2021 10:07:20 -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=hcdWIzfiEnr5YjLOweJjbjnDrZHniEoFC+nDpdhcc00=; b=YDsEngu8j+BZQsx6M8gEQ66EzaKqRyaMGIhtxdO3tvw24Cw9KJN2ylvB5OnO/sCwDL L7dcyoj3YWAfpHuyi84qzTS7yCLAx8L8IBMEQmIzSEoAVX7J9oaDYFHeCDeP2Ar7MGL0 MGn7wxxDW0ZGkRHRtanYuM0ev8tiCTs9mqhlSVgKqRUTOAYZXUiMn2im2dcb2pMUgYlI VU/Nq16gig4zrG1m/5Qerf2xpTRljb2I5V/LByY/XAAvPW0/SVnO7X0KueN9c5v5uGmW VQKnIEgUhLrkkspIQBZGyr9s8PRMxTg0gKIH1lTZ/b9L27dHI2A1RHZRWgDALdfgCc8n QOAA== 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=hcdWIzfiEnr5YjLOweJjbjnDrZHniEoFC+nDpdhcc00=; b=CnCzZB3LuETI+p1e1j10tQFTZOORRvMFBeSFQlC0EQ85W45bgWONltWO6A0DegBVlr zit3jzC1RSZsGc4EY5Az03HGvAz/YT7Daq/7SEQRcUm9n0s9x/+LrDe9HHqDIiNwHhLe 53BmVpC9s1jrE02sp0dbK2gdh4SH5q0DPp/irh8fb2+ccRJ+xzYBucoXWtmdOulew9Tu aEYxIbHgSo8hLHO99hbnrO+l/GwoVFdbP6PeIBmHxO0WLHqx6fF9QkruIzdZJVPxNjxA AmQkqOhr++xLCP8SZN4/yzx0Kczz+AFv+ByN5xI5PwmXouJxWvLtKmcZCDuMxVNqpmIZ G2ug== X-Gm-Message-State: AOAM530NglGD+kYuWN3MySi2OAf7j09PSdxc1NuN0kmfrXo+V7JNG/iN 5YsNQE9sMakU3w9FxUv+3i9y3XuyVrD5RDHm2+dE5irhkdxg2/ZLpPZkqhMnoQzHY6c6GWBNvQ6 qAbpFOlp5AdR5RNTe7otiHe02ND40BUIbrVXpVIaaCwR7uymQ/y9iFISnBD6lxzngz12hWy16y8 EEEOvRkx3kXJY/4YTjKZf7qY94BHo/kwqepTrQ X-Google-Smtp-Source: ABdhPJzU/QTTZZ5dHmLeaaNSpOXiP5WwS8/+aWwqKwaeE4QV+W9P2MSWJvn2ZN/g93qbFGy7F+0adw== X-Received: by 2002:a17:902:106:b029:e8:de25:4a1d with SMTP id 6-20020a1709020106b02900e8de254a1dmr4940663plb.7.1618506439272; Thu, 15 Apr 2021 10:07:19 -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 z1sm2124205pgz.94.2021.04.15.10.07.17 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 15 Apr 2021 10:07:18 -0700 (PDT) From: Mark Dilger Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_E9A07B8E-5C76-4E7C-95AB-CE07977E656B" Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.4\)) Subject: Re: pg_amcheck contrib application Date: Thu, 15 Apr 2021 10:07:16 -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> <6915B9B2-B551-4DBC-89DB-C12D9AF985B8@enterprisedb.com> <23192440-3B8A-4D82-8C24-9D8161BAAB01@enterprisedb.com> <1F1A6246-854F-47F0-A179-A3CD9F05356B@enterprisedb.com> <50DA1F9A-D6AB-40DE-AB24-E8BDC13F4DA1@enterprisedb.com> <7D3B9BF6-50D0-4C30-8506-1C1851C7F96F@enterprisedb.com> X-Mailer: Apple Mail (2.3608.120.23.2.4) 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=_E9A07B8E-5C76-4E7C-95AB-CE07977E656B Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On Apr 14, 2021, at 10:17 AM, Robert Haas = wrote: >=20 > On Mon, Apr 12, 2021 at 11:06 PM Mark Dilger > wrote: >> It now reports: >>=20 >> # heap table "postgres"."public"."test", block 0, offset 18, = attribute 2: >> # toast value 16461 missing chunk 3 with expected size 1996 >> # heap table "postgres"."public"."test", block 0, offset 18, = attribute 2: >> # toast value 16461 was expected to end at chunk 6 with total = size 10000, but ended at chunk 5 with total size 8004 >>=20 >> It sounds like you weren't expecting the second of these reports. I = think it is valuable, especially when there are multiple missing chunks = and multiple extraneous chunks, as it makes it easier for the user to = reconcile the missing chunks against the extraneous chunks. >=20 > I wasn't, but I'm not overwhelmingly opposed to it, either. I do think > I would be in favor of splitting this kind of thing up into two > messages: >=20 > # toast value 16459 unexpected chunks 1000 through 1004 each with > size 1996 followed by chunk 1005 with size 20 >=20 > We'll have fewer message variants and I don't think any real > regression in usability if we say: >=20 > # toast value 16459 has unexpected chunks 1000 through 1004 each > with size 1996 > # toast value 16459 has unexpected chunk 1005 with size 20 Changed. > (Notice that I also inserted "has" so that the sentence a verb. Or we > could "contains.") I have added the verb "has" rather than "contains" because "has" is more = consistent with the phrasing of other similar corruption reports. --Apple-Mail=_E9A07B8E-5C76-4E7C-95AB-CE07977E656B Content-Disposition: attachment; filename=v21-0001-amcheck-adding-toast-pointer-corruption-checks.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v21-0001-amcheck-adding-toast-pointer-corruption-checks.patch" Content-Transfer-Encoding: quoted-printable =46rom=202f41e74d211d0bb939bedd688933aa891c511b2d=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Thu,=2015=20Apr=202021=2008:56:59=20-0700=0ASubject:=20[PATCH=20= v21]=20amcheck:=20adding=20toast=20pointer=20corruption=20checks=0A=0A= Adding=20additional=20checks=20of=20toast=20pointers:=20checking=20the=20= extsize=0Aagainst=20the=20rawsize,=20the=20uncompressed=20size=20against=20= the=20size=20limit=0Afor=20varlena=20datums,=20the=20va_toastrelid=20= field=20against=20the=20heap=20table's=0Areltoastrelid,=20and=20if=20= compressed,=20the=20validity=20of=20the=20compression=0Amethod=20ID.=0A=0A= Adding=20checks=20that=20the=20toasted=20attribute=20chunks=20are=20= returned=20by=20the=0Atoast=20index=20scan=20in=20order=20and=20without=20= duplicates,=20and=20improving=20the=0Areports=20of=20missing=20or=20= extra=20chunks=20to=20be=20more=20clear=20to=20the=20user.=0A=0AChanging=20= the=20logic=20to=20continue=20checking=20toast=20even=20after=20= reporting=0Athat=20HEAP_HASEXTERNAL=20is=20false.=20=20Previously,=20the=20= toast=20checking=0Astopped=20here,=20but=20that=20wasn't=20necessary,=20= and=20subsequent=20checks=20may=0Aprovide=20additional=20useful=20= diagnostic=20information.=0A---=0A=20contrib/amcheck/verify_heapam.c=20=20= |=20370=20++++++++++++++++++++++++++-----=0A=20= src/tools/pgindent/typedefs.list=20|=20=20=201=20+=0A=202=20files=20= changed,=20319=20insertions(+),=2052=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/amcheck/verify_heapam.c=20b/contrib/amcheck/verify_heapam.c=0A= index=209366f45d74..b5500c53a0=20100644=0A---=20= a/contrib/amcheck/verify_heapam.c=0A+++=20= b/contrib/amcheck/verify_heapam.c=0A@@=20-30,6=20+30,9=20@@=20= PG_FUNCTION_INFO_V1(verify_heapam);=0A=20/*=20The=20number=20of=20= columns=20in=20tuples=20returned=20by=20verify_heapam=20*/=0A=20#define=20= HEAPCHECK_RELATION_COLS=204=0A=20=0A+/*=20The=20largest=20valid=20toast=20= va_rawsize=20*/=0A+#define=20VARLENA_SIZE_LIMIT=200x3FFFFFFF=0A+=0A=20/*=0A= =20=20*=20Despite=20the=20name,=20we=20use=20this=20for=20reporting=20= problems=20with=20both=20XIDs=20and=0A=20=20*=20MXIDs.=0A@@=20-146,12=20= +149,40=20@@=20typedef=20struct=20HeapCheckContext=0A=20=09= Tuplestorestate=20*tupstore;=0A=20}=20HeapCheckContext;=0A=20=0A+/*=0A+=20= *=20Struct=20holding=20the=20running=20context=20information=20during=20= the=20check=20of=20a=0A+=20*=20a=20single=20toasted=20attribute.=0A+=20= */=0A+typedef=20struct=20ToastCheckContext=0A+{=0A+=09/*=0A+=09=20*=20= Cache=20tracking=20a=20sequence=20of=20contiguous=20toast=20chunks,=20= each=20of=20size=0A+=09=20*=20TOAST_MAX_CHUNK_SIZE,=20and=20having=20= sequence=20numbers=20outside=20the=20expected=0A+=09=20*=20range.=20=20= The=20sequence=20numbers=20of=20such=20chunks=20are=20cached=20until=20= the=0A+=09=20*=20sequence=20ends=20so=20that=20a=20single=20toast=20= corruption=20report=20can=20be=20emitted=0A+=09=20*=20for=20the=20group,=20= rather=20than=20one=20report=20per=20chunk.=0A+=09=20*/=0A+=09bool=09=09= have_extraneous_chunks;=0A+=09int32=09=09first_extraneous;=0A+=09int32=09= =09last_extraneous;=0A+=0A+=09/*=20Most=20recent=20previously=20seen=20= chunk=20sequence=20number=20*/=0A+=09int32=09=09last_chunk_seen;=0A+=0A+=09= /*=0A+=09=20*=20Expected=20sequence=20number=20and=20size=20of=20the=20= final=20chunk=20expected=20for=20this=0A+=09=20*=20toasted=20attribute=0A= +=09=20*/=0A+=09int32=09=09final_expected_chunk;=0A+=09int32=09=09= final_expected_size;=0A+}=20ToastCheckContext;=0A+=0A=20/*=20Internal=20= implementation=20*/=0A=20static=20void=20sanity_check_relation(Relation=20= rel);=0A=20static=20void=20check_tuple(HeapCheckContext=20*ctx);=0A= -static=20void=20check_toast_tuple(HeapTuple=20toasttup,=20= HeapCheckContext=20*ctx,=0A-=09=09=09=09=09=09=09=20=20ToastedAttribute=20= *ta,=20int32=20chunkno,=0A-=09=09=09=09=09=09=09=20=20int32=20endchunk);=0A= +static=20int32=20check_toast_tuple(HeapTuple=20toasttup,=20= ToastedAttribute=20*ta,=0A+=09=09=09=09=09=09=09=20=20=20= ToastCheckContext=20*tctx,=20HeapCheckContext=20*hctx,=0A+=09=09=09=09=09= =09=09=20=20=20int32=20chunkno);=0A=20=0A=20static=20bool=20= check_tuple_attribute(HeapCheckContext=20*ctx);=0A=20static=20void=20= check_toasted_attribute(HeapCheckContext=20*ctx,=0A@@=20-1147,10=20= +1178,152=20@@=20check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=09= return=20true;=0A=20}=0A=20=0A+/*=0A+=20*=20Issues=20toast=20corruption=20= reports=20for=20the=20given=20extraneous=20partial=20chunk,=20if=0A+=20*=20= not=20null,=20along=20with=20any=20extraneous=20full=20chunks=20in=20the=20= tctx=20cache,=20which=20is=0A+=20*=20then=20cleared.=20=20A=20"partial=20= chunk"=20is=20any=20chunk=20with=20size=20different=20from=0A+=20*=20= TOAST_MAX_CHUNK_SIZE.=20=20An=20"extraneous=20chunk"=20is=20one=20with=20= a=20sequence=20number=0A+=20*=20outside=20the=20expected=20range=20for=20= the=20toasted=20attribute.=0A+=20*=0A+=20*=20To=20report=20extraneous=20= full=20chunks=20and=20clear=20the=20cache,=20call=20with=20partialchunk=0A= +=20*=20and=20partialsize=20NULL.=20=20If=20the=20cache=20is=20already=20= empty,=20the=20call=20is=20harmless.=0A+=20*=0A+=20*=20Extraneous=20= partial=20chunks=20are=20never=20cached.=20=20When=20reporting=20one,=20= any=20cached=0A+=20*=20extraneous=20full=20chunks=20will=20also=20be=20= reported=20and=20the=20cache=20cleared.=0A+=20*/=0A+static=20void=0A= +report_extraneous_chunks(HeapCheckContext=20*hctx,=20ToastedAttribute=20= *ta,=0A+=09=09=09=09=09=09=20ToastCheckContext=20*tctx,=20int32=20= *partialchunk,=0A+=09=09=09=09=09=09=20int32=20*partialsize)=0A+{=0A+=09= if=20(tctx->have_extraneous_chunks)=0A+=09{=0A+=09=09if=20= (tctx->first_extraneous=20<=20tctx->last_extraneous)=0A+=09=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20has=20unexpected=20chunks=20%d=20through=20= %d=20each=20with=20size=20%d",=0A+=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09=09=20= tctx->first_extraneous,=0A+=09=09=09=09=09=09=09=09=09=09=20= tctx->last_extraneous,=0A+=09=09=09=09=09=09=09=09=09=09=20= (int)TOAST_MAX_CHUNK_SIZE));=0A+=09=09else=0A+=09=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20has=20unexpected=20chunk=20%d=20with=20= size=20%d",=0A+=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09=09=20= tctx->first_extraneous,=0A+=09=09=09=09=09=09=09=09=09=09=20= (int)TOAST_MAX_CHUNK_SIZE));=0A+=09=09tctx->have_extraneous_chunks=20=3D=20= false;=0A+=09}=0A+=0A+=09if=20(partialchunk=20!=3D=20NULL)=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20has=20unexpected=20chunk=20%d=20with=20= size=20%d",=0A+=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09=09=20= *partialchunk,=20*partialsize));=0A+}=0A=20=0A=20/*=0A-=20*=20Check=20= the=20current=20toast=20tuple=20against=20the=20state=20tracked=20in=20= ctx,=20recording=0A-=20*=20any=20corruption=20found=20in=20= ctx->tupstore.=0A+=20*=20Records=20that=20a=20toast=20chunk=20should=20= be=20reported=20as=20extraneous.=20=20After=0A+=20*=20finishing=20all=20= calls=20to=20this=20function=20for=20a=20given=20toasted=20attribute,=20= a=20call=0A+=20*=20to=20report_extraneous_chunks()=20should=20be=20= issued=20to=20flush=20the=20cache.=0A+=20*/=0A+static=20void=0A= +handle_extraneous_chunk(HeapCheckContext=20*hctx,=20ToastedAttribute=20= *ta,=0A+=09=09=09=09=09=09ToastCheckContext=20*tctx,=20int32=20curchunk,=0A= +=09=09=09=09=09=09int32=20chunksize)=0A+{=0A+=09if=20(chunksize=20=3D=3D=20= TOAST_MAX_CHUNK_SIZE)=0A+=09{=0A+=09=09if=20= (tctx->have_extraneous_chunks)=0A+=09=09{=0A+=09=09=09if=20= (tctx->last_extraneous=20=3D=3D=20curchunk=20-=201)=0A+=09=09=09{=0A+=09=09= =09=09/*=0A+=09=09=09=09=20*=20This=20is=20the=20next=20chunk=20in=20an=20= ongoing=20sequence.=20=20Extend=20it,=0A+=09=09=09=09=20*=20but=20do=20= not=20report=20it=20yet.=0A+=09=09=09=09=20*/=0A+=09=09=09=09= tctx->last_extraneous=20=3D=20curchunk;=0A+=09=09=09=09return;=0A+=09=09=09= }=0A+=0A+=09=09=09/*=0A+=09=09=09=20*=20There=20is=20an=20ongoing=20= sequence,=20but=20this=20chunk=20is=20discontiguous=0A+=09=09=09=20*=20= with=20it.=20=20Report=20the=20sequence=20and=20clear=20the=20cache=20so=20= we=20can=0A+=09=09=09=20*=20start=20over=20with=20this=20chunk.=0A+=09=09= =09=20*/=0A+=09=09=09report_extraneous_chunks(hctx,=20ta,=20tctx,=20= NULL,=20NULL);=0A+=09=09}=0A+=0A+=09=09/*=20Start=20a=20new=20sequence,=20= but=20do=20not=20report=20it=20yet.=20*/=0A+=09=09tctx->first_extraneous=20= =3D=20curchunk;=0A+=09=09tctx->last_extraneous=20=3D=20curchunk;=0A+=09=09= tctx->have_extraneous_chunks=20=3D=20true;=0A+=09=09return;=0A+=09}=0A+=0A= +=09/*=0A+=09=20*=20This=20is=20a=20partial=20chunk.=20=20Report=20it.=20= =20If=20there=20is=20an=20ongoing=20full=20chunk=0A+=09=20*=20sequence,=20= this=20will=20report=20and=20flush=20that,=20too,=20but=20we=20don't=20= care.=0A+=09=20*/=0A+=09report_extraneous_chunks(hctx,=20ta,=20tctx,=20= &curchunk,=20&chunksize);=0A+}=0A+=0A+/*=0A+=20*=20Issues=20toast=20= corruption=20reports=20for=20one=20or=20more=20missing=20toast=20chunks=0A= +=20*=20in=20the=20[first_missing..last_missing]=20range,=20inclusive.=0A= +=20*/=0A+static=20void=0A+report_missing_chunks(HeapCheckContext=20= *hctx,=20ToastedAttribute=20*ta,=0A+=09=09=09=09=09=20=20= ToastCheckContext=20*tctx,=20int32=20first_missing,=0A+=09=09=09=09=09=20= =20int32=20last_missing)=0A+{=0A+=09int32=09expected_size;=0A+=0A+=09= Assert(first_missing=20>=3D=200);=0A+=09Assert(last_missing=20>=3D=20= first_missing);=0A+=09Assert(last_missing=20<=3D=20= tctx->final_expected_chunk);=0A+=0A+=09if=20(last_missing=20<=20= tctx->final_expected_chunk)=0A+=09=09expected_size=20=3D=20= TOAST_MAX_CHUNK_SIZE;=0A+=09else=0A+=09=09expected_size=20=3D=20= tctx->final_expected_size;=0A+=0A+=09/*=0A+=09=20*=20Report=20missing=20= chunks=20with=20language=20matching=20language=20used=20for=20reporting=0A= +=09=20*=20extraneous=20chunks.=20=20Mention=20the=20sizes=20expected=20= for=20the=20missing=20chunks=20so=0A+=09=20*=20the=20user=20can=20= reconcile=20that=20against=20any=20extraneous=20chunk=20reports.=0A+=09=20= */=0A+=09if=20(last_missing=20>=20first_missing=20+=201=20&&=0A+=09=09= expected_size=20<=20TOAST_MAX_CHUNK_SIZE)=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20missing=20chunks=20%d=20through=20%d=20= with=20expected=20size=20%d=20and=20chunk=20%d=20with=20expected=20size=20= %d",=0A+=09=09=09=09=09=09=09=09=09=09=20ta->toast_pointer.va_valueid,=0A= +=09=09=09=09=09=09=09=09=09=09=20first_missing,=20last_missing=20-=201,=0A= +=09=09=09=09=09=09=09=09=09=09=20(int)TOAST_MAX_CHUNK_SIZE,=0A+=09=09=09= =09=09=09=09=09=09=09=20last_missing,=20expected_size));=0A+=09else=20if=20= (last_missing=20=3D=3D=20first_missing=20+=201=20&&=0A+=09=09=09=20= expected_size=20<=20TOAST_MAX_CHUNK_SIZE)=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20missing=20chunk=20%d=20with=20expected=20= size=20%d=20and=20chunk=20%d=20with=20expected=20size=20%d",=0A+=09=09=09= =09=09=09=09=09=09=09=20ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09= =09=09=09=09=20first_missing,=0A+=09=09=09=09=09=09=09=09=09=09=20= (int)TOAST_MAX_CHUNK_SIZE,=0A+=09=09=09=09=09=09=09=09=09=09=20= last_missing,=20expected_size));=0A+=09else=20if=20(last_missing=20>=20= first_missing)=0A+=09=09report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09= =09=09=09=09psprintf("toast=20value=20%u=20missing=20chunks=20%d=20= through=20%d=20with=20expected=20size=20%d",=0A+=09=09=09=09=09=09=09=09=09= =09=20ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09=09=20= first_missing,=20last_missing,=0A+=09=09=09=09=09=09=09=09=09=09=20= (int)TOAST_MAX_CHUNK_SIZE));=0A+=09else=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20missing=20chunk=20%d=20with=20expected=20= size=20%d",=0A+=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09=09=20= last_missing,=20expected_size));=0A+}=0A+=0A+/*=0A+=20*=20Check=20the=20= current=20toast=20tuple,=20recording=20any=20corruption=20found=20in=0A+=20= *=20ctx->tupstore.=0A=20=20*=0A=20=20*=20This=20is=20not=20equivalent=20= to=20running=20verify_heapam=20on=20the=20toast=20table=20itself,=0A=20=20= *=20and=20is=20not=20hardened=20against=20corruption=20of=20the=20toast=20= table.=20=20Rather,=20when=0A@@=20-1159,38=20+1332,73=20@@=20= check_tuple_visibility(HeapCheckContext=20*ctx)=0A=20=20*=20each=20toast=20= tuple=20being=20checked=20against=20where=20we=20are=20in=20the=20= sequence,=20as=20well=0A=20=20*=20as=20each=20toast=20tuple=20having=20= its=20varlena=20structure=20sanity=20checked.=0A=20=20*=0A-=20*=20= Returns=20whether=20the=20toast=20tuple=20passed=20the=20corruption=20= checks.=0A+=20*=20Returns=20the=20size=20of=20the=20current=20toast=20= tuple=20chunk,=20or=20zero=20if=20the=0A+=20*=20chunk=20is=20not=20= sufficiently=20sensible=20for=20the=20chunk=20size=20to=20be=20= determined.=0A=20=20*/=0A-static=20void=0A-check_toast_tuple(HeapTuple=20= toasttup,=20HeapCheckContext=20*ctx,=0A-=09=09=09=09=20=20= ToastedAttribute=20*ta,=20int32=20chunkno,=20int32=20endchunk)=0A+static=20= int32=0A+check_toast_tuple(HeapTuple=20toasttup,=20ToastedAttribute=20= *ta,=0A+=09=09=09=09=20=20ToastCheckContext=20*tctx,=20HeapCheckContext=20= *hctx,=0A+=09=09=09=09=20=20int32=20chunkno)=0A=20{=0A=20=09int32=09=09= curchunk;=0A=20=09Pointer=09=09chunk;=0A=20=09bool=09=09isnull;=0A=20=09= int32=09=09chunksize;=0A-=09int32=09=09expected_size;=0A+=09int32=09=09= max_valid_prior_chunk;=0A=20=0A=20=09/*=0A=20=09=20*=20Have=20a=20chunk,=20= extract=20the=20sequence=20number=20and=20the=20data=0A=20=09=20*/=0A=20=09= curchunk=20=3D=20DatumGetInt32(fastgetattr(toasttup,=202,=0A-=09=09=09=09= =09=09=09=09=09=09=20ctx->toast_rel->rd_att,=20&isnull));=0A+=09=09=09=09= =09=09=09=09=09=09=20hctx->toast_rel->rd_att,=20&isnull));=0A=20=09if=20= (isnull)=0A=20=09{=0A-=09=09report_toast_corruption(ctx,=20ta,=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A=20=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20has=20toast=20chunk=20with=20null=20= sequence=20number",=0A=20=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid));=0A-=09=09return;=0A+=09=09return=200;=0A=20= =09}=0A+=0A+=09/*=0A+=09=20*=20Maximum=20chunk=20sequence=20number=20in=20= the=20expected=20range=20which=20is=20less=20than=0A+=09=20*=20curchunk.=20= =20Note=20that=20curchunk=20itself=20may=20be=20outside=20the=20valid=20= range.=0A+=09=20*/=0A+=09max_valid_prior_chunk=20=3D=20Min(curchunk-1,=20= tctx->final_expected_chunk);=0A+=0A+=09/*=20Report=20any=20missing=20= chunks=20at=20the=20beginning=20of=20the=20expected=20sequence=20*/=0A+=09= if=20(chunkno=20=3D=3D=200=20&&=20max_valid_prior_chunk=20>=3D=200)=0A+=09= =09report_missing_chunks(hctx,=20ta,=20tctx,=200,=20= max_valid_prior_chunk);=0A+=0A+=09/*=20Complain=20if=20the=20chunk=20= sequence=20number=20retreats=20*/=0A+=09if=20(chunkno=20>=200=20&&=20= curchunk=20<=20tctx->last_chunk_seen)=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A+=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20index=20scan=20returned=20chunk=20number=20= %d=20after=20chunk=20number=20%d",=0A+=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09=09=20= curchunk,=20tctx->last_chunk_seen));=0A+=0A+=09/*=20Complain=20if=20the=20= same=20chunk=20sequence=20number=20is=20returned=20multiple=20times=20*/=0A= +=09else=20if=20(chunkno=20>=200=20&&=20curchunk=20=3D=3D=20= tctx->last_chunk_seen)=0A+=09=09report_toast_corruption(hctx,=20ta,=0A+=09= =09=09=09=09=09=09=09psprintf("toast=20value=20%u=20index=20scan=20= returned=20chunk=20number=20%d=20more=20than=20once",=0A+=09=09=09=09=09=09= =09=09=09=09=20ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=09= =09=20curchunk));=0A+=0A+=09/*=20Report=20any=20missing=20chunks=20in=20= the=20middle=20of=20the=20expected=20sequence=20*/=0A+=09else=20if=20= (chunkno=20>=200=20&&=20max_valid_prior_chunk=20>=20= tctx->last_chunk_seen)=0A+=09=09report_missing_chunks(hctx,=20ta,=20= tctx,=20tctx->last_chunk_seen=20+=201,=0A+=09=09=09=09=09=09=09=20=20= max_valid_prior_chunk);=0A+=0A+=09/*=20Remember=20this=20chunk=20= sequence=20number=20as=20the=20last=20one=20seen=20*/=0A+=09= tctx->last_chunk_seen=20=3D=20curchunk;=0A+=0A=20=09chunk=20=3D=20= DatumGetPointer(fastgetattr(toasttup,=203,=0A-=09=09=09=09=09=09=09=09=09= =09ctx->toast_rel->rd_att,=20&isnull));=0A+=09=09=09=09=09=09=09=09=09=09= hctx->toast_rel->rd_att,=20&isnull));=0A=20=09if=20(isnull)=0A=20=09{=0A= -=09=09report_toast_corruption(ctx,=20ta,=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A=20=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20chunk=20%d=20has=20null=20data",=0A=20=09=09= =09=09=09=09=09=09=09=09=20ta->toast_pointer.va_valueid,=20chunkno));=0A= -=09=09return;=0A+=09=09return=200;=0A=20=09}=0A=20=09if=20= (!VARATT_IS_EXTENDED(chunk))=0A=20=09=09chunksize=20=3D=20VARSIZE(chunk)=20= -=20VARHDRSZ;=0A@@=20-1206,41=20+1414,34=20@@=20= check_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_toast_corruption(ctx,=20ta,=0A+=09=09= report_toast_corruption(hctx,=20ta,=0A=20=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20chunk=20%d=20has=20invalid=20varlena=20= header=20%0x",=0A=20=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A=20=09=09=09=09=09=09=09=09=09=09=20= chunkno,=20header));=0A-=09=09return;=0A+=09=09return=200;=0A=20=09}=0A=20= =0A-=09/*=0A-=09=20*=20Some=20checks=20on=20the=20data=20we've=20found=0A= -=09=20*/=0A-=09if=20(curchunk=20!=3D=20chunkno)=0A-=09{=0A-=09=09= report_toast_corruption(ctx,=20ta,=0A-=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20chunk=20%d=20has=20sequence=20number=20= %d,=20but=20expected=20sequence=20number=20%d",=0A-=09=09=09=09=09=09=09=09= =09=09=20ta->toast_pointer.va_valueid,=0A-=09=09=09=09=09=09=09=09=09=09=20= chunkno,=20curchunk,=20chunkno));=0A-=09=09return;=0A-=09}=0A-=09if=20= (chunkno=20>=20endchunk)=0A-=09{=0A-=09=09report_toast_corruption(ctx,=20= ta,=0A-=09=09=09=09=09=09=09=09psprintf("toast=20value=20%u=20chunk=20%d=20= follows=20last=20expected=20chunk=20%d",=0A-=09=09=09=09=09=09=09=09=09=09= =20ta->toast_pointer.va_valueid,=0A-=09=09=09=09=09=09=09=09=09=09=20= chunkno,=20endchunk));=0A-=09=09return;=0A-=09}=0A+=09/*=20Report=20an=20= extraneous=20chunk=20outside=20the=20expected=20sequence=20*/=0A+=09if=20= (curchunk=20<=200=20||=20curchunk=20>=20tctx->final_expected_chunk)=0A+=09= =09handle_extraneous_chunk(hctx,=20ta,=20tctx,=20curchunk,=20chunksize);=0A= =20=0A-=09expected_size=20=3D=20curchunk=20<=20endchunk=20?=20= TOAST_MAX_CHUNK_SIZE=0A-=09=09:=20= VARATT_EXTERNAL_GET_EXTSIZE(ta->toast_pointer)=20-=20(endchunk=20*=20= TOAST_MAX_CHUNK_SIZE);=0A+=09/*=20Report=20a=20partial=20chunk=20before=20= the=20final=20expected=20chunk=20*/=0A+=09else=20if=20(curchunk=20<=20= tctx->final_expected_chunk=20&&=20chunksize=20!=3D=20= TOAST_MAX_CHUNK_SIZE)=0A+=09=09report_toast_corruption(hctx,=20ta,=0A+=09= =09=09=09=09=09=09=09psprintf("toast=20value=20%u=20chunk=20%d=20has=20= size=20%d,=20but=20expected=20chunk=20with=20size=20%d",=0A+=09=09=09=09=09= =09=09=09=09=09=20ta->toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09= =09=09=20curchunk,=20chunksize,=0A+=09=09=09=09=09=09=09=09=09=09=20= (int)TOAST_MAX_CHUNK_SIZE));=0A=20=0A-=09if=20(chunksize=20!=3D=20= expected_size)=0A-=09=09report_toast_corruption(ctx,=20ta,=0A-=09=09=09=09= =09=09=09=09psprintf("toast=20value=20%u=20chunk=20%d=20has=20size=20%u,=20= but=20expected=20size=20%u",=0A+=09/*=20Report=20a=20final=20chunk=20of=20= the=20wrong=20size=20*/=0A+=09else=20if=20(curchunk=20=3D=3D=20= tctx->final_expected_chunk=20&&=20chunksize=20!=3D=20= tctx->final_expected_size)=0A+=09=09report_toast_corruption(hctx,=20ta,=0A= +=09=09=09=09=09=09=09=09psprintf("toast=20value=20%u=20chunk=20%d=20has=20= size=20%d,=20but=20expected=20chunk=20with=20size=20%d",=0A=20=09=09=09=09= =09=09=09=09=09=09=20ta->toast_pointer.va_valueid,=0A-=09=09=09=09=09=09=09= =09=09=09=20chunkno,=20chunksize,=20expected_size));=0A+=09=09=09=09=09=09= =09=09=09=09=20curchunk,=20chunksize,=0A+=09=09=09=09=09=09=09=09=09=09=20= tctx->final_expected_size));=0A+=0A+=09return=20chunksize;=0A=20}=0A=20=0A= =20/*=0A@@=20-1379,14=20+1580,55=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=09=20*/=0A=20=09= VARATT_EXTERNAL_GET_POINTER(toast_pointer,=20attr);=0A=20=0A+=09/*=20= Oversized=20toasted=20attributes=20should=20never=20be=20stored=20*/=0A+=09= if=20(toast_pointer.va_rawsize=20>=20VARLENA_SIZE_LIMIT)=0A+=09=09= report_corruption(ctx,=0A+=09=09=09=09=09=09=20=20psprintf("toast=20= value=20%u=20rawsize=20%u=20exceeds=20limit=20%u",=0A+=09=09=09=09=09=09=09= =09=20=20=20toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=20=20=20= toast_pointer.va_rawsize,=0A+=09=09=09=09=09=09=09=09=20=20=20= VARLENA_SIZE_LIMIT));=0A+=0A+=09/*=20Compression=20should=20never=20= expand=20the=20attribute=20*/=0A+=09if=20= (VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer)=20>=20= toast_pointer.va_rawsize=20-=20VARHDRSZ)=0A+=09=09report_corruption(ctx,=0A= +=09=09=09=09=09=09=20=20psprintf("toast=20value=20%u=20external=20size=20= %u=20exceeds=20maximum=20expected=20for=20rawsize=20%u",=0A+=09=09=09=09=09= =09=09=09=20=20=20toast_pointer.va_valueid,=0A+=09=09=09=09=09=09=09=09=20= =20=20VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer),=0A+=09=09=09=09=09=09=09= =09=20=20=20toast_pointer.va_rawsize));=0A+=0A+=09/*=20Compressed=20= attributes=20should=20have=20a=20valid=20compression=20method=20*/=0A+=09= if=20(VARATT_IS_COMPRESSED(&toast_pointer))=0A+=09{=0A+=09=09= ToastCompressionId=20cmid;=0A+=09=09bool=09=09invalid=20=3D=20true;=0A+=0A= +=09=09cmid=20=3D=20TOAST_COMPRESS_METHOD(&toast_pointer);=0A+=09=09= switch=20(cmid)=0A+=09=09{=0A+=09=09=09/*=20List=20of=20all=20valid=20= compression=20method=20IDs=20*/=0A+=09=09=09case=20= TOAST_PGLZ_COMPRESSION_ID:=0A+=09=09=09case=20TOAST_LZ4_COMPRESSION_ID:=0A= +=09=09=09=09invalid=20=3D=20false;=0A+=09=09=09=09break;=0A+=0A+=09=09=09= /*=20Recognized=20but=20invalid=20compression=20method=20ID=20*/=0A+=09=09= =09case=20TOAST_INVALID_COMPRESSION_ID:=0A+=09=09=09=09break;=0A+=0A+=09=09= =09/*=20Intentionally=20no=20default=20here=20*/=0A+=09=09}=0A+=0A+=09=09= if=20(invalid)=0A+=09=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=09= =20=20psprintf("toast=20value=20%u=20has=20invalid=20compression=20= method=20id=20%d",=0A+=09=09=09=09=09=09=09=09=09=20=20=20= toast_pointer.va_valueid,=20cmid));=0A+=09}=0A+=0A=20=09/*=20The=20tuple=20= header=20better=20claim=20to=20contain=20toasted=20values=20*/=0A=20=09= if=20(!(infomask=20&=20HEAP_HASEXTERNAL))=0A-=09{=0A=20=09=09= report_corruption(ctx,=0A=20=09=09=09=09=09=09=20=20psprintf("toast=20= value=20%u=20is=20external=20but=20tuple=20header=20flag=20= HEAP_HASEXTERNAL=20not=20set",=0A=20=09=09=09=09=09=09=09=09=20=20=20= toast_pointer.va_valueid));=0A-=09=09return=20true;=0A-=09}=0A=20=0A=20=09= /*=20The=20relation=20better=20have=20a=20toast=20table=20*/=0A=20=09if=20= (!ctx->rel->rd_rel->reltoastrelid)=0A@@=20-1397,6=20+1639,14=20@@=20= check_tuple_attribute(HeapCheckContext=20*ctx)=0A=20=09=09return=20true;=0A= =20=09}=0A=20=0A+=09/*=20The=20toast=20pointer=20had=20better=20point=20= at=20the=20relation's=20toast=20table=20*/=0A+=09if=20= (toast_pointer.va_toastrelid=20!=3D=20ctx->rel->rd_rel->reltoastrelid)=0A= +=09=09report_corruption(ctx,=0A+=09=09=09=09=09=09=20=20psprintf("toast=20= value=20%u=20toast=20relation=20oid=20%u=20differs=20from=20expected=20= oid=20%u",=0A+=09=09=09=09=09=09=09=09=20=20=20toast_pointer.va_valueid,=0A= +=09=09=09=09=09=09=09=09=20=20=20toast_pointer.va_toastrelid,=0A+=09=09=09= =09=09=09=09=09=20=20=20ctx->rel->rd_rel->reltoastrelid));=0A+=0A=20=09= /*=20If=20we=20were=20told=20to=20skip=20toast=20checking,=20then=20= we're=20done.=20*/=0A=20=09if=20(ctx->toast_rel=20=3D=3D=20NULL)=0A=20=09= =09return=20true;=0A@@=20-1437,9=20+1687,20=20@@=20= check_toasted_attribute(HeapCheckContext=20*ctx,=20ToastedAttribute=20= *ta)=0A=20=09bool=09=09found_toasttup;=0A=20=09HeapTuple=09toasttup;=0A=20= =09int32=09=09chunkno;=0A-=09int32=09=09endchunk;=0A+=09int64=09=09= totalsize;=09=09/*=20corrupt=20toast=20could=20overflow=2032=20bits=20*/=0A= +=09int32=09=09extsize;=0A+=09ToastCheckContext=20tctx;=0A+=0A+=09/*=20= Calculate=20expected=20number=20of=20chunks=20and=20size=20of=20final=20= chunk=20*/=0A+=09extsize=20=3D=20= VARATT_EXTERNAL_GET_EXTSIZE(ta->toast_pointer);=0A+=09= tctx.final_expected_chunk=20=3D=20(extsize=20-=201)=20/=20= TOAST_MAX_CHUNK_SIZE;=0A+=09tctx.final_expected_size=20=3D=20extsize=20-=20= tctx.final_expected_chunk=20*=20TOAST_MAX_CHUNK_SIZE;=0A=20=0A-=09= endchunk=20=3D=20(VARATT_EXTERNAL_GET_EXTSIZE(ta->toast_pointer)=20-=20= 1)=20/=20TOAST_MAX_CHUNK_SIZE;=0A+=09/*=20Have=20not=20yet=20seen=20any=20= chunks=20for=20this=20toast=20tuple=20*/=0A+=09= tctx.have_extraneous_chunks=20=3D=20false;=0A+=09tctx.first_extraneous=20= =3D=20-1;=0A+=09tctx.last_extraneous=20=3D=20-1;=0A+=09= tctx.last_chunk_seen=20=3D=20-1;=0A=20=0A=20=09/*=0A=20=09=20*=20Setup=20= a=20scan=20key=20to=20find=20chunks=20in=20toast=20table=20with=20= matching=20va_valueid=0A@@=20-1459,13=20+1720,14=20@@=20= check_toasted_attribute(HeapCheckContext=20*ctx,=20ToastedAttribute=20= *ta)=0A=20=09=09=09=09=09=09=09=09=09=09=20=20=20&SnapshotToast,=201,=0A=20= =09=09=09=09=09=09=09=09=09=09=20=20=20&toastkey);=0A=20=09chunkno=20=3D=20= 0;=0A+=09totalsize=20=3D=200;=0A=20=09found_toasttup=20=3D=20false;=0A=20= =09while=20((toasttup=20=3D=0A=20=09=09=09= systable_getnext_ordered(toastscan,=0A=20=09=09=09=09=09=09=09=09=09=20= ForwardScanDirection))=20!=3D=20NULL)=0A=20=09{=0A=20=09=09= found_toasttup=20=3D=20true;=0A-=09=09check_toast_tuple(toasttup,=20ctx,=20= ta,=20chunkno,=20endchunk);=0A+=09=09totalsize=20+=3D=20= check_toast_tuple(toasttup,=20ta,=20&tctx,=20ctx,=20chunkno);=0A=20=09=09= chunkno++;=0A=20=09}=0A=20=09systable_endscan_ordered(toastscan);=0A@@=20= -1474,11=20+1736,15=20@@=20check_toasted_attribute(HeapCheckContext=20= *ctx,=20ToastedAttribute=20*ta)=0A=20=09=09report_toast_corruption(ctx,=20= ta,=0A=20=09=09=09=09=09=09=09=09psprintf("toast=20value=20%u=20not=20= found=20in=20toast=20table",=0A=20=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid));=0A-=09else=20if=20(chunkno=20!=3D=20= (endchunk=20+=201))=0A+=09else=20if=20(chunkno=20!=3D=20= tctx.final_expected_chunk=20+=201=20||=20extsize=20!=3D=20totalsize)=0A=20= =09=09report_toast_corruption(ctx,=20ta,=0A-=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20was=20expected=20to=20end=20at=20chunk=20= %d,=20but=20ended=20at=20chunk=20%d",=0A+=09=09=09=09=09=09=09=09= psprintf("toast=20value=20%u=20was=20expected=20to=20end=20at=20chunk=20= %u=20with=20total=20size=20%d,=20but=20ended=20at=20chunk=20%u=20with=20= total=20size=20"=20INT64_FORMAT,=0A=20=09=09=09=09=09=09=09=09=09=09=20= ta->toast_pointer.va_valueid,=0A-=09=09=09=09=09=09=09=09=09=09=20= (endchunk=20+=201),=20chunkno));=0A+=09=09=09=09=09=09=09=09=09=09=20= (tctx.final_expected_chunk=20+=201),=0A+=09=09=09=09=09=09=09=09=09=09=20= extsize,=20chunkno,=20totalsize));=0A+=0A+=09/*=20Report=20any=20= remaining=20cached=20extraneous=20chunks=20*/=0A+=09= report_extraneous_chunks(ctx,=20ta,=20&tctx,=20NULL,=20NULL);=0A=20}=0A=20= =0A=20/*=0Adiff=20--git=20a/src/tools/pgindent/typedefs.list=20= b/src/tools/pgindent/typedefs.list=0Aindex=20c7aff677d4..996ef03180=20= 100644=0A---=20a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-2558,6=20+2558,7=20@@=20= TimestampTz=0A=20TmFromChar=0A=20TmToChar=0A=20ToastAttrInfo=0A= +ToastCheckContext=0A=20ToastTupleContext=0A=20ToastedAttribute=0A=20= TocEntry=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_E9A07B8E-5C76-4E7C-95AB-CE07977E656B 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=_E9A07B8E-5C76-4E7C-95AB-CE07977E656B--