nodeIndexscan.c 26.4 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * nodeIndexscan.c
4
 *	  Routines to support indexes and indexed scans of relations
5
 *
Bruce Momjian's avatar
Bruce Momjian committed
6
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.74 2002/12/13 19:45:52 tgl Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
17 18 19 20 21 22 23
 *		ExecIndexScan			scans a relation using indices
 *		ExecIndexNext			using index to retrieve next tuple
 *		ExecInitIndexScan		creates and initializes state info.
 *		ExecIndexReScan			rescans the indexed relation.
 *		ExecEndIndexScan		releases all storage.
 *		ExecIndexMarkPos		marks scan position.
 *		ExecIndexRestrPos		restores scan position.
24
 */
25 26
#include "postgres.h"

27
#include "access/genam.h"
Bruce Momjian's avatar
Bruce Momjian committed
28 29 30
#include "access/heapam.h"
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
31
#include "nodes/nodeFuncs.h"
Bruce Momjian's avatar
Bruce Momjian committed
32 33
#include "optimizer/clauses.h"
#include "parser/parsetree.h"
34 35

/* ----------------
36
 *		Misc stuff to move to executor.h soon -cim 6/5/90
37 38
 * ----------------
 */
39 40 41
#define NO_OP			0
#define LEFT_OP			1
#define RIGHT_OP		2
42

43
static TupleTableSlot *IndexNext(IndexScanState *node);
44 45

/* ----------------------------------------------------------------
46
 *		IndexNext
47
 *
48 49
 *		Retrieve a tuple from the IndexScan node's currentRelation
 *		using the indices in the IndexScanState information.
50
 *
51 52
 *		note: the old code mentions 'Primary indices'.	to my knowledge
 *		we only support a single secondary index. -cim 9/11/89
53 54
 *
 * old comments:
55 56 57 58 59 60 61 62 63 64
 *		retrieve a tuple from relation using the indices given.
 *		The indices are used in the order they appear in 'indices'.
 *		The indices may be primary or secondary indices:
 *		  * primary index --	scan the relation 'relID' using keys supplied.
 *		  * secondary index --	scan the index relation to get the 'tid' for
 *								a tuple in the relation 'relID'.
 *		If the current index(pointed by 'indexPtr') fails to return a
 *		tuple, the next index in the indices is used.
 *
 *		  bug fix so that it should retrieve on a null scan key.
65 66 67
 * ----------------------------------------------------------------
 */
static TupleTableSlot *
68
IndexNext(IndexScanState *node)
69
{
70
	EState	   *estate;
71
	ExprContext *econtext;
72
	ScanDirection direction;
73
	IndexScanDescPtr scanDescs;
74
	IndexScanDesc scandesc;
75
	Index		scanrelid;
Bruce Momjian's avatar
Bruce Momjian committed
76
	HeapTuple	tuple;
77
	TupleTableSlot *slot;
78
	int			numIndices;
Bruce Momjian's avatar
Bruce Momjian committed
79 80 81
	bool		bBackward;
	int			indexNumber;

82 83
	/*
	 * extract necessary information from index scan node
84
	 */
85
	estate = node->ss.ps.state;
86
	direction = estate->es_direction;
87
	if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
88 89 90 91 92
	{
		if (ScanDirectionIsForward(direction))
			direction = BackwardScanDirection;
		else if (ScanDirectionIsBackward(direction))
			direction = ForwardScanDirection;
93
	}
94 95 96 97 98
	scanDescs = node->iss_ScanDescs;
	numIndices = node->iss_NumIndices;
	econtext = node->ss.ps.ps_ExprContext;
	slot = node->ss.ss_ScanTupleSlot;
	scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
99 100 101

	/*
	 * Check if we are evaluating PlanQual for tuple of this relation.
Bruce Momjian's avatar
Bruce Momjian committed
102 103 104
	 * Additional checking is not good, but no other way for now. We could
	 * introduce new nodes for this case and handle IndexScan --> NewNode
	 * switching in Init/ReScan plan...
105
	 */
Bruce Momjian's avatar
Bruce Momjian committed
106
	if (estate->es_evTuple != NULL &&
107
		estate->es_evTuple[scanrelid - 1] != NULL)
108
	{
109
		List	   *qual;
110

111
		ExecClearTuple(slot);
112
		if (estate->es_evTupleNull[scanrelid - 1])
113 114
			return slot;		/* return empty slot */

115
		ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
116
					   slot, InvalidBuffer, false);
117 118

		/* Does the tuple meet any of the OR'd indxqual conditions? */
119
		econtext->ecxt_scantuple = slot;
120 121 122

		ResetExprContext(econtext);

123
		foreach(qual, node->indxqualorig)
124
		{
125
			if (ExecQual((List *) lfirst(qual), econtext, false))
126 127
				break;
		}
128
		if (qual == NIL)		/* would not be returned by indices */
129
			slot->val = NULL;
130

131
		/* Flag for the next call that no more tuples */
132
		estate->es_evTupleNull[scanrelid - 1] = true;
133 134

		return slot;
135 136
	}

