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 1vubF3-00FJ3a-1B for pgsql-bugs@arkaria.postgresql.org; Mon, 23 Feb 2026 19:05:13 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vubF0-00EgeM-2O for pgsql-bugs@arkaria.postgresql.org; Mon, 23 Feb 2026 19:05:10 +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 1vubF0-00EgeD-0m for pgsql-bugs@lists.postgresql.org; Mon, 23 Feb 2026 19:05:10 +0000 Received: from mail-lf1-x12b.google.com ([2a00:1450:4864:20::12b]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1vubEx-00000000qD7-0Stw for pgsql-bugs@lists.postgresql.org; Mon, 23 Feb 2026 19:05:09 +0000 Received: by mail-lf1-x12b.google.com with SMTP id 2adb3069b0e04-59e6c181402so5909995e87.3 for ; Mon, 23 Feb 2026 11:05:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1771873507; cv=none; d=google.com; s=arc-20240605; b=IcCaEO27zG8IcxVvI/ZGvP0WRHU4G8Urkh2wUm6++4VyehI8oL95AzT3vHLc2TmJuV Pzq8uWjKPn1u9SFPB5vQFkrWYtgCdHQjg3W4mIbLFk9y03uuftb5Ae9liYwkKwtAPJeF IrkqtJO/YQO4Nvb1neCw/RkwCpidX1ZjZ9kmCgAlZir37snGh8ud25UYb2WVHOqo8HDz OE0SnMV7RvLLb7k2x5YDsgO9MPJhvM+GKIaIDQyb61YYGW92AGVNZwMmMHNzWyIRjmp0 kvOcm0b8ke1fLDQj7NLyo/pUk+/mv0rXJIEFqsQmENQBufaNgH8UqqMTcg8qZ0FO/2H3 voPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=SIVR3DQJo3miEsh8OxI/WW1QdplvBpAE3ERpdCcZpfg=; fh=xltBBJ02k7MgufP5JFofdBvOPsjYIdxXUgzFl/BvW08=; b=FwGIQ1EugY92Eo+a8PqqUEwpztWnhOc3RKYTNaj1xhwzZvxkNT4y9h5FzoaZhbuBQm +IUuYwu9mwLXS7HVYsXdwf8jzW64QUafqvdaIKqUe4XVwBP2XIzM+c0JtQ1lPM7JxTmP 0weEyDYUO3HqD5cW7RsQbjaU68ea/wClY0OKGm/LjIT15Jw5kULFesVzqfJnc/wj4upn uheRCOBq7UxaQInj1Dn5/GQhFENbyKWVQJAE5XFDJAnqqJPArQNCw8r6N6dp0SuZsOlp QeqOyvzFxMN/rLYXPZvNYzTVxVVfXmFLLgkMc9nr/BTcTKmEUkPMTFEkIH4rl0lFJ6Xc fIUw==; 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=20230601; t=1771873507; x=1772478307; darn=lists.postgresql.org; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=SIVR3DQJo3miEsh8OxI/WW1QdplvBpAE3ERpdCcZpfg=; b=RF0OS6P/88ZnykaHrDrARwsM+AUUsQiv6fCzFQaUAfaujOAKvzmsYv7SujWCnbdmTd th9gOIkjL/K6iNmUxBXxZOGomEcITyUdWBwAarrukEHNXJF/FI2vmkDcE9YHAXiORZwE N0Kj/ZAYBaEjeqwgjSRBmbCbzz4B3oF6TCXknUVPtv0GbS0JUiivFhrcZ3aZr2qZtYJx QdHU8l48cVJAv3M8NbJa7JkZKInDoglrfISVDselH7qMWUT8y37IKVaf7OzrpsJPeRfg NtF4REJUl39C0LuwunloFQhAQPmiNsbe/IrIJHpkErYC4CkOqx3PXUZGGruxU7EgmcbC 1KDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771873507; x=1772478307; h=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=SIVR3DQJo3miEsh8OxI/WW1QdplvBpAE3ERpdCcZpfg=; b=fX8rpvfgQuhcnUfonL3REKHEGShUEzVOkXa0WnuGiHGdllgLxdqA/NseEmkJRhXCHG Mqk8hAfHmBAivKg7qjnYZWy2nd6gX7h1SG101AdXkgihdFukf8edeuaUuVPQKxtphwAv yrI7lp3mPBSVqLvBWc6r3tw8vlkNUS0BEoRO7oUQmytpkEkHgwuA6ZGIvDbfaplFmZP5 vL+8mukZdQxrNptr33sj6RCStoPK3Ix21HKYlJXSGbf9t7GgTxLeFSWJooKPi35MEEGQ eEUDrVh1ovq7zNGHye8P8SPIg61I13jt8dIHSWidOtBwZeLt/VM3ecEcF86/EFVurnIZ E75Q== X-Forwarded-Encrypted: i=1; AJvYcCWGko2p8v41+vYwkMZq8XoB3Fs3APO8AEUu2/Ga/+UkyJYfPkzgF1IuF4e6dfFnQOdi2pnXT3gn8Otr@lists.postgresql.org X-Gm-Message-State: AOJu0YzC3MKzXRLB82Eg5fQJg74H9718LbKPqiQqh5/hLDFEHBqDKzuF VnJ3mFThTWjtmAyY/9M188+SRQHm7NSNzV1Pr1bE25uXo1DpDGtxqcJaEUlJJuZotihJ8NPHmxa SAV3nJV2OeQ+A8MLAiKGca2KblDjKESzKS2SJ X-Gm-Gg: ATEYQzxQbyymjP7Wm2WewQ/6iqHznxjaaMf1FnBx0LDzqD6Lip0sQLYdTG+VZrnJB+e YyHYj6wtVuCqJMjNWBTAxsdsZRpC2xYbiNWC58wr24i2Q/T1uCioz9zuQ6B+MrJFvS9u/MXV1Bs teZEVhutvznbgZxNhD8UXjnsAFnA5UX6SEYQV9XnsDYVpSo5iQCWELUHONACAZ3MU+pf86fdauT Di3+pSbEdGtIhbD1RAC6Ub3fZdVODJxjOtr5FV5ii4LQuYPbaj5V0SjNx4C2B5rdlGJzoHF9NL9 bbpPpK98QHtrVVFMVMgygR/qAAum9O0YhGSsEZM9OBZzsTJ8SVHb9ODTpexQ1aM1P7reRBIZ4GG 5blXV X-Received: by 2002:a05:6512:64a8:b0:5a0:ee0b:c25c with SMTP id 2adb3069b0e04-5a0ee0bc33cmr2818121e87.26.1771873506408; Mon, 23 Feb 2026 11:05:06 -0800 (PST) MIME-Version: 1.0 References: <19414-add8251d7863a802@postgresql.org> In-Reply-To: <19414-add8251d7863a802@postgresql.org> From: Rafia Sabih Date: Mon, 23 Feb 2026 11:04:54 -0800 X-Gm-Features: AaiRm5056bayqYShiLU1mV9TzkldHt1E7c_oFjTj_FmifisK9X5XwbuETFL5-kk Message-ID: Subject: Re: BUG #19414: Wrong rows returned by index scan on HASH-partitioned table with PRIMARY KEY (PostgreSQL 16.9) To: jose.morcillo.valenciano@gmail.com, pgsql-bugs@lists.postgresql.org Content-Type: multipart/alternative; boundary="000000000000efbf0d064b82721c" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000efbf0d064b82721c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello, Thanks for reporting, but we can be more helpful if you may provide a reproducible case to investigate this further. On Fri, 20 Feb 2026 at 00:21, PG Bug reporting form wrote: > 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: > > Hi folks!! > > Summary > > An index scan on a partition of a HASH-partitioned table returns rows tha= t > 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 b= ehaviour. > =E2=80=A2 Issue appears only when index scan is used. > =E2=80=A2 Table and indexes originate from a cluster initia= lly > 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 reproducib= le > test case if needed. > REINDEX of similar partitions previously failed due to duplicate keys. > > > Thanks!!! > > > > > --=20 Regards, Rafia Sabih CYBERTEC PostgreSQL International GmbH --000000000000efbf0d064b82721c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hello,

Thanks for reporting, but we can= be more helpful if you may provide a reproducible case to investigate this= further.

<= div dir=3D"ltr" class=3D"gmail_attr">On Fri, 20 Feb 2026 at 00:21, PG Bug r= eporting form <noreply@postgre= sql.org> wrote:
The following bug has been logged on the website:

Bug reference:=C2=A0 =C2=A0 =C2=A0 19414
Logged by:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Jos=C3=A9 Antonio Morcillo Val= enciano
Email address:=C2=A0 =C2=A0 =C2=A0 jose.morcillo.valenciano@gmail.com
PostgreSQL version: 16.9
Operating system:=C2=A0 =C2=A0Red Hat Enterprise Linux 9.4 (Plow)
Description:=C2=A0 =C2=A0 =C2=A0 =C2=A0

Hi folks!!

Summary

An index scan on a partition of a HASH-partitioned table returns rows that<= br> 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 (
=C2=A0 =C2=A0 site_public_id varchar(10) NOT NULL,
=C2=A0 =C2=A0 site_storage_location_id varchar(4) NOT NULL,
=C2=A0 =C2=A0 product_format_public_id varchar(18) NOT NULL,
=C2=A0 =C2=A0 logisticvariantid varchar(1) NOT NULL,
=C2=A0 =C2=A0 stockstatus_id varchar(3) NOT NULL,
=C2=A0 =C2=A0 has_stock boolean,
=C2=A0 =C2=A0 PRIMARY KEY (
=C2=A0 =C2=A0 =C2=A0 site_public_id,
=C2=A0 =C2=A0 =C2=A0 site_storage_location_id,
=C2=A0 =C2=A0 =C2=A0 product_format_public_id,
=C2=A0 =C2=A0 =C2=A0 logisticvariantid,
=C2=A0 =C2=A0 =C2=A0 stockstatus_id
=C2=A0 =C2=A0 )
) 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'
=C2=A0 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'
=C2=A0 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'
=C2=A0 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'
=C2=A0 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, t= rue);

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
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =E2=80=A2=C2=A0 =C2=A0 =C2=A0 =C2=A0Database co= llation: en_US.UTF-8
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =E2=80=A2=C2=A0 =C2=A0 =C2=A0 =C2=A0Server enco= ding: UTF8
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =E2=80=A2=C2=A0 =C2=A0 =C2=A0 =C2=A0Explicit ca= sts and COLLATE tests did not change behaviour.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =E2=80=A2=C2=A0 =C2=A0 =C2=A0 =C2=A0Issue appea= rs only when index scan is used.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =E2=80=A2=C2=A0 =C2=A0 =C2=A0 =C2=A0Table and i= ndexes originate from a cluster initially running
PostgreSQL 14.12 and later upgraded to 16.9.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =E2=80=A2=C2=A0 =C2=A0 =C2=A0 =C2=A0After reind= ex 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!!!






--
Regards,
Rafia Sabih
CYBERTEC PostgreSQL = International GmbH
--000000000000efbf0d064b82721c--