~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/access/nbtree/nbtutils.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * nbtutils.c
 
4
 *        Utility code for Postgres btree implementation.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.62 2004-12-31 21:59:22 pgsql Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
 
 
16
#include "postgres.h"
 
17
 
 
18
#include "access/genam.h"
 
19
#include "access/nbtree.h"
 
20
#include "catalog/catalog.h"
 
21
#include "executor/execdebug.h"
 
22
 
 
23
 
 
24
/*
 
25
 * _bt_mkscankey
 
26
 *              Build a scan key that contains comparison data from itup
 
27
 *              as well as comparator routines appropriate to the key datatypes.
 
28
 *
 
29
 *              The result is intended for use with _bt_compare().
 
30
 */
 
31
ScanKey
 
32
_bt_mkscankey(Relation rel, IndexTuple itup)
 
33
{
 
34
        ScanKey         skey;
 
35
        TupleDesc       itupdesc;
 
36
        int                     natts;
 
37
        int                     i;
 
38
 
 
39
        itupdesc = RelationGetDescr(rel);
 
40
        natts = RelationGetNumberOfAttributes(rel);
 
41
 
 
42
        skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
 
43
 
 
44
        for (i = 0; i < natts; i++)
 
45
        {
 
46
                FmgrInfo   *procinfo;
 
47
                Datum           arg;
 
48
                bool            null;
 
49
 
 
50
                /*
 
51
                 * We can use the cached (default) support procs since no
 
52
                 * cross-type comparison can be needed.
 
53
                 */
 
54
                procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
 
55
                arg = index_getattr(itup, i + 1, itupdesc, &null);
 
56
                ScanKeyEntryInitializeWithInfo(&skey[i],
 
57
                                                                           null ? SK_ISNULL : 0,
 
58
                                                                           (AttrNumber) (i + 1),
 
59
                                                                           InvalidStrategy,
 
60
                                                                           InvalidOid,
 
61
                                                                           procinfo,
 
62
                                                                           arg);
 
63
        }
 
64
 
 
65
        return skey;
 
66
}
 
67
 
 
68
/*
 
69
 * _bt_mkscankey_nodata
 
70
 *              Build a scan key that contains comparator routines appropriate to
 
71
 *              the key datatypes, but no comparison data.      The comparison data
 
72
 *              ultimately used must match the key datatypes.
 
73
 *
 
74
 *              The result cannot be used with _bt_compare().  Currently this
 
75
 *              routine is only called by nbtsort.c and tuplesort.c, which have
 
76
 *              their own comparison routines.
 
77
 */
 
78
ScanKey
 
79
_bt_mkscankey_nodata(Relation rel)
 
80
{
 
81
        ScanKey         skey;
 
82
        TupleDesc       itupdesc;
 
83
        int                     natts;
 
84
        int                     i;
 
85
 
 
86
        itupdesc = RelationGetDescr(rel);
 
87
        natts = RelationGetNumberOfAttributes(rel);
 
88
 
 
89
        skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
 
90
 
 
91
        for (i = 0; i < natts; i++)
 
92
        {
 
93
                FmgrInfo   *procinfo;
 
94
 
 
95
                /*
 
96
                 * We can use the cached (default) support procs since no
 
97
                 * cross-type comparison can be needed.
 
98
                 */
 
99
                procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
 
100
                ScanKeyEntryInitializeWithInfo(&skey[i],
 
101
                                                                           SK_ISNULL,
 
102
                                                                           (AttrNumber) (i + 1),
 
103
                                                                           InvalidStrategy,
 
104
                                                                           InvalidOid,
 
105
                                                                           procinfo,
 
106
                                                                           (Datum) 0);
 
107
        }
 
108
 
 
109
        return skey;
 
110
}
 
111
 
 
112
/*
 
113
 * free a scan key made by either _bt_mkscankey or _bt_mkscankey_nodata.
 
114
 */
 
115
void
 
116
_bt_freeskey(ScanKey skey)
 
117
{
 
118
        pfree(skey);
 
119
}
 
120
 
 
121
/*
 
122
 * free a retracement stack made by _bt_search.
 
123
 */
 
124
void
 
125
_bt_freestack(BTStack stack)
 