137 138 139 140
	/*
	 * ok, now that we have what we need, fetch an index tuple. if
	 * scanning this index succeeded then return the appropriate heap
	 * tuple.. else return NULL.
141
	 */
Bruce Momjian's avatar
Bruce Momjian committed
142 143 144
	bBackward = ScanDirectionIsBackward(direction);
	if (bBackward)
	{
145
		indexNumber = numIndices - node->iss_IndexPtr - 1;
Bruce Momjian's avatar
Bruce Momjian committed
146 147 148
		if (indexNumber < 0)
		{
			indexNumber = 0;
149
			node->iss_IndexPtr = numIndices - 1;
Bruce Momjian's avatar
Bruce Momjian committed
150 151 152 153
		}
	}
	else
	{
154
		if ((indexNumber = node->iss_IndexPtr) < 0)
Bruce Momjian's avatar
Bruce Momjian committed
155 156
		{
			indexNumber = 0;
157
			node->iss_IndexPtr = 0;
Bruce Momjian's avatar
Bruce Momjian committed
158 159 160 161
		}
	}
	while (indexNumber < numIndices)
	{
162
		scandesc = scanDescs[node->iss_IndexPtr];
163
		while ((tuple = index_getnext(scandesc, direction)) != NULL)
164
		{
165
			/*
Bruce Momjian's avatar
Bruce Momjian committed
166 167 168 169
			 * store the scanned tuple in the scan tuple slot of the scan
			 * state.  Note: we pass 'false' because tuples returned by
			 * amgetnext are pointers onto disk pages and must not be
			 * pfree()'d.
170
			 */
Bruce Momjian's avatar
Bruce Momjian committed
171
			ExecStoreTuple(tuple,		/* tuple to store */
172
						   slot,	/* slot to store in */
Bruce Momjian's avatar
Bruce Momjian committed
173 174
						   scandesc->xs_cbuf,	/* buffer containing tuple */
						   false);		/* don't pfree */
175

176 177
			/*
			 * We must check to see if the current tuple was already
Bruce Momjian's avatar
Bruce Momjian committed
178 179 180
			 * matched by an earlier index, so we don't double-report it.
			 * We do this by passing the tuple through ExecQual and
			 * checking for failure with all previous qualifications.
181
			 */
182
			if (node->iss_IndexPtr > 0)
183 184 185
			{
				bool		prev_matches = false;
				int			prev_index;
186
				List	   *qual;
187

188 189
				econtext->ecxt_scantuple = slot;
				ResetExprContext(econtext);
190
				qual = node->indxqualorig;
191
				for (prev_index = 0;
192
					 prev_index < node->iss_IndexPtr;
193
					 prev_index++)
194
				{
195
					if (ExecQual((List *) lfirst(qual), econtext, false))
196 197 198 199
					{
						prev_matches = true;
						break;
					}
200
					qual = lnext(qual);
201
				}
202 203 204 205 206 207
				if (prev_matches)
				{
					/* Duplicate, so drop it and loop back for another */
					ExecClearTuple(slot);
					continue;
				}
208
			}
209 210

			return slot;		/* OK to return tuple */
211
		}
212

Bruce Momjian's avatar
Bruce Momjian committed
213 214 215 216
		if (indexNumber < numIndices)
		{
			indexNumber++;
			if (bBackward)
217
				node->iss_IndexPtr--;
Bruce Momjian's avatar
Bruce Momjian committed
218
			else
219
				node->iss_IndexPtr++;
Bruce Momjian's avatar
Bruce Momjian committed
220
		}
221
	}
222 223 224 225

	/*
	 * if we get here it means the index scan failed so we are at the end
	 * of the scan..
226 227
	 */
	return ExecClearTuple(slot);
