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 1x275g-005arA-0a for pgsql-bugs@arkaria.postgresql.org; Thu, 03 Sep 2026 13:02:52 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1x275f-000ZDj-0l for pgsql-bugs@arkaria.postgresql.org; Thu, 03 Sep 2026 13:02:51 +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 1x219D-00GJKT-21 for pgsql-bugs@lists.postgresql.org; Thu, 03 Sep 2026 06:42:07 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x219B-00000003lK7-3lK0 for pgsql-bugs@lists.postgresql.org; Thu, 03 Sep 2026 06:42:06 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=cyYGyQuEOk0GmRvBOpkR6ypVR7bmh9qNTQd0g2suxrM=; b=Tch9Kp6yRkSe+NXI5ZAI+guyQp s9SAU+kzf2f4bZ+gVESzjuYOQwadOgwReBVbcuKI0lfSlIU0owqDVCoPbXzaJsSCMZWeCAX8DeooR YrvHjlnWpM1eYi5PcqqWxX16NkZ1huZT4rGSZlpFzz52HerbIqKDGaMnERG8KkPW8wunhI9cYRo7B +BaGjGiTnkeanfe4pQNQepBFvZRp8hV+Hz+S3Pt89Ao9h2Gb5e+XBrh4iN9WfyJMpgRXBnQTg3y9H ZanX11RlPrMKurgYg9QdeiMgsBGbCJsccNljtBPHM8zlvI2aKS07i+O/8Sd4nAc6OeFuejcmJhzVt wVJiQyxg==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1x219A-00BOXN-1G for pgsql-bugs@lists.postgresql.org; Thu, 03 Sep 2026 06:42:05 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1x2199-0000000D7c1-0A5Y for pgsql-bugs@lists.postgresql.org; Thu, 03 Sep 2026 06:42:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19649: Qual pushdown into GROUP BY subqueries ignores non-equivalence-preserving references to grouping col To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: 303677365@qq.com Reply-To: 303677365@qq.com, pgsql-bugs@lists.postgresql.org Date: Thu, 03 Sep 2026 06:41:49 +0000 Message-ID: <19649-2cabf1440793cc71@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19649 Logged by: chunling qin Email address: 303677365@qq.com PostgreSQL version: 18.6 Operating system: 86_64 Description: =20 When an outer WHERE/HAVING clause references a grouping column of a GROUP BY (or DISTINCT) subquery through a type coercion (::text, CoerceViaIO) or a function/operator wrapper (j->>0), the qual is pushed down below the grouping node even though the reference applies a different equivalence relation than the grouping does. Values that the grouping considers equal = =E2=80=94 but whose text representations differ =E2=80=94 get separated by the pushed= -down qual, splitting one group into two halves. This produces silently wrong results: count(*) values change, a group can emit different group keys depending on the WHERE, and rows are lost. The simplest proof that something is wrong: the same subquery group answers with two different group keys under two different outer WHERE clauses =E2= =80=94 impossible under SQL semantics, since WHERE may only select subquery output rows, never alter them. CREATE TABLE t(id int primary key, j jsonb); INSERT INTO t VALUES (1,'1'),(2,'1.0'); -- jsonb 1 =3D 1.0, so the table has exactly ONE jsonb group with count =3D= 2 SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s; -- 1 | 2 (baseline: one group) SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s WHERE j::text = =3D '1'; -- 1 | 1 (WRONG: count changed by WHERE) SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s WHERE j::text = =3D '1.0'; -- 1.0 | 1 (WRONG: the same group, different key) SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s WHERE j =3D '1'::jsonb; -- 1 | 2 (control: same-eqop comparison is correct) ``` hunt@(null)=3D# CREATE TABLE t(id int primary key, j jsonb); INSERT INTO t VALUES (1,'1'),(2,'1.0'); -- jsonb 1 =3D 1.0, so the table has exactly ONE jsonb group with count =3D= 2 SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s; -- 1 | 2 (baseline: one group) SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s WHERE j::text = =3D '1'; -- 1 | 1 (WRONG: count changed by WHERE) SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s WHERE j::text = =3D '1.0'; -- 1.0 | 1 (WRONG: the same group, different key) SELECT j, c FROM (SELECT j, count(*) c FROM t GROUP BY j) s WHERE j =3D '1'::jsonb; -- 1 | 2 (control: same-eqop comparison is correct) CREATE TABLE INSERT 0 2 j | c ---+--- 1 | 2 (1 row) j | c ---+--- 1 | 1 (1 row) j | c -----+--- 1.0 | 1 (1 row) j | c ---+--- 1 | 2 (1 row) hunt@(null)=3D# select version(); version =20 ---------------------------------------------------------------------------= ------------------ ------------------------------------------ PostgreSQL 20devel on x86_64-pc-linux-gnu, compiled by gcc (Tencent Compiler 12.3.1.8) 12.3. 1 20230912 (TencentOS 12.3.1.8-6), 64-bit (1 row) ```