126
{
 
127
        BTStack         ostack;
 
128
 
 
129
        while (stack != NULL)
 
130
        {
 
131
                ostack = stack;
 
132
                stack = stack->bts_parent;
 
133
                pfree(ostack);
 
134
        }
 
135
}
 
136
 
 
137
/*
 
138
 * Construct a BTItem from a plain IndexTuple.
 
139
 *
 
140
 * This is now useless code, since a BTItem *is* an index tuple with
 
141
 * no extra stuff.      We hang onto it for the moment to preserve the
 
142
 * notational distinction, in case we want to add some extra stuff
 
143
 * again someday.
 
144
 */
 
145
BTItem
 
146
_bt_formitem(IndexTuple itup)
 
147
{
 
148
        int                     nbytes_btitem;
 
149
        BTItem          btitem;
 
150
        Size            tuplen;
 
151
 
 
152
        /* make a copy of the index tuple with room for extra stuff */
 
153
        tuplen = IndexTupleSize(itup);
 
154
        nbytes_btitem = tuplen + (sizeof(BTItemData) - sizeof(IndexTupleData));
 
155
 
 
156
        btitem = (BTItem) palloc(nbytes_btitem);
 
157
        memcpy((char *) &(btitem->bti_itup), (char *) itup, tuplen);
 
158
 
 
159
        return btitem;
 
160
}
 
161
 
 
162
/*----------
 
163
 *      _bt_preprocess_keys() -- Preprocess scan keys
 
164
 *
 
165
 * The caller-supplied keys (in scan->keyData[]) are copied to
 
166
 * so->keyData[] with possible transformation.  scan->numberOfKeys is
 
167
 * the number of input keys, so->numberOfKeys gets the number of output
 
168
 * keys (possibly less, never greater).
 
169
 *
 
170
 * The primary purpose of this routine is to discover how many scan keys
 
171
 * must be satisfied to continue the scan.      It also attempts to eliminate
 
172
 * redundant keys and detect contradictory keys.  At present, redundant and
 
173
 * contradictory keys can only be detected for same-data-type comparisons,
 
174
 * but that's the usual case so it seems worth doing.
 
175
 *
 
176
 * The output keys must be sorted by index attribute.  Presently we expect
 
177
 * (but verify) that the input keys are already so sorted --- this is done
 
178
 * by group_clauses_by_indexkey() in indxpath.c.  Some reordering of the keys
 
179
 * within each attribute may be done as a byproduct of the processing here,
 
180
 * but no other code depends on that.
 
181
 *
 
182
 * Aside from preparing so->keyData[], this routine sets
 
183
 * so->numberOfRequiredKeys to the number of quals that must be satisfied to
 
184
 * continue the scan.  _bt_checkkeys uses this.  For example, if the quals
 
185
 * are "x = 1 AND y < 4 AND z < 5", then _bt_checkkeys will reject a tuple
 
186
 * (1,2,7), but we must continue the scan in case there are tuples (1,3,z).
 
187
 * But once we reach tuples like (1,4,z) we can stop scanning because no
 
188
 * later tuples could match.  This is reflected by setting
 
189
 * so->numberOfRequiredKeys to 2, the number of leading keys that must be
 
190
 * matched to continue the scan.  In general, numberOfRequiredKeys is equal
 
191
 * to the number of keys for leading attributes with "=" keys, plus the
 
192
 * key(s) for the first non "=" attribute, which can be seen to be correct
 
193
 * by considering the above example.
 
194
 *
 
195
 * If possible, redundant keys are eliminated: we keep only the tightest
 
196
 * >/>= bound and the tightest </<= bound, and if there's an = key then
 
197
 * that's the only one returned.  (So, we return either a single = key,
 
198
 * or one or two boundary-condition keys for each attr.)  However, we can
 
199
 * only detect redundant keys when the right-hand datatypes are all equal
 
200
 * to the index datatype, because we do not know suitable operators for
 
201
 * comparing right-hand values of two different datatypes.      (In theory
 
202
 * we could handle comparison of a RHS of the index datatype with a RHS of
 
203
 * another type, but that seems too much pain for too little gain.)  So,
 
204
 * keys whose operator has a nondefault subtype (ie, its RHS is not of the
 
205
 * index datatype) are ignored here, except for noting whether they impose
 
206
 * an "=" condition or not.
 
207
 *
 
208
 * As a byproduct of this work, we can detect contradictory quals such
 
209
 * as "x = 1 AND x > 2".  If we see that, we return so->quals_ok = FALSE,
 
210
 * indicating the scan need not be run at all since no tuples can match.
 
211
 * Again though, only keys with RHS datatype equal to the index datatype
 
212
 * can be checked for contradictions.
 
213
 *
 
214
 * Furthermore, we detect the case where the index is unique and we have
 
215
 * equality quals for all columns.      In this case there can be at most one
 
216
 * (visible) matching tuple.  index_getnext uses this to avoid uselessly
 
217
 * continuing the scan after finding one match.
 
218
 *----------
 
219
 */
 