228 229 230
}

/* ----------------------------------------------------------------
231
 *		ExecIndexScan(node)
232 233
 *
 * old comments:
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
 *		Scans the relation using primary or secondary indices and returns
 *		   the next qualifying tuple in the direction specified.
 *		It calls ExecScan() and passes it the access methods which returns
 *		the next tuple using the indices.
 *
 *		Conditions:
 *		  -- the "cursor" maintained by the AMI is positioned at the tuple
 *			 returned previously.
 *
 *		Initial States:
 *		  -- the relation indicated is opened for scanning so that the
 *			 "cursor" is positioned before the first qualifying tuple.
 *		  -- all index realtions are opened for scanning.
 *		  -- indexPtr points to the first index.
 *		  -- state variable ruleFlag = nil.
249 250 251
 * ----------------------------------------------------------------
 */
TupleTableSlot *
252
ExecIndexScan(IndexScanState *node)
253
{
254 255 256
	/*
	 * If we have runtime keys and they've not already been set up, do it
	 * now.
257
	 */
258 259
	if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady)
		ExecReScan((PlanState *) node, NULL);
260

261 262
	/*
	 * use IndexNext as access method
263
	 */
264
	return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
265
}
266 267

/* ----------------------------------------------------------------
268
 *		ExecIndexReScan(node)
269
 *
270 271 272
 *		Recalculates the value of the scan keys whose value depends on
 *		information known at runtime and rescans the indexed relation.
 *		Updating the scan key was formerly done separately in
273 274
 *		ExecUpdateIndexScanKeys. Integrating it into ReScan makes
 *		rescans of indices and relations/general streams more uniform.
275 276 277 278
 *
 * ----------------------------------------------------------------
 */
void
279
ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
280
{
281
	EState	   *estate;
282
	ExprContext *econtext;
283
	int			numIndices;
284
	IndexScanDescPtr scanDescs;
285
	ScanKey    *scanKeys;
286
	ExprState ***runtimeKeyInfo;
287
	int		   *numScanKeys;
288
	Index		scanrelid;
289
	int			i;
290
	int			j;
291

292 293 294 295 296 297 298 299
	estate = node->ss.ps.state;
	econtext = node->iss_RuntimeContext;	/* context for runtime keys */
	numIndices = node->iss_NumIndices;
	scanDescs = node->iss_ScanDescs;
	scanKeys = node->iss_ScanKeys;
	runtimeKeyInfo = node->iss_RuntimeKeyInfo;
	numScanKeys = node->iss_NumScanKeys;
	scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
300

301 302 303
	if (econtext)
	{
		/*
304
		 * If we are being passed an outer tuple, save it for runtime key
305 306
		 * calc.  We also need to link it into the "regular" per-tuple
		 * econtext, so it can be used during indexqualorig evaluations.
307 308
		 */
		if (exprCtxt != NULL)
309 310 311
		{
			ExprContext *stdecontext;

312
			econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
313
			stdecontext = node->ss.ps.ps_ExprContext;
314 315
			stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
		}
316

317
		/*
318 319 320
		 * Reset the runtime-key context so we don't leak memory as each
		 * outer tuple is scanned.	Note this assumes that we will
		 * recalculate *all* runtime keys on each call.
321 322 323
		 */
		ResetExprContext(econtext);
	}
324

325
	/*
326 327
	 * If we are doing runtime key calculations (ie, the index keys depend
	 * on data from an outer scan), compute the new key values
328
	 */
329
	if (runtimeKeyInfo)
330
	{
331
		for (i = 0; i < numIndices; i++)
332
		{
333 334
			int			n_keys;
			ScanKey		scan_keys;
335
			ExprState **run_keys;
336 337 338

			n_keys = numScanKeys[i];
			scan_keys = scanKeys[i];
339
			run_keys = runtimeKeyInfo[i];
340

Bruce Momjian's avatar
Bruce Momjian committed
341
			for (j = 0; j < n_keys; j++)
342 343
			{
				/*
Bruce Momjian's avatar
Bruce Momjian committed
344 345
				 * If we have a run-time key, then extract the run-time
				 * expression and evaluate it with respect to the current
346 347
				 * outer tuple.  We then stick the result into the scan
				 * key.
348
				 *
349 350
				 * Note: the result of the eval could be a pass-by-ref value
				 * that's stored in the outer scan's tuple, not in
351 352 353 354
				 * econtext->ecxt_per_tuple_memory.  We assume that the
				 * outer tuple will stay put throughout our scan.  If this
				 * is wrong, we could copy the result into our context
				 * explicitly, but I think that's not necessary...
355
				 */
356
				if (run_keys[j] != NULL)
Bruce Momjian's avatar
Bruce Momjian committed
357
				{
358 359 360
					Datum		scanvalue;
					bool		isNull;

361
					scanvalue = ExecEvalExprSwitchContext(run_keys[j],
362 363
														  econtext,
														  &isNull,
364
														  NULL);
Bruce Momjian's avatar
Bruce Momjian committed
365 366 367 368 369 370
					scan_keys[j].sk_argument = scanvalue;
					if (isNull)
						scan_keys[j].sk_flags |= SK_ISNULL;
					else
						scan_keys[j].sk_flags &= ~SK_ISNULL;
				}
371
			}
Marc G. Fournier's avatar
Marc G. Fournier committed
372
		}
373

374
		node->iss_RuntimeKeysReady = true;
375 376 377 378
	}

	/* If this is re-scanning of PlanQual ... */
	if (estate->es_evTuple != NULL &&
379
		estate->es_evTuple[scanrelid - 1] != NULL)
380
	{
381
		estate->es_evTupleNull[scanrelid - 1] = false;
382 383 384 385
		return;
	}

	/* reset index scans */
386 387
	if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
		node->iss_IndexPtr = numIndices;
388
	else
389
		node->iss_IndexPtr = -1;
390 391 392 393 394 395

	for (i = 0; i < numIndices; i++)
	{
		IndexScanDesc scan = scanDescs[i];
		ScanKey		skey = scanKeys[i];

396
		index_rescan(scan, skey);
397
	}
398 399 400
}

