~ubuntu-branches/ubuntu/lucid/postgresql-8.4/lucid-proposed

« back to all changes in this revision

Viewing changes to src/backend/executor/nodeIndexscan.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * nodeIndexscan.c
 
4
 *        Routines to support indexed scans of relations
 
5
 *
 
6
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL$
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
/*
 
16
 * INTERFACE ROUTINES
 
17
 *              ExecIndexScan                   scans a relation using indices
 
18
 *              ExecIndexNext                   using index to retrieve next tuple
 
19
 *              ExecInitIndexScan               creates and initializes state info.
 
20
 *              ExecIndexReScan                 rescans the indexed relation.
 
21
 *              ExecEndIndexScan                releases all storage.
 
22
 *              ExecIndexMarkPos                marks scan position.
 
23
 *              ExecIndexRestrPos               restores scan position.
 
24
 */
 
25
#include "postgres.h"
 
26
 
 
27
#include "access/genam.h"
 
28
#include "access/nbtree.h"
 
29
#include "access/relscan.h"
 
30
#include "executor/execdebug.h"
 
31
#include "executor/nodeIndexscan.h"
 
32
#include "optimizer/clauses.h"
 
33
#include "utils/array.h"
 
34
#include "utils/lsyscache.h"
 
35
#include "utils/memutils.h"
 
36
 
 
37
 
 
38
static TupleTableSlot *IndexNext(IndexScanState *node);
 
39
 
 
40
 
 
41
/* ----------------------------------------------------------------
 
42
 *              IndexNext
 
43
 *
 
44
 *              Retrieve a tuple from the IndexScan node's currentRelation
 
45
 *              using the index specified in the IndexScanState information.
 
46
 * ----------------------------------------------------------------
 
47
 */
 
48
static TupleTableSlot *
 
49
IndexNext(IndexScanState *node)
 
50
{
 
51
        EState     *estate;
 
52
        ExprContext *econtext;
 
53
        ScanDirection direction;
 
54
        IndexScanDesc scandesc;
 
55
        Index           scanrelid;
 
56
        HeapTuple       tuple;
 
57
        TupleTableSlot *slot;
 
58
 
 
59
        /*
 
60
         * extract necessary information from index scan node
 
61
         */
 
62
        estate = node->ss.ps.state;
 
63
        direction = estate->es_direction;
 
64
        /* flip direction if this is an overall backward scan */
 
65
        if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
 
66
        {
 
67
                if (ScanDirectionIsForward(direction))
 
68
                        direction = BackwardScanDirection;
 
69
                else if (ScanDirectionIsBackward(direction))
 
70
                        direction = ForwardScanDirection;
 
71
        }
 
72
        scandesc = node->iss_ScanDesc;
 
73
        econtext = node->ss.ps.ps_ExprContext;
 
74
        slot = node->ss.ss_ScanTupleSlot;
 
75
        scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
 
76
 
 
77
        /*
 
78
         * Check if we are evaluating PlanQual for tuple of this relation.
 
79
         * Additional checking is not good, but no other way for now. We could
 
80
         * introduce new nodes for this case and handle IndexScan --> NewNode
 
81
         * switching in Init/ReScan plan...
 
82
         */
 
83
        if (estate->es_evTuple != NULL &&
 
84
                estate->es_evTuple[scanrelid - 1] != NULL)
 
85
        {
 
86
                if (estate->es_evTupleNull[scanrelid - 1])
 
87
                        return ExecClearTuple(slot);
 
88
 
 
89
                ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
 
90
                                           slot, InvalidBuffer, false);
 
91
 
 
92
                /* Does the tuple meet the indexqual condition? */
 
93
                econtext->ecxt_scantuple = slot;
 
94
 
 
95
                ResetExprContext(econtext);
 
96
 
 
97
                if (!ExecQual(node->indexqualorig, econtext, false))
 
98
                        ExecClearTuple(slot);           /* would not be returned by scan */
 
99
 
 
100
                /* Flag for the next call that no more tuples */
 
101
                estate->es_evTupleNull[scanrelid - 1] = true;
 
102
 
 
103
                return slot;
 
104
        }
 
105
 
 
106
        /*
 
107
         * ok, now that we have what we need, fetch the next tuple.
 
108
         */
 
109
        while ((tuple = index_getnext(scandesc, direction)) != NULL)
 
110
        {
 
111
                /*
 
112
                 * Store the scanned tuple in the scan tuple slot of the scan state.
 
113
                 * Note: we pass 'false' because tuples returned by amgetnext are
 
114
                 * pointers onto disk pages and must not be pfree()'d.
 
115
                 */
 
116
                ExecStoreTuple(tuple,   /* tuple to store */
 
117
                                           slot,        /* slot to store in */
 
118
                                           scandesc->xs_cbuf,           /* buffer containing tuple */
 
119
                                           false);      /* don't pfree */
 
120
 
 
121
                /*
 
122
                 * If the index was lossy, we have to recheck the index quals using
 
123
                 * the real tuple.
 
124
                 */
 
125
                if (scandesc->xs_recheck)
 
126
                {
 
127
                        econtext->ecxt_scantuple = slot;
 
128
                        ResetExprContext(econtext);
 
129
                        if (!ExecQual(node->indexqualorig, econtext, false))
 
130
                                continue;               /* nope, so ask index for another one */
 
131
                }
 
132
 
 
133
                return slot;
 
134
        }
 
135
 
 
136
        /*
 
137
         * if we get here it means the index scan failed so we are at the end of
 
138
         * the scan..
 
139
         */
 
140
        return ExecClearTuple(slot);
 
141
}
 
