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 1wCXI6-0024ws-2d for pgsql-hackers@arkaria.postgresql.org; Tue, 14 Apr 2026 06:30:31 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wCXI5-00AITQ-0b for pgsql-hackers@arkaria.postgresql.org; Tue, 14 Apr 2026 06:30:30 +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 1wCXGm-00AEU4-0I for pgsql-hackers@lists.postgresql.org; Tue, 14 Apr 2026 06:29:08 +0000 Received: from mail-pf1-x42a.google.com ([2607:f8b0:4864:20::42a]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wCXGk-00000000yei-2gSO for pgsql-hackers@lists.postgresql.org; Tue, 14 Apr 2026 06:29:08 +0000 Received: by mail-pf1-x42a.google.com with SMTP id d2e1a72fcca58-82f07e5ad92so2586804b3a.0 for ; Mon, 13 Apr 2026 23:29:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776148145; x=1776752945; darn=lists.postgresql.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=E1KnPt5RxKeo39MHnmiJLfa6sYzhRF0IfUdBZRi+Ml0=; b=GPZ7zdpXWsiv80TzVylkhRxuj1OGUzptB8dE23am0xtQoyt2pkRfmUX6aAxa1Ljwy/ kMjSesj4Os8PMkGhJ14XYz+m1/5Mp6/SgMv1ccRzloryyZsQcxB/vVu3alJ+RY1pAtao g3oRqloLaMJ0IJ2sRgek0JtimoCjUZS+ahHO/0cZeyKQIjrsP7cHWDtyiIn9qfxvGFfK wBCQHc/3uvbWgfGI+Xios5T9+HRzja1noWOV8RPkiBhRbzgpLlMTp4/QCtNhIBivkj0f RVQyjZyQLDr92nYP1h7mbxl4vIKwLcbCTASnDgqrHPyYP8uw6RrGM2uxYbjpzAs+I9/7 Z2BQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776148145; x=1776752945; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-gg:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=E1KnPt5RxKeo39MHnmiJLfa6sYzhRF0IfUdBZRi+Ml0=; b=M2flTNWRDb4tP3EJq3n34909F01x9Bjc7wYcyecmhd/rT9gKYVpUo6+26GayiCm4JA ObrmmkES9BgUwzrQs2Np7qYdBvG942RaKoLO+xOQS9B+KjYBH+NFCRmVUmjS5QMz59sS Q+Ma7RF0BGYtIsOzWFkQ9D+9AfWsWIdjZjoNTBGXAtmH1VuCLAyNjqPvtieAMIzGJLpQ Rgq7H3Z36+fAdnY3Ovg3bAqDpgKRtzLw0YmkMtvDCrcNConZfB8WL8TjyZfCuTLpytKz sB5xdj7duh4NkUzC0MvjkWy7f7e1FWlb1JRN6Gyp6SJXj95eqeqVG3fXwluHA5zOxnS0 L14Q== X-Forwarded-Encrypted: i=1; AFNElJ9p+qYIqJZEc+RKRpxY83Y7It45sWcHkPdihwXRs7ESWz4zVIJLFzS2/yrBgLnuo40fWAyuhiHBHkOgWfoJ@lists.postgresql.org X-Gm-Message-State: AOJu0Yzlvx9EmLpLlgydCEOnE26s16Ej1mlAXi9mvf0eMkOruaoqzkJh lwDpfI3Rr+xPzDxHZLuxLaF2ZHK1u2t1g31DNlldfaA19E/u/uaUuORG X-Gm-Gg: AeBDieu76aFt5GegQciihOtpUUA+ard5+rC8IZ8+uK4fuazu7+wC8wh/8ofi7XmvUvR SnmoVVazvgnTXosFlU2q0Zje9fbIOEYVdgLMi2wu0+3OqNQTMZfhDrqAMZPev/ePcyqyL29t40f efLQjmHiGswtBiusyeZgsGrImgSJY6NOjg53sblVVHoQvhkNlNXkgL/3ql4bBe3PRHRfOmkUR6U fjhwXR/Tavo5UfqOrWIgtFbX9Yc2gANMqCbMJwpS6aMyaoTVTusLwiuCZNmAA4bLVyYBKtJR1n1 V3gPCBhhnksbIXGEAL1aADhUcMKi2I+EiZBcQvVi1vbD1AedDkd/0aa1wMyVkc4FL9b3Nn3RtoX m84Z71R7ixxsqEoSPLANukzex/F+92QHwVeCEBKByt7aiP4e6TNKiavRLms+9jLgsySgILldkE2 tYRPeOwqbQN9I/4MIOnK4T/B1ZLrkXiT8= X-Received: by 2002:a05:6a00:400e:b0:82c:9f7f:3495 with SMTP id d2e1a72fcca58-82f0c351b36mr16097854b3a.45.1776148144593; Mon, 13 Apr 2026 23:29:04 -0700 (PDT) Received: from smtpclient.apple ([45.32.121.103]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82f0c339570sm13125435b3a.16.2026.04.13.23.29.01 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 13 Apr 2026 23:29:03 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.400.21\)) Subject: Re: Bug: Rule actions see wrong values for generated columns (NEW.gen reads OLD value) From: Chao Li In-Reply-To: Date: Tue, 14 Apr 2026 14:28:24 +0800 Cc: Dean Rasheed , SATYANARAYANA NARLAPURAM , PostgreSQL Hackers , Peter Eisentraut Content-Transfer-Encoding: quoted-printable Message-Id: <8D1CD3EB-BF72-4C73-AF24-D88581AC01BE@gmail.com> References: <22B4A33A-99F3-46F5-BE0C-426A9E1D9ABA@gmail.com> To: Richard Guo X-Mailer: Apple Mail (2.3864.400.21) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk > On Apr 14, 2026, at 11:27, Richard Guo wrote: >=20 > On Mon, Apr 13, 2026 at 8:04=E2=80=AFPM Dean Rasheed = wrote: >> On Mon, 13 Apr 2026, 09:20 Richard Guo, = wrote: >>> I think a simpler fix might be to expand generated column references >>> in the NEW relation to their generation expressions before >>> ReplaceVarsFromTargetList resolves NEW references, so that the base >>> column Vars within the expressions can be correctly resolved. >>> Something like attached. >=20 >> One thing about that approach is that it leads to 2 full rewrites of = the rule action using ReplaceVarsFromTargetList(). I think that could be = avoided by using including generated column expressions in the = targetlist passed to ReplaceVarsFromTargetList() by rewriteRuleAction(). = I haven't tried it, but I imagine it could reuse some code from = expand_generated_columns_internal(). >=20 > I considered it, but I'm afraid it doesn't work directly, because > replace_rte_variables_mutator returns the callback's replacement node > without recursing into its children. >=20 > Take Satya's repro as an example. If we add the generation expression > for gen to the UPDATE's targetlist, the list would be: >=20 > TargetEntry 1: resno=3D2, expr=3DConst(100) -- a =3D 100 > TargetEntry 2: resno=3D3, expr=3DVar(3, 2) * 2 -- gen =3D NEW.a = * 2 >=20 > When ReplaceVarsFromTargetList processes Var(3, 3) (NEW.gen) in the > rule action, it finds resno=3D3 and substitutes Var(3, 2) * 2. = However, > replace_rte_variables_mutator returns this replacement directly to its > caller; it does not recurse into the replacement's children to look > for further matching Vars. So the inner Var(3, 2) (NEW.a) is never > processed, even though resno=3D2 with Const(100) is right there in the > targetlist. The Var(3, 2) survives into the planner and would cause > problems. >=20 > It could be made to work by pre-resolving the generation expressions' > base column Vars before adding them to the UPDATE's targetlist. For > each generated column, we'd call ReplaceVarsFromTargetList on the > generation expression to resolve its base column Vars, then add the > fully resolved expression to the targetlist. But this seems to add > code complexity. And I'm not sure about the performance difference > between these two approaches. I expect that rule action trees are > typically small. >=20 > - Richard My implementation has pre-resolved the generation expressions, that=E2=80=99= s why all tests passed. But I agree my change is heavier as I had to add = a new static helper function. If we think rule actions are usually small enough that the extra = full-tree pass would not be an issue, then v1 may be preferable for = simplicity. My only comment on v1 is the typo in generated_virtual.sql where = =E2=80=9CSTORED=E2=80=9D should be =E2=80=9CVIRTUAL=E2=80=9D. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/