/* ----------------------------------------------------------------
401
 *		ExecEndIndexScan
402 403
 *
 * old comments
404 405
 *		Releases any storage allocated through C routines.
 *		Returns nothing.
406 407 408
 * ----------------------------------------------------------------
 */
void
409
ExecEndIndexScan(IndexScanState *node)
410
{
411
	ExprState ***runtimeKeyInfo;
412
	ScanKey    *scanKeys;
413
	int		   *numScanKeys;
414
	int			numIndices;
415 416 417
	Relation	relation;
	RelationPtr indexRelationDescs;
	IndexScanDescPtr indexScanDescs;
418
	int			i;
419

420
	runtimeKeyInfo = node->iss_RuntimeKeyInfo;
421

422 423
	/*
	 * extract information from the node
424
	 */
425 426 427 428 429 430
	numIndices = node->iss_NumIndices;
	scanKeys = node->iss_ScanKeys;
	numScanKeys = node->iss_NumScanKeys;
	indexRelationDescs = node->iss_RelationDescs;
	indexScanDescs = node->iss_ScanDescs;
	relation = node->ss.ss_currentRelation;
431

432 433
	/*
	 * Free the projection info and the scan attribute info
434
	 */
435 436 437 438
	ExecFreeProjectionInfo(&node->ss.ps);
	ExecFreeExprContext(&node->ss.ps);
	if (node->iss_RuntimeContext)
		FreeExprContext(node->iss_RuntimeContext);
439

440
	/*
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
	 * close the index relations
	 */
	for (i = 0; i < numIndices; i++)
	{
		if (indexScanDescs[i] != NULL)
			index_endscan(indexScanDescs[i]);

		if (indexRelationDescs[i] != NULL)
			index_close(indexRelationDescs[i]);
	}

	/*
	 * close the heap relation.
	 *
	 * Currently, we do not release the AccessShareLock acquired by
Bruce Momjian's avatar
Bruce Momjian committed
456 457 458
	 * ExecInitIndexScan.  This lock should be held till end of
	 * transaction. (There is a faction that considers this too much
	 * locking, however.)
459
	 */
460
	heap_close(relation, NoLock);
461

462 463
	/*
	 * free the scan keys used in scanning the indices
464 465 466 467 468 469
	 */
	for (i = 0; i < numIndices; i++)
	{
		if (scanKeys[i] != NULL)
			pfree(scanKeys[i]);
	}
470 471 472 473
	pfree(scanKeys);
	pfree(numScanKeys);

	if (runtimeKeyInfo)
474
	{
475 476
		for (i = 0; i < numIndices; i++)
		{
477
			if (runtimeKeyInfo[i] != NULL)
478 479 480 481
				pfree(runtimeKeyInfo[i]);
		}
		pfree(runtimeKeyInfo);
	}
482

483 484
	/*
	 * clear out tuple table slots
485
	 */
486 487 488 489 490
	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
	ExecClearTuple(node->ss.ss_ScanTupleSlot);
	pfree(node->iss_RelationDescs);
	pfree(node->iss_ScanDescs);
	pfree(node);
491 492 493
}