142
 
 
143
/* ----------------------------------------------------------------
 
144
 *              ExecIndexScan(node)
 
145
 * ----------------------------------------------------------------
 
146
 */
 
147
TupleTableSlot *
 
148
ExecIndexScan(IndexScanState *node)
 
149
{
 
150
        /*
 
151
         * If we have runtime keys and they've not already been set up, do it now.
 
152
         */
 
153
        if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
 
154
                ExecReScan((PlanState *) node, NULL);
 
155
 
 
156
        /*
 
157
         * use IndexNext as access method
 
158
         */
 
159
        return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
 
160
}
 
161
 
 
162
/* ----------------------------------------------------------------
 
163
 *              ExecIndexReScan(node)
 
164
 *
 
165
 *              Recalculates the value of the scan keys whose value depends on
 
166
 *              information known at runtime and rescans the indexed relation.
 
167
 *              Updating the scan key was formerly done separately in
 
168
 *              ExecUpdateIndexScanKeys. Integrating it into ReScan makes
 
169
 *              rescans of indices and relations/general streams more uniform.
 
170
 * ----------------------------------------------------------------
 
171
 */
 
172
void
 
173
ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
 
174
{
 
175
        EState     *estate;
 
176
        ExprContext *econtext;
 
177
        Index           scanrelid;
 
178
 
 
179
        estate = node->ss.ps.state;
 
180
        econtext = node->iss_RuntimeContext;            /* context for runtime keys */
 
181
        scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
 
182
 
 
183
        node->ss.ps.ps_TupFromTlist = false;
 
184
 
 
185
        if (econtext)
 
186
        {
 
187
                /*
 
188
                 * If we are being passed an outer tuple, save it for runtime key
 
189
                 * calc.  We also need to link it into the "regular" per-tuple
 
190
                 * econtext, so it can be used during indexqualorig evaluations.
 
191
                 */
 
192
                if (exprCtxt != NULL)
 
193
                {
 
194
                        ExprContext *stdecontext;
 
195
 
 
196
                        econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
 
197
                        stdecontext = node->ss.ps.ps_ExprContext;
 
198
                        stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
 
199
                }
 
200
 
 
201
                /*
 
202
                 * Reset the runtime-key context so we don't leak memory as each outer
 
203
                 * tuple is scanned.  Note this assumes that we will recalculate *all*
 
204
                 * runtime keys on each call.
 
205
                 */
 
206
                ResetExprContext(econtext);
 
207
        }
 
208
 
 
209
        /*
 
210
         * If we are doing runtime key calculations (ie, the index keys depend on
 
211
         * data from an outer scan), compute the new key values
 
212
         */
 
213
        if (node->iss_NumRuntimeKeys != 0)
 
214
                ExecIndexEvalRuntimeKeys(econtext,
 
215
                                                                 node->iss_RuntimeKeys,
 
216
                                                                 node->iss_NumRuntimeKeys);
 
217
        node->iss_RuntimeKeysReady = true;
 
218
 
 
219
        /* If this is re-scanning of PlanQual ... */
 
220
        if (estate->es_evTuple != NULL &&
 
221
                estate->es_evTuple[scanrelid - 1] != NULL)
 
222
        {
 
223
                estate->es_evTupleNull[scanrelid - 1] = false;
 
224
                return;
 
225
        }
 
226
 
 
227
        /* reset index scan */
 
228
        index_rescan(node->iss_ScanDesc, node->iss_ScanKeys);
 
229
}
 
230
 
 
231
 
 
232
/*
 
233
 * ExecIndexEvalRuntimeKeys
 
234
 *              Evaluate any runtime key values, and update the scankeys.
 
235
 */
 
236
void
 