220
void
 
221
_bt_preprocess_keys(IndexScanDesc scan)
 
222
{
 
223
        Relation        relation = scan->indexRelation;
 
224
        BTScanOpaque so = (BTScanOpaque) scan->opaque;
 
225
        int                     numberOfKeys = scan->numberOfKeys;
 
226
        int                     new_numberOfKeys;
 
227
        int                     numberOfEqualCols;
 
228
        ScanKey         inkeys;
 
229
        ScanKey         outkeys;
 
230
        ScanKey         cur;
 
231
        ScanKey         xform[BTMaxStrategyNumber];
 
232
        bool            hasOtherTypeEqual;
 
233
        Datum           test;
 
234
        int                     i,
 
235
                                j;
 
236
        AttrNumber      attno;
 
237
 
 
238
        /* initialize result variables */
 
239
        so->qual_ok = true;
 
240
        so->numberOfKeys = 0;
 
241
        so->numberOfRequiredKeys = 0;
 
242
        scan->keys_are_unique = false;
 
243
 
 
244
        if (numberOfKeys < 1)
 
245
                return;                                 /* done if qual-less scan */
 
246
 
 
247
        inkeys = scan->keyData;
 
248
        outkeys = so->keyData;
 
249
        cur = &inkeys[0];
 
250
        /* we check that input keys are correctly ordered */
 
251
        if (cur->sk_attno != 1)
 
252
                elog(ERROR, "key(s) for attribute 1 missed");
 
253
 
 
254
        /* We can short-circuit most of the work if there's just one key */
 
255
        if (numberOfKeys == 1)
 
256
        {
 
257
                /*
 
258
                 * We don't use indices for 'A is null' and 'A is not null'
 
259
                 * currently and 'A < = > <> NULL' will always fail - so qual is
 
260
                 * not OK if comparison value is NULL.          - vadim 03/21/97
 
261
                 */
 
262
                if (cur->sk_flags & SK_ISNULL)
 
263
                        so->qual_ok = false;
 
264
                else if (relation->rd_index->indisunique &&
 
265
                                 relation->rd_rel->relnatts == 1)
 
266
                {
 
267
                        /* it's a unique index, do we have an equality qual? */
 
268
                        if (cur->sk_strategy == BTEqualStrategyNumber)
 
269
                                scan->keys_are_unique = true;
 
270
                }
 
271
                memcpy(outkeys, inkeys, sizeof(ScanKeyData));
 
272
                so->numberOfKeys = 1;
 
273
                so->numberOfRequiredKeys = 1;
 
274
                return;
 
275
        }
 
276
 
 
277
        /*
 
278
         * Otherwise, do the full set of pushups.
 
279
         */
 
280
        new_numberOfKeys = 0;
 
281
        numberOfEqualCols = 0;
 
282
 
 
283
        /*
 
284
         * Initialize for processing of keys for attr 1.
 
285
         *
 
286
         * xform[i] points to the currently best scan key of strategy type i+1,
 
287
         * if any is found with a default operator subtype; it is NULL if we
 
288
         * haven't yet found such a key for this attr.  Scan keys of
 
289
         * nondefault subtypes are transferred to the output with no
 
290
         * processing except for noting if they are of "=" type.
 
291
         */
 
292
        attno = 1;
 
293
        memset(xform, 0, sizeof(xform));
 
294
        hasOtherTypeEqual = false;
 
295
 
 
296
        /*
 
297
         * Loop iterates from 0 to numberOfKeys inclusive; we use the last
 
298
         * pass to handle after-last-key processing.  Actual exit from the
 
299
         * loop is at the "break" statement below.
 
300
         */
 
301
        for (i = 0;; cur++, i++)
 
302
        {
 
303
                if (i < numberOfKeys)
 
304
                {
 
305
                        /* See comments above: any NULL implies cannot match qual */
 
306
                        if (cur->sk_flags & SK_ISNULL)
 
307
                        {
 
308
                                so->qual_ok = false;
 
309
 
 
310
                                /*
 
311
                                 * Quit processing so we don't try to invoke comparison
 
312
                                 * routines on NULLs.
 
313
                                 */
 
314
                                return;
 
315
                        }
 
316
                }
 
317
 
 
318
                /*
 
319
                 * If we are at the end of the keys for a particular attr, finish
 
320
                 * up processing and emit the cleaned-up keys.
 
321
                 */
 
322
                if (i == numberOfKeys || cur->sk_attno != attno)
 
323
                {
 
324
                        int                     priorNumberOfEqualCols = numberOfEqualCols;
 
325
 
 
326
                        /* check input keys are correctly ordered */
 
327
                        if (i < numberOfKeys && cur->sk_attno != attno + 1)
 
328
                                elog(ERROR, "key(s) for attribute %d missed", attno + 1);
 
329
 
 
330
                        /*
 
331
                         * If = has been specified, no other key will be used. In case
 
332
                         * of key > 2 && key == 1 and so on we have to set qual_ok to
 
333
                         * false before discarding the other keys.
 
334
                         */
 
335
                        if (xform[BTEqualStrategyNumber - 1])
 
336
                        {
 
337
                                ScanKey         eq = xform[BTEqualStrategyNumber - 1];
 
338
 
 
339
                                for (j = BTMaxStrategyNumber; --j >= 0;)
 
340
                                {
 
341
                                        ScanKey         chk = xform[j];
 
342
 
 
343
                                        if (!chk || j == (BTEqualStrategyNumber - 1))
 
344
                                                continue;
 
345
                                        test = FunctionCall2(&chk->sk_func,
 
346
                                                                                 eq->sk_argument,
 
347
                                                                                 chk->sk_argument);
 
348
                                        if (!DatumGetBool(test))
 
349
                                        {
 
350
                                                so->qual_ok = false;
 
351
                                                break;
 
352
                                        }
 
353
                                }
 
354
                                xform[BTLessStrategyNumber - 1] = NULL;
 
355
                                xform[BTLessEqualStrategyNumber - 1] = NULL;
 
356
                                xform[BTGreaterEqualStrategyNumber - 1] = NULL;
 
357
                                xform[BTGreaterStrategyNumber - 1] = NULL;
 
358
                                /* track number of attrs for which we have "=" keys */
 
359
                                numberOfEqualCols++;
 
360
                        }
 
361
                        else
 
362
                        {
 
363
                                /* track number of attrs for which we have "=" keys */
 
364
                                if (hasOtherTypeEqual)
 
365
                                        numberOfEqualCols++;
 
366
                        }
 
367
 
 
368
                        /* keep only one of <, <= */
 
369
                        if (xform[BTLessStrategyNumber - 1]
 
370
                                && xform[BTLessEqualStrategyNumber - 1])
 
371
                        {
 
372
                                ScanKey         lt = xform[BTLessStrategyNumber - 1];
 
373
                                ScanKey         le = xform[BTLessEqualStrategyNumber - 1];
 
374
 
 
375
                                test = FunctionCall2(&le->sk_func,
 
376
                                                                         lt->sk_argument,
 
377
                                                                         le->sk_argument);
 
378
                                if (DatumGetBool(test))
 
379
                                        xform[BTLessEqualStrategyNumber - 1] = NULL;
 
380
                                else
 
381
                                        xform[BTLessStrategyNumber - 1] = NULL;
 
382
                        }
 
383
 
 
384
                        /* keep only one of >, >= */
 
385
                        if (xform[BTGreaterStrategyNumber - 1]
 
386
                                && xform[BTGreaterEqualStrategyNumber - 1])
 
387
                        {
 
388
                                ScanKey         gt = xform[BTGreaterStrategyNumber - 1];
 
389
                                ScanKey         ge = xform[BTGreaterEqualStrategyNumber - 1];
 
390
 
 
391
                                test = FunctionCall2(&ge->sk_func,
 
392
                                                                         gt->sk_argument,
 
393
                                                                         ge->sk_argument);
 
394
                                if (DatumGetBool(test))
 
395
                                        xform[BTGreaterEqualStrategyNumber - 1] = NULL;
 
396
                                else
 
397
                                        xform[BTGreaterStrategyNumber - 1] = NULL;
 
398
                        }
 
399
 
 
400
                        /*
 
401
                         * Emit the cleaned-up keys into the outkeys[] array.
 
402
                         */
 
403
                        for (j = BTMaxStrategyNumber; --j >= 0;)
 
404
                        {
 
405
                                if (xform[j])
 
406
                                        memcpy(&outkeys[new_numberOfKeys++], xform[j],
 
407
                                                   sizeof(ScanKeyData));
 
408
                        }
 
409
 
 
410
                        /*
 
411
                         * If all attrs before this one had "=", include these keys
 
412
                         * into the required-keys count.
 
413
                         */
 
414
                        if (priorNumberOfEqualCols == attno - 1)
 
415
                                so->numberOfRequiredKeys = new_numberOfKeys;
 
416
 
 
417
                        /*
 
418
                         * Exit loop here if done.
 
419
                         */
 
420
                        if (i == numberOfKeys)
 
421
                                break;
 
422
 
 
423
                        /* Re-initialize for new attno */
 
424
                        attno = cur->sk_attno;
 
425
                        memset(xform, 0, sizeof(xform));
 
426
                        hasOtherTypeEqual = false;
 
427
                }
 
428
 
 
429
                /* check strategy this key's operator corresponds to */
 
430
                j = cur->sk_strategy - 1;
 
431
 
 
432
                /* if wrong RHS data type, punt */
 
433
                if (cur->sk_subtype != InvalidOid)
 
434
                {
 
435
                        memcpy(&outkeys[new_numberOfKeys++], cur,
 
436
                                   sizeof(ScanKeyData));
 
437
                        if (j == (BTEqualStrategyNumber - 1))
 
438
                                hasOtherTypeEqual = true;
 
439
                        continue;
 
440
                }
 
441
 
 
442
                /* have we seen one of these before? */
 
443
                if (xform[j])
 
444
                {
 
445
                        /* yup, keep the more restrictive key */
 
446
                        test = FunctionCall2(&cur->sk_func,
 
447
                                                                 cur->sk_argument,
 
448
                                                                 xform[j]->sk_argument);
 
449
                        if (DatumGetBool(test))
 
450
                                xform[j] = cur;
 
451
                        else if (j == (BTEqualStrategyNumber - 1))
 
452
                        {
 
453
                                /* key == a && key == b, but a != b */
 
454
                                so->qual_ok = false;
 
455
                                return;
 
456
                        }
 
457
                }
 
458
                else
 
459
                {
 
460
                        /* nope, so remember this scankey */
 
461
                        xform[j] = cur;
 
462
                }
 
463
        }
 
464
 
 
465
        so->numberOfKeys = new_numberOfKeys;
 
466
 
 
467
        /*
 
468
         * If unique index and we have equality keys for all columns, set
 
469
         * keys_are_unique flag for higher levels.
 
470
         */
 
471
        if (relation->rd_index->indisunique &&
 
472
                relation->rd_rel->relnatts == numberOfEqualCols)
 
473
                scan->keys_are_unique = true;
 
474
}
 
