|
8 | 8 | * |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.83 2007/03/30 00:12:59 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.84 2007/04/06 22:33:42 tgl Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
@@ -264,12 +264,27 @@ _bt_preprocess_keys(IndexScanDesc scan) |
264 | 264 | if (numberOfKeys==1) |
265 | 265 | { |
266 | 266 | /* |
267 | | - * We don't use indices for 'A is null' and 'A is not null' currently |
268 | | - * and 'A < = > <> NULL' will always fail - so qual is not OK if |
269 | | - * comparison value is NULL. - vadim 03/21/97 |
| 267 | + * We treat all btree operators as strict (even if they're not so |
| 268 | + * marked in pg_proc). This means that it is impossible for an |
| 269 | + * operator condition with a NULL comparison constant to succeed, |
| 270 | + * and we can reject it right away. |
| 271 | + * |
| 272 | + * However, we now also support "x IS NULL" clauses as search |
| 273 | + * conditions, so in that case keep going. The planner has not |
| 274 | + * filled in any particular strategy in this case, so set it to |
| 275 | + * BTEqualStrategyNumber --- we can treat IS NULL as an equality |
| 276 | + * operator for purposes of search strategy. |
270 | 277 | */ |
271 | 278 | if (cur->sk_flags&SK_ISNULL) |
272 | | -so->qual_ok= false; |
| 279 | +{ |
| 280 | +if (cur->sk_flags&SK_SEARCHNULL) |
| 281 | +{ |
| 282 | +cur->sk_strategy=BTEqualStrategyNumber; |
| 283 | +cur->sk_subtype=InvalidOid; |
| 284 | +} |
| 285 | +else |
| 286 | +so->qual_ok= false; |
| 287 | +} |
273 | 288 | _bt_mark_scankey_with_indoption(cur,indoption); |
274 | 289 | memcpy(outkeys,cur,sizeof(ScanKeyData)); |
275 | 290 | so->numberOfKeys=1; |
@@ -303,17 +318,20 @@ _bt_preprocess_keys(IndexScanDesc scan) |
303 | 318 | { |
304 | 319 | if (i<numberOfKeys) |
305 | 320 | { |
306 | | -/* See comments above: any NULL implies cannot match qual */ |
| 321 | +/* See comments above about NULLs and IS NULL handling. */ |
307 | 322 | /* Note: we assume SK_ISNULL is never set in a row header key */ |
308 | 323 | if (cur->sk_flags&SK_ISNULL) |
309 | 324 | { |
310 | | -so->qual_ok= false; |
311 | | - |
312 | | -/* |
313 | | - * Quit processing so we don't try to invoke comparison |
314 | | - * routines on NULLs. |
315 | | - */ |
316 | | -return; |
| 325 | +if (cur->sk_flags&SK_SEARCHNULL) |
| 326 | +{ |
| 327 | +cur->sk_strategy=BTEqualStrategyNumber; |
| 328 | +cur->sk_subtype=InvalidOid; |
| 329 | +} |
| 330 | +else |
| 331 | +{ |
| 332 | +so->qual_ok= false; |
| 333 | +return; |
| 334 | +} |
317 | 335 | } |
318 | 336 | } |
319 | 337 |
|
@@ -344,6 +362,14 @@ _bt_preprocess_keys(IndexScanDesc scan) |
344 | 362 |
|
345 | 363 | if (!chk||j== (BTEqualStrategyNumber-1)) |
346 | 364 | continue; |
| 365 | + |
| 366 | +/* IS NULL together with any other predicate must fail */ |
| 367 | +if (eq->sk_flags&SK_SEARCHNULL) |
| 368 | +{ |
| 369 | +so->qual_ok= false; |
| 370 | +return; |
| 371 | +} |
| 372 | + |
347 | 373 | if (_bt_compare_scankey_args(scan,chk,eq,chk, |
348 | 374 | &test_result)) |
349 | 375 | { |
@@ -455,6 +481,23 @@ _bt_preprocess_keys(IndexScanDesc scan) |
455 | 481 | else |
456 | 482 | { |
457 | 483 | /* yup, keep only the more restrictive key */ |
| 484 | + |
| 485 | +/* if either arg is NULL, don't try to compare */ |
| 486 | +if ((cur->sk_flags |xform[j]->sk_flags)&SK_ISNULL) |
| 487 | +{ |
| 488 | +/* at least one of them must be an IS NULL clause */ |
| 489 | +Assert(j== (BTEqualStrategyNumber-1)); |
| 490 | +Assert((cur->sk_flags |xform[j]->sk_flags)&SK_SEARCHNULL); |
| 491 | +/* if one is and one isn't, the search must fail */ |
| 492 | +if ((cur->sk_flags ^xform[j]->sk_flags)&SK_SEARCHNULL) |
| 493 | +{ |
| 494 | +so->qual_ok= false; |
| 495 | +return; |
| 496 | +} |
| 497 | +/* we have duplicate IS NULL clauses, ignore the newer one */ |
| 498 | +continue; |
| 499 | +} |
| 500 | + |
458 | 501 | if (_bt_compare_scankey_args(scan,cur,cur,xform[j], |
459 | 502 | &test_result)) |
460 | 503 | { |
@@ -798,11 +841,29 @@ _bt_checkkeys(IndexScanDesc scan, |
798 | 841 | tupdesc, |
799 | 842 | &isNull); |
800 | 843 |
|
801 | | -/* btree doesn't support 'A is null' clauses, yet */ |
802 | 844 | if (key->sk_flags&SK_ISNULL) |
803 | 845 | { |
804 | | -/* we shouldn't get here, really; see _bt_preprocess_keys() */ |
805 | | -*continuescan= false; |
| 846 | +/* Handle IS NULL tests */ |
| 847 | +Assert(key->sk_flags&SK_SEARCHNULL); |
| 848 | + |
| 849 | +if (isNull) |
| 850 | +continue;/* tuple satisfies this qual */ |
| 851 | + |
| 852 | +/* |
| 853 | + * Tuple fails this qual. If it's a required qual for the current |
| 854 | + * scan direction, then we can conclude no further tuples will |
| 855 | + * pass, either. |
| 856 | + */ |
| 857 | +if ((key->sk_flags&SK_BT_REQFWD)&& |
| 858 | +ScanDirectionIsForward(dir)) |
| 859 | +*continuescan= false; |
| 860 | +elseif ((key->sk_flags&SK_BT_REQBKWD)&& |
| 861 | +ScanDirectionIsBackward(dir)) |
| 862 | +*continuescan= false; |
| 863 | + |
| 864 | +/* |
| 865 | + * In any case, this indextuple doesn't match the qual. |
| 866 | + */ |
806 | 867 | return false; |
807 | 868 | } |
808 | 869 |
|
|