237
ExecIndexEvalRuntimeKeys(ExprContext *econtext,
 
238
                                                 IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
 
239
{
 
240
        int                     j;
 
241
 
 
242
        for (j = 0; j < numRuntimeKeys; j++)
 
243
        {
 
244
                ScanKey         scan_key = runtimeKeys[j].scan_key;
 
245
                ExprState  *key_expr = runtimeKeys[j].key_expr;
 
246
                Datum           scanvalue;
 
247
                bool            isNull;
 
248
 
 
249
                /*
 
250
                 * For each run-time key, extract the run-time expression and evaluate
 
251
                 * it with respect to the current outer tuple.  We then stick the
 
252
                 * result into the proper scan key.
 
253
                 *
 
254
                 * Note: the result of the eval could be a pass-by-ref value that's
 
255
                 * stored in the outer scan's tuple, not in
 
256
                 * econtext->ecxt_per_tuple_memory.  We assume that the outer tuple
 
257
                 * will stay put throughout our scan.  If this is wrong, we could copy
 
258
                 * the result into our context explicitly, but I think that's not
 
259
                 * necessary...
 
260
                 */
 
261
                scanvalue = ExecEvalExprSwitchContext(key_expr,
 
262
                                                                                          econtext,
 
263
                                                                                          &isNull,
 
264
                                                                                          NULL);
 
265
                scan_key->sk_argument = scanvalue;
 
266
                if (isNull)
 
267
                        scan_key->sk_flags |= SK_ISNULL;
 
268
                else
 
269
                        scan_key->sk_flags &= ~SK_ISNULL;
 
270
        }
 
271
}
 
272
 
 
273
/*
 
274
 * ExecIndexEvalArrayKeys
 
275
 *              Evaluate any array key values, and set up to iterate through arrays.
 
276
 *
 
277
 * Returns TRUE if there are array elements to consider; FALSE means there
 
278
 * is at least one null or empty array, so no match is possible.  On TRUE
 
279
 * result, the scankeys are initialized with the first elements of the arrays.
 
280
 */
 
281
bool
 
282
ExecIndexEvalArrayKeys(ExprContext *econtext,
 
283
                                           IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
284
{
 
285
        bool            result = true;
 
286
        int                     j;
 
287
        MemoryContext oldContext;
 
288
 
 
289
        /* We want to keep the arrays in per-tuple memory */
 
290
        oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
291
 
 
292
        for (j = 0; j < numArrayKeys; j++)
 
293
        {
 
294
                ScanKey         scan_key = arrayKeys[j].scan_key;
 
295
                ExprState  *array_expr = arrayKeys[j].array_expr;
 
296
                Datum           arraydatum;
 
297
                bool            isNull;
 
298
                ArrayType  *arrayval;
 
299
                int16           elmlen;
 
300
                bool            elmbyval;
 
301
                char            elmalign;
 
302
                int                     num_elems;
 
303
                Datum      *elem_values;
 
304
                bool       *elem_nulls;
 
305
 
 
306
                /*
 
307
                 * Compute and deconstruct the array expression. (Notes in
 
308
                 * ExecIndexEvalRuntimeKeys() apply here too.)
 
309
                 */
 
310
                arraydatum = ExecEvalExpr(array_expr,
 
311
                                                                  econtext,
 
312
                                                                  &isNull,
 
313
                                                                  NULL);
 
314
                if (isNull)
 
315
                {
 
316
                        result = false;
 
317
                        break;                          /* no point in evaluating more */
 
318
                }
 
319
                arrayval = DatumGetArrayTypeP(arraydatum);
 
320
                /* We could cache this data, but not clear it's worth it */
 
321
                get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
 
322
                                                         &elmlen, &elmbyval, &elmalign);
 
323
                deconstruct_array(arrayval,
 
324
                                                  ARR_ELEMTYPE(arrayval),
 
325
                                                  elmlen, elmbyval, elmalign,
 
326
                                                  &elem_values, &elem_nulls, &num_elems);
 
327
                if (num_elems <= 0)
 
328
                {
 
329
                        result = false;
 
330
                        break;                          /* no point in evaluating more */
 
331
                }
 
332
 
 
333
                /*
 
334
                 * Note: we expect the previous array data, if any, to be
 
335
                 * automatically freed by resetting the per-tuple context; hence no
 
336
                 * pfree's here.
 
337
                 */
 
338
                arrayKeys[j].elem_values = elem_values;
 
339
                arrayKeys[j].elem_nulls = elem_nulls;
 
340
                arrayKeys[j].num_elems = num_elems;
 
341
                scan_key->sk_argument = elem_values[0];
 
342
                if (elem_nulls[0])
 
343
                        scan_key->sk_flags |= SK_ISNULL;
 
344
                else
 
345
                        scan_key->sk_flags &= ~SK_ISNULL;
 
346
                arrayKeys[j].next_elem = 1;
 
347
        }
 
348
 
 
349
        MemoryContextSwitchTo(oldContext);
 
350
 
 
351
        return result;
 
352
}
 
353
 
 
354
/*
 
355
 * ExecIndexAdvanceArrayKeys
 
356
 *              Advance to the next set of array key values, if any.
 
357
 *
 
358
 * Returns TRUE if there is another set of values to consider, FALSE if not.
 
359
 * On TRUE result, the scankeys are initialized with the next set of values.
 
360
 */
 
361
bool
 
362
ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
 
363
{
 
364
        bool            found = false;
 
365
        int                     j;
 
366
 
 
367
        /*
 
368
         * Note we advance the rightmost array key most quickly, since it will
 
369
         * correspond to the lowest-order index column among the available
 
370
         * qualifications.  This is hypothesized to result in better locality
 
371
         * of access in the index.
 
372
         */
 
373
        for (j = numArrayKeys - 1; j >= 0; j--)
 
374
        {
 
375
                ScanKey         scan_key = arrayKeys[j].scan_key;
 
376
                int                     next_elem = arrayKeys[j].next_elem;
 
377
                int                     num_elems = arrayKeys[j].num_elems;
 
378
                Datum      *elem_values = arrayKeys[j].elem_values;
 
379
                bool       *elem_nulls = arrayKeys[j].elem_nulls;
 
380
 
 
381
                if (next_elem >= num_elems)
 
382
                {
 
383
                        next_elem = 0;
 
384
                        found = false;          /* need to advance next array key */
 
385
                }
 
386
                else
 
387
                        found = true;
 
388
                scan_key->sk_argument = elem_values[next_elem];
 
389
                if (elem_nulls[next_elem])
 
390
                        scan_key->sk_flags |= SK_ISNULL;
 
391
                else
 
392
                        scan_key->sk_flags &= ~SK_ISNULL;
 
393
                arrayKeys[j].next_elem = next_elem + 1;
 
394
                if (found)
 
395
                        break;
 
396
        }
 
397
 
 
398
        return found;
 
399
}
 
400
 
 
401
 
 
402
/* ----------------------------------------------------------------
 
403
 *              ExecEndIndexScan
 
404
 * ----------------------------------------------------------------
 
405
 */
 
406
void
 
407
ExecEndIndexScan(IndexScanState *node)
 
408
{
 
409
        Relation        indexRelationDesc;
 
410
        IndexScanDesc indexScanDesc;
 
411
        Relation        relation;
 
412
 
 
413
        /*
 
414
         * extract information from the node
 
415
         */
 
416
        indexRelationDesc = node->iss_RelationDesc;
 
417
        indexScanDesc = node->iss_ScanDesc;
 
418
        relation = node->ss.ss_currentRelation;
 
419
 
 
420
        /*
 
421
         * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
 
422
         */
 
423
#ifdef NOT_USED
 
424
        ExecFreeExprContext(&node->ss.ps);
 
425
        if (node->iss_RuntimeContext)
 
426
                FreeExprContext(node->iss_RuntimeContext);
 
427
#endif
 
428
 
 
429
        /*
 
430
         * clear out tuple table slots
 
431
         */
 
432
        ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
433
        ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
434
 
 
435
        /*
 
436
         * close the index relation (no-op if we didn't open it)
 
437
         */
 
438
        if (indexScanDesc)
 
439
                index_endscan(indexScanDesc);
 
440
        if (indexRelationDesc)
 
441
                index_close(indexRelationDesc, NoLock);
 
442
 
 
443
        /*
 
444
         * close the heap relation.
 
445
         */
 
446
        ExecCloseScanRelation(relation);
 
447
}
 
448
 
 
449
/* ----------------------------------------------------------------
 
450
 *              ExecIndexMarkPos
 
451
 * ----------------------------------------------------------------
 
452
 */
 
453
void
 
454
ExecIndexMarkPos(IndexScanState *node)
 
455
{
 
456
        index_markpos(node->iss_ScanDesc);
 
457
}
 
458
 
 
459
/* ----------------------------------------------------------------
 
460
 *              ExecIndexRestrPos
 
461
 * ----------------------------------------------------------------
 
462
 */
 
463
void
 
464
ExecIndexRestrPos(IndexScanState *node)
 
465
{
 
466
        index_restrpos(node->iss_ScanDesc);
 
467
}
 
468
 
 
469
/* ----------------------------------------------------------------
 
470
 *              ExecInitIndexScan
 
471
 *
 
472
 *              Initializes the index scan's state information, creates
 
473
 *              scan keys, and opens the base and index relations.
 
474
 *
 
475
 *              Note: index scans have 2 sets of state information because
 
476
 *                        we have to keep track of the base relation and the
 
477
 *                        index relation.
 
478
 * ----------------------------------------------------------------
 
479
 */
 
480
IndexScanState *
 
481
ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 
482
{
 
483
        IndexScanState *indexstate;
 
484
        Relation        currentRelation;
 
485
        bool            relistarget;
 
486
 
 
487
        /*
 
488
         * create state structure
 
489
         */
 
490
        indexstate = makeNode(IndexScanState);
 
491
        indexstate->ss.ps.plan = (Plan *) node;
 
492
        indexstate->ss.ps.state = estate;
 
493
 
 
494
        /*
 
495
         * Miscellaneous initialization
 
496
         *
 
497
         * create expression context for node
 
498
         */
 
499
        ExecAssignExprContext(estate, &indexstate->ss.ps);
 
500
 
 
501
        indexstate->ss.ps.ps_TupFromTlist = false;
 
502
 
 
503
        /*
 
504
         * initialize child expressions
 
505
         *
 
506
         * Note: we don't initialize all of the indexqual expression, only the
 
507
         * sub-parts corresponding to runtime keys (see below).  The indexqualorig
 
508
         * expression is always initialized even though it will only be used in
 
509
         * some uncommon cases --- would be nice to improve that.  (Problem is
 
510
         * that any SubPlans present in the expression must be found now...)
 
511
         */
 
512
        indexstate->ss.ps.targetlist = (List *)
 
513
                ExecInitExpr((Expr *) node->scan.plan.targetlist,
 
514
                                         (PlanState *) indexstate);
 
515
        indexstate->ss.ps.qual = (List *)
 
516
                ExecInitExpr((Expr *) node->scan.plan.qual,
 
517
                                         (PlanState *) indexstate);
 
518
        indexstate->indexqualorig = (List *)
 
519
                ExecInitExpr((Expr *) node->indexqualorig,
 
520
                                         (PlanState *) indexstate);
 
521
 
 
522
#define INDEXSCAN_NSLOTS 2
 
523
 
 
524
        /*
 
525
         * tuple table initialization
 
526
         */
 
527
        ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
 
528
        ExecInitScanTupleSlot(estate, &indexstate->ss);
 
529
 
 
530
        /*
 
531
         * open the base relation and acquire appropriate lock on it.
 
532
         */
 
533
        currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
 
534
 
 
535
        indexstate->ss.ss_currentRelation = currentRelation;
 
536
        indexstate->ss.ss_currentScanDesc = NULL;       /* no heap scan here */
 
537
 
 
538
        /*
 
539
         * get the scan type from the relation descriptor.
 
540
         */
 
541
        ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
 
542
 
 
543
        /*
 
544
         * Initialize result tuple type and projection info.
 
545
         */
 
546
        ExecAssignResultTypeFromTL(&indexstate->ss.ps);
 
547
        ExecAssignScanProjectionInfo(&indexstate->ss);
 
548
 
 
549
        /*
 
550
         * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
 
551
         * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
 
552
         * references to nonexistent indexes.
 
553
         */
 
554
        if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
 
555
                return indexstate;
 
556
 
 
557
        /*
 
558
         * Open the index relation.
 
559
         *
 
560
         * If the parent table is one of the target relations of the query, then
 
561
         * InitPlan already opened and write-locked the index, so we can avoid
 
562
         * taking another lock here.  Otherwise we need a normal reader's lock.
 
563
         */
 
564
        relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
 
565
        indexstate->iss_RelationDesc = index_open(node->indexid,
 
566
                                                                         relistarget ? NoLock : AccessShareLock);
 
567
 
 
568
        /*
 
569
         * Initialize index-specific scan state
 
570
         */
 
571
        indexstate->iss_RuntimeKeysReady = false;
 
572
 
 
573
        /*
 
574
         * build the index scan keys from the index qualification
 
575
         */
 
576
        ExecIndexBuildScanKeys((PlanState *) indexstate,
 
577
                                                   indexstate->iss_RelationDesc,
 
578
                                                   node->scan.scanrelid,
 
579
                                                   node->indexqual,
 
580
                                                   &indexstate->iss_ScanKeys,
 
581
                                                   &indexstate->iss_NumScanKeys,
 
582
                                                   &indexstate->iss_RuntimeKeys,
 
583
                                                   &indexstate->iss_NumRuntimeKeys,
 
584
                                                   NULL,        /* no ArrayKeys */
 
585
                                                   NULL);
 
586
 
 
587
        /*
 
588
         * If we have runtime keys, we need an ExprContext to evaluate them. The
 
589
         * node's standard context won't do because we want to reset that context
 
590
         * for every tuple.  So, build another context just like the other one...
 
591
         * -tgl 7/11/00
 
592
         */
 
593
        if (indexstate->iss_NumRuntimeKeys != 0)
 
594
        {
 
595
                ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
 
596
 
 
597
                ExecAssignExprContext(estate, &indexstate->ss.ps);
 
598
                indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
 
599
                indexstate->ss.ps.ps_ExprContext = stdecontext;
 
600
        }
 
601
        else
 
602
        {
 
603
                indexstate->iss_RuntimeContext = NULL;
 
604
        }
 
605
 
 
606
        /*
 
607
         * Initialize scan descriptor.
 
608
         */
 
609
        indexstate->iss_ScanDesc = index_beginscan(currentRelation,
 
610
                                                                                           indexstate->iss_RelationDesc,
 
611
                                                                                           estate->es_snapshot,
 
612
                                                                                           indexstate->iss_NumScanKeys,
 
613
                                                                                           indexstate->iss_ScanKeys);
 
614
 
 
615
        /*
 
616
         * all done.
 
617
         */
 
618
        return indexstate;
 
619
}
 
620
 
 
621
 
 
622
/*
 
623
 * ExecIndexBuildScanKeys
 
624
 *              Build the index scan keys from the index qualification expressions
 
625
 *
 
626
 * The index quals are passed to the index AM in the form of a ScanKey array.
 
627
 * This routine sets up the ScanKeys, fills in all constant fields of the
 
628
 * ScanKeys, and prepares information about the keys that have non-constant
 
629
 * comparison values.  We divide index qual expressions into five types:
 
630
 *
 
631
 * 1. Simple operator with constant comparison value ("indexkey op constant").
 
632
 * For these, we just fill in a ScanKey containing the constant value.
 
633
 *
 
634
 * 2. Simple operator with non-constant value ("indexkey op expression").
 
635
 * For these, we create a ScanKey with everything filled in except the
 
636
 * expression value, and set up an IndexRuntimeKeyInfo struct to drive
 
637
 * evaluation of the expression at the right times.
 
638
 *
 
639
 * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
 
640
 * For these, we create a header ScanKey plus a subsidiary ScanKey array,
 
641
 * as specified in access/skey.h.  The elements of the row comparison
 
642
 * can have either constant or non-constant comparison values.
 
643
 *
 
644
 * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)").  For these,
 
645
 * we create a ScanKey with everything filled in except the comparison value,
 
646
 * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
 
647
 * (Note that we treat all array-expressions as requiring runtime evaluation,
 
648
 * even if they happen to be constants.)
 
649
 *
 
650
 * 5. NullTest ("indexkey IS NULL").  We just fill in the ScanKey properly.
 
651
 *
 
652
 * Input params are:
 
653
 *
 
654
 * planstate: executor state node we are working for
 
655
 * index: the index we are building scan keys for
 
656
 * scanrelid: varno of the index's relation within current query
 
657
 * quals: indexquals expressions
 
658
 *
 
659
 * Output params are:
 
660
 *
 
661
 * *scanKeys: receives ptr to array of ScanKeys
 
662
 * *numScanKeys: receives number of scankeys
 
663
 * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
 
664
 * *numRuntimeKeys: receives number of runtime keys
 
665
 * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
 
666
 * *numArrayKeys: receives number of array keys
 
667
 *
 
668
 * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
 
669
 * ScalarArrayOpExpr quals are not supported.
 
670
 */
 
671
void
 
672
ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
 
673
                                           List *quals, ScanKey *scanKeys, int *numScanKeys,
 
674
                                           IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
 
675
                                           IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
 
676
{
 
677
        ListCell   *qual_cell;
 
678
        ScanKey         scan_keys;
 
679
        IndexRuntimeKeyInfo *runtime_keys;
 
680
        IndexArrayKeyInfo *array_keys;
 
681
        int                     n_scan_keys;
 
682
        int                     extra_scan_keys;
 
683
        int                     n_runtime_keys;
 
684
        int                     n_array_keys;
 
685
        int                     j;
 
686
 
 
687
        /*
 
688
         * If there are any RowCompareExpr quals, we need extra ScanKey entries
 
689
         * for them, and possibly extra runtime-key entries.  Count up what's
 
690
         * needed.      (The subsidiary ScanKey arrays for the RowCompareExprs could
 
691
         * be allocated as separate chunks, but we have to count anyway to make
 
692
         * runtime_keys large enough, so might as well just do one palloc.)
 
693
         */
 
694
        n_scan_keys = list_length(quals);
 
695
        extra_scan_keys = 0;
 
696
        foreach(qual_cell, quals)
 
697
        {
 
698
                if (IsA(lfirst(qual_cell), RowCompareExpr))
 
699
                        extra_scan_keys +=
 
700
                                list_length(((RowCompareExpr *) lfirst(qual_cell))->opnos);
 
701
        }
 
702
        scan_keys = (ScanKey)
 
703
                palloc((n_scan_keys + extra_scan_keys) * sizeof(ScanKeyData));
 
704
        /* Allocate these arrays as large as they could possibly need to be */
 
705
        runtime_keys = (IndexRuntimeKeyInfo *)
 
706
                palloc((n_scan_keys + extra_scan_keys) * sizeof(IndexRuntimeKeyInfo));
 
707
        array_keys = (IndexArrayKeyInfo *)
 
708
                palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
 
709
        n_runtime_keys = 0;
 
710
        n_array_keys = 0;
 
711
 
 
712
        /*
 
713
         * Below here, extra_scan_keys is index of first cell to use for next
 
714
         * RowCompareExpr
 
715
         */
 
716
        extra_scan_keys = n_scan_keys;
 
717
 
 
718
        /*
 
719
         * for each opclause in the given qual, convert the opclause into
 
720
         * a single scan key
 
721
         */
 
722
        j = 0;
 
723
        foreach(qual_cell, quals)
 
724
        {
 
725
                Expr       *clause = (Expr *) lfirst(qual_cell);
 
726
                ScanKey         this_scan_key = &scan_keys[j++];
 
727
                Oid                     opno;           /* operator's OID */
 
728
                RegProcedure opfuncid;  /* operator proc id used in scan */
 
729
                Oid                     opfamily;       /* opfamily of index column */
 
730
                int                     op_strategy; /* operator's strategy number */
 
731
                Oid                     op_lefttype; /* operator's declared input types */
 
732
                Oid                     op_righttype;
 
733
                Expr       *leftop;             /* expr on lhs of operator */
 
734
                Expr       *rightop;    /* expr on rhs ... */
 
735
                AttrNumber      varattno;       /* att number used in scan */
 
736
 
 
737
                if (IsA(clause, OpExpr))
 
738
                {
 
739
                        /* indexkey op const or indexkey op expression */
 
740
                        int                     flags = 0;
 
741
                        Datum           scanvalue;
 
742
 
 
743
                        opno = ((OpExpr *) clause)->opno;
 
744
                        opfuncid = ((OpExpr *) clause)->opfuncid;
 
745
 
 
746
                        /*
 
747
                         * leftop should be the index key Var, possibly relabeled
 
748
                         */
 
749
                        leftop = (Expr *) get_leftop(clause);
 
750
 
 
751
                        if (leftop && IsA(leftop, RelabelType))
 
752
                                leftop = ((RelabelType *) leftop)->arg;
 
753
 
 
754
                        Assert(leftop != NULL);
 
755
 
 
756
                        if (!(IsA(leftop, Var) &&
 
757
                                  ((Var *) leftop)->varno == scanrelid))
 
758
                                elog(ERROR, "indexqual doesn't have key on left side");
 
759
 
 
760
                        varattno = ((Var *) leftop)->varattno;
 
761
                        if (varattno < 1 || varattno > index->rd_index->indnatts)
 
762
                                elog(ERROR, "bogus index qualification");
 
763
 
 
764
                        /*
 
765
                         * We have to look up the operator's strategy number.  This
 
766
                         * provides a cross-check that the operator does match the index.
 
767
                         */
 
768
                        opfamily = index->rd_opfamily[varattno - 1];
 
769
 
 
770
                        get_op_opfamily_properties(opno, opfamily,
 
771
                                                                           &op_strategy,
 
772
                                                                           &op_lefttype,
 
773
                                                                           &op_righttype);
 
774
 
 
775
                        /*
 
776
                         * rightop is the constant or variable comparison value
 
777
                         */
 
778
                        rightop = (Expr *) get_rightop(clause);
 
779
 
 
780
                        if (rightop && IsA(rightop, RelabelType))
 
781
                                rightop = ((RelabelType *) rightop)->arg;
 
782
 
 
783
                        Assert(rightop != NULL);
 
784
 
 
785
                        if (IsA(rightop, Const))
 
786
                        {
 
787
                                /* OK, simple constant comparison value */
 
788
                                scanvalue = ((Const *) rightop)->constvalue;
 
789
                                if (((Const *) rightop)->constisnull)
 
790
                                        flags |= SK_ISNULL;
 
791
                        }
 
792
                        else
 
793
                        {
 
794
                                /* Need to treat this one as a runtime key */
 
795
                                runtime_keys[n_runtime_keys].scan_key = this_scan_key;
 
796
                                runtime_keys[n_runtime_keys].key_expr =
 
797
                                        ExecInitExpr(rightop, planstate);
 
798
                                n_runtime_keys++;
 
799
                                scanvalue = (Datum) 0;
 
800
                        }
 
801
 
 
802
                        /*
 
803
                         * initialize the scan key's fields appropriately
 
804
                         */
 
805
                        ScanKeyEntryInitialize(this_scan_key,
 
806
                                                                   flags,
 
807
                                                                   varattno,    /* attribute number to scan */
 
808
                                                                   op_strategy, /* op's strategy */
 
809
                                                                   op_righttype, /* strategy subtype */
 
810
                                                                   opfuncid,    /* reg proc to use */
 
811
                                                                   scanvalue);  /* constant */
 
812
                }
 
813
                else if (IsA(clause, RowCompareExpr))
 
814
                {
 
815
                        /* (indexkey, indexkey, ...) op (expression, expression, ...) */
 
816
                        RowCompareExpr *rc = (RowCompareExpr *) clause;
 
817
                        ListCell   *largs_cell = list_head(rc->largs);
 
818
                        ListCell   *rargs_cell = list_head(rc->rargs);
 
819
                        ListCell   *opnos_cell = list_head(rc->opnos);
 
820
                        ScanKey         first_sub_key = &scan_keys[extra_scan_keys];
 
821
 
 
822
                        /* Scan RowCompare columns and generate subsidiary ScanKey items */
 
823
                        while (opnos_cell != NULL)
 
824
                        {
 
825
                                ScanKey         this_sub_key = &scan_keys[extra_scan_keys];
 
826
                                int                     flags = SK_ROW_MEMBER;
 
827
                                Datum           scanvalue;
 
828
 
 
829
                                /*
 
830
                                 * leftop should be the index key Var, possibly relabeled
 
831
                                 */
 
832
                                leftop = (Expr *) lfirst(largs_cell);
 
833
                                largs_cell = lnext(largs_cell);
 
834
 
 
835
                                if (leftop && IsA(leftop, RelabelType))
 
836
                                        leftop = ((RelabelType *) leftop)->arg;
 
837
 
 
838
                                Assert(leftop != NULL);
 
839
 
 
840
                                if (!(IsA(leftop, Var) &&
 
841
                                          ((Var *) leftop)->varno == scanrelid))
 
842
                                        elog(ERROR, "indexqual doesn't have key on left side");
 
843
 
 
844
                                varattno = ((Var *) leftop)->varattno;
 
845
 
 
846
                                /*
 
847
                                 * rightop is the constant or variable comparison value
 
848
                                 */
 
849
                                rightop = (Expr *) lfirst(rargs_cell);
 
850
                                rargs_cell = lnext(rargs_cell);
 
851
 
 
852
                                if (rightop && IsA(rightop, RelabelType))
 
853
                                        rightop = ((RelabelType *) rightop)->arg;
 
854
 
 
855
                                Assert(rightop != NULL);
 
856
 
 
857
                                if (IsA(rightop, Const))
 
858
                                {
 
859
                                        /* OK, simple constant comparison value */
 
860
                                        scanvalue = ((Const *) rightop)->constvalue;
 
861
                                        if (((Const *) rightop)->constisnull)
 
862
                                                flags |= SK_ISNULL;
 
863
                                }
 
864
                                else
 
865
                                {
 
866
                                        /* Need to treat this one as a runtime key */
 
867
                                        runtime_keys[n_runtime_keys].scan_key = this_sub_key;
 
868
                                        runtime_keys[n_runtime_keys].key_expr =
 
869
                                                ExecInitExpr(rightop, planstate);
 
870
                                        n_runtime_keys++;
 
871
                                        scanvalue = (Datum) 0;
 
872
                                }
 
873
 
 
874
                                /*
 
875
                                 * We have to look up the operator's associated btree support
 
876
                                 * function
 
877
                                 */
 
878
                                opno = lfirst_oid(opnos_cell);
 
879
                                opnos_cell = lnext(opnos_cell);
 
880
 
 
881
                                if (index->rd_rel->relam != BTREE_AM_OID ||
 
882
                                        varattno < 1 || varattno > index->rd_index->indnatts)
 
883
                                        elog(ERROR, "bogus RowCompare index qualification");
 
884
                                opfamily = index->rd_opfamily[varattno - 1];
 
885
 
 
886
                                get_op_opfamily_properties(opno, opfamily,
 
887
                                                                                   &op_strategy,
 
888
                                                                                   &op_lefttype,
 
889
                                                                                   &op_righttype);
 
890
 
 
891
                                if (op_strategy != rc->rctype)
 
892
                                        elog(ERROR, "RowCompare index qualification contains wrong operator");
 
893
 
 
894
                                opfuncid = get_opfamily_proc(opfamily,
 
895
                                                                                         op_lefttype,
 
896
                                                                                         op_righttype,
 
897
                                                                                         BTORDER_PROC);
 
898
 
 
899
                                /*
 
900
                                 * initialize the subsidiary scan key's fields appropriately
 
901
                                 */
 
902
                                ScanKeyEntryInitialize(this_sub_key,
 
903
                                                                           flags,
 
904
                                                                           varattno,            /* attribute number */
 
905
                                                                           op_strategy,         /* op's strategy */
 
906
                                                                           op_righttype,        /* strategy subtype */
 
907
                                                                           opfuncid,            /* reg proc to use */
 
908
                                                                           scanvalue);          /* constant */
 
909
                                extra_scan_keys++;
 
910
                        }
 
911
 
 
912
                        /* Mark the last subsidiary scankey correctly */
 
913
                        scan_keys[extra_scan_keys - 1].sk_flags |= SK_ROW_END;
 
914
 
 
915
                        /*
 
916
                         * We don't use ScanKeyEntryInitialize for the header because it
 
917
                         * isn't going to contain a valid sk_func pointer.
 
918
                         */
 
919
                        MemSet(this_scan_key, 0, sizeof(ScanKeyData));
 
920
                        this_scan_key->sk_flags = SK_ROW_HEADER;
 
921
                        this_scan_key->sk_attno = first_sub_key->sk_attno;
 
922
                        this_scan_key->sk_strategy = rc->rctype;
 
923
                        /* sk_subtype, sk_func not used in a header */
 
924
                        this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
 
925
                }
 
926
                else if (IsA(clause, ScalarArrayOpExpr))
 
927
                {
 
928
                        /* indexkey op ANY (array-expression) */
 
929
                        ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
 
930
 
 
931
                        Assert(saop->useOr);
 
932
                        opno = saop->opno;
 
933
                        opfuncid = saop->opfuncid;
 
934
 
 
935
                        /*
 
936
                         * leftop should be the index key Var, possibly relabeled
 
937
                         */
 
938
                        leftop = (Expr *) linitial(saop->args);
 
939
 
 
940
                        if (leftop && IsA(leftop, RelabelType))
 
941
                                leftop = ((RelabelType *) leftop)->arg;
 
942
 
 
943
                        Assert(leftop != NULL);
 
944
 
 
945
                        if (!(IsA(leftop, Var) &&
 
946
                                  ((Var *) leftop)->varno == scanrelid))
 
947
                                elog(ERROR, "indexqual doesn't have key on left side");
 
948
 
 
949
                        varattno = ((Var *) leftop)->varattno;
 
950
                        if (varattno < 1 || varattno > index->rd_index->indnatts)
 
951
                                elog(ERROR, "bogus index qualification");
 
952
 
 
953
                        /*
 
954
                         * We have to look up the operator's strategy number.  This
 
955
                         * provides a cross-check that the operator does match the index.
 
956
                         */
 
957
                        opfamily = index->rd_opfamily[varattno - 1];
 
958
 
 
959
                        get_op_opfamily_properties(opno, opfamily,
 
960
                                                                           &op_strategy,
 
961
                                                                           &op_lefttype,
 
962
                                                                           &op_righttype);
 
963
 
 
964
                        /*
 
965
                         * rightop is the constant or variable array value
 
966
                         */
 
967
                        rightop = (Expr *) lsecond(saop->args);
 
968
 
 
969
                        if (rightop && IsA(rightop, RelabelType))
 
970
                                rightop = ((RelabelType *) rightop)->arg;
 
971
 
 
972
                        Assert(rightop != NULL);
 
973
 
 
974
                        array_keys[n_array_keys].scan_key = this_scan_key;
 
975
                        array_keys[n_array_keys].array_expr =
 
976
                                ExecInitExpr(rightop, planstate);
 
977
                        /* the remaining fields were zeroed by palloc0 */
 
978
                        n_array_keys++;
 
979
 
 
980
                        /*
 
981
                         * initialize the scan key's fields appropriately
 
982
                         */
 
983
                        ScanKeyEntryInitialize(this_scan_key,
 
984
                                                                   0,   /* flags */
 
985
                                                                   varattno,    /* attribute number to scan */
 
986
                                                                   op_strategy, /* op's strategy */
 
987
                                                                   op_righttype, /* strategy subtype */
 
988
                                                                   opfuncid,    /* reg proc to use */
 
989
                                                                   (Datum) 0);  /* constant */
 
990
                }
 
991
                else if (IsA(clause, NullTest))
 
992
                {
 
993
                        /* indexkey IS NULL */
 
994
                        Assert(((NullTest *) clause)->nulltesttype == IS_NULL);
 
995
 
 
996
                        /*
 
997
                         * argument should be the index key Var, possibly relabeled
 
998
                         */
 
999
                        leftop = ((NullTest *) clause)->arg;
 
1000
 
 
1001
                        if (leftop && IsA(leftop, RelabelType))
 
1002
                                leftop = ((RelabelType *) leftop)->arg;
 
1003
 
 
1004
                        Assert(leftop != NULL);
 
1005
 
 
1006
                        if (!(IsA(leftop, Var) &&
 
1007
                                  ((Var *) leftop)->varno == scanrelid))
 
1008
                                elog(ERROR, "NullTest indexqual has wrong key");
 
1009
 
 
1010
                        varattno = ((Var *) leftop)->varattno;
 
1011
 
 
1012
                        /*
 
1013
                         * initialize the scan key's fields appropriately
 
1014
                         */
 
1015
                        ScanKeyEntryInitialize(this_scan_key,
 
1016
                                                                   SK_ISNULL | SK_SEARCHNULL,
 
1017
                                                                   varattno,    /* attribute number to scan */
 
1018
                                                                   InvalidStrategy,     /* no strategy */
 
1019
                                                                   InvalidOid,  /* no strategy subtype */
 
1020
                                                                   InvalidOid,  /* no reg proc for this */
 
1021
                                                                   (Datum) 0);  /* constant */
 
1022
                }
 
1023
                else
 
1024
                        elog(ERROR, "unsupported indexqual type: %d",
 
1025
                                 (int) nodeTag(clause));
 
1026
        }
 
1027
 
 
1028
        /* Get rid of any unused arrays */
 
1029
        if (n_runtime_keys == 0)
 
1030
        {
 
1031
                pfree(runtime_keys);
 
1032
                runtime_keys = NULL;
 
1033
        }
 
1034
        if (n_array_keys == 0)
 
1035
        {
 
1036
                pfree(array_keys);
 
1037
                array_keys = NULL;
 
1038
        }
 
1039
 
 
1040
        /*
 
1041
         * Return info to our caller.
 
1042
         */
 
1043
        *scanKeys = scan_keys;
 
1044
        *numScanKeys = n_scan_keys;
 
1045
        *runtimeKeys = runtime_keys;
 
1046
        *numRuntimeKeys = n_runtime_keys;
 
1047
        if (arrayKeys)
 
1048
        {
 
1049
                *arrayKeys = array_keys;
 
1050
                *numArrayKeys = n_array_keys;
 
1051
        }
 
1052
        else if (n_array_keys != 0)
 
1053
                elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
 
1054
}
 
1055
 
 
1056
int
 
1057
ExecCountSlotsIndexScan(IndexScan *node)
 
1058
{
 
1059
        return ExecCountSlotsNode(outerPlan((Plan *) node)) +
 
1060
                ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
 
1061
}