Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wXF0J-0039J3-22 for pgsql-hackers@arkaria.postgresql.org; Wed, 10 Jun 2026 09:13:43 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wXF0I-00AJlo-1c for pgsql-hackers@arkaria.postgresql.org; Wed, 10 Jun 2026 09:13:42 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wXF0I-00AJlf-0Q for pgsql-hackers@lists.postgresql.org; Wed, 10 Jun 2026 09:13:42 +0000 Received: from mail-pl1-x62b.google.com ([2607:f8b0:4864:20::62b]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wXF0F-00000002IvM-1Gzf for pgsql-hackers@lists.postgresql.org; Wed, 10 Jun 2026 09:13:41 +0000 Received: by mail-pl1-x62b.google.com with SMTP id d9443c01a7336-2c0c3543590so43793305ad.2 for ; Wed, 10 Jun 2026 02:13:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781082817; x=1781687617; darn=lists.postgresql.org; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=yNUx+ouFRWQCZMpUpsw1vfQ92XjLtCoNiPNWflUhjVA=; b=sxi1ocDw5vVvyt5GegB1VXXPTwoOAH8Dx1EMcpO8dhzVzTP7hGLxGQz9abRgB41jjl 9D7S+WMqfeCMFvb7VSrlRe71tbgKhYDmH5DtySmZ9W1vKagI7c1NIxq9tgFLr1RVnqTq 7TPjscmWWTIcfXf3S1O7IPLORyfJR/V6JbWCAVMc0CHGQEcWYzuYhs4yb4CdggflR2N7 c0GboQc9zE6MJuU/LwNorqt6DHREYP+ueBUhGEdNxGRafKWjv6Ak4Qw3xzdGOUc1r5/a TwTS8H/RnMGn6cFe+VmVcVf2MfiulFhqMMAEGSCmVE1YUtNOJtziLPRFVh4CAR57TFBm rdNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781082817; x=1781687617; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=yNUx+ouFRWQCZMpUpsw1vfQ92XjLtCoNiPNWflUhjVA=; b=Am61h0vHKgjXB04q8KVaIsKUTJ3aR6HadD9G2h3NWmyR/kyvPGtJMy1MI7meOMbaL+ Znch4GFbm+wteyB93831v1eby0GP5WAsDSoRDPlNs6U8E5k+jvuc8Tm4/CAivIBO6A7t kPWSls/4dXZ5C/bAfIqxjp4p0GEMUHinroqROBndpd+mw9+fqukW+yefmOW0uhHCNWEx zhb+XMEn6dnK0zXB3IUazb74TxpSpov+4s7Gh7mgZG/ZyIcoF+5ZESgxqsv6Pp0lv39W mGnEC0AqpPDHxnEgP0MoFKtrjGn2VsBTMrgP6IOPvan366jW4hOAugKAwRTOCFeWNyvq SQeg== X-Gm-Message-State: AOJu0YwB29ATX9T5P41yezLwc8EuqmhISe9LjoDm4XqTHtoL+/fIznfH fPT4xDv/IAvaIdlvwvzPNJw7ObCzA9d3emIMxa6pz6R2w1WeIIuGBZfYhlMYjAiB X-Gm-Gg: Acq92OEyfkJTQImIWq63oqKKbJUQHxbmv+gcJdcY7Que/nyrVVwrDT/GOBAkEF9Q/y6 NkMJaEO4ErR6ljEArQYotr04RDvOi/A+PP8jSsmTaAK2L1yJwVzPskqe+jOM0UXxnDVMPbOo0tX kVSz+g6DnyV/5kBLFv+q9kx4CamvG6G3zkSxnYmpR0wKVTUGsDvQuOuMEla3p4oHUx+cWkomdN/ UdZ0+RSX9VcgyPpOKpR7uqh9zWygYNupaYOwew6Q2BVsy8P4JaBpZCUxsLsD0HBWOy0bRE9JXLB rZ0pyNaUuyaAKJa1mIxWZCSkDu1bKtXB/i/Vi5n2JP7qnaTEEUmo4DwH0nhrqpa3tbQIZ4H6l3g Dok7+6xv5nQ14K94IkHtTc86kGpPQr/Bzqdd7Q3wuRM/TL3sYip+ivACKzmY75ZWewYul1qvJm5 W3qAU82hmiGwr9Ci1t+709XNDfEvv9yF9vThnz3A/HEm4= X-Received: by 2002:a17:903:38d0:b0:2bd:ba75:81c4 with SMTP id d9443c01a7336-2c1e7b150a9mr306915375ad.13.1781082816987; Wed, 10 Jun 2026 02:13:36 -0700 (PDT) Received: from smtpclient.apple ([185.135.79.161]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2c164f9f358sm236095495ad.30.2026.06.10.02.13.33 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Jun 2026 02:13:36 -0700 (PDT) From: Chao Li Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_63FFC136-2AAB-4146-9F3D-3500A614C1CE" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: Fix SET EXPRESSION for virtual columns with whole-row dependencies Date: Wed, 10 Jun 2026 17:12:58 +0800 In-Reply-To: Cc: Postgres hackers , Peter Eisentraut To: jian he References: <71242FEA-15A3-4073-9FA1-561CA744ACBD@gmail.com> <5B739323-C897-4B1A-9BFC-656E5CB4AD58@gmail.com> X-Mailer: Apple Mail (2.3864.600.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_63FFC136-2AAB-4146-9F3D-3500A614C1CE Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On Jun 10, 2026, at 17:05, Chao Li wrote: >=20 >=20 >=20 >> On Jun 9, 2026, at 15:28, Chao Li wrote: >>=20 >>=20 >>=20 >>> On Jun 9, 2026, at 15:23, jian he = wrote: >>>=20 >>> On Tue, Jun 9, 2026 at 2:23=E2=80=AFPM Chao Li = wrote: >>>>=20 >>>> Hi, >>>>=20 >>>> While testing =E2=80=9C[f80bedd52] Allow ALTER COLUMN SET = EXPRESSION on virtual columns=E2=80=9D, I found that the feature missed = handling whole-row check constraints. >>>>=20 >>>> Here is a repro: >>>> ``` >>>> evantest=3D# create table t( >>>> evantest(# a int, >>>> evantest(# b int generated always as (a*2) virtual, >>>> evantest(# constraint row_c check (t is not null) >>>> evantest(# ); >>>> CREATE TABLE >>>> evantest=3D# insert into t(a) values(1); >>>> INSERT 0 1 >>>> evantest=3D# alter table t alter b set expression as (nullif(a, = 1)); >>>> ALTER TABLE >>>> evantest=3D# select * from t; >>>> a | b >>>> ---+--- >>>> 1 | >>>> (1 row) >>>> ``` >>>>=20 >>>> The ALTER TABLE should fail, because it makes b become NULL, which = breaks the constraint row_c. >>>>=20 >>>=20 >>> Hi. >>>=20 >>> In case you are wondering whole-row objects: >>> ALTER TABLE DROP COLUMN and ALTER COLUMN SET DATA TYPE are covered = by >>> https://commitfest.postgresql.org/patch/5988 and >>> https://commitfest.postgresql.org/patch/6055. >>>=20 >>> Meanwhile, ALTER TABLE SET EXPRESSION is being handled over in >>> https://commitfest.postgresql.org/patch/6755 >>=20 >> Thanks for pointing out that. I will review 6755. >>=20 >> Best regards, >> -- >> Chao Li (Evan) >> HighGo Software Co., Ltd. >> https://www.highgo.com/ >>=20 >=20 > After reading the other implementation in [1], I realized that I had = missed the partial-index case, so I added coverage for that. >=20 > I am still sending an updated version of this patch because my = implementation is different from the one in [1]. I would like people to = compare the two approaches and decide which direction is better. >=20 > [1] = https://postgr.es/m/CAJTYsWXOkyeDVbzymWc9sKrq7Y_MUv6XJXN4H9GfsBOPd3NJ+w@ma= il.gmail.com >=20 > Best regards, > -- > Chao Li (Evan) > HighGo Software Co., Ltd. > https://www.highgo.com/ >=20 >=20 Oops! Forgot the attachment. Here comes it. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_63FFC136-2AAB-4146-9F3D-3500A614C1CE Content-Disposition: attachment; filename=v2-0001-Fix-SET-EXPRESSION-with-whole-row-virtual-column-.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0001-Fix-SET-EXPRESSION-with-whole-row-virtual-column-.patch" Content-Transfer-Encoding: quoted-printable =46rom=2019b577b3e5ea2c1ec2e88e6b3009e5375f7b7c61=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Tue,=209=20Jun=202026=2014:05:00=20+0800=0ASubject:=20[PATCH=20= v2]=20Fix=20SET=20EXPRESSION=20with=20whole-row=20virtual=20column=0A=20= dependencies=0A=0AALTER=20COLUMN=20SET=20EXPRESSION=20on=20a=20virtual=20= generated=20column=20only=20looked=20for=0Adependencies=20on=20the=20= column's=20attnum.=20=20Whole-row=20expressions,=20such=20as=0A"rel=20IS=20= NOT=20NULL",=20depend=20on=20the=20relation=20as=20a=20whole=20instead,=20= but=20they=20can=0Astill=20observe=20the=20virtual=20column's=20computed=20= value.=0A=0ATeach=20the=20SET=20EXPRESSION=20path=20to=20also=20scan=20= whole-relation=20dependencies=20for=0Agenerated=20columns.=20=20This=20= lets=20whole-row=20CHECK=20constraints=20be=20revalidated=0Aand=20= whole-row=20expression=20indexes=20be=20rebuilt=20after=20the=20= expression=20changes.=0A=0AAdd=20regression=20coverage=20for=20a=20= whole-row=20CHECK=20constraint,=20a=20whole-row=0Aexpression=20index,=20= and=20an=20ordinary=20index=20that=20should=20not=20be=20rebuilt.=0A=0A= Author:=20Chao=20Li=20=0ADiscussion:=20= https://postgr.es/m/71242FEA-15A3-4073-9FA1-561CA744ACBD@gmail.com=0A= Discussion:=20= https://postgr.es/m/CAJTYsWXOkyeDVbzymWc9sKrq7Y_MUv6XJXN4H9GfsBOPd3NJ+w@ma= il.gmail.com=0A---=0A=20src/backend/commands/tablecmds.c=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20123=20+++++++++++++++++-=0A=20= .../regress/expected/generated_stored.out=20=20=20=20=20|=20=2011=20++=0A= =20.../regress/expected/generated_virtual.out=20=20=20=20|=20=2027=20= ++++=0A=20src/test/regress/sql/generated_stored.sql=20=20=20=20=20|=20=20= =205=20+=0A=20src/test/regress/sql/generated_virtual.sql=20=20=20=20|=20=20= 11=20++=0A=205=20files=20changed,=20174=20insertions(+),=203=20= deletions(-)=0A=0Adiff=20--git=20a/src/backend/commands/tablecmds.c=20= b/src/backend/commands/tablecmds.c=0Aindex=20a33e22e8e61..a4b80fa596b=20= 100644=0A---=20a/src/backend/commands/tablecmds.c=0A+++=20= b/src/backend/commands/tablecmds.c=0A@@=20-43,6=20+43,7=20@@=0A=20= #include=20"catalog/pg_extension_d.h"=0A=20#include=20= "catalog/pg_foreign_table.h"=0A=20#include=20"catalog/pg_inherits.h"=0A= +#include=20"catalog/pg_index.h"=0A=20#include=20= "catalog/pg_largeobject.h"=0A=20#include=20= "catalog/pg_largeobject_metadata.h"=0A=20#include=20= "catalog/pg_namespace.h"=0A@@=20-686,6=20+687,7=20@@=20static=20= ObjectAddress=20ATExecAlterColumnType(AlteredTableInfo=20*tab,=20= Relation=20rel,=0A=20=09=09=09=09=09=09=09=09=09=09=20=20=20= AlterTableCmd=20*cmd,=20LOCKMODE=20lockmode);=0A=20static=20void=20= RememberAllDependentForRebuilding(AlteredTableInfo=20*tab,=20= AlterTableType=20subtype,=0A=20=09=09=09=09=09=09=09=09=09=09=09=20=20= Relation=20rel,=20AttrNumber=20attnum,=20const=20char=20*colName);=0A= +static=20void=20RememberWholeRowIndexesForRebuilding(AlteredTableInfo=20= *tab,=20Relation=20rel);=0A=20static=20void=20= RememberConstraintForRebuilding(Oid=20conoid,=20AlteredTableInfo=20= *tab);=0A=20static=20void=20RememberIndexForRebuilding(Oid=20indoid,=20= AlteredTableInfo=20*tab);=0A=20static=20void=20= RememberStatisticsForRebuilding(Oid=20stxoid,=20AlteredTableInfo=20= *tab);=0A@@=20-8766,6=20+8768,20=20@@=20= ATExecSetExpression(AlteredTableInfo=20*tab,=20Relation=20rel,=20const=20= char=20*colName,=0A=20=09=20*/=0A=20=09= RememberAllDependentForRebuilding(tab,=20AT_SetExpression,=20rel,=20= attnum,=20colName);=0A=20=0A+=09/*=0A+=09=20*=20Whole-row=20expressions,=20= such=20as=20"rel=20IS=20NOT=20NULL",=20depend=20on=20the=0A+=09=20*=20= relation=20as=20a=20whole=20rather=20than=20on=20the=20generated=20= column's=20attnum,=20but=0A+=09=20*=20they=20can=20observe=20the=20= column's=20new=20computed=20value.=0A+=09=20*/=0A+=09= RememberAllDependentForRebuilding(tab,=20AT_SetExpression,=20rel,=200,=20= NULL);=0A+=0A+=09/*=0A+=09=20*=20recordDependencyOnSingleRelExpr()=20= does=20not=20emit=20dependencies=20for=0A+=09=20*=20whole-row=20Vars,=20= so=20indexes=20with=20ordinary=20key=20columns=20and=20whole-row=0A+=09=20= *=20predicates=20might=20not=20have=20a=20whole-relation=20dependency=20= to=20find=20above.=0A+=09=20*/=0A+=09= RememberWholeRowIndexesForRebuilding(tab,=20rel);=0A+=0A=20=09/*=0A=20=09= =20*=20Drop=20the=20dependency=20records=20of=20the=20GENERATED=20= expression,=20in=20particular=0A=20=09=20*=20its=20INTERNAL=20dependency=20= on=20the=20column,=20which=20would=20otherwise=20cause=0A@@=20-15290,10=20= +15306,88=20@@=20ATExecAlterColumnType(AlteredTableInfo=20*tab,=20= Relation=20rel,=0A=20=09return=20address;=0A=20}=0A=20=0A+/*=0A+=20*=20= Return=20true=20if=20the=20expression=20contains=20a=20whole-row=20Var.=0A= +=20*/=0A+static=20bool=0A+expr_has_whole_row_var(Node=20*expr)=0A+{=0A+=09= Bitmapset=20=20*expr_attrs=20=3D=20NULL;=0A+=09bool=09=09result;=0A+=0A+=09= pull_varattnos(expr,=201,=20&expr_attrs);=0A+=09result=20=3D=20= bms_is_member(InvalidAttrNumber=20-=20= FirstLowInvalidHeapAttributeNumber,=0A+=09=09=09=09=09=09=20=20=20= expr_attrs);=0A+=09bms_free(expr_attrs);=0A+=0A+=09return=20result;=0A+}=0A= +=0A+/*=0A+=20*=20Find=20indexes=20whose=20expressions=20or=20predicates=20= contain=20whole-row=20Vars,=20and=0A+=20*=20remember=20them=20for=20= rebuilding.=0A+=20*/=0A+static=20void=0A= +RememberWholeRowIndexesForRebuilding(AlteredTableInfo=20*tab,=20= Relation=20rel)=0A+{=0A+=09Relation=09pg_index;=0A+=09ScanKeyData=20key;=0A= +=09SysScanDesc=20scan;=0A+=09HeapTuple=09indexTuple;=0A+=0A+=09pg_index=20= =3D=20table_open(IndexRelationId,=20AccessShareLock);=0A+=0A+=09= ScanKeyInit(&key,=0A+=09=09=09=09Anum_pg_index_indrelid,=0A+=09=09=09=09= BTEqualStrategyNumber,=20F_OIDEQ,=0A+=09=09=09=09= ObjectIdGetDatum(RelationGetRelid(rel)));=0A+=0A+=09scan=20=3D=20= systable_beginscan(pg_index,=20IndexIndrelidIndexId,=20true,=0A+=09=09=09= =09=09=09=09=20=20NULL,=201,=20&key);=0A+=0A+=09while=20= (HeapTupleIsValid(indexTuple=20=3D=20systable_getnext(scan)))=0A+=09{=0A= +=09=09Form_pg_index=20index=20=3D=20(Form_pg_index)=20= GETSTRUCT(indexTuple);=0A+=09=09bool=09=09remember=20=3D=20false;=0A+=09=09= Datum=09=09exprDatum;=0A+=09=09char=09=20=20=20*exprString;=0A+=09=09= bool=09=09isnull;=0A+=0A+=09=09exprDatum=20=3D=20fastgetattr(indexTuple,=20= Anum_pg_index_indexprs,=0A+=09=09=09=09=09=09=09=09= RelationGetDescr(pg_index),=20&isnull);=0A+=09=09if=20(!isnull)=0A+=09=09= {=0A+=09=09=09exprString=20=3D=20TextDatumGetCString(exprDatum);=0A+=09=09= =09remember=20=3D=20expr_has_whole_row_var((Node=20*)=20= stringToNode(exprString));=0A+=09=09=09pfree(exprString);=0A+=09=09}=0A+=0A= +=09=09if=20(!remember)=0A+=09=09{=0A+=09=09=09exprDatum=20=3D=20= fastgetattr(indexTuple,=20Anum_pg_index_indpred,=0A+=09=09=09=09=09=09=09= =09=09RelationGetDescr(pg_index),=20&isnull);=0A+=09=09=09if=20(!isnull)=0A= +=09=09=09{=0A+=09=09=09=09exprString=20=3D=20= TextDatumGetCString(exprDatum);=0A+=09=09=09=09remember=20=3D=20= expr_has_whole_row_var((Node=20*)=20stringToNode(exprString));=0A+=09=09=09= =09pfree(exprString);=0A+=09=09=09}=0A+=09=09}=0A+=0A+=09=09if=20= (remember)=0A+=09=09=09RememberIndexForRebuilding(index->indexrelid,=20= tab);=0A+=09}=0A+=0A+=09systable_endscan(scan);=0A+=09= table_close(pg_index,=20AccessShareLock);=0A+}=0A+=0A=20/*=0A=20=20*=20= Subroutine=20for=20ATExecAlterColumnType=20and=20ATExecSetExpression:=20= Find=20everything=0A=20=20*=20that=20depends=20on=20the=20column=20= (constraints,=20indexes,=20etc),=20and=20record=20enough=0A-=20*=20= information=20to=20let=20us=20recreate=20the=20objects.=0A+=20*=20= information=20to=20let=20us=20recreate=20the=20objects.=20=20= ATExecSetExpression=20can=20also=0A+=20*=20pass=20attnum=20=3D=3D=200=20= to=20find=20whole-row=20expression=20dependencies=20that=20observe=20a=0A= +=20*=20generated=20column's=20computed=20value.=0A=20=20*/=0A=20static=20= void=0A=20RememberAllDependentForRebuilding(AlteredTableInfo=20*tab,=20= AlterTableType=20subtype,=0A@@=20-15305,6=20+15399,7=20@@=20= RememberAllDependentForRebuilding(AlteredTableInfo=20*tab,=20= AlterTableType=20subtype,=0A=20=09HeapTuple=09depTup;=0A=20=0A=20=09= Assert(subtype=20=3D=3D=20AT_AlterColumnType=20||=20subtype=20=3D=3D=20= AT_SetExpression);=0A+=09Assert(attnum=20!=3D=200=20||=20subtype=20=3D=3D=20= AT_SetExpression);=0A=20=0A=20=09depRel=20=3D=20= table_open(DependRelationId,=20RowExclusiveLock);=0A=20=0A@@=20-15355,6=20= +15450,15=20@@=20RememberAllDependentForRebuilding(AlteredTableInfo=20= *tab,=20AlterTableType=20subtype,=0A=20=09=09=09=09=09}=0A=20=09=09=09=09= =09else=0A=20=09=09=09=09=09{=0A+=09=09=09=09=09=09/*=0A+=09=09=09=09=09=09= =20*=20In=20a=20whole-relation=20scan=20for=20SET=20EXPRESSION,=20ignore=0A= +=09=09=09=09=09=09=20*=20relation=20dependencies=20that=20are=20not=20= indexes.=20=20Objects=0A+=09=09=09=09=09=09=20*=20with=20expressions=20= that=20need=20action,=20such=20as=0A+=09=09=09=09=09=09=20*=20= constraints,=20are=20handled=20by=20their=20own=20cases.=0A+=09=09=09=09=09= =09=20*/=0A+=09=09=09=09=09=09if=20(attnum=20=3D=3D=200)=0A+=09=09=09=09=09= =09=09break;=0A+=0A=20=09=09=09=09=09=09/*=20Not=20expecting=20any=20= other=20direct=20dependencies...=20*/=0A=20=09=09=09=09=09=09elog(ERROR,=20= "unexpected=20object=20depending=20on=20column:=20%s",=0A=20=09=09=09=09=09= =09=09=20getObjectDescription(&foundObject,=20false));=0A@@=20-15364,7=20= +15468,14=20@@=20RememberAllDependentForRebuilding(AlteredTableInfo=20= *tab,=20AlterTableType=20subtype,=0A=20=0A=20=09=09=09case=20= ConstraintRelationId:=0A=20=09=09=09=09Assert(foundObject.objectSubId=20= =3D=3D=200);=0A-=09=09=09=09= RememberConstraintForRebuilding(foundObject.objectId,=20tab);=0A+=09=09=09= =09if=20(attnum=20=3D=3D=200)=0A+=09=09=09=09{=0A+=09=09=09=09=09/*=20= Whole-row=20CHECK=20constraints=20may=20need=20to=20be=20revalidated=20= */=0A+=09=09=09=09=09if=20(get_constraint_type(foundObject.objectId)=20= =3D=3D=20CONSTRAINT_CHECK)=0A+=09=09=09=09=09=09= RememberConstraintForRebuilding(foundObject.objectId,=20tab);=0A+=09=09=09= =09}=0A+=09=09=09=09else=0A+=09=09=09=09=09= RememberConstraintForRebuilding(foundObject.objectId,=20tab);=0A=20=09=09= =09=09break;=0A=20=0A=20=09=09=09case=20ProcedureRelationId:=0A@@=20= -15505,8=20+15616,14=20@@=20= RememberAllDependentForRebuilding(AlteredTableInfo=20*tab,=20= AlterTableType=20subtype,=0A=20=0A=20=09=09=09=09/*=0A=20=09=09=09=09=20= *=20We=20don't=20expect=20any=20other=20sorts=20of=20objects=20to=20= depend=20on=20a=0A-=09=09=09=09=20*=20column.=0A+=09=09=09=09=20*=20= column.=20=20A=20whole-relation=20scan=20can=20find=20the=20relation's=20= row=0A+=09=09=09=09=20*=20type,=20which=20doesn't=20need=20rebuilding=20= for=20SET=20EXPRESSION.=0A=20=09=09=09=09=20*/=0A+=09=09=09=09if=20= (attnum=20=3D=3D=200=20&&=0A+=09=09=09=09=09foundObject.classId=20=3D=3D=20= TypeRelationId=20&&=0A+=09=09=09=09=09= get_typ_typrelid(foundObject.objectId)=20=3D=3D=20RelationGetRelid(rel))=0A= +=09=09=09=09=09continue;=0A+=0A=20=09=09=09=09elog(ERROR,=20"unexpected=20= object=20depending=20on=20column:=20%s",=0A=20=09=09=09=09=09=20= getObjectDescription(&foundObject,=20false));=0A=20=09=09=09=09break;=0A= diff=20--git=20a/src/test/regress/expected/generated_stored.out=20= b/src/test/regress/expected/generated_stored.out=0Aindex=20= 7866ae0ebbe..b6ec6819fd9=20100644=0A---=20= a/src/test/regress/expected/generated_stored.out=0A+++=20= b/src/test/regress/expected/generated_stored.out=0A@@=20-688,6=20+688,17=20= @@=20INSERT=20INTO=20gtest20c=20VALUES=20(1);=20=20--=20ok=0A=20INSERT=20= INTO=20gtest20c=20VALUES=20(NULL);=20=20--=20fails=0A=20ERROR:=20=20new=20= row=20for=20relation=20"gtest20c"=20violates=20check=20constraint=20= "whole_row_check"=0A=20DETAIL:=20=20Failing=20row=20contains=20(null,=20= null).=0A+ALTER=20TABLE=20gtest20c=20ALTER=20COLUMN=20b=20SET=20= EXPRESSION=20AS=20(nullif(a,=201));=20--=20fails=0A+ERROR:=20=20check=20= constraint=20"whole_row_check"=20of=20relation=20"gtest20c"=20is=20= violated=20by=20some=20row=0A+CREATE=20INDEX=20gtest20c_expr_idx=20ON=20= gtest20c=20((gtest20c=20IS=20NOT=20NULL));=0A+SELECT=20= pg_relation_filenode('gtest20c_expr_idx')=20AS=20= gtest20c_expr_idx_filenode=20\gset=0A+ALTER=20TABLE=20gtest20c=20ALTER=20= COLUMN=20b=20SET=20EXPRESSION=20AS=20(a=20*=203);=20--=20ok,=20rebuilds=20= index=0A+SELECT=20pg_relation_filenode('gtest20c_expr_idx')=20<>=20= :gtest20c_expr_idx_filenode=20AS=20whole_row_index_rebuilt;=0A+=20= whole_row_index_rebuilt=20=0A+-------------------------=0A+=20t=0A+(1=20= row)=0A+=0A=20--=20not-null=20constraints=0A=20CREATE=20TABLE=20gtest21a=20= (a=20int=20PRIMARY=20KEY,=20b=20int=20GENERATED=20ALWAYS=20AS=20= (nullif(a,=200))=20STORED=20NOT=20NULL);=0A=20INSERT=20INTO=20gtest21a=20= (a)=20VALUES=20(1);=20=20--=20ok=0Adiff=20--git=20= a/src/test/regress/expected/generated_virtual.out=20= b/src/test/regress/expected/generated_virtual.out=0Aindex=20= 24d5dbf46ca..fb6b8976af2=20100644=0A---=20= a/src/test/regress/expected/generated_virtual.out=0A+++=20= b/src/test/regress/expected/generated_virtual.out=0A@@=20-694,6=20= +694,33=20@@=20INSERT=20INTO=20gtest20c=20VALUES=20(1);=20=20--=20ok=0A=20= INSERT=20INTO=20gtest20c=20VALUES=20(NULL);=20=20--=20fails=0A=20ERROR:=20= =20new=20row=20for=20relation=20"gtest20c"=20violates=20check=20= constraint=20"whole_row_check"=0A=20DETAIL:=20=20Failing=20row=20= contains=20(null,=20virtual).=0A+ALTER=20TABLE=20gtest20c=20ALTER=20= COLUMN=20b=20SET=20EXPRESSION=20AS=20(nullif(a,=201));=20--=20fails=0A= +ERROR:=20=20check=20constraint=20"whole_row_check"=20of=20relation=20= "gtest20c"=20is=20violated=20by=20some=20row=0A+CREATE=20INDEX=20= gtest20c_expr_idx=20ON=20gtest20c=20((gtest20c=20IS=20NOT=20NULL));=0A= +CREATE=20INDEX=20gtest20c_pred_idx=20ON=20gtest20c=20(a)=20WHERE=20= gtest20c=20=3D=20ROW(1,=202);=0A+CREATE=20INDEX=20gtest20c_a_idx=20ON=20= gtest20c=20(a);=0A+SELECT=20pg_relation_filenode('gtest20c_expr_idx')=20= AS=20gtest20c_expr_idx_filenode=20\gset=0A+SELECT=20= pg_relation_filenode('gtest20c_pred_idx')=20AS=20= gtest20c_pred_idx_filenode=20\gset=0A+SELECT=20= pg_relation_filenode('gtest20c_a_idx')=20AS=20gtest20c_a_idx_filenode=20= \gset=0A+ALTER=20TABLE=20gtest20c=20ALTER=20COLUMN=20b=20SET=20= EXPRESSION=20AS=20(a=20*=203);=20--=20ok,=20rebuilds=20index=0A+SELECT=20= pg_relation_filenode('gtest20c_expr_idx')=20<>=20= :gtest20c_expr_idx_filenode=20AS=20whole_row_index_rebuilt;=0A+=20= whole_row_index_rebuilt=20=0A+-------------------------=0A+=20t=0A+(1=20= row)=0A+=0A+SELECT=20pg_relation_filenode('gtest20c_pred_idx')=20<>=20= :gtest20c_pred_idx_filenode=20AS=20whole_row_predicate_index_rebuilt;=0A= +=20whole_row_predicate_index_rebuilt=20=0A= +-----------------------------------=0A+=20t=0A+(1=20row)=0A+=0A+SELECT=20= pg_relation_filenode('gtest20c_a_idx')=20=3D=20:gtest20c_a_idx_filenode=20= AS=20ordinary_index_not_rebuilt;=0A+=20ordinary_index_not_rebuilt=20=0A= +----------------------------=0A+=20t=0A+(1=20row)=0A+=0A=20--=20= not-null=20constraints=0A=20CREATE=20TABLE=20gtest21a=20(a=20int=20= PRIMARY=20KEY,=20b=20int=20GENERATED=20ALWAYS=20AS=20(nullif(a,=200))=20= VIRTUAL=20NOT=20NULL);=0A=20INSERT=20INTO=20gtest21a=20(a)=20VALUES=20= (1);=20=20--=20ok=0Adiff=20--git=20= a/src/test/regress/sql/generated_stored.sql=20= b/src/test/regress/sql/generated_stored.sql=0Aindex=20= 6746cd4632b..24dc42545ad=20100644=0A---=20= a/src/test/regress/sql/generated_stored.sql=0A+++=20= b/src/test/regress/sql/generated_stored.sql=0A@@=20-341,6=20+341,11=20@@=20= CREATE=20TABLE=20gtest20c=20(a=20int,=20b=20int=20GENERATED=20ALWAYS=20= AS=20(a=20*=202)=20STORED);=0A=20ALTER=20TABLE=20gtest20c=20ADD=20= CONSTRAINT=20whole_row_check=20CHECK=20(gtest20c=20IS=20NOT=20NULL);=0A=20= INSERT=20INTO=20gtest20c=20VALUES=20(1);=20=20--=20ok=0A=20INSERT=20INTO=20= gtest20c=20VALUES=20(NULL);=20=20--=20fails=0A+ALTER=20TABLE=20gtest20c=20= ALTER=20COLUMN=20b=20SET=20EXPRESSION=20AS=20(nullif(a,=201));=20--=20= fails=0A+CREATE=20INDEX=20gtest20c_expr_idx=20ON=20gtest20c=20((gtest20c=20= IS=20NOT=20NULL));=0A+SELECT=20pg_relation_filenode('gtest20c_expr_idx')=20= AS=20gtest20c_expr_idx_filenode=20\gset=0A+ALTER=20TABLE=20gtest20c=20= ALTER=20COLUMN=20b=20SET=20EXPRESSION=20AS=20(a=20*=203);=20--=20ok,=20= rebuilds=20index=0A+SELECT=20pg_relation_filenode('gtest20c_expr_idx')=20= <>=20:gtest20c_expr_idx_filenode=20AS=20whole_row_index_rebuilt;=0A=20=0A= =20--=20not-null=20constraints=0A=20CREATE=20TABLE=20gtest21a=20(a=20int=20= PRIMARY=20KEY,=20b=20int=20GENERATED=20ALWAYS=20AS=20(nullif(a,=200))=20= STORED=20NOT=20NULL);=0Adiff=20--git=20= a/src/test/regress/sql/generated_virtual.sql=20= b/src/test/regress/sql/generated_virtual.sql=0Aindex=20= 9c2bb6590b3..26a14a9294a=20100644=0A---=20= a/src/test/regress/sql/generated_virtual.sql=0A+++=20= b/src/test/regress/sql/generated_virtual.sql=0A@@=20-347,6=20+347,17=20= @@=20CREATE=20TABLE=20gtest20c=20(a=20int,=20b=20int=20GENERATED=20= ALWAYS=20AS=20(a=20*=202)=20VIRTUAL);=0A=20ALTER=20TABLE=20gtest20c=20= ADD=20CONSTRAINT=20whole_row_check=20CHECK=20(gtest20c=20IS=20NOT=20= NULL);=0A=20INSERT=20INTO=20gtest20c=20VALUES=20(1);=20=20--=20ok=0A=20= INSERT=20INTO=20gtest20c=20VALUES=20(NULL);=20=20--=20fails=0A+ALTER=20= TABLE=20gtest20c=20ALTER=20COLUMN=20b=20SET=20EXPRESSION=20AS=20= (nullif(a,=201));=20--=20fails=0A+CREATE=20INDEX=20gtest20c_expr_idx=20= ON=20gtest20c=20((gtest20c=20IS=20NOT=20NULL));=0A+CREATE=20INDEX=20= gtest20c_pred_idx=20ON=20gtest20c=20(a)=20WHERE=20gtest20c=20=3D=20= ROW(1,=202);=0A+CREATE=20INDEX=20gtest20c_a_idx=20ON=20gtest20c=20(a);=0A= +SELECT=20pg_relation_filenode('gtest20c_expr_idx')=20AS=20= gtest20c_expr_idx_filenode=20\gset=0A+SELECT=20= pg_relation_filenode('gtest20c_pred_idx')=20AS=20= gtest20c_pred_idx_filenode=20\gset=0A+SELECT=20= pg_relation_filenode('gtest20c_a_idx')=20AS=20gtest20c_a_idx_filenode=20= \gset=0A+ALTER=20TABLE=20gtest20c=20ALTER=20COLUMN=20b=20SET=20= EXPRESSION=20AS=20(a=20*=203);=20--=20ok,=20rebuilds=20index=0A+SELECT=20= pg_relation_filenode('gtest20c_expr_idx')=20<>=20= :gtest20c_expr_idx_filenode=20AS=20whole_row_index_rebuilt;=0A+SELECT=20= pg_relation_filenode('gtest20c_pred_idx')=20<>=20= :gtest20c_pred_idx_filenode=20AS=20whole_row_predicate_index_rebuilt;=0A= +SELECT=20pg_relation_filenode('gtest20c_a_idx')=20=3D=20= :gtest20c_a_idx_filenode=20AS=20ordinary_index_not_rebuilt;=0A=20=0A=20= --=20not-null=20constraints=0A=20CREATE=20TABLE=20gtest21a=20(a=20int=20= PRIMARY=20KEY,=20b=20int=20GENERATED=20ALWAYS=20AS=20(nullif(a,=200))=20= VIRTUAL=20NOT=20NULL);=0A--=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_63FFC136-2AAB-4146-9F3D-3500A614C1CE--