From e8c1f8d2a4b8e7c5d6e3f4a5b6c7d8e9f0a1b2c3 Mon Sep 17 00:00:00 2001
From: Baji Shaik <baji.pgdev@gmail.com>
Date: Wed, 27 May 2026 07:11:27 -0500
Subject: [PATCH] Add regression tests for btree skip scan support functions

Several btree skip scan support functions in nbtcompare.c have zero
test coverage as shown by coverage.postgresql.org:

  oid8:  btoid8skipsupport, oid8_decrement, oid8_increment
  int8:  btint8skipsupport, int8_decrement, int8_increment
  bool:  btboolskipsupport, bool_decrement, bool_increment
  char:  btcharskipsupport, char_decrement, char_increment
  oid:   oid_decrement
  int2:  int2_decrement

Add tests that exercise skip scans (both forward and backward) on
multi-column indexes with these types as the leading column.  This
triggers the per-type skip-support function and the increment/
decrement helpers via the Index Only Scan path.

Author: Baji Shaik <baji.pgdev@gmail.com>
Reviewed-by:
Discussion: 
---
diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out
index 21dc9b5783a..111f5d4b682 100644
--- a/src/test/regress/expected/btree_index.out
+++ b/src/test/regress/expected/btree_index.out
@@ -736,3 +736,235 @@ ALTER INDEX btree_part_idx ALTER COLUMN id SET (n_distinct=100);
 ERROR:  ALTER action ALTER COLUMN ... SET cannot be performed on relation "btree_part_idx"
 DETAIL:  This operation is not supported for partitioned indexes.
 DROP TABLE btree_part;
