diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 2e896a258f..f87eadcdec 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -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)) { diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index c78d9ee1e8..b23c712204 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -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; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 31b49ca227..bf27379f59 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -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;