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 1wCURP-0022Ep-1S for pgsql-hackers@arkaria.postgresql.org; Tue, 14 Apr 2026 03:27:55 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wCURN-009bjC-2b for pgsql-hackers@arkaria.postgresql.org; Tue, 14 Apr 2026 03:27:54 +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 1wCURN-009bj4-1k for pgsql-hackers@lists.postgresql.org; Tue, 14 Apr 2026 03:27:54 +0000 Received: from mail-oo1-xc34.google.com ([2607:f8b0:4864:20::c34]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wCURM-00000000xNA-1uQf for pgsql-hackers@lists.postgresql.org; Tue, 14 Apr 2026 03:27:54 +0000 Received: by mail-oo1-xc34.google.com with SMTP id 006d021491bc7-68be75dc734so1289490eaf.1 for ; Mon, 13 Apr 2026 20:27:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1776137271; cv=none; d=google.com; s=arc-20240605; b=JCnMjAbbTEUeEkzwA6Mb+3nqP7gzIUtt2DUlQJlVH1g90TMUZFJNs6xgEB2j55KO6D c7wkQ91DoNalOdEI7yp+3HtKXW2d9M1z5iWd1wbFiuyNQqUXGo0BNidJiwT19o+OCunF U29fvcnye7LlMTPSYvMTl5vvOkBSX6xPJo7UI/AfzCqJpOQivvZqfw794K7UstHLUNSJ V1V0hgv7bK3LDtndUhunIjfhjyRo/npHOgJaX3J1RaIRms4kTULDKi19PRVkdGsVY7KJ wK1tB7ATHtRvwtfA11KnQFU4MLRB29evul3CLBKfn8XEG2ri2ehFxagqYBF3KBa5rTbE lYqw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=inmCofMC9JPVMOQhf2cIIj8OBKWqexraoD8CrWz/9bE=; fh=9Q7bvlMYgz0JH++8Jj8P5yorsJrxTg7WUlaYuvciNgU=; b=TFvUrBLvchPTm4RQrBcEpOHonlDrqjEpmJUUGATcGLpiu5Na/y+QCj6Kv+WY7Ax9y1 9UaU72nNBUdiN2ci4aU8MIBV1fDZ36yLfzkjOliC6OVAqDBuoAzrEZkv/hScKjPakHDQ FqP/DJbjO1bmeXcsF13a8aFiTl56GmzDNLOtxaIecTVM7cGxwh5EvLnihj/oYw/X5FRJ 4cKCTA/gxluNxGzRTfM5Eper+fgdatwF1rG6jTvOFtmd0VetKs88oWr+uf+6msBJwxMc N3ND0Nu8RyO8wfTbG+R4qHfZWzPITGeYV7wTDzSCab9innmyAiMSp2rNXIRyd6UEV5+V gaoQ==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776137271; x=1776742071; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=inmCofMC9JPVMOQhf2cIIj8OBKWqexraoD8CrWz/9bE=; b=Svqfb937gSrHzP2JYnkeE4jQoDnDWLI2pjyI0JLjy77YXdUW7wAxGZHVDOciQyH1Vq podtH6FL8SnPfpxP/dZGU52dikRnD3vi7Gns7mmPEuHXUIyDqD461noy5eHgfsRs5v6A 2ohLWwaZMfqcMixk5T4WVpfkGoFSl5aBXEd18UPVrTTHbyZBNDtYjDp9PV6ARfCln2rO NMI8Mnhmj/H2cCrV0s3aVclobj6GjJvp2yV+rrtY51LKwznNFud44DH09U5bDJZ5y/6I o4XonoiybkO83l//5IGgJA8WBaqkvl5UByzyKbrXoSp/nC/oPSzbBfjdM2kCG1/6od8j ZYsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776137271; x=1776742071; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=inmCofMC9JPVMOQhf2cIIj8OBKWqexraoD8CrWz/9bE=; b=dcXNJs3ki4na0EU/c7dlB7w8vlJ6RTRzRmr2DIwilUrYsJrwXEd7ZNjrfn2GBIYqSI 7zmNn3q/kNz2DqPzy0xi4kQgFdUyoCPIbpifluaKTocCIRg9/GLzFywdA2yvPdY2Glsv yDHuxTfdxrWJCZiyenFjP00zhXjzU1qMdm4Fu27nXJ6Na3yQlZ54MVkUF9zTs4/5InBF NauU2VF3/vUW9RttegnFI0d94Iym4Zeh+pZvfde6uGvGsZ5ofkccayhkDruvmiY3+pco MfbaRkcuSpM06dn3doJx4F+tbz/vzMniw6DAEVgE8/mKZcqgs069avcAWg7jiSgggjSA Okjg== X-Forwarded-Encrypted: i=1; AFNElJ+ofLhZLUeQzDesvvNhXYmXKGiBJNyv2mkScGI2HsNxYsA5rqhu2X5US8eruFtHQeCCaCrHeXqVgO8jINXY@lists.postgresql.org X-Gm-Message-State: AOJu0YxbSnPW3AkP4gL9WMQROTgMviyaa2ArB/jugqXiXP+7tVk9kaqm pkZs4qZ23RGxb/KmEHx2Y7sL4/cW09vqf3xWavuPn0GtmPuq//Fv0EWq1RJsYmCrDfQzByUhHYZ v1ZyNlUAXCZK7RBP5qLFuKBfHs3hHKnA= X-Gm-Gg: AeBDieuIpYSxaqzi+FREvqWmXLyj/CP434P+wyUf4dEj66ri9C40TVywssejMqVv/tl F/wuNGDgjhqMDM6Wf5YSUA2eX8STIHTKXdIjPRyNaKrhGy+pVGGcgxu6eTsALHtvBEtEDJL7Ze0 96VHOcyQ+IM7UN9KvLzVTuQFbLuQsnTz+E1wrRnvL9WToH4S1Q3WfcyLNxsd/Y5bhTwF5qddNTx fsGxIgcbLfKY7PIsuHN6JkNMf/ZfYYKxM7JJCjrD0GZJeGaHpQ0PRU/SG+LyafOVuOs4utiZWbC p/ldHShvTg== X-Received: by 2002:a05:6820:4b8f:b0:679:97ac:2cc0 with SMTP id 006d021491bc7-68be6430b08mr7810900eaf.24.1776137270669; Mon, 13 Apr 2026 20:27:50 -0700 (PDT) MIME-Version: 1.0 References: <22B4A33A-99F3-46F5-BE0C-426A9E1D9ABA@gmail.com> In-Reply-To: From: Richard Guo Date: Tue, 14 Apr 2026 12:27:39 +0900 X-Gm-Features: AQROBzDY71-uTtq7P9uCkMyRNXe9FRl2CaCWPS6YTHeSnGV-yzhrJpSwT2NetsA Message-ID: Subject: Re: Bug: Rule actions see wrong values for generated columns (NEW.gen reads OLD value) To: Dean Rasheed Cc: Chao Li , SATYANARAYANA NARLAPURAM , PostgreSQL Hackers , Peter Eisentraut Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk 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. > One thing about that approach is that it leads to 2 full rewrites of the = rule action using ReplaceVarsFromTargetList(). I think that could be avoide= d 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_intern= al(). 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. Take Satya's repro as an example. If we add the generation expression for gen to the UPDATE's targetlist, the list would be: TargetEntry 1: resno=3D2, expr=3DConst(100) -- a =3D 100 TargetEntry 2: resno=3D3, expr=3DVar(3, 2) * 2 -- gen =3D NEW.a * 2 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. 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. - Richard