88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.96 2010/01/02 16:57:35 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.97 2010/01/03 05:39:08 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
3232static bool _bt_compare_scankey_args (IndexScanDesc scan , ScanKey op ,
3333 ScanKey leftarg , ScanKey rightarg ,
3434 bool * result );
35- static void _bt_mark_scankey_with_indoption (ScanKey skey , int16 * indoption );
35+ static bool _bt_fix_scankey_strategy (ScanKey skey , int16 * indoption );
3636static void _bt_mark_scankey_required (ScanKey skey );
3737static bool _bt_check_rowcompare (ScanKey skey ,
3838 IndexTuple tuple , TupleDesc tupdesc ,
@@ -265,49 +265,9 @@ _bt_preprocess_keys(IndexScanDesc scan)
265265 /* We can short-circuit most of the work if there's just one key */
266266 if (numberOfKeys == 1 )
267267 {
268- /*
269- * We treat all btree operators as strict (even if they're not so
270- * marked in pg_proc). This means that it is impossible for an
271- * operator condition with a NULL comparison constant to succeed, and
272- * we can reject it right away.
273- *
274- * However, we now also support "x IS NULL" clauses as search
275- * conditions, so in that case keep going. The planner has not filled
276- * in any particular strategy in this case, so set it to
277- * BTEqualStrategyNumber --- we can treat IS NULL as an equality
278- * 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.
284- */
285- if (cur -> sk_flags & SK_ISNULL )
286- {
287- if (cur -> sk_flags & SK_SEARCHNULL )
288- {
289- cur -> sk_strategy = BTEqualStrategyNumber ;
290- cur -> sk_subtype = InvalidOid ;
291- }
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- }
307- else
308- so -> qual_ok = false;
309- }
310- _bt_mark_scankey_with_indoption (cur , indoption );
268+ /* Apply indoption to scankey (might change sk_strategy!) */
269+ if (!_bt_fix_scankey_strategy (cur , indoption ))
270+ so -> qual_ok = false;
311271 memcpy (outkeys , cur , sizeof (ScanKeyData ));
312272 so -> numberOfKeys = 1 ;
313273 /* We can mark the qual as required if it's for first index col */
@@ -340,35 +300,12 @@ _bt_preprocess_keys(IndexScanDesc scan)
340300 {
341301 if (i < numberOfKeys )
342302 {
343- /* See comments above about NULLs and IS NULL/NOT NULL handling */
344- /* Note: we assume SK_ISNULL is never set in a row header key */
345- if (cur -> sk_flags & SK_ISNULL )
303+ /* Apply indoption to scankey (might change sk_strategy!) */
304+ if (!_bt_fix_scankey_strategy (cur , indoption ))
346305 {
347- if (cur -> sk_flags & SK_SEARCHNULL )
348- {
349- cur -> sk_strategy = BTEqualStrategyNumber ;
350- cur -> sk_subtype = InvalidOid ;
351- }
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- }
367- else
368- {
369- so -> qual_ok = false;
370- return ;
371- }
306+ /* NULL can't be matched, so give up */
307+ so -> qual_ok = false;
308+ return ;
372309 }
373310 }
374311
@@ -480,9 +417,6 @@ _bt_preprocess_keys(IndexScanDesc scan)
480417 memset (xform , 0 , sizeof (xform ));
481418 }
482419
483- /* apply indoption to scankey (might change sk_strategy!) */
484- _bt_mark_scankey_with_indoption (cur , indoption );
485-
486420 /* check strategy this key's operator corresponds to */
487421 j = cur -> sk_strategy - 1 ;
488422
@@ -678,7 +612,7 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
678612 * indexscan initiated by syscache lookup will use cross-data-type
679613 * operators.)
680614 *
681- * If the sk_strategy was flipped by _bt_mark_scankey_with_indoption , we
615+ * If the sk_strategy was flipped by _bt_fix_scankey_strategy , we
682616 * have to un-flip it to get the correct opfamily member.
683617 */
684618 strat = op -> sk_strategy ;
@@ -708,29 +642,88 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
708642}
709643
710644/*
711- * Mark a scankey with info from the index's indoption array .
645+ * Adjust a scankey's strategy and flags setting as needed for indoptions .
712646 *
713647 * We copy the appropriate indoption value into the scankey sk_flags
714648 * (shifting to avoid clobbering system-defined flag bits). Also, if
715649 * the DESC option is set, commute (flip) the operator strategy number.
716650 *
651+ * A secondary purpose is to check for IS NULL/NOT NULL scankeys and set up
652+ * the strategy field correctly for them.
653+ *
654+ * Lastly, for ordinary scankeys (not IS NULL/NOT NULL), we check for a
655+ * NULL comparison value. Since all btree operators are assumed strict,
656+ * a NULL means that the qual cannot be satisfied. We return TRUE if the
657+ * comparison value isn't NULL, or FALSE if the scan should be abandoned.
658+ *
717659 * This function is applied to the *input* scankey structure; therefore
718660 * on a rescan we will be looking at already-processed scankeys. Hence
719661 * we have to be careful not to re-commute the strategy if we already did it.
720662 * It's a bit ugly to modify the caller's copy of the scankey but in practice
721663 * there shouldn't be any problem, since the index's indoptions are certainly
722664 * not going to change while the scankey survives.
723665 */
724- static void
725- _bt_mark_scankey_with_indoption (ScanKey skey , int16 * indoption )
666+ static bool
667+ _bt_fix_scankey_strategy (ScanKey skey , int16 * indoption )
726668{
727669 int addflags ;
728670
729671 addflags = indoption [skey -> sk_attno - 1 ] << SK_BT_INDOPTION_SHIFT ;
672+
673+ /*
674+ * We treat all btree operators as strict (even if they're not so marked
675+ * in pg_proc). This means that it is impossible for an operator condition
676+ * with a NULL comparison constant to succeed, and we can reject it right
677+ * away.
678+ *
679+ * However, we now also support "x IS NULL" clauses as search conditions,
680+ * so in that case keep going. The planner has not filled in any
681+ * particular strategy in this case, so set it to BTEqualStrategyNumber
682+ * --- we can treat IS NULL as an equality operator for purposes of search
683+ * strategy.
684+ *
685+ * Likewise, "x IS NOT NULL" is supported. We treat that as either "less
686+ * than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
687+ * FIRST index.
688+ */
689+ if (skey -> sk_flags & SK_ISNULL )
690+ {
691+ /* SK_ISNULL shouldn't be set in a row header scankey */
692+ Assert (!(skey -> sk_flags & SK_ROW_HEADER ));
693+
694+ /* Set indoption flags in scankey (might be done already) */
695+ skey -> sk_flags |= addflags ;
696+
697+ /* Set correct strategy for IS NULL or NOT NULL search */
698+ if (skey -> sk_flags & SK_SEARCHNULL )
699+ {
700+ skey -> sk_strategy = BTEqualStrategyNumber ;
701+ skey -> sk_subtype = InvalidOid ;
702+ }
703+ else if (skey -> sk_flags & SK_SEARCHNOTNULL )
704+ {
705+ if (skey -> sk_flags & SK_BT_NULLS_FIRST )
706+ skey -> sk_strategy = BTGreaterStrategyNumber ;
707+ else
708+ skey -> sk_strategy = BTLessStrategyNumber ;
709+ skey -> sk_subtype = InvalidOid ;
710+ }
711+ else
712+ {
713+ /* regular qual, so it cannot be satisfied */
714+ return false;
715+ }
716+
717+ /* Needn't do the rest */
718+ return true;
719+ }
720+
721+ /* Adjust strategy for DESC, if we didn't already */
730722 if ((addflags & SK_BT_DESC ) && !(skey -> sk_flags & SK_BT_DESC ))
731723 skey -> sk_strategy = BTCommuteStrategyNumber (skey -> sk_strategy );
732724 skey -> sk_flags |= addflags ;
733725
726+ /* If it's a row header, fix row member flags and strategies similarly */
734727 if (skey -> sk_flags & SK_ROW_HEADER )
735728 {
736729 ScanKey subkey = (ScanKey ) DatumGetPointer (skey -> sk_argument );
@@ -747,6 +740,8 @@ _bt_mark_scankey_with_indoption(ScanKey skey, int16 *indoption)
747740 subkey ++ ;
748741 }
749742 }
743+
744+ return true;
750745}
751746
752747/*
0 commit comments