1
/*-------------------------------------------------------------------------
4
* Routines to support indexed scans of relations
6
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
13
*-------------------------------------------------------------------------
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.
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"
38
static TupleTableSlot *IndexNext(IndexScanState *node);
41
/* ----------------------------------------------------------------
44
* Retrieve a tuple from the IndexScan node's currentRelation
45
* using the index specified in the IndexScanState information.
46
* ----------------------------------------------------------------
48
static TupleTableSlot *
49
IndexNext(IndexScanState *node)
52
ExprContext *econtext;
53
ScanDirection direction;
54
IndexScanDesc scandesc;
60
* extract necessary information from index scan node
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))
67
if (ScanDirectionIsForward(direction))
68
direction = BackwardScanDirection;
69
else if (ScanDirectionIsBackward(direction))
70
direction = ForwardScanDirection;
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;
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...
83
if (estate->es_evTuple != NULL &&
84
estate->es_evTuple[scanrelid - 1] != NULL)
86
if (estate->es_evTupleNull[scanrelid - 1])
87
return ExecClearTuple(slot);
89
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
90
slot, InvalidBuffer, false);
92
/* Does the tuple meet the indexqual condition? */
93
econtext->ecxt_scantuple = slot;
95
ResetExprContext(econtext);
97
if (!ExecQual(node->indexqualorig, econtext, false))
98
ExecClearTuple(slot); /* would not be returned by scan */
100
/* Flag for the next call that no more tuples */
101
estate->es_evTupleNull[scanrelid - 1] = true;
107
* ok, now that we have what we need, fetch the next tuple.
109
while ((tuple = index_getnext(scandesc, direction)) != NULL)
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.
116
ExecStoreTuple(tuple, /* tuple to store */
117
slot, /* slot to store in */
118
scandesc->xs_cbuf, /* buffer containing tuple */
119
false); /* don't pfree */
122
* If the index was lossy, we have to recheck the index quals using
125
if (scandesc->xs_recheck)
127
econtext->ecxt_scantuple = slot;
128
ResetExprContext(econtext);
129
if (!ExecQual(node->indexqualorig, econtext, false))
130
continue; /* nope, so ask index for another one */
137
* if we get here it means the index scan failed so we are at the end of
140
return ExecClearTuple(slot);
143
/* ----------------------------------------------------------------
144
* ExecIndexScan(node)
145
* ----------------------------------------------------------------
148
ExecIndexScan(IndexScanState *node)
151
* If we have runtime keys and they've not already been set up, do it now.
153
if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
154
ExecReScan((PlanState *) node, NULL);
157
* use IndexNext as access method
159
return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
162
/* ----------------------------------------------------------------
163
* ExecIndexReScan(node)
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
* ----------------------------------------------------------------
173
ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
176
ExprContext *econtext;
179
estate = node->ss.ps.state;
180
econtext = node->iss_RuntimeContext; /* context for runtime keys */
181
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
183
node->ss.ps.ps_TupFromTlist = false;
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.
192
if (exprCtxt != NULL)
194
ExprContext *stdecontext;
196
econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
197
stdecontext = node->ss.ps.ps_ExprContext;
198
stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
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.
206
ResetExprContext(econtext);
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
213
if (node->iss_NumRuntimeKeys != 0)
214
ExecIndexEvalRuntimeKeys(econtext,
215
node->iss_RuntimeKeys,
216
node->iss_NumRuntimeKeys);
217
node->iss_RuntimeKeysReady = true;
219
/* If this is re-scanning of PlanQual ... */
220
if (estate->es_evTuple != NULL &&
221
estate->es_evTuple[scanrelid - 1] != NULL)
223
estate->es_evTupleNull[scanrelid - 1] = false;
227
/* reset index scan */
228
index_rescan(node->iss_ScanDesc, node->iss_ScanKeys);
233
* ExecIndexEvalRuntimeKeys
234
* Evaluate any runtime key values, and update the scankeys.
237
ExecIndexEvalRuntimeKeys(ExprContext *econtext,
238
IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
242
for (j = 0; j < numRuntimeKeys; j++)
244
ScanKey scan_key = runtimeKeys[j].scan_key;
245
ExprState *key_expr = runtimeKeys[j].key_expr;
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.
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
261
scanvalue = ExecEvalExprSwitchContext(key_expr,
265
scan_key->sk_argument = scanvalue;
267
scan_key->sk_flags |= SK_ISNULL;
269
scan_key->sk_flags &= ~SK_ISNULL;
274
* ExecIndexEvalArrayKeys
275
* Evaluate any array key values, and set up to iterate through arrays.
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.
282
ExecIndexEvalArrayKeys(ExprContext *econtext,
283
IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
287
MemoryContext oldContext;
289
/* We want to keep the arrays in per-tuple memory */
290
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
292
for (j = 0; j < numArrayKeys; j++)
294
ScanKey scan_key = arrayKeys[j].scan_key;
295
ExprState *array_expr = arrayKeys[j].array_expr;
307
* Compute and deconstruct the array expression. (Notes in
308
* ExecIndexEvalRuntimeKeys() apply here too.)
310
arraydatum = ExecEvalExpr(array_expr,
317
break; /* no point in evaluating more */
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);
330
break; /* no point in evaluating more */
334
* Note: we expect the previous array data, if any, to be
335
* automatically freed by resetting the per-tuple context; hence no
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];
343
scan_key->sk_flags |= SK_ISNULL;
345
scan_key->sk_flags &= ~SK_ISNULL;
346
arrayKeys[j].next_elem = 1;
349
MemoryContextSwitchTo(oldContext);
355
* ExecIndexAdvanceArrayKeys
356
* Advance to the next set of array key values, if any.
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.
362
ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
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.
373
for (j = numArrayKeys - 1; j >= 0; j--)
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;
381
if (next_elem >= num_elems)
384
found = false; /* need to advance next array key */
388
scan_key->sk_argument = elem_values[next_elem];
389
if (elem_nulls[next_elem])
390
scan_key->sk_flags |= SK_ISNULL;
392
scan_key->sk_flags &= ~SK_ISNULL;
393
arrayKeys[j].next_elem = next_elem + 1;
402
/* ----------------------------------------------------------------
404
* ----------------------------------------------------------------
407
ExecEndIndexScan(IndexScanState *node)
409
Relation indexRelationDesc;
410
IndexScanDesc indexScanDesc;
414
* extract information from the node
416
indexRelationDesc = node->iss_RelationDesc;
417
indexScanDesc = node->iss_ScanDesc;
418
relation = node->ss.ss_currentRelation;
421
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
424
ExecFreeExprContext(&node->ss.ps);
425
if (node->iss_RuntimeContext)
426
FreeExprContext(node->iss_RuntimeContext);
430
* clear out tuple table slots
432
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
433
ExecClearTuple(node->ss.ss_ScanTupleSlot);
436
* close the index relation (no-op if we didn't open it)
439
index_endscan(indexScanDesc);
440
if (indexRelationDesc)
441
index_close(indexRelationDesc, NoLock);
444
* close the heap relation.
446
ExecCloseScanRelation(relation);
449
/* ----------------------------------------------------------------
451
* ----------------------------------------------------------------
454
ExecIndexMarkPos(IndexScanState *node)
456
index_markpos(node->iss_ScanDesc);
459
/* ----------------------------------------------------------------
461
* ----------------------------------------------------------------
464
ExecIndexRestrPos(IndexScanState *node)
466
index_restrpos(node->iss_ScanDesc);
469
/* ----------------------------------------------------------------
472
* Initializes the index scan's state information, creates
473
* scan keys, and opens the base and index relations.
475
* Note: index scans have 2 sets of state information because
476
* we have to keep track of the base relation and the
478
* ----------------------------------------------------------------
481
ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
483
IndexScanState *indexstate;
484
Relation currentRelation;
488
* create state structure
490
indexstate = makeNode(IndexScanState);
491
indexstate->ss.ps.plan = (Plan *) node;
492
indexstate->ss.ps.state = estate;
495
* Miscellaneous initialization
497
* create expression context for node
499
ExecAssignExprContext(estate, &indexstate->ss.ps);
501
indexstate->ss.ps.ps_TupFromTlist = false;
504
* initialize child expressions
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...)
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);
522
#define INDEXSCAN_NSLOTS 2
525
* tuple table initialization
527
ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
528
ExecInitScanTupleSlot(estate, &indexstate->ss);
531
* open the base relation and acquire appropriate lock on it.
533
currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
535
indexstate->ss.ss_currentRelation = currentRelation;
536
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
539
* get the scan type from the relation descriptor.
541
ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
544
* Initialize result tuple type and projection info.
546
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
547
ExecAssignScanProjectionInfo(&indexstate->ss);
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.
554
if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
558
* Open the index relation.
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.
564
relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
565
indexstate->iss_RelationDesc = index_open(node->indexid,
566
relistarget ? NoLock : AccessShareLock);
569
* Initialize index-specific scan state
571
indexstate->iss_RuntimeKeysReady = false;
574
* build the index scan keys from the index qualification
576
ExecIndexBuildScanKeys((PlanState *) indexstate,
577
indexstate->iss_RelationDesc,
578
node->scan.scanrelid,
580
&indexstate->iss_ScanKeys,
581
&indexstate->iss_NumScanKeys,
582
&indexstate->iss_RuntimeKeys,
583
&indexstate->iss_NumRuntimeKeys,
584
NULL, /* no ArrayKeys */
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...
593
if (indexstate->iss_NumRuntimeKeys != 0)
595
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
597
ExecAssignExprContext(estate, &indexstate->ss.ps);
598
indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
599
indexstate->ss.ps.ps_ExprContext = stdecontext;
603
indexstate->iss_RuntimeContext = NULL;
607
* Initialize scan descriptor.
609
indexstate->iss_ScanDesc = index_beginscan(currentRelation,
610
indexstate->iss_RelationDesc,
612
indexstate->iss_NumScanKeys,
613
indexstate->iss_ScanKeys);
623
* ExecIndexBuildScanKeys
624
* Build the index scan keys from the index qualification expressions
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:
631
* 1. Simple operator with constant comparison value ("indexkey op constant").
632
* For these, we just fill in a ScanKey containing the constant value.
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.
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.
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.)
650
* 5. NullTest ("indexkey IS NULL"). We just fill in the ScanKey properly.
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
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
668
* Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
669
* ScalarArrayOpExpr quals are not supported.
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)
679
IndexRuntimeKeyInfo *runtime_keys;
680
IndexArrayKeyInfo *array_keys;
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.)
694
n_scan_keys = list_length(quals);
696
foreach(qual_cell, quals)
698
if (IsA(lfirst(qual_cell), RowCompareExpr))
700
list_length(((RowCompareExpr *) lfirst(qual_cell))->opnos);
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));
713
* Below here, extra_scan_keys is index of first cell to use for next
716
extra_scan_keys = n_scan_keys;
719
* for each opclause in the given qual, convert the opclause into
723
foreach(qual_cell, quals)
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 */
733
Expr *leftop; /* expr on lhs of operator */
734
Expr *rightop; /* expr on rhs ... */
735
AttrNumber varattno; /* att number used in scan */
737
if (IsA(clause, OpExpr))
739
/* indexkey op const or indexkey op expression */
743
opno = ((OpExpr *) clause)->opno;
744
opfuncid = ((OpExpr *) clause)->opfuncid;
747
* leftop should be the index key Var, possibly relabeled
749
leftop = (Expr *) get_leftop(clause);
751
if (leftop && IsA(leftop, RelabelType))
752
leftop = ((RelabelType *) leftop)->arg;
754
Assert(leftop != NULL);
756
if (!(IsA(leftop, Var) &&
757
((Var *) leftop)->varno == scanrelid))
758
elog(ERROR, "indexqual doesn't have key on left side");
760
varattno = ((Var *) leftop)->varattno;
761
if (varattno < 1 || varattno > index->rd_index->indnatts)
762
elog(ERROR, "bogus index qualification");
765
* We have to look up the operator's strategy number. This
766
* provides a cross-check that the operator does match the index.
768
opfamily = index->rd_opfamily[varattno - 1];
770
get_op_opfamily_properties(opno, opfamily,
776
* rightop is the constant or variable comparison value
778
rightop = (Expr *) get_rightop(clause);
780
if (rightop && IsA(rightop, RelabelType))
781
rightop = ((RelabelType *) rightop)->arg;
783
Assert(rightop != NULL);
785
if (IsA(rightop, Const))
787
/* OK, simple constant comparison value */
788
scanvalue = ((Const *) rightop)->constvalue;
789
if (((Const *) rightop)->constisnull)
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);
799
scanvalue = (Datum) 0;
803
* initialize the scan key's fields appropriately
805
ScanKeyEntryInitialize(this_scan_key,
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 */
813
else if (IsA(clause, RowCompareExpr))
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];
822
/* Scan RowCompare columns and generate subsidiary ScanKey items */
823
while (opnos_cell != NULL)
825
ScanKey this_sub_key = &scan_keys[extra_scan_keys];
826
int flags = SK_ROW_MEMBER;
830
* leftop should be the index key Var, possibly relabeled
832
leftop = (Expr *) lfirst(largs_cell);
833
largs_cell = lnext(largs_cell);
835
if (leftop && IsA(leftop, RelabelType))
836
leftop = ((RelabelType *) leftop)->arg;
838
Assert(leftop != NULL);
840
if (!(IsA(leftop, Var) &&
841
((Var *) leftop)->varno == scanrelid))
842
elog(ERROR, "indexqual doesn't have key on left side");
844
varattno = ((Var *) leftop)->varattno;
847
* rightop is the constant or variable comparison value
849
rightop = (Expr *) lfirst(rargs_cell);
850
rargs_cell = lnext(rargs_cell);
852
if (rightop && IsA(rightop, RelabelType))
853
rightop = ((RelabelType *) rightop)->arg;
855
Assert(rightop != NULL);
857
if (IsA(rightop, Const))
859
/* OK, simple constant comparison value */
860
scanvalue = ((Const *) rightop)->constvalue;
861
if (((Const *) rightop)->constisnull)
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);
871
scanvalue = (Datum) 0;
875
* We have to look up the operator's associated btree support
878
opno = lfirst_oid(opnos_cell);
879
opnos_cell = lnext(opnos_cell);
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];
886
get_op_opfamily_properties(opno, opfamily,
891
if (op_strategy != rc->rctype)
892
elog(ERROR, "RowCompare index qualification contains wrong operator");
894
opfuncid = get_opfamily_proc(opfamily,
900
* initialize the subsidiary scan key's fields appropriately
902
ScanKeyEntryInitialize(this_sub_key,
904
varattno, /* attribute number */
905
op_strategy, /* op's strategy */
906
op_righttype, /* strategy subtype */
907
opfuncid, /* reg proc to use */
908
scanvalue); /* constant */
912
/* Mark the last subsidiary scankey correctly */
913
scan_keys[extra_scan_keys - 1].sk_flags |= SK_ROW_END;
916
* We don't use ScanKeyEntryInitialize for the header because it
917
* isn't going to contain a valid sk_func pointer.
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);
926
else if (IsA(clause, ScalarArrayOpExpr))
928
/* indexkey op ANY (array-expression) */
929
ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
933
opfuncid = saop->opfuncid;
936
* leftop should be the index key Var, possibly relabeled
938
leftop = (Expr *) linitial(saop->args);
940
if (leftop && IsA(leftop, RelabelType))
941
leftop = ((RelabelType *) leftop)->arg;
943
Assert(leftop != NULL);
945
if (!(IsA(leftop, Var) &&
946
((Var *) leftop)->varno == scanrelid))
947
elog(ERROR, "indexqual doesn't have key on left side");
949
varattno = ((Var *) leftop)->varattno;
950
if (varattno < 1 || varattno > index->rd_index->indnatts)
951
elog(ERROR, "bogus index qualification");
954
* We have to look up the operator's strategy number. This
955
* provides a cross-check that the operator does match the index.
957
opfamily = index->rd_opfamily[varattno - 1];
959
get_op_opfamily_properties(opno, opfamily,
965
* rightop is the constant or variable array value
967
rightop = (Expr *) lsecond(saop->args);
969
if (rightop && IsA(rightop, RelabelType))
970
rightop = ((RelabelType *) rightop)->arg;
972
Assert(rightop != NULL);
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 */
981
* initialize the scan key's fields appropriately
983
ScanKeyEntryInitialize(this_scan_key,
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 */
991
else if (IsA(clause, NullTest))
993
/* indexkey IS NULL */
994
Assert(((NullTest *) clause)->nulltesttype == IS_NULL);
997
* argument should be the index key Var, possibly relabeled
999
leftop = ((NullTest *) clause)->arg;
1001
if (leftop && IsA(leftop, RelabelType))
1002
leftop = ((RelabelType *) leftop)->arg;
1004
Assert(leftop != NULL);
1006
if (!(IsA(leftop, Var) &&
1007
((Var *) leftop)->varno == scanrelid))
1008
elog(ERROR, "NullTest indexqual has wrong key");
1010
varattno = ((Var *) leftop)->varattno;
1013
* initialize the scan key's fields appropriately
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 */
1024
elog(ERROR, "unsupported indexqual type: %d",
1025
(int) nodeTag(clause));
1028
/* Get rid of any unused arrays */
1029
if (n_runtime_keys == 0)
1031
pfree(runtime_keys);
1032
runtime_keys = NULL;
1034
if (n_array_keys == 0)
1041
* Return info to our caller.
1043
*scanKeys = scan_keys;
1044
*numScanKeys = n_scan_keys;
1045
*runtimeKeys = runtime_keys;
1046
*numRuntimeKeys = n_runtime_keys;
1049
*arrayKeys = array_keys;
1050
*numArrayKeys = n_array_keys;
1052
else if (n_array_keys != 0)
1053
elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1057
ExecCountSlotsIndexScan(IndexScan *node)
1059
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
1060
ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;