/* ----------------------------------------------------------------
494
 *		ExecIndexMarkPos
495 496
 *
 * old comments
497 498
 *		Marks scan position by marking the current index.
 *		Returns nothing.
499 500 501
 * ----------------------------------------------------------------
 */
void
502
ExecIndexMarkPos(IndexScanState *node)
503
{
504
	IndexScanDescPtr indexScanDescs;
505 506
	IndexScanDesc scanDesc;
	int			indexPtr;
507

508 509
	indexPtr = node->iss_MarkIndexPtr = node->iss_IndexPtr;
	indexScanDescs = node->iss_ScanDescs;
510 511
	scanDesc = indexScanDescs[indexPtr];

512
	index_markpos(scanDesc);
513 514 515
}

/* ----------------------------------------------------------------
516
 *		ExecIndexRestrPos
517 518
 *
 * old comments
519 520 521 522
 *		Restores scan position by restoring the current index.
 *		Returns nothing.
 *
 *		XXX Assumes previously marked scan position belongs to current index
523 524 525
 * ----------------------------------------------------------------
 */
void
526
ExecIndexRestrPos(IndexScanState *node)
527
{
528
	IndexScanDescPtr indexScanDescs;
529 530
	IndexScanDesc scanDesc;
	int			indexPtr;
531

532 533
	indexPtr = node->iss_IndexPtr = node->iss_MarkIndexPtr;
	indexScanDescs = node->iss_ScanDescs;
534
	scanDesc = indexScanDescs[indexPtr];
535

536
	index_restrpos(scanDesc);
537 538 539
}

/* ----------------------------------------------------------------
540
 *		ExecInitIndexScan
541
  *
542 543
 *		Initializes the index scan's state information, creates
 *		scan keys, and opens the base and index relations.
544
 *
545 546 547
 *		Note: index scans have 2 sets of state information because
 *			  we have to keep track of the base relation and the
 *			  index relations.
548 549
 *
 * old comments
550
 *		Creates the run-time state information for the node and
551
 *		sets the relation id to contain relevant descriptors.
552 553 554 555
 *
 *		Parameters:
 *		  node: IndexNode node produced by the planner.
 *		  estate: the execution state initialized in InitPlan.
556 557
 * ----------------------------------------------------------------
 */
558 559
IndexScanState *
ExecInitIndexScan(IndexScan *node, EState *estate)
560
{
561
	IndexScanState *indexstate;
562 563
	List	   *indxqual;
	List	   *indxid;
564
	List	   *listscan;
565 566 567 568 569
	int			i;
	int			numIndices;
	int			indexPtr;
	ScanKey    *scanKeys;
	int		   *numScanKeys;
570
	RelationPtr indexDescs;
571
	IndexScanDescPtr scanDescs;
572
	ExprState ***runtimeKeyInfo;
573 574 575 576 577
	bool		have_runtime_keys;
	RangeTblEntry *rtentry;
	Index		relid;
	Oid			reloid;
	Relation	currentRelation;
578

579
	/*
580
	 * create state structure
581
	 */
582 583 584
	indexstate = makeNode(IndexScanState);
	indexstate->ss.ps.plan = (Plan *) node;
	indexstate->ss.ps.state = estate;
585

586
	/*
587
	 * Miscellaneous initialization
588
	 *
589
	 * create expression context for node
590
	 */
591
	ExecAssignExprContext(estate, &indexstate->ss.ps);
592

593
	/*
594
	 * initialize child expressions
595
	 */
596
	indexstate->ss.ps.targetlist = (List *)
597
		ExecInitExpr((Expr *) node->scan.plan.targetlist,
598 599
					 (PlanState *) indexstate);
	indexstate->ss.ps.qual = (List *)
600
		ExecInitExpr((Expr *) node->scan.plan.qual,
601 602
					 (PlanState *) indexstate);
	indexstate->indxqual = (List *)
603
		ExecInitExpr((Expr *) node->indxqual,
604 605
					 (PlanState *) indexstate);
	indexstate->indxqualorig = (List *)
606
		ExecInitExpr((Expr *) node->indxqualorig,
607
					 (PlanState *) indexstate);
608

609
#define INDEXSCAN_NSLOTS 2
610 611 612

	/*
	 * tuple table initialization
613
	 */
614 615
	ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
	ExecInitScanTupleSlot(estate, &indexstate->ss);
616

617 618 619
	/*
	 * initialize projection info.	result type comes from scan desc
	 * below..
620
	 */
621
	ExecAssignProjectionInfo(&indexstate->ss.ps);
622

623
	/*
624
	 * Initialize index-specific scan state
625
	 */
626
	indexstate->iss_NumIndices = 0;
627
	indexstate->iss_IndexPtr = -1;
628 629 630
	indexstate->iss_ScanKeys = NULL;
	indexstate->iss_NumScanKeys = NULL;
	indexstate->iss_RuntimeKeyInfo = NULL;
631
	indexstate->iss_RuntimeContext = NULL;
632
	indexstate->iss_RuntimeKeysReady = false;
633 634 635
	indexstate->iss_RelationDescs = NULL;
	indexstate->iss_ScanDescs = NULL;

636 637
	/*
	 * get the index node information
638 639 640
	 */
	indxid = node->indxid;
	numIndices = length(indxid);
641
	indexPtr = -1;
642 643 644

	CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);

