8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
32
32
static bool _bt_compare_scankey_args (IndexScanDesc scan , ScanKey op ,
33
33
ScanKey leftarg , ScanKey rightarg ,
34
34
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 );
36
36
static void _bt_mark_scankey_required (ScanKey skey );
37
37
static bool _bt_check_rowcompare (ScanKey skey ,
38
38
IndexTuple tuple , TupleDesc tupdesc ,
@@ -265,49 +265,9 @@ _bt_preprocess_keys(IndexScanDesc scan)
265
265
/* We can short-circuit most of the work if there's just one key */
266
266
if (numberOfKeys == 1 )
267
267
{
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;
311
271
memcpy (outkeys , cur , sizeof (ScanKeyData ));
312
272
so -> numberOfKeys = 1 ;
313
273
/* We can mark the qual as required if it's for first index col */
@@ -340,35 +300,12 @@ _bt_preprocess_keys(IndexScanDesc scan)
340
300
{
341
301
if (i < numberOfKeys )
342
302
{
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 ))
346
305
{
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 ;
372
309
}
373
310
}
374
311
@@ -480,9 +417,6 @@ _bt_preprocess_keys(IndexScanDesc scan)
480
417
memset (xform , 0 , sizeof (xform ));
481
418
}
482
419
483
- /* apply indoption to scankey (might change sk_strategy!) */
484
- _bt_mark_scankey_with_indoption (cur , indoption );
485
-
486
420
/* check strategy this key's operator corresponds to */
487
421
j = cur -> sk_strategy - 1 ;
488
422
@@ -678,7 +612,7 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
678
612
* indexscan initiated by syscache lookup will use cross-data-type
679
613
* operators.)
680
614
*
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
682
616
* have to un-flip it to get the correct opfamily member.
683
617
*/
684
618
strat = op -> sk_strategy ;
@@ -708,29 +642,88 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
708
642
}
709
643
710
644
/*
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 .
712
646
*
713
647
* We copy the appropriate indoption value into the scankey sk_flags
714
648
* (shifting to avoid clobbering system-defined flag bits). Also, if
715
649
* the DESC option is set, commute (flip) the operator strategy number.
716
650
*
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
+ *
717
659
* This function is applied to the *input* scankey structure; therefore
718
660
* on a rescan we will be looking at already-processed scankeys. Hence
719
661
* we have to be careful not to re-commute the strategy if we already did it.
720
662
* It's a bit ugly to modify the caller's copy of the scankey but in practice
721
663
* there shouldn't be any problem, since the index's indoptions are certainly
722
664
* not going to change while the scankey survives.
723
665
*/
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 )
726
668
{
727
669
int addflags ;
728
670
729
671
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 */
730
722
if ((addflags & SK_BT_DESC ) && !(skey -> sk_flags & SK_BT_DESC ))
731
723
skey -> sk_strategy = BTCommuteStrategyNumber (skey -> sk_strategy );
732
724
skey -> sk_flags |= addflags ;
733
725
726
+ /* If it's a row header, fix row member flags and strategies similarly */
734
727
if (skey -> sk_flags & SK_ROW_HEADER )
735
728
{
736
729
ScanKey subkey = (ScanKey ) DatumGetPointer (skey -> sk_argument );
@@ -747,6 +740,8 @@ _bt_mark_scankey_with_indoption(ScanKey skey, int16 *indoption)
747
740
subkey ++ ;
748
741
}
749
742
}
743
+
744
+ return true;
750
745
}
751
746
752
747
/*
0 commit comments