|
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 |
|
|