475
 
 
476
/*
 
477
 * Test whether an indextuple satisfies all the scankey conditions.
 
478
 *
 
479
 * If the tuple fails to pass the qual, we also determine whether there's
 
480
 * any need to continue the scan beyond this tuple, and set *continuescan
 
481
 * accordingly.  See comments for _bt_preprocess_keys(), above, about how
 
482
 * this is done.
 
483
 */
 
484
bool
 
485
_bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
 
486
                          ScanDirection dir, bool *continuescan)
 
487
{
 
488
        BTScanOpaque so = (BTScanOpaque) scan->opaque;
 
489
        int                     keysz = so->numberOfKeys;
 
490
        int                     ikey;
 
491
        TupleDesc       tupdesc;
 
492
        ScanKey         key;
 
493
 
 
494
        *continuescan = true;
 
495
 
 
496
        /* If no keys, always scan the whole index */
 
497
        if (keysz == 0)
 
498
                return true;
 
499
 
 
500
        IncrIndexProcessed();
 
501
 
 
502
        tupdesc = RelationGetDescr(scan->indexRelation);
 
503
 
 
504
        for (key = so->keyData, ikey = 0; ikey < keysz; key++, ikey++)
 
505
        {
 
506
                Datum           datum;
 
507
                bool            isNull;
 
508
                Datum           test;
 
509
 
 
510
                datum = index_getattr(tuple,
 
511
                                                          key->sk_attno,
 
512
                                                          tupdesc,
 
513
                                                          &isNull);
 
514
 
 
515
                /* btree doesn't support 'A is null' clauses, yet */
 
516
                if (key->sk_flags & SK_ISNULL)
 
517
                {
 
518
                        /* we shouldn't get here, really; see _bt_preprocess_keys() */
 
519
                        *continuescan = false;
 
520
                        return false;
 
521
                }
 
522
 
 
523
                if (isNull)
 
524
                {
 
525
                        /*
 
526
                         * Since NULLs are sorted after non-NULLs, we know we have
 
527
                         * reached the upper limit of the range of values for this
 
528
                         * index attr.  On a forward scan, we can stop if this qual is
 
529
                         * one of the "must match" subset.      On a backward scan,
 
530
                         * however, we should keep going.
 
531
                         */
 
532
                        if (ikey < so->numberOfRequiredKeys &&
 
533
                                ScanDirectionIsForward(dir))
 
534
                                *continuescan = false;
 
535
 
 
536
                        /*
 
537
                         * In any case, this indextuple doesn't match the qual.
 
538
                         */
 
539
                        return false;
 
540
                }
 
541
 
 
542
                test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
 
543
 
 
544
                if (!DatumGetBool(test))
 
545
                {
 
546
                        /*
 
547
                         * Tuple fails this qual.  If it's a required qual, then we
 
548
                         * may be able to conclude no further tuples will pass,
 
549
                         * either. We have to look at the scan direction and the qual
 
550
                         * type.
 
551
                         *
 
552
                         * Note: the only case in which we would keep going after failing
 
553
                         * a required qual is if there are partially-redundant quals
 
554
                         * that _bt_preprocess_keys() was unable to eliminate.  For
 
555
                         * example, given "x > 4 AND x > 10" where both are cross-type
 
556
                         * comparisons and so not removable, we might start the scan
 
557
                         * at the x = 4 boundary point.  The "x > 10" condition will
 
558
                         * fail until we pass x = 10, but we must not stop the scan on
 
559
                         * its account.
 
560
                         *
 
561
                         * Note: because we stop the scan as soon as any required
 
562
                         * equality qual fails, it is critical that equality quals be
 
563
                         * used for the initial positioning in _bt_first() when they
 
564
                         * are available. See comments in _bt_first().
 
565
                         */
 
566
                        if (ikey < so->numberOfRequiredKeys)
 
567
                        {
 
568
                                switch (key->sk_strategy)
 
569
                                {
 
570
                                        case BTLessStrategyNumber:
 
571
                                        case BTLessEqualStrategyNumber:
 
572
                                                if (ScanDirectionIsForward(dir))
 
573
                                                        *continuescan = false;
 
574
                                                break;
 
575
                                        case BTEqualStrategyNumber:
 
576
                                                *continuescan = false;
 
577
                                                break;
 
578
                                        case BTGreaterEqualStrategyNumber:
 
579
                                        case BTGreaterStrategyNumber:
 
580
                                                if (ScanDirectionIsBackward(dir))
 
581
                                                        *continuescan = false;
 
582
                                                break;
 
583
                                        default:
 
584
                                                elog(ERROR, "unrecognized StrategyNumber: %d",
 
585
                                                         key->sk_strategy);
 
586
                                }
 
587
                        }
 
588
 
 
589
                        /*
 
590
                         * In any case, this indextuple doesn't match the qual.
 
591
                         */
 
592
                        return false;
 
593
                }
 
594
        }
 
595
 
 
596
        /* If we get here, the tuple passes all quals. */
 
597
        return true;
 
598
}