]> granicus.if.org Git - postgresql/commitdiff
Fix indexable-row-comparison logic to account for covering indexes.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 11 Feb 2019 03:51:32 +0000 (22:51 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 11 Feb 2019 03:51:32 +0000 (22:51 -0500)
indxpath.c needs a good deal more attention for covering indexes than
it's gotten.  But so far as I can tell, the only really awful breakage
is in expand_indexqual_rowcompare (nee adjust_rowcompare_for_index),
which was only half fixed in c266ed31a.  The other problems aren't
bad enough to take the risk of a just-before-wrap fix.

The problem here is that if the leading column of a row comparison
matches an index (allowing this code to be reached), and some later
column doesn't match the index, it'll nonetheless believe that that
column matches the first included index column.  Typically that'll
lead to an error like "operator M is not a member of opfamily N" as
a result of fetching a garbage opfamily OID.  But with enough bad
luck, maybe a broken plan would be generated.

Discussion: https://postgr.es/m/25526.1549847928@sss.pgh.pa.us

src/backend/optimizer/path/indxpath.c
src/test/regress/expected/index_including.out
src/test/regress/sql/index_including.sql

index 51d2da56832632c5448dc38af44f255e0d577ad9..c03777ed6070e48fcf95412f615b65887f5d8e1f 100644 (file)
@@ -3979,7 +3979,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                        break;                          /* no good, volatile comparison value */
 
                /*
-                * The Var side can match any column of the index.
+                * The Var side can match any key column of the index.
                 */
                for (i = 0; i < index->nkeycolumns; i++)
                {
@@ -3991,7 +3991,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
 
                                break;
                }
-               if (i >= index->ncolumns)
+               if (i >= index->nkeycolumns)
                        break;                          /* no match found */
 
                /* Add column number to returned list */
index 16b4be34de3a73f6ccdaee56dfbf47fffacf6ee7..f86e5953facc6931fa4c51a35e49e46fb16b6864 100644 (file)
@@ -127,6 +127,23 @@ INSERT INTO tbl SELECT 1, NULL, 3*x, box('4,4,4,4') FROM generate_series(1,10) A
 ERROR:  null value in column "c2" violates not-null constraint
 DETAIL:  Failing row contains (1, null, 3, (4,4),(4,4)).
 INSERT INTO tbl SELECT x, 2*x, NULL, NULL FROM generate_series(1,10) AS x;
+explain (costs off)
+select * from tbl where (c1,c2,c3) < (2,5,1);
+                   QUERY PLAN                   
+------------------------------------------------
+ Bitmap Heap Scan on tbl
+   Filter: (ROW(c1, c2, c3) < ROW(2, 5, 1))
+   ->  Bitmap Index Scan on covering
+         Index Cond: (ROW(c1, c2) <= ROW(2, 5))
+(4 rows)
+
+select * from tbl where (c1,c2,c3) < (2,5,1);
+ c1 | c2 | c3 | c4 
+----+----+----+----
+  1 |  2 |    | 
+  2 |  4 |    | 
+(2 rows)
+
 DROP TABLE tbl;
 CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
                                UNIQUE(c1,c2) INCLUDE(c3,c4));
index ef5fd882f539b338d4b0677c56be961e0f809544..2c6dd6211e650b4ac47d8366af5461124ca99386 100644 (file)
@@ -73,6 +73,9 @@ SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conre
 INSERT INTO tbl SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
 INSERT INTO tbl SELECT 1, NULL, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
 INSERT INTO tbl SELECT x, 2*x, NULL, NULL FROM generate_series(1,10) AS x;
+explain (costs off)
+select * from tbl where (c1,c2,c3) < (2,5,1);
+select * from tbl where (c1,c2,c3) < (2,5,1);
 DROP TABLE tbl;
 
 CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,