]> granicus.if.org Git - postgresql/commitdiff
Restore correct btree preprocessing of "indexedcol IS NULL" conditions.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 29 Jun 2011 23:46:58 +0000 (19:46 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 29 Jun 2011 23:46:58 +0000 (19:46 -0400)
Such a condition is unsatisfiable in combination with any other type of
btree-indexable condition (since we assume btree operators are always
strict).  8.3 and 8.4 had an explicit test for this, which I removed in
commit 29c4ad98293e3c5cb3fcdd413a3f4904efff8762, mistakenly thinking that
the case would be subsumed by the more general handling of IS (NOT) NULL
added in that patch.  Put it back, and improve the comments about it, and
add a regression test case.

Per bug #6079 from Renat Nasyrov, and analysis by Dean Rasheed.

src/backend/access/nbtree/nbtutils.c
src/test/regress/expected/create_index.out
src/test/regress/sql/create_index.sql

index 2e896a258f7cb3763552096af5d3d76eafa4d2f4..f87eadcdec2dbd3c9ca95859ef5f4cb899e5bb28 100644 (file)
@@ -325,8 +325,14 @@ _bt_preprocess_keys(IndexScanDesc scan)
 
                        /*
                         * If = has been specified, all other keys can be eliminated as
-                        * redundant.  In case of key > 2 && key == 1 we can set qual_ok
-                        * to false and abandon further processing.
+                        * redundant.  If we have a case like key = 1 AND key > 2, we can
+                        * set qual_ok to false and abandon further processing.
+                        *
+                        * We also have to deal with the case of "key IS NULL", which is
+                        * unsatisfiable in combination with any other index condition.
+                        * By the time we get here, that's been classified as an equality
+                        * check, and we've rejected any combination of it with a regular
+                        * equality condition; but not with other types of conditions.
                         */
                        if (xform[BTEqualStrategyNumber - 1])
                        {
@@ -339,6 +345,13 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                        if (!chk || j == (BTEqualStrategyNumber - 1))
                                                continue;
 
+                                       if (eq->sk_flags & SK_SEARCHNULL)
+                                       {
+                                               /* IS NULL is contradictory to anything else */
+                                               so->qual_ok = false;
+                                               return;
+                                       }
+
                                        if (_bt_compare_scankey_args(scan, chk, eq, chk,
                                                                                                 &test_result))
                                        {
index c78d9ee1e801a51d61bd3830a9760a1b051a90d3..b23c712204e2052005db2a8f8da88d81e0baf340 100644 (file)
@@ -1279,6 +1279,18 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NUL
      1
 (1 row)
 
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+ count 
+-------
+   499
+(1 row)
+
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
+ count 
+-------
+     0
+(1 row)
+
 DROP INDEX onek_nulltest;
 CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 desc,unique1);
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
@@ -1305,6 +1317,18 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NUL
      1
 (1 row)
 
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+ count 
+-------
+   499
+(1 row)
+
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
+ count 
+-------
+     0
+(1 row)
+
 DROP INDEX onek_nulltest;
 CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 desc nulls last,unique1);
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
@@ -1331,6 +1355,18 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NUL
      1
 (1 row)
 
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+ count 
+-------
+   499
+(1 row)
+
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
+ count 
+-------
+     0
+(1 row)
+
 DROP INDEX onek_nulltest;
 CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2  nulls first,unique1);
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
@@ -1357,6 +1393,18 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NUL
      1
 (1 row)
 
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+ count 
+-------
+   499
+(1 row)
+
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
+ count 
+-------
+     0
+(1 row)
+
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
index 31b49ca2273b922aec961bfd406cbe483ab6f07b..bf27379f5918e112da8546b2b9472b131ef5cd31 100644 (file)
@@ -451,6 +451,8 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
 
 DROP INDEX onek_nulltest;
 
@@ -460,6 +462,8 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
 
 DROP INDEX onek_nulltest;
 
@@ -469,6 +473,8 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
 
 DROP INDEX onek_nulltest;
 
@@ -478,6 +484,8 @@ SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
 SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
+SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
 
 RESET enable_seqscan;
 RESET enable_indexscan;