645 646 647 648
	/*
	 * scanKeys is used to keep track of the ScanKey's. This is needed
	 * because a single scan may use several indices and each index has
	 * its own ScanKey.
649 650 651
	 */
	numScanKeys = (int *) palloc(numIndices * sizeof(int));
	scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
652
	indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
653 654
	scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));

655 656
	/*
	 * initialize space for runtime key info (may not be needed)
657 658
	 */
	have_runtime_keys = false;
659
	runtimeKeyInfo = (ExprState ***) palloc0(numIndices * sizeof(ExprState **));
660

661 662
	/*
	 * build the index scan keys from the index qualification
663
	 */
664
	indxqual = node->indxqual;
665 666
	for (i = 0; i < numIndices; i++)
	{
667 668 669 670
		int			j;
		List	   *qual;
		int			n_keys;
		ScanKey		scan_keys;
671
		ExprState **run_keys;
672

673 674
		qual = lfirst(indxqual);
		indxqual = lnext(indxqual);
675
		n_keys = length(qual);
676
		scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
677
			(ScanKey) palloc(n_keys * sizeof(ScanKeyData));
678 679
		run_keys = (n_keys <= 0) ? (ExprState **) NULL :
			(ExprState **) palloc(n_keys * sizeof(ExprState *));
680

Bruce Momjian's avatar
Bruce Momjian committed
681
		CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
682

683 684 685
		/*
		 * for each opclause in the given qual, convert each qual's
		 * opclause into a single scan key
686
		 */
687
		listscan = qual;
688 689
		for (j = 0; j < n_keys; j++)
		{
690
			OpExpr	   *clause; /* one clause of index qual */
691 692
			Expr	   *leftop; /* expr on lhs of operator */
			Expr	   *rightop;	/* expr on rhs ... */
693 694
			bits16		flags = 0;

695
			int			scanvar;	/* which var identifies varattno */
696
			AttrNumber	varattno = 0;	/* att number used in scan */
697
			Oid			opfuncid;		/* operator id used in scan */
698
			Datum		scanvalue = 0;	/* value used in scan (if const) */
699

700 701
			/*
			 * extract clause information from the qualification
702
			 */
703
			clause = (OpExpr *) lfirst(listscan);
704
			listscan = lnext(listscan);
705

706
			if (!IsA(clause, OpExpr))
707
				elog(ERROR, "ExecInitIndexScan: indxqual not an opclause!");
708

709
			opfuncid = clause->opfuncid;
710

711 712 713 714 715
			/*
			 * Here we figure out the contents of the index qual. The
			 * usual case is (var op const) or (const op var) which means
			 * we form a scan key for the attribute listed in the var node
			 * and use the value of the const.
716
			 *
717 718 719 720
			 * If we don't have a const node, then it means that one of the
			 * var nodes refers to the "scan" tuple and is used to
			 * determine which attribute to scan, and the other expression
			 * is used to calculate the value used in scanning the index.
721
			 *
722 723 724 725
			 * This means our index scan's scan key is a function of
			 * information obtained during the execution of the plan in
			 * which case we need to recalculate the index scan key at run
			 * time.
726
			 *
727 728 729
			 * Hence, we set have_runtime_keys to true and place the
			 * appropriate subexpression in run_keys. The corresponding
			 * scan key values are recomputed at run time.
730
			 *
731 732 733 734 735 736 737 738 739
			 * XXX Although this code *thinks* it can handle an indexqual
			 * with the indexkey on either side, in fact it cannot.
			 * Indexscans only work with quals that have the indexkey on
			 * the left (the planner/optimizer makes sure it never passes
			 * anything else).	The reason: the scankey machinery has no
			 * provision for distinguishing which side of the operator is
			 * the indexed attribute and which is the compared-to
			 * constant. It just assumes that the attribute is on the left
			 * :-(
740
			 *
741 742 743
			 * I am leaving this code able to support both ways, even though
			 * half of it is dead code, on the off chance that someone
			 * will fix the scankey machinery someday --- tgl 8/11/99.
744 745 746
			 */

			scanvar = NO_OP;
747
			run_keys[j] = NULL;
748

749 750
			/*
			 * determine information in leftop
751
			 */
752
			leftop = (Expr *) get_leftop((Expr *) clause);
753

754
			if (leftop && IsA(leftop, RelabelType))
755
				leftop = ((RelabelType *) leftop)->arg;
756

757 758
			Assert(leftop != NULL);

759 760
			if (IsA(leftop, Var) &&
				var_is_rel((Var *) leftop))
761
			{
762 763 764 765
				/*
				 * if the leftop is a "rel-var", then it means that it is
				 * a var node which tells us which attribute to use for
				 * our scan key.
766 767 768 769 770 771
				 */
				varattno = ((Var *) leftop)->varattno;
				scanvar = LEFT_OP;
			}
			else if (IsA(leftop, Const))
			{
772 773 774
				/*
				 * if the leftop is a const node then it means it
				 * identifies the value to place in our scan key.
775 776
				 */
				scanvalue = ((Const *) leftop)->constvalue;
777 778
				if (((Const *) leftop)->constisnull)
					flags |= SK_ISNULL;
779 780 781
			}
			else
			{
782 783 784 785
				/*
				 * otherwise, the leftop contains an expression evaluable
				 * at runtime to figure out the value to place in our scan
				 * key.
786 787
				 */
				have_runtime_keys = true;
788
				run_keys[j] = ExecInitExpr(leftop, (PlanState *) indexstate);
789 790
			}

791 792
			/*
			 * now determine information in rightop
793
			 */
794
			rightop = (Expr *) get_rightop((Expr *) clause);
795

796
			if (rightop && IsA(rightop, RelabelType))
797
				rightop = ((RelabelType *) rightop)->arg;
798

799 800
			Assert(rightop != NULL);

801 802
			if (IsA(rightop, Var) &&
				var_is_rel((Var *) rightop))
803
			{
804 805 806
				/*
				 * here we make sure only one op identifies the
				 * scan-attribute...
807 808
				 */
				if (scanvar == LEFT_OP)
809
					elog(ERROR, "ExecInitIndexScan: %s",
810 811
						 "both left and right op's are rel-vars");

812 813 814 815
				/*
				 * if the rightop is a "rel-var", then it means that it is
				 * a var node which tells us which attribute to use for
				 * our scan key.
816 817 818
				 */
				varattno = ((Var *) rightop)->varattno;
				scanvar = RIGHT_OP;
819
			}
820 821
			else if (IsA(rightop, Const))
			{
822 823 824
				/*
				 * if the rightop is a const node then it means it
				 * identifies the value to place in our scan key.
825 826
				 */
				scanvalue = ((Const *) rightop)->constvalue;
827 828
				if (((Const *) rightop)->constisnull)
					flags |= SK_ISNULL;
829 830 831
			}
			else
			{
832 833 834 835
				/*
				 * otherwise, the rightop contains an expression evaluable
				 * at runtime to figure out the value to place in our scan
				 * key.
836 837
				 */
				have_runtime_keys = true;
838
				run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);
839 840
			}

841 842 843
			/*
			 * now check that at least one op tells us the scan
			 * attribute...
844 845
			 */
			if (scanvar == NO_OP)
846
				elog(ERROR, "ExecInitIndexScan: %s",
847 848
					 "neither leftop nor rightop refer to scan relation");

849 850
			/*
			 * initialize the scan key's fields appropriately
851 852 853 854 855
			 */
			ScanKeyEntryInitialize(&scan_keys[j],
								   flags,
								   varattno,	/* attribute number to
												 * scan */
856
								   opfuncid,	/* reg proc to use */
857
								   scanvalue);	/* constant */
858 859
		}

