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 1vtLoW-000oUz-08 for pgsql-bugs@arkaria.postgresql.org; Fri, 20 Feb 2026 08:24:40 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vtLoV-0070hx-01 for pgsql-bugs@arkaria.postgresql.org; Fri, 20 Feb 2026 08:24:39 +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 1vt35g-003b38-00 for pgsql-bugs@lists.postgresql.org; Thu, 19 Feb 2026 12:25:08 +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 1vt35c-000000008DZ-1FVe for pgsql-bugs@lists.postgresql.org; Thu, 19 Feb 2026 12:25:07 +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=AaDyi2oPSJ9OJZqgioKUbyFJgCTQoLZQ100NMu9aw+Y=; b=uix1AvW7/G1vEEdF9oBHqvp9sb kt5l1JJ/SLzcaoVz1Zwl7FmWxvFpAb3WEtG+PzaDYOr+4E4nAK6DhxEmq+U53Egf8o8SGILuyGiU8 XVDyN+8W2Y4uQ/76uTekEd+LgSou0MqPzXBuniymSeZIEShGpAkU6FqZSiPQ2RNaAGkUrKwp/61iR 3rdhL5tmSNN0VI+a8IobKpuVYTiuB5P6wnhVdd76NK8dUsmGLCQZwNbH7kXv1/nCwxgy06QhQwGUc 2XIXRZmY4cyZOm0fQqjUIBqxuLaD5hftHfwG/mz0VSXiuu/CzKsGNJ+Mn1PgRHPOYgvZaZ8xcF/aK qNkrGwMg==; 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 1vt35c-000NT2-0G for pgsql-bugs@lists.postgresql.org; Thu, 19 Feb 2026 12:25:04 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vt35a-00696r-2u for pgsql-bugs@lists.postgresql.org; Thu, 19 Feb 2026 12:25:02 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19414: Wrong rows returned by index scan on HASH-partitioned table with PRIMARY KEY (PostgreSQL 16.9) To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: jose.morcillo.valenciano@gmail.com Reply-To: jose.morcillo.valenciano@gmail.com, pgsql-bugs@lists.postgresql.org Date: Thu, 19 Feb 2026 12:24:50 +0000 Message-ID: <19414-add8251d7863a802@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: 19414 Logged by: Jos=C3=A9 Antonio Morcillo Valenciano Email address: jose.morcillo.valenciano@gmail.com PostgreSQL version: 16.9 Operating system: Red Hat Enterprise Linux 9.4 (Plow) Description: =20 Hi folks!! Summary An index scan on a partition of a HASH-partitioned table returns rows that do not satisfy the query predicate. Sequential scans return correct results. The issue affects a PRIMARY KEY index inherited from a partitioned table. amcheck reports no corruption. Table definition (simplified) CREATE TABLE r_has_stock ( site_public_id varchar(10) NOT NULL, site_storage_location_id varchar(4) NOT NULL, product_format_public_id varchar(18) NOT NULL, logisticvariantid varchar(1) NOT NULL, stockstatus_id varchar(3) NOT NULL, has_stock boolean, PRIMARY KEY ( site_public_id, site_storage_location_id, product_format_public_id, logisticvariantid, stockstatus_id ) ) PARTITION BY HASH (site_public_id); The table has 10 HASH partitions: FOR VALUES WITH (modulus 10, remainder N) Problem description 1. Query using default plan (index scan) EXPLAIN (ANALYZE, VERBOSE, BUFFERS) SELECT * FROM r_has_stock WHERE site_public_id =3D '2781' AND product_format_public_id =3D '21594'; Plan: Index Scan using has_stock_p6_pkey Result: 1 row returned Returned row values: site_public_id =3D 2175 product_format_public_id =3D 84706 Row does NOT match predicate. 2. Force heap scan (disable index access) BEGIN; SET LOCAL enable_indexscan =3D off; SET LOCAL enable_bitmapscan =3D off; SET LOCAL enable_indexonlyscan =3D off; SELECT * FROM r_has_stock WHERE site_public_id =3D '2781' AND product_format_public_id =3D '21594'; ROLLBACK; Result: 0 rows 3. Verify tuple in partition SELECT ctid, site_public_id, product_format_public_id FROM has_stock_p6 WHERE site_public_id =3D '2781' AND product_format_public_id =3D '21594'; Result: 0 rows But: SELECT ctid, site_public_id, product_format_public_id FROM has_stock_p6 WHERE site_public_id =3D '2175' AND product_format_public_id =3D '84706'; returns: (3157,8) 4. amcheck results SELECT bt_index_check('has_stock_p6_pkey'::regclass, false); SELECT bt_index_check('has_stock_p6_pkey'::regclass, true); SELECT bt_index_parent_check('has_stock_p6_pkey'::regclass, true, true); All return success (no errors). Expected behavior Index scan should return exactly the same rows as heap scan. Expected result: 0 rows Actual behavior Index scan returns a tuple that does not satisfy the predicate. Additional checks Data checksums SHOW data_checksums; on Checksum failures SELECT datname, checksum_failures, checksum_last_failure FROM pg_stat_database WHERE datname =3D current_database(); Result: checksum_failures =3D 0 Additional notes =E2=80=A2 Database collation: en_US.UTF-8 =E2=80=A2 Server encoding: UTF8 =E2=80=A2 Explicit casts and COLLATE tests did not change beh= aviour. =E2=80=A2 Issue appears only when index scan is used. =E2=80=A2 Table and indexes originate from a cluster initiall= y running PostgreSQL 14.12 and later upgraded to 16.9. =E2=80=A2 After reindex the issue was resolved. Question Could this be related to HASH partitioning combined with PRIMARY KEY / UNIQUE indexes, or to data created in older PostgreSQL versions and later upgraded? Availability I can provide additional details or attempt to build a reduced reproducible test case if needed. REINDEX of similar partitions previously failed due to duplicate keys. Thanks!!!