+--
+-- Test btree skip scan support for types that currently lack test coverage
+-- (exercises btXXXskipsupport, XXX_decrement, XXX_increment functions)
+--
+SET enable_seqscan = off;
+SET enable_bitmapscan = off;
+-- int8: btint8skipsupport, int8_decrement, int8_increment
+CREATE TABLE skip_int8 (a int8, b int4);
+INSERT INTO skip_int8 SELECT i / 10, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_int8 (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a;
+                      QUERY PLAN                      
+------------------------------------------------------
+ Index Only Scan using skip_int8_a_b_idx on skip_int8
+   Index Cond: (b = 5)
+(2 rows)
+
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a;
+ a | b 
+---+---
+ 0 | 5
+ 1 | 5
+ 2 | 5
+ 3 | 5
+ 4 | 5
+ 5 | 5
+ 6 | 5
+ 7 | 5
+ 8 | 5
+ 9 | 5
+(10 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a DESC;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan Backward using skip_int8_a_b_idx on skip_int8
+   Index Cond: (b = 5)
+(2 rows)
+
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a DESC;
+ a | b 
+---+---
+ 9 | 5
+ 8 | 5
+ 7 | 5
+ 6 | 5
+ 5 | 5
+ 4 | 5
+ 3 | 5
+ 2 | 5
+ 1 | 5
+ 0 | 5
+(10 rows)
+
+DROP TABLE skip_int8;
+-- oid8: btoid8skipsupport, oid8_decrement, oid8_increment
+CREATE TABLE skip_oid8 (a oid8, b int4);
+INSERT INTO skip_oid8 SELECT (i / 10)::int8::oid8, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_oid8 (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a;
+                      QUERY PLAN                      
+------------------------------------------------------
+ Index Only Scan using skip_oid8_a_b_idx on skip_oid8
+   Index Cond: (b = 5)
+(2 rows)
+
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a;
+ a | b 
+---+---
+ 0 | 5
+ 1 | 5
+ 2 | 5
+ 3 | 5
+ 4 | 5
+ 5 | 5
+ 6 | 5
+ 7 | 5
+ 8 | 5
+ 9 | 5
+(10 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a DESC;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan Backward using skip_oid8_a_b_idx on skip_oid8
+   Index Cond: (b = 5)
+(2 rows)
+
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a DESC;
+ a | b 
+---+---
+ 9 | 5
+ 8 | 5
+ 7 | 5
+ 6 | 5
+ 5 | 5
+ 4 | 5
+ 3 | 5
+ 2 | 5
+ 1 | 5
+ 0 | 5
+(10 rows)
+
+DROP TABLE skip_oid8;
+-- bool: btboolskipsupport, bool_decrement, bool_increment
+CREATE TABLE skip_bool (a bool, b int4);
+INSERT INTO skip_bool SELECT (i % 2 = 0), i FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_bool (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a;
+                      QUERY PLAN                      
+------------------------------------------------------
+ Index Only Scan using skip_bool_a_b_idx on skip_bool
+   Index Cond: (b = 50)
+(2 rows)
+
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a;
+ a | b  
+---+----
+ t | 50
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a DESC;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan Backward using skip_bool_a_b_idx on skip_bool
+   Index Cond: (b = 50)
+(2 rows)
+
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a DESC;
+ a | b  
+---+----
+ t | 50
+(1 row)
+
+DROP TABLE skip_bool;
+-- "char": btcharskipsupport, char_decrement, char_increment
+CREATE TABLE skip_char (a "char", b int4);
+INSERT INTO skip_char SELECT chr(ascii('a') + (i % 26))::"char", i FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_char (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a;
+                      QUERY PLAN                      
+------------------------------------------------------
+ Index Only Scan using skip_char_a_b_idx on skip_char
+   Index Cond: (b = 50)
+(2 rows)
+
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a;
+ a | b  
+---+----
+ y | 50
+(1 row)
+
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a DESC;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan Backward using skip_char_a_b_idx on skip_char
+   Index Cond: (b = 50)
+(2 rows)
+
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a DESC;
+ a | b  
+---+----
+ y | 50
+(1 row)
+
+DROP TABLE skip_char;
+-- oid: oid_decrement (btoidskipsupport and oid_increment already covered)
+CREATE TABLE skip_oid (a oid, b int4);
+INSERT INTO skip_oid SELECT (i / 10)::oid, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_oid (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_oid WHERE b = 5 ORDER BY a DESC;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Index Only Scan Backward using skip_oid_a_b_idx on skip_oid
+   Index Cond: (b = 5)
+(2 rows)
+
+SELECT a, b FROM skip_oid WHERE b = 5 ORDER BY a DESC;
+ a | b 
+---+---
+ 9 | 5
+ 8 | 5
+ 7 | 5
+ 6 | 5
+ 5 | 5
+ 4 | 5
+ 3 | 5
+ 2 | 5
+ 1 | 5
+ 0 | 5
+(10 rows)
+
+DROP TABLE skip_oid;
+-- int2: int2_decrement (btint2skipsupport and int2_increment already covered)
+CREATE TABLE skip_int2 (a int2, b int4);
+INSERT INTO skip_int2 SELECT (i / 10)::int2, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_int2 (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_int2 WHERE b = 5 ORDER BY a DESC;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Index Only Scan Backward using skip_int2_a_b_idx on skip_int2
+   Index Cond: (b = 5)
+(2 rows)
+
+SELECT a, b FROM skip_int2 WHERE b = 5 ORDER BY a DESC;
+ a | b 
+---+---
+ 9 | 5
+ 8 | 5
+ 7 | 5
+ 6 | 5
+ 5 | 5
+ 4 | 5
+ 3 | 5
+ 2 | 5
+ 1 | 5
+ 0 | 5
+(10 rows)
+
+DROP TABLE skip_int2;
+RESET enable_seqscan;
+RESET enable_bitmapscan;
diff --git a/src/test/regress/sql/btree_index.sql b/src/test/regress/sql/btree_index.sql
index 6aaaa386abc..1109f1e0506 100644
--- a/src/test/regress/sql/btree_index.sql
+++ b/src/test/regress/sql/btree_index.sql
@@ -438,3 +438,79 @@ CREATE TABLE btree_part (id int4) PARTITION BY RANGE (id);
 CREATE INDEX btree_part_idx ON btree_part(id);
 ALTER INDEX btree_part_idx ALTER COLUMN id SET (n_distinct=100);
 DROP TABLE btree_part;
+
+--
+-- Test btree skip scan support for types that currently lack test coverage
+-- (exercises btXXXskipsupport, XXX_decrement, XXX_increment functions)
+--
+SET enable_seqscan = off;
+SET enable_bitmapscan = off;
+
+-- int8: btint8skipsupport, int8_decrement, int8_increment
+CREATE TABLE skip_int8 (a int8, b int4);
+INSERT INTO skip_int8 SELECT i / 10, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_int8 (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a;
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a;
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a DESC;
+SELECT a, b FROM skip_int8 WHERE b = 5 ORDER BY a DESC;
+DROP TABLE skip_int8;
+
+-- oid8: btoid8skipsupport, oid8_decrement, oid8_increment
+CREATE TABLE skip_oid8 (a oid8, b int4);
+INSERT INTO skip_oid8 SELECT (i / 10)::int8::oid8, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_oid8 (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a;
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a;
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a DESC;
+SELECT a, b FROM skip_oid8 WHERE b = 5 ORDER BY a DESC;
+DROP TABLE skip_oid8;
+
+-- bool: btboolskipsupport, bool_decrement, bool_increment
+CREATE TABLE skip_bool (a bool, b int4);
+INSERT INTO skip_bool SELECT (i % 2 = 0), i FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_bool (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a;
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a;
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a DESC;
+SELECT a, b FROM skip_bool WHERE b = 50 ORDER BY a DESC;
+DROP TABLE skip_bool;
+
+-- "char": btcharskipsupport, char_decrement, char_increment
+CREATE TABLE skip_char (a "char", b int4);
+INSERT INTO skip_char SELECT chr(ascii('a') + (i % 26))::"char", i FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_char (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a;
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a;
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a DESC;
+SELECT a, b FROM skip_char WHERE b = 50 ORDER BY a DESC;
+DROP TABLE skip_char;
+
+-- oid: oid_decrement (btoidskipsupport and oid_increment already covered)
+CREATE TABLE skip_oid (a oid, b int4);
+INSERT INTO skip_oid SELECT (i / 10)::oid, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_oid (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_oid WHERE b = 5 ORDER BY a DESC;
+SELECT a, b FROM skip_oid WHERE b = 5 ORDER BY a DESC;
+DROP TABLE skip_oid;
+
+-- int2: int2_decrement (btint2skipsupport and int2_increment already covered)
+CREATE TABLE skip_int2 (a int2, b int4);
+INSERT INTO skip_int2 SELECT (i / 10)::int2, i % 10 FROM generate_series(1, 100) i;
+CREATE INDEX ON skip_int2 (a, b);
+EXPLAIN (COSTS OFF)
+SELECT a, b FROM skip_int2 WHERE b = 5 ORDER BY a DESC;
+SELECT a, b FROM skip_int2 WHERE b = 5 ORDER BY a DESC;
+DROP TABLE skip_int2;
+
+RESET enable_seqscan;
+RESET enable_bitmapscan;

-- 
2.50.1 (Apple Git-155)
