1 /*-------------------------------------------------------------------------
2  *
3  * nodeIndexscan.c
4  *	  Routines to support indexed scans of relations
5  *
6  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/executor/nodeIndexscan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *		ExecIndexScan			scans a relation using an index
18  *		IndexNext				retrieve next tuple using index
19  *		IndexNextWithReorder	same, but recheck ORDER BY expressions
20  *		ExecInitIndexScan		creates and initializes state info.
21  *		ExecReScanIndexScan		rescans the indexed relation.
22  *		ExecEndIndexScan		releases all storage.
23  *		ExecIndexMarkPos		marks scan position.
24  *		ExecIndexRestrPos		restores scan position.
25  */
26 #include "postgres.h"
27 
28 #include "access/nbtree.h"
29 #include "access/relscan.h"
30 #include "catalog/pg_am.h"
31 #include "executor/execdebug.h"
32 #include "executor/nodeIndexscan.h"
33 #include "lib/pairingheap.h"
34 #include "nodes/nodeFuncs.h"
35 #include "optimizer/clauses.h"
36 #include "utils/array.h"
37 #include "utils/datum.h"
38 #include "utils/lsyscache.h"
39 #include "utils/memutils.h"
40 #include "utils/rel.h"
41 
42 /*
43  * When an ordering operator is used, tuples fetched from the index that
44  * need to be reordered are queued in a pairing heap, as ReorderTuples.
45  */
46 typedef struct
47 {
48 	pairingheap_node ph_node;
49 	HeapTuple	htup;
50 	Datum	   *orderbyvals;
51 	bool	   *orderbynulls;
52 } ReorderTuple;
53 
54 static TupleTableSlot *IndexNext(IndexScanState *node);
55 static TupleTableSlot *IndexNextWithReorder(IndexScanState *node);
56 static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext);
57 static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot);
58 static int cmp_orderbyvals(const Datum *adist, const bool *anulls,
59 				const Datum *bdist, const bool *bnulls,
60 				IndexScanState *node);
61 static int reorderqueue_cmp(const pairingheap_node *a,
62 				 const pairingheap_node *b, void *arg);
63 static void reorderqueue_push(IndexScanState *node, HeapTuple tuple,
64 				  Datum *orderbyvals, bool *orderbynulls);
65 static HeapTuple reorderqueue_pop(IndexScanState *node);
66 
67 
68 /* ----------------------------------------------------------------
69  *		IndexNext
70  *
71  *		Retrieve a tuple from the IndexScan node's currentRelation
72  *		using the index specified in the IndexScanState information.
73  * ----------------------------------------------------------------
74  */
75 static TupleTableSlot *
IndexNext(IndexScanState * node)76 IndexNext(IndexScanState *node)
77 {
78 	EState	   *estate;
79 	ExprContext *econtext;
80 	ScanDirection direction;
81 	IndexScanDesc scandesc;
82 	HeapTuple	tuple;
83 	TupleTableSlot *slot;
84 
85 	/*
86 	 * extract necessary information from index scan node
87 	 */
88 	estate = node->ss.ps.state;
89 	direction = estate->es_direction;
90 	/* flip direction if this is an overall backward scan */
91 	if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
92 	{
93 		if (ScanDirectionIsForward(direction))
94 			direction = BackwardScanDirection;
95 		else if (ScanDirectionIsBackward(direction))
96 			direction = ForwardScanDirection;
97 	}
98 	scandesc = node->iss_ScanDesc;
99 	econtext = node->ss.ps.ps_ExprContext;
100 	slot = node->ss.ss_ScanTupleSlot;
101 
102 	/*
103 	 * ok, now that we have what we need, fetch the next tuple.
104 	 */
105 	while ((tuple = index_getnext(scandesc, direction)) != NULL)
106 	{
107 		/*
108 		 * Store the scanned tuple in the scan tuple slot of the scan state.
109 		 * Note: we pass 'false' because tuples returned by amgetnext are
110 		 * pointers onto disk pages and must not be pfree()'d.
111 		 */
112 		ExecStoreTuple(tuple,	/* tuple to store */
113 					   slot,	/* slot to store in */
114 					   scandesc->xs_cbuf,		/* buffer containing tuple */
115 					   false);	/* don't pfree */
116 
117 		/*
118 		 * If the index was lossy, we have to recheck the index quals using
119 		 * the fetched tuple.
120 		 */
121 		if (scandesc->xs_recheck)
122 		{
123 			econtext->ecxt_scantuple = slot;
124 			ResetExprContext(econtext);
125 			if (!ExecQual(node->indexqualorig, econtext, false))
126 			{
127 				/* Fails recheck, so drop it and loop back for another */
128 				InstrCountFiltered2(node, 1);
129 				continue;
130 			}
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 	node->iss_ReachedEnd = true;
141 	return ExecClearTuple(slot);
142 }
143 
144 /* ----------------------------------------------------------------
145  *		IndexNextWithReorder
146  *
147  *		Like IndexNext, but this version can also re-check ORDER BY
148  *		expressions, and reorder the tuples as necessary.
149  * ----------------------------------------------------------------
150  */
151 static TupleTableSlot *
IndexNextWithReorder(IndexScanState * node)152 IndexNextWithReorder(IndexScanState *node)
153 {
154 	ExprContext *econtext;
155 	IndexScanDesc scandesc;
156 	HeapTuple	tuple;
157 	TupleTableSlot *slot;
158 	ReorderTuple *topmost = NULL;
159 	bool		was_exact;
160 	Datum	   *lastfetched_vals;
161 	bool	   *lastfetched_nulls;
162 	int			cmp;
163 
164 	/*
165 	 * Only forward scan is supported with reordering.  Note: we can get away
166 	 * with just Asserting here because the system will not try to run the
167 	 * plan backwards if ExecSupportsBackwardScan() says it won't work.
168 	 * Currently, that is guaranteed because no index AMs support both
169 	 * amcanorderbyop and amcanbackward; if any ever do,
170 	 * ExecSupportsBackwardScan() will need to consider indexorderbys
171 	 * explicitly.
172 	 */
173 	Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
174 	Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
175 
176 	scandesc = node->iss_ScanDesc;
177 	econtext = node->ss.ps.ps_ExprContext;
178 	slot = node->ss.ss_ScanTupleSlot;
179 
180 	for (;;)
181 	{
182 		/*
183 		 * Check the reorder queue first.  If the topmost tuple in the queue
184 		 * has an ORDER BY value smaller than (or equal to) the value last
185 		 * returned by the index, we can return it now.
186 		 */
187 		if (!pairingheap_is_empty(node->iss_ReorderQueue))
188 		{
189 			topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
190 
191 			if (node->iss_ReachedEnd ||
192 				cmp_orderbyvals(topmost->orderbyvals,
193 								topmost->orderbynulls,
194 								scandesc->xs_orderbyvals,
195 								scandesc->xs_orderbynulls,
196 								node) <= 0)
197 			{
198 				tuple = reorderqueue_pop(node);
199 
200 				/* Pass 'true', as the tuple in the queue is a palloc'd copy */
201 				ExecStoreTuple(tuple, slot, InvalidBuffer, true);
202 				return slot;
203 			}
204 		}
205 		else if (node->iss_ReachedEnd)
206 		{
207 			/* Queue is empty, and no more tuples from index.  We're done. */
208 			return ExecClearTuple(slot);
209 		}
210 
211 		/*
212 		 * Fetch next tuple from the index.
213 		 */
214 next_indextuple:
215 		tuple = index_getnext(scandesc, ForwardScanDirection);
216 		if (!tuple)
217 		{
218 			/*
219 			 * No more tuples from the index.  But we still need to drain any
220 			 * remaining tuples from the queue before we're done.
221 			 */
222 			node->iss_ReachedEnd = true;
223 			continue;
224 		}
225 
226 		/*
227 		 * Store the scanned tuple in the scan tuple slot of the scan state.
228 		 * Note: we pass 'false' because tuples returned by amgetnext are
229 		 * pointers onto disk pages and must not be pfree()'d.
230 		 */
231 		ExecStoreTuple(tuple,	/* tuple to store */
232 					   slot,	/* slot to store in */
233 					   scandesc->xs_cbuf,		/* buffer containing tuple */
234 					   false);	/* don't pfree */
235 
236 		/*
237 		 * If the index was lossy, we have to recheck the index quals and
238 		 * ORDER BY expressions using the fetched tuple.
239 		 */
240 		if (scandesc->xs_recheck)
241 		{
242 			econtext->ecxt_scantuple = slot;
243 			ResetExprContext(econtext);
244 			if (!ExecQual(node->indexqualorig, econtext, false))
245 			{
246 				/* Fails recheck, so drop it and loop back for another */
247 				InstrCountFiltered2(node, 1);
248 				goto next_indextuple;
249 			}
250 		}
251 
252 		if (scandesc->xs_recheckorderby)
253 		{
254 			econtext->ecxt_scantuple = slot;
255 			ResetExprContext(econtext);
256 			EvalOrderByExpressions(node, econtext);
257 
258 			/*
259 			 * Was the ORDER BY value returned by the index accurate?  The
260 			 * recheck flag means that the index can return inaccurate values,
261 			 * but then again, the value returned for any particular tuple
262 			 * could also be exactly correct.  Compare the value returned by
263 			 * the index with the recalculated value.  (If the value returned
264 			 * by the index happened to be exact right, we can often avoid
265 			 * pushing the tuple to the queue, just to pop it back out again.)
266 			 */
267 			cmp = cmp_orderbyvals(node->iss_OrderByValues,
268 								  node->iss_OrderByNulls,
269 								  scandesc->xs_orderbyvals,
270 								  scandesc->xs_orderbynulls,
271 								  node);
272 			if (cmp < 0)
273 				elog(ERROR, "index returned tuples in wrong order");
274 			else if (cmp == 0)
275 				was_exact = true;
276 			else
277 				was_exact = false;
278 			lastfetched_vals = node->iss_OrderByValues;
279 			lastfetched_nulls = node->iss_OrderByNulls;
280 		}
281 		else
282 		{
283 			was_exact = true;
284 			lastfetched_vals = scandesc->xs_orderbyvals;
285 			lastfetched_nulls = scandesc->xs_orderbynulls;
286 		}
287 
288 		/*
289 		 * Can we return this tuple immediately, or does it need to be pushed
290 		 * to the reorder queue?  If the ORDER BY expression values returned
291 		 * by the index were inaccurate, we can't return it yet, because the
292 		 * next tuple from the index might need to come before this one. Also,
293 		 * we can't return it yet if there are any smaller tuples in the queue
294 		 * already.
295 		 */
296 		if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals,
297 													  lastfetched_nulls,
298 													  topmost->orderbyvals,
299 													  topmost->orderbynulls,
300 													  node) > 0))
301 		{
302 			/* Put this tuple to the queue */
303 			reorderqueue_push(node, tuple, lastfetched_vals, lastfetched_nulls);
304 			continue;
305 		}
306 		else
307 		{
308 			/* Can return this tuple immediately. */
309 			return slot;
310 		}
311 	}
312 
313 	/*
314 	 * if we get here it means the index scan failed so we are at the end of
315 	 * the scan..
316 	 */
317 	return ExecClearTuple(slot);
318 }
319 
320 /*
321  * Calculate the expressions in the ORDER BY clause, based on the heap tuple.
322  */
323 static void
EvalOrderByExpressions(IndexScanState * node,ExprContext * econtext)324 EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
325 {
326 	int			i;
327 	ListCell   *l;
328 	MemoryContext oldContext;
329 
330 	oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
331 
332 	i = 0;
333 	foreach(l, node->indexorderbyorig)
334 	{
335 		ExprState  *orderby = (ExprState *) lfirst(l);
336 
337 		node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
338 												  econtext,
339 												  &node->iss_OrderByNulls[i],
340 												  NULL);
341 		i++;
342 	}
343 
344 	MemoryContextSwitchTo(oldContext);
345 }
346 
347 /*
348  * IndexRecheck -- access method routine to recheck a tuple in EvalPlanQual
349  */
350 static bool
IndexRecheck(IndexScanState * node,TupleTableSlot * slot)351 IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
352 {
353 	ExprContext *econtext;
354 
355 	/*
356 	 * extract necessary information from index scan node
357 	 */
358 	econtext = node->ss.ps.ps_ExprContext;
359 
360 	/* Does the tuple meet the indexqual condition? */
361 	econtext->ecxt_scantuple = slot;
362 
363 	ResetExprContext(econtext);
364 
365 	return ExecQual(node->indexqualorig, econtext, false);
366 }
367 
368 
369 /*
370  * Compare ORDER BY expression values.
371  */
372 static int
cmp_orderbyvals(const Datum * adist,const bool * anulls,const Datum * bdist,const bool * bnulls,IndexScanState * node)373 cmp_orderbyvals(const Datum *adist, const bool *anulls,
374 				const Datum *bdist, const bool *bnulls,
375 				IndexScanState *node)
376 {
377 	int			i;
378 	int			result;
379 
380 	for (i = 0; i < node->iss_NumOrderByKeys; i++)
381 	{
382 		SortSupport ssup = &node->iss_SortSupport[i];
383 
384 		/*
385 		 * Handle nulls.  We only need to support NULLS LAST ordering, because
386 		 * match_pathkeys_to_index() doesn't consider indexorderby
387 		 * implementation otherwise.
388 		 */
389 		if (anulls[i] && !bnulls[i])
390 			return 1;
391 		else if (!anulls[i] && bnulls[i])
392 			return -1;
393 		else if (anulls[i] && bnulls[i])
394 			return 0;
395 
396 		result = ssup->comparator(adist[i], bdist[i], ssup);
397 		if (result != 0)
398 			return result;
399 	}
400 
401 	return 0;
402 }
403 
404 /*
405  * Pairing heap provides getting topmost (greatest) element while KNN provides
406  * ascending sort.  That's why we invert the sort order.
407  */
408 static int
reorderqueue_cmp(const pairingheap_node * a,const pairingheap_node * b,void * arg)409 reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b,
410 				 void *arg)
411 {
412 	ReorderTuple *rta = (ReorderTuple *) a;
413 	ReorderTuple *rtb = (ReorderTuple *) b;
414 	IndexScanState *node = (IndexScanState *) arg;
415 
416 	/* exchange argument order to invert the sort order */
417 	return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls,
418 						   rta->orderbyvals, rta->orderbynulls,
419 						   node);
420 }
421 
422 /*
423  * Helper function to push a tuple to the reorder queue.
424  */
425 static void
reorderqueue_push(IndexScanState * node,HeapTuple tuple,Datum * orderbyvals,bool * orderbynulls)426 reorderqueue_push(IndexScanState *node, HeapTuple tuple,
427 				  Datum *orderbyvals, bool *orderbynulls)
428 {
429 	IndexScanDesc scandesc = node->iss_ScanDesc;
430 	EState	   *estate = node->ss.ps.state;
431 	MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
432 	ReorderTuple *rt;
433 	int			i;
434 
435 	rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
436 	rt->htup = heap_copytuple(tuple);
437 	rt->orderbyvals =
438 		(Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
439 	rt->orderbynulls =
440 		(bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
441 	for (i = 0; i < node->iss_NumOrderByKeys; i++)
442 	{
443 		if (!orderbynulls[i])
444 			rt->orderbyvals[i] = datumCopy(orderbyvals[i],
445 										   node->iss_OrderByTypByVals[i],
446 										   node->iss_OrderByTypLens[i]);
447 		else
448 			rt->orderbyvals[i] = (Datum) 0;
449 		rt->orderbynulls[i] = orderbynulls[i];
450 	}
451 	pairingheap_add(node->iss_ReorderQueue, &rt->ph_node);
452 
453 	MemoryContextSwitchTo(oldContext);
454 }
455 
456 /*
457  * Helper function to pop the next tuple from the reorder queue.
458  */
459 static HeapTuple
reorderqueue_pop(IndexScanState * node)460 reorderqueue_pop(IndexScanState *node)
461 {
462 	HeapTuple	result;
463 	ReorderTuple *topmost;
464 	int			i;
465 
466 	topmost = (ReorderTuple *) pairingheap_remove_first(node->iss_ReorderQueue);
467 
468 	result = topmost->htup;
469 	for (i = 0; i < node->iss_NumOrderByKeys; i++)
470 	{
471 		if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
472 			pfree(DatumGetPointer(topmost->orderbyvals[i]));
473 	}
474 	pfree(topmost->orderbyvals);
475 	pfree(topmost->orderbynulls);
476 	pfree(topmost);
477 
478 	return result;
479 }
480 
481 
482 /* ----------------------------------------------------------------
483  *		ExecIndexScan(node)
484  * ----------------------------------------------------------------
485  */
486 TupleTableSlot *
ExecIndexScan(IndexScanState * node)487 ExecIndexScan(IndexScanState *node)
488 {
489 	/*
490 	 * If we have runtime keys and they've not already been set up, do it now.
491 	 */
492 	if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
493 		ExecReScan((PlanState *) node);
494 
495 	if (node->iss_NumOrderByKeys > 0)
496 		return ExecScan(&node->ss,
497 						(ExecScanAccessMtd) IndexNextWithReorder,
498 						(ExecScanRecheckMtd) IndexRecheck);
499 	else
500 		return ExecScan(&node->ss,
501 						(ExecScanAccessMtd) IndexNext,
502 						(ExecScanRecheckMtd) IndexRecheck);
503 }
504 
505 /* ----------------------------------------------------------------
506  *		ExecReScanIndexScan(node)
507  *
508  *		Recalculates the values of any scan keys whose value depends on
509  *		information known at runtime, then rescans the indexed relation.
510  *
511  *		Updating the scan key was formerly done separately in
512  *		ExecUpdateIndexScanKeys. Integrating it into ReScan makes
513  *		rescans of indices and relations/general streams more uniform.
514  * ----------------------------------------------------------------
515  */
516 void
ExecReScanIndexScan(IndexScanState * node)517 ExecReScanIndexScan(IndexScanState *node)
518 {
519 	/*
520 	 * If we are doing runtime key calculations (ie, any of the index key
521 	 * values weren't simple Consts), compute the new key values.  But first,
522 	 * reset the context so we don't leak memory as each outer tuple is
523 	 * scanned.  Note this assumes that we will recalculate *all* runtime keys
524 	 * on each call.
525 	 */
526 	if (node->iss_NumRuntimeKeys != 0)
527 	{
528 		ExprContext *econtext = node->iss_RuntimeContext;
529 
530 		ResetExprContext(econtext);
531 		ExecIndexEvalRuntimeKeys(econtext,
532 								 node->iss_RuntimeKeys,
533 								 node->iss_NumRuntimeKeys);
534 	}
535 	node->iss_RuntimeKeysReady = true;
536 
537 	/* flush the reorder queue */
538 	if (node->iss_ReorderQueue)
539 	{
540 		while (!pairingheap_is_empty(node->iss_ReorderQueue))
541 			reorderqueue_pop(node);
542 	}
543 
544 	/* reset index scan */
545 	index_rescan(node->iss_ScanDesc,
546 				 node->iss_ScanKeys, node->iss_NumScanKeys,
547 				 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
548 	node->iss_ReachedEnd = false;
549 
550 	ExecScanReScan(&node->ss);
551 }
552 
553 
554 /*
555  * ExecIndexEvalRuntimeKeys
556  *		Evaluate any runtime key values, and update the scankeys.
557  */
558 void
ExecIndexEvalRuntimeKeys(ExprContext * econtext,IndexRuntimeKeyInfo * runtimeKeys,int numRuntimeKeys)559 ExecIndexEvalRuntimeKeys(ExprContext *econtext,
560 						 IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
561 {
562 	int			j;
563 	MemoryContext oldContext;
564 
565 	/* We want to keep the key values in per-tuple memory */
566 	oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
567 
568 	for (j = 0; j < numRuntimeKeys; j++)
569 	{
570 		ScanKey		scan_key = runtimeKeys[j].scan_key;
571 		ExprState  *key_expr = runtimeKeys[j].key_expr;
572 		Datum		scanvalue;
573 		bool		isNull;
574 
575 		/*
576 		 * For each run-time key, extract the run-time expression and evaluate
577 		 * it with respect to the current context.  We then stick the result
578 		 * into the proper scan key.
579 		 *
580 		 * Note: the result of the eval could be a pass-by-ref value that's
581 		 * stored in some outer scan's tuple, not in
582 		 * econtext->ecxt_per_tuple_memory.  We assume that the outer tuple
583 		 * will stay put throughout our scan.  If this is wrong, we could copy
584 		 * the result into our context explicitly, but I think that's not
585 		 * necessary.
586 		 *
587 		 * It's also entirely possible that the result of the eval is a
588 		 * toasted value.  In this case we should forcibly detoast it, to
589 		 * avoid repeat detoastings each time the value is examined by an
590 		 * index support function.
591 		 */
592 		scanvalue = ExecEvalExpr(key_expr,
593 								 econtext,
594 								 &isNull,
595 								 NULL);
596 		if (isNull)
597 		{
598 			scan_key->sk_argument = scanvalue;
599 			scan_key->sk_flags |= SK_ISNULL;
600 		}
601 		else
602 		{
603 			if (runtimeKeys[j].key_toastable)
604 				scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
605 			scan_key->sk_argument = scanvalue;
606 			scan_key->sk_flags &= ~SK_ISNULL;
607 		}
608 	}
609 
610 	MemoryContextSwitchTo(oldContext);
611 }
612 
613 /*
614  * ExecIndexEvalArrayKeys
615  *		Evaluate any array key values, and set up to iterate through arrays.
616  *
617  * Returns TRUE if there are array elements to consider; FALSE means there
618  * is at least one null or empty array, so no match is possible.  On TRUE
619  * result, the scankeys are initialized with the first elements of the arrays.
620  */
621 bool
ExecIndexEvalArrayKeys(ExprContext * econtext,IndexArrayKeyInfo * arrayKeys,int numArrayKeys)622 ExecIndexEvalArrayKeys(ExprContext *econtext,
623 					   IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
624 {
625 	bool		result = true;
626 	int			j;
627 	MemoryContext oldContext;
628 
629 	/* We want to keep the arrays in per-tuple memory */
630 	oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
631 
632 	for (j = 0; j < numArrayKeys; j++)
633 	{
634 		ScanKey		scan_key = arrayKeys[j].scan_key;
635 		ExprState  *array_expr = arrayKeys[j].array_expr;
636 		Datum		arraydatum;
637 		bool		isNull;
638 		ArrayType  *arrayval;
639 		int16		elmlen;
640 		bool		elmbyval;
641 		char		elmalign;
642 		int			num_elems;
643 		Datum	   *elem_values;
644 		bool	   *elem_nulls;
645 
646 		/*
647 		 * Compute and deconstruct the array expression. (Notes in
648 		 * ExecIndexEvalRuntimeKeys() apply here too.)
649 		 */
650 		arraydatum = ExecEvalExpr(array_expr,
651 								  econtext,
652 								  &isNull,
653 								  NULL);
654 		if (isNull)
655 		{
656 			result = false;
657 			break;				/* no point in evaluating more */
658 		}
659 		arrayval = DatumGetArrayTypeP(arraydatum);
660 		/* We could cache this data, but not clear it's worth it */
661 		get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
662 							 &elmlen, &elmbyval, &elmalign);
663 		deconstruct_array(arrayval,
664 						  ARR_ELEMTYPE(arrayval),
665 						  elmlen, elmbyval, elmalign,
666 						  &elem_values, &elem_nulls, &num_elems);
667 		if (num_elems <= 0)
668 		{
669 			result = false;
670 			break;				/* no point in evaluating more */
671 		}
672 
673 		/*
674 		 * Note: we expect the previous array data, if any, to be
675 		 * automatically freed by resetting the per-tuple context; hence no
676 		 * pfree's here.
677 		 */
678 		arrayKeys[j].elem_values = elem_values;
679 		arrayKeys[j].elem_nulls = elem_nulls;
680 		arrayKeys[j].num_elems = num_elems;
681 		scan_key->sk_argument = elem_values[0];
682 		if (elem_nulls[0])
683 			scan_key->sk_flags |= SK_ISNULL;
684 		else
685 			scan_key->sk_flags &= ~SK_ISNULL;
686 		arrayKeys[j].next_elem = 1;
687 	}
688 
689 	MemoryContextSwitchTo(oldContext);
690 
691 	return result;
692 }
693 
694 /*
695  * ExecIndexAdvanceArrayKeys
696  *		Advance to the next set of array key values, if any.
697  *
698  * Returns TRUE if there is another set of values to consider, FALSE if not.
699  * On TRUE result, the scankeys are initialized with the next set of values.
700  */
701 bool
ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo * arrayKeys,int numArrayKeys)702 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
703 {
704 	bool		found = false;
705 	int			j;
706 
707 	/*
708 	 * Note we advance the rightmost array key most quickly, since it will
709 	 * correspond to the lowest-order index column among the available
710 	 * qualifications.  This is hypothesized to result in better locality of
711 	 * access in the index.
712 	 */
713 	for (j = numArrayKeys - 1; j >= 0; j--)
714 	{
715 		ScanKey		scan_key = arrayKeys[j].scan_key;
716 		int			next_elem = arrayKeys[j].next_elem;
717 		int			num_elems = arrayKeys[j].num_elems;
718 		Datum	   *elem_values = arrayKeys[j].elem_values;
719 		bool	   *elem_nulls = arrayKeys[j].elem_nulls;
720 
721 		if (next_elem >= num_elems)
722 		{
723 			next_elem = 0;
724 			found = false;		/* need to advance next array key */
725 		}
726 		else
727 			found = true;
728 		scan_key->sk_argument = elem_values[next_elem];
729 		if (elem_nulls[next_elem])
730 			scan_key->sk_flags |= SK_ISNULL;
731 		else
732 			scan_key->sk_flags &= ~SK_ISNULL;
733 		arrayKeys[j].next_elem = next_elem + 1;
734 		if (found)
735 			break;
736 	}
737 
738 	return found;
739 }
740 
741 
742 /* ----------------------------------------------------------------
743  *		ExecEndIndexScan
744  * ----------------------------------------------------------------
745  */
746 void
ExecEndIndexScan(IndexScanState * node)747 ExecEndIndexScan(IndexScanState *node)
748 {
749 	Relation	indexRelationDesc;
750 	IndexScanDesc indexScanDesc;
751 	Relation	relation;
752 
753 	/*
754 	 * extract information from the node
755 	 */
756 	indexRelationDesc = node->iss_RelationDesc;
757 	indexScanDesc = node->iss_ScanDesc;
758 	relation = node->ss.ss_currentRelation;
759 
760 	/*
761 	 * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
762 	 */
763 #ifdef NOT_USED
764 	ExecFreeExprContext(&node->ss.ps);
765 	if (node->iss_RuntimeContext)
766 		FreeExprContext(node->iss_RuntimeContext, true);
767 #endif
768 
769 	/*
770 	 * clear out tuple table slots
771 	 */
772 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
773 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
774 
775 	/*
776 	 * close the index relation (no-op if we didn't open it)
777 	 */
778 	if (indexScanDesc)
779 		index_endscan(indexScanDesc);
780 	if (indexRelationDesc)
781 		index_close(indexRelationDesc, NoLock);
782 
783 	/*
784 	 * close the heap relation.
785 	 */
786 	ExecCloseScanRelation(relation);
787 }
788 
789 /* ----------------------------------------------------------------
790  *		ExecIndexMarkPos
791  * ----------------------------------------------------------------
792  */
793 void
ExecIndexMarkPos(IndexScanState * node)794 ExecIndexMarkPos(IndexScanState *node)
795 {
796 	index_markpos(node->iss_ScanDesc);
797 }
798 
799 /* ----------------------------------------------------------------
800  *		ExecIndexRestrPos
801  * ----------------------------------------------------------------
802  */
803 void
ExecIndexRestrPos(IndexScanState * node)804 ExecIndexRestrPos(IndexScanState *node)
805 {
806 	index_restrpos(node->iss_ScanDesc);
807 }
808 
809 /* ----------------------------------------------------------------
810  *		ExecInitIndexScan
811  *
812  *		Initializes the index scan's state information, creates
813  *		scan keys, and opens the base and index relations.
814  *
815  *		Note: index scans have 2 sets of state information because
816  *			  we have to keep track of the base relation and the
817  *			  index relation.
818  * ----------------------------------------------------------------
819  */
820 IndexScanState *
ExecInitIndexScan(IndexScan * node,EState * estate,int eflags)821 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
822 {
823 	IndexScanState *indexstate;
824 	Relation	currentRelation;
825 	bool		relistarget;
826 
827 	/*
828 	 * create state structure
829 	 */
830 	indexstate = makeNode(IndexScanState);
831 	indexstate->ss.ps.plan = (Plan *) node;
832 	indexstate->ss.ps.state = estate;
833 
834 	/*
835 	 * Miscellaneous initialization
836 	 *
837 	 * create expression context for node
838 	 */
839 	ExecAssignExprContext(estate, &indexstate->ss.ps);
840 
841 	indexstate->ss.ps.ps_TupFromTlist = false;
842 
843 	/*
844 	 * initialize child expressions
845 	 *
846 	 * Note: we don't initialize all of the indexqual expression, only the
847 	 * sub-parts corresponding to runtime keys (see below).  Likewise for
848 	 * indexorderby, if any.  But the indexqualorig expression is always
849 	 * initialized even though it will only be used in some uncommon cases ---
850 	 * would be nice to improve that.  (Problem is that any SubPlans present
851 	 * in the expression must be found now...)
852 	 */
853 	indexstate->ss.ps.targetlist = (List *)
854 		ExecInitExpr((Expr *) node->scan.plan.targetlist,
855 					 (PlanState *) indexstate);
856 	indexstate->ss.ps.qual = (List *)
857 		ExecInitExpr((Expr *) node->scan.plan.qual,
858 					 (PlanState *) indexstate);
859 	indexstate->indexqualorig = (List *)
860 		ExecInitExpr((Expr *) node->indexqualorig,
861 					 (PlanState *) indexstate);
862 	indexstate->indexorderbyorig = (List *)
863 		ExecInitExpr((Expr *) node->indexorderbyorig,
864 					 (PlanState *) indexstate);
865 
866 	/*
867 	 * tuple table initialization
868 	 */
869 	ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
870 	ExecInitScanTupleSlot(estate, &indexstate->ss);
871 
872 	/*
873 	 * open the base relation and acquire appropriate lock on it.
874 	 */
875 	currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
876 
877 	indexstate->ss.ss_currentRelation = currentRelation;
878 	indexstate->ss.ss_currentScanDesc = NULL;	/* no heap scan here */
879 
880 	/*
881 	 * get the scan type from the relation descriptor.
882 	 */
883 	ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
884 
885 	/*
886 	 * Initialize result tuple type and projection info.
887 	 */
888 	ExecAssignResultTypeFromTL(&indexstate->ss.ps);
889 	ExecAssignScanProjectionInfo(&indexstate->ss);
890 
891 	/*
892 	 * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
893 	 * here.  This allows an index-advisor plugin to EXPLAIN a plan containing
894 	 * references to nonexistent indexes.
895 	 */
896 	if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
897 		return indexstate;
898 
899 	/*
900 	 * Open the index relation.
901 	 *
902 	 * If the parent table is one of the target relations of the query, then
903 	 * InitPlan already opened and write-locked the index, so we can avoid
904 	 * taking another lock here.  Otherwise we need a normal reader's lock.
905 	 */
906 	relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
907 	indexstate->iss_RelationDesc = index_open(node->indexid,
908 									 relistarget ? NoLock : AccessShareLock);
909 
910 	/*
911 	 * Initialize index-specific scan state
912 	 */
913 	indexstate->iss_RuntimeKeysReady = false;
914 	indexstate->iss_RuntimeKeys = NULL;
915 	indexstate->iss_NumRuntimeKeys = 0;
916 
917 	/*
918 	 * build the index scan keys from the index qualification
919 	 */
920 	ExecIndexBuildScanKeys((PlanState *) indexstate,
921 						   indexstate->iss_RelationDesc,
922 						   node->indexqual,
923 						   false,
924 						   &indexstate->iss_ScanKeys,
925 						   &indexstate->iss_NumScanKeys,
926 						   &indexstate->iss_RuntimeKeys,
927 						   &indexstate->iss_NumRuntimeKeys,
928 						   NULL,	/* no ArrayKeys */
929 						   NULL);
930 
931 	/*
932 	 * any ORDER BY exprs have to be turned into scankeys in the same way
933 	 */
934 	ExecIndexBuildScanKeys((PlanState *) indexstate,
935 						   indexstate->iss_RelationDesc,
936 						   node->indexorderby,
937 						   true,
938 						   &indexstate->iss_OrderByKeys,
939 						   &indexstate->iss_NumOrderByKeys,
940 						   &indexstate->iss_RuntimeKeys,
941 						   &indexstate->iss_NumRuntimeKeys,
942 						   NULL,	/* no ArrayKeys */
943 						   NULL);
944 
945 	/* Initialize sort support, if we need to re-check ORDER BY exprs */
946 	if (indexstate->iss_NumOrderByKeys > 0)
947 	{
948 		int			numOrderByKeys = indexstate->iss_NumOrderByKeys;
949 		int			i;
950 		ListCell   *lco;
951 		ListCell   *lcx;
952 
953 		/*
954 		 * Prepare sort support, and look up the data type for each ORDER BY
955 		 * expression.
956 		 */
957 		Assert(numOrderByKeys == list_length(node->indexorderbyops));
958 		Assert(numOrderByKeys == list_length(node->indexorderbyorig));
959 		indexstate->iss_SortSupport = (SortSupportData *)
960 			palloc0(numOrderByKeys * sizeof(SortSupportData));
961 		indexstate->iss_OrderByTypByVals = (bool *)
962 			palloc(numOrderByKeys * sizeof(bool));
963 		indexstate->iss_OrderByTypLens = (int16 *)
964 			palloc(numOrderByKeys * sizeof(int16));
965 		i = 0;
966 		forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
967 		{
968 			Oid			orderbyop = lfirst_oid(lco);
969 			Node	   *orderbyexpr = (Node *) lfirst(lcx);
970 			Oid			orderbyType = exprType(orderbyexpr);
971 			Oid			orderbyColl = exprCollation(orderbyexpr);
972 			SortSupport orderbysort = &indexstate->iss_SortSupport[i];
973 
974 			/* Initialize sort support */
975 			orderbysort->ssup_cxt = CurrentMemoryContext;
976 			orderbysort->ssup_collation = orderbyColl;
977 			/* See cmp_orderbyvals() comments on NULLS LAST */
978 			orderbysort->ssup_nulls_first = false;
979 			/* ssup_attno is unused here and elsewhere */
980 			orderbysort->ssup_attno = 0;
981 			/* No abbreviation */
982 			orderbysort->abbreviate = false;
983 			PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
984 
985 			get_typlenbyval(orderbyType,
986 							&indexstate->iss_OrderByTypLens[i],
987 							&indexstate->iss_OrderByTypByVals[i]);
988 			i++;
989 		}
990 
991 		/* allocate arrays to hold the re-calculated distances */
992 		indexstate->iss_OrderByValues = (Datum *)
993 			palloc(numOrderByKeys * sizeof(Datum));
994 		indexstate->iss_OrderByNulls = (bool *)
995 			palloc(numOrderByKeys * sizeof(bool));
996 
997 		/* and initialize the reorder queue */
998 		indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
999 															indexstate);
1000 	}
1001 
1002 	/*
1003 	 * If we have runtime keys, we need an ExprContext to evaluate them. The
1004 	 * node's standard context won't do because we want to reset that context
1005 	 * for every tuple.  So, build another context just like the other one...
1006 	 * -tgl 7/11/00
1007 	 */
1008 	if (indexstate->iss_NumRuntimeKeys != 0)
1009 	{
1010 		ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
1011 
1012 		ExecAssignExprContext(estate, &indexstate->ss.ps);
1013 		indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1014 		indexstate->ss.ps.ps_ExprContext = stdecontext;
1015 	}
1016 	else
1017 	{
1018 		indexstate->iss_RuntimeContext = NULL;
1019 	}
1020 
1021 	/*
1022 	 * Initialize scan descriptor.
1023 	 */
1024 	indexstate->iss_ScanDesc = index_beginscan(currentRelation,
1025 											   indexstate->iss_RelationDesc,
1026 											   estate->es_snapshot,
1027 											   indexstate->iss_NumScanKeys,
1028 											 indexstate->iss_NumOrderByKeys);
1029 
1030 	/*
1031 	 * If no run-time keys to calculate, go ahead and pass the scankeys to the
1032 	 * index AM.
1033 	 */
1034 	if (indexstate->iss_NumRuntimeKeys == 0)
1035 		index_rescan(indexstate->iss_ScanDesc,
1036 					 indexstate->iss_ScanKeys, indexstate->iss_NumScanKeys,
1037 				indexstate->iss_OrderByKeys, indexstate->iss_NumOrderByKeys);
1038 
1039 	/*
1040 	 * all done.
1041 	 */
1042 	return indexstate;
1043 }
1044 
1045 
1046 /*
1047  * ExecIndexBuildScanKeys
1048  *		Build the index scan keys from the index qualification expressions
1049  *
1050  * The index quals are passed to the index AM in the form of a ScanKey array.
1051  * This routine sets up the ScanKeys, fills in all constant fields of the
1052  * ScanKeys, and prepares information about the keys that have non-constant
1053  * comparison values.  We divide index qual expressions into five types:
1054  *
1055  * 1. Simple operator with constant comparison value ("indexkey op constant").
1056  * For these, we just fill in a ScanKey containing the constant value.
1057  *
1058  * 2. Simple operator with non-constant value ("indexkey op expression").
1059  * For these, we create a ScanKey with everything filled in except the
1060  * expression value, and set up an IndexRuntimeKeyInfo struct to drive
1061  * evaluation of the expression at the right times.
1062  *
1063  * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
1064  * For these, we create a header ScanKey plus a subsidiary ScanKey array,
1065  * as specified in access/skey.h.  The elements of the row comparison
1066  * can have either constant or non-constant comparison values.
1067  *
1068  * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)").  If the index
1069  * supports amsearcharray, we handle these the same as simple operators,
1070  * setting the SK_SEARCHARRAY flag to tell the AM to handle them.  Otherwise,
1071  * we create a ScanKey with everything filled in except the comparison value,
1072  * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
1073  * (Note that if we use an IndexArrayKeyInfo struct, the array expression is
1074  * always treated as requiring runtime evaluation, even if it's a constant.)
1075  *
1076  * 5. NullTest ("indexkey IS NULL/IS NOT NULL").  We just fill in the
1077  * ScanKey properly.
1078  *
1079  * This code is also used to prepare ORDER BY expressions for amcanorderbyop
1080  * indexes.  The behavior is exactly the same, except that we have to look up
1081  * the operator differently.  Note that only cases 1 and 2 are currently
1082  * possible for ORDER BY.
1083  *
1084  * Input params are:
1085  *
1086  * planstate: executor state node we are working for
1087  * index: the index we are building scan keys for
1088  * quals: indexquals (or indexorderbys) expressions
1089  * isorderby: true if processing ORDER BY exprs, false if processing quals
1090  * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none
1091  * *numRuntimeKeys: number of pre-existing runtime keys
1092  *
1093  * Output params are:
1094  *
1095  * *scanKeys: receives ptr to array of ScanKeys
1096  * *numScanKeys: receives number of scankeys
1097  * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
1098  * *numRuntimeKeys: receives number of runtime keys
1099  * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
1100  * *numArrayKeys: receives number of array keys
1101  *
1102  * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
1103  * IndexArrayKeyInfos are not supported.
1104  */
1105 void
ExecIndexBuildScanKeys(PlanState * planstate,Relation index,List * quals,bool isorderby,ScanKey * scanKeys,int * numScanKeys,IndexRuntimeKeyInfo ** runtimeKeys,int * numRuntimeKeys,IndexArrayKeyInfo ** arrayKeys,int * numArrayKeys)1106 ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
1107 					   List *quals, bool isorderby,
1108 					   ScanKey *scanKeys, int *numScanKeys,
1109 					   IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
1110 					   IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
1111 {
1112 	ListCell   *qual_cell;
1113 	ScanKey		scan_keys;
1114 	IndexRuntimeKeyInfo *runtime_keys;
1115 	IndexArrayKeyInfo *array_keys;
1116 	int			n_scan_keys;
1117 	int			n_runtime_keys;
1118 	int			max_runtime_keys;
1119 	int			n_array_keys;
1120 	int			j;
1121 
1122 	/* Allocate array for ScanKey structs: one per qual */
1123 	n_scan_keys = list_length(quals);
1124 	scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData));
1125 
1126 	/*
1127 	 * runtime_keys array is dynamically resized as needed.  We handle it this
1128 	 * way so that the same runtime keys array can be shared between
1129 	 * indexquals and indexorderbys, which will be processed in separate calls
1130 	 * of this function.  Caller must be sure to pass in NULL/0 for first
1131 	 * call.
1132 	 */
1133 	runtime_keys = *runtimeKeys;
1134 	n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
1135 
1136 	/* Allocate array_keys as large as it could possibly need to be */
1137 	array_keys = (IndexArrayKeyInfo *)
1138 		palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
1139 	n_array_keys = 0;
1140 
1141 	/*
1142 	 * for each opclause in the given qual, convert the opclause into a single
1143 	 * scan key
1144 	 */
1145 	j = 0;
1146 	foreach(qual_cell, quals)
1147 	{
1148 		Expr	   *clause = (Expr *) lfirst(qual_cell);
1149 		ScanKey		this_scan_key = &scan_keys[j++];
1150 		Oid			opno;		/* operator's OID */
1151 		RegProcedure opfuncid;	/* operator proc id used in scan */
1152 		Oid			opfamily;	/* opfamily of index column */
1153 		int			op_strategy;	/* operator's strategy number */
1154 		Oid			op_lefttype;	/* operator's declared input types */
1155 		Oid			op_righttype;
1156 		Expr	   *leftop;		/* expr on lhs of operator */
1157 		Expr	   *rightop;	/* expr on rhs ... */
1158 		AttrNumber	varattno;	/* att number used in scan */
1159 
1160 		if (IsA(clause, OpExpr))
1161 		{
1162 			/* indexkey op const or indexkey op expression */
1163 			int			flags = 0;
1164 			Datum		scanvalue;
1165 
1166 			opno = ((OpExpr *) clause)->opno;
1167 			opfuncid = ((OpExpr *) clause)->opfuncid;
1168 
1169 			/*
1170 			 * leftop should be the index key Var, possibly relabeled
1171 			 */
1172 			leftop = (Expr *) get_leftop(clause);
1173 
1174 			if (leftop && IsA(leftop, RelabelType))
1175 				leftop = ((RelabelType *) leftop)->arg;
1176 
1177 			Assert(leftop != NULL);
1178 
1179 			if (!(IsA(leftop, Var) &&
1180 				  ((Var *) leftop)->varno == INDEX_VAR))
1181 				elog(ERROR, "indexqual doesn't have key on left side");
1182 
1183 			varattno = ((Var *) leftop)->varattno;
1184 			if (varattno < 1 || varattno > index->rd_index->indnatts)
1185 				elog(ERROR, "bogus index qualification");
1186 
1187 			/*
1188 			 * We have to look up the operator's strategy number.  This
1189 			 * provides a cross-check that the operator does match the index.
1190 			 */
1191 			opfamily = index->rd_opfamily[varattno - 1];
1192 
1193 			get_op_opfamily_properties(opno, opfamily, isorderby,
1194 									   &op_strategy,
1195 									   &op_lefttype,
1196 									   &op_righttype);
1197 
1198 			if (isorderby)
1199 				flags |= SK_ORDER_BY;
1200 
1201 			/*
1202 			 * rightop is the constant or variable comparison value
1203 			 */
1204 			rightop = (Expr *) get_rightop(clause);
1205 
1206 			if (rightop && IsA(rightop, RelabelType))
1207 				rightop = ((RelabelType *) rightop)->arg;
1208 
1209 			Assert(rightop != NULL);
1210 
1211 			if (IsA(rightop, Const))
1212 			{
1213 				/* OK, simple constant comparison value */
1214 				scanvalue = ((Const *) rightop)->constvalue;
1215 				if (((Const *) rightop)->constisnull)
1216 					flags |= SK_ISNULL;
1217 			}
1218 			else
1219 			{
1220 				/* Need to treat this one as a runtime key */
1221 				if (n_runtime_keys >= max_runtime_keys)
1222 				{
1223 					if (max_runtime_keys == 0)
1224 					{
1225 						max_runtime_keys = 8;
1226 						runtime_keys = (IndexRuntimeKeyInfo *)
1227 							palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1228 					}
1229 					else
1230 					{
1231 						max_runtime_keys *= 2;
1232 						runtime_keys = (IndexRuntimeKeyInfo *)
1233 							repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1234 					}
1235 				}
1236 				runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1237 				runtime_keys[n_runtime_keys].key_expr =
1238 					ExecInitExpr(rightop, planstate);
1239 				runtime_keys[n_runtime_keys].key_toastable =
1240 					TypeIsToastable(op_righttype);
1241 				n_runtime_keys++;
1242 				scanvalue = (Datum) 0;
1243 			}
1244 
1245 			/*
1246 			 * initialize the scan key's fields appropriately
1247 			 */
1248 			ScanKeyEntryInitialize(this_scan_key,
1249 								   flags,
1250 								   varattno,	/* attribute number to scan */
1251 								   op_strategy, /* op's strategy */
1252 								   op_righttype,		/* strategy subtype */
1253 								   ((OpExpr *) clause)->inputcollid,	/* collation */
1254 								   opfuncid,	/* reg proc to use */
1255 								   scanvalue);	/* constant */
1256 		}
1257 		else if (IsA(clause, RowCompareExpr))
1258 		{
1259 			/* (indexkey, indexkey, ...) op (expression, expression, ...) */
1260 			RowCompareExpr *rc = (RowCompareExpr *) clause;
1261 			ListCell   *largs_cell = list_head(rc->largs);
1262 			ListCell   *rargs_cell = list_head(rc->rargs);
1263 			ListCell   *opnos_cell = list_head(rc->opnos);
1264 			ListCell   *collids_cell = list_head(rc->inputcollids);
1265 			ScanKey		first_sub_key;
1266 			int			n_sub_key;
1267 
1268 			Assert(!isorderby);
1269 
1270 			first_sub_key = (ScanKey)
1271 				palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
1272 			n_sub_key = 0;
1273 
1274 			/* Scan RowCompare columns and generate subsidiary ScanKey items */
1275 			while (opnos_cell != NULL)
1276 			{
1277 				ScanKey		this_sub_key = &first_sub_key[n_sub_key];
1278 				int			flags = SK_ROW_MEMBER;
1279 				Datum		scanvalue;
1280 				Oid			inputcollation;
1281 
1282 				/*
1283 				 * leftop should be the index key Var, possibly relabeled
1284 				 */
1285 				leftop = (Expr *) lfirst(largs_cell);
1286 				largs_cell = lnext(largs_cell);
1287 
1288 				if (leftop && IsA(leftop, RelabelType))
1289 					leftop = ((RelabelType *) leftop)->arg;
1290 
1291 				Assert(leftop != NULL);
1292 
1293 				if (!(IsA(leftop, Var) &&
1294 					  ((Var *) leftop)->varno == INDEX_VAR))
1295 					elog(ERROR, "indexqual doesn't have key on left side");
1296 
1297 				varattno = ((Var *) leftop)->varattno;
1298 
1299 				/*
1300 				 * We have to look up the operator's associated btree support
1301 				 * function
1302 				 */
1303 				opno = lfirst_oid(opnos_cell);
1304 				opnos_cell = lnext(opnos_cell);
1305 
1306 				if (index->rd_rel->relam != BTREE_AM_OID ||
1307 					varattno < 1 || varattno > index->rd_index->indnatts)
1308 					elog(ERROR, "bogus RowCompare index qualification");
1309 				opfamily = index->rd_opfamily[varattno - 1];
1310 
1311 				get_op_opfamily_properties(opno, opfamily, isorderby,
1312 										   &op_strategy,
1313 										   &op_lefttype,
1314 										   &op_righttype);
1315 
1316 				if (op_strategy != rc->rctype)
1317 					elog(ERROR, "RowCompare index qualification contains wrong operator");
1318 
1319 				opfuncid = get_opfamily_proc(opfamily,
1320 											 op_lefttype,
1321 											 op_righttype,
1322 											 BTORDER_PROC);
1323 
1324 				inputcollation = lfirst_oid(collids_cell);
1325 				collids_cell = lnext(collids_cell);
1326 
1327 				/*
1328 				 * rightop is the constant or variable comparison value
1329 				 */
1330 				rightop = (Expr *) lfirst(rargs_cell);
1331 				rargs_cell = lnext(rargs_cell);
1332 
1333 				if (rightop && IsA(rightop, RelabelType))
1334 					rightop = ((RelabelType *) rightop)->arg;
1335 
1336 				Assert(rightop != NULL);
1337 
1338 				if (IsA(rightop, Const))
1339 				{
1340 					/* OK, simple constant comparison value */
1341 					scanvalue = ((Const *) rightop)->constvalue;
1342 					if (((Const *) rightop)->constisnull)
1343 						flags |= SK_ISNULL;
1344 				}
1345 				else
1346 				{
1347 					/* Need to treat this one as a runtime key */
1348 					if (n_runtime_keys >= max_runtime_keys)
1349 					{
1350 						if (max_runtime_keys == 0)
1351 						{
1352 							max_runtime_keys = 8;
1353 							runtime_keys = (IndexRuntimeKeyInfo *)
1354 								palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1355 						}
1356 						else
1357 						{
1358 							max_runtime_keys *= 2;
1359 							runtime_keys = (IndexRuntimeKeyInfo *)
1360 								repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1361 						}
1362 					}
1363 					runtime_keys[n_runtime_keys].scan_key = this_sub_key;
1364 					runtime_keys[n_runtime_keys].key_expr =
1365 						ExecInitExpr(rightop, planstate);
1366 					runtime_keys[n_runtime_keys].key_toastable =
1367 						TypeIsToastable(op_righttype);
1368 					n_runtime_keys++;
1369 					scanvalue = (Datum) 0;
1370 				}
1371 
1372 				/*
1373 				 * initialize the subsidiary scan key's fields appropriately
1374 				 */
1375 				ScanKeyEntryInitialize(this_sub_key,
1376 									   flags,
1377 									   varattno,		/* attribute number */
1378 									   op_strategy,		/* op's strategy */
1379 									   op_righttype,	/* strategy subtype */
1380 									   inputcollation,	/* collation */
1381 									   opfuncid,		/* reg proc to use */
1382 									   scanvalue);		/* constant */
1383 				n_sub_key++;
1384 			}
1385 
1386 			/* Mark the last subsidiary scankey correctly */
1387 			first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
1388 
1389 			/*
1390 			 * We don't use ScanKeyEntryInitialize for the header because it
1391 			 * isn't going to contain a valid sk_func pointer.
1392 			 */
1393 			MemSet(this_scan_key, 0, sizeof(ScanKeyData));
1394 			this_scan_key->sk_flags = SK_ROW_HEADER;
1395 			this_scan_key->sk_attno = first_sub_key->sk_attno;
1396 			this_scan_key->sk_strategy = rc->rctype;
1397 			/* sk_subtype, sk_collation, sk_func not used in a header */
1398 			this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
1399 		}
1400 		else if (IsA(clause, ScalarArrayOpExpr))
1401 		{
1402 			/* indexkey op ANY (array-expression) */
1403 			ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1404 			int			flags = 0;
1405 			Datum		scanvalue;
1406 
1407 			Assert(!isorderby);
1408 
1409 			Assert(saop->useOr);
1410 			opno = saop->opno;
1411 			opfuncid = saop->opfuncid;
1412 
1413 			/*
1414 			 * leftop should be the index key Var, possibly relabeled
1415 			 */
1416 			leftop = (Expr *) linitial(saop->args);
1417 
1418 			if (leftop && IsA(leftop, RelabelType))
1419 				leftop = ((RelabelType *) leftop)->arg;
1420 
1421 			Assert(leftop != NULL);
1422 
1423 			if (!(IsA(leftop, Var) &&
1424 				  ((Var *) leftop)->varno == INDEX_VAR))
1425 				elog(ERROR, "indexqual doesn't have key on left side");
1426 
1427 			varattno = ((Var *) leftop)->varattno;
1428 			if (varattno < 1 || varattno > index->rd_index->indnatts)
1429 				elog(ERROR, "bogus index qualification");
1430 
1431 			/*
1432 			 * We have to look up the operator's strategy number.  This
1433 			 * provides a cross-check that the operator does match the index.
1434 			 */
1435 			opfamily = index->rd_opfamily[varattno - 1];
1436 
1437 			get_op_opfamily_properties(opno, opfamily, isorderby,
1438 									   &op_strategy,
1439 									   &op_lefttype,
1440 									   &op_righttype);
1441 
1442 			/*
1443 			 * rightop is the constant or variable array value
1444 			 */
1445 			rightop = (Expr *) lsecond(saop->args);
1446 
1447 			if (rightop && IsA(rightop, RelabelType))
1448 				rightop = ((RelabelType *) rightop)->arg;
1449 
1450 			Assert(rightop != NULL);
1451 
1452 			if (index->rd_amroutine->amsearcharray)
1453 			{
1454 				/* Index AM will handle this like a simple operator */
1455 				flags |= SK_SEARCHARRAY;
1456 				if (IsA(rightop, Const))
1457 				{
1458 					/* OK, simple constant comparison value */
1459 					scanvalue = ((Const *) rightop)->constvalue;
1460 					if (((Const *) rightop)->constisnull)
1461 						flags |= SK_ISNULL;
1462 				}
1463 				else
1464 				{
1465 					/* Need to treat this one as a runtime key */
1466 					if (n_runtime_keys >= max_runtime_keys)
1467 					{
1468 						if (max_runtime_keys == 0)
1469 						{
1470 							max_runtime_keys = 8;
1471 							runtime_keys = (IndexRuntimeKeyInfo *)
1472 								palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1473 						}
1474 						else
1475 						{
1476 							max_runtime_keys *= 2;
1477 							runtime_keys = (IndexRuntimeKeyInfo *)
1478 								repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1479 						}
1480 					}
1481 					runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1482 					runtime_keys[n_runtime_keys].key_expr =
1483 						ExecInitExpr(rightop, planstate);
1484 
1485 					/*
1486 					 * Careful here: the runtime expression is not of
1487 					 * op_righttype, but rather is an array of same; so
1488 					 * TypeIsToastable() isn't helpful.  However, we can
1489 					 * assume that all array types are toastable.
1490 					 */
1491 					runtime_keys[n_runtime_keys].key_toastable = true;
1492 					n_runtime_keys++;
1493 					scanvalue = (Datum) 0;
1494 				}
1495 			}
1496 			else
1497 			{
1498 				/* Executor has to expand the array value */
1499 				array_keys[n_array_keys].scan_key = this_scan_key;
1500 				array_keys[n_array_keys].array_expr =
1501 					ExecInitExpr(rightop, planstate);
1502 				/* the remaining fields were zeroed by palloc0 */
1503 				n_array_keys++;
1504 				scanvalue = (Datum) 0;
1505 			}
1506 
1507 			/*
1508 			 * initialize the scan key's fields appropriately
1509 			 */
1510 			ScanKeyEntryInitialize(this_scan_key,
1511 								   flags,
1512 								   varattno,	/* attribute number to scan */
1513 								   op_strategy, /* op's strategy */
1514 								   op_righttype,		/* strategy subtype */
1515 								   saop->inputcollid,	/* collation */
1516 								   opfuncid,	/* reg proc to use */
1517 								   scanvalue);	/* constant */
1518 		}
1519 		else if (IsA(clause, NullTest))
1520 		{
1521 			/* indexkey IS NULL or indexkey IS NOT NULL */
1522 			NullTest   *ntest = (NullTest *) clause;
1523 			int			flags;
1524 
1525 			Assert(!isorderby);
1526 
1527 			/*
1528 			 * argument should be the index key Var, possibly relabeled
1529 			 */
1530 			leftop = ntest->arg;
1531 
1532 			if (leftop && IsA(leftop, RelabelType))
1533 				leftop = ((RelabelType *) leftop)->arg;
1534 
1535 			Assert(leftop != NULL);
1536 
1537 			if (!(IsA(leftop, Var) &&
1538 				  ((Var *) leftop)->varno == INDEX_VAR))
1539 				elog(ERROR, "NullTest indexqual has wrong key");
1540 
1541 			varattno = ((Var *) leftop)->varattno;
1542 
1543 			/*
1544 			 * initialize the scan key's fields appropriately
1545 			 */
1546 			switch (ntest->nulltesttype)
1547 			{
1548 				case IS_NULL:
1549 					flags = SK_ISNULL | SK_SEARCHNULL;
1550 					break;
1551 				case IS_NOT_NULL:
1552 					flags = SK_ISNULL | SK_SEARCHNOTNULL;
1553 					break;
1554 				default:
1555 					elog(ERROR, "unrecognized nulltesttype: %d",
1556 						 (int) ntest->nulltesttype);
1557 					flags = 0;	/* keep compiler quiet */
1558 					break;
1559 			}
1560 
1561 			ScanKeyEntryInitialize(this_scan_key,
1562 								   flags,
1563 								   varattno,	/* attribute number to scan */
1564 								   InvalidStrategy,		/* no strategy */
1565 								   InvalidOid,	/* no strategy subtype */
1566 								   InvalidOid,	/* no collation */
1567 								   InvalidOid,	/* no reg proc for this */
1568 								   (Datum) 0);	/* constant */
1569 		}
1570 		else
1571 			elog(ERROR, "unsupported indexqual type: %d",
1572 				 (int) nodeTag(clause));
1573 	}
1574 
1575 	Assert(n_runtime_keys <= max_runtime_keys);
1576 
1577 	/* Get rid of any unused arrays */
1578 	if (n_array_keys == 0)
1579 	{
1580 		pfree(array_keys);
1581 		array_keys = NULL;
1582 	}
1583 
1584 	/*
1585 	 * Return info to our caller.
1586 	 */
1587 	*scanKeys = scan_keys;
1588 	*numScanKeys = n_scan_keys;
1589 	*runtimeKeys = runtime_keys;
1590 	*numRuntimeKeys = n_runtime_keys;
1591 	if (arrayKeys)
1592 	{
1593 		*arrayKeys = array_keys;
1594 		*numArrayKeys = n_array_keys;
1595 	}
1596 	else if (n_array_keys != 0)
1597 		elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1598 }
1599