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 1wBrCD-001REV-1h for pgsql-hackers@arkaria.postgresql.org; Sun, 12 Apr 2026 09:33:38 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wBrC9-001obG-2A for pgsql-hackers@arkaria.postgresql.org; Sun, 12 Apr 2026 09:33:34 +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 1wBrC9-001ob7-0y for pgsql-hackers@lists.postgresql.org; Sun, 12 Apr 2026 09:33:34 +0000 Received: from mail-vk1-xa35.google.com ([2607:f8b0:4864:20::a35]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wBrC8-00000000e8N-13UW for pgsql-hackers@lists.postgresql.org; Sun, 12 Apr 2026 09:33:33 +0000 Received: by mail-vk1-xa35.google.com with SMTP id 71dfb90a1353d-56d9ed609d2so1056654e0c.1 for ; Sun, 12 Apr 2026 02:33:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1775986410; cv=none; d=google.com; s=arc-20240605; b=fRDiYBREZLxCt4G7FJ7LNAtDq8LWYROopdCql1vbNJ+nek9KGky/MVB+xOdRZOTovW Onxr2Rdnvv2kc9ry4Pt0Pcq+XCgmkLwIh3iHjlRj7GA0GzO3vz3rt9xMsUJ8TRd3ghCR QditQRqWPNJa6jcjfJVQMRmHdjJkeGhFHq1j3y70bE7py3sw2wswiewWOw7IPH8UzGZn PWFq6xyJqDfRd+k5okLsqQFW22pCvvLHwJ37zU9Y4U3++xxBGDjC+HiPPNiwBPeb95FU sKzvzlAam/nY7xLcR33zWUqZGvdfU35jpsVgActG8f/twElGOJrGvD63Pi2R5U9vDJWH nUCg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=ebHp2AcwiPyoeSb0de/FXuVyFYjLzZnvL9HsKSQGSMI=; fh=NOo30AAV3JZ2gV+RE/nn4WjuTPJNrVMgF4c+LPp6+pw=; b=Oc4kL52pRxfcRSYfN9HTIQPZNrNESYKvFIWZWOk7FFAhg3MSd303PmODGhJLq+eml4 EkJj3wXkZSoAaCdR8KlpYpQE+d0dXFWUK1I01yc84QVq/qQX7UPPI17j93P5+GMvOV3U 1BkXWH7dVyyRys5Yy5zraz57YblNlpYzDNyCK2JE/JXqHSU55Pn6YIUTrokx7VJiyw8/ b26XM9m8nZTHCWQE+E2V4eXyrC5XPia4fJSoiBCiorGDrwQ43OGLjTthxFVnigIhjnS1 RF88/CBk6/zoXu9BAO0ZN4PrxmncLfVd5G8flyfrL7xUNP0iHTCKRb9SJ0zBSHgmkCOH V3jg==; 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=1775986410; x=1776591210; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=ebHp2AcwiPyoeSb0de/FXuVyFYjLzZnvL9HsKSQGSMI=; b=HTH6dQ9pxUKrX/mbCqOgYm3I/JvEODzZ8vgrAE83A3Hj78DkpjFbPqYllta1wpPoLK 80mg9+DP2J1ILmyxmsQcXbiw5xO7MpdPt5VH6GrMQ7j0giJC9SvvyTfwq+TUICtSsUL/ SuWMgVyVbZugveLbHuRuVcF59ILW1S/mTWLlQ6AfQb7QUSmMuwdSgV41/JRE93kNOzKv LfyfQ5dt9x+1dVpUNTG+mIdgdnHtRiehu23bomwm+ETingHaAMtFsLM1oL/3kDulQJCY NUd9CtBxxpaKGbDyKssZGHnc+v6t9VxqSajm6YjQyfY8poaZ+pu0fLKBerLwWDVmS5D/ JG1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775986410; x=1776591210; h=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=ebHp2AcwiPyoeSb0de/FXuVyFYjLzZnvL9HsKSQGSMI=; b=E3dSGYsmljcGGHginA81HiOHsUBfogq1R6mW5gOqWDtvyKKWMRhLlV2oLEtYE0xoFA FWaXHnMe29qp9OFor4if+yp1fxCeZcKSIqJ/rP/zifpSxlRzk82cNZAI/R3nNl2XunGd h/a4BIW7PsTi4XS1bG+2fLyk189xBeQ2461aCMr1hrHSxoN8G3mfZY+aTbLE7TncpWnl DWFOiWnFA8wtQIHPS7fRpoi50reLi+5xxaHwHxkEt8SoDaAVOo6tC1/jzkxZR6t/E6e5 smDWE5/5M9l8YGEqiRdBhQYz/DR+vd5uINBfU6tFZpgAi+VBiKPyj0m5Mbzvf32aFmf5 Z2AA== X-Gm-Message-State: AOJu0YzvXPusn5y3BiUpdu38XfsJfYmec05asyIrIGH61L+zkr7zVKng qUW3jjKn7zTXIVXYy6SEtCbchEQqlMEC9VFO8rtBdHAcrAFcRcq3C+Tdg1QI0YOZ+rCW6u33SIj N0pOIvrOwZK9SrIr07sNFA7xeCHvx2Gg= X-Gm-Gg: AeBDietC/NUSAoo2iJAj7PmuZWnIyKMuHULF2CzcZaH9XfdqCNZgeOQi+Yd1ZFctrYn u3JVtamxO3JblwKy8oLTLAuSlyN3jcwWHxAbJTmF2Jh38oyhM3VI4hniHm0LwavoXWuVRXFtE5i gSi6IFF+1ajrpyMhc0qqMthNgWjcvRA15MhgdgMonJYRvhdKZoGFtupQrBd7FVBzI7PtRpA3fkX y+6TLBM45G/uZPJgA7/k1iA2hevH6x8lY5h3Cznc8zOQq9+4kOg9PuHkK25GImjn5jJdB6Qbbhq u/WAmZE= X-Received: by 2002:a05:6122:1688:b0:56c:d34e:bb1a with SMTP id 71dfb90a1353d-56f3bbf8835mr4015244e0c.4.1775986410313; Sun, 12 Apr 2026 02:33:30 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: SATYANARAYANA NARLAPURAM Date: Sun, 12 Apr 2026 02:33:19 -0700 X-Gm-Features: AQROBzBP78MTEgU6XYrIeXR4NSkf2IDAuKNutX5-SK7W77DZ4mvDdJc5J0BGLHA Message-ID: Subject: Re: var_is_nonnullable() fails to handle invalid NOT NULL constraints To: Richard Guo Cc: Pg Hackers Content-Type: multipart/alternative; boundary="0000000000001cdc7d064f400f01" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000001cdc7d064f400f01 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi RIchard, On Fri, Apr 10, 2026 at 1:48=E2=80=AFAM Richard Guo wrote: > While fixing another bug in var_is_nonnullable(), I noticed $subject. > The NOTNULL_SOURCE_SYSCACHE code path (newly added for the NOT IN to > anti-join transformation) checks pg_attribute.attnotnull, which can be > true even for invalid (NOT VALID) NOT NULL constraints. > > The consequence is that query_outputs_are_not_nullable() could wrongly > conclude that a subquery's output is non-nullable, causing NOT IN to > be incorrectly converted to an anti-join. > > The attached fix checks the attnullability field in the relation's > tuple descriptor instead, which correctly distinguishes valid from > invalid constraints. This is also consistent with what we do in > get_relation_notnullatts(). > I tested this patch against the current HEAD (155c03ee) and it looks good. Build & tests: Applies cleanly, compiles without warnings, all 247 regression tests pass including the new subselect test case. Reproduced the bug before the patch and verified it is fixed after the patch. > It could be argued that the added table_open/table_close call is a > performance concern, but I don't think so: > > 1. The relation is already locked by the rewriter, so > table_open(rte->relid, NoLock) is just a relcache lookup. > > 2. This code path is only reached when converting NOT IN to an > anti-join, and only after the outer side of the test expression has > already been proved non-nullable. > > 3. It is only called for relation RTEs in the subquery. > > Thoughts? > Looks like it needs to perform table_open/table_close multiple times depending upon the number of output columns? I don't see it as a major concern but let others comment. Thanks, Satya --0000000000001cdc7d064f400f01 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi RIchard,

On Fri, = Apr 10, 2026 at 1:48=E2=80=AFAM Richard Guo <guofenglinux@gmail.com> wrote:
While fixing another bug in var_is_non= nullable(), I noticed $subject.
The NOTNULL_SOURCE_SYSCACHE code path (newly added for the NOT IN to
anti-join transformation) checks pg_attribute.attnotnull, which can be
true even for invalid (NOT VALID) NOT NULL constraints.

The consequence is that query_outputs_are_not_nullable() could wrongly
conclude that a subquery's output is non-nullable, causing NOT IN to be incorrectly converted to an anti-join.

The attached fix checks the attnullability field in the relation's
tuple descriptor instead, which correctly distinguishes valid from
invalid constraints.=C2=A0 This is also consistent with what we do in
get_relation_notnullatts().

I tested th= is patch against the current HEAD (155c03ee) and it looks good.
B= uild & tests: Applies cleanly, compiles without warnings, all 247 regre= ssion tests=C2=A0
pass including the new subselect test case. Rep= roduced the bug before the patch
and verified it is fixed after t= he patch.


It could be argued that the added table_open/table_close call is a
performance concern, but I don't think so:

1. The relation is already locked by the rewriter, so
table_open(rte->relid, NoLock) is just a relcache lookup.

2. This code path is only reached when converting NOT IN to an
anti-join, and only after the outer side of the test expression has
already been proved non-nullable.

3. It is only called for relation RTEs in the subquery.

Thoughts?

Looks like it needs to perfor= m table_open/table_close multiple times depending upon
the number= of output columns? I don't see it as a major concern but let others co= mment.

Thanks,
Satya
--0000000000001cdc7d064f400f01--