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 1l74oq-0001Sz-AO for pgsql-hackers@arkaria.postgresql.org; Tue, 02 Feb 2021 23:10:49 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1l74on-000509-Lo for pgsql-hackers@arkaria.postgresql.org; Tue, 02 Feb 2021 23:10:45 +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 1l74on-0004zW-2F for pgsql-hackers@lists.postgresql.org; Tue, 02 Feb 2021 23:10:45 +0000 Received: from mail-pg1-x52c.google.com ([2607:f8b0:4864:20::52c]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1l74oh-0005SF-L6 for pgsql-hackers@postgresql.org; Tue, 02 Feb 2021 23:10:44 +0000 Received: by mail-pg1-x52c.google.com with SMTP id s23so14673016pgh.11 for ; Tue, 02 Feb 2021 15:10:39 -0800 (PST) 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=3MhxNdDZmWXtDTm/gMLw7PJlJV2UgPEuBqcqi7LOc+w=; b=KXYroCssosdaWGWhyxfgNV11BE8CLJWCx9Q1paVvNGKL03k9Bo2xHN731qTQmmLciE z+my2SJUmCAki0IitlT4RKBQuFiinx84SCaFCdYKsTN8gAkfAI4rwRIXhgxw9IRDBWQZ AhqK0rYijz67h3Tr/xDMJCJOGm8XFc/QjfCVz2acNEGLrteLeOCAToCNW4h1xA+BmPkL nCKqGGH9NjS4Ajr1BO07oYJ9OpX4O1pe/HBXrI0CfaMOS73npk7+Nvn3zw/oCoJHKxLN SHezSjgKXVGv8UY9ByprKem/0acpEpEsD1PZtxnHo9ZmM53MicfGKuVqhOxk4ifJNRyP ZPeA== 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=3MhxNdDZmWXtDTm/gMLw7PJlJV2UgPEuBqcqi7LOc+w=; b=oXf2Eb2FdOTRbnrMJFcz5bu7Y0MkcI/64V/u+ym9OUnDBOjdR8+6q8f7gTJYR3StuY FbcX9kbhJ8xNpZiVMzAMgkHCB6DlkzkIlZilyq8WMtKs1rFkYQs5ousKQ3K+wbJwp8aV uWn307J+f8y1OQH8Qe3yoyYZEd1ZQRXstXILp5O6b8PE4ed/wUUVoJzDL4KCerkU4ZNI +uvLBjis9Yg5flUD91Scjjh/0HH8kFlxI5aeeqqTIQwE1IG6L8sFCafwk3Pr/DL3RJpM X+n3/KCshvuiWwRyieqsF4Lv9FmOItXSDeDLVJMZNN8JOkcTGRE104TMFRN8p8L7/sDn vWvw== X-Gm-Message-State: AOAM533A/ZC6Tshaf2mTT4PJCJuoFEn8LvV8mnV1a5RVqHBVGnShc6sK tDhcZqQ9oUDt8fSzGnDsU140qLLzNEDvc56NbYAj0CvcG90C5hz7JrmJrMuBm4mlTvrLzBQgTFh NoQFwhjh6Y+yEflAGKO0Dvq/4aPKnoOW7chpTX+9gSxcwCELCddytotrSIqzD9ehlvJ3+OP411L 84I7p1D5G3aV/YxH0G+xRk2fG5HFX3L7qxNlXq X-Google-Smtp-Source: ABdhPJxdM2qrDYLD7GNm2FLWwlOO/xlpCflM7C3j3jmH/2b+jfn+IiIu8TWaYmZVpymc7CJjYJgyoA== X-Received: by 2002:a63:f34f:: with SMTP id t15mr395021pgj.239.1612307437128; Tue, 02 Feb 2021 15:10:37 -0800 (PST) Received: from [192.168.0.29] (24-113-193-150.wavecable.com. [24.113.193.150]) by smtp.gmail.com with ESMTPSA id dw23sm90894pjb.3.2021.02.02.15.10.34 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 02 Feb 2021 15:10:35 -0800 (PST) From: Mark Dilger Message-Id: <70655DF3-33CE-4527-9A4D-DDEB582B6BA0@enterprisedb.com> Content-Type: multipart/mixed; boundary="Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34" Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.1\)) Subject: Re: new heapcheck contrib module Date: Tue, 2 Feb 2021 15:10:34 -0800 In-Reply-To: <70A7BABE-EDC1-4217-8FEB-F446F2938CE1@enterprisedb.com> Cc: Thomas Munro , Tom Lane , Peter Geoghegan , "Andrey M. Borodin" , Stephen Frost , Michael Paquier , Amul Sul , Dilip Kumar , Andres Freund , PostgreSQL-development To: Robert Haas References: <12ED3DA8-25F0-4B68-937D-D907CFBF08E7@enterprisedb.com> <20200420194210.sevnpi4lyghoanxi@alap3.anarazel.de> <23E60C3C-C20A-4508-84AC-E0CEA59E784A@enterprisedb.com> <5F743835-3399-419C-8324-2D424237E999@enterprisedb.com> <885D2EC9-7D06-4903-A17D-72C184A1E1C5@enterprisedb.com> <5CC85F28-F210-47AC-8DA8-EC4E82AF3FD5@enterprisedb.com> <0C0349EB-DD85-4DA8-82C7-DF70AB714592@enterprisedb.com> <9DF93B83-FE46-4EC4-A99D-77A60729FD2D@enterprisedb.com> <50F6468F-5A5E-412A-86EC-DF24B549D733@enterprisedb.com> <7D603B53-8078-4AF0-851B-803FF4416501@enterprisedb.com> <98265AA9-7BDC-4708-9348-CC1B173BBE1D@enterprisedb.com> <209783.1603313248@sss.pgh.pa.us> <77A60E99-6054-40FD-A5D6-769C287D4A0F@enterprisedb.com> <721BFA83-EA6F-463D-A9DF-CE78A318B73A@enterprisedb.com> <2A7DA1A8-C4AA-43DF-A985-3CA52F4DC775@enterprisedb.com> <146814.1603463293@sss.pgh.pa.us> <221029.1603476265@sss.pgh.pa.us> <153EEBAD-2673-4367-B36D-4A6AE8EE7A9F@enterprisedb.com> <85BE72E5-A926-4F23-9FD5-64239C0C6BA5@enterprisedb.com> <10677BFE-3B45-4EF3-82E5-E45CA1445CA6@enterprisedb.com> <411C72E5-23A6-485F-A101-FBF7CFA6D2D5@enterprisedb.com> <70A7BABE-EDC1-4217-8FEB-F446F2938CE1@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: Precedence: bulk --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On Jan 31, 2021, at 4:05 PM, Mark Dilger = wrote: >=20 > Attached is patch set 35. I found some things to improve in the v35 patch set. Please find = attached the v36 patch set, which differs from v35 in the following = ways: 0001 -- no changes 0002 -- fixing omissions in @pgfeutilsfiles in file = src/tools/msvc/Mkvcbuild.pm 0003 -- no changes 0004: -- Fixes handling of amcheck contrib module installed in non-default = schema. -- Adds database name to corruption messages to make identifying the = relation being complained about unambiguous in multi-database checks -- Fixes an instance where pg_amcheck was querying pg_database without = schema-qualifying it -- Simplifying some functions in pg_amcheck.c -- Updating a comment to reflect the renaming of a variable that the = comment mentioned by name 0005 -- fixes =3Dpod added in PostgresNode.pm. The =3Dpod was = grammatically correct so far I can tell, but rendered strangely in = perldoc. --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 Content-Disposition: attachment; filename=v36-0001-Refactoring-processSQLNamePattern.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v36-0001-Refactoring-processSQLNamePattern.patch" Content-Transfer-Encoding: quoted-printable =46rom=205375f952570ff75a56e916de13e63c43c3ba2604=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Tue,=202=20Feb=202021=2012:29:11=20-0800=0ASubject:=20[PATCH=20= v36=201/5]=20Refactoring=20processSQLNamePattern.=0A=0AFactoring=20out=20= logic=20which=20transforms=20shell-style=20patterns=20into=20SQL=0Astyle=20= regexp=20format=20from=20inside=20processSQLNamePattern=20into=20a=0A= separate=20new=20function=20"patternToSQLRegex".=20=20The=20interface=20= and=0Asemantics=20of=20processSQLNamePattern=20are=20unchanged.=0A=0AThe=20= motivation=20for=20the=20refactoring=20is=20that=20processSQLNamePattern=0A= mixes=20the=20job=20of=20transforming=20the=20pattern=20with=20the=20job=20= of=0Aconstructing=20a=20where-clause=20based=20on=20a=20single=20= pattern,=20which=20makes=0Athe=20code=20hard=20to=20reuse=20from=20other=20= places.=0A=0AThe=20new=20helper=20function=20patternToSQLRegex=20can=20= handle=20parsing=20of=0Apatterns=20of=20the=20form=20= "database.schema.relation",=20"schema.relation",=0Aand=20"relation".=20=20= The=20three-part=20form=20is=20unused=20in=20this=20commit,=20as=0Athe=20= pre-existing=20patternToSQLRegex=20function=20ignores=20the=20dbname=0A= functionality,=20and=20there=20are=20not=20yet=20any=20other=20callers.=20= =20The=0Athree-part=20form=20will=20be=20used=20by=20pg_amcheck,=20not=20= yet=20committed,=20to=0Aallow=20specifying=20on=20the=20command=20line=20= the=20inclusion=20and=20exclusion=20of=0Arelations=20spanning=20multiple=20= databases.=0A---=0A=20src/fe_utils/string_utils.c=20=20=20=20=20=20=20=20= =20|=20260=20+++++++++++++++++-----------=0A=20= src/include/fe_utils/string_utils.h=20|=20=20=204=20+=0A=202=20files=20= changed,=20167=20insertions(+),=2097=20deletions(-)=0A=0Adiff=20--git=20= a/src/fe_utils/string_utils.c=20b/src/fe_utils/string_utils.c=0Aindex=20= a1a9d691d5..9a1ea9ab98=20100644=0A---=20a/src/fe_utils/string_utils.c=0A= +++=20b/src/fe_utils/string_utils.c=0A@@=20-831,10=20+831,6=20@@=20= processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20buf,=20const=20= char=20*pattern,=0A=20{=0A=20=09PQExpBufferData=20schemabuf;=0A=20=09= PQExpBufferData=20namebuf;=0A-=09int=09=09=09encoding=20=3D=20= PQclientEncoding(conn);=0A-=09bool=09=09inquotes;=0A-=09const=20char=20= *cp;=0A-=09int=09=09=09i;=0A=20=09bool=09=09added_clause=20=3D=20false;=0A= =20=0A=20#define=20WHEREAND()=20\=0A@@=20-856,98=20+852,12=20@@=20= processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20buf,=20const=20= char=20*pattern,=0A=20=09initPQExpBuffer(&namebuf);=0A=20=0A=20=09/*=0A-=09= =20*=20Parse=20the=20pattern,=20converting=20quotes=20and=20lower-casing=20= unquoted=20letters.=0A-=09=20*=20Also,=20adjust=20shell-style=20wildcard=20= characters=20into=20regexp=20notation.=0A-=09=20*=0A-=09=20*=20We=20= surround=20the=20pattern=20with=20"^(...)$"=20to=20force=20it=20to=20= match=20the=20whole=0A-=09=20*=20string,=20as=20per=20SQL=20practice.=20=20= We=20have=20to=20have=20parens=20in=20case=20the=20string=0A-=09=20*=20= contains=20"|",=20else=20the=20"^"=20and=20"$"=20will=20be=20bound=20= into=20the=20first=20and=0A-=09=20*=20last=20alternatives=20which=20is=20= not=20what=20we=20want.=0A-=09=20*=0A-=09=20*=20Note:=20the=20result=20= of=20this=20pass=20is=20the=20actual=20regexp=20pattern(s)=20we=20want=0A= -=09=20*=20to=20execute.=20=20Quoting/escaping=20into=20SQL=20literal=20= format=20will=20be=20done=0A-=09=20*=20below=20using=20= appendStringLiteralConn().=0A+=09=20*=20Convert=20shell-style=20= 'pattern'=20into=20the=20regular=20expression(s)=20we=20want=20to=0A+=09=20= *=20execute.=20=20Quoting/escaping=20into=20SQL=20literal=20format=20= will=20be=20done=20below=0A+=09=20*=20using=20appendStringLiteralConn().=0A= =20=09=20*/=0A-=09appendPQExpBufferStr(&namebuf,=20"^(");=0A-=0A-=09= inquotes=20=3D=20false;=0A-=09cp=20=3D=20pattern;=0A-=0A-=09while=20= (*cp)=0A-=09{=0A-=09=09char=09=09ch=20=3D=20*cp;=0A-=0A-=09=09if=20(ch=20= =3D=3D=20'"')=0A-=09=09{=0A-=09=09=09if=20(inquotes=20&&=20cp[1]=20=3D=3D=20= '"')=0A-=09=09=09{=0A-=09=09=09=09/*=20emit=20one=20quote,=20stay=20in=20= inquotes=20mode=20*/=0A-=09=09=09=09appendPQExpBufferChar(&namebuf,=20= '"');=0A-=09=09=09=09cp++;=0A-=09=09=09}=0A-=09=09=09else=0A-=09=09=09=09= inquotes=20=3D=20!inquotes;=0A-=09=09=09cp++;=0A-=09=09}=0A-=09=09else=20= if=20(!inquotes=20&&=20isupper((unsigned=20char)=20ch))=0A-=09=09{=0A-=09= =09=09appendPQExpBufferChar(&namebuf,=0A-=09=09=09=09=09=09=09=09=20=20= pg_tolower((unsigned=20char)=20ch));=0A-=09=09=09cp++;=0A-=09=09}=0A-=09=09= else=20if=20(!inquotes=20&&=20ch=20=3D=3D=20'*')=0A-=09=09{=0A-=09=09=09= appendPQExpBufferStr(&namebuf,=20".*");=0A-=09=09=09cp++;=0A-=09=09}=0A-=09= =09else=20if=20(!inquotes=20&&=20ch=20=3D=3D=20'?')=0A-=09=09{=0A-=09=09=09= appendPQExpBufferChar(&namebuf,=20'.');=0A-=09=09=09cp++;=0A-=09=09}=0A-=09= =09else=20if=20(!inquotes=20&&=20ch=20=3D=3D=20'.')=0A-=09=09{=0A-=09=09=09= /*=20Found=20schema/name=20separator,=20move=20current=20pattern=20to=20= schema=20*/=0A-=09=09=09resetPQExpBuffer(&schemabuf);=0A-=09=09=09= appendPQExpBufferStr(&schemabuf,=20namebuf.data);=0A-=09=09=09= resetPQExpBuffer(&namebuf);=0A-=09=09=09appendPQExpBufferStr(&namebuf,=20= "^(");=0A-=09=09=09cp++;=0A-=09=09}=0A-=09=09else=20if=20(ch=20=3D=3D=20= '$')=0A-=09=09{=0A-=09=09=09/*=0A-=09=09=09=20*=20Dollar=20is=20always=20= quoted,=20whether=20inside=20quotes=20or=20not.=20The=0A-=09=09=09=20*=20= reason=20is=20that=20it's=20allowed=20in=20SQL=20identifiers,=20so=20= there's=20a=0A-=09=09=09=20*=20significant=20use-case=20for=20treating=20= it=20literally,=20while=20because=0A-=09=09=09=20*=20we=20anchor=20the=20= pattern=20automatically=20there=20is=20no=20use-case=20for=0A-=09=09=09=20= *=20having=20it=20possess=20its=20regexp=20meaning.=0A-=09=09=09=20*/=0A= -=09=09=09appendPQExpBufferStr(&namebuf,=20"\\$");=0A-=09=09=09cp++;=0A-=09= =09}=0A-=09=09else=0A-=09=09{=0A-=09=09=09/*=0A-=09=09=09=20*=20Ordinary=20= data=20character,=20transfer=20to=20pattern=0A-=09=09=09=20*=0A-=09=09=09= =20*=20Inside=20double=20quotes,=20or=20at=20all=20times=20if=20= force_escape=20is=20true,=0A-=09=09=09=20*=20quote=20regexp=20special=20= characters=20with=20a=20backslash=20to=20avoid=0A-=09=09=09=20*=20regexp=20= errors.=20=20Outside=20quotes,=20however,=20let=20them=20pass=20through=0A= -=09=09=09=20*=20as-is;=20this=20lets=20knowledgeable=20users=20build=20= regexp=20expressions=0A-=09=09=09=20*=20that=20are=20more=20powerful=20= than=20shell-style=20patterns.=0A-=09=09=09=20*/=0A-=09=09=09if=20= ((inquotes=20||=20force_escape)=20&&=0A-=09=09=09=09= strchr("|*+?()[]{}.^$\\",=20ch))=0A-=09=09=09=09= appendPQExpBufferChar(&namebuf,=20'\\');=0A-=09=09=09i=20=3D=20= PQmblen(cp,=20encoding);=0A-=09=09=09while=20(i--=20&&=20*cp)=0A-=09=09=09= {=0A-=09=09=09=09appendPQExpBufferChar(&namebuf,=20*cp);=0A-=09=09=09=09= cp++;=0A-=09=09=09}=0A-=09=09}=0A-=09}=0A+=09= patternToSQLRegex(PQclientEncoding(conn),=20NULL,=20&schemabuf,=20= &namebuf,=0A+=09=09=09=09=09=20=20pattern,=20force_escape);=0A=20=0A=20=09= /*=0A=20=09=20*=20Now=20decide=20what=20we=20need=20to=20emit.=20=20We=20= may=20run=20under=20a=20hostile=0A@@=20-964,7=20+874,6=20@@=20= processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20buf,=20const=20= char=20*pattern,=0A=20=09{=0A=20=09=09/*=20We=20have=20a=20name=20= pattern,=20so=20constrain=20the=20namevar(s)=20*/=0A=20=0A-=09=09= appendPQExpBufferStr(&namebuf,=20")$");=0A=20=09=09/*=20Optimize=20away=20= a=20"*"=20pattern=20*/=0A=20=09=09if=20(strcmp(namebuf.data,=20"^(.*)$")=20= !=3D=200)=0A=20=09=09{=0A@@=20-999,7=20+908,6=20@@=20= processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20buf,=20const=20= char=20*pattern,=0A=20=09{=0A=20=09=09/*=20We=20have=20a=20schema=20= pattern,=20so=20constrain=20the=20schemavar=20*/=0A=20=0A-=09=09= appendPQExpBufferStr(&schemabuf,=20")$");=0A=20=09=09/*=20Optimize=20= away=20a=20"*"=20pattern=20*/=0A=20=09=09if=20(strcmp(schemabuf.data,=20= "^(.*)$")=20!=3D=200=20&&=20schemavar)=0A=20=09=09{=0A@@=20-1027,3=20= +935,161=20@@=20processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20= buf,=20const=20char=20*pattern,=0A=20=09return=20added_clause;=0A=20= #undef=20WHEREAND=0A=20}=0A+=0A+/*=0A+=20*=20Transform=20a=20possibly=20= qualified=20shell-style=20object=20name=20pattern=20into=20up=20to=0A+=20= *=20three=20SQL-style=20regular=20expressions,=20converting=20quotes,=20= lower-casing=0A+=20*=20unquoted=20letters,=20and=20adjusting=20= shell-style=20wildcard=20characters=20into=20regexp=0A+=20*=20notation.=0A= +=20*=0A+=20*=20If=20the=20dbnamebuf=20and=20schemabuf=20arguments=20are=20= non-NULL,=20and=20the=20pattern=0A+=20*=20contains=20two=20or=20more=20= dbname/schema/name=20separators,=20we=20parse=20the=20portions=20of=0A+=20= *=20the=20pattern=20prior=20to=20the=20first=20and=20second=20separators=20= into=20dbnamebuf=20and=0A+=20*=20schemabuf,=20and=20the=20rest=20into=20= namebuf.=20=20(Additional=20dots=20in=20the=20name=20portion=0A+=20*=20= are=20not=20treated=20as=20special.)=0A+=20*=0A+=20*=20If=20dbnamebuf=20= is=20NULL=20and=20schemabuf=20is=20non-NULL,=20and=20the=20pattern=20= contains=20at=0A+=20*=20least=20one=20separator,=20we=20parse=20the=20= first=20portion=20into=20schemabuf=20and=20the=20rest=0A+=20*=20into=20= namebuf.=0A+=20*=0A+=20*=20Otherwise,=20we=20parse=20all=20the=20pattern=20= into=20namebuf.=0A+=20*=0A+=20*=20We=20surround=20the=20regexps=20with=20= "^(...)$"=20to=20force=20them=20to=20match=20whole=20strings,=0A+=20*=20= as=20per=20SQL=20practice.=20=20We=20have=20to=20have=20parens=20in=20= case=20strings=20contain=20"|",=0A+=20*=20else=20the=20"^"=20and=20"$"=20= will=20be=20bound=20into=20the=20first=20and=20last=20alternatives=0A+=20= *=20which=20is=20not=20what=20we=20want.=0A+=20*=0A+=20*=20The=20regexps=20= we=20parse=20into=20the=20buffers=20are=20appended=20to=20the=20data=20= (if=20any)=0A+=20*=20already=20present.=20=20If=20we=20parse=20fewer=20= fields=20than=20the=20number=20of=20buffers=20we=0A+=20*=20were=20given,=20= the=20extra=20buffers=20are=20unaltered.=0A+=20*/=0A+void=0A= +patternToSQLRegex(int=20encoding,=20PQExpBuffer=20dbnamebuf,=20= PQExpBuffer=20schemabuf,=0A+=09=09=09=09=20=20PQExpBuffer=20namebuf,=20= const=20char=20*pattern,=20bool=20force_escape)=0A+{=0A+=09= PQExpBufferData=20buf[3];=0A+=09PQExpBuffer=20curbuf;=0A+=09PQExpBuffer=20= maxbuf;=0A+=09int=09=09=09i;=0A+=09bool=09=09inquotes;=0A+=09const=20= char=20*cp;=0A+=0A+=09Assert(pattern=20!=3D=20NULL);=0A+=09= Assert(namebuf=20!=3D=20NULL);=0A+=0A+=09/*=20callers=20should=20never=20= expect=20"dbname.relname"=20format=20*/=0A+=09Assert(dbnamebuf=20=3D=3D=20= NULL=20||=20schemabuf=20!=3D=20NULL);=0A+=0A+=09inquotes=20=3D=20false;=0A= +=09cp=20=3D=20pattern;=0A+=0A+=09if=20(dbnamebuf=20!=3D=20NULL)=0A+=09=09= maxbuf=20=3D=20&buf[2];=0A+=09else=20if=20(schemabuf=20!=3D=20NULL)=0A+=09= =09maxbuf=20=3D=20&buf[1];=0A+=09else=0A+=09=09maxbuf=20=3D=20&buf[0];=0A= +=0A+=09curbuf=20=3D=20&buf[0];=0A+=09initPQExpBuffer(curbuf);=0A+=09= appendPQExpBufferStr(curbuf,=20"^(");=0A+=09while=20(*cp)=0A+=09{=0A+=09=09= char=09=09ch=20=3D=20*cp;=0A+=0A+=09=09if=20(ch=20=3D=3D=20'"')=0A+=09=09= {=0A+=09=09=09if=20(inquotes=20&&=20cp[1]=20=3D=3D=20'"')=0A+=09=09=09{=0A= +=09=09=09=09/*=20emit=20one=20quote,=20stay=20in=20inquotes=20mode=20*/=0A= +=09=09=09=09appendPQExpBufferChar(curbuf,=20'"');=0A+=09=09=09=09cp++;=0A= +=09=09=09}=0A+=09=09=09else=0A+=09=09=09=09inquotes=20=3D=20!inquotes;=0A= +=09=09=09cp++;=0A+=09=09}=0A+=09=09else=20if=20(!inquotes=20&&=20= isupper((unsigned=20char)=20ch))=0A+=09=09{=0A+=09=09=09= appendPQExpBufferChar(curbuf,=0A+=09=09=09=09=09=09=09=09=20=20= pg_tolower((unsigned=20char)=20ch));=0A+=09=09=09cp++;=0A+=09=09}=0A+=09=09= else=20if=20(!inquotes=20&&=20ch=20=3D=3D=20'*')=0A+=09=09{=0A+=09=09=09= appendPQExpBufferStr(curbuf,=20".*");=0A+=09=09=09cp++;=0A+=09=09}=0A+=09= =09else=20if=20(!inquotes=20&&=20ch=20=3D=3D=20'?')=0A+=09=09{=0A+=09=09=09= appendPQExpBufferChar(curbuf,=20'.');=0A+=09=09=09cp++;=0A+=09=09}=0A+=0A= +=09=09/*=0A+=09=09=20*=20When=20we=20find=20a=20dbname/schema/name=20= separator,=20we=20treat=20it=20specially=0A+=09=09=20*=20only=20if=20the=20= caller=20requested=20more=20patterns=20to=20be=20parsed=20than=20we=0A+=09= =09=20*=20have=20already=20parsed=20from=20the=20pattern.=20=20= Otherwise,=20dot=20characters=0A+=09=09=20*=20are=20not=20special.=0A+=09= =09=20*/=0A+=09=09else=20if=20(!inquotes=20&&=20ch=20=3D=3D=20'.'=20&&=20= curbuf=20<=20maxbuf)=0A+=09=09{=0A+=09=09=09appendPQExpBufferStr(curbuf,=20= ")$");=0A+=09=09=09curbuf++;=0A+=09=09=09initPQExpBuffer(curbuf);=0A+=09=09= =09appendPQExpBufferStr(curbuf,=20"^(");=0A+=09=09=09cp++;=0A+=09=09}=0A= +=09=09else=20if=20(ch=20=3D=3D=20'$')=0A+=09=09{=0A+=09=09=09/*=0A+=09=09= =09=20*=20Dollar=20is=20always=20quoted,=20whether=20inside=20quotes=20= or=20not.=20The=0A+=09=09=09=20*=20reason=20is=20that=20it's=20allowed=20= in=20SQL=20identifiers,=20so=20there's=20a=0A+=09=09=09=20*=20= significant=20use-case=20for=20treating=20it=20literally,=20while=20= because=0A+=09=09=09=20*=20we=20anchor=20the=20pattern=20automatically=20= there=20is=20no=20use-case=20for=0A+=09=09=09=20*=20having=20it=20= possess=20its=20regexp=20meaning.=0A+=09=09=09=20*/=0A+=09=09=09= appendPQExpBufferStr(curbuf,=20"\\$");=0A+=09=09=09cp++;=0A+=09=09}=0A+=09= =09else=0A+=09=09{=0A+=09=09=09/*=0A+=09=09=09=20*=20Ordinary=20data=20= character,=20transfer=20to=20pattern=0A+=09=09=09=20*=0A+=09=09=09=20*=20= Inside=20double=20quotes,=20or=20at=20all=20times=20if=20force_escape=20= is=20true,=0A+=09=09=09=20*=20quote=20regexp=20special=20characters=20= with=20a=20backslash=20to=20avoid=0A+=09=09=09=20*=20regexp=20errors.=20=20= Outside=20quotes,=20however,=20let=20them=20pass=20through=0A+=09=09=09=20= *=20as-is;=20this=20lets=20knowledgeable=20users=20build=20regexp=20= expressions=0A+=09=09=09=20*=20that=20are=20more=20powerful=20than=20= shell-style=20patterns.=0A+=09=09=09=20*/=0A+=09=09=09if=20((inquotes=20= ||=20force_escape)=20&&=0A+=09=09=09=09strchr("|*+?()[]{}.^$\\",=20ch))=0A= +=09=09=09=09appendPQExpBufferChar(curbuf,=20'\\');=0A+=09=09=09i=20=3D=20= PQmblen(cp,=20encoding);=0A+=09=09=09while=20(i--=20&&=20*cp)=0A+=09=09=09= {=0A+=09=09=09=09appendPQExpBufferChar(curbuf,=20*cp);=0A+=09=09=09=09= cp++;=0A+=09=09=09}=0A+=09=09}=0A+=09}=0A+=09= appendPQExpBufferStr(curbuf,=20")$");=0A+=0A+=09= appendPQExpBufferStr(namebuf,=20curbuf->data);=0A+=09= termPQExpBuffer(curbuf);=0A+=0A+=09if=20(curbuf=20>=20buf)=0A+=09{=0A+=09= =09curbuf--;=0A+=09=09appendPQExpBufferStr(schemabuf,=20curbuf->data);=0A= +=09=09termPQExpBuffer(curbuf);=0A+=0A+=09=09if=20(curbuf=20>=20buf)=0A+=09= =09{=0A+=09=09=09curbuf--;=0A+=09=09=09appendPQExpBufferStr(dbnamebuf,=20= curbuf->data);=0A+=09=09=09termPQExpBuffer(curbuf);=0A+=09=09}=0A+=09}=0A= +}=0Adiff=20--git=20a/src/include/fe_utils/string_utils.h=20= b/src/include/fe_utils/string_utils.h=0Aindex=20c290c302f5..caafb97d29=20= 100644=0A---=20a/src/include/fe_utils/string_utils.h=0A+++=20= b/src/include/fe_utils/string_utils.h=0A@@=20-56,4=20+56,8=20@@=20extern=20= bool=20processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20buf,=0A=20=09= =09=09=09=09=09=09=09=20=20const=20char=20*schemavar,=20const=20char=20= *namevar,=0A=20=09=09=09=09=09=09=09=09=20=20const=20char=20*altnamevar,=20= const=20char=20*visibilityrule);=0A=20=0A+extern=20void=20= patternToSQLRegex(int=20encoding,=20PQExpBuffer=20dbnamebuf,=0A+=09=09=09= =09=09=09=09=20=20PQExpBuffer=20schemabuf,=20PQExpBuffer=20namebuf,=0A+=09= =09=09=09=09=09=09=20=20const=20char=20*pattern,=20bool=20force_escape);=0A= +=0A=20#endif=09=09=09=09=09=09=09/*=20STRING_UTILS_H=20*/=0A--=20=0A= 2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 Content-Disposition: attachment; filename=v36-0002-Moving-code-from-src-bin-scripts-to-fe_utils.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v36-0002-Moving-code-from-src-bin-scripts-to-fe_utils.patch" Content-Transfer-Encoding: quoted-printable =46rom=203c671447d64d68bd2e378aebc04db1e6dae8206c=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Tue,=202=20Feb=202021=2012:30:53=20-0800=0ASubject:=20[PATCH=20= v36=202/5]=20Moving=20code=20from=20src/bin/scripts=20to=20fe_utils=0A=0A= To=20make=20code=20useable=20from=20contrib/pg_amcheck,=20moving=0A= scripts_parallel.[ch]=20and=20handle_help_version_opts()=20into=0A= fe_utils.=0A=0AMoving=20supporting=20code=20from=20= src/bin/scripts/common=20into=20fe_utils.=0A=0AUpdating=20applications=20= in=20src/bin/scripts=20with=20the=20new=20location.=0A---=0A=20= src/bin/scripts/Makefile=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=20=206=20+-=0A=20src/bin/scripts/clusterdb.c=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=202=20+=0A=20= src/bin/scripts/common.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20318=20+-----------------=0A=20= src/bin/scripts/common.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=2049=20+--=0A=20src/bin/scripts/createdb.c=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A=20= src/bin/scripts/createuser.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=201=20+=0A=20src/bin/scripts/dropdb.c=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A=20= src/bin/scripts/dropuser.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=20=201=20+=0A=20src/bin/scripts/nls.mk=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=202=20+-=0A= =20src/bin/scripts/pg_isready.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=20=201=20+=0A=20src/bin/scripts/reindexdb.c=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/bin/scripts/vacuumdb.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=20=204=20+-=0A=20src/fe_utils/Makefile=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=204=20+=0A= =20src/fe_utils/connect_utils.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20170=20++++++++++=0A=20src/fe_utils/option_utils.c=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=2038=20+++=0A=20= .../parallel_slot.c}=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=2063=20+++-=0A=20src/fe_utils/query_utils.c=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=2092=20= +++++=0A=20src/fe_utils/string_utils.c=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=2017=20+-=0A=20= src/include/fe_utils/connect_utils.h=20=20=20=20=20=20=20=20=20=20|=20=20= 48=20+++=0A=20src/include/fe_utils/option_utils.h=20=20=20=20=20=20=20=20= =20=20=20|=20=2023=20++=0A=20.../fe_utils/parallel_slot.h}=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=2013=20+-=0A=20= src/include/fe_utils/query_utils.h=20=20=20=20=20=20=20=20=20=20=20=20|=20= =2026=20++=0A=20src/tools/msvc/Mkvcbuild.pm=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20=20=20=20= |=20=20=201=20+=0A=2024=20files=20changed,=20495=20insertions(+),=20394=20= deletions(-)=0A=20create=20mode=20100644=20src/fe_utils/connect_utils.c=0A= =20create=20mode=20100644=20src/fe_utils/option_utils.c=0A=20rename=20= src/{bin/scripts/scripts_parallel.c=20=3D>=20fe_utils/parallel_slot.c}=20= (80%)=0A=20create=20mode=20100644=20src/fe_utils/query_utils.c=0A=20= create=20mode=20100644=20src/include/fe_utils/connect_utils.h=0A=20= create=20mode=20100644=20src/include/fe_utils/option_utils.h=0A=20rename=20= src/{bin/scripts/scripts_parallel.h=20=3D>=20= include/fe_utils/parallel_slot.h}=20(82%)=0A=20create=20mode=20100644=20= src/include/fe_utils/query_utils.h=0A=0Adiff=20--git=20= a/src/bin/scripts/Makefile=20b/src/bin/scripts/Makefile=0Aindex=20= a02e4e430c..b8d7cf2f2d=20100644=0A---=20a/src/bin/scripts/Makefile=0A+++=20= b/src/bin/scripts/Makefile=0A@@=20-28,8=20+28,8=20@@=20createuser:=20= createuser.o=20common.o=20$(WIN32RES)=20|=20submake-libpq=20= submake-libpgport=0A=20dropdb:=20dropdb.o=20common.o=20$(WIN32RES)=20|=20= submake-libpq=20submake-libpgport=20submake-libpgfeutils=0A=20dropuser:=20= dropuser.o=20common.o=20$(WIN32RES)=20|=20submake-libpq=20= submake-libpgport=20submake-libpgfeutils=0A=20clusterdb:=20clusterdb.o=20= common.o=20$(WIN32RES)=20|=20submake-libpq=20submake-libpgport=20= submake-libpgfeutils=0A-vacuumdb:=20vacuumdb.o=20common.o=20= scripts_parallel.o=20$(WIN32RES)=20|=20submake-libpq=20submake-libpgport=20= submake-libpgfeutils=0A-reindexdb:=20reindexdb.o=20common.o=20= scripts_parallel.o=20$(WIN32RES)=20|=20submake-libpq=20submake-libpgport=20= submake-libpgfeutils=0A+vacuumdb:=20vacuumdb.o=20common.o=20$(WIN32RES)=20= |=20submake-libpq=20submake-libpgport=20submake-libpgfeutils=0A= +reindexdb:=20reindexdb.o=20common.o=20$(WIN32RES)=20|=20submake-libpq=20= submake-libpgport=20submake-libpgfeutils=0A=20pg_isready:=20pg_isready.o=20= common.o=20$(WIN32RES)=20|=20submake-libpq=20submake-libpgport=20= submake-libpgfeutils=0A=20=0A=20install:=20all=20installdirs=0A@@=20= -50,7=20+50,7=20@@=20uninstall:=0A=20=0A=20clean=20distclean=20= maintainer-clean:=0A=20=09rm=20-f=20$(addsuffix=20$(X),=20$(PROGRAMS))=20= $(addsuffix=20.o,=20$(PROGRAMS))=0A-=09rm=20-f=20common.o=20= scripts_parallel.o=20$(WIN32RES)=0A+=09rm=20-f=20common.o=20$(WIN32RES)=0A= =20=09rm=20-rf=20tmp_check=0A=20=0A=20check:=0Adiff=20--git=20= a/src/bin/scripts/clusterdb.c=20b/src/bin/scripts/clusterdb.c=0Aindex=20= 7d25bb31d4..fc771eed77=20100644=0A---=20a/src/bin/scripts/clusterdb.c=0A= +++=20b/src/bin/scripts/clusterdb.c=0A@@=20-13,6=20+13,8=20@@=0A=20= #include=20"common.h"=0A=20#include=20"common/logging.h"=0A=20#include=20= "fe_utils/cancel.h"=0A+#include=20"fe_utils/option_utils.h"=0A+#include=20= "fe_utils/query_utils.h"=0A=20#include=20"fe_utils/simple_list.h"=0A=20= #include=20"fe_utils/string_utils.h"=0A=20=0Adiff=20--git=20= a/src/bin/scripts/common.c=20b/src/bin/scripts/common.c=0Aindex=20= 21ef297e6e..c86c19eae2=20100644=0A---=20a/src/bin/scripts/common.c=0A+++=20= b/src/bin/scripts/common.c=0A@@=20-22,325=20+22,9=20@@=0A=20#include=20= "common/logging.h"=0A=20#include=20"common/string.h"=0A=20#include=20= "fe_utils/cancel.h"=0A+#include=20"fe_utils/query_utils.h"=0A=20#include=20= "fe_utils/string_utils.h"=0A=20=0A-#define=20ERRCODE_UNDEFINED_TABLE=20=20= "42P01"=0A-=0A-/*=0A-=20*=20Provide=20strictly=20harmonized=20handling=20= of=20--help=20and=20--version=0A-=20*=20options.=0A-=20*/=0A-void=0A= -handle_help_version_opts(int=20argc,=20char=20*argv[],=0A-=09=09=09=09=09= =09=20const=20char=20*fixed_progname,=20help_handler=20hlp)=0A-{=0A-=09= if=20(argc=20>=201)=0A-=09{=0A-=09=09if=20(strcmp(argv[1],=20"--help")=20= =3D=3D=200=20||=20strcmp(argv[1],=20"-?")=20=3D=3D=200)=0A-=09=09{=0A-=09= =09=09hlp(get_progname(argv[0]));=0A-=09=09=09exit(0);=0A-=09=09}=0A-=09=09= if=20(strcmp(argv[1],=20"--version")=20=3D=3D=200=20||=20strcmp(argv[1],=20= "-V")=20=3D=3D=200)=0A-=09=09{=0A-=09=09=09printf("%s=20(PostgreSQL)=20"=20= PG_VERSION=20"\n",=20fixed_progname);=0A-=09=09=09exit(0);=0A-=09=09}=0A= -=09}=0A-}=0A-=0A-=0A-/*=0A-=20*=20Make=20a=20database=20connection=20= with=20the=20given=20parameters.=0A-=20*=0A-=20*=20An=20interactive=20= password=20prompt=20is=20automatically=20issued=20if=20needed=20and=0A-=20= *=20allowed=20by=20cparams->prompt_password.=0A-=20*=0A-=20*=20If=20= allow_password_reuse=20is=20true,=20we=20will=20try=20to=20re-use=20any=20= password=0A-=20*=20given=20during=20previous=20calls=20to=20this=20= routine.=20=20(Callers=20should=20not=20pass=0A-=20*=20= allow_password_reuse=3Dtrue=20unless=20reconnecting=20to=20the=20same=20= database+user=0A-=20*=20as=20before,=20else=20we=20might=20create=20= password=20exposure=20hazards.)=0A-=20*/=0A-PGconn=20*=0A= -connectDatabase(const=20ConnParams=20*cparams,=20const=20char=20= *progname,=0A-=09=09=09=09bool=20echo,=20bool=20fail_ok,=20bool=20= allow_password_reuse)=0A-{=0A-=09PGconn=09=20=20=20*conn;=0A-=09bool=09=09= new_pass;=0A-=09static=20char=20*password=20=3D=20NULL;=0A-=0A-=09/*=20= Callers=20must=20supply=20at=20least=20dbname;=20other=20params=20can=20= be=20NULL=20*/=0A-=09Assert(cparams->dbname);=0A-=0A-=09if=20= (!allow_password_reuse=20&&=20password)=0A-=09{=0A-=09=09free(password);=0A= -=09=09password=20=3D=20NULL;=0A-=09}=0A-=0A-=09if=20= (cparams->prompt_password=20=3D=3D=20TRI_YES=20&&=20password=20=3D=3D=20= NULL)=0A-=09=09password=20=3D=20simple_prompt("Password:=20",=20false);=0A= -=0A-=09/*=0A-=09=20*=20Start=20the=20connection.=20=20Loop=20until=20we=20= have=20a=20password=20if=20requested=20by=0A-=09=20*=20backend.=0A-=09=20= */=0A-=09do=0A-=09{=0A-=09=09const=20char=20*keywords[8];=0A-=09=09const=20= char=20*values[8];=0A-=09=09int=09=09=09i=20=3D=200;=0A-=0A-=09=09/*=0A-=09= =09=20*=20If=20dbname=20is=20a=20connstring,=20its=20entries=20can=20= override=20the=20other=0A-=09=09=20*=20values=20obtained=20from=20= cparams;=20but=20in=20turn,=20override_dbname=20can=0A-=09=09=20*=20= override=20the=20dbname=20component=20of=20it.=0A-=09=09=20*/=0A-=09=09= keywords[i]=20=3D=20"host";=0A-=09=09values[i++]=20=3D=20= cparams->pghost;=0A-=09=09keywords[i]=20=3D=20"port";=0A-=09=09= values[i++]=20=3D=20cparams->pgport;=0A-=09=09keywords[i]=20=3D=20= "user";=0A-=09=09values[i++]=20=3D=20cparams->pguser;=0A-=09=09= keywords[i]=20=3D=20"password";=0A-=09=09values[i++]=20=3D=20password;=0A= -=09=09keywords[i]=20=3D=20"dbname";=0A-=09=09values[i++]=20=3D=20= cparams->dbname;=0A-=09=09if=20(cparams->override_dbname)=0A-=09=09{=0A-=09= =09=09keywords[i]=20=3D=20"dbname";=0A-=09=09=09values[i++]=20=3D=20= cparams->override_dbname;=0A-=09=09}=0A-=09=09keywords[i]=20=3D=20= "fallback_application_name";=0A-=09=09values[i++]=20=3D=20progname;=0A-=09= =09keywords[i]=20=3D=20NULL;=0A-=09=09values[i++]=20=3D=20NULL;=0A-=09=09= Assert(i=20<=3D=20lengthof(keywords));=0A-=0A-=09=09new_pass=20=3D=20= false;=0A-=09=09conn=20=3D=20PQconnectdbParams(keywords,=20values,=20= true);=0A-=0A-=09=09if=20(!conn)=0A-=09=09{=0A-=09=09=09= pg_log_error("could=20not=20connect=20to=20database=20%s:=20out=20of=20= memory",=0A-=09=09=09=09=09=09=20cparams->dbname);=0A-=09=09=09exit(1);=0A= -=09=09}=0A-=0A-=09=09/*=0A-=09=09=20*=20No=20luck?=20=20Trying=20asking=20= (again)=20for=20a=20password.=0A-=09=09=20*/=0A-=09=09if=20= (PQstatus(conn)=20=3D=3D=20CONNECTION_BAD=20&&=0A-=09=09=09= PQconnectionNeedsPassword(conn)=20&&=0A-=09=09=09= cparams->prompt_password=20!=3D=20TRI_NO)=0A-=09=09{=0A-=09=09=09= PQfinish(conn);=0A-=09=09=09if=20(password)=0A-=09=09=09=09= free(password);=0A-=09=09=09password=20=3D=20simple_prompt("Password:=20= ",=20false);=0A-=09=09=09new_pass=20=3D=20true;=0A-=09=09}=0A-=09}=20= while=20(new_pass);=0A-=0A-=09/*=20check=20to=20see=20that=20the=20= backend=20connection=20was=20successfully=20made=20*/=0A-=09if=20= (PQstatus(conn)=20=3D=3D=20CONNECTION_BAD)=0A-=09{=0A-=09=09if=20= (fail_ok)=0A-=09=09{=0A-=09=09=09PQfinish(conn);=0A-=09=09=09return=20= NULL;=0A-=09=09}=0A-=09=09pg_log_error("%s",=20PQerrorMessage(conn));=0A= -=09=09exit(1);=0A-=09}=0A-=0A-=09/*=20Start=20strict;=20callers=20may=20= override=20this.=20*/=0A-=09PQclear(executeQuery(conn,=20= ALWAYS_SECURE_SEARCH_PATH_SQL,=20echo));=0A-=0A-=09return=20conn;=0A-}=0A= -=0A-/*=0A-=20*=20Try=20to=20connect=20to=20the=20appropriate=20= maintenance=20database.=0A-=20*=0A-=20*=20This=20differs=20from=20= connectDatabase=20only=20in=20that=20it=20has=20a=20rule=20for=0A-=20*=20= inserting=20a=20default=20"dbname"=20if=20none=20was=20given=20(which=20= is=20why=20cparams=0A-=20*=20is=20not=20const).=20=20Note=20that=20= cparams->dbname=20should=20typically=20come=20from=0A-=20*=20a=20= --maintenance-db=20command=20line=20parameter.=0A-=20*/=0A-PGconn=20*=0A= -connectMaintenanceDatabase(ConnParams=20*cparams,=0A-=09=09=09=09=09=09=20= =20=20const=20char=20*progname,=20bool=20echo)=0A-{=0A-=09PGconn=09=20=20= =20*conn;=0A-=0A-=09/*=20If=20a=20maintenance=20database=20name=20was=20= specified,=20just=20connect=20to=20it.=20*/=0A-=09if=20(cparams->dbname)=0A= -=09=09return=20connectDatabase(cparams,=20progname,=20echo,=20false,=20= false);=0A-=0A-=09/*=20Otherwise,=20try=20postgres=20first=20and=20then=20= template1.=20*/=0A-=09cparams->dbname=20=3D=20"postgres";=0A-=09conn=20=3D= =20connectDatabase(cparams,=20progname,=20echo,=20true,=20false);=0A-=09= if=20(!conn)=0A-=09{=0A-=09=09cparams->dbname=20=3D=20"template1";=0A-=09= =09conn=20=3D=20connectDatabase(cparams,=20progname,=20echo,=20false,=20= false);=0A-=09}=0A-=09return=20conn;=0A-}=0A-=0A-/*=0A-=20*=20Disconnect=20= the=20given=20connection,=20canceling=20any=20statement=20if=20one=20is=20= active.=0A-=20*/=0A-void=0A-disconnectDatabase(PGconn=20*conn)=0A-{=0A-=09= char=09=09errbuf[256];=0A-=0A-=09Assert(conn=20!=3D=20NULL);=0A-=0A-=09= if=20(PQtransactionStatus(conn)=20=3D=3D=20PQTRANS_ACTIVE)=0A-=09{=0A-=09= =09PGcancel=20=20=20*cancel;=0A-=0A-=09=09if=20((cancel=20=3D=20= PQgetCancel(conn)))=0A-=09=09{=0A-=09=09=09(void)=20PQcancel(cancel,=20= errbuf,=20sizeof(errbuf));=0A-=09=09=09PQfreeCancel(cancel);=0A-=09=09}=0A= -=09}=0A-=0A-=09PQfinish(conn);=0A-}=0A-=0A-/*=0A-=20*=20Run=20a=20= query,=20return=20the=20results,=20exit=20program=20on=20failure.=0A-=20= */=0A-PGresult=20*=0A-executeQuery(PGconn=20*conn,=20const=20char=20= *query,=20bool=20echo)=0A-{=0A-=09PGresult=20=20=20*res;=0A-=0A-=09if=20= (echo)=0A-=09=09printf("%s\n",=20query);=0A-=0A-=09res=20=3D=20= PQexec(conn,=20query);=0A-=09if=20(!res=20||=0A-=09=09= PQresultStatus(res)=20!=3D=20PGRES_TUPLES_OK)=0A-=09{=0A-=09=09= pg_log_error("query=20failed:=20%s",=20PQerrorMessage(conn));=0A-=09=09= pg_log_info("query=20was:=20%s",=20query);=0A-=09=09PQfinish(conn);=0A-=09= =09exit(1);=0A-=09}=0A-=0A-=09return=20res;=0A-}=0A-=0A-=0A-/*=0A-=20*=20= As=20above=20for=20a=20SQL=20command=20(which=20returns=20nothing).=0A-=20= */=0A-void=0A-executeCommand(PGconn=20*conn,=20const=20char=20*query,=20= bool=20echo)=0A-{=0A-=09PGresult=20=20=20*res;=0A-=0A-=09if=20(echo)=0A-=09= =09printf("%s\n",=20query);=0A-=0A-=09res=20=3D=20PQexec(conn,=20query);=0A= -=09if=20(!res=20||=0A-=09=09PQresultStatus(res)=20!=3D=20= PGRES_COMMAND_OK)=0A-=09{=0A-=09=09pg_log_error("query=20failed:=20%s",=20= PQerrorMessage(conn));=0A-=09=09pg_log_info("query=20was:=20%s",=20= query);=0A-=09=09PQfinish(conn);=0A-=09=09exit(1);=0A-=09}=0A-=0A-=09= PQclear(res);=0A-}=0A-=0A-=0A-/*=0A-=20*=20As=20above=20for=20a=20SQL=20= maintenance=20command=20(returns=20command=20success).=0A-=20*=20Command=20= is=20executed=20with=20a=20cancel=20handler=20set,=20so=20Ctrl-C=20can=0A= -=20*=20interrupt=20it.=0A-=20*/=0A-bool=0A= -executeMaintenanceCommand(PGconn=20*conn,=20const=20char=20*query,=20= bool=20echo)=0A-{=0A-=09PGresult=20=20=20*res;=0A-=09bool=09=09r;=0A-=0A= -=09if=20(echo)=0A-=09=09printf("%s\n",=20query);=0A-=0A-=09= SetCancelConn(conn);=0A-=09res=20=3D=20PQexec(conn,=20query);=0A-=09= ResetCancelConn();=0A-=0A-=09r=20=3D=20(res=20&&=20PQresultStatus(res)=20= =3D=3D=20PGRES_COMMAND_OK);=0A-=0A-=09if=20(res)=0A-=09=09PQclear(res);=0A= -=0A-=09return=20r;=0A-}=0A-=0A-/*=0A-=20*=20Consume=20all=20the=20= results=20generated=20for=20the=20given=20connection=20until=0A-=20*=20= nothing=20remains.=20=20If=20at=20least=20one=20error=20is=20= encountered,=20return=20false.=0A-=20*=20Note=20that=20this=20will=20= block=20if=20the=20connection=20is=20busy.=0A-=20*/=0A-bool=0A= -consumeQueryResult(PGconn=20*conn)=0A-{=0A-=09bool=09=09ok=20=3D=20= true;=0A-=09PGresult=20=20=20*result;=0A-=0A-=09SetCancelConn(conn);=0A-=09= while=20((result=20=3D=20PQgetResult(conn))=20!=3D=20NULL)=0A-=09{=0A-=09= =09if=20(!processQueryResult(conn,=20result))=0A-=09=09=09ok=20=3D=20= false;=0A-=09}=0A-=09ResetCancelConn();=0A-=09return=20ok;=0A-}=0A-=0A= -/*=0A-=20*=20Process=20(and=20delete)=20a=20query=20result.=20=20= Returns=20true=20if=20there's=20no=20error,=0A-=20*=20false=20otherwise=20= --=20but=20errors=20about=20trying=20to=20work=20on=20a=20missing=20= relation=0A-=20*=20are=20reported=20and=20subsequently=20ignored.=0A-=20= */=0A-bool=0A-processQueryResult(PGconn=20*conn,=20PGresult=20*result)=0A= -{=0A-=09/*=0A-=09=20*=20If=20it's=20an=20error,=20report=20it.=20=20= Errors=20about=20a=20missing=20table=20are=20harmless=0A-=09=20*=20so=20= we=20continue=20processing;=20but=20die=20for=20other=20errors.=0A-=09=20= */=0A-=09if=20(PQresultStatus(result)=20!=3D=20PGRES_COMMAND_OK)=0A-=09{=0A= -=09=09char=09=20=20=20*sqlState=20=3D=20PQresultErrorField(result,=20= PG_DIAG_SQLSTATE);=0A-=0A-=09=09pg_log_error("processing=20of=20database=20= \"%s\"=20failed:=20%s",=0A-=09=09=09=09=09=20PQdb(conn),=20= PQerrorMessage(conn));=0A-=0A-=09=09if=20(sqlState=20&&=20= strcmp(sqlState,=20ERRCODE_UNDEFINED_TABLE)=20!=3D=200)=0A-=09=09{=0A-=09= =09=09PQclear(result);=0A-=09=09=09return=20false;=0A-=09=09}=0A-=09}=0A= -=0A-=09PQclear(result);=0A-=09return=20true;=0A-}=0A-=0A-=0A=20/*=0A=20=20= *=20Split=20TABLE[(COLUMNS)]=20into=20TABLE=20and=20[(COLUMNS)]=20= portions.=20=20When=20you=0A=20=20*=20finish=20using=20them,=20= pg_free(*table).=20=20*columns=20is=20a=20pointer=20into=20"spec",=0A= diff=20--git=20a/src/bin/scripts/common.h=20b/src/bin/scripts/common.h=0A= index=205630975712..ddd8f35274=20100644=0A---=20= a/src/bin/scripts/common.h=0A+++=20b/src/bin/scripts/common.h=0A@@=20= -10,58=20+10,11=20@@=0A=20#define=20COMMON_H=0A=20=0A=20#include=20= "common/username.h"=0A+#include=20"fe_utils/connect_utils.h"=0A=20= #include=20"getopt_long.h"=09=09/*=20pgrminclude=20ignore=20*/=0A=20= #include=20"libpq-fe.h"=0A=20#include=20"pqexpbuffer.h"=09=09/*=20= pgrminclude=20ignore=20*/=0A=20=0A-enum=20trivalue=0A-{=0A-=09= TRI_DEFAULT,=0A-=09TRI_NO,=0A-=09TRI_YES=0A-};=0A-=0A-/*=20Parameters=20= needed=20by=20connectDatabase/connectMaintenanceDatabase=20*/=0A-typedef=20= struct=20_connParams=0A-{=0A-=09/*=20These=20fields=20record=20the=20= actual=20command=20line=20parameters=20*/=0A-=09const=20char=20*dbname;=09= =09=09/*=20this=20may=20be=20a=20connstring!=20*/=0A-=09const=20char=20= *pghost;=0A-=09const=20char=20*pgport;=0A-=09const=20char=20*pguser;=0A-=09= enum=20trivalue=20prompt_password;=0A-=09/*=20If=20not=20NULL,=20this=20= overrides=20the=20dbname=20obtained=20from=20command=20line=20*/=0A-=09= /*=20(but=20*only*=20the=20DB=20name,=20not=20anything=20else=20in=20the=20= connstring)=20*/=0A-=09const=20char=20*override_dbname;=0A-}=20= ConnParams;=0A-=0A-typedef=20void=20(*help_handler)=20(const=20char=20= *progname);=0A-=0A-extern=20void=20handle_help_version_opts(int=20argc,=20= char=20*argv[],=0A-=09=09=09=09=09=09=09=09=09=20const=20char=20= *fixed_progname,=0A-=09=09=09=09=09=09=09=09=09=20help_handler=20hlp);=0A= -=0A-extern=20PGconn=20*connectDatabase(const=20ConnParams=20*cparams,=0A= -=09=09=09=09=09=09=09=20=20=20const=20char=20*progname,=0A-=09=09=09=09=09= =09=09=20=20=20bool=20echo,=20bool=20fail_ok,=0A-=09=09=09=09=09=09=09=20= =20=20bool=20allow_password_reuse);=0A-=0A-extern=20PGconn=20= *connectMaintenanceDatabase(ConnParams=20*cparams,=0A-=09=09=09=09=09=09=09= =09=09=09=20=20const=20char=20*progname,=20bool=20echo);=0A-=0A-extern=20= void=20disconnectDatabase(PGconn=20*conn);=0A-=0A-extern=20PGresult=20= *executeQuery(PGconn=20*conn,=20const=20char=20*query,=20bool=20echo);=0A= -=0A-extern=20void=20executeCommand(PGconn=20*conn,=20const=20char=20= *query,=20bool=20echo);=0A-=0A-extern=20bool=20= executeMaintenanceCommand(PGconn=20*conn,=20const=20char=20*query,=0A-=09= =09=09=09=09=09=09=09=09=20=20bool=20echo);=0A-=0A-extern=20bool=20= consumeQueryResult(PGconn=20*conn);=0A-=0A-extern=20bool=20= processQueryResult(PGconn=20*conn,=20PGresult=20*result);=0A-=0A=20= extern=20void=20splitTableColumnsSpec(const=20char=20*spec,=20int=20= encoding,=0A=20=09=09=09=09=09=09=09=09=20=20char=20**table,=20const=20= char=20**columns);=0A=20=0Adiff=20--git=20a/src/bin/scripts/createdb.c=20= b/src/bin/scripts/createdb.c=0Aindex=20abf21d4942..041454f075=20100644=0A= ---=20a/src/bin/scripts/createdb.c=0A+++=20b/src/bin/scripts/createdb.c=0A= @@=20-13,6=20+13,7=20@@=0A=20=0A=20#include=20"common.h"=0A=20#include=20= "common/logging.h"=0A+#include=20"fe_utils/option_utils.h"=0A=20#include=20= "fe_utils/string_utils.h"=0A=20=0A=20=0Adiff=20--git=20= a/src/bin/scripts/createuser.c=20b/src/bin/scripts/createuser.c=0Aindex=20= 47b0e28bc6..ef7e0e549f=20100644=0A---=20a/src/bin/scripts/createuser.c=0A= +++=20b/src/bin/scripts/createuser.c=0A@@=20-14,6=20+14,7=20@@=0A=20= #include=20"common.h"=0A=20#include=20"common/logging.h"=0A=20#include=20= "common/string.h"=0A+#include=20"fe_utils/option_utils.h"=0A=20#include=20= "fe_utils/simple_list.h"=0A=20#include=20"fe_utils/string_utils.h"=0A=20=0A= diff=20--git=20a/src/bin/scripts/dropdb.c=20b/src/bin/scripts/dropdb.c=0A= index=20ba0dcdecb9..b154ed1bb6=20100644=0A---=20= a/src/bin/scripts/dropdb.c=0A+++=20b/src/bin/scripts/dropdb.c=0A@@=20= -13,6=20+13,7=20@@=0A=20#include=20"postgres_fe.h"=0A=20#include=20= "common.h"=0A=20#include=20"common/logging.h"=0A+#include=20= "fe_utils/option_utils.h"=0A=20#include=20"fe_utils/string_utils.h"=0A=20= =0A=20=0Adiff=20--git=20a/src/bin/scripts/dropuser.c=20= b/src/bin/scripts/dropuser.c=0Aindex=20ff5b455ae5..61b8557bc7=20100644=0A= ---=20a/src/bin/scripts/dropuser.c=0A+++=20b/src/bin/scripts/dropuser.c=0A= @@=20-14,6=20+14,7=20@@=0A=20#include=20"common.h"=0A=20#include=20= "common/logging.h"=0A=20#include=20"common/string.h"=0A+#include=20= "fe_utils/option_utils.h"=0A=20#include=20"fe_utils/string_utils.h"=0A=20= =0A=20=0Adiff=20--git=20a/src/bin/scripts/nls.mk=20= b/src/bin/scripts/nls.mk=0Aindex=205d5dd11b7b..7fc716092e=20100644=0A---=20= a/src/bin/scripts/nls.mk=0A+++=20b/src/bin/scripts/nls.mk=0A@@=20-7,7=20= +7,7=20@@=20GETTEXT_FILES=20=20=20=20=3D=20= $(FRONTEND_COMMON_GETTEXT_FILES)=20\=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20clusterdb.c=20vacuumdb.c=20reindexdb.c=20\=0A=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20pg_isready.c=20\=0A= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20common.c=20\=0A= -=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= scripts_parallel.c=20\=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20../../fe_utils/parallel_slot.c=20\=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20../../fe_utils/cancel.c=20= ../../fe_utils/print.c=20\=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20../../common/fe_memutils.c=20../../common/username.c=0A=20= GETTEXT_TRIGGERS=20=3D=20$(FRONTEND_COMMON_GETTEXT_TRIGGERS)=20= simple_prompt=20yesno_prompt=0Adiff=20--git=20= a/src/bin/scripts/pg_isready.c=20b/src/bin/scripts/pg_isready.c=0Aindex=20= ceb8a09b4c..fc6f7b0a93=20100644=0A---=20a/src/bin/scripts/pg_isready.c=0A= +++=20b/src/bin/scripts/pg_isready.c=0A@@=20-12,6=20+12,7=20@@=0A=20= #include=20"postgres_fe.h"=0A=20#include=20"common.h"=0A=20#include=20= "common/logging.h"=0A+#include=20"fe_utils/option_utils.h"=0A=20=0A=20= #define=20DEFAULT_CONNECT_TIMEOUT=20"3"=0A=20=0Adiff=20--git=20= a/src/bin/scripts/reindexdb.c=20b/src/bin/scripts/reindexdb.c=0Aindex=20= dece8200fa..7781fb1151=20100644=0A---=20a/src/bin/scripts/reindexdb.c=0A= +++=20b/src/bin/scripts/reindexdb.c=0A@@=20-16,9=20+16,11=20@@=0A=20= #include=20"common/connect.h"=0A=20#include=20"common/logging.h"=0A=20= #include=20"fe_utils/cancel.h"=0A+#include=20"fe_utils/option_utils.h"=0A= +#include=20"fe_utils/parallel_slot.h"=0A+#include=20= "fe_utils/query_utils.h"=0A=20#include=20"fe_utils/simple_list.h"=0A=20= #include=20"fe_utils/string_utils.h"=0A-#include=20"scripts_parallel.h"=0A= =20=0A=20typedef=20enum=20ReindexType=0A=20{=0Adiff=20--git=20= a/src/bin/scripts/vacuumdb.c=20b/src/bin/scripts/vacuumdb.c=0Aindex=20= 8246327770..ed320817bc=20100644=0A---=20a/src/bin/scripts/vacuumdb.c=0A= +++=20b/src/bin/scripts/vacuumdb.c=0A@@=20-18,9=20+18,11=20@@=0A=20= #include=20"common/connect.h"=0A=20#include=20"common/logging.h"=0A=20= #include=20"fe_utils/cancel.h"=0A+#include=20"fe_utils/option_utils.h"=0A= +#include=20"fe_utils/parallel_slot.h"=0A+#include=20= "fe_utils/query_utils.h"=0A=20#include=20"fe_utils/simple_list.h"=0A=20= #include=20"fe_utils/string_utils.h"=0A-#include=20"scripts_parallel.h"=0A= =20=0A=20=0A=20/*=20vacuum=20options=20controlled=20by=20user=20flags=20= */=0Adiff=20--git=20a/src/fe_utils/Makefile=20b/src/fe_utils/Makefile=0A= index=2010d6838cf9..456c441a33=20100644=0A---=20a/src/fe_utils/Makefile=0A= +++=20b/src/fe_utils/Makefile=0A@@=20-23,9=20+23,13=20@@=20OBJS=20=3D=20= \=0A=20=09archive.o=20\=0A=20=09cancel.o=20\=0A=20=09conditional.o=20\=0A= +=09connect_utils.o=20\=0A=20=09mbprint.o=20\=0A+=09option_utils.o=20\=0A= +=09parallel_slot.o=20\=0A=20=09print.o=20\=0A=20=09psqlscan.o=20\=0A+=09= query_utils.o=20\=0A=20=09recovery_gen.o=20\=0A=20=09simple_list.o=20\=0A= =20=09string_utils.o=0Adiff=20--git=20a/src/fe_utils/connect_utils.c=20= b/src/fe_utils/connect_utils.c=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..7475e2f366=0A---=20/dev/null=0A+++=20= b/src/fe_utils/connect_utils.c=0A@@=20-0,0=20+1,170=20@@=0A+#include=20= "postgres_fe.h"=0A+=0A+#include=20"common/connect.h"=0A+#include=20= "common/logging.h"=0A+#include=20"common/string.h"=0A+#include=20= "fe_utils/connect_utils.h"=0A+#include=20"fe_utils/query_utils.h"=0A+=0A= +/*=0A+=20*=20Make=20a=20database=20connection=20with=20the=20given=20= parameters.=0A+=20*=0A+=20*=20An=20interactive=20password=20prompt=20is=20= automatically=20issued=20if=20needed=20and=0A+=20*=20allowed=20by=20= cparams->prompt_password.=0A+=20*=0A+=20*=20If=20allow_password_reuse=20= is=20true,=20we=20will=20try=20to=20re-use=20any=20password=0A+=20*=20= given=20during=20previous=20calls=20to=20this=20routine.=20=20(Callers=20= should=20not=20pass=0A+=20*=20allow_password_reuse=3Dtrue=20unless=20= reconnecting=20to=20the=20same=20database+user=0A+=20*=20as=20before,=20= else=20we=20might=20create=20password=20exposure=20hazards.)=0A+=20*/=0A= +PGconn=20*=0A+connectDatabase(const=20ConnParams=20*cparams,=20const=20= char=20*progname,=0A+=09=09=09=09bool=20echo,=20bool=20fail_ok,=20bool=20= allow_password_reuse)=0A+{=0A+=09PGconn=09=20=20=20*conn;=0A+=09bool=09=09= new_pass;=0A+=09static=20char=20*password=20=3D=20NULL;=0A+=0A+=09/*=20= Callers=20must=20supply=20at=20least=20dbname;=20other=20params=20can=20= be=20NULL=20*/=0A+=09Assert(cparams->dbname);=0A+=0A+=09if=20= (!allow_password_reuse=20&&=20password)=0A+=09{=0A+=09=09free(password);=0A= +=09=09password=20=3D=20NULL;=0A+=09}=0A+=0A+=09if=20= (cparams->prompt_password=20=3D=3D=20TRI_YES=20&&=20password=20=3D=3D=20= NULL)=0A+=09=09password=20=3D=20simple_prompt("Password:=20",=20false);=0A= +=0A+=09/*=0A+=09=20*=20Start=20the=20connection.=20=20Loop=20until=20we=20= have=20a=20password=20if=20requested=20by=0A+=09=20*=20backend.=0A+=09=20= */=0A+=09do=0A+=09{=0A+=09=09const=20char=20*keywords[8];=0A+=09=09const=20= char=20*values[8];=0A+=09=09int=09=09=09i=20=3D=200;=0A+=0A+=09=09/*=0A+=09= =09=20*=20If=20dbname=20is=20a=20connstring,=20its=20entries=20can=20= override=20the=20other=0A+=09=09=20*=20values=20obtained=20from=20= cparams;=20but=20in=20turn,=20override_dbname=20can=0A+=09=09=20*=20= override=20the=20dbname=20component=20of=20it.=0A+=09=09=20*/=0A+=09=09= keywords[i]=20=3D=20"host";=0A+=09=09values[i++]=20=3D=20= cparams->pghost;=0A+=09=09keywords[i]=20=3D=20"port";=0A+=09=09= values[i++]=20=3D=20cparams->pgport;=0A+=09=09keywords[i]=20=3D=20= "user";=0A+=09=09values[i++]=20=3D=20cparams->pguser;=0A+=09=09= keywords[i]=20=3D=20"password";=0A+=09=09values[i++]=20=3D=20password;=0A= +=09=09keywords[i]=20=3D=20"dbname";=0A+=09=09values[i++]=20=3D=20= cparams->dbname;=0A+=09=09if=20(cparams->override_dbname)=0A+=09=09{=0A+=09= =09=09keywords[i]=20=3D=20"dbname";=0A+=09=09=09values[i++]=20=3D=20= cparams->override_dbname;=0A+=09=09}=0A+=09=09keywords[i]=20=3D=20= "fallback_application_name";=0A+=09=09values[i++]=20=3D=20progname;=0A+=09= =09keywords[i]=20=3D=20NULL;=0A+=09=09values[i++]=20=3D=20NULL;=0A+=09=09= Assert(i=20<=3D=20lengthof(keywords));=0A+=0A+=09=09new_pass=20=3D=20= false;=0A+=09=09conn=20=3D=20PQconnectdbParams(keywords,=20values,=20= true);=0A+=0A+=09=09if=20(!conn)=0A+=09=09{=0A+=09=09=09= pg_log_error("could=20not=20connect=20to=20database=20%s:=20out=20of=20= memory",=0A+=09=09=09=09=09=09=20cparams->dbname);=0A+=09=09=09exit(1);=0A= +=09=09}=0A+=0A+=09=09/*=0A+=09=09=20*=20No=20luck?=20=20Trying=20asking=20= (again)=20for=20a=20password.=0A+=09=09=20*/=0A+=09=09if=20= (PQstatus(conn)=20=3D=3D=20CONNECTION_BAD=20&&=0A+=09=09=09= PQconnectionNeedsPassword(conn)=20&&=0A+=09=09=09= cparams->prompt_password=20!=3D=20TRI_NO)=0A+=09=09{=0A+=09=09=09= PQfinish(conn);=0A+=09=09=09if=20(password)=0A+=09=09=09=09= free(password);=0A+=09=09=09password=20=3D=20simple_prompt("Password:=20= ",=20false);=0A+=09=09=09new_pass=20=3D=20true;=0A+=09=09}=0A+=09}=20= while=20(new_pass);=0A+=0A+=09/*=20check=20to=20see=20that=20the=20= backend=20connection=20was=20successfully=20made=20*/=0A+=09if=20= (PQstatus(conn)=20=3D=3D=20CONNECTION_BAD)=0A+=09{=0A+=09=09if=20= (fail_ok)=0A+=09=09{=0A+=09=09=09PQfinish(conn);=0A+=09=09=09return=20= NULL;=0A+=09=09}=0A+=09=09pg_log_error("%s",=20PQerrorMessage(conn));=0A= +=09=09exit(1);=0A+=09}=0A+=0A+=09/*=20Start=20strict;=20callers=20may=20= override=20this.=20*/=0A+=09PQclear(executeQuery(conn,=20= ALWAYS_SECURE_SEARCH_PATH_SQL,=20echo));=0A+=0A+=09return=20conn;=0A+}=0A= +=0A+/*=0A+=20*=20Try=20to=20connect=20to=20the=20appropriate=20= maintenance=20database.=0A+=20*=0A+=20*=20This=20differs=20from=20= connectDatabase=20only=20in=20that=20it=20has=20a=20rule=20for=0A+=20*=20= inserting=20a=20default=20"dbname"=20if=20none=20was=20given=20(which=20= is=20why=20cparams=0A+=20*=20is=20not=20const).=20=20Note=20that=20= cparams->dbname=20should=20typically=20come=20from=0A+=20*=20a=20= --maintenance-db=20command=20line=20parameter.=0A+=20*/=0A+PGconn=20*=0A= +connectMaintenanceDatabase(ConnParams=20*cparams,=0A+=09=09=09=09=09=09=20= =20=20const=20char=20*progname,=20bool=20echo)=0A+{=0A+=09PGconn=09=20=20= =20*conn;=0A+=0A+=09/*=20If=20a=20maintenance=20database=20name=20was=20= specified,=20just=20connect=20to=20it.=20*/=0A+=09if=20(cparams->dbname)=0A= +=09=09return=20connectDatabase(cparams,=20progname,=20echo,=20false,=20= false);=0A+=0A+=09/*=20Otherwise,=20try=20postgres=20first=20and=20then=20= template1.=20*/=0A+=09cparams->dbname=20=3D=20"postgres";=0A+=09conn=20=3D= =20connectDatabase(cparams,=20progname,=20echo,=20true,=20false);=0A+=09= if=20(!conn)=0A+=09{=0A+=09=09cparams->dbname=20=3D=20"template1";=0A+=09= =09conn=20=3D=20connectDatabase(cparams,=20progname,=20echo,=20false,=20= false);=0A+=09}=0A+=09return=20conn;=0A+}=0A+=0A+/*=0A+=20*=20Disconnect=20= the=20given=20connection,=20canceling=20any=20statement=20if=20one=20is=20= active.=0A+=20*/=0A+void=0A+disconnectDatabase(PGconn=20*conn)=0A+{=0A+=09= char=09=09errbuf[256];=0A+=0A+=09Assert(conn=20!=3D=20NULL);=0A+=0A+=09= if=20(PQtransactionStatus(conn)=20=3D=3D=20PQTRANS_ACTIVE)=0A+=09{=0A+=09= =09PGcancel=20=20=20*cancel;=0A+=0A+=09=09if=20((cancel=20=3D=20= PQgetCancel(conn)))=0A+=09=09{=0A+=09=09=09(void)=20PQcancel(cancel,=20= errbuf,=20sizeof(errbuf));=0A+=09=09=09PQfreeCancel(cancel);=0A+=09=09}=0A= +=09}=0A+=0A+=09PQfinish(conn);=0A+}=0Adiff=20--git=20= a/src/fe_utils/option_utils.c=20b/src/fe_utils/option_utils.c=0Anew=20= file=20mode=20100644=0Aindex=200000000000..97aca1f02b=0A---=20/dev/null=0A= +++=20b/src/fe_utils/option_utils.c=0A@@=20-0,0=20+1,38=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20Command=20line=20option=20processing=20facilities=20= for=20frontend=20code=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2020,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20src/fe_utils/option_utils.c=0A+=20*=0A= +=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+=0A+#include=20"postgres_fe.h"=0A+=0A+#include=20= "fe_utils/option_utils.h"=0A+=0A+/*=0A+=20*=20Provide=20strictly=20= harmonized=20handling=20of=20--help=20and=20--version=0A+=20*=20options.=0A= +=20*/=0A+void=0A+handle_help_version_opts(int=20argc,=20char=20*argv[],=0A= +=09=09=09=09=09=09=20const=20char=20*fixed_progname,=20help_handler=20= hlp)=0A+{=0A+=09if=20(argc=20>=201)=0A+=09{=0A+=09=09if=20= (strcmp(argv[1],=20"--help")=20=3D=3D=200=20||=20strcmp(argv[1],=20"-?")=20= =3D=3D=200)=0A+=09=09{=0A+=09=09=09hlp(get_progname(argv[0]));=0A+=09=09=09= exit(0);=0A+=09=09}=0A+=09=09if=20(strcmp(argv[1],=20"--version")=20=3D=3D= =200=20||=20strcmp(argv[1],=20"-V")=20=3D=3D=200)=0A+=09=09{=0A+=09=09=09= printf("%s=20(PostgreSQL)=20"=20PG_VERSION=20"\n",=20fixed_progname);=0A= +=09=09=09exit(0);=0A+=09=09}=0A+=09}=0A+}=0Adiff=20--git=20= a/src/bin/scripts/scripts_parallel.c=20b/src/fe_utils/parallel_slot.c=0A= similarity=20index=2080%=0Arename=20from=20= src/bin/scripts/scripts_parallel.c=0Arename=20to=20= src/fe_utils/parallel_slot.c=0Aindex=201f863a1bb4..3987a4702b=20100644=0A= ---=20a/src/bin/scripts/scripts_parallel.c=0A+++=20= b/src/fe_utils/parallel_slot.c=0A@@=20-1,13=20+1,13=20@@=0A=20= /*------------------------------------------------------------------------= -=0A=20=20*=0A-=20*=09scripts_parallel.c=0A-=20*=09=09Parallel=20support=20= for=20bin/scripts/=0A+=20*=09parallel_slot.c=0A+=20*=09=09Parallel=20= support=20for=20front-end=20parallel=20database=20connections=0A=20=20*=0A= =20=20*=0A=20=20*=20Portions=20Copyright=20(c)=201996-2021,=20PostgreSQL=20= Global=20Development=20Group=0A=20=20*=20Portions=20Copyright=20(c)=20= 1994,=20Regents=20of=20the=20University=20of=20California=0A=20=20*=0A-=20= *=20src/bin/scripts/scripts_parallel.c=0A+=20*=20= src/fe_utils/parallel_slot.c=0A=20=20*=0A=20=20= *-------------------------------------------------------------------------= =0A=20=20*/=0A@@=20-22,13=20+22,15=20@@=0A=20#include=20=0A= =20#endif=0A=20=0A-#include=20"common.h"=0A=20#include=20= "common/logging.h"=0A=20#include=20"fe_utils/cancel.h"=0A-#include=20= "scripts_parallel.h"=0A+#include=20"fe_utils/parallel_slot.h"=0A+=0A= +#define=20ERRCODE_UNDEFINED_TABLE=20=20"42P01"=0A=20=0A=20static=20void=20= init_slot(ParallelSlot=20*slot,=20PGconn=20*conn);=0A=20static=20int=09= select_loop(int=20maxFd,=20fd_set=20*workerset);=0A+static=20bool=20= processQueryResult(PGconn=20*conn,=20PGresult=20*result);=0A=20=0A=20= static=20void=0A=20init_slot(ParallelSlot=20*slot,=20PGconn=20*conn)=0A= @@=20-38,6=20+40,57=20@@=20init_slot(ParallelSlot=20*slot,=20PGconn=20= *conn)=0A=20=09slot->isFree=20=3D=20true;=0A=20}=0A=20=0A+/*=0A+=20*=20= Process=20(and=20delete)=20a=20query=20result.=20=20Returns=20true=20if=20= there's=20no=20error,=0A+=20*=20false=20otherwise=20--=20but=20errors=20= about=20trying=20to=20work=20on=20a=20missing=20relation=0A+=20*=20are=20= reported=20and=20subsequently=20ignored.=0A+=20*/=0A+static=20bool=0A= +processQueryResult(PGconn=20*conn,=20PGresult=20*result)=0A+{=0A+=09/*=0A= +=09=20*=20If=20it's=20an=20error,=20report=20it.=20=20Errors=20about=20= a=20missing=20table=20are=20harmless=0A+=09=20*=20so=20we=20continue=20= processing;=20but=20die=20for=20other=20errors.=0A+=09=20*/=0A+=09if=20= (PQresultStatus(result)=20!=3D=20PGRES_COMMAND_OK)=0A+=09{=0A+=09=09char=09= =20=20=20*sqlState=20=3D=20PQresultErrorField(result,=20= PG_DIAG_SQLSTATE);=0A+=0A+=09=09pg_log_error("processing=20of=20database=20= \"%s\"=20failed:=20%s",=0A+=09=09=09=09=09=20PQdb(conn),=20= PQerrorMessage(conn));=0A+=0A+=09=09if=20(sqlState=20&&=20= strcmp(sqlState,=20ERRCODE_UNDEFINED_TABLE)=20!=3D=200)=0A+=09=09{=0A+=09= =09=09PQclear(result);=0A+=09=09=09return=20false;=0A+=09=09}=0A+=09}=0A= +=0A+=09PQclear(result);=0A+=09return=20true;=0A+}=0A+=0A+/*=0A+=20*=20= Consume=20all=20the=20results=20generated=20for=20the=20given=20= connection=20until=0A+=20*=20nothing=20remains.=20=20If=20at=20least=20= one=20error=20is=20encountered,=20return=20false.=0A+=20*=20Note=20that=20= this=20will=20block=20if=20the=20connection=20is=20busy.=0A+=20*/=0A= +static=20bool=0A+consumeQueryResult(PGconn=20*conn)=0A+{=0A+=09bool=09=09= ok=20=3D=20true;=0A+=09PGresult=20=20=20*result;=0A+=0A+=09= SetCancelConn(conn);=0A+=09while=20((result=20=3D=20PQgetResult(conn))=20= !=3D=20NULL)=0A+=09{=0A+=09=09if=20(!processQueryResult(conn,=20result))=0A= +=09=09=09ok=20=3D=20false;=0A+=09}=0A+=09ResetCancelConn();=0A+=09= return=20ok;=0A+}=0A+=0A=20/*=0A=20=20*=20Wait=20until=20a=20file=20= descriptor=20from=20the=20given=20set=20becomes=20readable.=0A=20=20*=0A= diff=20--git=20a/src/fe_utils/query_utils.c=20= b/src/fe_utils/query_utils.c=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..a70ae3c082=0A---=20/dev/null=0A+++=20= b/src/fe_utils/query_utils.c=0A@@=20-0,0=20+1,92=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20Facilities=20for=20frontend=20code=20to=20query=20a=20= databases.=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=201996-2020,=20= PostgreSQL=20Global=20Development=20Group=0A+=20*=20Portions=20Copyright=20= (c)=201994,=20Regents=20of=20the=20University=20of=20California=0A+=20*=0A= +=20*=20src/fe_utils/query_utils.c=0A+=20*=0A+=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#include=20"postgres_fe.h"=0A+=0A+#include=20= "common/logging.h"=0A+#include=20"fe_utils/cancel.h"=0A+#include=20= "fe_utils/query_utils.h"=0A+=0A+/*=0A+=20*=20Run=20a=20query,=20return=20= the=20results,=20exit=20program=20on=20failure.=0A+=20*/=0A+PGresult=20*=0A= +executeQuery(PGconn=20*conn,=20const=20char=20*query,=20bool=20echo)=0A= +{=0A+=09PGresult=20=20=20*res;=0A+=0A+=09if=20(echo)=0A+=09=09= printf("%s\n",=20query);=0A+=0A+=09res=20=3D=20PQexec(conn,=20query);=0A= +=09if=20(!res=20||=0A+=09=09PQresultStatus(res)=20!=3D=20= PGRES_TUPLES_OK)=0A+=09{=0A+=09=09pg_log_error("query=20failed:=20%s",=20= PQerrorMessage(conn));=0A+=09=09pg_log_info("query=20was:=20%s",=20= query);=0A+=09=09PQfinish(conn);=0A+=09=09exit(1);=0A+=09}=0A+=0A+=09= return=20res;=0A+}=0A+=0A+=0A+/*=0A+=20*=20As=20above=20for=20a=20SQL=20= command=20(which=20returns=20nothing).=0A+=20*/=0A+void=0A= +executeCommand(PGconn=20*conn,=20const=20char=20*query,=20bool=20echo)=0A= +{=0A+=09PGresult=20=20=20*res;=0A+=0A+=09if=20(echo)=0A+=09=09= printf("%s\n",=20query);=0A+=0A+=09res=20=3D=20PQexec(conn,=20query);=0A= +=09if=20(!res=20||=0A+=09=09PQresultStatus(res)=20!=3D=20= PGRES_COMMAND_OK)=0A+=09{=0A+=09=09pg_log_error("query=20failed:=20%s",=20= PQerrorMessage(conn));=0A+=09=09pg_log_info("query=20was:=20%s",=20= query);=0A+=09=09PQfinish(conn);=0A+=09=09exit(1);=0A+=09}=0A+=0A+=09= PQclear(res);=0A+}=0A+=0A+=0A+/*=0A+=20*=20As=20above=20for=20a=20SQL=20= maintenance=20command=20(returns=20command=20success).=0A+=20*=20Command=20= is=20executed=20with=20a=20cancel=20handler=20set,=20so=20Ctrl-C=20can=0A= +=20*=20interrupt=20it.=0A+=20*/=0A+bool=0A= +executeMaintenanceCommand(PGconn=20*conn,=20const=20char=20*query,=20= bool=20echo)=0A+{=0A+=09PGresult=20=20=20*res;=0A+=09bool=09=09r;=0A+=0A= +=09if=20(echo)=0A+=09=09printf("%s\n",=20query);=0A+=0A+=09= SetCancelConn(conn);=0A+=09res=20=3D=20PQexec(conn,=20query);=0A+=09= ResetCancelConn();=0A+=0A+=09r=20=3D=20(res=20&&=20PQresultStatus(res)=20= =3D=3D=20PGRES_COMMAND_OK);=0A+=0A+=09if=20(res)=0A+=09=09PQclear(res);=0A= +=0A+=09return=20r;=0A+}=0Adiff=20--git=20a/src/fe_utils/string_utils.c=20= b/src/fe_utils/string_utils.c=0Aindex=209a1ea9ab98..94941132ac=20100644=0A= ---=20a/src/fe_utils/string_utils.c=0A+++=20= b/src/fe_utils/string_utils.c=0A@@=20-852,9=20+852,9=20@@=20= processSQLNamePattern(PGconn=20*conn,=20PQExpBuffer=20buf,=20const=20= char=20*pattern,=0A=20=09initPQExpBuffer(&namebuf);=0A=20=0A=20=09/*=0A-=09= =20*=20Convert=20shell-style=20'pattern'=20into=20the=20regular=20= expression(s)=20we=20want=20to=0A-=09=20*=20execute.=20=20= Quoting/escaping=20into=20SQL=20literal=20format=20will=20be=20done=20= below=0A-=09=20*=20using=20appendStringLiteralConn().=0A+=09=20*=20= Convert=20shell-style=20'pattern'=20into=20the=20regular=20expression(s)=20= we=20want=0A+=09=20*=20to=20execute.=20=20Quoting/escaping=20into=20SQL=20= literal=20format=20will=20be=20done=0A+=09=20*=20below=20using=20= appendStringLiteralConn().=0A=20=09=20*/=0A=20=09= patternToSQLRegex(PQclientEncoding(conn),=20NULL,=20&schemabuf,=20= &namebuf,=0A=20=09=09=09=09=09=20=20pattern,=20force_escape);=0A@@=20= -968,8=20+968,8=20@@=20patternToSQLRegex(int=20encoding,=20PQExpBuffer=20= dbnamebuf,=20PQExpBuffer=20schemabuf,=0A=20=09=09=09=09=20=20PQExpBuffer=20= namebuf,=20const=20char=20*pattern,=20bool=20force_escape)=0A=20{=0A=20=09= PQExpBufferData=20buf[3];=0A-=09PQExpBuffer=20curbuf;=0A-=09PQExpBuffer=20= maxbuf;=0A+=09PQExpBuffer=09curbuf;=0A+=09PQExpBuffer=09maxbuf;=0A=20=09= int=09=09=09i;=0A=20=09bool=09=09inquotes;=0A=20=09const=20char=20*cp;=0A= @@=20-1025,12=20+1025,11=20@@=20patternToSQLRegex(int=20encoding,=20= PQExpBuffer=20dbnamebuf,=20PQExpBuffer=20schemabuf,=0A=20=09=09=09= appendPQExpBufferChar(curbuf,=20'.');=0A=20=09=09=09cp++;=0A=20=09=09}=0A= -=0A=20=09=09/*=0A=20=09=09=20*=20When=20we=20find=20a=20= dbname/schema/name=20separator,=20we=20treat=20it=20specially=0A-=09=09=20= *=20only=20if=20the=20caller=20requested=20more=20patterns=20to=20be=20= parsed=20than=20we=0A-=09=09=20*=20have=20already=20parsed=20from=20the=20= pattern.=20=20Otherwise,=20dot=20characters=0A-=09=09=20*=20are=20not=20= special.=0A+=09=09=20*=20only=20if=20the=20caller=20requested=20more=20= patterns=20to=20be=20parsed=20than=20we=20have=0A+=09=09=20*=20already=20= parsed=20from=20the=20pattern.=20=20Otherwise,=20dot=20characters=20are=20= not=0A+=09=09=20*=20special.=0A=20=09=09=20*/=0A=20=09=09else=20if=20= (!inquotes=20&&=20ch=20=3D=3D=20'.'=20&&=20curbuf=20<=20maxbuf)=0A=20=09=09= {=0Adiff=20--git=20a/src/include/fe_utils/connect_utils.h=20= b/src/include/fe_utils/connect_utils.h=0Anew=20file=20mode=20100644=0A= index=200000000000..8fde0ea2a0=0A---=20/dev/null=0A+++=20= b/src/include/fe_utils/connect_utils.h=0A@@=20-0,0=20+1,48=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20Facilities=20for=20frontend=20code=20to=20connect=20= to=20and=20disconnect=20from=20databases.=0A+=20*=0A+=20*=20Portions=20= Copyright=20(c)=201996-2020,=20PostgreSQL=20Global=20Development=20Group=0A= +=20*=20Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20= University=20of=20California=0A+=20*=0A+=20*=20= src/include/fe_utils/connect_utils.h=0A+=20*=0A+=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#ifndef=20CONNECT_UTILS_H=0A+#define=20CONNECT_UTILS_H=0A+=0A= +#include=20"libpq-fe.h"=0A+=0A+enum=20trivalue=0A+{=0A+=09TRI_DEFAULT,=0A= +=09TRI_NO,=0A+=09TRI_YES=0A+};=0A+=0A+/*=20Parameters=20needed=20by=20= connectDatabase/connectMaintenanceDatabase=20*/=0A+typedef=20struct=20= _connParams=0A+{=0A+=09/*=20These=20fields=20record=20the=20actual=20= command=20line=20parameters=20*/=0A+=09const=20char=20*dbname;=09=09=09= /*=20this=20may=20be=20a=20connstring!=20*/=0A+=09const=20char=20= *pghost;=0A+=09const=20char=20*pgport;=0A+=09const=20char=20*pguser;=0A+=09= enum=20trivalue=20prompt_password;=0A+=09/*=20If=20not=20NULL,=20this=20= overrides=20the=20dbname=20obtained=20from=20command=20line=20*/=0A+=09= /*=20(but=20*only*=20the=20DB=20name,=20not=20anything=20else=20in=20the=20= connstring)=20*/=0A+=09const=20char=20*override_dbname;=0A+}=20= ConnParams;=0A+=0A+extern=20PGconn=20*connectDatabase(const=20ConnParams=20= *cparams,=0A+=09=09=09=09=09=09=09=20=20=20const=20char=20*progname,=0A+=09= =09=09=09=09=09=09=20=20=20bool=20echo,=20bool=20fail_ok,=0A+=09=09=09=09= =09=09=09=20=20=20bool=20allow_password_reuse);=0A+=0A+extern=20PGconn=20= *connectMaintenanceDatabase(ConnParams=20*cparams,=0A+=09=09=09=09=09=09=09= =09=09=09=20=20const=20char=20*progname,=20bool=20echo);=0A+=0A+extern=20= void=20disconnectDatabase(PGconn=20*conn);=0A+=0A+#endif=09=09=09=09=09=09= =09/*=20CONNECT_UTILS_H=20*/=0Adiff=20--git=20= a/src/include/fe_utils/option_utils.h=20= b/src/include/fe_utils/option_utils.h=0Anew=20file=20mode=20100644=0A= index=200000000000..ef6eb24ae0=0A---=20/dev/null=0A+++=20= b/src/include/fe_utils/option_utils.h=0A@@=20-0,0=20+1,23=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20Command=20line=20option=20processing=20facilities=20= for=20frontend=20code=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2020,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20src/include/fe_utils/option_utils.h=0A= +=20*=0A+=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#ifndef=20OPTION_UTILS_H=0A+#define=20OPTION_UTILS_H=0A+=0A= +#include=20"postgres_fe.h"=0A+=0A+typedef=20void=20(*help_handler)=20= (const=20char=20*progname);=0A+=0A+extern=20void=20= handle_help_version_opts(int=20argc,=20char=20*argv[],=0A+=09=09=09=09=09= =09=09=09=09=20const=20char=20*fixed_progname,=0A+=09=09=09=09=09=09=09=09= =09=20help_handler=20hlp);=0A+=0A+#endif=09=09=09=09=09=09=09/*=20= OPTION_UTILS_H=20*/=0Adiff=20--git=20= a/src/bin/scripts/scripts_parallel.h=20= b/src/include/fe_utils/parallel_slot.h=0Asimilarity=20index=2082%=0A= rename=20from=20src/bin/scripts/scripts_parallel.h=0Arename=20to=20= src/include/fe_utils/parallel_slot.h=0Aindex=20f62692510a..99eeb3328d=20= 100644=0A---=20a/src/bin/scripts/scripts_parallel.h=0A+++=20= b/src/include/fe_utils/parallel_slot.h=0A@@=20-1,21=20+1,20=20@@=0A=20= /*------------------------------------------------------------------------= -=0A=20=20*=0A-=20*=09scripts_parallel.h=0A+=20*=09parallel_slot.h=0A=20=20= *=09=09Parallel=20support=20for=20bin/scripts/=0A=20=20*=0A=20=20*=09= Copyright=20(c)=202003-2021,=20PostgreSQL=20Global=20Development=20Group=0A= =20=20*=0A-=20*=09src/bin/scripts/scripts_parallel.h=0A+=20*=09= src/include/fe_utils/parallel_slot.h=0A=20=20*=0A=20=20= *-------------------------------------------------------------------------= =0A=20=20*/=0A-#ifndef=20SCRIPTS_PARALLEL_H=0A-#define=20= SCRIPTS_PARALLEL_H=0A+#ifndef=20PARALLEL_SLOT_H=0A+#define=20= PARALLEL_SLOT_H=0A=20=0A-#include=20"common.h"=0A+#include=20= "fe_utils/connect_utils.h"=0A=20#include=20"libpq-fe.h"=0A=20=0A-=0A=20= typedef=20struct=20ParallelSlot=0A=20{=0A=20=09PGconn=09=20=20=20= *connection;=09=09/*=20One=20connection=20*/=0A@@=20-33,4=20+32,4=20@@=20= extern=20void=20ParallelSlotsTerminate(ParallelSlot=20*slots,=20int=20= numslots);=0A=20extern=20bool=20ParallelSlotsWaitCompletion(ParallelSlot=20= *slots,=20int=20numslots);=0A=20=0A=20=0A-#endif=09=09=09=09=09=09=09/*=20= SCRIPTS_PARALLEL_H=20*/=0A+#endif=09=09=09=09=09=09=09/*=20= PARALLEL_SLOT_H=20*/=0Adiff=20--git=20= a/src/include/fe_utils/query_utils.h=20= b/src/include/fe_utils/query_utils.h=0Anew=20file=20mode=20100644=0A= index=200000000000..1f5812bbf6=0A---=20/dev/null=0A+++=20= b/src/include/fe_utils/query_utils.h=0A@@=20-0,0=20+1,26=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20Facilities=20for=20frontend=20code=20to=20query=20a=20= databases.=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=201996-2020,=20= PostgreSQL=20Global=20Development=20Group=0A+=20*=20Portions=20Copyright=20= (c)=201994,=20Regents=20of=20the=20University=20of=20California=0A+=20*=0A= +=20*=20src/include/fe_utils/query_utils.h=0A+=20*=0A+=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#ifndef=20QUERY_UTILS_H=0A+#define=20QUERY_UTILS_H=0A+=0A= +#include=20"postgres_fe.h"=0A+=0A+#include=20"libpq-fe.h"=0A+=0A+extern=20= PGresult=20*executeQuery(PGconn=20*conn,=20const=20char=20*query,=20bool=20= echo);=0A+=0A+extern=20void=20executeCommand(PGconn=20*conn,=20const=20= char=20*query,=20bool=20echo);=0A+=0A+extern=20bool=20= executeMaintenanceCommand(PGconn=20*conn,=20const=20char=20*query,=0A+=09= =09=09=09=09=09=09=09=09=20=20bool=20echo);=0A+=0A+#endif=09=09=09=09=09=09= =09/*=20QUERY_UTILS_H=20*/=0Adiff=20--git=20= a/src/tools/msvc/Mkvcbuild.pm=20b/src/tools/msvc/Mkvcbuild.pm=0Aindex=20= 90328db04e..7be6e6c9e5=20100644=0A---=20a/src/tools/msvc/Mkvcbuild.pm=0A= +++=20b/src/tools/msvc/Mkvcbuild.pm=0A@@=20-147,8=20+147,8=20@@=20sub=20= mkvcbuild=0A=20=09our=20@pgcommonbkndfiles=20=3D=20@pgcommonallfiles;=0A=20= =0A=20=09our=20@pgfeutilsfiles=20=3D=20qw(=0A-=09=20=20archive.c=20= cancel.c=20conditional.c=20mbprint.c=20print.c=20psqlscan.l=0A-=09=20=20= psqlscan.c=20simple_list.c=20string_utils.c=20recovery_gen.c);=0A+=09=20=20= archive.c=20cancel.c=20conditional.c=20connect_utils.c=20mbprint.c=20= option_utils.c=20parallel_slot.c=20print.c=20psqlscan.l=0A+=09=20=20= psqlscan.c=20query_utils.c=20simple_list.c=20string_utils.c=20= recovery_gen.c);=0A=20=0A=20=09$libpgport=20=3D=20= $solution->AddProject('libpgport',=20'lib',=20'misc');=0A=20=09= $libpgport->AddDefine('FRONTEND');=0Adiff=20--git=20= a/src/tools/pgindent/typedefs.list=20b/src/tools/pgindent/typedefs.list=0A= index=201d540fe489..4d0d09a5dd=20100644=0A---=20= a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-403,6=20+403,7=20@@=20= ConfigData=0A=20ConfigVariable=0A=20ConnCacheEntry=0A=20ConnCacheKey=0A= +ConnParams=0A=20ConnStatusType=0A=20ConnType=0A=20ConnectionStateEnum=0A= --=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 Content-Disposition: attachment; filename=v36-0003-Parameterizing-parallel-slot-result-handling.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v36-0003-Parameterizing-parallel-slot-result-handling.patch" Content-Transfer-Encoding: quoted-printable =46rom=20968f9bcb440580f912d34a74ed2928e8658fb710=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Tue,=202=20Feb=202021=2012:35:56=20-0800=0ASubject:=20[PATCH=20= v36=203/5]=20Parameterizing=20parallel=20slot=20result=20handling=0A=0A= The=20function=20consumeQueryResult=20was=20being=20used=20to=20handle=20= all=20results=0Areturned=20by=20queries=20executed=20through=20the=20= parallel=20slot=20interface,=0Abut=20this=20hardcodes=20knowledge=20= about=20the=20expectations=20of=20reindexdb=20and=0Avacuumdb=20such=20as=20= the=20expected=20result=20status=20being=20PGRES_COMMAND_OK=0A(as=20= opposed=20to,=20say,=20PGRES_TUPLES_OK).=0A=0AReworking=20the=20slot=20= interface=20to=20optionally=20include=20a=20PGresultHandler=0Aand=20= related=20fields=20per=20slot.=20=20The=20idea=20is=20that=20a=20caller=20= who=20executes=0Aa=20command=20or=20query=20through=20the=20slot=20can=20= set=20the=20handler=20to=20be=20called=0Awhen=20the=20query=20completes.=0A= =0AThe=20old=20logic=20of=20consumeQueryResults=20is=20moved=20into=20a=20= new=20callback=0Afunction,=20TableCommandSlotHandler(),=20which=20gets=20= registered=20as=20the=0Aslot=20handler=20explicitly=20from=20vacuumdb=20= and=20reindexdb.=20=20This=20is=0Adefined=20in=20= fe_utils/parallel_slot.c=20rather=20than=20somewhere=20in=0A= src/bin/scripts=20where=20its=20only=20callers=20reside,=20partly=20to=20= keep=20it=0Aclose=20to=20the=20rest=20of=20the=20shared=20parallel=20= slot=20handling=20code=20and=0Apartly=20in=20anticipation=20that=20other=20= utility=20programs=20will=20eventually=0Awant=20to=20use=20it=20also.=0A=0A= Adding=20a=20default=20handler=20which=20is=20used=20to=20handle=20= results=20for=20slots=0Awhich=20have=20no=20handler=20explicitly=20= registered.=20=20The=20default=20simply=0Achecks=20the=20status=20of=20= the=20result=20and=20makes=20a=20judgement=20about=20whether=0Athe=20= status=20is=20ok,=20similarly=20to=20psql's=20AcceptResult().=20=20I=20= also=0Aconsidered=20whether=20to=20just=20have=20a=20missing=20handler=20= always=20be=20an=0Aerror,=20but=20decided=20against=20requiring=20users=20= of=20the=20parallel=20slot=0Ainfrastructure=20to=20pedantically=20= specify=20the=20default=20handler.=20=20Both=0Adesigns=20seem=20= reasonable,=20but=20the=20tie-breaker=20for=20me=20is=20that=20edge=0A= cases=20that=20do=20not=20come=20up=20in=20testing=20will=20be=20better=20= handled=20in=0Aproduction=20with=20this=20design=20than=20with=20= pedantically=20erroring=20out.=0A=0AThe=20expectation=20of=20this=20= commit=20is=20that=20pg_amcheck=20will=20have=20handlers=0Afor=20table=20= and=20index=20checks=20which=20will=20process=20the=20PGresults=20of=20= calls=0Ato=20the=20amcheck=20functions.=20=20This=20commit=20sets=20up=20= the=20infrastructure=0Anecessary=20to=20support=20those=20handlers=20= being=20different=20from=20the=20one=0Aused=20by=20vacuumdb=20and=20= reindexdb.=0A---=0A=20src/bin/scripts/reindexdb.c=20=20=20=20=20=20=20=20= =20=20|=20=20=201=20+=0A=20src/bin/scripts/vacuumdb.c=20=20=20=20=20=20=20= =20=20=20=20|=20=20=201=20+=0A=20src/fe_utils/parallel_slot.c=20=20=20=20= =20=20=20=20=20|=20142=20+++++++++++++++++++++------=0A=20= src/include/fe_utils/parallel_slot.h=20|=20=2032=20++++++=0A=204=20files=20= changed,=20148=20insertions(+),=2028=20deletions(-)=0A=0Adiff=20--git=20= a/src/bin/scripts/reindexdb.c=20b/src/bin/scripts/reindexdb.c=0Aindex=20= 7781fb1151..29394d4a4a=20100644=0A---=20a/src/bin/scripts/reindexdb.c=0A= +++=20b/src/bin/scripts/reindexdb.c=0A@@=20-466,6=20+466,7=20@@=20= reindex_one_database(const=20ConnParams=20*cparams,=20ReindexType=20= type,=0A=20=09=09=09goto=20finish;=0A=20=09=09}=0A=20=0A+=09=09= ParallelSlotSetHandler(free_slot,=20TableCommandSlotHandler,=20NULL);=0A=20= =09=09run_reindex_command(free_slot->connection,=20process_type,=20= objname,=0A=20=09=09=09=09=09=09=09echo,=20verbose,=20concurrently,=20= true);=0A=20=0Adiff=20--git=20a/src/bin/scripts/vacuumdb.c=20= b/src/bin/scripts/vacuumdb.c=0Aindex=20ed320817bc..1158f7b776=20100644=0A= ---=20a/src/bin/scripts/vacuumdb.c=0A+++=20b/src/bin/scripts/vacuumdb.c=0A= @@=20-713,6=20+713,7=20@@=20vacuum_one_database(const=20ConnParams=20= *cparams,=0A=20=09=09=20*=20Execute=20the=20vacuum.=20=20All=20errors=20= are=20handled=20in=20processQueryResult=0A=20=09=09=20*=20through=20= ParallelSlotsGetIdle.=0A=20=09=09=20*/=0A+=09=09= ParallelSlotSetHandler(free_slot,=20TableCommandSlotHandler,=20NULL);=0A=20= =09=09run_vacuum_command(free_slot->connection,=20sql.data,=0A=20=09=09=09= =09=09=09=20=20=20echo,=20tabname);=0A=20=0Adiff=20--git=20= a/src/fe_utils/parallel_slot.c=20b/src/fe_utils/parallel_slot.c=0Aindex=20= 3987a4702b..8e0c65988d=20100644=0A---=20a/src/fe_utils/parallel_slot.c=0A= +++=20b/src/fe_utils/parallel_slot.c=0A@@=20-30,7=20+30,7=20@@=0A=20=0A=20= static=20void=20init_slot(ParallelSlot=20*slot,=20PGconn=20*conn);=0A=20= static=20int=09select_loop(int=20maxFd,=20fd_set=20*workerset);=0A= -static=20bool=20processQueryResult(PGconn=20*conn,=20PGresult=20= *result);=0A+static=20bool=20handleOneQueryResult(ParallelSlot=20*slot,=20= PGresult=20*result);=0A=20=0A=20static=20void=0A=20= init_slot(ParallelSlot=20*slot,=20PGconn=20*conn)=0A@@=20-38,53=20+38,46=20= @@=20init_slot(ParallelSlot=20*slot,=20PGconn=20*conn)=0A=20=09= slot->connection=20=3D=20conn;=0A=20=09/*=20Initially=20assume=20= connection=20is=20idle=20*/=0A=20=09slot->isFree=20=3D=20true;=0A+=09= ParallelSlotClearHandler(slot);=0A=20}=0A=20=0A=20/*=0A-=20*=20Process=20= (and=20delete)=20a=20query=20result.=20=20Returns=20true=20if=20there's=20= no=20error,=0A-=20*=20false=20otherwise=20--=20but=20errors=20about=20= trying=20to=20work=20on=20a=20missing=20relation=0A-=20*=20are=20= reported=20and=20subsequently=20ignored.=0A+=20*=20Invoke=20the=20slot's=20= handler=20for=20a=20single=20query=20result,=20or=20fall=20back=20to=20= the=0A+=20*=20default=20handler=20if=20none=20is=20defined=20for=20the=20= slot.=20=20Returns=20true=20if=20the=0A+=20*=20handler=20reports=20that=20= there's=20no=20error,=20false=20otherwise.=0A=20=20*/=0A=20static=20bool=0A= -processQueryResult(PGconn=20*conn,=20PGresult=20*result)=0A= +handleOneQueryResult(ParallelSlot=20*slot,=20PGresult=20*result)=0A=20{=0A= -=09/*=0A-=09=20*=20If=20it's=20an=20error,=20report=20it.=20=20Errors=20= about=20a=20missing=20table=20are=20harmless=0A-=09=20*=20so=20we=20= continue=20processing;=20but=20die=20for=20other=20errors.=0A-=09=20*/=0A= -=09if=20(PQresultStatus(result)=20!=3D=20PGRES_COMMAND_OK)=0A-=09{=0A-=09= =09char=09=20=20=20*sqlState=20=3D=20PQresultErrorField(result,=20= PG_DIAG_SQLSTATE);=0A+=09PGresultHandler=20handler=20=3D=20= slot->handler;=0A=20=0A-=09=09pg_log_error("processing=20of=20database=20= \"%s\"=20failed:=20%s",=0A-=09=09=09=09=09=20PQdb(conn),=20= PQerrorMessage(conn));=0A+=09if=20(!handler)=0A+=09=09handler=20=3D=20= DefaultSlotHandler;=0A=20=0A-=09=09if=20(sqlState=20&&=20= strcmp(sqlState,=20ERRCODE_UNDEFINED_TABLE)=20!=3D=200)=0A-=09=09{=0A-=09= =09=09PQclear(result);=0A-=09=09=09return=20false;=0A-=09=09}=0A-=09}=0A= +=09/*=20On=20failure,=20the=20handler=20should=20return=20NULL=20after=20= freeing=20the=20result=20*/=0A+=09if=20(!handler(result,=20= slot->connection,=20slot->handler_context))=0A+=09=09return=20false;=0A=20= =0A+=09/*=20Ok,=20we=20have=20to=20free=20it=20ourself=20*/=0A=20=09= PQclear(result);=0A=20=09return=20true;=0A=20}=0A=20=0A=20/*=0A-=20*=20= Consume=20all=20the=20results=20generated=20for=20the=20given=20= connection=20until=0A+=20*=20Handle=20all=20the=20results=20generated=20= for=20the=20given=20connection=20until=0A=20=20*=20nothing=20remains.=20=20= If=20at=20least=20one=20error=20is=20encountered,=20return=20false.=0A=20= =20*=20Note=20that=20this=20will=20block=20if=20the=20connection=20is=20= busy.=0A=20=20*/=0A=20static=20bool=0A-consumeQueryResult(PGconn=20= *conn)=0A+handleQueryResults(ParallelSlot=20*slot)=0A=20{=0A=20=09bool=09= =09ok=20=3D=20true;=0A=20=09PGresult=20=20=20*result;=0A=20=0A-=09= SetCancelConn(conn);=0A-=09while=20((result=20=3D=20PQgetResult(conn))=20= !=3D=20NULL)=0A+=09SetCancelConn(slot->connection);=0A+=09while=20= ((result=20=3D=20PQgetResult(slot->connection))=20!=3D=20NULL)=0A=20=09{=0A= -=09=09if=20(!processQueryResult(conn,=20result))=0A+=09=09if=20= (!handleOneQueryResult(slot,=20result))=0A=20=09=09=09ok=20=3D=20false;=0A= =20=09}=0A=20=09ResetCancelConn();=0A@@=20-227,14=20+220,15=20@@=20= ParallelSlotsGetIdle(ParallelSlot=20*slots,=20int=20numslots)=0A=20=0A=20= =09=09=09=09if=20(result=20!=3D=20NULL)=0A=20=09=09=09=09{=0A-=09=09=09=09= =09/*=20Check=20and=20discard=20the=20command=20result=20*/=0A-=09=09=09=09= =09if=20(!processQueryResult(slots[i].connection,=20result))=0A+=09=09=09= =09=09/*=20Handle=20and=20discard=20the=20command=20result=20*/=0A+=09=09= =09=09=09if=20(!handleOneQueryResult(slots=20+=20i,=20result))=0A=20=09=09= =09=09=09=09return=20NULL;=0A=20=09=09=09=09}=0A=20=09=09=09=09else=0A=20= =09=09=09=09{=0A=20=09=09=09=09=09/*=20This=20connection=20has=20become=20= idle=20*/=0A=20=09=09=09=09=09slots[i].isFree=20=3D=20true;=0A+=09=09=09=09= =09ParallelSlotClearHandler(slots=20+=20i);=0A=20=09=09=09=09=09if=20= (firstFree=20<=200)=0A=20=09=09=09=09=09=09firstFree=20=3D=20i;=0A=20=09=09= =09=09=09break;=0A@@=20-329,9=20+323,101=20@@=20= ParallelSlotsWaitCompletion(ParallelSlot=20*slots,=20int=20numslots)=0A=20= =0A=20=09for=20(i=20=3D=200;=20i=20<=20numslots;=20i++)=0A=20=09{=0A-=09=09= if=20(!consumeQueryResult((slots=20+=20i)->connection))=0A+=09=09if=20= (!handleQueryResults(slots=20+=20i))=0A=20=09=09=09return=20false;=0A=20=09= }=0A=20=0A=20=09return=20true;=0A=20}=0A+=0A+/*=0A+=20*=20= DefaultSlotHandler=0A+=20*=0A+=20*=20PGresultHandler=20for=20query=20= results=20from=20slots=20with=20no=20handler=20registered.=0A+=20*=20= Success=20or=20failure=20is=20determined=20entirely=20by=20examining=20= the=20status=20of=20the=0A+=20*=20query=20result.=20=20This=20is=20very=20= basic,=20but=20users=20who=20need=20better=20can=20register=20a=0A+=20*=20= custom=20handler.=0A+=20*=0A+=20*=20res:=20PGresult=20from=20the=20query=20= executed=20on=20the=20slot's=20connection=0A+=20*=20conn:=20connection=20= belonging=20to=20the=20slot=0A+=20*=20context:=20unused=0A+=20*/=0A= +PGresult=20*=0A+DefaultSlotHandler(PGresult=20*res,=20PGconn=20*conn,=20= void=20*context)=0A+{=0A+=09switch=20(PQresultStatus(res))=0A+=09{=0A+=09= =09=09/*=20Success=20codes=20*/=0A+=09=09case=20PGRES_EMPTY_QUERY:=0A+=09= =09case=20PGRES_COMMAND_OK:=0A+=09=09case=20PGRES_TUPLES_OK:=0A+=09=09= case=20PGRES_COPY_OUT:=0A+=09=09case=20PGRES_COPY_IN:=0A+=09=09case=20= PGRES_COPY_BOTH:=0A+=09=09case=20PGRES_SINGLE_TUPLE:=0A+=09=09=09/*=20Ok=20= */=0A+=09=09=09return=20res;=0A+=0A+=09=09=09/*=20Error=20codes=20*/=0A+=09= =09case=20PGRES_BAD_RESPONSE:=0A+=09=09case=20PGRES_NONFATAL_ERROR:=0A+=09= =09case=20PGRES_FATAL_ERROR:=0A+=09=09=09break;=0A+=0A+=09=09=09/*=20= Intentionally=20no=20default=20here=20*/=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= Handle=20all=20error=20cases=20here,=20including=20anything=20not=20= matched=20in=20the=0A+=09=20*=20switch=20(though=20that=20should=20not=20= happen.)=20=20The=20'query'=20argument=20may=20be=0A+=09=20*=20NULL=20or=20= garbage=20left=20over=20from=20a=20prior=20usage=20of=20the=20lot.=20=20= Don't=20include=0A+=09=20*=20it=20in=20the=20error=20message!=0A+=09=20= */=0A+=09pg_log_error("processing=20in=20database=20\"%s\"=20failed:=20= %s",=20PQdb(conn),=0A+=09=09=09=09=20PQerrorMessage(conn));=0A+=09= PQclear(res);=0A+=09return=20NULL;=0A+}=0A+=0A+/*=0A+=20*=20= TableCommandSlotHandler=0A+=20*=0A+=20*=20PGresultHandler=20for=20= results=20of=20commands=20(not=20queries)=20against=20tables.=0A+=20*=0A= +=20*=20Requires=20that=20the=20result=20status=20is=20either=20= PGRES_COMMAND_OK=20or=20an=20error=20about=0A+=20*=20a=20missing=20= table.=20=20This=20is=20useful=20for=20utilities=20that=20compile=20a=20= list=20of=20tables=0A+=20*=20to=20process=20and=20then=20run=20commands=20= (vacuum,=20reindex,=20or=20whatever)=20against=0A+=20*=20those=20tables,=20= as=20there=20is=20a=20race=20condition=20between=20the=20time=20the=20= list=20is=0A+=20*=20compiled=20and=20the=20time=20the=20command=20= attempts=20to=20open=20the=20table.=0A+=20*=0A+=20*=20For=20missing=20= tables,=20logs=20an=20error=20but=20allows=20processing=20to=20continue.=0A= +=20*=0A+=20*=20For=20all=20other=20errors,=20logs=20an=20error=20and=20= terminates=20further=20processing.=0A+=20*=0A+=20*=20res:=20PGresult=20= from=20the=20query=20executed=20on=20the=20slot's=20connection=0A+=20*=20= conn:=20connection=20belonging=20to=20the=20slot=0A+=20*=20context:=20= unused=0A+=20*/=0A+PGresult=20*=0A+TableCommandSlotHandler(PGresult=20= *res,=20PGconn=20*conn,=20void=20*context)=0A+{=0A+=09/*=0A+=09=20*=20If=20= it's=20an=20error,=20report=20it.=20=20Errors=20about=20a=20missing=20= table=20are=20harmless=0A+=09=20*=20so=20we=20continue=20processing;=20= but=20die=20for=20other=20errors.=0A+=09=20*/=0A+=09if=20= (PQresultStatus(res)=20!=3D=20PGRES_COMMAND_OK)=0A+=09{=0A+=09=09char=09=20= =20=20*sqlState=20=3D=20PQresultErrorField(res,=20PG_DIAG_SQLSTATE);=0A+=0A= +=09=09pg_log_error("processing=20of=20database=20\"%s\"=20failed:=20= %s",=0A+=09=09=09=09=09=20PQdb(conn),=20PQerrorMessage(conn));=0A+=0A+=09= =09if=20(sqlState=20&&=20strcmp(sqlState,=20ERRCODE_UNDEFINED_TABLE)=20= !=3D=200)=0A+=09=09{=0A+=09=09=09PQclear(res);=0A+=09=09=09return=20= NULL;=0A+=09=09}=0A+=09}=0A+=0A+=09return=20res;=0A+}=0Adiff=20--git=20= a/src/include/fe_utils/parallel_slot.h=20= b/src/include/fe_utils/parallel_slot.h=0Aindex=2099eeb3328d..524d62306d=20= 100644=0A---=20a/src/include/fe_utils/parallel_slot.h=0A+++=20= b/src/include/fe_utils/parallel_slot.h=0A@@=20-15,12=20+15,39=20@@=0A=20= #include=20"fe_utils/connect_utils.h"=0A=20#include=20"libpq-fe.h"=0A=20=0A= +typedef=20PGresult=20*(*PGresultHandler)=20(PGresult=20*res,=20PGconn=20= *conn,=0A+=09=09=09=09=09=09=09=09=09=20=20void=20*context);=0A+=0A=20= typedef=20struct=20ParallelSlot=0A=20{=0A=20=09PGconn=09=20=20=20= *connection;=09=09/*=20One=20connection=20*/=0A=20=09bool=09=09isFree;=09= =09=09/*=20Is=20it=20known=20to=20be=20idle?=20*/=0A+=0A+=09/*=0A+=09=20= *=20Prior=20to=20issuing=20a=20command=20or=20query=20on=20'connection',=20= a=20handler=20callback=0A+=09=20*=20function=20may=20optionally=20be=20= registered=20to=20be=20invoked=20to=20process=20the=0A+=09=20*=20= results,=20and=20context=20information=20may=20optionally=20be=20= registered=20for=20use=0A+=09=20*=20by=20the=20handler.=20=20If=20unset,=20= these=20fields=20should=20be=20NULL.=0A+=09=20*/=0A+=09PGresultHandler=20= handler;=0A+=09void=09=20=20=20*handler_context;=0A=20}=20ParallelSlot;=0A= =20=0A+static=20inline=20void=0A+ParallelSlotSetHandler(ParallelSlot=20= *slot,=20PGresultHandler=20handler,=0A+=09=09=09=09=09=20=20=20void=20= *context)=0A+{=0A+=09slot->handler=20=3D=20handler;=0A+=09= slot->handler_context=20=3D=20context;=0A+}=0A+=0A+static=20inline=20= void=0A+ParallelSlotClearHandler(ParallelSlot=20*slot)=0A+{=0A+=09= slot->handler=20=3D=20NULL;=0A+=09slot->handler_context=20=3D=20NULL;=0A= +}=0A+=0A=20extern=20ParallelSlot=20*ParallelSlotsGetIdle(ParallelSlot=20= *slots,=20int=20numslots);=0A=20=0A=20extern=20ParallelSlot=20= *ParallelSlotsSetup(const=20ConnParams=20*cparams,=0A@@=20-31,5=20+58,10=20= @@=20extern=20void=20ParallelSlotsTerminate(ParallelSlot=20*slots,=20int=20= numslots);=0A=20=0A=20extern=20bool=20= ParallelSlotsWaitCompletion(ParallelSlot=20*slots,=20int=20numslots);=0A=20= =0A+extern=20PGresult=20*DefaultSlotHandler(PGresult=20*res,=20PGconn=20= *conn,=0A+=09=09=09=09=09=09=09=09=09void=20*context);=0A+=0A+extern=20= PGresult=20*TableCommandSlotHandler(PGresult=20*res,=20PGconn=20*conn,=0A= +=09=09=09=09=09=09=09=09=09=09=20void=20*context);=0A=20=0A=20#endif=09=09= =09=09=09=09=09/*=20PARALLEL_SLOT_H=20*/=0A--=20=0A2.21.1=20(Apple=20= Git-122.3)=0A=0A= --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 Content-Disposition: attachment; filename=v36-0004-Adding-contrib-module-pg_amcheck.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v36-0004-Adding-contrib-module-pg_amcheck.patch" Content-Transfer-Encoding: quoted-printable =46rom=201fbb9903eaef4d5e30f986f77226fdd7fdf7c680=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Tue,=202=20Feb=202021=2012:36:59=20-0800=0ASubject:=20[PATCH=20= v36=204/5]=20Adding=20contrib=20module=20pg_amcheck=0A=0AAdding=20new=20= contrib=20module=20pg_amcheck,=20which=20is=20a=20command=20line=0A= interface=20for=20running=20amcheck's=20verifications=20against=20tables=20= and=0Aindexes.=0A---=0A=20contrib/Makefile=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=20=201=20+=0A=20= contrib/pg_amcheck/.gitignore=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20= =20=20=203=20+=0A=20contrib/pg_amcheck/Makefile=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=2029=20+=0A=20= contrib/pg_amcheck/pg_amcheck.c=20=20=20=20=20=20=20=20=20=20=20=20|=20= 1519=20++++++++++++++++++++=0A=20contrib/pg_amcheck/pg_amcheck.h=20=20=20= =20=20=20=20=20=20=20=20=20|=20=20135=20++=0A=20= contrib/pg_amcheck/t/001_basic.pl=20=20=20=20=20=20=20=20=20=20|=20=20=20= =209=20+=0A=20contrib/pg_amcheck/t/002_nonesuch.pl=20=20=20=20=20=20=20|=20= =20=2078=20+=0A=20contrib/pg_amcheck/t/003_check.pl=20=20=20=20=20=20=20=20= =20=20|=20=20475=20++++++=0A=20contrib/pg_amcheck/t/004_verify_heapam.pl=20= =20|=20=20496=20+++++++=0A=20contrib/pg_amcheck/t/005_opclass_damage.pl=20= |=20=20=2052=20+=0A=20doc/src/sgml/contrib.sgml=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=20=20=201=20+=0A=20= doc/src/sgml/filelist.sgml=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=20=201=20+=0A=20doc/src/sgml/pgamcheck.sgml=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20|=201004=20+++++++++++++=0A=20= src/tools/msvc/Install.pm=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20=20=20=202=20+-=0A=20src/tools/msvc/Mkvcbuild.pm=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20|=20=20=20=206=20+-=0A=20= src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20|=20=20=20= =204=20+=0A=2016=20files=20changed,=203811=20insertions(+),=204=20= deletions(-)=0A=20create=20mode=20100644=20contrib/pg_amcheck/.gitignore=0A= =20create=20mode=20100644=20contrib/pg_amcheck/Makefile=0A=20create=20= mode=20100644=20contrib/pg_amcheck/pg_amcheck.c=0A=20create=20mode=20= 100644=20contrib/pg_amcheck/pg_amcheck.h=0A=20create=20mode=20100644=20= contrib/pg_amcheck/t/001_basic.pl=0A=20create=20mode=20100644=20= contrib/pg_amcheck/t/002_nonesuch.pl=0A=20create=20mode=20100644=20= contrib/pg_amcheck/t/003_check.pl=0A=20create=20mode=20100644=20= contrib/pg_amcheck/t/004_verify_heapam.pl=0A=20create=20mode=20100644=20= contrib/pg_amcheck/t/005_opclass_damage.pl=0A=20create=20mode=20100644=20= doc/src/sgml/pgamcheck.sgml=0A=0Adiff=20--git=20a/contrib/Makefile=20= b/contrib/Makefile=0Aindex=20f27e458482..a72dcf7304=20100644=0A---=20= a/contrib/Makefile=0A+++=20b/contrib/Makefile=0A@@=20-30,6=20+30,7=20@@=20= SUBDIRS=20=3D=20\=0A=20=09=09old_snapshot=09\=0A=20=09=09pageinspect=09\=0A= =20=09=09passwordcheck=09\=0A+=09=09pg_amcheck=09\=0A=20=09=09= pg_buffercache=09\=0A=20=09=09pg_freespacemap=20\=0A=20=09=09pg_prewarm=09= \=0Adiff=20--git=20a/contrib/pg_amcheck/.gitignore=20= b/contrib/pg_amcheck/.gitignore=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..c21a14de31=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/.gitignore=0A@@=20-0,0=20+1,3=20@@=0A+pg_amcheck=0A= +=0A+/tmp_check/=0Adiff=20--git=20a/contrib/pg_amcheck/Makefile=20= b/contrib/pg_amcheck/Makefile=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..bc61ee7970=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/Makefile=0A@@=20-0,0=20+1,29=20@@=0A+#=20= contrib/pg_amcheck/Makefile=0A+=0A+PGFILEDESC=20=3D=20"pg_amcheck=20-=20= detects=20corruption=20within=20database=20relations"=0A+PGAPPICON=20=3D=20= win32=0A+=0A+PROGRAM=20=3D=20pg_amcheck=0A+OBJS=20=3D=20\=0A+=09= $(WIN32RES)=20\=0A+=09pg_amcheck.o=0A+=0A+REGRESS_OPTS=20+=3D=20= --load-extension=3Damcheck=20--load-extension=3Dpageinspect=0A= +EXTRA_INSTALL=20+=3D=20contrib/amcheck=20contrib/pageinspect=0A+=0A= +TAP_TESTS=20=3D=201=0A+=0A+PG_CPPFLAGS=20=3D=20-I$(libpq_srcdir)=0A= +PG_LIBS_INTERNAL=20=3D=20-L$(top_builddir)/src/fe_utils=20-lpgfeutils=20= $(libpq_pgport)=0A+=0A+ifdef=20USE_PGXS=0A+PG_CONFIG=20=3D=20pg_config=0A= +PGXS=20:=3D=20$(shell=20$(PG_CONFIG)=20--pgxs)=0A+include=20$(PGXS)=0A= +else=0A+SHLIB_PREREQS=20=3D=20submake-libpq=0A+subdir=20=3D=20= contrib/pg_amcheck=0A+top_builddir=20=3D=20../..=0A+include=20= $(top_builddir)/src/Makefile.global=0A+include=20= $(top_srcdir)/contrib/contrib-global.mk=0A+endif=0Adiff=20--git=20= a/contrib/pg_amcheck/pg_amcheck.c=20b/contrib/pg_amcheck/pg_amcheck.c=0A= new=20file=20mode=20100644=0Aindex=200000000000..4209b5ec50=0A---=20= /dev/null=0A+++=20b/contrib/pg_amcheck/pg_amcheck.c=0A@@=20-0,0=20= +1,1519=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20pg_amcheck.c=0A+=20*=09=09Detects=20corruption=20= within=20database=20relations.=0A+=20*=0A+=20*=20Copyright=20(c)=20= 2017-2020,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=0A+=20*=20= IDENTIFICATION=0A+=20*=09=20=20contrib/pg_amcheck/pg_amcheck.c=0A+=20*=0A= +=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#include=20"postgres_fe.h"=0A+=0A+#include=20= "catalog/pg_class.h"=0A+#include=20"common/connect.h"=0A+#include=20= "common/logging.h"=0A+#include=20"common/username.h"=0A+#include=20= "fe_utils/cancel.h"=0A+#include=20"fe_utils/connect_utils.h"=0A+#include=20= "fe_utils/option_utils.h"=0A+#include=20"fe_utils/parallel_slot.h"=0A= +#include=20"fe_utils/query_utils.h"=0A+#include=20= "fe_utils/simple_list.h"=0A+#include=20"fe_utils/string_utils.h"=0A= +#include=20"getopt_long.h"=09=09/*=20pgrminclude=20ignore=20*/=0A= +#include=20"libpq-fe.h"=0A+#include=20"pg_amcheck.h"=0A+#include=20= "pqexpbuffer.h"=09=09/*=20pgrminclude=20ignore=20*/=0A+#include=20= "storage/block.h"=0A+=0A+/*=20Keep=20this=20in=20order=20by=20CheckType=20= */=0A+static=20const=20CheckTypeFilter=20ctfilter[]=20=3D=20{=0A+=09{=0A= +=09=09.relam=20=3D=20HEAP_TABLE_AM_OID,=0A+=09=09.relkinds=20=3D=20= CppAsString2(RELKIND_RELATION)=20","=0A+=09=09= CppAsString2(RELKIND_MATVIEW)=20","=0A+=09=09= CppAsString2(RELKIND_TOASTVALUE),=0A+=09=09.typname=20=3D=20"heap"=0A+=09= },=0A+=09{=0A+=09=09.relam=20=3D=20BTREE_AM_OID,=0A+=09=09.relkinds=20=3D=20= CppAsString2(RELKIND_INDEX),=0A+=09=09.typname=20=3D=20"btree=20index"=0A= +=09}=0A+};=0A+=0A+/*=0A+=20*=20Query=20for=20determining=20if=20= contrib's=20amcheck=20is=20installed.=20=20If=20so,=20selects=20the=0A+=20= *=20namespace=20name=20where=20amcheck's=20functions=20can=20be=20found.=0A= +=20*/=0A+static=20const=20char=20*amcheck_sql=20=3D=0A+"SELECT=20= n.nspname,=20x.extversion"=0A+"\nFROM=20pg_catalog.pg_extension=20x"=0A= +"\nJOIN=20pg_catalog.pg_namespace=20n"=0A+"\nON=20x.extnamespace=20= OPERATOR(pg_catalog.=3D)=20n.oid"=0A+"\nWHERE=20x.extname=20= OPERATOR(pg_catalog.=3D)=20'amcheck'";=0A+=0A+int=0A+main(int=20argc,=20= char=20*argv[])=0A+{=0A+=09static=20struct=20option=20long_options[]=20=3D= =20{=0A+=09=09/*=20Connection=20options=20*/=0A+=09=09{"host",=20= required_argument,=20NULL,=20'h'},=0A+=09=09{"port",=20= required_argument,=20NULL,=20'p'},=0A+=09=09{"username",=20= required_argument,=20NULL,=20'U'},=0A+=09=09{"no-password",=20= no_argument,=20NULL,=20'w'},=0A+=09=09{"password",=20no_argument,=20= NULL,=20'W'},=0A+=09=09{"maintenance-db",=20required_argument,=20NULL,=20= 1},=0A+=0A+=09=09/*=20check=20options=20*/=0A+=09=09{"all",=20= no_argument,=20NULL,=20'a'},=0A+=09=09{"dbname",=20required_argument,=20= NULL,=20'd'},=0A+=09=09{"exclude-dbname",=20required_argument,=20NULL,=20= 'D'},=0A+=09=09{"echo",=20no_argument,=20NULL,=20'e'},=0A+=09=09= {"heapallindexed",=20no_argument,=20NULL,=20'H'},=0A+=09=09{"index",=20= required_argument,=20NULL,=20'i'},=0A+=09=09{"exclude-index",=20= required_argument,=20NULL,=20'I'},=0A+=09=09{"jobs",=20= required_argument,=20NULL,=20'j'},=0A+=09=09{"parent-check",=20= no_argument,=20NULL,=20'P'},=0A+=09=09{"quiet",=20no_argument,=20NULL,=20= 'q'},=0A+=09=09{"relation",=20required_argument,=20NULL,=20'r'},=0A+=09=09= {"exclude-relation",=20required_argument,=20NULL,=20'R'},=0A+=09=09= {"schema",=20required_argument,=20NULL,=20's'},=0A+=09=09= {"exclude-schema",=20required_argument,=20NULL,=20'S'},=0A+=09=09= {"table",=20required_argument,=20NULL,=20't'},=0A+=09=09= {"exclude-table",=20required_argument,=20NULL,=20'T'},=0A+=09=09= {"verbose",=20no_argument,=20NULL,=20'v'},=0A+=09=09{"exclude-indexes",=20= no_argument,=20NULL,=202},=0A+=09=09{"exclude-toast",=20no_argument,=20= NULL,=203},=0A+=09=09{"exclude-toast-pointers",=20no_argument,=20NULL,=20= 4},=0A+=09=09{"on-error-stop",=20no_argument,=20NULL,=205},=0A+=09=09= {"skip",=20required_argument,=20NULL,=206},=0A+=09=09{"startblock",=20= required_argument,=20NULL,=207},=0A+=09=09{"endblock",=20= required_argument,=20NULL,=208},=0A+=09=09{"rootdescend",=20no_argument,=20= NULL,=209},=0A+=09=09{"no-dependents",=20no_argument,=20NULL,=2010},=0A+=0A= +=09=09{NULL,=200,=20NULL,=200}=0A+=09};=0A+=0A+=09const=20char=20= *progname;=0A+=09int=09=09=09optindex;=0A+=09int=09=09=09c;=0A+=0A+=09= const=20char=20*maintenance_db=20=3D=20NULL;=0A+=09const=20char=20= *connect_db=20=3D=20NULL;=0A+=09const=20char=20*host=20=3D=20NULL;=0A+=09= const=20char=20*port=20=3D=20NULL;=0A+=09const=20char=20*username=20=3D=20= NULL;=0A+=09enum=20trivalue=20prompt_password=20=3D=20TRI_DEFAULT;=0A+=09= ConnParams=09cparams;=0A+=0A+=09amcheckOptions=20checkopts=20=3D=20{=0A+=09= =09.alldb=20=3D=20false,=0A+=09=09.echo=20=3D=20false,=0A+=09=09.quiet=20= =3D=20false,=0A+=09=09.verbose=20=3D=20false,=0A+=09=09.dependents=20=3D=20= true,=0A+=09=09.no_indexes=20=3D=20false,=0A+=09=09.on_error_stop=20=3D=20= false,=0A+=09=09.parent_check=20=3D=20false,=0A+=09=09.rootdescend=20=3D=20= false,=0A+=09=09.heapallindexed=20=3D=20false,=0A+=09=09.exclude_toast=20= =3D=20false,=0A+=09=09.reconcile_toast=20=3D=20true,=0A+=09=09.skip=20=3D=20= "none",=0A+=09=09.jobs=20=3D=20-1,=0A+=09=09.startblock=20=3D=20-1,=0A+=09= =09.endblock=20=3D=20-1=0A+=09};=0A+=0A+=09amcheckObjects=20objects=20=3D=20= {=0A+=09=09.databases=20=3D=20{NULL,=20NULL},=0A+=09=09.schemas=20=3D=20= {NULL,=20NULL},=0A+=09=09.tables=20=3D=20{NULL,=20NULL},=0A+=09=09= .indexes=20=3D=20{NULL,=20NULL},=0A+=09=09.exclude_databases=20=3D=20= {NULL,=20NULL},=0A+=09=09.exclude_schemas=20=3D=20{NULL,=20NULL},=0A+=09=09= .exclude_tables=20=3D=20{NULL,=20NULL},=0A+=09=09.exclude_indexes=20=3D=20= {NULL,=20NULL}=0A+=09};=0A+=0A+=09pg_logging_init(argv[0]);=0A+=09= progname=20=3D=20get_progname(argv[0]);=0A+=09= set_pglocale_pgservice(argv[0],=20PG_TEXTDOMAIN("contrib"));=0A+=0A+=09= handle_help_version_opts(argc,=20argv,=20progname,=20help);=0A+=0A+=09/*=20= process=20command-line=20options=20*/=0A+=09while=20((c=20=3D=20= getopt_long(argc,=20argv,=20"ad:D:eh:Hi:I:j:p:Pqr:R:s:S:t:T:U:wWv",=0A+=09= =09=09=09=09=09=09long_options,=20&optindex))=20!=3D=20-1)=0A+=09{=0A+=09= =09char=09=20=20=20*endptr;=0A+=0A+=09=09switch=20(c)=0A+=09=09{=0A+=09=09= =09case=20'a':=0A+=09=09=09=09checkopts.alldb=20=3D=20true;=0A+=09=09=09=09= break;=0A+=09=09=09case=20'd':=0A+=09=09=09=09= simple_string_list_append(&objects.databases,=20optarg);=0A+=09=09=09=09= break;=0A+=09=09=09case=20'D':=0A+=09=09=09=09= simple_string_list_append(&objects.exclude_databases,=20optarg);=0A+=09=09= =09=09break;=0A+=09=09=09case=20'e':=0A+=09=09=09=09checkopts.echo=20=3D=20= true;=0A+=09=09=09=09break;=0A+=09=09=09case=20'h':=0A+=09=09=09=09host=20= =3D=20pg_strdup(optarg);=0A+=09=09=09=09break;=0A+=09=09=09case=20'H':=0A= +=09=09=09=09checkopts.heapallindexed=20=3D=20true;=0A+=09=09=09=09= break;=0A+=09=09=09case=20'i':=0A+=09=09=09=09= simple_string_list_append(&objects.indexes,=20optarg);=0A+=09=09=09=09= break;=0A+=09=09=09case=20'I':=0A+=09=09=09=09= simple_string_list_append(&objects.exclude_indexes,=20optarg);=0A+=09=09=09= =09break;=0A+=09=09=09case=20'j':=0A+=09=09=09=09checkopts.jobs=20=3D=20= atoi(optarg);=0A+=09=09=09=09if=20(checkopts.jobs=20<=3D=200)=0A+=09=09=09= =09{=0A+=09=09=09=09=09pg_log_error("number=20of=20parallel=20jobs=20= must=20be=20at=20least=201");=0A+=09=09=09=09=09exit(1);=0A+=09=09=09=09= }=0A+=09=09=09=09break;=0A+=09=09=09case=20'p':=0A+=09=09=09=09port=20=3D=20= pg_strdup(optarg);=0A+=09=09=09=09break;=0A+=09=09=09case=20'P':=0A+=09=09= =09=09checkopts.parent_check=20=3D=20true;=0A+=09=09=09=09break;=0A+=09=09= =09case=20'q':=0A+=09=09=09=09checkopts.quiet=20=3D=20true;=0A+=09=09=09=09= break;=0A+=09=09=09case=20'r':=0A+=09=09=09=09= simple_string_list_append(&objects.indexes,=20optarg);=0A+=09=09=09=09= simple_string_list_append(&objects.tables,=20optarg);=0A+=09=09=09=09= break;=0A+=09=09=09case=20'R':=0A+=09=09=09=09= simple_string_list_append(&objects.exclude_tables,=20optarg);=0A+=09=09=09= =09simple_string_list_append(&objects.exclude_indexes,=20optarg);=0A+=09=09= =09=09break;=0A+=09=09=09case=20's':=0A+=09=09=09=09= simple_string_list_append(&objects.schemas,=20optarg);=0A+=09=09=09=09= break;=0A+=09=09=09case=20'S':=0A+=09=09=09=09= simple_string_list_append(&objects.exclude_schemas,=20optarg);=0A+=09=09=09= =09break;=0A+=09=09=09case=20't':=0A+=09=09=09=09= simple_string_list_append(&objects.tables,=20optarg);=0A+=09=09=09=09= break;=0A+=09=09=09case=20'T':=0A+=09=09=09=09= simple_string_list_append(&objects.exclude_tables,=20optarg);=0A+=09=09=09= =09break;=0A+=09=09=09case=20'U':=0A+=09=09=09=09username=20=3D=20= pg_strdup(optarg);=0A+=09=09=09=09break;=0A+=09=09=09case=20'w':=0A+=09=09= =09=09prompt_password=20=3D=20TRI_NO;=0A+=09=09=09=09break;=0A+=09=09=09= case=20'W':=0A+=09=09=09=09prompt_password=20=3D=20TRI_YES;=0A+=09=09=09=09= break;=0A+=09=09=09case=20'v':=0A+=09=09=09=09checkopts.verbose=20=3D=20= true;=0A+=09=09=09=09pg_logging_increase_verbosity();=0A+=09=09=09=09= break;=0A+=09=09=09case=201:=0A+=09=09=09=09maintenance_db=20=3D=20= pg_strdup(optarg);=0A+=09=09=09=09break;=0A+=09=09=09case=202:=0A+=09=09=09= =09checkopts.no_indexes=20=3D=20true;=0A+=09=09=09=09break;=0A+=09=09=09= case=203:=0A+=09=09=09=09checkopts.exclude_toast=20=3D=20true;=0A+=09=09=09= =09break;=0A+=09=09=09case=204:=0A+=09=09=09=09checkopts.reconcile_toast=20= =3D=20false;=0A+=09=09=09=09break;=0A+=09=09=09case=205:=0A+=09=09=09=09= checkopts.on_error_stop=20=3D=20true;=0A+=09=09=09=09break;=0A+=09=09=09= case=206:=0A+=09=09=09=09if=20(pg_strcasecmp(optarg,=20"all-visible")=20= =3D=3D=200)=0A+=09=09=09=09=09checkopts.skip=20=3D=20"all=20visible";=0A= +=09=09=09=09else=20if=20(pg_strcasecmp(optarg,=20"all-frozen")=20=3D=3D=20= 0)=0A+=09=09=09=09=09checkopts.skip=20=3D=20"all=20frozen";=0A+=09=09=09=09= else=0A+=09=09=09=09{=0A+=09=09=09=09=09fprintf(stderr,=20_("invalid=20= skip=20options"));=0A+=09=09=09=09=09exit(1);=0A+=09=09=09=09}=0A+=09=09=09= =09break;=0A+=09=09=09case=207:=0A+=09=09=09=09checkopts.startblock=20=3D=20= strtol(optarg,=20&endptr,=2010);=0A+=09=09=09=09if=20(*endptr=20!=3D=20= '\0')=0A+=09=09=09=09{=0A+=09=09=09=09=09fprintf(stderr,=0A+=09=09=09=09=09= =09=09_("relation=20starting=20block=20argument=20contains=20garbage=20= characters"));=0A+=09=09=09=09=09exit(1);=0A+=09=09=09=09}=0A+=09=09=09=09= if=20(checkopts.startblock=20>=20(long)=20MaxBlockNumber)=0A+=09=09=09=09= {=0A+=09=09=09=09=09fprintf(stderr,=0A+=09=09=09=09=09=09=09_("relation=20= starting=20block=20argument=20out=20of=20bounds"));=0A+=09=09=09=09=09= exit(1);=0A+=09=09=09=09}=0A+=09=09=09=09break;=0A+=09=09=09case=208:=0A= +=09=09=09=09checkopts.endblock=20=3D=20strtol(optarg,=20&endptr,=2010);=0A= +=09=09=09=09if=20(*endptr=20!=3D=20'\0')=0A+=09=09=09=09{=0A+=09=09=09=09= =09fprintf(stderr,=0A+=09=09=09=09=09=09=09_("relation=20ending=20block=20= argument=20contains=20garbage=20characters"));=0A+=09=09=09=09=09= exit(1);=0A+=09=09=09=09}=0A+=09=09=09=09if=20(checkopts.startblock=20>=20= (long)=20MaxBlockNumber)=0A+=09=09=09=09{=0A+=09=09=09=09=09= fprintf(stderr,=0A+=09=09=09=09=09=09=09_("relation=20ending=20block=20= argument=20out=20of=20bounds"));=0A+=09=09=09=09=09exit(1);=0A+=09=09=09=09= }=0A+=09=09=09=09break;=0A+=09=09=09case=209:=0A+=09=09=09=09= checkopts.rootdescend=20=3D=20true;=0A+=09=09=09=09= checkopts.parent_check=20=3D=20true;=0A+=09=09=09=09break;=0A+=09=09=09= case=2010:=0A+=09=09=09=09checkopts.dependents=20=3D=20false;=0A+=09=09=09= =09break;=0A+=09=09=09default:=0A+=09=09=09=09fprintf(stderr,=0A+=09=09=09= =09=09=09_("Try=20\"%s=20--help\"=20for=20more=20information.\n"),=0A+=09= =09=09=09=09=09progname);=0A+=09=09=09=09exit(1);=0A+=09=09}=0A+=09}=0A+=0A= +=09if=20(checkopts.endblock=20>=3D=200=20&&=20checkopts.endblock=20<=20= checkopts.startblock)=0A+=09{=0A+=09=09pg_log_error("relation=20ending=20= block=20argument=20precedes=20starting=20block=20argument");=0A+=09=09= exit(1);=0A+=09}=0A+=0A+=09/*=20non-option=20arguments=20specify=20= database=20names=20*/=0A+=09while=20(optind=20<=20argc)=0A+=09{=0A+=09=09= if=20(connect_db=20=3D=3D=20NULL)=0A+=09=09=09connect_db=20=3D=20= argv[optind];=0A+=09=09simple_string_list_append(&objects.databases,=20= argv[optind]);=0A+=09=09optind++;=0A+=09}=0A+=0A+=09/*=20fill=20cparams=20= except=20for=20dbname,=20which=20is=20set=20below=20*/=0A+=09= cparams.pghost=20=3D=20host;=0A+=09cparams.pgport=20=3D=20port;=0A+=09= cparams.pguser=20=3D=20username;=0A+=09cparams.prompt_password=20=3D=20= prompt_password;=0A+=09cparams.override_dbname=20=3D=20NULL;=0A+=0A+=09= setup_cancel_handler(NULL);=0A+=0A+=09/*=20choose=20the=20database=20for=20= our=20initial=20connection=20*/=0A+=09if=20(maintenance_db)=0A+=09=09= cparams.dbname=20=3D=20maintenance_db;=0A+=09else=20if=20(connect_db=20= !=3D=20NULL)=0A+=09=09cparams.dbname=20=3D=20connect_db;=0A+=09else=20if=20= (objects.databases.head=20!=3D=20NULL)=0A+=09=09cparams.dbname=20=3D=20= objects.databases.head->val;=0A+=09else=0A+=09{=0A+=09=09const=20char=20= *default_db;=0A+=0A+=09=09if=20(getenv("PGDATABASE"))=0A+=09=09=09= default_db=20=3D=20getenv("PGDATABASE");=0A+=09=09else=20if=20= (getenv("PGUSER"))=0A+=09=09=09default_db=20=3D=20getenv("PGUSER");=0A+=09= =09else=0A+=09=09=09default_db=20=3D=20get_user_name_or_exit(progname);=0A= +=0A+=09=09if=20(objects.databases.head=20=3D=3D=20NULL)=0A+=09=09=09= simple_string_list_append(&objects.databases,=20default_db);=0A+=0A+=09=09= cparams.dbname=20=3D=20default_db;=0A+=09}=0A+=0A+=09= check_each_database(&cparams,=20&objects,=20&checkopts,=20progname);=0A+=0A= +=09exit(0);=0A+}=0A+=0A+/*=0A+=20*=20check_each_database=0A+=20*=0A+=20= *=20Connects=20to=20the=20initial=20database=20and=20resolves=20a=20list=20= of=20all=20databases=20that=0A+=20*=20should=20be=20checked=20per=20the=20= user=20supplied=20options.=20=20Sequentially=20checks=20each=0A+=20*=20= database=20in=20the=20list.=0A+=20*=0A+=20*=20The=20user=20supplied=20= options=20may=20include=20zero=20databases,=20or=20only=20one=20= database,=0A+=20*=20in=20which=20case=20we=20could=20skip=20the=20step=20= of=20resolving=20a=20list=20of=20databases,=20but=0A+=20*=20it=20seems=20= not=20worth=20optimizing,=20especially=20considering=20that=20there=20= are=0A+=20*=20multiple=20ways=20in=20which=20no=20databases=20or=20just=20= one=20database=20might=20be=20specified,=0A+=20*=20including=20a=20= pattern=20that=20happens=20to=20match=20no=20entries=20or=20to=20match=20= only=20one=0A+=20*=20entry=20in=20pg_database.=0A+=20*=0A+=20*=20= cparams:=20parameters=20for=20the=20initial=20database=20connection=0A+=20= *=20objects:=20lists=20of=20include=20and=20exclude=20patterns=20for=20= filtering=20objects=0A+=20*=20checkopts:=20user=20supplied=20program=20= options=0A+=20*=20progname:=20name=20of=20this=20program,=20such=20as=20= "pg_amcheck"=0A+=20*/=0A+static=20void=0A+check_each_database(ConnParams=20= *cparams,=20const=20amcheckObjects=20*objects,=0A+=09=09=09=09=09const=20= amcheckOptions=20*checkopts,=20const=20char=20*progname)=0A+{=0A+=09= PGconn=09=20=20=20*conn;=0A+=09PGresult=20=20=20*databases;=0A+=09= PQExpBufferData=20sql;=0A+=09int=09=09=09ntups;=0A+=09int=09=09=09i;=0A+=09= SimpleStringList=20dbregex=20=3D=20{NULL,=20NULL};=0A+=09= SimpleStringList=20exclude=20=3D=20{NULL,=20NULL};=0A+=0A+=09/*=0A+=09=20= *=20Get=20a=20list=20of=20all=20database=20SQL=20regexes=20to=20use=20= for=20selecting=20database=0A+=09=20*=20names.=20=20We=20assemble=20= these=20regexes=20from=20fully-qualified=20relation=0A+=09=20*=20= patterns=20and=20database=20patterns.=20=20This=20process=20may=20result=20= in=20the=20same=0A+=09=20*=20database=20regex=20in=20the=20list=20= multiple=20times,=20but=20the=20query=20against=0A+=09=20*=20pg_database=20= will=20deduplice,=20so=20we=20don't=20care.=0A+=09=20*/=0A+=09= get_db_regexes_from_fqrps(&dbregex,=20&objects->tables);=0A+=09= get_db_regexes_from_fqrps(&dbregex,=20&objects->indexes);=0A+=09= get_db_regexes_from_patterns(&dbregex,=20&objects->databases);=0A+=0A+=09= /*=0A+=09=20*=20Assemble=20SQL=20regexes=20for=20databases=20to=20be=20= excluded.=20=20Note=20that=20excluded=0A+=09=20*=20relations=20are=20not=20= considered=20here,=20as=20excluding=20relation=20x.y.z=20does=20not=0A+=09= =20*=20imply=20excluding=20database=20x.=20=20Excluding=20x.*.*=20would=20= imply=20excluding=0A+=09=20*=20database=20x,=20but=20we=20do=20not=20= check=20for=20that=20here.=0A+=09=20*/=0A+=09= get_db_regexes_from_patterns(&exclude,=20&objects->exclude_databases);=0A= +=0A+=09conn=20=3D=20connectMaintenanceDatabase(cparams,=20progname,=20= checkopts->echo);=0A+=0A+=09initPQExpBuffer(&sql);=0A+=09= dbname_select(conn,=20&sql,=20&dbregex,=20checkopts->alldb);=0A+=09= appendPQExpBufferStr(&sql,=20"\nEXCEPT");=0A+=09dbname_select(conn,=20= &sql,=20&exclude,=20false);=0A+=09executeCommand(conn,=20"RESET=20= search_path;",=20checkopts->echo);=0A+=09databases=20=3D=20= executeQuery(conn,=20sql.data,=20checkopts->echo);=0A+=09if=20= (PQresultStatus(databases)=20!=3D=20PGRES_TUPLES_OK)=0A+=09{=0A+=09=09= pg_log_error("query=20failed:=20%s",=20PQerrorMessage(conn));=0A+=09=09= pg_log_error("query=20was:=20%s",=20sql.data);=0A+=09=09PQfinish(conn);=0A= +=09=09exit(1);=0A+=09}=0A+=0A+=09termPQExpBuffer(&sql);=0A+=09= PQclear(executeQuery(conn,=20ALWAYS_SECURE_SEARCH_PATH_SQL,=20= checkopts->echo));=0A+=09PQfinish(conn);=0A+=0A+=09ntups=20=3D=20= PQntuples(databases);=0A+=09if=20(ntups=20=3D=3D=200=20&&=20= !checkopts->quiet)=0A+=09=09printf(_("%s:=20no=20databases=20to=20= check\n"),=20progname);=0A+=0A+=09for=20(i=20=3D=200;=20i=20<=20ntups;=20= i++)=0A+=09{=0A+=09=09cparams->override_dbname=20=3D=20= PQgetvalue(databases,=20i,=200);=0A+=09=09check_one_database(cparams,=20= objects,=20checkopts,=20progname);=0A+=09}=0A+=0A+=09PQclear(databases);=0A= +}=0A+=0A+/*=0A+=20*=20string_in_list=0A+=20*=0A+=20*=20Returns=20= whether=20a=20given=20string=20is=20in=20the=20list=20of=20strings.=0A+=20= */=0A+static=20bool=0A+string_in_list(const=20SimpleStringList=20*list,=20= const=20char=20*str)=0A+{=0A+=09const=20SimpleStringListCell=20*cell;=0A= +=0A+=09for=20(cell=20=3D=20list->head;=20cell;=20cell=20=3D=20= cell->next)=0A+=09=09if=20(strcmp(cell->val,=20str)=20=3D=3D=200)=0A+=09=09= =09return=20true;=0A+=09return=20false;=0A+}=0A+=0A+/*=0A+=20*=20= check_one_database=0A+=20*=0A+=20*=20Connects=20to=20this=20next=20= database=20and=20checks=20all=20relations=20that=20match=20the=0A+=20*=20= supplied=20objects=20list.=20=20Patterns=20in=20the=20object=20lists=20= are=20matched=20to=20the=0A+=20*=20relations=20that=20exit=20in=20this=20= next=20database.=0A+=20*=0A+=20*=20cparams:=20parameters=20for=20this=20= next=20database=20connection=0A+=20*=20objects:=20lists=20of=20include=20= and=20exclude=20patterns=20for=20filtering=20objects=0A+=20*=20= checkopts:=20user=20supplied=20program=20options=0A+=20*=20progname:=20= name=20of=20this=20program,=20such=20as=20"pg_amcheck"=0A+=20*/=0A= +static=20void=0A+check_one_database(const=20ConnParams=20*cparams,=20= const=20amcheckObjects=20*objects,=0A+=09=09=09=09=20=20=20const=20= amcheckOptions=20*checkopts,=20const=20char=20*progname)=0A+{=0A+=09= PQExpBufferData=20sql;=0A+=09PGconn=09=20=20=20*conn;=0A+=09PGresult=20=20= =20*result;=0A+=09ParallelSlot=20*slots;=0A+=09int=09=09=09ntups;=0A+=09= int=09=09=09i;=0A+=09int=09=09=09parallel_workers;=0A+=09bool=09=09= inclusive;=0A+=09bool=09=09failed=20=3D=20false;=0A+=09char=09=20=20=20= *amcheck_schema=20=3D=20NULL;=0A+=0A+=09conn=20=3D=20= connectDatabase(cparams,=20progname,=20checkopts->echo,=20false,=20= true);=0A+=0A+=09if=20(!checkopts->quiet)=0A+=09{=0A+=09=09printf(_("%s:=20= checking=20database=20\"%s\"\n"),=0A+=09=09=09=20=20=20progname,=20= PQdb(conn));=0A+=09=09fflush(stdout);=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= Verify=20that=20amcheck=20is=20installed=20for=20this=20next=20database.=20= =20User=20error=0A+=09=20*=20could=20result=20in=20a=20database=20not=20= having=20amcheck=20that=20should=20have=20it,=20but=0A+=09=20*=20we=20= also=20could=20be=20iterating=20over=20multiple=20databases=20where=20= not=20all=20of=0A+=09=20*=20them=20have=20amcheck=20installed=20(for=20= example,=20'template1').=0A+=09=20*/=0A+=09result=20=3D=20= executeQuery(conn,=20amcheck_sql,=20checkopts->echo);=0A+=09if=20= (PQresultStatus(result)=20!=3D=20PGRES_TUPLES_OK)=0A+=09{=0A+=09=09/*=20= Querying=20the=20catalog=20failed.=20*/=0A+=09=09pg_log_error(_("%s:=20= database=20\"%s\":=20%s\n"),=0A+=09=09=09=09=09=20progname,=20= PQdb(conn),=20PQerrorMessage(conn));=0A+=09=09pg_log_error(_("%s:=20= query=20was:=20%s"),=20progname,=20amcheck_sql);=0A+=09=09= PQclear(result);=0A+=09=09PQfinish(conn);=0A+=09=09return;=0A+=09}=0A+=09= ntups=20=3D=20PQntuples(result);=0A+=09if=20(ntups=20=3D=3D=200)=0A+=09{=0A= +=09=09/*=20Querying=20the=20catalog=20succeeded,=20but=20amcheck=20is=20= missing.=20*/=0A+=09=09if=20(!checkopts->quiet=20&&=0A+=09=09=09= (checkopts->verbose=20||=0A+=09=09=09=20= string_in_list(&objects->databases,=20PQdb(conn))))=0A+=09=09{=0A+=09=09=09= printf(_("%s:=20skipping=20database=20\"%s\":=20amcheck=20is=20not=20= installed"),=0A+=09=09=09=09=20=20=20progname,=20PQdb(conn));=0A+=09=09}=0A= +=09=09PQfinish(conn);=0A+=09=09return;=0A+=09}=0A+=09amcheck_schema=20=3D= =20PQgetvalue(result,=200,=200);=0A+=09if=20(checkopts->verbose)=0A+=09=09= printf(_("%s:=20in=20database=20\"%s\":=20using=20amcheck=20version=20= \"%s\"=20in=20schema=20\"%s\""),=0A+=09=09=09=20=20=20progname,=20= PQdb(conn),=20PQgetvalue(result,=200,=201),=20amcheck_schema);=0A+=09= amcheck_schema=20=3D=20PQescapeIdentifier(conn,=20amcheck_schema,=20= strlen(amcheck_schema));=0A+=09PQclear(result);=0A+=0A+=09/*=0A+=09=20*=20= If=20we=20were=20given=20no=20tables=20nor=20indexes=20to=20check,=20= then=20we=20select=20all=0A+=09=20*=20targets=20not=20excluded.=20=20= Otherwise,=20we=20select=20only=20the=20targets=20that=20we=0A+=09=20*=20= were=20given.=0A+=09=20*/=0A+=09inclusive=20=3D=20objects->tables.head=20= =3D=3D=20NULL=20&&=0A+=09=09objects->indexes.head=20=3D=3D=20NULL;=0A+=0A= +=09initPQExpBuffer(&sql);=0A+=09target_select(conn,=20&sql,=20objects,=20= checkopts,=20progname,=20inclusive);=0A+=09executeCommand(conn,=20"RESET=20= search_path;",=20checkopts->echo);=0A+=09result=20=3D=20= executeQuery(conn,=20sql.data,=20checkopts->echo);=0A+=09if=20= (PQresultStatus(result)=20!=3D=20PGRES_TUPLES_OK)=0A+=09{=0A+=09=09= pg_log_error("query=20failed:=20%s",=20PQerrorMessage(conn));=0A+=09=09= pg_log_error("query=20was:=20%s",=20sql.data);=0A+=09=09PQfinish(conn);=0A= +=09=09exit(1);=0A+=09}=0A+=09termPQExpBuffer(&sql);=0A+=09= PQclear(executeQuery(conn,=20ALWAYS_SECURE_SEARCH_PATH_SQL,=20= checkopts->echo));=0A+=0A+=09/*=0A+=09=20*=20If=20no=20rows=20are=20= returned,=20there=20are=20no=20matching=20relations,=20so=20we=20are=0A+=09= =20*=20done.=0A+=09=20*/=0A+=09ntups=20=3D=20PQntuples(result);=0A+=09if=20= (ntups=20=3D=3D=200)=0A+=09{=0A+=09=09PQclear(result);=0A+=09=09= PQfinish(conn);=0A+=09=09PQfreemem(amcheck_schema);=0A+=09=09return;=0A+=09= }=0A+=0A+=09/*=0A+=09=20*=20Ensure=20parallel_workers=20is=20sane.=20=20= If=20there=20are=20more=20connections=20than=0A+=09=20*=20relations=20to=20= be=20checked,=20we=20don't=20need=20to=20use=20them=20all.=0A+=09=20*/=0A= +=09parallel_workers=20=3D=20checkopts->jobs;=0A+=09if=20= (parallel_workers=20>=20ntups)=0A+=09=09parallel_workers=20=3D=20ntups;=0A= +=09if=20(parallel_workers=20<=3D=200)=0A+=09=09parallel_workers=20=3D=20= 1;=0A+=0A+=09/*=0A+=09=20*=20Setup=20the=20database=20connections.=20=20= We=20reuse=20the=20connection=20we=20already=0A+=09=20*=20have=20for=20= the=20first=20slot.=20=20If=20not=20in=20parallel=20mode,=20the=20first=20= slot=20in=0A+=09=20*=20the=20array=20contains=20the=20connection.=0A+=09=20= */=0A+=09slots=20=3D=20ParallelSlotsSetup(cparams,=20progname,=20= checkopts->echo,=20conn,=0A+=09=09=09=09=09=09=09=20=20=20= parallel_workers);=0A+=0A+=09initPQExpBuffer(&sql);=0A+=0A+=09/*=0A+=09=20= *=20Loop=20over=20all=20objects=20to=20be=20checked,=20and=20execute=20= amcheck=20checking=0A+=09=20*=20commands=20for=20each.=20=20We=20do=20= not=20wait=20for=20the=20checks=20to=20complete,=20nor=20do=0A+=09=20*=20= we=20handle=20the=20results=20of=20those=20checks=20in=20the=20loop.=20=20= We=20register=0A+=09=20*=20handlers=20for=20doing=20all=20that.=0A+=09=20= */=0A+=09for=20(i=20=3D=200;=20i=20<=20ntups;=20i++)=0A+=09{=0A+=09=09= ParallelSlot=20*free_slot;=0A+=0A+=09=09CheckType=09checktype=20=3D=20= atoi(PQgetvalue(result,=20i,=200));=0A+=09=09Oid=09=09=09reloid=20=3D=20= atooid(PQgetvalue(result,=20i,=201));=0A+=0A+=09=09if=20= (CancelRequested)=0A+=09=09{=0A+=09=09=09failed=20=3D=20true;=0A+=09=09=09= goto=20finish;=0A+=09=09}=0A+=0A+=09=09/*=0A+=09=09=20*=20Get=20a=20= parallel=20slot=20for=20the=20next=20amcheck=20command,=20blocking=20if=0A= +=09=09=20*=20necessary=20until=20one=20is=20available,=20or=20until=20a=20= previously=20issued=20slot=0A+=09=09=20*=20command=20fails,=20indicating=20= that=20we=20should=20abort=20checking=20the=0A+=09=09=20*=20remaining=20= objects.=0A+=09=09=20*/=0A+=09=09free_slot=20=3D=20= ParallelSlotsGetIdle(slots,=20parallel_workers);=0A+=09=09if=20= (!free_slot)=0A+=09=09{=0A+=09=09=09/*=0A+=09=09=09=20*=20Something=20= failed.=20=20We=20don't=20need=20to=20know=20what=20it=20was,=20because=0A= +=09=09=09=20*=20the=20handler=20should=20already=20have=20emitted=20the=20= necessary=20error=0A+=09=09=09=20*=20messages.=0A+=09=09=09=20*/=0A+=09=09= =09failed=20=3D=20true;=0A+=09=09=09goto=20finish;=0A+=09=09}=0A+=0A+=09=09= /*=20Execute=20the=20amcheck=20command=20for=20the=20given=20relation=20= type.=20*/=0A+=09=09switch=20(checktype)=0A+=09=09{=0A+=09=09=09=09/*=20= heapam=20types=20*/=0A+=09=09=09case=20CT_TABLE:=0A+=09=09=09=09= prepare_table_command(&sql,=20checkopts,=20reloid,=20amcheck_schema);=0A= +=09=09=09=09ParallelSlotSetHandler(free_slot,=20= VerifyHeapamSlotHandler,=20sql.data);=0A+=09=09=09=09= run_command(free_slot->connection,=20sql.data,=20checkopts,=20reloid,=0A= +=09=09=09=09=09=09=09ctfilter[checktype].typname);=0A+=09=09=09=09= break;=0A+=0A+=09=09=09=09/*=20btreeam=20types=20*/=0A+=09=09=09case=20= CT_BTREE:=0A+=09=09=09=09prepare_btree_command(&sql,=20checkopts,=20= reloid,=20amcheck_schema);=0A+=09=09=09=09= ParallelSlotSetHandler(free_slot,=20VerifyBtreeSlotHandler,=20NULL);=0A+=09= =09=09=09run_command(free_slot->connection,=20sql.data,=20checkopts,=20= reloid,=0A+=09=09=09=09=09=09=09ctfilter[checktype].typname);=0A+=09=09=09= =09break;=0A+=0A+=09=09=09=09/*=20intentionally=20no=20default=20here=20= */=0A+=09=09}=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Wait=20for=20all=20slots=20= to=20complete,=20or=20for=20one=20to=20indicate=20that=20an=20error=0A+=09= =20*=20occurred.=20=20Like=20above,=20we=20rely=20on=20the=20handler=20= emitting=20the=20necessary=0A+=09=20*=20error=20messages.=0A+=09=20*/=0A= +=09if=20(!ParallelSlotsWaitCompletion(slots,=20parallel_workers))=0A+=09= =09failed=20=3D=20true;=0A+=0A+finish:=0A+=09= ParallelSlotsTerminate(slots,=20parallel_workers);=0A+=09pg_free(slots);=0A= +=0A+=09termPQExpBuffer(&sql);=0A+=0A+=09if=20(amcheck_schema=20!=3D=20= NULL)=0A+=09=09PQfreemem(amcheck_schema);=0A+=0A+=09if=20(failed)=0A+=09=09= exit(1);=0A+}=0A+=0A+/*=0A+=20*=20prepare_table_command=0A+=20*=0A+=20*=20= Creates=20a=20SQL=20command=20for=20running=20amcheck=20checking=20on=20= the=20given=20heap=0A+=20*=20relation.=20=20The=20command=20is=20phrased=20= as=20a=20SQL=20query,=20with=20column=20order=20and=0A+=20*=20names=20= matching=20the=20expectations=20of=20VerifyHeapamSlotHandler,=20which=20= will=0A+=20*=20receive=20and=20handle=20each=20row=20returned=20from=20= the=20verify_heapam()=20function.=0A+=20*=0A+=20*=20sql:=20buffer=20into=20= which=20the=20table=20checking=20command=20will=20be=20written=0A+=20*=20= checkopts:=20user=20supplied=20program=20options=0A+=20*=20reloid:=20= relation=20of=20the=20table=20to=20be=20checked=0A+=20*/=0A+static=20= void=0A+prepare_table_command(PQExpBuffer=20sql,=20const=20= amcheckOptions=20*checkopts,=0A+=09=09=09=09=09=20=20Oid=20reloid,=20= const=20char=20*amcheck_schema)=0A+{=0A+=09resetPQExpBuffer(sql);=0A+=09= appendPQExpBuffer(sql,=0A+=09=09=09=09=09=20=20"SELECT=20n.nspname,=20= c.relname,=20v.blkno,=20v.offnum,=20v.attnum,=20v.msg"=0A+=09=09=09=09=09= =20=20"\nFROM=20%s.verify_heapam("=0A+=09=09=09=09=09=20=20"\nrelation=20= :=3D=20%u,"=0A+=09=09=09=09=09=20=20"\non_error_stop=20:=3D=20%s,"=0A+=09= =09=09=09=09=20=20"\ncheck_toast=20:=3D=20%s,"=0A+=09=09=09=09=09=20=20= "\nskip=20:=3D=20'%s'",=0A+=09=09=09=09=09=20=20amcheck_schema,=0A+=09=09= =09=09=09=20=20reloid,=0A+=09=09=09=09=09=20=20checkopts->on_error_stop=20= ?=20"true"=20:=20"false",=0A+=09=09=09=09=09=20=20= checkopts->reconcile_toast=20?=20"true"=20:=20"false",=0A+=09=09=09=09=09= =20=20checkopts->skip);=0A+=09if=20(checkopts->startblock=20>=3D=200)=0A= +=09=09appendPQExpBuffer(sql,=20",\nstartblock=20:=3D=20%ld",=20= checkopts->startblock);=0A+=09if=20(checkopts->endblock=20>=3D=200)=0A+=09= =09appendPQExpBuffer(sql,=20",\nendblock=20:=3D=20%ld",=20= checkopts->endblock);=0A+=09appendPQExpBuffer(sql,=20"\n)=20v,"=0A+=09=09= =09=09=09=20=20"\npg_catalog.pg_class=20c"=0A+=09=09=09=09=09=20=20= "\nJOIN=20pg_catalog.pg_namespace=20n"=0A+=09=09=09=09=09=20=20"\nON=20= c.relnamespace=20OPERATOR(pg_catalog.=3D)=20n.oid"=0A+=09=09=09=09=09=20=20= "\nWHERE=20c.oid=20OPERATOR(pg_catalog.=3D)=20%u",=0A+=09=09=09=09=09=20=20= reloid);=0A+}=0A+=0A+/*=0A+=20*=20prepare_btree_command=0A+=20*=0A+=20*=20= Creates=20a=20SQL=20command=20for=20running=20amcheck=20checking=20on=20= the=20given=20btree=20index=0A+=20*=20relation.=20=20The=20command=20= does=20not=20select=20any=20columns,=20as=20btree=20checking=0A+=20*=20= functions=20do=20not=20return=20any,=20but=20rather=20return=20= corruption=20information=20by=0A+=20*=20raising=20errors,=20which=20= VerifyBtreeSlotHandler=20expects.=0A+=20*=0A+=20*=20sql:=20buffer=20into=20= which=20the=20table=20checking=20command=20will=20be=20written=0A+=20*=20= checkopts:=20user=20supplied=20program=20options=0A+=20*=20reloid:=20= relation=20of=20the=20table=20to=20be=20checked=0A+=20*/=0A+static=20= void=0A+prepare_btree_command(PQExpBuffer=20sql,=20const=20= amcheckOptions=20*checkopts,=0A+=09=09=09=09=09=20=20Oid=20reloid,=20= const=20char=20*amcheck_schema)=0A+{=0A+=09resetPQExpBuffer(sql);=0A+=09= if=20(checkopts->parent_check)=0A+=09=09appendPQExpBuffer(sql,=0A+=09=09=09= =09=09=09=20=20"SELECT=20%s.bt_index_parent_check("=0A+=09=09=09=09=09=09= =20=20"\nindex=20:=3D=20'%u'::regclass,"=0A+=09=09=09=09=09=09=20=20= "\nheapallindexed=20:=3D=20%s,"=0A+=09=09=09=09=09=09=20=20= "\nrootdescend=20:=3D=20%s)",=0A+=09=09=09=09=09=09=20=20amcheck_schema,=0A= +=09=09=09=09=09=09=20=20reloid,=0A+=09=09=09=09=09=09=20=20= (checkopts->heapallindexed=20?=20"true"=20:=20"false"),=0A+=09=09=09=09=09= =09=20=20(checkopts->rootdescend=20?=20"true"=20:=20"false"));=0A+=09= else=0A+=09=09appendPQExpBuffer(sql,=0A+=09=09=09=09=09=09=20=20"SELECT=20= %s.bt_index_check("=0A+=09=09=09=09=09=09=20=20"\nindex=20:=3D=20= '%u'::regclass,"=0A+=09=09=09=09=09=09=20=20"\nheapallindexed=20:=3D=20= %s)",=0A+=09=09=09=09=09=09=20=20amcheck_schema,=0A+=09=09=09=09=09=09=20= =20reloid,=0A+=09=09=09=09=09=09=20=20(checkopts->heapallindexed=20?=20= "true"=20:=20"false"));=0A+}=0A+=0A+/*=0A+=20*=20run_command=0A+=20*=0A+=20= *=20Sends=20a=20command=20to=20the=20server=20without=20waiting=20for=20= the=20command=20to=20complete.=0A+=20*=20Logs=20an=20error=20if=20the=20= command=20cannot=20be=20sent,=20but=20otherwise=20any=20errors=20are=0A+=20= *=20expected=20to=20be=20handled=20by=20a=20ParallelSlotHandler.=0A+=20*=0A= +=20*=20conn:=20connection=20to=20the=20server=20associated=20with=20the=20= slot=20to=20use=0A+=20*=20sql:=20query=20to=20send=0A+=20*=20checkopts:=20= user=20supplied=20program=20options=0A+=20*=20reloid:=20oid=20of=20the=20= object=20being=20checked,=20for=20error=20reporting=0A+=20*=20typ:=20= type=20of=20object=20being=20checked,=20for=20error=20reporting=0A+=20*/=0A= +static=20void=0A+run_command(PGconn=20*conn,=20const=20char=20*sql,=20= const=20amcheckOptions=20*checkopts,=0A+=09=09=09Oid=20reloid,=20const=20= char=20*typ)=0A+{=0A+=09bool=09=09status;=0A+=0A+=09if=20= (checkopts->echo)=0A+=09=09printf("%s\n",=20sql);=0A+=0A+=09status=20=3D=20= PQsendQuery(conn,=20sql)=20=3D=3D=201;=0A+=0A+=09if=20(!status)=0A+=09{=0A= +=09=09pg_log_error("check=20of=20%s=20with=20id=20%u=20in=20database=20= \"%s\"=20failed:=20%s",=0A+=09=09=09=09=09=20typ,=20reloid,=20= PQdb(conn),=20PQerrorMessage(conn));=0A+=09=09pg_log_error("command=20= was:=20%s",=20sql);=0A+=09}=0A+}=0A+=0A+/*=0A+=20*=20= VerifyHeapamSlotHandler=0A+=20*=0A+=20*=20ParallelSlotHandler=20that=20= receives=20results=20from=20a=20table=20checking=20command=0A+=20*=20= created=20by=20prepare_table_command=20and=20outputs=20the=20results=20= for=20the=20user.=0A+=20*=0A+=20*=20res:=20result=20from=20an=20executed=20= sql=20query=0A+=20*=20conn:=20connection=20on=20which=20the=20sql=20= query=20was=20executed=0A+=20*=20context:=20the=20sql=20query=20being=20= handled,=20as=20a=20cstring=0A+=20*/=0A+static=20PGresult=20*=0A= +VerifyHeapamSlotHandler(PGresult=20*res,=20PGconn=20*conn,=20void=20= *context)=0A+{=0A+=09int=09=09=09ntups=20=3D=20PQntuples(res);=0A+=0A+=09= if=20(PQresultStatus(res)=20=3D=3D=20PGRES_TUPLES_OK)=0A+=09{=0A+=09=09= int=09=09=09i;=0A+=0A+=09=09for=20(i=20=3D=200;=20i=20<=20ntups;=20i++)=0A= +=09=09{=0A+=09=09=09if=20(!PQgetisnull(res,=20i,=204))=0A+=09=09=09=09= printf("relation=20%s.%s.%s,=20block=20%s,=20offset=20%s,=20attribute=20= %s\n=20=20=20=20%s\n",=0A+=09=09=09=09=09=20=20=20PQdb(conn),=0A+=09=09=09= =09=09=20=20=20PQgetvalue(res,=20i,=200),=09/*=20schema=20*/=0A+=09=09=09= =09=09=20=20=20PQgetvalue(res,=20i,=201),=09/*=20relname=20*/=0A+=09=09=09= =09=09=20=20=20PQgetvalue(res,=20i,=202),=09/*=20blkno=20*/=0A+=09=09=09=09= =09=20=20=20PQgetvalue(res,=20i,=203),=09/*=20offnum=20*/=0A+=09=09=09=09= =09=20=20=20PQgetvalue(res,=20i,=204),=09/*=20attnum=20*/=0A+=09=09=09=09= =09=20=20=20PQgetvalue(res,=20i,=205));=09/*=20msg=20*/=0A+=0A+=09=09=09= else=20if=20(!PQgetisnull(res,=20i,=203))=0A+=09=09=09=09= printf("relation=20%s.%s.%s,=20block=20%s,=20offset=20%s\n=20=20=20=20= %s\n",=0A+=09=09=09=09=09=20=20=20PQdb(conn),=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=200),=09/*=20schema=20*/=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=201),=09/*=20relname=20*/=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=202),=09/*=20blkno=20*/=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=203),=09/*=20offnum=20*/=0A+=09=09=09=09/*=20attnum=20= is=20null:=204=20*/=0A+=09=09=09=09=09=20=20=20PQgetvalue(res,=20i,=20= 5));=09/*=20msg=20*/=0A+=0A+=09=09=09else=20if=20(!PQgetisnull(res,=20i,=20= 2))=0A+=09=09=09=09printf("relation=20%s.%s.%s,=20block=20%s\n=20=20=20=20= %s\n",=0A+=09=09=09=09=09=20=20=20PQdb(conn),=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=200),=09/*=20schema=20*/=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=201),=09/*=20relname=20*/=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=202),=09/*=20blkno=20*/=0A+=09=09=09=09/*=20offnum=20= is=20null:=203=20*/=0A+=09=09=09=09/*=20attnum=20is=20null:=204=20*/=0A+=09= =09=09=09=09=20=20=20PQgetvalue(res,=20i,=205));=09/*=20msg=20*/=0A+=0A+=09= =09=09else=20if=20(!PQgetisnull(res,=20i,=201))=0A+=09=09=09=09= printf("relation=20%s.%s.%s\n=20=20=20=20%s\n",=0A+=09=09=09=09=09=20=20=20= PQdb(conn),=0A+=09=09=09=09=09=20=20=20PQgetvalue(res,=20i,=200),=09/*=20= schema=20*/=0A+=09=09=09=09=09=20=20=20PQgetvalue(res,=20i,=201),=09/*=20= relname=20*/=0A+=09=09=09=09/*=20blkno=20is=20null:=20=202=20*/=0A+=09=09= =09=09/*=20offnum=20is=20null:=203=20*/=0A+=09=09=09=09/*=20attnum=20is=20= null:=204=20*/=0A+=09=09=09=09=09=20=20=20PQgetvalue(res,=20i,=205));=09= /*=20msg=20*/=0A+=0A+=09=09=09else=0A+=09=09=09=09printf("%s.%s\n",=0A+=09= =09=09=09=09=20=20=20PQdb(conn),=0A+=09=09=09=09=09=20=20=20= PQgetvalue(res,=20i,=205));=09/*=20msg=20*/=0A+=09=09}=0A+=09}=0A+=09= else=20if=20(PQresultStatus(res)=20!=3D=20PGRES_TUPLES_OK)=0A+=09{=0A+=09= =09printf("%s:=20%s\n",=20PQdb(conn),=20PQerrorMessage(conn));=0A+=09=09= printf(_("query=20was:=20%s\n"),=20(const=20char=20*)=20context);=0A+=09= }=0A+=0A+=09return=20res;=0A+}=0A+=0A+/*=0A+=20*=20= VerifyBtreeSlotHandler=0A+=20*=0A+=20*=20ParallelSlotHandler=20that=20= receives=20results=20from=20a=20btree=20checking=20command=0A+=20*=20= created=20by=20prepare_btree_command=20and=20outputs=20them=20for=20the=20= user.=20=20The=20results=0A+=20*=20from=20the=20btree=20checking=20= command=20is=20assumed=20to=20be=20empty,=20but=20when=20the=20results=0A= +=20*=20are=20an=20error=20code,=20the=20useful=20information=20about=20= the=20corruption=20is=20expected=0A+=20*=20in=20the=20connection's=20= error=20message.=0A+=20*=0A+=20*=20res:=20result=20from=20an=20executed=20= sql=20query=0A+=20*=20conn:=20connection=20on=20which=20the=20sql=20= query=20was=20executed=0A+=20*=20context:=20unused=0A+=20*/=0A+static=20= PGresult=20*=0A+VerifyBtreeSlotHandler(PGresult=20*res,=20PGconn=20= *conn,=20void=20*context)=0A+{=0A+=09if=20(PQresultStatus(res)=20!=3D=20= PGRES_TUPLES_OK)=0A+=09=09printf("%s:=20%s\n",=20PQdb(conn),=20= PQerrorMessage(conn));=0A+=09return=20res;=0A+}=0A+=0A+/*=0A+=20*=20help=0A= +=20*=0A+=20*=20Prints=20help=20page=20for=20the=20program=0A+=20*=0A+=20= *=20progname:=20the=20name=20of=20the=20executed=20program,=20such=20as=20= "pg_amcheck"=0A+=20*/=0A+static=20void=0A+help(const=20char=20*progname)=0A= +{=0A+=09printf(_("%s=20checks=20objects=20in=20a=20PostgreSQL=20= database=20for=20corruption.\n\n"),=20progname);=0A+=09= printf(_("Usage:\n"));=0A+=09printf(_("=20=20%s=20[OPTION]...=20= [DBNAME]\n"),=20progname);=0A+=09printf(_("\nTarget=20Options:\n"));=0A+=09= printf(_("=20=20-a,=20--all=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20check=20all=20databases\n"));=0A+=09printf(_("=20=20-d,=20= --dbname=3DDBNAME=20=20=20=20=20=20=20check=20specific=20= database(s)\n"));=0A+=09printf(_("=20=20-D,=20--exclude-dbname=3DDBNAME=20= do=20NOT=20check=20specific=20database(s)\n"));=0A+=09printf(_("=20=20= -i,=20--index=3DINDEX=20=20=20=20=20=20=20=20=20check=20specific=20= index(es)\n"));=0A+=09printf(_("=20=20-I,=20--exclude-index=3DINDEX=20do=20= NOT=20check=20specific=20index(es)\n"));=0A+=09printf(_("=20=20-r,=20= --relation=3DRELNAME=20=20=20=20check=20specific=20relation(s)\n"));=0A+=09= printf(_("=20=20-R,=20--exclude-relation=3DRELNAME=20do=20NOT=20check=20= specific=20relation(s)\n"));=0A+=09printf(_("=20=20-s,=20--schema=3DSCHEMA= =20=20=20=20=20=20=20check=20specific=20schema(s)\n"));=0A+=09printf(_("=20= =20-S,=20--exclude-schema=3DSCHEMA=20do=20NOT=20check=20specific=20= schema(s)\n"));=0A+=09printf(_("=20=20-t,=20--table=3DTABLE=20=20=20=20=20= =20=20=20=20check=20specific=20table(s)\n"));=0A+=09printf(_("=20=20-T,=20= --exclude-table=3DTABLE=20do=20NOT=20check=20specific=20table(s)\n"));=0A= +=09printf(_("=20=20=20=20=20=20--exclude-indexes=20=20=20=20=20do=20NOT=20= perform=20any=20index=20checking\n"));=0A+=09printf(_("=20=20=20=20=20=20= --exclude-toast=20=20=20=20=20=20=20do=20NOT=20check=20any=20toast=20= tables=20or=20indexes\n"));=0A+=09printf(_("=20=20=20=20=20=20= --no-dependents=20=20=20=20=20=20=20do=20NOT=20automatically=20check=20= dependent=20objects\n"));=0A+=09printf(_("\nIndex=20Checking=20= Options:\n"));=0A+=09printf(_("=20=20-H,=20--heapallindexed=20=20=20=20=20= =20check=20all=20heap=20tuples=20are=20found=20within=20indexes\n"));=0A= +=09printf(_("=20=20-P,=20--parent-check=20=20=20=20=20=20=20=20check=20= parent/child=20relationships=20during=20index=20checking\n"));=0A+=09= printf(_("=20=20=20=20=20=20--rootdescend=20=20=20=20=20=20=20=20=20= search=20from=20root=20page=20to=20refind=20tuples=20at=20the=20leaf=20= level\n"));=0A+=09printf(_("\nTable=20Checking=20Options:\n"));=0A+=09= printf(_("=20=20=20=20=20=20--exclude-toast-pointers=20do=20NOT=20check=20= relation=20toast=20pointers=20against=20toast\n"));=0A+=09printf(_("=20=20= =20=20=20=20--on-error-stop=20=20=20=20=20=20=20stop=20checking=20a=20= relation=20at=20end=20of=20first=20corrupt=20page\n"));=0A+=09printf(_("=20= =20=20=20=20=20--skip=3DOPTION=20=20=20=20=20=20=20=20=20do=20NOT=20= check=20\"all-frozen\"=20or=20\"all-visible\"=20blocks\n"));=0A+=09= printf(_("=20=20=20=20=20=20--startblock=20=20=20=20=20=20=20=20=20=20= begin=20checking=20table(s)=20at=20the=20given=20starting=20block=20= number\n"));=0A+=09printf(_("=20=20=20=20=20=20--endblock=20=20=20=20=20=20= =20=20=20=20=20=20check=20table(s)=20only=20up=20to=20the=20given=20= ending=20block=20number\n"));=0A+=09printf(_("\nConnection=20= options:\n"));=0A+=09printf(_("=20=20-h,=20--host=3DHOSTNAME=20=20=20=20=20= =20=20database=20server=20host=20or=20socket=20directory\n"));=0A+=09= printf(_("=20=20-p,=20--port=3DPORT=20=20=20=20=20=20=20=20=20=20=20= database=20server=20port\n"));=0A+=09printf(_("=20=20-U,=20= --username=3DUSERNAME=20=20=20user=20name=20to=20connect=20as\n"));=0A+=09= printf(_("=20=20-w,=20--no-password=20=20=20=20=20=20=20=20=20never=20= prompt=20for=20password\n"));=0A+=09printf(_("=20=20-W,=20--password=20=20= =20=20=20=20=20=20=20=20=20=20force=20password=20prompt\n"));=0A+=09= printf(_("=20=20--maintenance-db=3DDBNAME=20=20=20alternate=20= maintenance=20database\n"));=0A+=09printf(_("\nOther=20Options:\n"));=0A= +=09printf(_("=20=20-e,=20--echo=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20show=20the=20commands=20being=20sent=20to=20the=20server\n"));=0A+=09= printf(_("=20=20-j,=20--jobs=3DNUM=20=20=20=20=20=20=20=20=20=20=20=20= use=20this=20many=20concurrent=20connections=20to=20the=20server\n"));=0A= +=09printf(_("=20=20-q,=20--quiet=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20don't=20write=20any=20messages\n"));=0A+=09printf(_("=20=20-v,=20= --verbose=20=20=20=20=20=20=20=20=20=20=20=20=20write=20a=20lot=20of=20= output\n"));=0A+=09printf(_("=20=20-V,=20--version=20=20=20=20=20=20=20=20= =20=20=20=20=20output=20version=20information,=20then=20exit\n"));=0A+=09= printf(_("=20=20-?,=20--help=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20show=20this=20help,=20then=20exit\n"));=0A+=0A+=09printf(_("\nRead=20= the=20description=20of=20the=20amcheck=20contrib=20module=20for=20= details.\n"));=0A+=09printf(_("\nReport=20bugs=20to=20<%s>.\n"),=20= PACKAGE_BUGREPORT);=0A+=09printf(_("%s=20home=20page:=20<%s>\n"),=20= PACKAGE_NAME,=20PACKAGE_URL);=0A+}=0A+=0A+/*=0A+=20*=20= get_db_regexes_from_fqrps=0A+=20*=0A+=20*=20For=20each=20pattern=20in=20= the=20patterns=20list,=20if=20it=20is=20in=20fully-qualified=0A+=20*=20= database.schema.name=20format=20(fully-qualifed=20relation=20pattern=20= (fqrp)),=20parse=0A+=20*=20the=20database=20portion=20of=20the=20= pattern,=20convert=20it=20to=20SQL=20regex=20format,=20and=0A+=20*=20= append=20it=20to=20the=20databases=20list.=20=20Patterns=20that=20are=20= not=20fully-qualified=20are=0A+=20*=20skipped=20over.=20=20No=20= deduplication=20of=20regexes=20is=20performed.=0A+=20*=0A+=20*=20= regexes:=20list=20to=20which=20parsed=20and=20converted=20database=20= regexes=20are=20appended=0A+=20*=20patterns:=20list=20of=20all=20= patterns=20to=20parse=0A+=20*/=0A+static=20void=0A= +get_db_regexes_from_fqrps(SimpleStringList=20*regexes,=0A+=09=09=09=09=09= =09=20=20const=20SimpleStringList=20*patterns)=0A+{=0A+=09const=20= SimpleStringListCell=20*cell;=0A+=09PQExpBufferData=20dbnamebuf;=0A+=09= PQExpBufferData=20schemabuf;=0A+=09PQExpBufferData=20namebuf;=0A+=09int=09= =09=09encoding=20=3D=20pg_get_encoding_from_locale(NULL,=20false);=0A+=0A= +=09initPQExpBuffer(&dbnamebuf);=0A+=09initPQExpBuffer(&schemabuf);=0A+=09= initPQExpBuffer(&namebuf);=0A+=09for=20(cell=20=3D=20patterns->head;=20= cell;=20cell=20=3D=20cell->next)=0A+=09{=0A+=09=09/*=20parse=20the=20= pattern=20as=20dbname.schema.relname,=20if=20possible=20*/=0A+=09=09= patternToSQLRegex(encoding,=20&dbnamebuf,=20&schemabuf,=20&namebuf,=0A+=09= =09=09=09=09=09=20=20cell->val,=20false);=0A+=0A+=09=09/*=20add=20the=20= database=20name=20(or=20pattern),=20if=20any,=20to=20the=20list=20*/=0A+=09= =09if=20(dbnamebuf.data[0])=0A+=09=09=09= simple_string_list_append(regexes,=20dbnamebuf.data);=0A+=0A+=09=09/*=20= we=20do=20not=20use=20the=20schema=20or=20relname=20portions=20*/=0A+=0A= +=09=09/*=20we=20may=20have=20dirtied=20the=20buffers=20*/=0A+=09=09= resetPQExpBuffer(&dbnamebuf);=0A+=09=09resetPQExpBuffer(&schemabuf);=0A+=09= =09resetPQExpBuffer(&namebuf);=0A+=09}=0A+=09= termPQExpBuffer(&dbnamebuf);=0A+=09termPQExpBuffer(&schemabuf);=0A+=09= termPQExpBuffer(&namebuf);=0A+}=0A+=0A+/*=0A+=20*=20= get_db_regexes_from_patterns=0A+=20*=0A+=20*=20Convert=20each=20= unqualified=20pattern=20in=20the=20list=20to=20SQL=20regex=20format=20= and=20append=0A+=20*=20it=20to=20the=20regexes=20list.=0A+=20*=0A+=20*=20= regexes:=20list=20to=20which=20converted=20regexes=20are=20appended=0A+=20= *=20patterns:=20list=20of=20patterns=20to=20be=20converted=0A+=20*/=0A= +static=20void=0A+get_db_regexes_from_patterns(SimpleStringList=20= *regexes,=0A+=09=09=09=09=09=09=09=20const=20SimpleStringList=20= *patterns)=0A+{=0A+=09const=20SimpleStringListCell=20*cell;=0A+=09= PQExpBufferData=20buf;=0A+=09int=09=09=09encoding=20=3D=20= pg_get_encoding_from_locale(NULL,=20false);=0A+=0A+=09= initPQExpBuffer(&buf);=0A+=09for=20(cell=20=3D=20patterns->head;=20cell;=20= cell=20=3D=20cell->next)=0A+=09{=0A+=09=09patternToSQLRegex(encoding,=20= NULL,=20NULL,=20&buf,=20cell->val,=20false);=0A+=09=09if=20(buf.data[0])=0A= +=09=09=09simple_string_list_append(regexes,=20buf.data);=0A+=09=09= resetPQExpBuffer(&buf);=0A+=09}=0A+=09termPQExpBuffer(&buf);=0A+}=0A+=0A= +/*=0A+=20*=20dbname_select=0A+=20*=0A+=20*=20Appends=20a=20statement=20= which=20selects=20the=20names=20of=20all=20databases=20matching=20the=0A= +=20*=20given=20SQL=20regular=20expressions.=0A+=20*=0A+=20*=20conn:=20= connection=20to=20the=20initial=20database=0A+=20*=20sql:=20buffer=20= into=20which=20the=20constructed=20sql=20statement=20is=20appended=0A+=20= *=20regexes:=20list=20of=20database=20name=20regular=20expressions=20to=20= match=0A+=20*=20alldb:=20when=20true,=20select=20all=20databases=20which=20= allow=20connections=0A+=20*/=0A+static=20void=0A+dbname_select(PGconn=20= *conn,=20PQExpBuffer=20sql,=20const=20SimpleStringList=20*regexes,=0A+=09= =09=09=20=20bool=20alldb)=0A+{=0A+=09SimpleStringListCell=20*cell;=0A+=09= const=20char=20*comma;=0A+=0A+=09if=20(alldb)=0A+=09{=0A+=09=09= appendPQExpBufferStr(sql,=20"\nSELECT=20datname::TEXT=20AS=20datname"=0A= +=09=09=09=09=09=09=09=20"\nFROM=20pg_catalog.pg_database"=0A+=09=09=09=09= =09=09=09=20"\nWHERE=20datallowconn");=0A+=09=09return;=0A+=09}=0A+=09= else=20if=20(regexes->head=20=3D=3D=20NULL)=0A+=09{=0A+=09=09= appendPQExpBufferStr(sql,=20"\nSELECT=20''::TEXT=20AS=20datname"=0A+=09=09= =09=09=09=09=09=20"\nWHERE=20false");=0A+=09=09return;=0A+=09}=0A+=0A+=09= appendPQExpBufferStr(sql,=20"\nSELECT=20datname::TEXT=20AS=20datname"=0A= +=09=09=09=09=09=09=20"\nFROM=20pg_catalog.pg_database"=0A+=09=09=09=09=09= =09=20"\nWHERE=20datallowconn"=0A+=09=09=09=09=09=09=20"\nAND=20= datname::TEXT=20OPERATOR(pg_catalog.~)=20ANY(ARRAY[\n");=0A+=09for=20= (cell=20=3D=20regexes->head,=20comma=20=3D=20"";=20cell;=20cell=20=3D=20= cell->next,=20comma=20=3D=20",\n")=0A+=09{=0A+=09=09= appendPQExpBufferStr(sql,=20comma);=0A+=09=09= appendStringLiteralConn(sql,=20cell->val,=20conn);=0A+=09=09= appendPQExpBufferStr(sql,=20"::TEXT=20COLLATE=20pg_catalog.default");=0A= +=09}=0A+=09appendPQExpBufferStr(sql,=20"\n]::TEXT[])");=0A+}=0A+=0A+/*=0A= +=20*=20schema_select=0A+=20*=0A+=20*=20Appends=20a=20statement=20which=20= selects=20all=20schemas=20matching=20the=20given=20patterns=0A+=20*=0A+=20= *=20conn:=20connection=20to=20the=20current=20database=0A+=20*=20sql:=20= buffer=20into=20which=20the=20constructed=20sql=20statement=20is=20= appended=0A+=20*=20fieldname:=20alias=20to=20use=20for=20the=20oid=20= field=20within=20the=20created=20SELECT=0A+=20*=20statement=0A+=20*=20= patterns:=20list=20of=20schema=20name=20patterns=20to=20match=0A+=20*=20= inclusive:=20when=20patterns=20is=20an=20empty=20list,=20whether=20the=20= select=20statement=0A+=20*=20should=20match=20all=20non-system=20schemas=0A= +=20*/=0A+static=20void=0A+schema_select(PGconn=20*conn,=20PQExpBuffer=20= sql,=20const=20SimpleStringList=20*patterns,=0A+=09=09=09=20=20bool=20= inclusive)=0A+{=0A+=09SimpleStringListCell=20*cell;=0A+=09const=20char=20= *comma;=0A+=09int=09=09=09encoding=20=3D=20PQclientEncoding(conn);=0A+=0A= +=09if=20(patterns->head=20=3D=3D=20NULL)=0A+=09{=0A+=09=09if=20= (!inclusive)=0A+=09=09=09appendPQExpBufferStr(sql,=0A+=09=09=09=09=09=09=09= =09=20"\nSELECT=200::pg_catalog.oid=20AS=20nspoid=20WHERE=20false");=0A+=09= =09else=0A+=09=09=09appendPQExpBufferStr(sql,=0A+=09=09=09=09=09=09=09=09= =20"\nSELECT=20oid=20AS=20nspoid"=0A+=09=09=09=09=09=09=09=09=20"\nFROM=20= pg_catalog.pg_namespace"=0A+=09=09=09=09=09=09=09=09=20"\nWHERE=20oid=20= OPERATOR(pg_catalog.!=3D)=20pg_catalog.regnamespace('pg_catalog')"=0A+=09= =09=09=09=09=09=09=09=20"\nAND=20oid=20OPERATOR(pg_catalog.!=3D)=20= pg_catalog.regnamespace('pg_toast')");=0A+=09=09return;=0A+=09}=0A+=0A+=09= appendPQExpBufferStr(sql,=0A+=09=09=09=09=09=09=20"\nSELECT=20oid=20AS=20= nspoid"=0A+=09=09=09=09=09=09=20"\nFROM=20pg_catalog.pg_namespace"=0A+=09= =09=09=09=09=09=20"\nWHERE=20nspname=20OPERATOR(pg_catalog.~)=20= ANY(ARRAY[\n");=0A+=09for=20(cell=20=3D=20patterns->head,=20comma=20=3D=20= "";=20cell;=20cell=20=3D=20cell->next,=20comma=20=3D=20",\n")=0A+=09{=0A= +=09=09PQExpBufferData=20regexbuf;=0A+=0A+=09=09= initPQExpBuffer(®exbuf);=0A+=09=09patternToSQLRegex(encoding,=20NULL,=20= NULL,=20®exbuf,=20cell->val,=20false);=0A+=09=09= appendPQExpBufferStr(sql,=20comma);=0A+=09=09= appendStringLiteralConn(sql,=20regexbuf.data,=20conn);=0A+=09=09= appendPQExpBufferStr(sql,=20"::TEXT=20COLLATE=20pg_catalog.default");=0A= +=09=09termPQExpBuffer(®exbuf);=0A+=09}=0A+=09= appendPQExpBufferStr(sql,=20"\n]::TEXT[])");=0A+}=0A+=0A+/*=0A+=20*=20= schema_cte=0A+=20*=0A+=20*=20Appends=20a=20Common=20Table=20Expression=20= (CTE)=20which=20selects=20all=20schemas=20to=20be=0A+=20*=20checked,=20= with=20the=20CTE=20and=20oid=20field=20named=20as=20requested.=20=20The=20= CTE=20will=20select=0A+=20*=20all=20schemas=20matching=20the=20include=20= list=20except=20any=20schemas=20matching=20the=0A+=20*=20exclude=20list.=0A= +=20*=0A+=20*=20conn:=20connection=20to=20the=20current=20database=0A+=20= *=20sql:=20buffer=20into=20which=20the=20constructed=20sql=20statement=20= is=20appended=0A+=20*=20ctename:=20name=20of=20the=20schema=20CTE=20to=20= be=20created=0A+=20*=20fieldname:=20name=20of=20the=20oid=20field=20= within=20the=20schema=20CTE=20to=20be=20created=0A+=20*=20include:=20= list=20of=20schema=20name=20patterns=20for=20inclusion=0A+=20*=20= exclude:=20list=20of=20schema=20name=20patterns=20for=20exclusion=0A+=20= *=20inclusive:=20when=20'include'=20is=20an=20empty=20list,=20whether=20= to=20use=20all=20schemas=20in=0A+=20*=20the=20database=20in=20lieu=20of=20= the=20include=20list.=0A+=20*/=0A+static=20void=0A+schema_cte(PGconn=20= *conn,=20PQExpBuffer=20sql,=20const=20char=20*ctename,=0A+=09=09=20=20=20= const=20SimpleStringList=20*include,=20const=20SimpleStringList=20= *exclude,=0A+=09=09=20=20=20bool=20inclusive)=0A+{=0A+=09= appendPQExpBuffer(sql,=20"\n%s=20(nspoid)=20AS=20(",=20ctename);=0A+=09= schema_select(conn,=20sql,=20include,=20inclusive);=0A+=09= appendPQExpBufferStr(sql,=20"\nEXCEPT");=0A+=09schema_select(conn,=20= sql,=20exclude,=20false);=0A+=09appendPQExpBufferStr(sql,=20"\n)");=0A+}=0A= +=0A+/*=0A+=20*=20append_ctfilter_quals=0A+=20*=0A+=20*=20Appends=20= quals=20to=20a=20buffer=20that=20restrict=20the=20rows=20selected=20from=20= pg_class=20to=0A+=20*=20only=20those=20which=20match=20the=20given=20= checktype.=20=20No=20initial=20"WHERE"=20or=20"AND"=20is=0A+=20*=20= appended,=20nor=20do=20we=20surround=20our=20appended=20clauses=20in=20= parens.=20=20The=20caller=20is=0A+=20*=20assumed=20to=20take=20care=20of=20= such=20matters.=0A+=20*=0A+=20*=20sql:=20buffer=20into=20which=20the=20= constructed=20sql=20quals=20are=20appended=0A+=20*=20relname:=20name=20= (or=20alias)=20of=20pg_class=20in=20the=20surrounding=20query=0A+=20*=20= checktype:=20struct=20containing=20filter=20info=0A+=20*/=0A+static=20= void=0A+append_ctfilter_quals(PQExpBuffer=20sql,=20const=20char=20= *relname,=20CheckType=20checktype)=0A+{=0A+=09appendPQExpBuffer(sql,=0A+=09= =09=09=09=09=20=20"%s.relam=20OPERATOR(pg_catalog.=3D)=20%u"=0A+=09=09=09= =09=09=20=20"\nAND=20%s.relkind=20OPERATOR(pg_catalog.=3D)=20= ANY(ARRAY[%s])",=0A+=09=09=09=09=09=20=20relname,=20= ctfilter[checktype].relam,=0A+=09=09=09=09=09=20=20relname,=20= ctfilter[checktype].relkinds);=0A+}=0A+=0A+/*=0A+=20*=20relation_select=0A= +=20*=0A+=20*=20Appends=20a=20statement=20which=20selects=20the=20oid=20= of=20all=20relations=20matching=20the=0A+=20*=20given=20parameters.=20=20= Expects=20a=20mixture=20of=20qualified=20and=20unqualified=20relation=0A= +=20*=20name=20patterns.=0A+=20*=0A+=20*=20For=20unqualified=20relation=20= patterns,=20selects=20relations=20that=20match=20the=20relation=0A+=20*=20= name=20portion=20of=20the=20pattern=20which=20are=20in=20namespaces=20= that=20are=20in=20the=20given=0A+=20*=20namespace=20CTE.=0A+=20*=0A+=20*=20= For=20qualified=20relation=20patterns,=20ignores=20the=20given=20= namespace=20CTE=20and=20selects=0A+=20*=20relations=20that=20match=20the=20= relation=20name=20portion=20of=20the=20pattern=20which=20are=20in=0A+=20= *=20namespaces=20that=20match=20the=20schema=20portion=20of=20the=20= pattern.=0A+=20*=0A+=20*=20For=20fully=20qualified=20relation=20patterns=20= (database.schema.name),=20the=20pattern=0A+=20*=20will=20be=20ignored=20= unless=20the=20database=20portion=20of=20the=20pattern=20matches=20the=20= name=0A+=20*=20of=20the=20current=20database,=20as=20retrieved=20from=20= conn.=0A+=20*=0A+=20*=20Only=20relations=20of=20the=20specified=20= checktype=20will=20be=20selected.=0A+=20*=0A+=20*=20conn:=20connection=20= to=20the=20current=20database=0A+=20*=20sql:=20buffer=20into=20which=20= the=20constructed=20sql=20statement=20is=20appended=0A+=20*=20schemacte:=20= name=20of=20the=20CTE=20which=20selects=20all=20schemas=20to=20be=20= checked=0A+=20*=20fieldname:=20alias=20to=20use=20for=20the=20oid=20= field=20within=20the=20created=20SELECT=0A+=20*=20statement=0A+=20*=20= patterns:=20list=20of=20(possibly=20qualified)=20relation=20name=20= patterns=20to=20match=0A+=20*=20checktype:=20the=20type=20of=20relation=20= to=20select=0A+=20*=20inclusive:=20when=20patterns=20is=20an=20empty=20= list,=20whether=20the=20select=20statement=0A+=20*=20should=20match=20= all=20relations=20of=20the=20given=20type=0A+=20*/=0A+static=20void=0A= +relation_select(PGconn=20*conn,=20PQExpBuffer=20sql,=20const=20char=20= *schemacte,=0A+=09=09=09=09const=20char=20*fieldname,=0A+=09=09=09=09= const=20SimpleStringList=20*patterns,=20CheckType=20checktype,=0A+=09=09=09= =09bool=20inclusive)=0A+{=0A+=09SimpleStringListCell=20*cell;=0A+=09= const=20char=20*comma=20=3D=20"";=0A+=09const=20char=20*qor=20=3D=20"";=0A= +=09PQExpBufferData=20qualified;=0A+=09PQExpBufferData=20unqualified;=0A= +=09PQExpBufferData=20dbnamebuf;=0A+=09PQExpBufferData=20schemabuf;=0A+=09= PQExpBufferData=20namebuf;=0A+=09int=09=09=09encoding=20=3D=20= PQclientEncoding(conn);=0A+=0A+=09if=20(patterns->head=20=3D=3D=20NULL)=0A= +=09{=0A+=09=09if=20(!inclusive)=0A+=09=09=09appendPQExpBuffer(sql,=0A+=09= =09=09=09=09=09=09=20=20"\nSELECT=200::pg_catalog.oid=20AS=20%s=20WHERE=20= false",=0A+=09=09=09=09=09=09=09=20=20fieldname);=0A+=09=09else=0A+=09=09= {=0A+=09=09=09appendPQExpBuffer(sql,=0A+=09=09=09=09=09=09=09=20=20= "\nSELECT=20oid=20AS=20%s"=0A+=09=09=09=09=09=09=09=20=20"\nFROM=20= pg_catalog.pg_class=20c"=0A+=09=09=09=09=09=09=09=20=20"\nJOIN=20%s=20n"=0A= +=09=09=09=09=09=09=09=20=20"\nON=20n.nspoid=20OPERATOR(pg_catalog.=3D)=20= c.relnamespace"=0A+=09=09=09=09=09=09=09=20=20"\nWHERE=20",=0A+=09=09=09=09= =09=09=09=20=20fieldname,=20schemacte);=0A+=09=09=09= append_ctfilter_quals(sql,=20"c",=20checktype);=0A+=09=09}=0A+=09=09= return;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20We=20have=20to=20distinguish=20= between=20schema-qualified=20and=20unqualified=0A+=09=20*=20relation=20= patterns.=20=20The=20unqualified=20patterns=20need=20to=20be=20= restricted=20by=0A+=09=20*=20the=20list=20of=20schemas=20returned=20by=20= the=20schema=20CTE,=20but=20not=20so=20for=20the=0A+=09=20*=20qualified=20= patterns.=0A+=09=20*=0A+=09=20*=20We=20treat=20fully-qualified=20= relation=20patterns=20(database.schema.relation)=0A+=09=20*=20like=20= schema-qualified=20patterns=20except=20that=20we=20also=20require=20the=20= database=0A+=09=20*=20portion=20to=20match=20the=20current=20database=20= name.=0A+=09=20*/=0A+=09initPQExpBuffer(&qualified);=0A+=09= initPQExpBuffer(&unqualified);=0A+=09initPQExpBuffer(&dbnamebuf);=0A+=09= initPQExpBuffer(&schemabuf);=0A+=09initPQExpBuffer(&namebuf);=0A+=0A+=09= for=20(cell=20=3D=20patterns->head;=20cell;=20cell=20=3D=20cell->next)=0A= +=09{=0A+=09=09patternToSQLRegex(encoding,=20&dbnamebuf,=20&schemabuf,=20= &namebuf,=0A+=09=09=09=09=09=09=20=20cell->val,=20false);=0A+=0A+=09=09= if=20(schemabuf.data[0])=0A+=09=09{=0A+=09=09=09/*=20Qualified=20= relation=20pattern=20*/=0A+=09=09=09appendPQExpBuffer(&qualified,=20= "%s\n(",=20qor);=0A+=0A+=09=09=09if=20(dbnamebuf.data[0])=0A+=09=09=09{=0A= +=09=09=09=09/*=0A+=09=09=09=09=20*=20Fully-qualified=20relation=20= pattern.=20=20Require=20the=20database=0A+=09=09=09=09=20*=20name=20of=20= our=20connection=20to=20match=20the=20database=20portion=20of=20the=0A+=09= =09=09=09=20*=20relation=20pattern.=0A+=09=09=09=09=20*/=0A+=09=09=09=09= appendPQExpBufferStr(&qualified,=20"\n");=0A+=09=09=09=09= appendStringLiteralConn(&qualified,=20PQdb(conn),=20conn);=0A+=09=09=09=09= appendPQExpBufferStr(&qualified,=0A+=09=09=09=09=09=09=09=09=09=20= "::TEXT=20OPERATOR(pg_catalog.~)=20");=0A+=09=09=09=09= appendStringLiteralConn(&qualified,=20dbnamebuf.data,=20conn);=0A+=09=09=09= =09appendPQExpBufferStr(&qualified,=0A+=09=09=09=09=09=09=09=09=09=20= "::TEXT=20COLLATE=20pg_catalog.default=20AND");=0A+=09=09=09}=0A+=0A+=09=09= =09/*=0A+=09=09=09=20*=20Require=20the=20namespace=20name=20to=20match=20= the=20schema=20portion=20of=20the=0A+=09=09=09=20*=20relation=20pattern=20= and=20the=20relation=20name=20to=20match=20the=20relname=0A+=09=09=09=20= *=20portion=20of=20the=20relation=20pattern.=0A+=09=09=09=20*/=0A+=09=09=09= appendPQExpBufferStr(&qualified,=0A+=09=09=09=09=09=09=09=09=20= "\nn.nspname=20OPERATOR(pg_catalog.~)=20");=0A+=09=09=09= appendStringLiteralConn(&qualified,=20schemabuf.data,=20conn);=0A+=09=09=09= appendPQExpBufferStr(&qualified,=0A+=09=09=09=09=09=09=09=09=20"::TEXT=20= COLLATE=20pg_catalog.default=20AND"=0A+=09=09=09=09=09=09=09=09=20= "\nc.relname=20OPERATOR(pg_catalog.~)=20");=0A+=09=09=09= appendStringLiteralConn(&qualified,=20namebuf.data,=20conn);=0A+=09=09=09= appendPQExpBufferStr(&qualified,=0A+=09=09=09=09=09=09=09=09=20"::TEXT=20= COLLATE=20pg_catalog.default)");=0A+=09=09=09qor=20=3D=20"\nOR";=0A+=09=09= }=0A+=09=09else=0A+=09=09{=0A+=09=09=09/*=20Unqualified=20relation=20= pattern=20*/=0A+=09=09=09appendPQExpBufferStr(&unqualified,=20comma);=0A= +=09=09=09appendStringLiteralConn(&unqualified,=20namebuf.data,=20conn);=0A= +=09=09=09appendPQExpBufferStr(&unqualified,=0A+=09=09=09=09=09=09=09=09=20= "::TEXT=20COLLATE=20pg_catalog.default");=0A+=09=09=09comma=20=3D=20"\n,=20= ";=0A+=09=09}=0A+=0A+=09=09resetPQExpBuffer(&dbnamebuf);=0A+=09=09= resetPQExpBuffer(&schemabuf);=0A+=09=09resetPQExpBuffer(&namebuf);=0A+=09= }=0A+=0A+=09if=20(qualified.data[0])=0A+=09{=0A+=09=09= appendPQExpBuffer(sql,=0A+=09=09=09=09=09=09=20=20"\nSELECT=20c.oid=20AS=20= %s"=0A+=09=09=09=09=09=09=20=20"\nFROM=20pg_catalog.pg_class=20c"=0A+=09=09= =09=09=09=09=20=20"\nJOIN=20pg_catalog.pg_namespace=20n"=0A+=09=09=09=09=09= =09=20=20"\nON=20c.relnamespace=20OPERATOR(pg_catalog.=3D)=20n.oid"=0A+=09= =09=09=09=09=09=20=20"\nWHERE=20(",=0A+=09=09=09=09=09=09=20=20= fieldname);=0A+=09=09appendPQExpBufferStr(sql,=20qualified.data);=0A+=09=09= appendPQExpBufferStr(sql,=20")\nAND=20");=0A+=09=09= append_ctfilter_quals(sql,=20"c",=20checktype);=0A+=09=09if=20= (unqualified.data[0])=0A+=09=09=09appendPQExpBufferStr(sql,=20"\nUNION=20= ALL");=0A+=09}=0A+=09if=20(unqualified.data[0])=0A+=09{=0A+=09=09= appendPQExpBuffer(sql,=0A+=09=09=09=09=09=09=20=20"\nSELECT=20c.oid=20AS=20= %s"=0A+=09=09=09=09=09=09=20=20"\nFROM=20pg_catalog.pg_class=20c"=0A+=09=09= =09=09=09=09=20=20"\nJOIN=20%s=20ls"=0A+=09=09=09=09=09=09=20=20"\nON=20= c.relnamespace=20OPERATOR(pg_catalog.=3D)=20ls.nspoid"=0A+=09=09=09=09=09= =09=20=20"\nWHERE=20c.relname=20OPERATOR(pg_catalog.~)=20ANY(ARRAY[",=0A= +=09=09=09=09=09=09=20=20fieldname,=20schemacte);=0A+=09=09= appendPQExpBufferStr(sql,=20unqualified.data);=0A+=09=09= appendPQExpBufferStr(sql,=20"\n]::TEXT[])\nAND=20");=0A+=09=09= append_ctfilter_quals(sql,=20"c",=20checktype);=0A+=09}=0A+}=0A+=0A+/*=0A= +=20*=20table_cte=0A+=20*=0A+=20*=20Appends=20to=20the=20buffer=20'sql'=20= a=20Common=20Table=20Expression=20(CTE)=20which=20selects=0A+=20*=20all=20= table=20relations=20matching=20the=20given=20filters.=0A+=20*=0A+=20*=20= conn:=20connection=20to=20the=20current=20database=0A+=20*=20sql:=20= buffer=20into=20which=20the=20constructed=20sql=20statement=20is=20= appended=0A+=20*=20schemacte:=20name=20of=20the=20CTE=20which=20selects=20= all=20schemas=20to=20be=20checked=0A+=20*=20ctename:=20name=20of=20the=20= table=20CTE=20to=20be=20created=0A+=20*=20fieldname:=20name=20of=20the=20= oid=20field=20within=20the=20table=20CTE=20to=20be=20created=0A+=20*=20= include:=20list=20of=20table=20name=20patterns=20for=20inclusion=0A+=20*=20= exclude:=20list=20of=20table=20name=20patterns=20for=20exclusion=0A+=20*=20= inclusive:=20when=20'include'=20is=20an=20empty=20list,=20whether=20the=20= select=20statement=0A+=20*=20should=20match=20all=20relations=0A+=20*=20= toast:=20whether=20to=20also=20select=20the=20associated=20toast=20= tables=0A+=20*/=0A+static=20void=0A+table_cte(PGconn=20*conn,=20= PQExpBuffer=20sql,=20const=20char=20*schemacte,=0A+=09=09=20=20const=20= char=20*ctename,=20const=20char=20*fieldname,=0A+=09=09=20=20const=20= SimpleStringList=20*include,=20const=20SimpleStringList=20*exclude,=0A+=09= =09=20=20bool=20inclusive,=20bool=20toast)=0A+{=0A+=09= appendPQExpBuffer(sql,=20"\n%s=20(%s)=20AS=20(",=20ctename,=20= fieldname);=0A+=0A+=09if=20(toast)=0A+=09{=0A+=09=09/*=0A+=09=09=20*=20= Compute=20the=20primary=20tables,=20then=20union=20on=20all=20associated=20= toast=0A+=09=09=20*=20tables.=20=20We=20depend=20on=20left=20to=20right=20= evaluation=20of=20the=20UNION=20before=0A+=09=09=20*=20the=20EXCEPT=20= which=20gets=20added=20below.=20=20=20UNION=20and=20EXCEPT=20have=20= equal=0A+=09=09=20*=20precedence,=20so=20be=20careful=20if=20you=20= rearrange=20this=20query.=0A+=09=09=20*/=0A+=09=09appendPQExpBuffer(sql,=20= "\nWITH=20primary_table=20AS=20(");=0A+=09=09relation_select(conn,=20= sql,=20schemacte,=20fieldname,=20include,=0A+=09=09=09=09=09=09CT_TABLE,=20= inclusive);=0A+=09=09appendPQExpBuffer(sql,=20"\n)"=0A+=09=09=09=09=09=09= =20=20"\nSELECT=20%s"=0A+=09=09=09=09=09=09=20=20"\nFROM=20= primary_table"=0A+=09=09=09=09=09=09=20=20"\nUNION"=0A+=09=09=09=09=09=09= =20=20"\nSELECT=20c.reltoastrelid=20AS=20%s"=0A+=09=09=09=09=09=09=20=20= "\nFROM=20pg_catalog.pg_class=20c"=0A+=09=09=09=09=09=09=20=20"\nJOIN=20= primary_table=20pt"=0A+=09=09=09=09=09=09=20=20"\nON=20pt.%s=20= OPERATOR(pg_catalog.=3D)=20c.oid"=0A+=09=09=09=09=09=09=20=20"\nWHERE=20= c.reltoastrelid=20OPERATOR(pg_catalog.!=3D)=200",=0A+=09=09=09=09=09=09=20= =20fieldname,=20fieldname,=20fieldname);=0A+=09}=0A+=09else=0A+=09=09= relation_select(conn,=20sql,=20schemacte,=20fieldname,=20include,=0A+=09=09= =09=09=09=09CT_TABLE,=20inclusive);=0A+=0A+=09appendPQExpBufferStr(sql,=20= "\nEXCEPT");=0A+=09relation_select(conn,=20sql,=20schemacte,=20= fieldname,=20exclude,=0A+=09=09=09=09=09CT_TABLE,=20false);=0A+=09= appendPQExpBufferStr(sql,=20"\n)");=0A+}=0A+=0A+/*=0A+=20*=20= exclude_index_cte=0A+=20*=09=09Appends=20a=20CTE=20which=20selects=20all=20= indexes=20to=20be=20excluded=0A+=20*=0A+=20*=20conn:=20connection=20to=20= the=20current=20database=0A+=20*=20sql:=20buffer=20into=20which=20the=20= constructed=20sql=20CTE=20is=20appended=0A+=20*=20schemacte:=20name=20of=20= the=20CTE=20which=20selects=20all=20schemas=20to=20be=20checked=0A+=20*=20= ctename:=20name=20of=20the=20index=20CTE=20to=20be=20created=0A+=20*=20= fieldname:=20name=20of=20the=20oid=20field=20within=20the=20index=20CTE=20= to=20be=20created=0A+=20*=20patterns:=20list=20of=20index=20name=20= patterns=20to=20match=0A+=20*/=0A+static=20void=0A= +exclude_index_cte(PGconn=20*conn,=20PQExpBuffer=20sql,=20const=20char=20= *schemacte,=0A+=09=09=09=09=20=20const=20char=20*ctename,=0A+=09=09=09=09= =20=20const=20char=20*fieldname,=20const=20SimpleStringList=20*patterns)=0A= +{=0A+=09appendPQExpBuffer(sql,=20"\n%s=20(%s)=20AS=20(",=20ctename,=20= fieldname);=0A+=09relation_select(conn,=20sql,=20schemacte,=20fieldname,=20= patterns,=0A+=09=09=09=09=09CT_BTREE,=20false);=0A+=09= appendPQExpBufferStr(sql,=20"\n)");=0A+}=0A+=0A+/*=0A+=20*=20index_cte=0A= +=20*=09=09Appends=20a=20CTE=20which=20selects=20all=20indexes=20to=20be=20= checked=0A+=20*=0A+=20*=20conn:=20connection=20to=20the=20current=20= database=0A+=20*=20sql:=20buffer=20into=20which=20the=20constructed=20= sql=20CTE=20is=20appended=0A+=20*=20schemacte:=20name=20of=20the=20CTE=20= which=20selects=20all=20schemas=20to=20be=20checked=0A+=20*=20ctename:=20= name=20of=20the=20index=20CTE=20to=20be=20created=0A+=20*=20fieldname:=20= name=20of=20the=20oid=20field=20within=20the=20index=20CTE=20to=20be=20= created=0A+=20*=20excludecte:=20name=20of=20the=20CTE=20which=20contains=20= all=20indexes=20to=20be=20excluded=0A+=20*=20tablescte:=20optional;=20if=20= automatically=20including=20indexes=20for=20checked=20tables,=0A+=20*=09=09= the=20name=20of=20the=20CTE=20which=20contains=20all=20tables=20to=20be=20= checked=0A+=20*=20tablesfield:=20if=20tablescte=20is=20not=20NULL,=20the=20= name=20of=20the=20oid=20field=20in=20the=0A+=20*=09=09tables=20CTE=0A+=20= *=20patterns:=20list=20of=20index=20name=20patterns=20to=20match=0A+=20*=20= inclusive:=20when=20'include'=20is=20an=20empty=20list,=20whether=20the=20= select=20statement=20should=20match=20all=20relations=0A+=20*/=0A+static=20= void=0A+index_cte(PGconn=20*conn,=20PQExpBuffer=20sql,=20const=20char=20= *schemacte,=0A+=09=09=20=20const=20char=20*ctename,=20const=20char=20= *fieldname,=0A+=09=09=20=20const=20char=20*excludecte,=20const=20char=20= *tablescte,=0A+=09=09=20=20const=20char=20*tablesfield,=20const=20= SimpleStringList=20*patterns,=0A+=09=09=20=20bool=20inclusive)=0A+{=0A+=09= appendPQExpBuffer(sql,=20"\n%s=20(%s)=20AS=20(",=20ctename,=20= fieldname);=0A+=09appendPQExpBuffer(sql,=20"\nSELECT=20%s=20FROM=20(",=20= fieldname);=0A+=09relation_select(conn,=20sql,=20schemacte,=20fieldname,=20= patterns,=0A+=09=09=09=09=09CT_BTREE,=20inclusive);=0A+=09if=20= (tablescte)=0A+=09{=0A+=09=09appendPQExpBuffer(sql,=0A+=09=09=09=09=09=09= =20=20"\nUNION"=0A+=09=09=09=09=09=09=20=20"\nSELECT=20i.indexrelid=20AS=20= %s"=0A+=09=09=09=09=09=09=20=20"\nFROM=20pg_catalog.pg_index=20i"=0A+=09=09= =09=09=09=09=20=20"\nJOIN=20%s=20t=20ON=20t.%s=20OPERATOR(pg_catalog.=3D)=20= i.indrelid",=0A+=09=09=09=09=09=09=20=20fieldname,=20tablescte,=20= tablesfield);=0A+=09}=0A+=09appendPQExpBuffer(sql,=0A+=09=09=09=09=09=20=20= "\n)=20AS=20included_indexes"=0A+=09=09=09=09=09=20=20"\nEXCEPT"=0A+=09=09= =09=09=09=20=20"\nSELECT=20%s=20FROM=20%s",=0A+=09=09=09=09=09=20=20= fieldname,=20excludecte);=0A+=09appendPQExpBufferStr(sql,=20"\n)");=0A+}=0A= +=0A+/*=0A+=20*=20target_select=0A+=20*=0A+=20*=20Construct=20a=20query=20= that=20will=20return=20a=20list=20of=20all=20tables=20and=20indexes=20in=0A= +=20*=20the=20database=20matching=20the=20user=20specified=20options,=20= sorted=20by=20size.=20=20We=0A+=20*=20want=20the=20largest=20tables=20= and=20indexes=20first,=20so=20that=20the=20parallel=0A+=20*=20processing=20= of=20the=20larger=20database=20objects=20gets=20started=20sooner.=0A+=20= *=0A+=20*=20If=20'inclusive'=20is=20true,=20include=20all=20tables=20and=20= indexes=20not=20otherwise=0A+=20*=20excluded;=20if=20false,=20include=20= only=20tables=20and=20indexes=20explicitly=20included.=0A+=20*=0A+=20*=20= conn:=20connection=20to=20the=20current=20database=0A+=20*=20sql:=20= buffer=20into=20which=20the=20constructed=20sql=20select=20statement=20= is=20appended=0A+=20*=20objects:=20lists=20of=20include=20and=20exclude=20= patterns=20for=20filtering=20objects=0A+=20*=20checkopts:=20user=20= supplied=20program=20options=0A+=20*=20progname:=20name=20of=20this=20= program,=20such=20as=20"pg_amcheck"=0A+=20*=20inclusive:=20when=20list=20= of=20objects=20to=20include=20is=20empty,=20whether=20the=20select=0A+=20= *=20statement=20should=20match=20all=20objects=20not=20otherwise=20= excluded=0A+=20*/=0A+static=20void=0A+target_select(PGconn=20*conn,=20= PQExpBuffer=20sql,=20const=20amcheckObjects=20*objects,=0A+=09=09=09=20=20= const=20amcheckOptions=20*checkopts,=20const=20char=20*progname,=0A+=09=09= =09=20=20bool=20inclusive)=0A+{=0A+=09appendPQExpBufferStr(sql,=20= "WITH");=0A+=09schema_cte(conn,=20sql,=20"namespaces",=20= &objects->schemas,=0A+=09=09=09=20=20=20&objects->exclude_schemas,=20= inclusive);=0A+=09appendPQExpBufferStr(sql,=20",");=0A+=09= table_cte(conn,=20sql,=20"namespaces",=20"tables",=20"tbloid",=0A+=09=09=09= =20=20&objects->tables,=20&objects->exclude_tables,=20inclusive,=0A+=09=09= =09=20=20!checkopts->exclude_toast);=0A+=09if=20(!checkopts->no_indexes)=0A= +=09{=0A+=09=09appendPQExpBufferStr(sql,=20",");=0A+=09=09= exclude_index_cte(conn,=20sql,=20"namespaces",=0A+=09=09=09=09=09=09=20=20= "excluded_indexes",=20"idxoid",=0A+=09=09=09=09=09=09=20=20= &objects->exclude_indexes);=0A+=09=09appendPQExpBufferStr(sql,=20",");=0A= +=09=09if=20(checkopts->dependents)=0A+=09=09=09index_cte(conn,=20sql,=20= "namespaces",=20"indexes",=20"idxoid",=0A+=09=09=09=09=09=20=20= "excluded_indexes",=20"tables",=20"tbloid",=0A+=09=09=09=09=09=20=20= &objects->indexes,=20inclusive);=0A+=09=09else=0A+=09=09=09= index_cte(conn,=20sql,=20"namespaces",=20"indexes",=20"idxoid",=0A+=09=09= =09=09=09=20=20"excluded_indexes",=20NULL,=20NULL,=20&objects->indexes,=0A= +=09=09=09=09=09=20=20inclusive);=0A+=09}=0A+=09appendPQExpBuffer(sql,=0A= +=09=09=09=09=09=20=20"\nSELECT=20checktype,=20oid=20FROM=20("=0A+=09=09=09= =09=09=20=20"\nSELECT=20%u=20AS=20checktype,=20tables.tbloid=20AS=20oid,=20= c.relpages"=0A+=09=09=09=09=09=20=20"\nFROM=20pg_catalog.pg_class=20c"=0A= +=09=09=09=09=09=20=20"\nJOIN=20tables"=0A+=09=09=09=09=09=20=20"\nON=20= tables.tbloid=20OPERATOR(pg_catalog.=3D)=20c.oid"=0A+=09=09=09=09=09=20=20= "\nWHERE=20",=0A+=09=09=09=09=09=20=20CT_TABLE);=0A+=09= append_ctfilter_quals(sql,=20"c",=20CT_TABLE);=0A+=09if=20= (!checkopts->no_indexes)=0A+=09{=0A+=09=09appendPQExpBuffer(sql,=0A+=09=09= =09=09=09=09=20=20"\nUNION=20ALL"=0A+=09=09=09=09=09=09=20=20"\nSELECT=20= %u=20AS=20checktype,=20indexes.idxoid=20AS=20oid,=20c.relpages"=0A+=09=09= =09=09=09=09=20=20"\nFROM=20pg_catalog.pg_class=20c"=0A+=09=09=09=09=09=09= =20=20"\nJOIN=20indexes"=0A+=09=09=09=09=09=09=20=20"\nON=20= indexes.idxoid=20OPERATOR(pg_catalog.=3D)=20c.oid"=0A+=09=09=09=09=09=09=20= =20"\nWHERE=20",=0A+=09=09=09=09=09=09=20=20CT_BTREE);=0A+=09=09= append_ctfilter_quals(sql,=20"c",=20CT_BTREE);=0A+=09}=0A+=09= appendPQExpBufferStr(sql,=0A+=09=09=09=09=09=09=20"\n)=20AS=20ss"=0A+=09=09= =09=09=09=09=20"\nORDER=20BY=20relpages=20DESC,=20checktype,=20oid");=0A= +}=0Adiff=20--git=20a/contrib/pg_amcheck/pg_amcheck.h=20= b/contrib/pg_amcheck/pg_amcheck.h=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..b5ca276033=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/pg_amcheck.h=0A@@=20-0,0=20+1,135=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20pg_amcheck.h=0A+=20*=09=09Detects=20corruption=20= within=20database=20relations.=0A+=20*=0A+=20*=20Copyright=20(c)=20= 2020-2021,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=0A+=20*=20= IDENTIFICATION=0A+=20*=09=20=20contrib/pg_amcheck/pg_amcheck.h=0A+=20*=0A= +=20= *-------------------------------------------------------------------------= =0A+=20*/=0A+#ifndef=20PG_AMCHECK_H=0A+#define=20PG_AMCHECK_H=0A+=0A= +#include=20"fe_utils/simple_list.h"=0A+#include=20= "fe_utils/string_utils.h"=0A+#include=20"libpq-fe.h"=0A+#include=20= "pqexpbuffer.h"=09=09/*=20pgrminclude=20ignore=20*/=0A+=0A+/*=20amcheck=20= options=20controlled=20by=20user=20flags=20*/=0A+typedef=20struct=20= amcheckOptions=0A+{=0A+=09bool=09=09alldb;=0A+=09bool=09=09echo;=0A+=09= bool=09=09quiet;=0A+=09bool=09=09verbose;=0A+=09bool=09=09dependents;=0A= +=09bool=09=09no_indexes;=0A+=09bool=09=09exclude_toast;=0A+=09bool=09=09= reconcile_toast;=0A+=09bool=09=09on_error_stop;=0A+=09bool=09=09= parent_check;=0A+=09bool=09=09rootdescend;=0A+=09bool=09=09= heapallindexed;=0A+=09const=20char=20*skip;=0A+=09int=09=09=09jobs;=09=09= =09/*=20>=3D=200=20indicates=20user=20specified=20the=20parallel=0A+=09=09= =09=09=09=09=09=09=20*=20degree,=20otherwise=20-1=20*/=0A+=09long=09=09= startblock;=0A+=09long=09=09endblock;=0A+}=20amcheckOptions;=0A+=0A+/*=20= names=20of=20database=20objects=20to=20include=20or=20exclude=20= controlled=20by=20user=20flags=20*/=0A+typedef=20struct=20amcheckObjects=0A= +{=0A+=09SimpleStringList=20databases;=0A+=09SimpleStringList=20schemas;=0A= +=09SimpleStringList=20tables;=0A+=09SimpleStringList=20indexes;=0A+=09= SimpleStringList=20exclude_databases;=0A+=09SimpleStringList=20= exclude_schemas;=0A+=09SimpleStringList=20exclude_tables;=0A+=09= SimpleStringList=20exclude_indexes;=0A+}=20amcheckObjects;=0A+=0A+/*=0A+=20= *=20We=20cannot=20launch=20the=20same=20amcheck=20function=20for=20all=20= checked=20objects.=20=20For=0A+=20*=20btree=20indexes,=20we=20must=20use=20= either=20bt_index_check()=20or=0A+=20*=20bt_index_parent_check().=20=20= For=20heap=20relations,=20we=20must=20use=20verify_heapam().=0A+=20*=20= We=20silently=20ignore=20all=20other=20object=20types.=0A+=20*=0A+=20*=20= The=20following=20CheckType=20enum=20and=20corresponding=20ctfilter=20= array=20track=20which=0A+=20*=20which=20kinds=20of=20relations=20get=20= which=20treatment.=0A+=20*/=0A+typedef=20enum=0A+{=0A+=09CT_TABLE=20=3D=20= 0,=0A+=09CT_BTREE=0A+}=20CheckType;=0A+=0A+/*=0A+=20*=20This=20struct=20= is=20used=20for=20filtering=20relations=20in=20pg_catalog.pg_class=20to=20= just=0A+=20*=20those=20of=20a=20given=20CheckType.=20=20The=20relam=20= field=20should=20equal=20pg_class.relam,=0A+=20*=20and=20the=20= pg_class.relkind=20should=20be=20contained=20in=20the=20relkinds=20comma=20= separated=0A+=20*=20list.=0A+=20*=0A+=20*=20The=20'typname'=20field=20is=20= not=20strictly=20for=20filtering,=20but=20for=20printing=20messages=0A+=20= *=20about=20relations=20that=20matched=20the=20filter.=0A+=20*/=0A= +typedef=20struct=0A+{=0A+=09Oid=09=09=09relam;=0A+=09const=20char=20= *relkinds;=0A+=09const=20char=20*typname;=0A+}=20CheckTypeFilter;=0A+=0A= +/*=20Constants=20taken=20from=20pg_catalog/pg_am.dat=20*/=0A+#define=20= HEAP_TABLE_AM_OID=202=0A+#define=20BTREE_AM_OID=20403=0A+=0A+static=20= void=20check_each_database(ConnParams=20*cparams,=0A+=09=09=09=09=09=09=09= =09const=20amcheckObjects=20*objects,=0A+=09=09=09=09=09=09=09=09const=20= amcheckOptions=20*checkopts,=0A+=09=09=09=09=09=09=09=09const=20char=20= *progname);=0A+=0A+static=20void=20check_one_database(const=20ConnParams=20= *cparams,=0A+=09=09=09=09=09=09=09=20=20=20const=20amcheckObjects=20= *objects,=0A+=09=09=09=09=09=09=09=20=20=20const=20amcheckOptions=20= *checkopts,=0A+=09=09=09=09=09=09=09=20=20=20const=20char=20*progname);=0A= +static=20void=20prepare_table_command(PQExpBuffer=20sql,=0A+=09=09=09=09= =09=09=09=09=20=20const=20amcheckOptions=20*checkopts,=20Oid=20reloid,=0A= +=09=09=09=09=09=09=09=09=20=20const=20char=20*nspname);=0A+=0A+static=20= void=20prepare_btree_command(PQExpBuffer=20sql,=0A+=09=09=09=09=09=09=09=09= =20=20const=20amcheckOptions=20*checkopts,=20Oid=20reloid,=0A+=09=09=09=09= =09=09=09=09=20=20const=20char=20*nspname);=0A+=0A+static=20void=20= run_command(PGconn=20*conn,=20const=20char=20*sql,=0A+=09=09=09=09=09=09= const=20amcheckOptions=20*checkopts,=20Oid=20reloid,=0A+=09=09=09=09=09=09= const=20char=20*typ);=0A+=0A+static=20PGresult=20= *VerifyHeapamSlotHandler(PGresult=20*res,=20PGconn=20*conn,=0A+=09=09=09=09= =09=09=09=09=09=09=20void=20*context);=0A+=0A+static=20PGresult=20= *VerifyBtreeSlotHandler(PGresult=20*res,=20PGconn=20*conn,=0A+=09=09=09=09= =09=09=09=09=09=09void=20*context);=0A+=0A+static=20void=20help(const=20= char=20*progname);=0A+=0A+=0A+static=20void=20= get_db_regexes_from_fqrps(SimpleStringList=20*regexes,=0A+=09=09=09=09=09= =09=09=09=09=20=20const=20SimpleStringList=20*patterns);=0A+=0A+static=20= void=20get_db_regexes_from_patterns(SimpleStringList=20*regexes,=0A+=09=09= =09=09=09=09=09=09=09=09=20const=20SimpleStringList=20*patterns);=0A+=0A= +static=20void=20dbname_select(PGconn=20*conn,=20PQExpBuffer=20sql,=0A+=09= =09=09=09=09=09=20=20const=20SimpleStringList=20*regexes,=20bool=20= alldb);=0A+=0A+static=20void=20target_select(PGconn=20*conn,=20= PQExpBuffer=20sql,=0A+=09=09=09=09=09=09=20=20const=20amcheckObjects=20= *objects,=0A+=09=09=09=09=09=09=20=20const=20amcheckOptions=20*options,=20= const=20char=20*progname,=0A+=09=09=09=09=09=09=20=20bool=20inclusive);=0A= +=0A+#endif=09=09=09=09=09=09=09/*=20PG_AMCHECK_H=20*/=0Adiff=20--git=20= a/contrib/pg_amcheck/t/001_basic.pl=20= b/contrib/pg_amcheck/t/001_basic.pl=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..dfa0ae9e06=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/t/001_basic.pl=0A@@=20-0,0=20+1,9=20@@=0A+use=20= strict;=0A+use=20warnings;=0A+=0A+use=20TestLib;=0A+use=20Test::More=20= tests=20=3D>=208;=0A+=0A+program_help_ok('pg_amcheck');=0A= +program_version_ok('pg_amcheck');=0A= +program_options_handling_ok('pg_amcheck');=0Adiff=20--git=20= a/contrib/pg_amcheck/t/002_nonesuch.pl=20= b/contrib/pg_amcheck/t/002_nonesuch.pl=0Anew=20file=20mode=20100644=0A= index=200000000000..b52039c79b=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/t/002_nonesuch.pl=0A@@=20-0,0=20+1,78=20@@=0A+use=20= strict;=0A+use=20warnings;=0A+=0A+use=20PostgresNode;=0A+use=20TestLib;=0A= +use=20Test::More=20tests=20=3D>=2016;=0A+=0A+#=20Test=20set-up=0A+my=20= ($node,=20$port);=0A+$node=20=3D=20get_new_node('test');=0A+$node->init;=0A= +$node->start;=0A+$port=20=3D=20$node->port;=0A+=0A+#=20Load=20the=20= amcheck=20extension,=20upon=20which=20pg_amcheck=20depends=0A= +$node->safe_psql('postgres',=20q(CREATE=20EXTENSION=20amcheck));=0A+=0A= +#########################################=0A+#=20Test=20connecting=20to=20= a=20non-existent=20database=0A+=0A+command_fails_like(=0A+=09[=20= 'pg_amcheck',=20'-p',=20$port,=20'qqq'=20],=0A+=09qr/database=20"qqq"=20= does=20not=20exist/,=0A+=09'checking=20a=20non-existent=20database');=0A= +=0A+#########################################=0A+#=20Test=20connecting=20= with=20a=20non-existent=20user=0A+=0A+command_fails_like(=0A+=09[=20= 'pg_amcheck',=20'-p',=20$port,=20'-U=3Dno_such_user',=20'postgres'=20],=0A= +=09qr/role=20"=3Dno_such_user"=20does=20not=20exist/,=0A+=09'checking=20= with=20a=20non-existent=20user');=0A+=0A= +#########################################=0A+#=20Test=20checking=20a=20= database=20without=20amcheck=20installed,=20by=20name.=20=20We=20should=20= see=20a=0A+#=20message=20about=20missing=20amcheck=0A+=0A= +$node->command_like(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20= 'template1'=20],=0A+=09qr/pg_amcheck:=20skipping=20database=20= "template1":=20amcheck=20is=20not=20installed/,=0A+=09'checking=20a=20= database=20by=20name=20without=20amcheck=20installed');=0A+=0A= +#########################################=0A+#=20Test=20checking=20a=20= database=20without=20amcheck=20installed,=20by=20only=20indirectly=20= using=0A+#=20a=20dbname=20pattern.=20=20In=20verbose=20mode,=20we=20= should=20see=20a=20message=20about=20missing=0A+#=20amcheck=0A+=0A= +$node->command_like(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-v',=20= '-d',=20'*',=20'postgres'=20],=0A+=09qr/pg_amcheck:=20skipping=20= database=20"template1":=20amcheck=20is=20not=20installed/,=0A+=09= 'checking=20a=20database=20by=20dbname=20implication=20without=20amcheck=20= installed');=0A+=0A+#########################################=0A+#=20= Test=20checking=20non-existent=20schemas,=20tables,=20and=20indexes=0A+=0A= +$node->command_ok(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-s',=20= 'no_such_schema'=20],=0A+=09'checking=20a=20non-existent=20schema');=0A+=0A= +$node->command_ok(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-t',=20= 'no_such_table'=20],=0A+=09'checking=20a=20non-existent=20table');=0A+=0A= +$node->command_ok(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-i',=20= 'no_such_index'=20],=0A+=09'checking=20a=20non-existent=20schema');=0A+=0A= +$node->command_ok(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-s',=20= 'no*such*schema*'=20],=0A+=09'no=20matching=20schemas');=0A+=0A= +$node->command_ok(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-t',=20= 'no*such*table*'=20],=0A+=09'no=20matching=20tables');=0A+=0A= +$node->command_ok(=0A+=09[=20'pg_amcheck',=20'-p',=20$port,=20'-i',=20= 'no*such*index'=20],=0A+=09'no=20matching=20indexes');=0Adiff=20--git=20= a/contrib/pg_amcheck/t/003_check.pl=20= b/contrib/pg_amcheck/t/003_check.pl=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..957094fcdd=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/t/003_check.pl=0A@@=20-0,0=20+1,475=20@@=0A+use=20= strict;=0A+use=20warnings;=0A+=0A+use=20PostgresNode;=0A+use=20TestLib;=0A= +use=20Test::More=20tests=20=3D>=2070;=0A+=0A+my=20($node,=20$port);=0A+=0A= +#=20Returns=20the=20filesystem=20path=20for=20the=20named=20relation.=0A= +#=0A+#=20Assumes=20the=20test=20node=20is=20running=0A+sub=20= relation_filepath($$)=0A+{=0A+=09my=20($dbname,=20$relname)=20=3D=20@_;=0A= +=0A+=09my=20$pgdata=20=3D=20$node->data_dir;=0A+=09my=20$rel=20=3D=20= $node->safe_psql($dbname,=0A+=09=09=09=09=09=09=09=20=20=20qq(SELECT=20= pg_relation_filepath('$relname')));=0A+=09die=20"path=20not=20found=20= for=20relation=20$relname"=20unless=20defined=20$rel;=0A+=09return=20= "$pgdata/$rel";=0A+}=0A+=0A+#=20Returns=20the=20name=20of=20the=20toast=20= relation=20associated=20with=20the=20named=20relation.=0A+#=0A+#=20= Assumes=20the=20test=20node=20is=20running=0A+sub=20relation_toast($$)=0A= +{=0A+=09my=20($dbname,=20$relname)=20=3D=20@_;=0A+=0A+=09my=20$rel=20=3D=20= $node->safe_psql($dbname,=20qq(=0A+=09=09SELECT=20ct.relname=0A+=09=09=09= FROM=20pg_catalog.pg_class=20cr,=20pg_catalog.pg_class=20ct=0A+=09=09=09= WHERE=20cr.oid=20=3D=20'$relname'::regclass=0A+=09=09=09=20=20AND=20= cr.reltoastrelid=20=3D=20ct.oid=0A+=09=09=09));=0A+=09return=20undef=20= unless=20defined=20$rel;=0A+=09return=20"pg_toast.$rel";=0A+}=0A+=0A+#=20= Stops=20the=20test=20node,=20corrupts=20the=20first=20page=20of=20the=20= named=20relation,=20and=0A+#=20restarts=20the=20node.=0A+#=0A+#=20= Assumes=20the=20test=20node=20is=20running.=0A+sub=20= corrupt_first_page($$)=0A+{=0A+=09my=20($dbname,=20$relname)=20=3D=20@_;=0A= +=09my=20$relpath=20=3D=20relation_filepath($dbname,=20$relname);=0A+=0A= +=09$node->stop;=0A+=09my=20$fh;=0A+=09open($fh,=20'+<',=20$relpath);=0A= +=09binmode=20$fh;=0A+=09seek($fh,=2032,=200);=0A+=09syswrite($fh,=20= '\x77\x77\x77\x77',=20500);=0A+=09close($fh);=0A+=09$node->start;=0A+}=0A= +=0A+#=20Stops=20the=20test=20node,=20unlinks=20the=20file=20from=20the=20= filesystem=20that=20backs=20the=0A+#=20relation,=20and=20restarts=20the=20= node.=0A+#=0A+#=20Assumes=20the=20test=20node=20is=20running=0A+sub=20= remove_relation_file($$)=0A+{=0A+=09my=20($dbname,=20$relname)=20=3D=20= @_;=0A+=09my=20$relpath=20=3D=20relation_filepath($dbname,=20$relname);=0A= +=0A+=09$node->stop();=0A+=09unlink($relpath);=0A+=09$node->start;=0A+}=0A= +=0A+#=20Stops=20the=20test=20node,=20unlinks=20the=20file=20from=20the=20= filesystem=20that=20backs=20the=0A+#=20toast=20table=20(if=20any)=20= corresponding=20to=20the=20given=20main=20table=20relation,=20and=0A+#=20= restarts=20the=20node.=0A+#=0A+#=20Assumes=20the=20test=20node=20is=20= running=0A+sub=20remove_toast_file($$)=0A+{=0A+=09my=20($dbname,=20= $relname)=20=3D=20@_;=0A+=09my=20$toastname=20=3D=20= relation_toast($dbname,=20$relname);=0A+=09remove_relation_file($dbname,=20= $toastname)=20if=20($toastname);=0A+}=0A+=0A+#=20Test=20set-up=0A+$node=20= =3D=20get_new_node('test');=0A+$node->init;=0A+$node->start;=0A+$port=20= =3D=20$node->port;=0A+=0A+for=20my=20$dbname=20(qw(db1=20db2=20db3))=0A= +{=0A+=09#=20Create=20the=20database=0A+=09$node->safe_psql('postgres',=20= qq(CREATE=20DATABASE=20$dbname));=0A+=0A+=09#=20Load=20the=20amcheck=20= extension,=20upon=20which=20pg_amcheck=20depends.=20=20Put=20the=0A+=09#=20= extension=20in=20an=20unexpected=20location=20to=20test=20that=20= pg_amcheck=20finds=20it=0A+=09#=20correctly.=20=20Create=20tables=20with=20= names=20that=20look=20like=20pg_catalog=20names=20to=0A+=09#=20check=20= that=20pg_amcheck=20does=20not=20get=20confused=20by=20them.=20=20Create=20= functions=20in=0A+=09#=20schema=20public=20that=20look=20like=20amcheck=20= functions=20to=20check=20that=20pg_amcheck=0A+=09#=20does=20not=20use=20= them.=0A+=09$node->safe_psql($dbname,=20q(=0A+=09=09CREATE=20SCHEMA=20= amcheck_schema;=0A+=09=09CREATE=20EXTENSION=20amcheck=20WITH=20SCHEMA=20= amcheck_schema;=0A+=09=09CREATE=20TABLE=20amcheck_schema.pg_database=20= (junk=20text);=0A+=09=09CREATE=20TABLE=20amcheck_schema.pg_namespace=20= (junk=20text);=0A+=09=09CREATE=20TABLE=20amcheck_schema.pg_class=20(junk=20= text);=0A+=09=09CREATE=20TABLE=20amcheck_schema.pg_operator=20(junk=20= text);=0A+=09=09CREATE=20TABLE=20amcheck_schema.pg_proc=20(junk=20text);=0A= +=09=09CREATE=20TABLE=20amcheck_schema.pg_tablespace=20(junk=20text);=0A= +=0A+=09=09CREATE=20FUNCTION=20public.bt_index_check(index=20regclass,=0A= +=09=09=09=09=09=09=09=09=09=09=09=20=20heapallindexed=20boolean=20= default=20false)=0A+=09=09RETURNS=20VOID=20AS=20$$=0A+=09=09BEGIN=0A+=09=09= =09RAISE=20EXCEPTION=20'Invoked=20wrong=20bt_index_check!';=0A+=09=09= END;=0A+=09=09$$=20LANGUAGE=20plpgsql;=0A+=0A+=09=09CREATE=20FUNCTION=20= public.bt_index_parent_check(index=20regclass,=0A+=09=09=09=09=09=09=09=09= =09=09=09=09=09=20heapallindexed=20boolean=20default=20false,=0A+=09=09=09= =09=09=09=09=09=09=09=09=09=09=20rootdescend=20boolean=20default=20= false)=0A+=09=09RETURNS=20VOID=20AS=20$$=0A+=09=09BEGIN=0A+=09=09=09= RAISE=20EXCEPTION=20'Invoked=20wrong=20bt_index_parent_check!';=0A+=09=09= END;=0A+=09=09$$=20LANGUAGE=20plpgsql;=0A+=0A+=09=09CREATE=20FUNCTION=20= public.verify_heapam(relation=20regclass,=0A+=09=09=09=09=09=09=09=09=09=09= =09=20on_error_stop=20boolean=20default=20false,=0A+=09=09=09=09=09=09=09= =09=09=09=09=20check_toast=20boolean=20default=20false,=0A+=09=09=09=09=09= =09=09=09=09=09=09=20skip=20text=20default=20'none',=0A+=09=09=09=09=09=09= =09=09=09=09=09=20startblock=20bigint=20default=20null,=0A+=09=09=09=09=09= =09=09=09=09=09=09=20endblock=20bigint=20default=20null,=0A+=09=09=09=09=09= =09=09=09=09=09=09=20blkno=20OUT=20bigint,=0A+=09=09=09=09=09=09=09=09=09= =09=09=20offnum=20OUT=20integer,=0A+=09=09=09=09=09=09=09=09=09=09=09=20= attnum=20OUT=20integer,=0A+=09=09=09=09=09=09=09=09=09=09=09=20msg=20OUT=20= text)=0A+=09=09RETURNS=20SETOF=20record=20AS=20$$=0A+=09=09BEGIN=0A+=09=09= =09RAISE=20EXCEPTION=20'Invoked=20wrong=20verify_heapam!';=0A+=09=09END;=0A= +=09=09$$=20LANGUAGE=20plpgsql;=0A+=09));=0A+=0A+=09#=20Create=20= schemas,=20tables=20and=20indexes=20in=20five=20separate=0A+=09#=20= schemas.=20=20The=20schemas=20are=20all=20identical=20to=20start,=20but=0A= +=09#=20we=20will=20corrupt=20them=20differently=20later.=0A+=09#=0A+=09= for=20my=20$schema=20(qw(s1=20s2=20s3=20s4=20s5))=0A+=09{=0A+=09=09= $node->safe_psql($dbname,=20qq(=0A+=09=09=09CREATE=20SCHEMA=20$schema;=0A= +=09=09=09CREATE=20SEQUENCE=20$schema.seq1;=0A+=09=09=09CREATE=20= SEQUENCE=20$schema.seq2;=0A+=09=09=09CREATE=20TABLE=20$schema.t1=20(=0A+=09= =09=09=09i=20INTEGER,=0A+=09=09=09=09b=20BOX,=0A+=09=09=09=09ia=20= int4[],=0A+=09=09=09=09ir=20int4range,=0A+=09=09=09=09t=20TEXT=0A+=09=09=09= );=0A+=09=09=09CREATE=20TABLE=20$schema.t2=20(=0A+=09=09=09=09i=20= INTEGER,=0A+=09=09=09=09b=20BOX,=0A+=09=09=09=09ia=20int4[],=0A+=09=09=09= =09ir=20int4range,=0A+=09=09=09=09t=20TEXT=0A+=09=09=09);=0A+=09=09=09= CREATE=20VIEW=20$schema.t2_view=20AS=20(=0A+=09=09=09=09SELECT=20i*2,=20= t=20FROM=20$schema.t2=0A+=09=09=09);=0A+=09=09=09ALTER=20TABLE=20= $schema.t2=0A+=09=09=09=09ALTER=20COLUMN=20t=0A+=09=09=09=09SET=20= STORAGE=20EXTERNAL;=0A+=0A+=09=09=09INSERT=20INTO=20$schema.t1=20(i,=20= b,=20ia,=20ir,=20t)=0A+=09=09=09=09(SELECT=20gs::INTEGER=20AS=20i,=0A+=09= =09=09=09=09=09box(point(gs,gs+5),point(gs*2,gs*3))=20AS=20b,=0A+=09=09=09= =09=09=09array[gs,=20gs=20+=201]::int4[]=20AS=20ia,=0A+=09=09=09=09=09=09= int4range(gs,=20gs+100)=20AS=20ir,=0A+=09=09=09=09=09=09repeat('foo',=20= gs)=20AS=20t=0A+=09=09=09=09=09=20FROM=20generate_series(1,10000,3000)=20= AS=20gs);=0A+=0A+=09=09=09INSERT=20INTO=20$schema.t2=20(i,=20b,=20ia,=20= ir,=20t)=0A+=09=09=09=09(SELECT=20gs::INTEGER=20AS=20i,=0A+=09=09=09=09=09= =09box(point(gs,gs+5),point(gs*2,gs*3))=20AS=20b,=0A+=09=09=09=09=09=09= array[gs,=20gs=20+=201]::int4[]=20AS=20ia,=0A+=09=09=09=09=09=09= int4range(gs,=20gs+100)=20AS=20ir,=0A+=09=09=09=09=09=09repeat('foo',=20= gs)=20AS=20t=0A+=09=09=09=09=09=20FROM=20generate_series(1,10000,3000)=20= AS=20gs);=0A+=0A+=09=09=09CREATE=20MATERIALIZED=20VIEW=20$schema.t1_mv=20= AS=20SELECT=20*=20FROM=20$schema.t1;=0A+=09=09=09CREATE=20MATERIALIZED=20= VIEW=20$schema.t2_mv=20AS=20SELECT=20*=20FROM=20$schema.t2;=0A+=0A+=09=09= =09create=20table=20$schema.p1=20(a=20int,=20b=20int)=20PARTITION=20BY=20= list=20(a);=0A+=09=09=09create=20table=20$schema.p2=20(a=20int,=20b=20= int)=20PARTITION=20BY=20list=20(a);=0A+=0A+=09=09=09create=20table=20= $schema.p1_1=20partition=20of=20$schema.p1=20for=20values=20in=20(1,=20= 2,=203);=0A+=09=09=09create=20table=20$schema.p1_2=20partition=20of=20= $schema.p1=20for=20values=20in=20(4,=205,=206);=0A+=09=09=09create=20= table=20$schema.p2_1=20partition=20of=20$schema.p2=20for=20values=20in=20= (1,=202,=203);=0A+=09=09=09create=20table=20$schema.p2_2=20partition=20= of=20$schema.p2=20for=20values=20in=20(4,=205,=206);=0A+=0A+=09=09=09= CREATE=20INDEX=20t1_btree=20ON=20$schema.t1=20USING=20BTREE=20(i);=0A+=09= =09=09CREATE=20INDEX=20t2_btree=20ON=20$schema.t2=20USING=20BTREE=20(i);=0A= +=0A+=09=09=09CREATE=20INDEX=20t1_hash=20ON=20$schema.t1=20USING=20HASH=20= (i);=0A+=09=09=09CREATE=20INDEX=20t2_hash=20ON=20$schema.t2=20USING=20= HASH=20(i);=0A+=0A+=09=09=09CREATE=20INDEX=20t1_brin=20ON=20$schema.t1=20= USING=20BRIN=20(i);=0A+=09=09=09CREATE=20INDEX=20t2_brin=20ON=20= $schema.t2=20USING=20BRIN=20(i);=0A+=0A+=09=09=09CREATE=20INDEX=20= t1_gist=20ON=20$schema.t1=20USING=20GIST=20(b);=0A+=09=09=09CREATE=20= INDEX=20t2_gist=20ON=20$schema.t2=20USING=20GIST=20(b);=0A+=0A+=09=09=09= CREATE=20INDEX=20t1_gin=20ON=20$schema.t1=20USING=20GIN=20(ia);=0A+=09=09= =09CREATE=20INDEX=20t2_gin=20ON=20$schema.t2=20USING=20GIN=20(ia);=0A+=0A= +=09=09=09CREATE=20INDEX=20t1_spgist=20ON=20$schema.t1=20USING=20SPGIST=20= (ir);=0A+=09=09=09CREATE=20INDEX=20t2_spgist=20ON=20$schema.t2=20USING=20= SPGIST=20(ir);=0A+=09=09));=0A+=09}=0A+}=0A+=0A+#=20Database=20'db1'=20= corruptions=0A+#=0A+=0A+#=20Corrupt=20indexes=20in=20schema=20"s1"=0A= +remove_relation_file('db1',=20's1.t1_btree');=0A= +corrupt_first_page('db1',=20's1.t2_btree');=0A+=0A+#=20Corrupt=20tables=20= in=20schema=20"s2"=0A+remove_relation_file('db1',=20's2.t1');=0A= +corrupt_first_page('db1',=20's2.t2');=0A+=0A+#=20Corrupt=20tables,=20= partitions,=20matviews,=20and=20btrees=20in=20schema=20"s3"=0A= +remove_relation_file('db1',=20's3.t1');=0A+corrupt_first_page('db1',=20= 's3.t2');=0A+=0A+remove_relation_file('db1',=20's3.t1_mv');=0A= +remove_relation_file('db1',=20's3.p1_1');=0A+=0A= +corrupt_first_page('db1',=20's3.t2_mv');=0A+corrupt_first_page('db1',=20= 's3.p2_1');=0A+=0A+remove_relation_file('db1',=20's3.t1_btree');=0A= +corrupt_first_page('db1',=20's3.t2_btree');=0A+=0A+#=20Corrupt=20toast=20= table,=20partitions,=20and=20materialized=20views=20in=20schema=20"s4"=0A= +remove_toast_file('db1',=20's4.t2');=0A+=0A+#=20Corrupt=20all=20other=20= object=20types=20in=20schema=20"s5".=20=20We=20don't=20have=20amcheck=20= support=0A+#=20for=20these=20types,=20but=20we=20check=20that=20their=20= corruption=20does=20not=20trigger=20any=0A+#=20errors=20in=20pg_amcheck=0A= +remove_relation_file('db1',=20's5.seq1');=0A= +remove_relation_file('db1',=20's5.t1_hash');=0A= +remove_relation_file('db1',=20's5.t1_gist');=0A= +remove_relation_file('db1',=20's5.t1_gin');=0A= +remove_relation_file('db1',=20's5.t1_brin');=0A= +remove_relation_file('db1',=20's5.t1_spgist');=0A+=0A= +corrupt_first_page('db1',=20's5.seq2');=0A+corrupt_first_page('db1',=20= 's5.t2_hash');=0A+corrupt_first_page('db1',=20's5.t2_gist');=0A= +corrupt_first_page('db1',=20's5.t2_gin');=0A+corrupt_first_page('db1',=20= 's5.t2_brin');=0A+corrupt_first_page('db1',=20's5.t2_spgist');=0A+=0A+=0A= +#=20Database=20'db2'=20corruptions=0A+#=0A+remove_relation_file('db2',=20= 's1.t1');=0A+remove_relation_file('db2',=20's1.t1_btree');=0A+=0A+=0A+#=20= Leave=20'db3'=20uncorrupted=0A+#=0A+=0A+=0A+#=20Standard=20first=20= arguments=20to=20TestLib=20functions=0A+my=20@cmd=20=3D=20('pg_amcheck',=20= '--quiet',=20'-p',=20$port);=0A+=0A+#=20The=20pg_amcheck=20command=20= itself=20should=20return=20a=20success=20exit=20status,=20even=0A+#=20= though=20tables=20and=20indexes=20are=20corrupt.=20=20An=20error=20code=20= returned=20would=20mean=20the=0A+#=20pg_amcheck=20command=20itself=20= failed,=20for=20example=20because=20a=20connection=20to=20the=0A+#=20= database=20could=20not=20be=20established.=0A+#=0A+#=20For=20these=20= checks,=20we're=20ignoring=20any=20corruption=20reported=20and=20= focusing=0A+#=20exclusively=20on=20the=20exit=20code=20from=20= pg_amcheck.=0A+#=0A+$node->command_ok(=0A+=09[=20@cmd,,=20'db1'=20],=0A+=09= 'pg_amcheck=20all=20schemas,=20tables=20and=20indexes=20in=20database=20= db1');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,,=20'db1',=20'db2',=20= 'db3'=20],=0A+=09'pg_amcheck=20all=20schemas,=20tables=20and=20indexes=20= in=20databases=20db1,=20db2=20and=20db3');=0A+=0A+$node->command_ok(=0A+=09= [=20@cmd,=20'--all'=20],=0A+=09'pg_amcheck=20all=20schemas,=20tables=20= and=20indexes=20in=20all=20databases');=0A+=0A+$node->command_ok(=0A+=09= [=20@cmd,=20'db1',=20'-s',=20's1'=20],=0A+=09'pg_amcheck=20all=20objects=20= in=20schema=20s1');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20'db1',=20= '-r',=20's*.t1'=20],=0A+=09'pg_amcheck=20all=20tables=20named=20t1=20and=20= their=20indexes');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20'db1',=20= '-i',=20'i*.idx',=20'-i',=20'idx.i*'=20],=0A+=09'pg_amcheck=20all=20= indexes=20with=20qualified=20names=20matching=20/i*.idx/=20or=20= /idx.i*/');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20= '--no-dependents',=20'db1',=20'-r',=20's*.t1'=20],=0A+=09'pg_amcheck=20= all=20tables=20with=20qualified=20names=20matching=20/s*.t1/');=0A+=0A= +$node->command_ok(=0A+=09[=20@cmd,=20'--no-dependents',=20'db1',=20= '-t',=20's*.t1',=20'-t',=20'foo*.bar*'=20],=0A+=09'pg_amcheck=20all=20= tables=20with=20qualified=20names=20matching=20/s*.t1/=20or=20= /foo*.bar*/');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20'db1',=20= '-T',=20't1'=20],=0A+=09'pg_amcheck=20everything=20except=20tables=20= named=20t1');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20'db1',=20'-S',=20= 's1',=20'-R',=20't1'=20],=0A+=09'pg_amcheck=20everything=20not=20named=20= t1=20nor=20in=20schema=20s1');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20= 'db1',=20'-t',=20'*.*.*'=20],=0A+=09'pg_amcheck=20all=20tables=20across=20= all=20databases=20and=20schemas');=0A+=0A+$node->command_ok(=0A+=09[=20= @cmd,=20'db1',=20'-t',=20'*.*.t1'=20],=0A+=09'pg_amcheck=20all=20tables=20= named=20t1=20across=20all=20databases=20and=20schemas');=0A+=0A= +$node->command_ok(=0A+=09[=20@cmd,=20'db1',=20'-t',=20'*.s1.*'=20],=0A+=09= 'pg_amcheck=20all=20tables=20across=20all=20databases=20in=20schemas=20= named=20s1');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20'db1',=20'-t',=20= 'db2.*.*'=20],=0A+=09'pg_amcheck=20all=20tables=20across=20all=20schemas=20= in=20database=20db2');=0A+=0A+$node->command_ok(=0A+=09[=20@cmd,=20= 'db1',=20'-t',=20'db2.*.*',=20'-t',=20'db3.*.*'=20],=0A+=09'pg_amcheck=20= all=20tables=20across=20all=20schemas=20in=20databases=20db2=20and=20= db3');=0A+=0A+#=20Scans=20of=20indexes=20in=20s1=20should=20detect=20the=20= specific=20corruption=20that=20we=20created=0A+#=20above.=20=20For=20= missing=20relation=20forks,=20we=20know=20what=20the=20error=20message=20= looks=0A+#=20like.=20=20For=20corrupted=20index=20pages,=20the=20error=20= might=20vary=20depending=20on=20how=20the=0A+#=20page=20was=20formatted=20= on=20disk,=20including=20variations=20due=20to=20alignment=20differences=0A= +#=20between=20platforms,=20so=20we=20accept=20any=20non-empty=20error=20= message.=0A+#=0A+$node->command_like(=0A+=09[=20@cmd,=20'--all',=20'-s',=20= 's1',=20'-i',=20't1_btree'=20],=0A+=09qr/index=20"t1_btree"=20lacks=20a=20= main=20relation=20fork/,=0A+=09'pg_amcheck=20index=20s1.t1_btree=20= reports=20missing=20main=20relation=20fork');=0A+=0A= +$node->command_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's1',=20'-i',=20= 't2_btree'=20],=0A+=09qr/.+/,=09=09=09#=20Any=20non-empty=20error=20= message=20is=20acceptable=0A+=09'pg_amcheck=20index=20s1.s2=20reports=20= index=20corruption');=0A+=0A+#=20Checking=20db1.s1=20should=20show=20no=20= corruptions=20if=20indexes=20are=20excluded=0A+$node->command_like(=0A+=09= [=20@cmd,=20'db1',=20'-s',=20's1',=20'--exclude-indexes'=20],=0A+=09= qr/^$/,=0A+=09'pg_amcheck=20of=20db1.s1=20excluding=20indexes');=0A+=0A= +#=20But=20checking=20across=20all=20databases=20in=20schema=20s1=20= should=20show=20corruptions=0A+#=20messages=20for=20tables=20in=20db2=0A= +$node->command_like(=0A+=09[=20@cmd,=20'--all',=20'-s',=20's1',=20= '--exclude-indexes'=20],=0A+=09qr/could=20not=20open=20file/,=0A+=09= 'pg_amcheck=20of=20schema=20s1=20across=20all=20databases=20but=20= excluding=20indexes');=0A+=0A+#=20Checking=20across=20a=20list=20of=20= databases=20should=20also=20work=0A+$node->command_like(=0A+=09[=20@cmd,=20= '-d',=20'db2',=20'-d',=20'db1',=20'-s',=20's1',=20'--exclude-indexes'=20= ],=0A+=09qr/could=20not=20open=20file/,=0A+=09'pg_amcheck=20of=20schema=20= s1=20across=20db1=20and=20db2=20but=20excluding=20indexes');=0A+=0A+#=20= In=20schema=20s3,=20the=20tables=20and=20indexes=20are=20both=20corrupt.=20= =20We=20should=20see=0A+#=20corruption=20messages=20on=20stdout,=20= nothing=20on=20stderr,=20and=20an=20exit=0A+#=20status=20of=20zero.=0A+#=0A= +$node->command_checks_all(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's3'=20],=0A= +=090,=0A+=09[=20qr/index=20"t1_btree"=20lacks=20a=20main=20relation=20= fork/,=0A+=09=20=20qr/could=20not=20open=20file/=20],=0A+=09[=20qr/^$/=20= ],=0A+=09'pg_amcheck=20schema=20s3=20reports=20table=20and=20index=20= errors');=0A+=0A+#=20In=20schema=20s2,=20only=20tables=20are=20corrupt.=20= =20Check=20that=20table=20corruption=20is=0A+#=20reported=20as=20= expected.=0A+#=0A+$node->command_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20= 's2',=20'-t',=20't1'=20],=0A+=09qr/could=20not=20open=20file/,=0A+=09= 'pg_amcheck=20in=20schema=20s2=20reports=20table=20corruption');=0A+=0A= +$node->command_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's2',=20'-t',=20= 't2'=20],=0A+=09qr/.+/,=09=09=09#=20Any=20non-empty=20error=20message=20= is=20acceptable=0A+=09'pg_amcheck=20in=20schema=20s2=20reports=20table=20= corruption');=0A+=0A+#=20In=20schema=20s4,=20only=20toast=20tables=20are=20= corrupt.=20=20Check=20that=20under=20default=0A+#=20options=20the=20= toast=20corruption=20is=20reported,=20but=20when=20excluding=20toast=20= we=20get=20no=0A+#=20error=20reports.=0A+$node->command_like(=0A+=09[=20= @cmd,=20'db1',=20'-s',=20's4'=20],=0A+=09qr/could=20not=20open=20file/,=0A= +=09'pg_amcheck=20in=20schema=20s4=20reports=20toast=20corruption');=0A+=0A= +$node->command_like(=0A+=09[=20@cmd,=20'--exclude-toast',=20= '--exclude-toast-pointers',=20'db1',=20'-s',=20's4'=20],=0A+=09qr/^$/,=09= =09=09#=20Empty=0A+=09'pg_amcheck=20in=20schema=20s4=20excluding=20toast=20= reports=20no=20corruption');=0A+=0A+#=20Check=20that=20no=20corruption=20= is=20reported=20in=20schema=20s5=0A+$node->command_like(=0A+=09[=20@cmd,=20= 'db1',=20'-s',=20's5'=20],=0A+=09qr/^$/,=09=09=09#=20Empty=0A+=09= 'pg_amcheck=20over=20schema=20s5=20reports=20no=20corruption');=0A+=0A= +$node->command_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's1',=20'-I',=20= 't1_btree',=20'-I',=20't2_btree'=20],=0A+=09qr/^$/,=09=09=09#=20Empty=0A= +=09'pg_amcheck=20over=20schema=20s1=20with=20corrupt=20indexes=20= excluded=20reports=20no=20corruption');=0A+=0A+$node->command_like(=0A+=09= [=20@cmd,=20'db1',=20'-s',=20's1',=20'--exclude-indexes'=20],=0A+=09= qr/^$/,=09=09=09#=20Empty=0A+=09'pg_amcheck=20over=20schema=20s1=20with=20= all=20indexes=20excluded=20reports=20no=20corruption');=0A+=0A= +$node->command_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's2',=20'-T',=20= 't1',=20'-T',=20't2'=20],=0A+=09qr/^$/,=09=09=09#=20Empty=0A+=09= 'pg_amcheck=20over=20schema=20s2=20with=20corrupt=20tables=20excluded=20= reports=20no=20corruption');=0A+=0A+#=20Check=20errors=20about=20bad=20= block=20range=20command=20line=20arguments.=20=20We=20use=20schema=20s5=0A= +#=20to=20avoid=20getting=20messages=20about=20corrupt=20tables=20or=20= indexes.=0A+command_fails_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's5',=20= '--startblock',=20'junk'=20],=0A+=09qr/relation=20starting=20block=20= argument=20contains=20garbage=20characters/,=0A+=09'pg_amcheck=20rejects=20= garbage=20startblock');=0A+=0A+command_fails_like(=0A+=09[=20@cmd,=20= 'db1',=20'-s',=20's5',=20'--endblock',=20'1234junk'=20],=0A+=09= qr/relation=20ending=20block=20argument=20contains=20garbage=20= characters/,=0A+=09'pg_amcheck=20rejects=20garbage=20endblock');=0A+=0A= +command_fails_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's5',=20= '--startblock',=20'5',=20'--endblock',=20'4'=20],=0A+=09qr/relation=20= ending=20block=20argument=20precedes=20starting=20block=20argument/,=0A+=09= 'pg_amcheck=20rejects=20invalid=20block=20range');=0A+=0A+#=20Check=20= bt_index_parent_check=20alternates.=20=20We=20don't=20create=20any=20= index=20corruption=0A+#=20that=20would=20behave=20differently=20under=20= these=20modes,=20so=20just=20smoke=20test=20that=20the=0A+#=20arguments=20= are=20handled=20sensibly.=0A+=0A+$node->command_like(=0A+=09[=20@cmd,=20= 'db1',=20'-s',=20's1',=20'-i',=20't1_btree',=20'--parent-check'=20],=0A+=09= qr/index=20"t1_btree"=20lacks=20a=20main=20relation=20fork/,=0A+=09= 'pg_amcheck=20smoke=20test=20--parent-check');=0A+=0A= +$node->command_like(=0A+=09[=20@cmd,=20'db1',=20'-s',=20's1',=20'-i',=20= 't1_btree',=20'--heapallindexed',=20'--rootdescend'=20],=0A+=09qr/index=20= "t1_btree"=20lacks=20a=20main=20relation=20fork/,=0A+=09'pg_amcheck=20= smoke=20test=20--heapallindexed=20--rootdescend');=0Adiff=20--git=20= a/contrib/pg_amcheck/t/004_verify_heapam.pl=20= b/contrib/pg_amcheck/t/004_verify_heapam.pl=0Anew=20file=20mode=20100644=0A= index=200000000000..7e71d612fc=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/t/004_verify_heapam.pl=0A@@=20-0,0=20+1,496=20@@=0A= +use=20strict;=0A+use=20warnings;=0A+=0A+use=20PostgresNode;=0A+use=20= TestLib;=0A+=0A+use=20Test::More=20tests=20=3D>=2022;=0A+=0A+#=20This=20= regression=20test=20demonstrates=20that=20the=20pg_amcheck=20binary=20= supplied=20with=0A+#=20the=20pg_amcheck=20contrib=20module=20correctly=20= identifies=20specific=20kinds=20of=0A+#=20corruption=20within=20pages.=20= =20To=20test=20this,=20we=20need=20a=20mechanism=20to=20create=20corrupt=0A= +#=20pages=20with=20predictable,=20repeatable=20corruption.=20=20The=20= postgres=20backend=20cannot=0A+#=20be=20expected=20to=20help=20us=20with=20= this,=20as=20its=20design=20is=20not=20consistent=20with=20the=0A+#=20= goal=20of=20intentionally=20corrupting=20pages.=0A+#=0A+#=20Instead,=20= we=20create=20a=20table=20to=20corrupt,=20and=20with=20careful=20= consideration=20of=20how=0A+#=20postgresql=20lays=20out=20heap=20pages,=20= we=20seek=20to=20offsets=20within=20the=20page=20and=0A+#=20overwrite=20= deliberately=20chosen=20bytes=20with=20specific=20values=20calculated=20= to=0A+#=20corrupt=20the=20page=20in=20expected=20ways.=20=20We=20then=20= verify=20that=20pg_amcheck=20reports=0A+#=20the=20corruption,=20and=20= that=20it=20runs=20without=20crashing.=20=20Note=20that=20the=20backend=0A= +#=20cannot=20simply=20be=20started=20to=20run=20queries=20against=20the=20= corrupt=20table,=20as=20the=0A+#=20backend=20will=20crash,=20at=20least=20= for=20some=20of=20the=20corruption=20types=20we=20generate.=0A+#=0A+#=20= Autovacuum=20potentially=20touching=20the=20table=20in=20the=20= background=20makes=20the=20exact=0A+#=20behavior=20of=20this=20test=20= harder=20to=20reason=20about.=20=20We=20turn=20it=20off=20to=20keep=20= things=0A+#=20simpler.=20=20We=20use=20a=20"belt=20and=20suspenders"=20= approach,=20turning=20it=20off=20for=20the=0A+#=20system=20generally=20= in=20postgresql.conf,=20and=20turning=20it=20off=20specifically=20for=20= the=0A+#=20test=20table.=0A+#=0A+#=20This=20test=20depends=20on=20the=20= table=20being=20written=20to=20the=20heap=20file=20exactly=20as=20we=0A= +#=20expect=20it=20to=20be,=20so=20we=20take=20care=20to=20arrange=20the=20= columns=20of=20the=20table,=20and=0A+#=20insert=20rows=20of=20the=20= table,=20that=20give=20predictable=20sizes=20and=20locations=20within=0A= +#=20the=20table=20page.=0A+#=0A+#=20The=20HeapTupleHeaderData=20has=20= 23=20bytes=20of=20fixed=20size=20fields=20before=20the=20variable=0A+#=20= length=20t_bits[]=20array.=20=20We=20have=20exactly=203=20columns=20in=20= the=20table,=20so=20natts=20=3D=203,=0A+#=20t_bits=20is=201=20byte=20= long,=20and=20t_hoff=20=3D=20MAXALIGN(23=20+=201)=20=3D=2024.=0A+#=0A+#=20= We're=20not=20too=20fussy=20about=20which=20datatypes=20we=20use=20for=20= the=20test,=20but=20we=20do=20care=0A+#=20about=20some=20specific=20= properties.=20=20We'd=20like=20to=20test=20both=20fixed=20size=20and=0A= +#=20varlena=20types.=20=20We'd=20like=20some=20varlena=20data=20inline=20= and=20some=20toasted.=20=20And=0A+#=20we'd=20like=20the=20layout=20of=20= the=20table=20such=20that=20the=20datums=20land=20at=20predictable=0A+#=20= offsets=20within=20the=20tuple.=20=20We=20choose=20a=20structure=20= without=20padding=20on=20all=0A+#=20supported=20architectures:=0A+#=0A+#=20= =09a=20BIGINT=0A+#=09b=20TEXT=0A+#=09c=20TEXT=0A+#=0A+#=20We=20always=20= insert=20a=207-ascii=20character=20string=20into=20field=20'b',=20which=20= with=20a=0A+#=201-byte=20varlena=20header=20gives=20an=208=20byte=20= inline=20value.=20=20We=20always=20insert=20a=20long=0A+#=20text=20= string=20in=20field=20'c',=20long=20enough=20to=20force=20toast=20= storage.=0A+#=0A+#=20We=20choose=20to=20read=20and=20write=20binary=20= copies=20of=20our=20table's=20tuples,=20using=20perl's=0A+#=20pack()=20= and=20unpack()=20functions.=20=20Perl=20uses=20a=20packing=20code=20= system=20in=20which:=0A+#=0A+#=09L=20=3D=20"Unsigned=2032-bit=20Long",=0A= +#=09S=20=3D=20"Unsigned=2016-bit=20Short",=0A+#=09C=20=3D=20"Unsigned=20= 8-bit=20Octet",=0A+#=09c=20=3D=20"signed=208-bit=20octet",=0A+#=09q=20=3D=20= "signed=2064-bit=20quadword"=0A+#=0A+#=20Each=20tuple=20in=20our=20table=20= has=20a=20layout=20as=20follows:=0A+#=0A+#=20=20=20=20xx=20xx=20xx=20xx=20= =20=20=20=20=20=20=20=20=20=20=20t_xmin:=20xxxx=09=09offset=20=3D=200=09=09= L=0A+#=20=20=20=20xx=20xx=20xx=20xx=20=20=20=20=20=20=20=20=20=20=20=20= t_xmax:=20xxxx=09=09offset=20=3D=204=09=09L=0A+#=20=20=20=20xx=20xx=20xx=20= xx=20=20=20=20=20=20=20=20=20=20t_field3:=20xxxx=09=09offset=20=3D=208=09= =09L=0A+#=20=20=20=20xx=20xx=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20bi_hi:=20xx=09=09=09offset=20=3D=2012=09=09S=0A+#=20=20=20=20= xx=20xx=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20bi_lo:=20= xx=09=09=09offset=20=3D=2014=09=09S=0A+#=20=20=20=20xx=20xx=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20ip_posid:=20xx=09=09=09offset=20=3D=20= 16=09=09S=0A+#=20=20=20=20xx=20xx=20=20=20=20=20=20=20=20=20=20=20=20=20= t_infomask2:=20xx=09=09=09offset=20=3D=2018=09=09S=0A+#=20=20=20=20xx=20= xx=20=20=20=20=20=20=20=20=20=20=20=20=20=20t_infomask:=20xx=09=09=09= offset=20=3D=2020=09=09S=0A+#=20=20=20=20xx=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20t_hoff:=20x=09=09=09offset=20=3D=2022=09= =09C=0A+#=20=20=20=20xx=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20t_bits:=20x=09=09=09offset=20=3D=2023=09=09C=0A+#=20=20=20=20= xx=20xx=20xx=20xx=20xx=20xx=20xx=20xx=20=20=20'a':=20xxxxxxxx=09offset=20= =3D=2024=09=09q=0A+#=20=20=20=20xx=20xx=20xx=20xx=20xx=20xx=20xx=20xx=20=20= =20'b':=20xxxxxxxx=09offset=20=3D=2032=09=09Cccccccc=0A+#=20=20=20=20xx=20= xx=20xx=20xx=20xx=20xx=20xx=20xx=20=20=20'c':=20xxxxxxxx=09offset=20=3D=20= 40=09=09SSSS=0A+#=20=20=20=20xx=20xx=20xx=20xx=20xx=20xx=20xx=20xx=20=20=20= =20=20=20:=20xxxxxxxx=09=20...continued=09SSSS=0A+#=20=20=20=20xx=20xx=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20:=20= xx=20=20=20=20=20=20=09=20...continued=09S=0A+#=0A+#=20We=20could=20= choose=20to=20read=20and=20write=20columns=20'b'=20and=20'c'=20in=20= other=20ways,=20but=0A+#=20it=20is=20convenient=20enough=20to=20do=20it=20= this=20way.=20=20We=20define=20packing=20code=0A+#=20constants=20here,=20= where=20they=20can=20be=20compared=20easily=20against=20the=20layout.=0A= +=0A+use=20constant=20HEAPTUPLE_PACK_CODE=20=3D>=20= 'LLLSSSSSCCqCcccccccSSSSSSSSS';=0A+use=20constant=20= HEAPTUPLE_PACK_LENGTH=20=3D>=2058;=20=20=20=20=20#=20Total=20size=0A+=0A= +#=20Read=20a=20tuple=20of=20our=20table=20from=20a=20heap=20page.=0A+#=0A= +#=20Takes=20an=20open=20filehandle=20to=20the=20heap=20file,=20and=20= the=20offset=20of=20the=20tuple.=0A+#=0A+#=20Rather=20than=20returning=20= the=20binary=20data=20from=20the=20file,=20unpacks=20the=20data=20into=20= a=0A+#=20perl=20hash=20with=20named=20fields.=20=20These=20fields=20= exactly=20match=20the=20ones=20understood=0A+#=20by=20write_tuple(),=20= below.=20=20Returns=20a=20reference=20to=20this=20hash.=0A+#=0A+sub=20= read_tuple=20($$)=0A+{=0A+=09my=20($fh,=20$offset)=20=3D=20@_;=0A+=09my=20= ($buffer,=20%tup);=0A+=09seek($fh,=20$offset,=200);=0A+=09sysread($fh,=20= $buffer,=20HEAPTUPLE_PACK_LENGTH);=0A+=0A+=09@_=20=3D=20= unpack(HEAPTUPLE_PACK_CODE,=20$buffer);=0A+=09%tup=20=3D=20(t_xmin=20=3D>=20= shift,=0A+=09=09=09t_xmax=20=3D>=20shift,=0A+=09=09=09t_field3=20=3D>=20= shift,=0A+=09=09=09bi_hi=20=3D>=20shift,=0A+=09=09=09bi_lo=20=3D>=20= shift,=0A+=09=09=09ip_posid=20=3D>=20shift,=0A+=09=09=09t_infomask2=20=3D>= =20shift,=0A+=09=09=09t_infomask=20=3D>=20shift,=0A+=09=09=09t_hoff=20=3D>= =20shift,=0A+=09=09=09t_bits=20=3D>=20shift,=0A+=09=09=09a=20=3D>=20= shift,=0A+=09=09=09b_header=20=3D>=20shift,=0A+=09=09=09b_body1=20=3D>=20= shift,=0A+=09=09=09b_body2=20=3D>=20shift,=0A+=09=09=09b_body3=20=3D>=20= shift,=0A+=09=09=09b_body4=20=3D>=20shift,=0A+=09=09=09b_body5=20=3D>=20= shift,=0A+=09=09=09b_body6=20=3D>=20shift,=0A+=09=09=09b_body7=20=3D>=20= shift,=0A+=09=09=09c1=20=3D>=20shift,=0A+=09=09=09c2=20=3D>=20shift,=0A+=09= =09=09c3=20=3D>=20shift,=0A+=09=09=09c4=20=3D>=20shift,=0A+=09=09=09c5=20= =3D>=20shift,=0A+=09=09=09c6=20=3D>=20shift,=0A+=09=09=09c7=20=3D>=20= shift,=0A+=09=09=09c8=20=3D>=20shift,=0A+=09=09=09c9=20=3D>=20shift);=0A= +=09#=20Stitch=20together=20the=20text=20for=20column=20'b'=0A+=09= $tup{b}=20=3D=20join('',=20map=20{=20chr($tup{"b_body$_"})=20}=20= (1..7));=0A+=09return=20\%tup;=0A+}=0A+=0A+#=20Write=20a=20tuple=20of=20= our=20table=20to=20a=20heap=20page.=0A+#=0A+#=20Takes=20an=20open=20= filehandle=20to=20the=20heap=20file,=20the=20offset=20of=20the=20tuple,=20= and=20a=0A+#=20reference=20to=20a=20hash=20with=20the=20tuple=20values,=20= as=20returned=20by=20read_tuple().=0A+#=20Writes=20the=20tuple=20fields=20= from=20the=20hash=20into=20the=20heap=20file.=0A+#=0A+#=20The=20purpose=20= of=20this=20function=20is=20to=20write=20a=20tuple=20back=20to=20disk=20= with=20some=0A+#=20subset=20of=20fields=20modified.=20=20The=20function=20= does=20no=20error=20checking.=20=20Use=0A+#=20cautiously.=0A+#=0A+sub=20= write_tuple($$$)=0A+{=0A+=09my=20($fh,=20$offset,=20$tup)=20=3D=20@_;=0A= +=09my=20$buffer=20=3D=20pack(HEAPTUPLE_PACK_CODE,=0A+=09=09=09=09=09= $tup->{t_xmin},=0A+=09=09=09=09=09$tup->{t_xmax},=0A+=09=09=09=09=09= $tup->{t_field3},=0A+=09=09=09=09=09$tup->{bi_hi},=0A+=09=09=09=09=09= $tup->{bi_lo},=0A+=09=09=09=09=09$tup->{ip_posid},=0A+=09=09=09=09=09= $tup->{t_infomask2},=0A+=09=09=09=09=09$tup->{t_infomask},=0A+=09=09=09=09= =09$tup->{t_hoff},=0A+=09=09=09=09=09$tup->{t_bits},=0A+=09=09=09=09=09= $tup->{a},=0A+=09=09=09=09=09$tup->{b_header},=0A+=09=09=09=09=09= $tup->{b_body1},=0A+=09=09=09=09=09$tup->{b_body2},=0A+=09=09=09=09=09= $tup->{b_body3},=0A+=09=09=09=09=09$tup->{b_body4},=0A+=09=09=09=09=09= $tup->{b_body5},=0A+=09=09=09=09=09$tup->{b_body6},=0A+=09=09=09=09=09= $tup->{b_body7},=0A+=09=09=09=09=09$tup->{c1},=0A+=09=09=09=09=09= $tup->{c2},=0A+=09=09=09=09=09$tup->{c3},=0A+=09=09=09=09=09$tup->{c4},=0A= +=09=09=09=09=09$tup->{c5},=0A+=09=09=09=09=09$tup->{c6},=0A+=09=09=09=09= =09$tup->{c7},=0A+=09=09=09=09=09$tup->{c8},=0A+=09=09=09=09=09= $tup->{c9});=0A+=09seek($fh,=20$offset,=200);=0A+=09syswrite($fh,=20= $buffer,=20HEAPTUPLE_PACK_LENGTH);=0A+=09return;=0A+}=0A+=0A+#=20Set=20= umask=20so=20test=20directories=20and=20files=20are=20created=20with=20= default=20permissions=0A+umask(0077);=0A+=0A+#=20Set=20up=20the=20node.=20= =20Once=20we=20create=20and=20corrupt=20the=20table,=0A+#=20autovacuum=20= workers=20visiting=20the=20table=20could=20crash=20the=20backend.=0A+#=20= Disable=20autovacuum=20so=20that=20won't=20happen.=0A+my=20$node=20=3D=20= get_new_node('test');=0A+$node->init;=0A= +$node->append_conf('postgresql.conf',=20'autovacuum=3Doff');=0A+=0A+#=20= Start=20the=20node=20and=20load=20the=20extensions.=20=20We=20depend=20= on=20both=0A+#=20amcheck=20and=20pageinspect=20for=20this=20test.=0A= +$node->start;=0A+my=20$port=20=3D=20$node->port;=0A+my=20$pgdata=20=3D=20= $node->data_dir;=0A+$node->safe_psql('postgres',=20"CREATE=20EXTENSION=20= amcheck");=0A+$node->safe_psql('postgres',=20"CREATE=20EXTENSION=20= pageinspect");=0A+=0A+#=20Get=20a=20non-zero=20datfrozenxid=0A= +$node->safe_psql('postgres',=20qq(VACUUM=20FREEZE));=0A+=0A+#=20Create=20= the=20test=20table=20with=20precisely=20the=20schema=20that=20our=20= corruption=20function=0A+#=20expects.=0A+$node->safe_psql(=0A+=09= 'postgres',=20qq(=0A+=09=09CREATE=20TABLE=20public.test=20(a=20BIGINT,=20= b=20TEXT,=20c=20TEXT);=0A+=09=09ALTER=20TABLE=20public.test=20SET=20= (autovacuum_enabled=3Dfalse);=0A+=09=09ALTER=20TABLE=20public.test=20= ALTER=20COLUMN=20c=20SET=20STORAGE=20EXTERNAL;=0A+=09=09CREATE=20INDEX=20= test_idx=20ON=20public.test(a,=20b);=0A+=09));=0A+=0A+#=20We=20want=20(0=20= <=20datfrozenxid=20<=20test.relfrozenxid).=20=20To=20achieve=20this,=20= we=20freeze=0A+#=20an=20otherwise=20unused=20table,=20public.junk,=20= prior=20to=20inserting=20data=20and=20freezing=0A+#=20public.test=0A= +$node->safe_psql(=0A+=09'postgres',=20qq(=0A+=09=09CREATE=20TABLE=20= public.junk=20AS=20SELECT=20'junk'::TEXT=20AS=20junk_column;=0A+=09=09= ALTER=20TABLE=20public.junk=20SET=20(autovacuum_enabled=3Dfalse);=0A+=09=09= VACUUM=20FREEZE=20public.junk=0A+=09));=0A+=0A+my=20$rel=20=3D=20= $node->safe_psql('postgres',=20qq(SELECT=20= pg_relation_filepath('public.test')));=0A+my=20$relpath=20=3D=20= "$pgdata/$rel";=0A+=0A+#=20Insert=20data=20and=20freeze=20public.test=0A= +use=20constant=20ROWCOUNT=20=3D>=2016;=0A+$node->safe_psql('postgres',=20= qq(=0A+=09INSERT=20INTO=20public.test=20(a,=20b,=20c)=0A+=09=09VALUES=20= (=0A+=09=09=0912345678,=0A+=09=09=09'abcdefg',=0A+=09=09=09repeat('w',=20= 10000)=0A+=09=09);=0A+=09VACUUM=20FREEZE=20public.test=0A+=09))=20for=20= (1..ROWCOUNT);=0A+=0A+my=20$relfrozenxid=20=3D=20= $node->safe_psql('postgres',=0A+=09q(select=20relfrozenxid=20from=20= pg_class=20where=20relname=20=3D=20'test'));=0A+my=20$datfrozenxid=20=3D=20= $node->safe_psql('postgres',=0A+=09q(select=20datfrozenxid=20from=20= pg_database=20where=20datname=20=3D=20'postgres'));=0A+=0A+#=20Find=20= where=20each=20of=20the=20tuples=20is=20located=20on=20the=20page.=0A+my=20= @lp_off;=0A+for=20my=20$tup=20(0..ROWCOUNT-1)=0A+{=0A+=09push=20= (@lp_off,=20$node->safe_psql('postgres',=20qq(=0A+select=20lp_off=20from=20= heap_page_items(get_raw_page('test',=20'main',=200))=0A+=09offset=20$tup=20= limit=201)));=0A+}=0A+=0A+#=20Check=20that=20pg_amcheck=20runs=20against=20= the=20uncorrupted=20table=20without=20error.=0A= +$node->command_ok(['pg_amcheck',=20'-p',=20$port,=20'postgres'],=0A+=09=09= =09=09=20=20'pg_amcheck=20test=20table,=20prior=20to=20corruption');=0A+=0A= +#=20Check=20that=20pg_amcheck=20runs=20against=20the=20uncorrupted=20= table=20and=20index=20without=20error.=0A= +$node->command_ok(['pg_amcheck',=20'-p',=20$port,=20'postgres'],=0A+=09=09= =09=09=20=20'pg_amcheck=20test=20table=20and=20index,=20prior=20to=20= corruption');=0A+=0A+$node->stop;=0A+=0A+#=20Sanity=20check=20that=20our=20= 'test'=20table=20has=20a=20relfrozenxid=20newer=20than=20the=0A+#=20= datfrozenxid=20for=20the=20database,=20and=20that=20the=20datfrozenxid=20= is=20greater=20than=20the=0A+#=20first=20normal=20xid.=20=20We=20rely=20= on=20these=20invariants=20in=20some=20of=20our=20tests.=0A+if=20= ($datfrozenxid=20<=3D=203=20||=20$datfrozenxid=20>=3D=20$relfrozenxid)=0A= +{=0A+=09fail('Xid=20thresholds=20not=20as=20expected');=0A+=09= $node->clean_node;=0A+=09exit;=0A+}=0A+=0A+#=20Some=20#define=20= constants=20from=20access/htup_details.h=20for=20use=20while=20= corrupting.=0A+use=20constant=20HEAP_HASNULL=20=20=20=20=20=20=20=20=20=20= =20=20=3D>=200x0001;=0A+use=20constant=20HEAP_XMAX_LOCK_ONLY=20=20=20=20=20= =3D>=200x0080;=0A+use=20constant=20HEAP_XMIN_COMMITTED=20=20=20=20=20=3D>=20= 0x0100;=0A+use=20constant=20HEAP_XMIN_INVALID=20=20=20=20=20=20=20=3D>=20= 0x0200;=0A+use=20constant=20HEAP_XMAX_COMMITTED=20=20=20=20=20=3D>=20= 0x0400;=0A+use=20constant=20HEAP_XMAX_INVALID=20=20=20=20=20=20=20=3D>=20= 0x0800;=0A+use=20constant=20HEAP_NATTS_MASK=20=20=20=20=20=20=20=20=20=3D>= =200x07FF;=0A+use=20constant=20HEAP_XMAX_IS_MULTI=20=20=20=20=20=20=3D>=20= 0x1000;=0A+use=20constant=20HEAP_KEYS_UPDATED=20=20=20=20=20=20=20=3D>=20= 0x2000;=0A+=0A+#=20Helper=20function=20to=20generate=20a=20regular=20= expression=20matching=20the=20header=20we=0A+#=20expect=20= verify_heapam()=20to=20return=20given=20which=20fields=20we=20expect=20= to=20be=20non-null.=0A+sub=20header=0A+{=0A+=09my=20($blkno,=20$offnum,=20= $attnum)=20=3D=20@_;=0A+=09return=20qr/relation=20= postgres\.public\.test,=20block=20$blkno,=20offset=20$offnum,=20= attribute=20$attnum\s+/ms=0A+=09=09if=20(defined=20$attnum);=0A+=09= return=20qr/relation=20postgres\.public\.test,=20block=20$blkno,=20= offset=20$offnum\s+/ms=0A+=09=09if=20(defined=20$offnum);=0A+=09return=20= qr/relation=20postgres\.public\.test\s+/ms=0A+=09=09if=20(defined=20= $blkno);=0A+=09return=20qr/relation=20postgres\.public\.test\s+/ms;=0A+}=0A= +=0A+#=20Corrupt=20the=20tuples,=20one=20type=20of=20corruption=20per=20= tuple.=20=20Some=20types=20of=0A+#=20corruption=20cause=20verify_heapam=20= to=20skip=20to=20the=20next=20tuple=20without=0A+#=20performing=20any=20= remaining=20checks,=20so=20we=20can't=20exercise=20the=20system=20= properly=20if=0A+#=20we=20focus=20all=20our=20corruption=20on=20a=20= single=20tuple.=0A+#=0A+my=20@expected;=0A+my=20$file;=0A+open($file,=20= '+<',=20$relpath);=0A+binmode=20$file;=0A+=0A+for=20(my=20$tupidx=20=3D=20= 0;=20$tupidx=20<=20ROWCOUNT;=20$tupidx++)=0A+{=0A+=09my=20$offnum=20=3D=20= $tupidx=20+=201;=20=20#=20offnum=20is=201-based,=20not=20zero-based=0A+=09= my=20$offset=20=3D=20$lp_off[$tupidx];=0A+=09my=20$tup=20=3D=20= read_tuple($file,=20$offset);=0A+=0A+=09#=20Sanity-check=20that=20the=20= data=20appears=20on=20the=20page=20where=20we=20expect.=0A+=09if=20= ($tup->{a}=20ne=20'12345678'=20||=20$tup->{b}=20ne=20'abcdefg')=0A+=09{=0A= +=09=09fail('Page=20layout=20differs=20from=20our=20expectations');=0A+=09= =09$node->clean_node;=0A+=09=09exit;=0A+=09}=0A+=0A+=09my=20$header=20=3D=20= header(0,=20$offnum,=20undef);=0A+=09if=20($offnum=20=3D=3D=201)=0A+=09{=0A= +=09=09#=20Corruptly=20set=20xmin=20<=20relfrozenxid=0A+=09=09my=20$xmin=20= =3D=20$relfrozenxid=20-=201;=0A+=09=09$tup->{t_xmin}=20=3D=20$xmin;=0A+=09= =09$tup->{t_infomask}=20&=3D=20~HEAP_XMIN_COMMITTED;=0A+=09=09= $tup->{t_infomask}=20&=3D=20~HEAP_XMIN_INVALID;=0A+=0A+=09=09#=20= Expected=20corruption=20report=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${header}xmin=20$xmin=20precedes=20relation=20freeze=20threshold=20= 0:\d+/;=0A+=09}=0A+=09if=20($offnum=20=3D=3D=202)=0A+=09{=0A+=09=09#=20= Corruptly=20set=20xmin=20<=20datfrozenxid=0A+=09=09my=20$xmin=20=3D=203;=0A= +=09=09$tup->{t_xmin}=20=3D=20$xmin;=0A+=09=09$tup->{t_infomask}=20&=3D=20= ~HEAP_XMIN_COMMITTED;=0A+=09=09$tup->{t_infomask}=20&=3D=20= ~HEAP_XMIN_INVALID;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${$header}xmin=20$xmin=20precedes=20oldest=20valid=20transaction=20ID=20= 0:\d+/;=0A+=09}=0A+=09elsif=20($offnum=20=3D=3D=203)=0A+=09{=0A+=09=09#=20= Corruptly=20set=20xmin=20<=20datfrozenxid,=20further=20back,=20noting=20= circularity=0A+=09=09#=20of=20xid=20comparison.=20=20For=20a=20new=20= cluster=20with=20epoch=20=3D=200,=20the=20corrupt=0A+=09=09#=20xmin=20= will=20be=20interpreted=20as=20in=20the=20future=0A+=09=09$tup->{t_xmin}=20= =3D=204026531839;=0A+=09=09$tup->{t_infomask}=20&=3D=20= ~HEAP_XMIN_COMMITTED;=0A+=09=09$tup->{t_infomask}=20&=3D=20= ~HEAP_XMIN_INVALID;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${$header}xmin=204026531839=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=200:\d+/;=0A+=09}=0A+=09elsif=20($offnum=20=3D=3D=204)=0A= +=09{=0A+=09=09#=20Corruptly=20set=20xmax=20<=20relminmxid;=0A+=09=09= $tup->{t_xmax}=20=3D=204026531839;=0A+=09=09$tup->{t_infomask}=20&=3D=20= ~HEAP_XMAX_INVALID;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${$header}xmax=204026531839=20equals=20or=20exceeds=20next=20valid=20= transaction=20ID=200:\d+/;=0A+=09}=0A+=09elsif=20($offnum=20=3D=3D=205)=0A= +=09{=0A+=09=09#=20Corrupt=20the=20tuple=20t_hoff,=20but=20keep=20it=20= aligned=20properly=0A+=09=09$tup->{t_hoff}=20+=3D=20128;=0A+=0A+=09=09= push=20@expected,=0A+=09=09=09qr/${$header}data=20begins=20at=20offset=20= 152=20beyond=20the=20tuple=20length=2058/,=0A+=09=09=09= qr/${$header}tuple=20data=20should=20begin=20at=20byte=2024,=20but=20= actually=20begins=20at=20byte=20152=20\(3=20attributes,=20no=20nulls\)/;=0A= +=09}=0A+=09elsif=20($offnum=20=3D=3D=206)=0A+=09{=0A+=09=09#=20Corrupt=20= the=20tuple=20t_hoff,=20wrong=20alignment=0A+=09=09$tup->{t_hoff}=20+=3D=20= 3;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09qr/${$header}tuple=20data=20= should=20begin=20at=20byte=2024,=20but=20actually=20begins=20at=20byte=20= 27=20\(3=20attributes,=20no=20nulls\)/;=0A+=09}=0A+=09elsif=20($offnum=20= =3D=3D=207)=0A+=09{=0A+=09=09#=20Corrupt=20the=20tuple=20t_hoff,=20= underflow=20but=20correct=20alignment=0A+=09=09$tup->{t_hoff}=20-=3D=20= 8;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09qr/${$header}tuple=20data=20= should=20begin=20at=20byte=2024,=20but=20actually=20begins=20at=20byte=20= 16=20\(3=20attributes,=20no=20nulls\)/;=0A+=09}=0A+=09elsif=20($offnum=20= =3D=3D=208)=0A+=09{=0A+=09=09#=20Corrupt=20the=20tuple=20t_hoff,=20= underflow=20and=20wrong=20alignment=0A+=09=09$tup->{t_hoff}=20-=3D=203;=0A= +=0A+=09=09push=20@expected,=0A+=09=09=09qr/${$header}tuple=20data=20= should=20begin=20at=20byte=2024,=20but=20actually=20begins=20at=20byte=20= 21=20\(3=20attributes,=20no=20nulls\)/;=0A+=09}=0A+=09elsif=20($offnum=20= =3D=3D=209)=0A+=09{=0A+=09=09#=20Corrupt=20the=20tuple=20to=20look=20= like=20it=20has=20lots=20of=20attributes,=20not=20just=203=0A+=09=09= $tup->{t_infomask2}=20|=3D=20HEAP_NATTS_MASK;=0A+=0A+=09=09push=20= @expected,=0A+=09=09=09qr/${$header}number=20of=20attributes=202047=20= exceeds=20maximum=20expected=20for=20table=203/;=0A+=09}=0A+=09elsif=20= ($offnum=20=3D=3D=2010)=0A+=09{=0A+=09=09#=20Corrupt=20the=20tuple=20to=20= look=20like=20it=20has=20lots=20of=20attributes,=20some=20of=0A+=09=09#=20= them=20null.=20=20This=20falsely=20creates=20the=20impression=20that=20= the=20t_bits=0A+=09=09#=20array=20is=20longer=20than=20just=20one=20= byte,=20but=20t_hoff=20still=20says=20otherwise.=0A+=09=09= $tup->{t_infomask}=20|=3D=20HEAP_HASNULL;=0A+=09=09$tup->{t_infomask2}=20= |=3D=20HEAP_NATTS_MASK;=0A+=09=09$tup->{t_bits}=20=3D=200xAA;=0A+=0A+=09=09= push=20@expected,=0A+=09=09=09qr/${$header}tuple=20data=20should=20begin=20= at=20byte=20280,=20but=20actually=20begins=20at=20byte=2024=20\(2047=20= attributes,=20has=20nulls\)/;=0A+=09}=0A+=09elsif=20($offnum=20=3D=3D=20= 11)=0A+=09{=0A+=09=09#=20Same=20as=20above,=20but=20this=20time=20t_hoff=20= plays=20along=0A+=09=09$tup->{t_infomask}=20|=3D=20HEAP_HASNULL;=0A+=09=09= $tup->{t_infomask2}=20|=3D=20(HEAP_NATTS_MASK=20&=200x40);=0A+=09=09= $tup->{t_bits}=20=3D=200xAA;=0A+=09=09$tup->{t_hoff}=20=3D=2032;=0A+=0A+=09= =09push=20@expected,=0A+=09=09=09qr/${$header}number=20of=20attributes=20= 67=20exceeds=20maximum=20expected=20for=20table=203/;=0A+=09}=0A+=09= elsif=20($offnum=20=3D=3D=2012)=0A+=09{=0A+=09=09#=20Corrupt=20the=20= bits=20in=20column=20'b'=201-byte=20varlena=20header=0A+=09=09= $tup->{b_header}=20=3D=200x80;=0A+=0A+=09=09$header=20=3D=20header(0,=20= $offnum,=201);=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${header}attribute=201=20with=20length=204294967295=20ends=20at=20= offset=20416848000=20beyond=20total=20tuple=20length=2058/;=0A+=09}=0A+=09= elsif=20($offnum=20=3D=3D=2013)=0A+=09{=0A+=09=09#=20Corrupt=20the=20= bits=20in=20column=20'c'=20toast=20pointer=0A+=09=09$tup->{c6}=20=3D=20= 41;=0A+=09=09$tup->{c7}=20=3D=2041;=0A+=0A+=09=09$header=20=3D=20= header(0,=20$offnum,=202);=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${header}final=20toast=20chunk=20number=200=20differs=20from=20= expected=20value=206/,=0A+=09=09=09qr/${header}toasted=20value=20for=20= attribute=202=20missing=20from=20toast=20table/;=0A+=09}=0A+=09elsif=20= ($offnum=20=3D=3D=2014)=0A+=09{=0A+=09=09#=20Set=20both=20= HEAP_XMAX_LOCK_ONLY=20and=20HEAP_KEYS_UPDATED=0A+=09=09= $tup->{t_infomask}=20|=3D=20HEAP_XMAX_LOCK_ONLY;=0A+=09=09= $tup->{t_infomask2}=20|=3D=20HEAP_KEYS_UPDATED;=0A+=0A+=09=09push=20= @expected,=0A+=09=09=09qr/${header}tuple=20is=20marked=20as=20only=20= locked,=20but=20also=20claims=20key=20columns=20were=20updated/;=0A+=09}=0A= +=09elsif=20($offnum=20=3D=3D=2015)=0A+=09{=0A+=09=09#=20Set=20both=20= HEAP_XMAX_COMMITTED=20and=20HEAP_XMAX_IS_MULTI=0A+=09=09= $tup->{t_infomask}=20|=3D=20HEAP_XMAX_COMMITTED;=0A+=09=09= $tup->{t_infomask}=20|=3D=20HEAP_XMAX_IS_MULTI;=0A+=09=09$tup->{t_xmax}=20= =3D=204;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${header}multitransaction=20ID=204=20equals=20or=20exceeds=20next=20= valid=20multitransaction=20ID=201/;=0A+=09}=0A+=09elsif=20($offnum=20=3D=3D= =2016)=09#=20Last=20offnum=20must=20equal=20ROWCOUNT=0A+=09{=0A+=09=09#=20= Set=20both=20HEAP_XMAX_COMMITTED=20and=20HEAP_XMAX_IS_MULTI=0A+=09=09= $tup->{t_infomask}=20|=3D=20HEAP_XMAX_COMMITTED;=0A+=09=09= $tup->{t_infomask}=20|=3D=20HEAP_XMAX_IS_MULTI;=0A+=09=09$tup->{t_xmax}=20= =3D=204000000000;=0A+=0A+=09=09push=20@expected,=0A+=09=09=09= qr/${header}multitransaction=20ID=204000000000=20precedes=20relation=20= minimum=20multitransaction=20ID=20threshold=201/;=0A+=09}=0A+=09= write_tuple($file,=20$offset,=20$tup);=0A+}=0A+close($file);=0A= +$node->start;=0A+=0A+#=20Run=20pg_amcheck=20against=20the=20corrupt=20= table=20with=20epoch=3D0,=20comparing=20actual=0A+#=20corruption=20= messages=20against=20the=20expected=20messages=0A= +$node->command_checks_all(=0A+=09['pg_amcheck',=20'--exclude-indexes',=20= '-p',=20$port,=20'postgres'],=0A+=090,=0A+=09[=20@expected=20],=0A+=09[=20= qr/^$/=20],=0A+=09'Expected=20corruption=20message=20output');=0A+=0A= +$node->teardown_node;=0A+$node->clean_node;=0Adiff=20--git=20= a/contrib/pg_amcheck/t/005_opclass_damage.pl=20= b/contrib/pg_amcheck/t/005_opclass_damage.pl=0Anew=20file=20mode=20= 100644=0Aindex=200000000000..379225cbf8=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/t/005_opclass_damage.pl=0A@@=20-0,0=20+1,52=20@@=0A= +#=20This=20regression=20test=20checks=20the=20behavior=20of=20the=20= btree=20validation=20in=20the=0A+#=20presence=20of=20breaking=20sort=20= order=20changes.=0A+#=0A+use=20strict;=0A+use=20warnings;=0A+use=20= PostgresNode;=0A+use=20TestLib;=0A+use=20Test::More=20tests=20=3D>=206;=0A= +=0A+my=20$node=20=3D=20get_new_node('test');=0A+$node->init;=0A= +$node->start;=0A+=0A+#=20Create=20a=20custom=20operator=20class=20and=20= an=20index=20which=20uses=20it.=0A+$node->safe_psql('postgres',=20q(=0A+=09= CREATE=20EXTENSION=20amcheck;=0A+=0A+=09CREATE=20FUNCTION=20int4_asc_cmp=20= (a=20int4,=20b=20int4)=20RETURNS=20int=20LANGUAGE=20sql=20AS=20$$=0A+=09=09= SELECT=20CASE=20WHEN=20$1=20=3D=20$2=20THEN=200=20WHEN=20$1=20>=20$2=20= THEN=201=20ELSE=20-1=20END;=20$$;=0A+=0A+=09CREATE=20OPERATOR=20CLASS=20= int4_fickle_ops=20FOR=20TYPE=20int4=20USING=20btree=20AS=0A+=09=20=20=20=20= OPERATOR=201=20<=20(int4,=20int4),=20OPERATOR=202=20<=3D=20(int4,=20= int4),=0A+=09=20=20=20=20OPERATOR=203=20=3D=20(int4,=20int4),=20OPERATOR=20= 4=20>=3D=20(int4,=20int4),=0A+=09=20=20=20=20OPERATOR=205=20>=20(int4,=20= int4),=20FUNCTION=201=20int4_asc_cmp(int4,=20int4);=0A+=0A+=09CREATE=20= TABLE=20int4tbl=20(i=20int4);=0A+=09INSERT=20INTO=20int4tbl=20(SELECT=20= *=20FROM=20generate_series(1,1000)=20gs);=0A+=09CREATE=20INDEX=20= fickleidx=20ON=20int4tbl=20USING=20btree=20(i=20int4_fickle_ops);=0A+));=0A= +=0A+#=20We=20have=20not=20yet=20broken=20the=20index,=20so=20we=20= should=20get=20no=20corruption=0A+$node->command_like(=0A+=09[=20= 'pg_amcheck',=20'--quiet',=20'-p',=20$node->port,=20'postgres'=20],=0A+=09= qr/^$/,=0A+=09'pg_amcheck=20all=20schemas,=20tables=20and=20indexes=20= reports=20no=20corruption');=0A+=0A+#=20Change=20the=20operator=20class=20= to=20use=20a=20function=20which=20sorts=20in=20a=20different=0A+#=20= order=20to=20corrupt=20the=20btree=20index=0A= +$node->safe_psql('postgres',=20q(=0A+=09CREATE=20FUNCTION=20= int4_desc_cmp=20(int4,=20int4)=20RETURNS=20int=20LANGUAGE=20sql=20AS=20= $$=0A+=09=09SELECT=20CASE=20WHEN=20$1=20=3D=20$2=20THEN=200=20WHEN=20$1=20= >=20$2=20THEN=20-1=20ELSE=201=20END;=20$$;=0A+=09UPDATE=20= pg_catalog.pg_amproc=0A+=09=09SET=20amproc=20=3D=20= 'int4_desc_cmp'::regproc=0A+=09=09WHERE=20amproc=20=3D=20= 'int4_asc_cmp'::regproc=0A+));=0A+=0A+#=20Index=20corruption=20should=20= now=20be=20reported=0A+$node->command_like(=0A+=09[=20'pg_amcheck',=20= '-p',=20$node->port,=20'postgres'=20],=0A+=09qr/item=20order=20invariant=20= violated=20for=20index=20"fickleidx"/,=0A+=09'pg_amcheck=20all=20= schemas,=20tables=20and=20indexes=20reports=20fickleidx=20corruption'=0A= +);=0Adiff=20--git=20a/doc/src/sgml/contrib.sgml=20= b/doc/src/sgml/contrib.sgml=0Aindex=20d3ca4b6932..7e101f7c11=20100644=0A= ---=20a/doc/src/sgml/contrib.sgml=0A+++=20b/doc/src/sgml/contrib.sgml=0A= @@=20-185,6=20+185,7=20@@=20pages.=0A=20=20=20=0A=20=0A=20=20= &oid2name;=0A+=20&pgamcheck;=0A=20=20&vacuumlo;=0A=20=20=0A=20=0A= diff=20--git=20a/doc/src/sgml/filelist.sgml=20= b/doc/src/sgml/filelist.sgml=0Aindex=20db1d369743..5115cb03d0=20100644=0A= ---=20a/doc/src/sgml/filelist.sgml=0A+++=20b/doc/src/sgml/filelist.sgml=0A= @@=20-133,6=20+133,7=20@@=0A=20=0A=20=0A=20=0A+=0A=20=0A=20=0A=20=0Adiff=20--git=20a/doc/src/sgml/pgamcheck.sgml=20= b/doc/src/sgml/pgamcheck.sgml=0Anew=20file=20mode=20100644=0Aindex=20= 0000000000..2b2c73ca8b=0A---=20/dev/null=0A+++=20= b/doc/src/sgml/pgamcheck.sgml=0A@@=20-0,0=20+1,1004=20@@=0A+=0A+=0A+=0A= +=20=0A+=20=20= pg_amcheck=0A+=20=0A+=0A+=20=0A+=20= =20pg_amcheck=0A= +=20=201=0A+=20=20= Application=0A+=20=0A+=0A+=20= =0A+=20=20pg_amcheck=0A+=20=20= checks=20for=20corruption=20in=20one=20or=20more=20= PostgreSQL=20databases=0A+=20= =0A+=0A+=20=0A+=20=20=0A+=20=20= =20pg_amcheck=0A+=20=20=20option=0A+=20=20=20dbname=0A+=20=20= =0A+=20=0A+=0A+=20=0A+=20=20= Description=0A+=0A+=20=20=0A+=20=20=20= pg_amcheck=20supports=20running=0A+=20=20=20= 's=20corruption=20checking=20functions=20= against=20one=20or=20more=0A+=20=20=20databases,=20with=20options=20to=20= select=20which=20schemas,=20tables=20and=20indexes=20to=20check,=0A+=20=20= =20which=20kinds=20of=20checking=20to=20perform,=20and=20whether=20to=20= perform=20the=20checks=20in=0A+=20=20=20parallel,=20and=20if=20so,=20the=20= number=20of=20parallel=20connections=20to=20establish=20and=20use.=0A+=20= =20=0A+=0A+=20=20=0A+=20=20=20Only=20table=20relations=20= and=20btree=20indexes=20are=20currently=20supported.=20=20Other=0A+=20=20= =20relation=20types=20are=20silently=20skipped.=0A+=20=20=0A+=0A+=20= =0A+=0A+=20=0A+=20=20Usage=0A+=0A+=20= =20=0A+=20=20=20Parallelism=20Options=0A+=0A+=20= =20=20=0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20= --jobs=3D20=20--all=0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Check=20all=20= databases=20one=20after=20another,=20but=20for=20each=20database=20= checked,=0A+=20=20=20=20=20=20=20=20use=20up=20to=2020=20simultaneous=20= connections=20to=20check=20relations=20in=20parallel.=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20--jobs=3D8=20mydb=20yourdb=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20Check=20databases=20mydb=20and=20= yourdb=0A+=20=20=20=20=20=20=20=20one=20after=20= another,=20using=20up=20to=208=20simultaneous=20connections=20to=20check=0A= +=20=20=20=20=20=20=20=20relations=20in=20parallel.=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=0A+=20= =20=0A+=20=20=20=20=0A+=20=20=0A+=20=20=20= Checking=20Option=20Specification=0A+=0A+=20=20=20=0A= +=20=20=20=20If=20no=20checking=20options=20are=20specified,=20by=20= default=20all=20table=20relation=20checks=0A+=20=20=20=20and=20default=20= level=20btree=20index=20checks=20are=20performed.=20=20A=20variety=20of=20= options=0A+=20=20=20=20exist=20to=20change=20the=20set=20of=20checks=20= performed=20on=20whichever=20relations=20are=0A+=20=20=20=20being=20= checked.=20=20They=20are=20briefly=20mentioned=20here=20in=20the=20= following=20examples,=0A+=20=20=20=20but=20see=20their=20full=20= descriptions=20below.=0A+=20=20=20=0A+=20=20=20=0A+=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=20=0A= +=20=20=20=20=20=20pg_amcheck=20--parent-check=20= --heapallindexed=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20For=20each=20btree=20= index=20checked,=20performs=20more=20extensive=20checks.=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20--exclude-toast-pointers=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20For=20each=20table=20relation=20checked,=20do=20not=20= check=20toast=20pointers=20against=0A+=20=20=20=20=20=20=20=20the=20= toast=20relation.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20= --on-error-stop=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20For=20each=20table=20= relation=20checked,=20do=20not=20continue=20checking=20pages=20after=0A+=20= =20=20=20=20=20=20=20the=20first=20page=20where=20corruption=20is=20= encountered.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20= --skip=3D"all-frozen"=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20For=20each=20= table=20relation=20checked,=20skips=20over=20blocks=20marked=20as=20all=0A= +=20=20=20=20=20=20=20=20frozen.=20=20Note=20that=20"all-visible"=20may=20= also=20be=20specified.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20= --startblock=3D3000=20--endblock=3D4000=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= For=20each=20table=20relation=20checked,=20check=20only=20blocks=20in=20= the=20given=20block=0A+=20=20=20=20=20=20=20=20range.=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=0A+=20= =20=0A+=0A+=20=20=0A+=20=20=20Relation=20= Specification=0A+=0A+=20=20=20=0A+=20=20=20=20If=20no=20= relations=20are=20explicitly=20listed,=20by=20default=20all=20relations=20= will=20be=0A+=20=20=20=20checked,=20but=20there=20are=20options=20to=20= specify=20which=20relations=20to=20check.=0A+=20=20=20=0A+=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=20=0A= +=20=20=20=20=20=20pg_amcheck=20-r=20mytable=20-r=20= yourtable=0A+=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20If=20one=20or=20more=20= relations=20are=20explicitly=20given,=20they=20are=20interpreted=20as=0A= +=20=20=20=20=20=20=20=20an=20exhaustive=20list=20of=20all=20relations=20= to=20be=20checked,=20with=20one=20caveat:=0A+=20=20=20=20=20=20=20=20for=20= all=20such=20relations,=20associated=20toast=20relations=20and=20indexes=20= are=20by=0A+=20=20=20=20=20=20=20=20default=20included=20in=20the=20list=20= of=20relations=20to=20check.=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=20Assuming=20= mytable=20is=20an=20ordinary=20table,=20and=20that=20= it=0A+=20=20=20=20=20=20=20=20is=20indexed=20by=20= mytable_idx=20and=20has=20an=20associated=0A+=20=20=20= =20=20=20=20=20toast=20table=20pg_toast_12345,=20= checking=20will=20be=0A+=20=20=20=20=20=20=20=20performed=20on=20= mytable,=0A+=20=20=20=20=20=20=20=20= mytable_idx,=20and=20= pg_toast_12345.=0A+=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Likewise=20for=20= yourtable.=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20-r=20= mytable=20--no-dependents=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= This=20restricts=20the=20list=20of=20relations=20checked=20to=20just=0A+=20= =20=20=20=20=20=20=20mytable,=20without=20pulling=20= in=20the=20corresponding=0A+=20=20=20=20=20=20=20=20indexes=20or=20= toast,=20but=20see=20also=0A+=20=20=20=20=20=20=20=20= .=0A+=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20-t=20mytable=20-i=20myindex=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20The=20=20()=20= will=20match=20any=0A+=20=20=20=20=20=20=20=20relation,=20but=20= =20()=20and=0A+=20=20=20=20=20= =20=20=20=20()=20may=20be=20= used=20to=20avoid=0A+=20=20=20=20=20=20=20=20matching=20objects=20of=20= the=20other=20type.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20-r=3D"my*"= =20-R=3D"mytemp*"=0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Relations=20may=20be=20= included=20()=20or=20excluded=0A+=20=20=20=20=20=20=20= =20()=20using=20shell-style=20patterns.=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20-r=3D"my*"=20-I=3D"myanmar"=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20Table=20and=20index=20inclusion=20and=20exclusion=20= patterns=20may=20be=20used=0A+=20=20=20=20=20=20=20=20equivalently=20= with=20,=20,=0A+=20=20=20=20=20=20=20= =20=20and=20.=20=20The=20above=20= example=20checks=0A+=20=20=20=20=20=20=20=20all=20tables=20and=20indexes=20= starting=20with=20my=20except=20for=0A+=20=20=20=20=20= =20=20=20indexes=20starting=20with=20myanmar.=0A+=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20-R=3D"india"=20-T=3D"laos"=20= -I=3D"myanmar"=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Unlike=20specifying=20= one=20ore=20more=20=20options,=20which=0A+=20=20= =20=20=20=20=20=20disables=20the=20default=20behavior=20of=20checking=20= all=20relations,=20specifying=20one=20or=0A+=20=20=20=20=20=20=20=20more=20= of=20,=20=20or=20= =20does=20not.=0A+=20=20=20=20=20=20=20=20The=20above=20= command=20will=20check=20all=20relations=20not=20named=0A+=20=20=20=20=20= =20=20=20india,=20not=20a=20table=20named=0A+=20=20=20= =20=20=20=20=20laos,=20nor=20an=20index=20named=20= myanmar.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=0A+=20=20=0A+=0A+=20=20= =0A+=20=20=20Schema=20Specification=0A+=0A+=20=20= =20=0A+=20=20=20=20If=20no=20schemas=20are=20explicitly=20listed,=20= by=20default=20all=20schemas=20except=0A+=20=20=20=20= pg_catalog=20and=20pg_toast=20will=20= be=0A+=20=20=20=20checked.=0A+=20=20=20=0A+=20=20=20=0A+=20=20= =20=20=0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20-s=20s1=20-s=20s2=20-r=20= mytable=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20If=20one=20or=20more=20schemas=20= are=20listed=20with=20,=20unqualified=0A+=20=20=20=20=20= =20=20=20relation=20names=20will=20be=20checked=20only=20in=20the=20= given=20schemas.=20=20The=20above=0A+=20=20=20=20=20=20=20=20command=20= will=20check=20tables=20s1.mytable=20and=0A+=20=20=20=20= =20=20=20=20s2.mytable=20but=20not=20tables=20named=0A= +=20=20=20=20=20=20=20=20mytable=20in=20other=20= schemas.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20-S=20s1=20= -S=20s2=20-r=20mytable=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20As=20with=20= relations,=20schemas=20may=20be=20excluded.=20=20The=20above=20command=20= will=0A+=20=20=20=20=20=20=20=20check=20any=20table=20named=20= mytable=20not=20in=20schemas=0A+=20=20=20=20=20=20=20=20= s1=20and=20s2.=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20-S=20s1=20-S=20s2=20-r=20mytable=20-t=20= s1.stuff=0A+=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20Relations=20may=20be=20= included=20or=20excluded=20with=20a=20schema-qualified=20name=0A+=20=20=20= =20=20=20=20=20without=20interference=20from=20the=20=20= or=0A+=20=20=20=20=20=20=20=20=20options.=20=20Even=20= though=20schema=20s1=0A+=20=20=20=20=20=20=20=20has=20= been=20excluded,=20the=20table=20s1.stuff=20will=20be=0A= +=20=20=20=20=20=20=20=20checked.=0A+=20=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=0A+=20=20=0A+=0A+=20=20= =0A+=20=20=20Database=20Specification=0A+=0A+=20= =20=20=0A+=20=20=20=20If=20no=20databases=20are=20explicitly=20= listed,=20the=20database=20to=20check=20is=20obtained=0A+=20=20=20=20= from=20environment=20variables=20in=20the=20usual=20way.=20=20Otherwise,=20= when=20one=20or=20more=0A+=20=20=20=20databases=20are=20explicitly=20= given,=20they=20are=20interpreted=20as=20an=20exhaustive=20list=0A+=20=20= =20=20of=20all=20databases=20to=20be=20checked.=20=20This=20list=20of=20= databases=20to=20check=20may=0A+=20=20=20=20contain=20patterns,=20but=20= because=20any=20such=20patterns=20need=20to=20be=20reconciled=0A+=20=20=20= =20against=20a=20list=20of=20all=20databases=20to=20find=20the=20= matching=20database=20names,=20at=0A+=20=20=20=20least=20one=20database=20= specified=20must=20be=20a=20literal=20database=20name=20and=20not=20= merely=0A+=20=20=20=20a=20pattern,=20and=20the=20one=20so=20specified=20= must=20be=20in=20a=20location=20where=0A+=20=20=20=20= pg_amcheck=20expects=20to=20find=20it.=0A+=20=20= =20=0A+=20=20=20=0A+=20=20=20=20For=20example:=0A+=20=20=20= =0A+=20=20=20=0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20pg_amcheck=20--all=20= --maintenance-db=3Dfoo=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20If=20the=20= =20option=20is=20given,=20it=20will=20= be=0A+=20=20=20=20=20=20=20=20used=20to=20look=20up=20the=20matching=20= databases,=20though=20it=20will=20not=20itself=20be=0A+=20=20=20=20=20=20= =20=20added=20to=20the=20list=20of=20databases=20for=20checking.=0A+=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20foo=20bar=20baz=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20Otherwise,=20if=20one=20or=20more=20plain=20database=20name=20= arguments=20not=20preceded=20by=0A+=20=20=20=20=20=20=20=20= =20or=20=20are=20given,=20= the=20first=0A+=20=20=20=20=20=20=20=20one=20will=20be=20used=20for=20= this=20purpose,=20and=20it=20will=20also=20be=20included=20in=20the=0A+=20= =20=20=20=20=20=20=20list=20of=20databases=20to=20check.=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20-d=20foo=20-d=20bar=20baz=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20If=20a=20mixture=20of=20plain=20database=20names=20and=20= databases=20preceded=20with=0A+=20=20=20=20=20=20=20=20= =20or=20=20are=20given,=20= the=20first=0A+=20=20=20=20=20=20=20=20plain=20database=20name=20will=20= be=20used=20for=20this=20purpose.=20=20In=20the=20above=0A+=20=20=20=20=20= =20=20=20example,=20baz=20will=20be=20used.=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20--dbname=3Dfoo=20= --dbname=3D"bar*"=0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Otherwise,=20if=20= one=20or=20more=20databases=20are=20given=20with=20the=0A+=20=20=20=20=20= =20=20=20=20or=20=20option,=20= the=20first=20one=0A+=20=20=20=20=20=20=20=20will=20be=20used=20and=20= must=20be=20a=20literal=20database=20name.=20=20In=20this=20example,=0A+=20= =20=20=20=20=20=20=20foo=20will=20be=20used.=0A+=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= pg_amcheck=20--relation=3D"accounts_*.*.*"= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20=20Otherwise,=20the=20environment=20will=20be=20consulted=20= for=20the=20database=20to=20be=0A+=20=20=20=20=20=20=20=20used.=20=20In=20= the=20example=20above,=20the=20default=20database=20will=20be=20queried=20= to=0A+=20=20=20=20=20=20=20=20find=20all=20databases=20with=20names=20= that=20begin=20with=0A+=20=20=20=20=20=20=20=20= accounts_.=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=0A+=0A+=20=20=20=0A+=20=20=20=20= As=20discussed=20above=20for=20schema-qualified=20relations,=20a=20= database-qualified=0A+=20=20=20=20relation=20name=20or=20pattern=20may=20= also=20be=20given.=0A+=0A+pg_amcheck=20mydb=20\=0A+=20=20= =20=20=20=20=20=20=20=20=20--schema=3D"t*"=20\=0A+=20=20=20=20=20=20=20=20= =20=20=20--exclude-schema=3D"tmp*"=20\=0A+=20=20=20=20=20=20=20=20=20=20=20= --relation=3Dbaz=20\=0A+=20=20=20=20=20=20=20=20=20=20=20= --relation=3Dbar.baz=20\=0A+=20=20=20=20=20=20=20=20=20=20=20= --relation=3Dfoo.bar.baz=20\=0A+=20=20=20=20=20=20=20=20=20=20=20= --relation=3D"f*".a.b=20\=0A+=20=20=20=20=20=20=20=20=20=20=20= --exclude-relation=3Dfoo.a.b=0A+=0A+=20=20=20=20will=20= check=20relations=20in=20database=20mydb=20using=20= the=20schema=0A+=20=20=20=20resolution=20rules=20discussed=20above,=20= but=20additionally=20will=20check=20all=20relations=0A+=20=20=20=20named=20= a.b=20in=20all=20databases=20with=20names=20starting=20= with=0A+=20=20=20=20f=20except=20database=20= foo.=0A+=20=20=20=0A+=0A+=20=20=0A+=20= =0A+=0A+=20=0A+=20=20Options=0A+=0A+=20= =20=0A+=20=20=20pg_amcheck=20accepts=20= the=20following=20command-line=20arguments:=0A+=20=20=0A+=0A+=20=20= =0A+=20=20=20Help=20and=20Version=20Information=20= Options=0A+=0A+=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Show=20= help=20about=20pg_amcheck=20command=20line=0A= +=20=20=20=20=20=20=20arguments,=20and=20exit.=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=0A+=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20Print=20the=20= pg_amcheck=20version=20and=20exit.=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20Print=20to=20stdout=20all=20= commands=20and=20queries=20being=20executed=20against=20the=0A+=20=20=20=20= =20=20=20server.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=0A= +=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20Do=20not=20write=20= additional=20messages=20beyond=20those=20about=20corruption.=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= This=20option=20does=20not=20quiet=20any=20output=20specifically=20due=20= to=20the=20use=20of=0A+=20=20=20=20=20=20=20the=20=20= =20option.=0A+=20=20=20=20=20=20=0A+=20=20=20= =20=20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Increases=20= the=20log=20level=20verbosity.=20=20This=20option=20may=20be=20given=20= more=20than=0A+=20=20=20=20=20=20=20once.=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=0A+=20=20=20=20=0A+=20=20=20= =0A+=20=20=0A+=0A+=20=20=0A+=20=20=20= Database=20Connection=20and=20Concurrent=20Connection=20= Options=0A+=0A+=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Specifies=20= the=20host=20name=20of=20the=20machine=20on=20which=20the=20server=20is=20= running.=0A+=20=20=20=20=20=20=20If=20the=20value=20begins=20with=20a=20= slash,=20it=20is=20used=20as=20the=20directory=20for=20the=0A+=20=20=20=20= =20=20=20Unix=20domain=20socket.=0A+=20=20=20=20=20=20=0A+=20=20=20= =20=20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Specifies=20= the=20TCP=20port=20or=20local=20Unix=20domain=20socket=20file=20= extension=20on=0A+=20=20=20=20=20=20=20which=20the=20server=20is=20= listening=20for=20connections.=0A+=20=20=20=20=20=20=0A+=20=20=20=20= =20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20= =20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= User=20name=20to=20connect=20as.=0A+=20=20=20=20=20=20=0A+=20=20=20= =20=20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Never=20= issue=20a=20password=20prompt.=20=20If=20the=20server=20requires=20= password=0A+=20=20=20=20=20=20=20authentication=20and=20a=20password=20= is=20not=20available=20by=20other=20means=20such=20as=0A+=20=20=20=20=20=20= =20a=20.pgpass=20file,=20the=20connection=20attempt=20= will=20fail.=0A+=20=20=20=20=20=20=20This=20option=20can=20be=20useful=20= in=20batch=20jobs=20and=20scripts=20where=20no=20user=20is=0A+=20=20=20=20= =20=20=20present=20to=20enter=20a=20password.=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=0A+=20= =20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Force=20= pg_amcheck=20to=20prompt=20for=20a=20password=0A= +=20=20=20=20=20=20=20before=20connecting=20to=20a=20database.=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= This=20option=20is=20never=20essential,=20since=0A+=20=20=20=20=20=20=20= pg_amcheck=20will=20automatically=20prompt=20= for=20a=0A+=20=20=20=20=20=20=20password=20if=20the=20server=20demands=20= password=20authentication.=20=20However,=0A+=20=20=20=20=20=20=20= pg_amcheck=20will=20waste=20a=20connection=20= attempt=0A+=20=20=20=20=20=20=20finding=20out=20that=20the=20server=20= wants=20a=20password.=20=20In=20some=20cases=20it=20is=0A+=20=20=20=20=20= =20=20worth=20typing=20=20to=20avoid=20the=20extra=20= connection=20attempt.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=0A= +=20=20=20=20=20=0A= +=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20Specifies=20the=20name=20of=20the=20database=20to=20connect=20to=20= when=20querying=20the=0A+=20=20=20=20=20=20=20list=20of=20all=20= databases.=20=20If=20not=20specified,=20the=0A+=20=20=20=20=20=20=20= postgres=20database=20will=20be=20used;=20if=20that=20= does=20not=0A+=20=20=20=20=20=20=20exist=20template1=20= will=20be=20used.=20=20This=20can=20be=20a=0A+=20=20=20=20=20=20=20connection=20string.=20=20If=20so,=0A= +=20=20=20=20=20=20=20connection=20string=20parameters=20will=20override=20= any=20conflicting=20command=0A+=20=20=20=20=20=20=20line=20options.=0A+=20= =20=20=20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Use=20the=20specified=20= number=20of=20concurrent=20connections=20to=20the=20server,=20or=0A+=20=20= =20=20=20=20=20one=20per=20object=20to=20be=20checked,=20whichever=20= number=20is=20smaller.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20When=20used=20in=20conjunction=20with=20= the=20=0A+=20=20=20=20=20=20=20=20= option,=20the=20total=20number=20of=20objects=20to=20check,=0A+=20=20=20=20= =20=20=20and=20correspondingly=20the=20number=20of=20concurrent=20= connections=20to=20use,=20is=0A+=20=20=20=20=20=20=20recalculated=20per=20= database.=20=20If=20the=20number=20of=20objects=20to=20check=20differs=0A= +=20=20=20=20=20=20=20from=20one=20database=20to=20the=20next=20and=20is=20= less=20than=20the=20concurrency=20level=0A+=20=20=20=20=20=20=20= specified,=20the=20number=20of=20concurrent=20connections=20open=20to=20= the=20server=0A+=20=20=20=20=20=20=20will=20fluctuate=20to=20meet=20the=20= needs=20of=20each=20database=20processed.=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20The=20default=20is=20= to=20use=20a=20single=20connection.=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=0A+=20=20=20=20=0A+=20=20=20= =0A+=20=20=0A+=0A+=20=20=0A+=20=20=20= Options=20Controlling=20Index=20Checking=20Functions=0A+=0A= +=20=20=20=0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20For=20= each=20btree=20index=20checked,=20use=20's=0A= +=20=20=20=20=20=20=20bt_index_parent_check=20= function,=20which=20performs=0A+=20=20=20=20=20=20=20additional=20checks=20= of=20parent/child=20relationships=20during=20index=20checking.=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20The=20= default=20is=20to=20use=20amcheck's=0A+=20=20=20= =20=20=20=20bt_index_check=20function,=20but=20note=20= that=20use=20of=20the=0A+=20=20=20=20=20=20=20= =20option=20implicitly=0A+=20=20=20=20=20=20= =20selects=20bt_index_parent_check.=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=0A+=20=20=20=20=0A= +=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20For=20= each=20index=20checked,=20verify=20the=20presence=20of=20all=20heap=20= tuples=20as=20index=0A+=20=20=20=20=20=20=20tuples=20in=20the=20index=20= using=20amcheck's=0A+=20=20=20=20=20=20=20= =20option.=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20For=20each=20index=20= checked,=20re-find=20tuples=20on=20the=20leaf=20level=20by=20performing=0A= +=20=20=20=20=20=20=20a=20new=20search=20from=20the=20root=20page=20for=20= each=20tuple=20using=0A+=20=20=20=20=20=20=20's=20=20option.=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= Use=20of=20this=20option=20implicitly=20also=20selects=20the=20= =0A+=20=20=20=20=20=20=20= =20option.=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20This=20form=20of=20= verification=20was=20originally=20written=20to=20help=20in=20the=0A+=20=20= =20=20=20=20=20development=20of=20btree=20index=20features.=20=20It=20= may=20be=20of=20limited=20use=20or=20even=0A+=20=20=20=20=20=20=20of=20= no=20use=20in=20helping=20detect=20the=20kinds=20of=20corruption=20that=20= occur=20in=0A+=20=20=20=20=20=20=20practice.=20=20It=20may=20also=20= cause=20corruption=20checking=20to=20take=20considerably=0A+=20=20=20=20=20= =20=20longer=20and=20consume=20considerably=20more=20resources=20on=20= the=20server.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=0A= +=20=20=20=20=0A+=20=20=20=0A+=20=20= =0A+=0A+=20=20=0A+=20=20=20Options=20= Controlling=20Table=20Checking=20Functions=0A+=0A+=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20When=20= checking=20main=20relations,=20do=20not=20look=20up=20entries=20in=20= toast=20tables=0A+=20=20=20=20=20=20=20corresponding=20to=20toast=20= pointers=20in=20the=20main=20releation.=0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20The=20default=20behavior=20= checks=20each=20toast=20pointer=20encountered=20in=20the=20main=0A+=20=20= =20=20=20=20=20table=20to=20verify,=20as=20much=20as=20possible,=20that=20= the=20pointer=20points=20at=0A+=20=20=20=20=20=20=20something=20in=20the=20= toast=20table=20that=20is=20reasonable.=20=20Toast=20pointers=20which=0A= +=20=20=20=20=20=20=20point=20beyond=20the=20end=20of=20the=20toast=20= table,=20or=20to=20the=20middle=20(rather=20than=0A+=20=20=20=20=20=20=20= the=20beginning)=20of=20a=20toast=20entry,=20are=20identified=20as=20= corrupt.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20The=20process=20by=20which=20's=0A+=20=20=20=20=20=20=20= verify_heapam=20function=20checks=20each=20toast=20= pointer=0A+=20=20=20=20=20=20=20is=20slow=20and=20may=20be=20improved=20= in=20a=20future=20release.=20=20Some=20users=20may=20wish=0A+=20=20=20=20= =20=20=20to=20disable=20this=20check=20to=20save=20time.=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Note=20= that,=20despite=20their=20similar=20names,=20this=20option=20is=20= unrelated=20to=20the=0A+=20=20=20=20=20=20=20= =20option.=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20After=20= reporting=20all=20corruptions=20on=20the=20first=20page=20of=20a=20table=20= where=0A+=20=20=20=20=20=20=20corruptions=20are=20found,=20stop=20= processing=20that=20table=20relation=20and=20move=20on=0A+=20=20=20=20=20= =20=20to=20the=20next=20table=20or=20index.=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Note=20that=20index=20= checking=20always=20stops=20after=20the=20first=20corrupt=20page.=0A+=20=20= =20=20=20=20=20This=20option=20only=20has=20meaning=20relative=20to=20= table=20relations.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=0A= +=20=20=20=20=20=0A+=20=20=20= =20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20If=20= "all-frozen"=20is=20given,=20table=20corruption=20= checks=0A+=20=20=20=20=20=20=20will=20skip=20over=20pages=20in=20all=20= tables=20that=20are=20marked=20as=20all=20frozen.=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20If=20= "all-visible"=20is=20given,=20table=20corruption=20= checks=0A+=20=20=20=20=20=20=20will=20skip=20over=20pages=20in=20all=20= tables=20that=20are=20marked=20as=20all=20visible.=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20By=20= default,=20no=20pages=20are=20skipped.=0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=0A+=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Skip=20= (do=20not=20check)=20pages=20prior=20to=20the=20given=20starting=20= block.=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20By=20default,=20no=20pages=20are=20skipped.=20=20This=20= option=20will=20be=20applied=20to=20all=0A+=20=20=20=20=20=20=20table=20= relations=20that=20are=20checked,=20including=20toast=20tables.=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=20=0A+=20=20=20=20=20= =0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20Skip=20= (do=20not=20check)=20all=20pages=20after=20the=20given=20ending=20block.=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20By=20default,=20no=20pages=20are=20skipped.=20=20This=20option=20= will=20be=20applied=20to=20all=0A+=20=20=20=20=20=20=20table=20relations=20= that=20are=20checked,=20including=20toast=20tables.=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=0A+=20= =20=20=0A+=20=20=0A+=0A+=20=20=0A+=20= =20=20Corruption=20Checking=20Target=20Options=0A+=0A+=20=20= =20=0A+=20=20=20=20Objects=20to=20be=20checked=20may=20span=20= schemas=20in=20more=20than=20one=20database.=20=20Options=0A+=20=20=20=20= for=20restricting=20the=20list=20of=20databases,=20schemas,=20tables=20= and=20indexes=20are=0A+=20=20=20=20described=20below.=20=20In=20each=20= place=20where=20a=20name=20may=20be=20specified,=20a=0A+=20=20=20=20= pattern=0A+=20=20=20=20may=20= also=20be=20used.=0A+=20=20=20=0A+=0A+=20=20=20=0A+=20=20=20= =20=0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= Perform=20checking=20in=20all=20databases.=0A+=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20In=20= the=20absence=20of=20any=20other=20options,=20selects=20all=20objects=20= across=20all=0A+=20=20=20=20=20=20=20=20schemas=20and=20databases.=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=20Option=20=20=20= takes=0A+=20=20=20=20=20=20=20=20precedence=20over=20= .=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=0A+=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= Perform=20checking=20in=20the=20specified=20database.=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= This=20option=20may=20be=20specified=20multiple=20times=20to=20list=20= more=20than=20one=0A+=20=20=20=20=20=20=20=20database=20(or=20database=20= pattern)=20for=20checking.=20=20By=20default,=20all=20objects=20in=0A+=20= =20=20=20=20=20=20=20the=20matching=20database(s)=20will=20be=20checked.=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20If=20no=20=20argument=20is=20= given=20nor=20is=20any=0A+=20=20=20=20=20=20=20=20database=20name=20= given=20as=20a=20command=20line=20argument,=20the=20first=20argument=0A+=20= =20=20=20=20=20=20=20specified=20with=20=20= =20will=20be=0A+=20=20=20=20=20=20=20=20used=20= for=20the=20initial=20connection.=20=20If=20that=20argument=20is=20not=20= a=20literal=0A+=20=20=20=20=20=20=20=20database=20name,=20the=20attempt=20= to=20connect=20will=20fail.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20If=20=20= is=20also=20specified,=20=0A+=20=20=20=20=20=20=20=20= =20does=20not=20affect=20which=20databases=20= are=20checked,=0A+=20=20=20=20=20=20=20=20but=20may=20be=20used=20to=20= specify=20the=20database=20for=20the=20initial=20connection.=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20Option=20=20=20takes=0A= +=20=20=20=20=20=20=20=20precedence=20over=20=20= .=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20Examples:=0A+=20=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20=20= --dbname=3Dafrica=0A+=20=20=20=20=20=20= =20=20=20--dbname=3D"a*"=0A+=20=20=20= =20=20=20=20=20=20= --dbname=3D"africa|asia|europe"=0A+=20= =20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=0A+=20=20=20=20=20=0A+=0A+=20=20= =20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Do=20= not=20perform=20checking=20in=20the=20specified=20database.=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= This=20option=20may=20be=20specified=20multiple=20times=20to=20list=20= more=20than=20one=0A+=20=20=20=20=20=20=20=20database=20(or=20database=20= pattern)=20for=20exclusion.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20If=20a=20database=20which=20= is=20included=20using=20=20or=0A+=20=20=20=20=20=20= =20=20=20=20is=20also=20= excluded=20using=0A+=20=20=20=20=20=20=20=20=20= ,=20the=20database=20will=20be=0A+=20=20=20=20= =20=20=20=20excluded.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=20Examples:=0A+=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20= --exclude-db=3Damerica=0A+=20=20=20=20= =20=20=20=20=20= --exclude-db=3D"*pacific*"=0A+=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=0A+=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= Perform=20checking=20in=20the=20specified=20schema(s).=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= This=20option=20may=20be=20specified=20multiple=20times=20to=20list=20= more=20than=20one=0A+=20=20=20=20=20=20=20=20schema=20(or=20schema=20= pattern)=20for=20checking.=20=20By=20default,=20all=20objects=20in=0A+=20= =20=20=20=20=20=20=20the=20matching=20schema(s)=20will=20be=20checked.=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20Option=20=20= =20takes=0A+=20=20=20=20=20=20=20=20= precedence=20over=20=20.=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=20Examples:=0A+=20=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=20=20--schema=3Dcorp=0A+=20= =20=20=20=20=20=20=20=20= --schema=3D"corp|llc|npo"=0A+=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=0A+=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20Do=20not=20perform=20checking=20in=20the=20specified=20schema.=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=20This=20option=20may=20be=20specified=20multiple=20times=20to=20= list=20more=20than=20one=0A+=20=20=20=20=20=20=20=20schema=20(or=20= schema=20pattern)=20for=20exclusion.=0A+=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20If=20a=20schema=20= which=20is=20included=20using=0A+=20=20=20=20=20=20=20=20= =20=20is=20also=20excluded=20= using=0A+=20=20=20=20=20=20=20=20=20= ,=20the=20schema=20will=20be=0A+=20=20=20= =20=20=20=20=20excluded.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=20Examples:=0A+=20=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=20=20-S=20corp=20= -S=20llc=0A+=20=20=20=20=20=20=20=20=20= --exclude-schema=3D"*c*"=0A+=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=0A+=20=20=20=20= =20=0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= Perform=20checking=20on=20the=20specified=20relation(s).=0A+=20=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= This=20option=20may=20be=20specified=20multiple=20times=20to=20list=20= more=20than=20one=0A+=20=20=20=20=20=20=20=20relation=20(or=20relation=20= pattern)=20for=20checking.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20Option=20=20= =20takes=0A+=20=20=20=20=20=20=20=20= precedence=20over=20=20.=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20If=20the=20relation=20is=20not=20schema=20qualified,=20= database=20and=20schema=0A+=20=20=20=20=20=20=20=20inclusion/exclusion=20= lists=20will=20determine=20in=20which=20databases=20or=20schemas=0A+=20=20= =20=20=20=20=20=20matching=20relations=20will=20be=20checked.=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20Examples:=0A+=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20--relation=3Daccounts_idx=0A= +=20=20=20=20=20=20=20=20=20= --relation=3D"llc.accounts_idx"=0A+=20= =20=20=20=20=20=20=20=20= --relation=3D"asia|africa.corp|llc.accounts_idx"=0A+=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20The=20= first=20example,=20--relation=3Daccounts_idx,=20= checks=0A+=20=20=20=20=20=20=20=20relations=20named=20= accounts_idx=20in=20all=20selected=20schemas=0A+=20=20= =20=20=20=20=20=20and=20databases.=0A+=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20The=20second=20= example,=20--relation=3D"llc.accounts_idx",=0A+=20=20=20= =20=20=20=20=20checks=20relations=20named=20= accounts_idx=20in=20schema=0A+=20=20=20=20=20=20=20=20= llc=20in=20all=20selected=20databases.=20=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20The=20third=20example,=0A+=20=20=20=20=20=20=20=20= --relation=3D"asia|africa.corp|llc.accounts_idx",=0A+=20= =20=20=20=20=20=20=20checks=20relations=20named=20= accounts_idx=20in=0A+=20=20=20=20=20=20=20=20schemas=20= corp=20and=20llc=20in=20databases=0A= +=20=20=20=20=20=20=20=20asia=20and=20= africa.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=20=20Note=20that=20if=20a=20= database=20is=20implicated=20in=20a=20relation=20pattern,=20such=20as=0A= +=20=20=20=20=20=20=20=20asia=20and=20= africa=20in=20the=20third=0A+=20=20=20=20=20=20=20=20= example=20above,=20the=20database=20need=20not=20be=20otherwise=20given=20= in=20the=20command=0A+=20=20=20=20=20=20=20=20arguments=20for=20the=20= relation=20to=20be=20checked.=20=20As=20an=20extreme=20example=20of=0A+=20= =20=20=20=20=20=20=20this:=0A+=20=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=20=20pg_amcheck=20--relation=3D"*.*.*"= =20mydb=0A+=20=20=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=20=20will=20check=20all=20relations=20in=20all=20= databases.=20=20The=20mydb=0A+=20=20=20=20=20=20=20=20= argument=20only=20serves=20to=20tell=20= pg_amcheck=20the=0A+=20=20=20=20=20=20=20=20= name=20of=20the=20database=20to=20use=20for=20querying=20the=20list=20of=20= all=20databases.=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=0A+=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20= =20=20=20=20=20=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20Exclude=20checks=20on=20the=20specified=20relation(s).=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20Option=20=20=20= takes=0A+=20=20=20=20=20=20=20=20precedence=20over=20=20= ,=0A+=20=20=20=20=20=20=20=20= =20=20and=20= =0A+=20=20=20=20=20=20=20=20.=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20= =20=20=0A+=0A+=20=20=20=20=20=0A+=20=20=20=20= =20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Perform=20checks=20= on=20the=20specified=20tables(s).=20=20This=20is=20an=20alias=20for=20= the=0A+=20=20=20=20=20=20=20=20=20= =20option,=20except=20that=20it=0A+=20=20=20=20= =20=20=20=20applies=20only=20to=20tables,=20not=20indexes.=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= Exclude=20checks=20on=20the=20specified=20tables(s).=20=20This=20is=20an=20= alias=20for=20the=0A+=20=20=20=20=20=20=20=20=20= =20option,=20except=0A+=20=20=20=20=20= =20=20=20that=20it=20applies=20only=20to=20tables,=20not=20indexes.=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20= =20=0A+=0A+=20=20=20=20=20=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20Perform=20checks=20= on=20the=20specified=20index(es).=20=20This=20is=20an=20alias=20for=20= the=0A+=20=20=20=20=20=20=20=20=20= =20option,=20except=20that=20it=0A+=20=20=20=20= =20=20=20=20applies=20only=20to=20indexes,=20not=20tables.=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A+=0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= Exclude=20checks=20on=20the=20specified=20index(es).=20=20This=20is=20an=20= alias=20for=20the=0A+=20=20=20=20=20=20=20=20=20= =20option,=20except=0A+=20=20=20=20=20= =20=20=20that=20it=20applies=20only=20to=20indexes,=20not=20tables.=0A+=20= =20=20=20=20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20= =20=0A+=0A+=20=20=20=20=20=0A+=20=20=20=20=20= =20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20= When=20calculating=20the=20list=20of=20objects=20to=20be=20checked,=20do=20= not=20automatically=0A+=20=20=20=20=20=20=20=20expand=20the=20list=20to=20= include=20associated=20indexes=20and=20toast=20tables=20of=0A+=20=20=20=20= =20=20=20=20elements=20otherwise=20in=20the=20list.=0A+=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20By=20= default,=20for=20each=20main=20table=20relation=20checked,=20any=20= associated=20toast=0A+=20=20=20=20=20=20=20=20table=20and=20all=20= associated=20indexes=20are=20also=20checked,=20unless=20explicitly=0A+=20= =20=20=20=20=20=20=20excluded.=0A+=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=20=20=20=0A+=20=20=0A+=20= =0A+=0A+=20=0A+=20=20Notes=0A+=0A+=20= =20=0A+=20=20=20pg_amcheck=20is=20= designed=20to=20work=20with=0A+=20=20=20= PostgreSQL=2014.0=20and=20later.=0A+=20=20= =0A+=20=0A+=0A+=20=0A+=20=20= Author=0A+=0A+=20=20=0A+=20=20=20Mark=20Dilger=20= mark.dilger@enterprisedb.com=0A+=20=20=0A+=20= =0A+=0A+=20=0A+=20=20See=20Also=0A+=0A= +=20=20=0A+=20=20=20=0A+=20=20=0A+=20=0A= +=0Adiff=20--git=20a/src/tools/msvc/Install.pm=20= b/src/tools/msvc/Install.pm=0Aindex=20ea3af48777..49ad558b74=20100644=0A= ---=20a/src/tools/msvc/Install.pm=0A+++=20b/src/tools/msvc/Install.pm=0A= @@=20-18,7=20+18,7=20@@=20our=20(@ISA,=20@EXPORT_OK);=0A=20@EXPORT_OK=20= =3D=20qw(Install);=0A=20=0A=20my=20$insttype;=0A-my=20@client_contribs=20= =3D=20('oid2name',=20'pgbench',=20'vacuumlo');=0A+my=20@client_contribs=20= =3D=20('oid2name',=20'pg_amcheck',=20'pgbench',=20'vacuumlo');=0A=20my=20= @client_program_files=20=3D=20(=0A=20=09'clusterdb',=20=20=20=20=20=20= 'createdb',=20=20=20'createuser',=20=20=20=20'dropdb',=0A=20=09= 'dropuser',=20=20=20=20=20=20=20'ecpg',=20=20=20=20=20=20=20'libecpg',=20= =20=20=20=20=20=20'libecpg_compat',=0Adiff=20--git=20= a/src/tools/msvc/Mkvcbuild.pm=20b/src/tools/msvc/Mkvcbuild.pm=0Aindex=20= 7be6e6c9e5..53fbfa012e=20100644=0A---=20a/src/tools/msvc/Mkvcbuild.pm=0A= +++=20b/src/tools/msvc/Mkvcbuild.pm=0A@@=20-33,9=20+33,9=20@@=20my=20= @unlink_on_exit;=0A=20=0A=20#=20Set=20of=20variables=20for=20modules=20= in=20contrib/=20and=20src/test/modules/=0A=20my=20$contrib_defines=20=3D=20= {=20'refint'=20=3D>=20'REFINT_VERBOSE'=20};=0A-my=20@contrib_uselibpq=20= =3D=20('dblink',=20'oid2name',=20'postgres_fdw',=20'vacuumlo');=0A-my=20= @contrib_uselibpgport=20=20=20=3D=20('oid2name',=20'vacuumlo');=0A-my=20= @contrib_uselibpgcommon=20=3D=20('oid2name',=20'vacuumlo');=0A+my=20= @contrib_uselibpq=20=3D=20('dblink',=20'oid2name',=20'pg_amcheck',=20= 'postgres_fdw',=20'vacuumlo');=0A+my=20@contrib_uselibpgport=20=20=20=3D=20= ('oid2name',=20'pg_amcheck',=20'vacuumlo');=0A+my=20= @contrib_uselibpgcommon=20=3D=20('oid2name',=20'pg_amcheck',=20= 'vacuumlo');=0A=20my=20$contrib_extralibs=20=20=20=20=20=20=3D=20undef;=0A= =20my=20$contrib_extraincludes=20=3D=20{=20'dblink'=20=3D>=20= ['src/backend']=20};=0A=20my=20$contrib_extrasource=20=3D=20{=0Adiff=20= --git=20a/src/tools/pgindent/typedefs.list=20= b/src/tools/pgindent/typedefs.list=0Aindex=204d0d09a5dd..26920cc512=20= 100644=0A---=20a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-336,6=20+336,8=20@@=20= CheckPointStmt=0A=20CheckpointStatsData=0A=20CheckpointerRequest=0A=20= CheckpointerShmemStruct=0A+CheckType=0A+CheckTypeFilter=0A=20Chromosome=0A= =20CkptSortItem=0A=20CkptTsStatus=0A@@=20-2847,6=20+2849,8=20@@=20= ambuildempty_function=0A=20ambuildphasename_function=0A=20= ambulkdelete_function=0A=20amcanreturn_function=0A+amcheckObjects=0A= +amcheckOptions=0A=20amcostestimate_function=0A=20amendscan_function=0A=20= amestimateparallelscan_function=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A= =0A= --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 Content-Disposition: attachment; filename=v36-0005-Extending-PostgresNode-to-test-corruption.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v36-0005-Extending-PostgresNode-to-test-corruption.patch" Content-Transfer-Encoding: quoted-printable =46rom=2030808fc59c1a1eb6f9a238b70e103846de44b834=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Mark=20Dilger=20=0A= Date:=20Tue,=202=20Feb=202021=2012:37:58=20-0800=0ASubject:=20[PATCH=20= v36=205/5]=20Extending=20PostgresNode=20to=20test=20corruption.=0A=0A= PostgresNode=20now=20has=20functions=20for=20overwriting=20relation=20= files=0Awith=20full=20or=20partial=20prior=20versions=20of=20those=20= files,=20creating=0Acorruption=20beyond=20merely=20twiddling=20the=20= bits=20of=20a=20heap=20relation=0Afile.=0A=0AAdding=20a=20regression=20= test=20for=20pg_amcheck=20based=20on=20this=20new=0Afunctionality.=0A---=0A= =20contrib/pg_amcheck/t/006_relfile_damage.pl=20=20=20=20|=20135=20= +++++++++=0A=20src/test/modules/Makefile=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A=20= src/test/modules/corruption/Makefile=20=20=20=20=20=20=20=20=20=20|=20=20= 16=20++=0A=20.../modules/corruption/t/001_corruption.pl=20=20=20=20|=20=20= 83=20++++++=0A=20src/test/perl/PostgresNode.pm=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20261=20++++++++++++++++++=0A=205=20files=20= changed,=20496=20insertions(+)=0A=20create=20mode=20100644=20= contrib/pg_amcheck/t/006_relfile_damage.pl=0A=20create=20mode=20100644=20= src/test/modules/corruption/Makefile=0A=20create=20mode=20100644=20= src/test/modules/corruption/t/001_corruption.pl=0A=0Adiff=20--git=20= a/contrib/pg_amcheck/t/006_relfile_damage.pl=20= b/contrib/pg_amcheck/t/006_relfile_damage.pl=0Anew=20file=20mode=20= 100644=0Aindex=200000000000..d997db5b63=0A---=20/dev/null=0A+++=20= b/contrib/pg_amcheck/t/006_relfile_damage.pl=0A@@=20-0,0=20+1,135=20@@=0A= +use=20strict;=0A+use=20warnings;=0A+=0A+use=20TestLib;=0A+use=20= Test::More=20tests=20=3D>=2027;=0A+use=20PostgresNode;=0A+=0A+my=20= ($node,=20$port);=0A+=0A+#=20Returns=20the=20name=20of=20the=20toast=20= relation=20associated=20with=20the=20named=20relation.=0A+#=0A+#=20= Assumes=20the=20test=20node=20is=20running=0A+sub=20relation_toast($$)=0A= +{=0A+=09my=20($dbname,=20$relname)=20=3D=20@_;=0A+=0A+=09my=20$rel=20=3D=20= $node->safe_psql($dbname,=20qq(=0A+=09=09SELECT=20ct.relname=0A+=09=09=09= FROM=20pg_catalog.pg_class=20cr,=20pg_catalog.pg_class=20ct=0A+=09=09=09= WHERE=20cr.oid=20=3D=20'$relname'::regclass=0A+=09=09=09=20=20AND=20= cr.reltoastrelid=20=3D=20ct.oid=0A+=09=09=09));=0A+=09return=20undef=20= unless=20defined=20$rel;=0A+=09return=20"pg_toast.$rel";=0A+}=0A+=0A+#=20= Test=20set-up=0A+$node=20=3D=20get_new_node('test');=0A+$node->init;=0A= +$node->start;=0A+$port=20=3D=20$node->port;=0A+=0A+#=20Load=20the=20= amcheck=20extension,=20upon=20which=20pg_amcheck=20depends=0A= +$node->safe_psql('postgres',=20q(CREATE=20EXTENSION=20amcheck));=0A+=0A= +#=20Create=20a=20table=20with=20a=20btree=20index.=20=20Use=20a=20= fillfactor=20for=20the=20table=20and=20index=0A+#=20that=20will=20allow=20= some=20fraction=20of=20updates=20to=20be=20on=20the=20original=20pages=20= and=20some=0A+#=20on=20new=20pages.=0A+#=0A+$node->safe_psql('postgres',=20= qq(=0A+create=20schema=20t;=0A+create=20table=20t.t1=20(id=20integer,=20= t=20text)=20with=20(fillfactor=3D75);=0A+alter=20table=20t.t1=20alter=20= column=20t=20set=20storage=20external;=0A+insert=20into=20t.t1=20select=20= gs,=20repeat('x',gs)=20from=20generate_series(9990,10000)=20gs;=0A= +create=20index=20t1_idx=20on=20t.t1=20(id)=20with=20(fillfactor=3D75);=0A= +));=0A+=0A+my=20$toastrel=20=3D=20relation_toast('postgres',=20't.t1');=0A= +=0A+#=20Flush=20relation=20files=20to=20disk=20and=20take=20snapshots=20= of=20the=20toast=20and=20index=0A+#=0A+$node->restart;=0A= +$node->take_relfile_snapshot_minimal('postgres',=20'idx',=20= 't.t1_idx');=0A+$node->take_relfile_snapshot_minimal('postgres',=20= 'toast',=20$toastrel);=0A+=0A+#=20Insert=20new=20data=20into=20the=20= table=20and=20index=0A+#=0A+$node->safe_psql('postgres',=20qq(=0A+insert=20= into=20t.t1=20select=20gs,=20repeat('y',gs)=20from=20= generate_series(10001,10100)=20gs;=0A+));=0A+=0A+#=20Revert=20index.=20=20= The=20reverted=20snapshot=20file=20is=20not=20corrupt,=20but=20it=20also=0A= +#=20does=20not=20match=20the=20current=20contents=20of=20the=20table.=0A= +#=0A+$node->stop;=0A+$node->revert_to_snapshot('idx');=0A+=0A+#=20= Restart=20the=20node=20and=20check=20table=20and=20index=20with=20= varying=20options.=0A+#=0A+$node->start;=0A+=0A+#=20Checks=20which=20do=20= not=20reconcile=20the=20index=20and=20table=20via=20--heapallindexed=20= will=0A+#=20not=20notice=20any=20problems=0A+#=0A+$node->command_like(=0A= +=09[=20'pg_amcheck',=20'--quiet',=20'-p',=20$port,=20'-r',=20= 'postgres.t.*'=20],=0A+=09qr/^$/,=0A+=09'pg_amcheck=20reverted=20index=20= at=20default=20checking=20level');=0A+=0A+$node->command_like(=0A+=09[=20= 'pg_amcheck',=20'--quiet',=20'-p',=20$port,=20'-r',=20'postgres.t.*'=20= ],=0A+=09qr/^$/,=0A+=09'pg_amcheck=20reverted=20index=20at=20default=20= checking=20level');=0A+=0A+$node->command_like(=0A+=09[=20'pg_amcheck',=20= '--quiet',=20'-p',=20$port,=20'-r',=20'postgres.t.*',=20'--parent-check'=20= ],=0A+=09qr/^$/,=0A+=09'pg_amcheck=20reverted=20index=20with=20= --parent-check');=0A+=0A+$node->command_like(=0A+=09[=20'pg_amcheck',=20= '--quiet',=20'-p',=20$port,=20'-r',=20'postgres.t.*',=20'--rootdescend'=20= ],=0A+=09qr/^$/,=0A+=09'pg_amcheck=20reverted=20index=20with=20= --rootdescend');=0A+=0A+#=20Checks=20which=20do=20reconcile=20the=20= index=20and=20table=20via=20--heapallindexed=20will=0A+#=20notice=20the=20= mismatch=20in=20their=20contents=0A+#=0A+$node->command_like(=0A+=09[=20= 'pg_amcheck',=20'--quiet',=20'-p',=20$port,=20'-r',=20'postgres.t.*',=20= '--heapallindexed'=20],=0A+=09qr/heap=20tuple=20.*=20from=20table=20"t1"=20= lacks=20matching=20index=20tuple=20within=20index=20"t1_idx"/,=0A+=09= 'pg_amcheck=20reverted=20index=20with=20--heapallindexed');=0A+=0A= +$node->command_like(=0A+=09[=20'pg_amcheck',=20'--quiet',=20'-p',=20= $port,=20'-r',=20'postgres.t.*',=20'--heapallindexed',=20'--rootdescend'=20= ],=0A+=09qr/heap=20tuple=20.*=20from=20table=20"t1"=20lacks=20matching=20= index=20tuple=20within=20index=20"t1_idx"/,=0A+=09'pg_amcheck=20reverted=20= index=20with=20--heapallindexed=20--rootdescend');=0A+=0A+#=20Revert=20= the=20toast.=20=20The=20reverted=20toast=20table=20is=20not=20corrupt,=20= but=20it=20does=20not=0A+#=20have=20entries=20for=20all=20toast=20= pointers=20in=20the=20main=20table=0A+#=0A+$node->stop;=0A= +$node->revert_to_snapshot('toast');=0A+=0A+#=20Restart=20the=20node=20= and=20check=20table=20and=20toast=20with=20varying=20options.=20=20When=0A= +#=20checking=20the=20toast=20pointers,=20we=20may=20get=20errors=20= produced=20by=20verify_heapam,=20but=0A+#=20we=20may=20also=20get=20= errors=20from=20failure=20to=20read=20toast=20blocks=20that=20are=20= beyond=20the=0A+#=20end=20of=20the=20toast=20table,=20of=20the=20form=20= /ERROR:=20=20could=20not=20read=20block/.=20=20To=20avoid=0A+#=20having=20= a=20brittle=20test,=20we=20accept=20any=20error=20message.=0A+#=0A= +$node->start;=0A+=0A+$node->command_like(=0A+=09[=20'pg_amcheck',=20= '--quiet',=20'-p',=20$port,=20'-r',=20$toastrel=20],=0A+=09qr/^$/,=0A+=09= 'pg_amcheck=20reverted=20toast=20table');=0A+=0A+$node->command_like(=0A= +=09[=20'pg_amcheck',=20'--quiet',=20'-p',=20$port,=20'-r',=20= 'postgres.t.*',=20'--exclude-toast-pointers'=20],=0A+=09qr/^$/,=0A+=09= 'pg_amcheck=20with=20reverted=20toast=20using=20= --exclude-toast-pointers');=0A+=0A+$node->command_like(=0A+=09[=20= 'pg_amcheck',=20'--quiet',=20'-p',=20$port,=20'-r',=20'postgres.t.*'=20= ],=0A+=09qr/.+/,=09=09=09#=20Any=20non-empty=20error=20message=20is=20= acceptable=0A+=09'pg_amcheck=20with=20reverted=20toast=20and=20default=20= checking');=0Adiff=20--git=20a/src/test/modules/Makefile=20= b/src/test/modules/Makefile=0Aindex=205391f461a2..c92d1702b4=20100644=0A= ---=20a/src/test/modules/Makefile=0A+++=20b/src/test/modules/Makefile=0A= @@=20-7,6=20+7,7=20@@=20include=20$(top_builddir)/src/Makefile.global=0A=20= SUBDIRS=20=3D=20\=0A=20=09=09=20=20brin=20\=0A=20=09=09=20=20commit_ts=20= \=0A+=09=09=20=20corruption=20\=0A=20=09=09=20=20delay_execution=20\=0A=20= =09=09=20=20dummy_index_am=20\=0A=20=09=09=20=20dummy_seclabel=20\=0A= diff=20--git=20a/src/test/modules/corruption/Makefile=20= b/src/test/modules/corruption/Makefile=0Anew=20file=20mode=20100644=0A= index=200000000000..ba461c645d=0A---=20/dev/null=0A+++=20= b/src/test/modules/corruption/Makefile=0A@@=20-0,0=20+1,16=20@@=0A+#=20= src/test/modules/corruption/Makefile=0A+=0A+#=20EXTRA_INSTALL=20=3D=20= contrib/pg_amcheck=0A+=0A+TAP_TESTS=20=3D=201=0A+=0A+ifdef=20USE_PGXS=0A= +PG_CONFIG=20=3D=20pg_config=0A+PGXS=20:=3D=20$(shell=20$(PG_CONFIG)=20= --pgxs)=0A+include=20$(PGXS)=0A+else=0A+subdir=20=3D=20= src/test/modules/corruption=0A+top_builddir=20=3D=20../../../..=0A= +include=20$(top_builddir)/src/Makefile.global=0A+include=20= $(top_srcdir)/contrib/contrib-global.mk=0A+endif=0Adiff=20--git=20= a/src/test/modules/corruption/t/001_corruption.pl=20= b/src/test/modules/corruption/t/001_corruption.pl=0Anew=20file=20mode=20= 100644=0Aindex=200000000000..ae4a262e06=0A---=20/dev/null=0A+++=20= b/src/test/modules/corruption/t/001_corruption.pl=0A@@=20-0,0=20+1,83=20= @@=0A+use=20strict;=0A+use=20warnings;=0A+=0A+use=20TestLib;=0A+use=20= Test::More=20tests=20=3D>=2010;=0A+use=20PostgresNode;=0A+=0A+my=20$node=20= =3D=20get_new_node('test');=0A+$node->init;=0A+$node->start;=0A+=0A+#=20= Create=20something=20non-trivial=20for=20the=20first=20snapshot=0A= +$node->safe_psql('postgres',=20qq(=0A+create=20table=20t1=20(id=20= integer,=20short_text=20text,=20long_text=20text);=0A+insert=20into=20t1=20= (id,=20short_text,=20long_text)=0A+=09(select=20gs,=20'foo',=20= repeat('x',=20gs)=0A+=09=09from=20generate_series(1,10000)=20gs);=0A= +create=20unique=20index=20idx1=20on=20t1=20(id,=20short_text);=0A= +vacuum=20freeze;=0A+));=0A+=0A+#=20Flush=20relation=20files=20to=20disk=20= and=20take=20snapshot=20of=20them=0A+$node->restart;=0A= +$node->take_relfile_snapshot('postgres',=20'snap1',=20'public.t1');=0A+=0A= +#=20Update=20data=20in=20the=20table,=20toast=20table,=20and=20index=0A= +$node->safe_psql('postgres',=20qq(=0A+update=20t1=20set=0A+=09= short_text=20=3D=20'bar',=0A+=09long_text=20=3D=20repeat('y',=20id);=0A= +));=0A+=0A+#=20Flush=20relation=20files=20to=20disk=20and=20take=20= second=20snapshot=0A+$node->restart;=0A= +$node->take_relfile_snapshot('postgres',=20'snap2',=20'public.t1');=0A+=0A= +#=20Revert=20the=20first=20page=20of=20t1=20using=20a=20torn=20= snapshot.=20=20This=20should=20be=20a=20partial=0A+#=20and=20corrupt=20= reverting=20of=20the=20update.=0A+$node->stop;=0A= +$node->revert_to_torn_relfile_snapshot('snap1',=208192);=0A+=0A+#=20= Restart=20the=20node=20and=20count=20the=20number=20of=20rows=20in=20t1=20= with=20the=20original=0A+#=20(pre-update)=20values.=20=20It=20should=20= not=20be=20zero,=20but=20nor=20will=20it=20be=20the=20full=0A+#=2010000.=0A= +$node->start;=0A+my=20($old,=20$new,=20$oldtoast,=20$newtoast)=20=3D=20= counts();=0A+ok($old=20>=200=20&&=20$old=20<=2010000,=20"Torn=20snapshot=20= reverts=20some=20of=20the=20main=20updates");=0A+ok($new=20>=200=20&&=20= $new=20<=3D=2010000,=20"Torn=20snapshot=20retains=20some=20of=20the=20= main=20updates");=0A+=0A+#=20Revert=20t1=20fully=20to=20the=20first=20= snapshot.=20=20This=20should=20fully=20restore=20the=0A+#=20original=20= (pre-update)=20values.=0A+$node->stop;=0A= +$node->revert_to_snapshot('snap1');=0A+=0A+#=20Restart=20the=20node=20= and=20verify=20only=20old=20values=20remain=0A+$node->start;=0A+($old,=20= $new,=20$oldtoast,=20$newtoast)=20=3D=20counts();=0A+is($old,=2010000,=20= "Full=20snapshot=20restores=20all=20the=20old=20main=20values");=0A= +is($oldtoast,=2010000,=20"Full=20snapshot=20restores=20all=20the=20old=20= toast=20values");=0A+is($new,=200,=20"Full=20snapshot=20reverts=20all=20= the=20new=20main=20values");=0A+is($newtoast,=200,=20"Full=20snapshot=20= reverts=20all=20the=20new=20toast=20values");=0A+=0A+#=20Restore=20t1=20= fully=20to=20the=20second=20snapshot.=20=20This=20should=20fully=20= restore=20the=0A+#=20new=20(post-update)=20values.=0A+$node->stop;=0A= +$node->revert_to_snapshot('snap2');=0A+=0A+#=20Restart=20the=20node=20= and=20verify=20only=20new=20values=20remain=0A+$node->start;=0A+($old,=20= $new,=20$oldtoast,=20$newtoast)=20=3D=20counts();=0A+is($old,=200,=20= "Full=20snapshot=20reverts=20all=20the=20old=20main=20values");=0A= +is($oldtoast,=200,=20"Full=20snapshot=20reverts=20all=20the=20old=20= toast=20values");=0A+is($new,=2010000,=20"Full=20snapshot=20restores=20= all=20the=20new=20main=20values");=0A+is($newtoast,=2010000,=20"Full=20= snapshot=20restores=20all=20the=20new=20toast=20values");=0A+=0A+sub=20= counts=20{=0A+=09return=20map=20{=0A+=09=09$node->safe_psql('postgres',=20= qq(select=20count(*)=20from=20t1=20where=20$_))=0A+=09}=20("short_text=20= =3D=20'foo'",=0A+=09=20=20=20"short_text=20=3D=20'bar'",=0A+=09=20=20=20= "long_text=20~=20'x'",=0A+=09=20=20=20"long_text=20~=20'y'");=0A+}=0A= diff=20--git=20a/src/test/perl/PostgresNode.pm=20= b/src/test/perl/PostgresNode.pm=0Aindex=209667f7667e..d470af93c5=20= 100644=0A---=20a/src/test/perl/PostgresNode.pm=0A+++=20= b/src/test/perl/PostgresNode.pm=0A@@=20-2225,6=20+2225,267=20@@=20sub=20= pg_recvlogical_upto=0A=20=0A=20=3Dback=0A=20=0A+=3Dhead1=20DATABASE=20= CORRUPTION=20METHODS=0A+=0A+=3Dover=0A+=0A+=3Ditem=20= $node->relfile_snapshot_repository()=0A+=0A+The=20path=20to=20the=20= parent=20directory=20of=20all=20directories=20storing=20snapshots=20of=0A= +relation=20backing=20files.=0A+=0A+=3Dcut=0A+=0A+sub=20= relfile_snapshot_repository=0A+{=0A+=09my=20($self)=20=3D=20@_;=0A+=09my=20= $snaprepo=20=3D=20join('/',=20$self->basedir,=20'snapshot');=0A+=09= unless=20(-d=20$snaprepo)=0A+=09{=0A+=09=09mkdir=20$snaprepo=0A+=09=09=09= or=20$!{EEXIST}=0A+=09=09=09or=20BAIL_OUT("could=20not=20create=20= snapshot=20repository=20directory=20\"$snaprepo\":=20$!");=0A+=09}=0A+=09= return=20$snaprepo;=0A+}=0A+=0A+=3Dpod=0A+=0A+=3Ditem=20= $node->relfile_snapshot_directory(snapname)=0A+=0A+The=20path=20to=20the=20= directory=20for=20storing=20the=20named=20snapshot.=0A+=0A+=3Dcut=0A+=0A= +sub=20relfile_snapshot_directory=0A+{=0A+=09my=20($self,=20$snapname)=20= =3D=20@_;=0A+=0A+=09join("/",=20$self->relfile_snapshot_repository(),=20= $snapname);=0A+}=0A+=0A+=3Dpod=0A+=0A+=3Ditem=20= $node->take_relfile_snapshot($self,=20$dbname,=20$snapname,=20@relnames)=0A= +=0A+Makes=20a=20copy=20of=20the=20files=20backing=20the=20relations=20= B<@relname>,=20the=20associated=0A+toast=20relations=20(if=20any),=20and=20= all=20associated=20indexes=20(if=20any).=20=20No=20attempt=20is=0A+made=20= to=20flush=20these=20files=20to=20disk,=20meaning=20the=20snapshot=20= taken=20could=20be=20stale=0A+unless=20the=20caller=20ensures=20these=20= files=20have=20been=20flushed=20prior=20to=20calling.=0A+=0A+Dies=20on=20= failure=20to=20invoke=20psql.=0A+=0A+Dies=20on=20missing=20relations.=0A= +=0A+Dies=20if=20the=20given=20B<$snapname>=20is=20already=20in=20use.=0A= +=0A+=3Dcut=0A+=0A+=3Dpod=0A+=0A+=3Ditem=20= $node->take_relfile_snapshot_minimal($self,=20$dbname,=20$snapname,=20= @relnames)=0A+=0A+Makes=20a=20copy=20of=20the=20files=20backing=20the=20= relations=20B<@relnames>.=20=20No=20attempt=20is=20made=0A+to=20flush=20= these=20files=20to=20disk,=20meaning=20the=20snapshot=20taken=20could=20= be=20stale=20unless=20the=0A+caller=20ensures=20these=20files=20have=20= been=20flushed=20prior=20to=20calling.=0A+=0A+Dies=20on=20failure=20to=20= invoke=20psql.=0A+=0A+Dies=20on=20missing=20relation.=0A+=0A+Dies=20if=20= the=20given=20B<$snapname>=20is=20already=20in=20use.=0A+=0A+=3Dcut=0A+=0A= +sub=20take_relfile_snapshot=0A+{=0A+=09my=20($self,=20$dbname,=20= $snapname,=20@relnames)=20=3D=20@_;=0A+=09= $self->take_relfile_snapshot_helper($dbname,=20$snapname,=201,=20= @relnames);=0A+}=0A+=0A+sub=20take_relfile_snapshot_minimal=0A+{=0A+=09= my=20($self,=20$dbname,=20$snapname,=20@relnames)=20=3D=20@_;=0A+=09= $self->take_relfile_snapshot_helper($dbname,=20$snapname,=200,=20= @relnames);=0A+}=0A+=0A+sub=20take_relfile_snapshot_helper=0A+{=0A+=09my=20= ($self,=20$dbname,=20$snapname,=20$extended,=20@relnames)=20=3D=20@_;=0A= +=0A+=09croak=20"dbname=20must=20be=20specified"=20unless=20defined=20= $dbname;=0A+=09croak=20"relnames=20must=20be=20defined"=20unless=20= scalar(grep=20{=20defined=20$_=20}=20@relnames);=0A+=09croak=20"snapname=20= must=20be=20specified"=20unless=20defined=20$snapname;=0A+=09croak=20= "snapname=20must=20be=20unique"=20if=20exists=20= $self->{snapshot}->{$snapname};=0A+=0A+=09my=20$pgdata=20=3D=20= $self->data_dir;=0A+=09my=20$snapdir=20=3D=20= $self->relfile_snapshot_directory($snapname);=0A+=09croak=20"snapname=20= directory=20name=20already=20in=20use:=20$snapdir"=20if=20(-e=20= $snapdir);=0A+=09mkdir=20$snapdir=0A+=09=09or=20BAIL_OUT("could=20not=20= create=20snapshot=20directory=20\"$snapdir\":=20$!");=0A+=0A+=09my=20= @relpaths=20=3D=20map=20{=0A+=09=09$self->safe_psql($dbname,=0A+=09=09=09= qq(SELECT=20pg_relation_filepath('$_')));=0A+=09}=20@relnames;=0A+=0A+=09= my=20(@toastpaths,=20@idxpaths);=0A+=09if=20($extended)=0A+=09{=0A+=09=09= for=20my=20$relname=20(@relnames)=0A+=09=09{=0A+=09=09=09push=20= (@toastpaths,=20grep=20/\w/,=20split(/(?:\s*\r?\n\s*)+/,=20= $self->safe_psql($dbname,=0A+=09=09=09=09qq(SELECT=20= pg_relation_filepath(c.reltoastrelid)=0A+=09=09=09=09=09FROM=20= pg_catalog.pg_class=20c=0A+=09=09=09=09=09WHERE=20c.oid=20=3D=20= '$relname'::regclass=0A+=09=09=09=09=09AND=20c.reltoastrelid=20!=3D=20= 0::oid))));=0A+=09=09=09push=20(@idxpaths,=20grep=20/\w/,=20= split(/(?:\s*\r?\n\s*)+/,=20$self->safe_psql($dbname,=0A+=09=09=09=09= qq(SELECT=20pg_relation_filepath(i.indexrelid)=0A+=09=09=09=09=09FROM=20= pg_catalog.pg_index=20i=0A+=09=09=09=09=09WHERE=20i.indrelid=20=3D=20= '$relname'::regclass))));=0A+=09=09}=0A+=09}=0A+=0A+=09= $self->{snapshot}->{$snapname}=20=3D=20{};=0A+=09for=20my=20$path=20= (@relpaths,=20grep=20{=20defined($_)=20}=20@toastpaths,=20@idxpaths)=0A+=09= {=0A+=09=09croak=20"file=20backing=20relation=20is=20missing:=20= $pgdata/$path"=20unless=20-f=20"$pgdata/$path";=0A+=09=09= copy_file($snapdir,=20$pgdata,=200,=20$path);=0A+=09=09= $self->{snapshot}->{$snapname}->{$path}=20=3D=201;=0A+=09}=0A+}=0A+=0A= +=3Dpod=0A+=0A+=3Ditem=20$node->revert_to_snapshot($self,=20$snapname)=0A= +=0A+Overwrites=20the=20database's=20relation=20files=20with=20files=20= previously=20saved=20in=0A+B<$snapname>.=0A+=0A+Dies=20if=20the=20given=20= B<$snapname>=20does=20not=20exist.=0A+=0A+=3Dcut=0A+=0A+=3Dpod=0A+=0A= +=3Ditem=20$node->revert_to_torn_relfile_snapshot($self,=20$snapname,=20= $bytes)=0A+=0A+Partially=20overwrites=20the=20database's=20relation=20= files=20using=20prefixes=20of=20the=20given=0A+number=20of=20bytes=20= from=20the=20files=20saved=20in=20B<$snapname>.=20=20If=20B<$bytes>=20is=0A= +negative,=20uses=20suffixes=20of=20the=20given=20byte=20length=20rather=20= than=20prefixes.=0A+=0A+If=20B<$bytes>=20is=20null,=20replaces=20the=20= database's=20relation=20files=20using=20the=20saved=0A+files=20in=20the=20= B<$snapname>,=20which=20unlike=20for=20non-undef=20values,=20means=20the=20= file=0A+may=20become=20shorter=20if=20the=20saved=20file=20is=20shorter=20= than=20the=20current=20file.=0A+=0A+=3Dcut=0A+=0A+sub=20= revert_to_snapshot=0A+{=0A+=09my=20($self,=20$snapname)=20=3D=20@_;=0A+=09= $self->revert_to_torn_relfile_snapshot($snapname,=20undef);=0A+}=0A+=0A= +sub=20revert_to_torn_relfile_snapshot=0A+{=0A+=09my=20($self,=20= $snapname,=20$bytes)=20=3D=20@_;=0A+=0A+=09croak=20"no=20such=20= snapshot"=20unless=20exists=20$self->{snapshot}->{$snapname};=0A+=0A+=09= my=20$pgdata=20=3D=20$self->data_dir;=0A+=09my=20$snaprepo=20=3D=20= join('/',=20$self->relfile_snapshot_repository,=20$snapname);=0A+=09= croak=20"snapname=20directory=20missing:=20$snaprepo"=20unless=20(-d=20= $snaprepo);=0A+=0A+=09if=20(defined=20$bytes)=0A+=09{=0A+=09=09= tear_file($pgdata,=20$snaprepo,=20$bytes,=20$_)=0A+=09=09=09for=20(keys=20= %{$self->{snapshot}->{$snapname}});=0A+=09}=0A+=09else=0A+=09{=0A+=09=09= copy_file($pgdata,=20$snaprepo,=201,=20$_)=0A+=09=09=09for=20(keys=20= %{$self->{snapshot}->{$snapname}});=0A+=09}=0A+}=0A+=0A+sub=20copy_file=0A= +{=0A+=09my=20($dstdir,=20$srcdir,=20$overwrite,=20$path)=20=3D=20@_;=0A= +=0A+=09croak=20"No=20such=20directory:=20$dstdir"=20unless=20-d=20= $dstdir;=0A+=09croak=20"No=20such=20directory:=20$srcdir"=20unless=20-d=20= $srcdir;=0A+=0A+=09foreach=20my=20$part=20(split(m{/},=20$path))=0A+=09{=0A= +=09=09my=20$srcpart=20=3D=20"$srcdir/$part";=0A+=09=09my=20$dstpart=20=3D= =20"$dstdir/$part";=0A+=0A+=09=09if=20(-d=20$srcpart)=0A+=09=09{=0A+=09=09= =09$srcdir=20=3D=20$srcpart;=0A+=09=09=09$dstdir=20=3D=20$dstpart;=0A+=09= =09=09die=20"$dstdir=20is=20in=20the=20way"=20if=20(-e=20$dstdir=20&&=20= !=20-d=20$dstdir);=0A+=09=09=09unless=20(-d=20$dstdir)=0A+=09=09=09{=0A+=09= =09=09=09mkdir=20$dstdir=0A+=09=09=09=09=09or=20BAIL_OUT("could=20not=20= create=20directory=20\"$dstdir\":=20$!");=0A+=09=09=09}=0A+=09=09}=0A+=09= =09elsif=20(-f=20$srcpart)=0A+=09=09{=0A+=09=09=09die=20"$dstdir/$part=20= is=20in=20the=20way"=20if=20(!$overwrite=20&&=20-e=20"$dstdir/$part");=0A= +=0A+=09=09=09File::Copy::copy($srcpart,=20"$dstdir/$part");=0A+=09=09}=0A= +=09}=0A+}=0A+=0A+sub=20tear_file=0A+{=0A+=09my=20($dstdir,=20$srcdir,=20= $bytes,=20$path)=20=3D=20@_;=0A+=0A+=09croak=20"No=20such=20directory:=20= $dstdir"=20unless=20-d=20$dstdir;=0A+=09croak=20"No=20such=20directory:=20= $srcdir"=20unless=20-d=20$srcdir;=0A+=0A+=09my=20$srcfile=20=3D=20= "$srcdir/$path";=0A+=09my=20$dstfile=20=3D=20"$dstdir/$path";=0A+=0A+=09= croak=20"No=20such=20file:=20$srcfile"=20unless=20-f=20$srcfile;=0A+=09= croak=20"No=20such=20file:=20$dstfile"=20unless=20-f=20$dstfile;=0A+=0A+=09= my=20($srcfh,=20$dstfh);=0A+=09open($srcfh,=20'<',=20$srcfile)=20or=20= die=20"Cannot=20read=20$srcfile:=20$!";=0A+=09open($dstfh,=20'+<',=20= $dstfile)=20or=20die=20"Cannot=20modify=20$dstfile:=20$!";=0A+=09= binmode($srcfh);=0A+=09binmode($dstfh);=0A+=0A+=09my=20$buffer;=0A+=09if=20= ($bytes=20<=200)=0A+=09{=0A+=09=09$bytes=20*=3D=20-1;=09=09#=20Easier=20= to=20use=20positive=20value=0A+=09=09my=20$srcsize=20=3D=20= (stat($srcfh))[7];=0A+=09=09my=20$offset=20=3D=20$srcsize=20-=20$bytes;=0A= +=09=09seek($srcfh,=20$offset,=200);=0A+=09=09seek($dstfh,=20$offset,=20= 0);=0A+=09=09sysread($srcfh,=20$buffer,=20$bytes);=0A+=09=09= syswrite($dstfh,=20$buffer,=20$bytes);=0A+=09}=0A+=09else=0A+=09{=0A+=09=09= seek($srcfh,=200,=200);=0A+=09=09seek($dstfh,=200,=200);=0A+=09=09= sysread($srcfh,=20$buffer,=20$bytes);=0A+=09=09syswrite($dstfh,=20= $buffer,=20$bytes);=0A+=09}=0A+=0A+=09close($srcfh);=0A+=09= close($dstfh);=0A+}=0A+=0A+=3Dpod=0A+=0A+=3Dback=0A+=0A=20=3Dcut=0A=20=0A= =201;=0A--=20=0A2.21.1=20(Apple=20Git-122.3)=0A=0A= --Apple-Mail=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34 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=_4EE2FE81-6BFF-45AD-B63B-1E209D0FCD34--