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 1w2RiR-000IVd-1d for pgsql-hackers@arkaria.postgresql.org; Tue, 17 Mar 2026 10:31:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w2RiQ-000EOg-1Q for pgsql-hackers@arkaria.postgresql.org; Tue, 17 Mar 2026 10:31:58 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w2RiP-000EOY-2Y for pgsql-hackers@lists.postgresql.org; Tue, 17 Mar 2026 10:31:58 +0000 Received: from mail-wm1-x32b.google.com ([2a00:1450:4864:20::32b]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w2RiK-00000000AUo-37EM for pgsql-hackers@postgresql.org; Tue, 17 Mar 2026 10:31:56 +0000 Received: by mail-wm1-x32b.google.com with SMTP id 5b1f17b1804b1-4838c15e3cbso50685465e9.3 for ; Tue, 17 Mar 2026 03:31:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773743513; x=1774348313; darn=postgresql.org; h=content-transfer-encoding:content-disposition:mime-version :message-id:subject:to:from:date:from:to:cc:subject:date:message-id :reply-to; bh=5mSD4hQ1ozA0kWtkpLOwhqVTp4sbNI86ynHTM7ipDmQ=; b=I+CmAdfSD9JzbblupvuzXveqQQljA7WTVWKeFJ0BEjDOq9/L4akQHpHwlprStCYSXi sh5BsXfIIx3fTX3sB3Hm4qDWrK4vg6AqOJfwu8xwdJ58ax3zTcFkDFyACx/Zk/GsE4GM +wv7Dhqqvo7BvXbe4Iy+naQaSxU+eyfnhKVIPxiWikeQNMx5eK8sMot6ilTPDhjSqha/ /do/tg9l2pqbCtCFBLnwB9Ch/X5jNI3v2xK+OU/ylK/5Z18cExWqfE23gEeqRPbXRSnW pv5wBOgN6u5hdo7AHZ0rYoNskbRaRbTP21ENqyoMtP0mU3xOR4EIo9REoiZ9hug7sR5/ /rKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773743513; x=1774348313; h=content-transfer-encoding:content-disposition:mime-version :message-id:subject:to:from:date:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=5mSD4hQ1ozA0kWtkpLOwhqVTp4sbNI86ynHTM7ipDmQ=; b=qN9VAZ0LaTtnJg+bENrzYk17gaBBlUrz6ptCdzDoG2ExJEj2qWkntC/2KzWEnB80+e w9GfkEk40EuXW3Z/v4OC/d9dmUrAtkyNDWLZETIKeGwaK2aiBh1ZlrO6TsPP2yuT8NAa iiKsnEVekvrOXHMHaMCIR2anmQDdGTPrXx/3NYbOC7N4J1mg66IDZI0yJCUnH8eTpg2O mFt7Av5nRgLv3Ruy9TX7kFtSPBTv5PXIAYBT997Aq5NgxFCyVQlpwdNXa17OqYJW/Yzp 4knz3mqtGfKnjqyMPlv+bFut1kk6EjJr4vXKJs9JJNoRCF4KfjnhPJiobMCJvtELaFLI UnHw== X-Gm-Message-State: AOJu0YxKqtCNtxa4jsi+v/l/hhei5RLKuza4t+M042O89JXgM9JvLFFL Rhd9XvpmjVXcU9GT6HmoSuxhPQftuQMXlQo1m7x5LrqClbAt3hYCciatA8BRdQ== X-Gm-Gg: ATEYQzxvGzVSXAAhgujQObDi41J2NkESY0+R75TKSvsdCR1PujxtrpXt/WsoEfmb4IF 0PKU67N1Tn24P3i7awtHZldhWsGkNiwu/h7Zwf1/qOzrgTT1pFjwQVyPkpdwFGx8BuFGl9dYPTj PmusRh0ADHOzI1hWekARsTakRXLnMNu2hcVf2s99OtU1SAlk7kdfH/85i+PUVpkRIIBiu+HnVnc SHc5GGBgId9dUqaMMTDnbPmOk8QbDWVDyV0aWSRy8vXl1HJovcHgP8XjhLsSLuilg1+IDTYXE9S +es53IHqpo3FESU17hTZGt0BJhyE1qofaq7IzWa7OmF2lkd47hdtlTHKBsRFXuc13aj2zXUO9xl bymNS2EkufKcrsoPrAoVZT3vqqV13f4B7B6rXQGyDFRD7FK84hDlT1aF6f4tdv2Cdo87RW0Ycor JAtSmthYLE5x+c6by7PIk2Yw8JHKpsLrTbvOgm9jQFAtZPoJhyJlDdh3n75qtDydRKqplmob5/Y 8ffcmESJhMO X-Received: by 2002:a05:600c:4f54:b0:485:3af5:7e53 with SMTP id 5b1f17b1804b1-485566fd026mr274624535e9.19.1773743512523; Tue, 17 Mar 2026 03:31:52 -0700 (PDT) Received: from localhost (85-195-242-240.fiber7.init7.net. [85.195.242.240]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4856eae3037sm58716675e9.11.2026.03.17.03.31.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Mar 2026 03:31:52 -0700 (PDT) Date: Tue, 17 Mar 2026 11:31:47 +0100 From: Alberto Piai To: pgsql-hackers@postgresql.org Subject: Adding a stored generated column without long-lived locks Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="24dzbv6kpqxe4yje" Content-Disposition: inline Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --24dzbv6kpqxe4yje Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit Hi, I recently needed to add a stored generated column to a table of nontrivial size, and realized that currently there is no way to do that without rewriting the table under an AccessExclusiveLock. One way I think this could be achieved: - allow turning an existing column into a stored generated column, by default doing a table rewrite using the new stored column expression - when doing the above, try to detect the presence of a check constraint which proves that the contents of the column already match its defined expression, and in that case skip the rewrite This would open up a path to add such a column (GENERATED ALWAYS AS (expr) STORED) without long-lived locks: - add column c, nullable - add trigger to set c = expr for new/updated rows - add constraint check (c = expr) NOT VALID - backfill the table at the appropriate pace - VALIDATE the constraint - alter the column c to be GENERATED ALWAYS AS (expr) STORED, which would skip the rewrite because of the valid check constraint on c - clean up the trigger and the constraint To this effect, I started prototyping an alter table command ALTER TABLE t ALTER COLUMN c ADD GENERATED ALWAYS AS (expr) STORED The syntax seemed like a good fit because it's similar to the command to change a column to be GENERATED AS IDENTITY, but I didn't spend a whole lot of thought on the exact syntax yet. The attached patches are a first prototype for discussion: - patch v1-0001: add the command - patch v1-0002: detect the check constraint and skip the rewrite The check constraint must be of the form (c = ) where `=` is a mergejoinable operator for the type c. The in the constraint and in the column definition are matched structurally, so they must match exactly. Before spending more time on this, I wanted to bring this up for discussion and to gauge interest in the idea. Looking forward to your feedback! Alberto -- Alberto Piai Sensational AG Zürich, Switzerland --24dzbv6kpqxe4yje Content-Type: text/x-patch; charset=utf-8 Content-Disposition: attachment; filename="v1-0001-Support-changing-a-column-into-a-stored-generated.patch"