88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.94 2009/10/08 22:34:57 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.95 2010/01/01 21:53:49 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -276,6 +276,11 @@ _bt_preprocess_keys(IndexScanDesc scan)
276276 * in any particular strategy in this case, so set it to
277277 * BTEqualStrategyNumber --- we can treat IS NULL as an equality
278278 * operator for purposes of search strategy.
279+ *
280+ * Likewise, "x IS NOT NULL" is supported. We treat that as either
281+ * "less than NULL" in a NULLS LAST index, or "greater than NULL"
282+ * in a NULLS FIRST index. However, we have to flip those around in
283+ * a DESC index, to allow for the re-flipping that occurs elsewhere.
279284 */
280285 if (cur -> sk_flags & SK_ISNULL )
281286 {
@@ -284,6 +289,21 @@ _bt_preprocess_keys(IndexScanDesc scan)
284289 cur -> sk_strategy = BTEqualStrategyNumber ;
285290 cur -> sk_subtype = InvalidOid ;
286291 }
292+ else if (cur -> sk_flags & SK_SEARCHNOTNULL )
293+ {
294+ switch (indoption [cur -> sk_attno - 1 ] &
295+ (INDOPTION_DESC | INDOPTION_NULLS_FIRST ))
296+ {
297+ case 0 : /* ASC / NULLS LAST */
298+ case INDOPTION_DESC | INDOPTION_NULLS_FIRST :
299+ cur -> sk_strategy = BTLessStrategyNumber ;
300+ break ;
301+ default :
302+ cur -> sk_strategy = BTGreaterStrategyNumber ;
303+ break ;
304+ }
305+ cur -> sk_subtype = InvalidOid ;
306+ }
287307 else
288308 so -> qual_ok = false;
289309 }
@@ -320,7 +340,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
320340 {
321341 if (i < numberOfKeys )
322342 {
323- /* See comments above about NULLs and IS NULL handling. */
343+ /* See comments above about NULLs and IS NULL/NOT NULL handling */
324344 /* Note: we assume SK_ISNULL is never set in a row header key */
325345 if (cur -> sk_flags & SK_ISNULL )
326346 {
@@ -329,6 +349,21 @@ _bt_preprocess_keys(IndexScanDesc scan)
329349 cur -> sk_strategy = BTEqualStrategyNumber ;
330350 cur -> sk_subtype = InvalidOid ;
331351 }
352+ else if (cur -> sk_flags & SK_SEARCHNOTNULL )
353+ {
354+ switch (indoption [cur -> sk_attno - 1 ] &
355+ (INDOPTION_DESC | INDOPTION_NULLS_FIRST ))
356+ {
357+ case 0 : /* ASC / NULLS LAST */
358+ case INDOPTION_DESC | INDOPTION_NULLS_FIRST :
359+ cur -> sk_strategy = BTLessStrategyNumber ;
360+ break ;
361+ default :
362+ cur -> sk_strategy = BTGreaterStrategyNumber ;
363+ break ;
364+ }
365+ cur -> sk_subtype = InvalidOid ;
366+ }
332367 else
333368 {
334369 so -> qual_ok = false;
@@ -365,13 +400,6 @@ _bt_preprocess_keys(IndexScanDesc scan)
365400 if (!chk || j == (BTEqualStrategyNumber - 1 ))
366401 continue ;
367402
368- /* IS NULL together with any other predicate must fail */
369- if (eq -> sk_flags & SK_SEARCHNULL )
370- {
371- so -> qual_ok = false;
372- return ;
373- }
374-
375403 if (_bt_compare_scankey_args (scan , chk , eq , chk ,
376404 & test_result ))
377405 {
@@ -484,23 +512,6 @@ _bt_preprocess_keys(IndexScanDesc scan)
484512 else
485513 {
486514 /* yup, keep only the more restrictive key */
487-
488- /* if either arg is NULL, don't try to compare */
489- if ((cur -> sk_flags | xform [j ]-> sk_flags ) & SK_ISNULL )
490- {
491- /* at least one of them must be an IS NULL clause */
492- Assert (j == (BTEqualStrategyNumber - 1 ));
493- Assert ((cur -> sk_flags | xform [j ]-> sk_flags ) & SK_SEARCHNULL );
494- /* if one is and one isn't, the search must fail */
495- if ((cur -> sk_flags ^ xform [j ]-> sk_flags ) & SK_SEARCHNULL )
496- {
497- so -> qual_ok = false;
498- return ;
499- }
500- /* we have duplicate IS NULL clauses, ignore the newer one */
501- continue ;
502- }
503-
504515 if (_bt_compare_scankey_args (scan , cur , cur , xform [j ],
505516 & test_result ))
506517 {
@@ -534,8 +545,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
534545}
535546
536547/*
537- * Compare two scankey values using a specified operator. Both values
538- * must be already known non-NULL.
548+ * Compare two scankey values using a specified operator.
539549 *
540550 * The test we want to perform is logically "leftarg op rightarg", where
541551 * leftarg and rightarg are the sk_argument values in those ScanKeys, and
@@ -555,8 +565,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
555565 *
556566 * Note: this routine needs to be insensitive to any DESC option applied
557567 * to the index column. For example, "x < 4" is a tighter constraint than
558- * "x < 5" regardless of which way the index is sorted. We don't worry about
559- * NULLS FIRST/LAST either, since the given values are never nulls.
568+ * "x < 5" regardless of which way the index is sorted.
560569 */
561570static bool
562571_bt_compare_scankey_args (IndexScanDesc scan , ScanKey op ,
@@ -571,6 +580,64 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
571580 cmp_op ;
572581 StrategyNumber strat ;
573582
583+ /*
584+ * First, deal with cases where one or both args are NULL. This should
585+ * only happen when the scankeys represent IS NULL/NOT NULL conditions.
586+ */
587+ if ((leftarg -> sk_flags | rightarg -> sk_flags ) & SK_ISNULL )
588+ {
589+ bool leftnull ,
590+ rightnull ;
591+
592+ if (leftarg -> sk_flags & SK_ISNULL )
593+ {
594+ Assert (leftarg -> sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL ));
595+ leftnull = true;
596+ }
597+ else
598+ leftnull = false;
599+ if (rightarg -> sk_flags & SK_ISNULL )
600+ {
601+ Assert (rightarg -> sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL ));
602+ rightnull = true;
603+ }
604+ else
605+ rightnull = false;
606+
607+ /*
608+ * We treat NULL as either greater than or less than all other values.
609+ * Since true > false, the tests below work correctly for NULLS LAST
610+ * logic. If the index is NULLS FIRST, we need to flip the strategy.
611+ */
612+ strat = op -> sk_strategy ;
613+ if (op -> sk_flags & SK_BT_NULLS_FIRST )
614+ strat = BTCommuteStrategyNumber (strat );
615+
616+ switch (strat )
617+ {
618+ case BTLessStrategyNumber :
619+ * result = (leftnull < rightnull );
620+ break ;
621+ case BTLessEqualStrategyNumber :
622+ * result = (leftnull <= rightnull );
623+ break ;
624+ case BTEqualStrategyNumber :
625+ * result = (leftnull == rightnull );
626+ break ;
627+ case BTGreaterEqualStrategyNumber :
628+ * result = (leftnull >= rightnull );
629+ break ;
630+ case BTGreaterStrategyNumber :
631+ * result = (leftnull > rightnull );
632+ break ;
633+ default :
634+ elog (ERROR , "unrecognized StrategyNumber: %d" , (int ) strat );
635+ * result = false; /* keep compiler quiet */
636+ break ;
637+ }
638+ return true;
639+ }
640+
574641 /*
575642 * The opfamily we need to worry about is identified by the index column.
576643 */
@@ -844,11 +911,18 @@ _bt_checkkeys(IndexScanDesc scan,
844911
845912 if (key -> sk_flags & SK_ISNULL )
846913 {
847- /* Handle IS NULL tests */
848- Assert (key -> sk_flags & SK_SEARCHNULL );
849-
850- if (isNull )
851- continue ; /* tuple satisfies this qual */
914+ /* Handle IS NULL/NOT NULL tests */
915+ if (key -> sk_flags & SK_SEARCHNULL )
916+ {
917+ if (isNull )
918+ continue ; /* tuple satisfies this qual */
919+ }
920+ else
921+ {
922+ Assert (key -> sk_flags & SK_SEARCHNOTNULL );
923+ if (!isNull )
924+ continue ; /* tuple satisfies this qual */
925+ }
852926
853927 /*
854928 * Tuple fails this qual. If it's a required qual for the current
0 commit comments