Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5b76bb1

Browse files
committed
Dept of second thoughts: my first cut at supporting "x IS NOT NULL" btree
indexscans would do the wrong thing if index_rescan() was called with a NULL instead of a new set of scankeys and the index was DESC order, because sk_strategy would not get flipped a second time. I think that those provisions for a NULL argument are dead code now as far as the core backend goes, but possibly somebody somewhere is still using it. In any case, this refactoring seems clearer, and it's definitely shorter.
1 parent c3705d8 commit 5b76bb1

File tree

1 file changed

+75
-80
lines changed

1 file changed

+75
-80
lines changed

src/backend/access/nbtree/nbtutils.c

+75-80
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
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
*/
@@ -32,7 +32,7 @@
3232
static 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);
3636
static void _bt_mark_scankey_required(ScanKey skey);
3737
static 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

Comments
 (0)