860 861
		/*
		 * store the key information into our arrays.
862
		 */
863 864
		numScanKeys[i] = n_keys;
		scanKeys[i] = scan_keys;
865
		runtimeKeyInfo[i] = run_keys;
866
	}
867 868

	indexstate->iss_NumIndices = numIndices;
869 870
	if (ScanDirectionIsBackward(node->indxorderdir))
		indexPtr = numIndices;
871 872 873 874
	indexstate->iss_IndexPtr = indexPtr;
	indexstate->iss_ScanKeys = scanKeys;
	indexstate->iss_NumScanKeys = numScanKeys;

875 876 877 878 879 880
	/*
	 * If all of our keys have the form (op var const) , then we have no
	 * runtime keys so we store NULL in the runtime key info. Otherwise
	 * runtime key info contains an array of pointers (one for each index)
	 * to arrays of flags (one for each key) which indicate that the qual
	 * needs to be evaluated at runtime. -cim 10/24/89
881
	 *
882 883 884 885
	 * If we do have runtime keys, we need an ExprContext to evaluate them;
	 * the node's standard context won't do because we want to reset that
	 * context for every tuple.  So, build another context just like the
	 * other one... -tgl 7/11/00
886
	 */
887
	if (have_runtime_keys)
888
	{
889
		ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
890

891
		ExecAssignExprContext(estate, &indexstate->ss.ps);
892
		indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
893 894
		indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
		indexstate->ss.ps.ps_ExprContext = stdecontext;
895
	}
896
	else
897
	{
898
		indexstate->iss_RuntimeKeyInfo = NULL;
899 900 901 902 903 904 905 906 907
		indexstate->iss_RuntimeContext = NULL;
		/* Get rid of the speculatively-allocated flag arrays, too */
		for (i = 0; i < numIndices; i++)
		{
			if (runtimeKeyInfo[i] != NULL)
				pfree(runtimeKeyInfo[i]);
		}
		pfree(runtimeKeyInfo);
	}
908

909
	/*
910
	 * open the base relation and acquire AccessShareLock on it.
911 912
	 */
	relid = node->scan.scanrelid;
913
	rtentry = rt_fetch(relid, estate->es_range_table);
914 915
	reloid = rtentry->relid;

916
	currentRelation = heap_open(reloid, AccessShareLock);
917

918 919
	if (!RelationGetForm(currentRelation)->relhasindex)
		elog(ERROR, "indexes of the relation %u was inactivated", reloid);
920

921 922
	indexstate->ss.ss_currentRelation = currentRelation;
	indexstate->ss.ss_currentScanDesc = NULL;		/* no heap scan here */
923

924 925
	/*
	 * get the scan type from the relation descriptor.
926
	 */
927 928
	ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
	ExecAssignResultTypeFromTL(&indexstate->ss.ps);
929

930 931
	/*
	 * open the index relations and initialize relation and scan
932 933 934
	 * descriptors.  Note we acquire no locks here; the index machinery
	 * does its own locks and unlocks.	(We rely on having AccessShareLock
	 * on the parent table to ensure the index won't go away!)
935
	 */
936
	listscan = indxid;
937 938
	for (i = 0; i < numIndices; i++)
	{
939
		Oid			indexOid = (Oid) lfirsti(listscan);
940

941 942 943 944 945 946
		indexDescs[i] = index_open(indexOid);
		scanDescs[i] = index_beginscan(currentRelation,
									   indexDescs[i],
									   estate->es_snapshot,
									   numScanKeys[i],
									   scanKeys[i]);
947
		listscan = lnext(listscan);
948 949
	}

950
	indexstate->iss_RelationDescs = indexDescs;
951
	indexstate->iss_ScanDescs = scanDescs;
952

953 954
	/*
	 * all done.
955
	 */
956
	return indexstate;
957 958 959
}

int
960
ExecCountSlotsIndexScan(IndexScan *node)
961
{
962
	return ExecCountSlotsNode(outerPlan((Plan *) node)) +
963
		ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
964
}