istrat.c 17.6 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * istrat.c
4 5
 *	  index scan strategy manipulation code and index strategy manipulation
 *	  operator code.
6 7 8 9 10
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.33 1999/06/19 04:54:10 momjian Exp $
12 13 14 15
 *
 *-------------------------------------------------------------------------
 */

Bruce Momjian's avatar
Bruce Momjian committed
16
#include "postgres.h"
17

18
#include "miscadmin.h"
Bruce Momjian's avatar
Bruce Momjian committed
19 20 21 22 23 24 25
#include "access/heapam.h"
#include "access/istrat.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_index.h"
#include "catalog/pg_operator.h"
26
#include "utils/syscache.h"
Bruce Momjian's avatar
Bruce Momjian committed
27 28
#include "fmgr.h"
#include "utils/memutils.h"		/* could have been access/itup.h */
29

Bruce Momjian's avatar
Bruce Momjian committed
30
#ifdef USE_ASSERT_CHECKING
31
static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
32
static bool StrategyExpressionIsValid(StrategyExpression expression,
33
						  StrategyNumber maxStrategy);
34
static ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
35
						   StrategyNumber strategyNumber);
36
static bool StrategyOperatorIsValid(StrategyOperator operator,
37
						StrategyNumber maxStrategy);
38
static bool StrategyTermIsValid(StrategyTerm term,
39 40
					StrategyNumber maxStrategy);

Bruce Momjian's avatar
Bruce Momjian committed
41 42
#endif

43

44
/* ----------------------------------------------------------------
45
 *				   misc strategy support routines
46 47
 * ----------------------------------------------------------------
 */
48 49 50 51 52 53 54

/*
 *		StrategyNumberIsValid
 *		StrategyNumberIsInBounds
 *		StrategyMapIsValid
 *		StrategyTransformMapIsValid
 *		IndexStrategyIsValid
55
 *
56
 *				... are now macros in istrat.h -cim 4/27/91
57
 */
58

59
/*
Bruce Momjian's avatar
Bruce Momjian committed
60
 * StrategyMapGetScanKeyEntry
61
 *		Returns a scan key entry of a index strategy mapping member.
62 63
 *
 * Note:
64 65 66
 *		Assumes that the index strategy mapping is valid.
 *		Assumes that the index strategy number is valid.
 *		Bounds checking should be done outside this routine.
67
 */
68
static ScanKey
69
StrategyMapGetScanKeyEntry(StrategyMap map,
70
						   StrategyNumber strategyNumber)
71
{
72 73
	Assert(StrategyMapIsValid(map));
	Assert(StrategyNumberIsValid(strategyNumber));
74
	return &map->entry[strategyNumber - 1];
75 76 77
}

/*
Bruce Momjian's avatar
Bruce Momjian committed
78
 * IndexStrategyGetStrategyMap
79
 *		Returns an index strategy mapping of an index strategy.
80 81
 *
 * Note:
82 83 84
 *		Assumes that the index strategy is valid.
 *		Assumes that the number of index strategies is valid.
 *		Bounds checking should be done outside this routine.
85 86 87
 */
StrategyMap
IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
88 89
							StrategyNumber maxStrategyNum,
							AttrNumber attrNum)
90
{
91 92 93 94 95
	Assert(IndexStrategyIsValid(indexStrategy));
	Assert(StrategyNumberIsValid(maxStrategyNum));
	Assert(AttributeNumberIsValid(attrNum));

	maxStrategyNum = AMStrategies(maxStrategyNum);		/* XXX */
96
	return &indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)];
97 98 99
}

/*
Bruce Momjian's avatar
Bruce Momjian committed
100
 * AttributeNumberGetIndexStrategySize
101
 *		Computes the size of an index strategy.
102 103 104
 */
Size
AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
105
									StrategyNumber maxStrategyNumber)
106
{
107
	maxStrategyNumber = AMStrategies(maxStrategyNumber);		/* XXX */
108
	return maxAttributeNumber * maxStrategyNumber * sizeof(ScanKeyData);
109 110
}

Bruce Momjian's avatar
Bruce Momjian committed
111
#ifdef USE_ASSERT_CHECKING
112
/*
113 114 115 116
 * StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91
 */

/* ----------------
117
 *		StrategyOperatorIsValid
118 119
 * ----------------
 */
120
static bool
121
StrategyOperatorIsValid(StrategyOperator operator,
122
						StrategyNumber maxStrategy)
123
{
124
	return (bool)
125 126 127 128 129 130
	(PointerIsValid(operator) &&
	 StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
	 !(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
}

/* ----------------
131
 *		StrategyTermIsValid
132 133
 * ----------------
 */
134
static bool
135
StrategyTermIsValid(StrategyTerm term,
136
					StrategyNumber maxStrategy)
137
{
138
	Index		index;
139 140 141 142 143 144 145 146 147

	if (!PointerIsValid(term) || term->degree == 0)
		return false;

	for (index = 0; index < term->degree; index += 1)
	{
		if (!StrategyOperatorIsValid(&term->operatorData[index],
									 maxStrategy))
			return false;
148
	}
149 150

	return true;
151 152 153
}

/* ----------------
154
 *		StrategyExpressionIsValid
155 156
 * ----------------
 */
157
static bool
158
StrategyExpressionIsValid(StrategyExpression expression,
159
						  StrategyNumber maxStrategy)
160
{
161
	StrategyTerm *termP;
162 163 164 165 166 167 168 169 170 171 172 173 174

	if (!PointerIsValid(expression))
		return true;

	if (!StrategyTermIsValid(expression->term[0], maxStrategy))
		return false;

	termP = &expression->term[1];
	while (StrategyTermIsValid(*termP, maxStrategy))
		termP += 1;

	return (bool)
		(!PointerIsValid(*termP));
175 176 177
}

/* ----------------
178
 *		StrategyEvaluationIsValid
179 180
 * ----------------
 */
181
static bool
182 183
StrategyEvaluationIsValid(StrategyEvaluation evaluation)
{
184
	Index		index;
185 186 187 188 189 190 191 192 193

	if (!PointerIsValid(evaluation) ||
		!StrategyNumberIsValid(evaluation->maxStrategy) ||
		!StrategyTransformMapIsValid(evaluation->negateTransform) ||
		!StrategyTransformMapIsValid(evaluation->commuteTransform) ||
		!StrategyTransformMapIsValid(evaluation->negateCommuteTransform))
	{

		return false;
194
	}
195 196 197 198 199 200 201 202 203 204 205

	for (index = 0; index < evaluation->maxStrategy; index += 1)
	{
		if (!StrategyExpressionIsValid(evaluation->expression[index],
									   evaluation->maxStrategy))
		{

			return false;
		}
	}
	return true;
206
}
207

Bruce Momjian's avatar
Bruce Momjian committed
208
#endif
209 210

/* ----------------
211
 *		StrategyTermEvaluate
212 213
 * ----------------
 */
214
static bool
215
StrategyTermEvaluate(StrategyTerm term,
216 217 218
					 StrategyMap map,
					 Datum left,
					 Datum right)
219
{
220 221 222
	Index		index;
	long		tmpres = 0;
	bool		result = 0;
223
	StrategyOperator operator;
224
	ScanKey		entry;
225 226 227 228 229 230 231 232 233 234 235

	for (index = 0, operator = &term->operatorData[0];
		 index < term->degree; index += 1, operator += 1)
	{

		entry = &map->entry[operator->strategy - 1];

		Assert(RegProcedureIsValid(entry->sk_procedure));

		switch (operator->flags ^ entry->sk_flags)
		{
236
			case 0x0:
237
				tmpres = (long) FMGR_PTR2(&entry->sk_func,
238 239 240 241
										  left, right);
				break;

			case SK_NEGATE:
242
				tmpres = (long) !FMGR_PTR2(&entry->sk_func,
243 244 245 246
										   left, right);
				break;

			case SK_COMMUTE:
247
				tmpres = (long) FMGR_PTR2(&entry->sk_func,
248 249 250 251
										  right, left);
				break;

			case SK_NEGATE | SK_COMMUTE:
252
				tmpres = (long) !FMGR_PTR2(&entry->sk_func,
253 254 255 256 257 258
										   right, left);
				break;

			default:
				elog(FATAL, "StrategyTermEvaluate: impossible case %d",
					 operator->flags ^ entry->sk_flags);
259 260 261 262 263
		}

		result = (bool) tmpres;
		if (!result)
			return result;
264
	}
265 266

	return result;
267 268 269 270
}


/* ----------------
271
 *		RelationGetStrategy
272 273 274 275
 * ----------------
 */
StrategyNumber
RelationGetStrategy(Relation relation,
276 277 278
					AttrNumber attributeNumber,
					StrategyEvaluation evaluation,
					RegProcedure procedure)
279
{
280 281 282 283 284
	StrategyNumber strategy;
	StrategyMap strategyMap;
	ScanKey		entry;
	Index		index;
	int			numattrs;
285 286 287 288 289 290 291 292 293 294 295

	Assert(RelationIsValid(relation));
	numattrs = RelationGetNumberOfAttributes(relation);

	Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
	Assert(AttributeNumberIsValid(attributeNumber));
	Assert((attributeNumber >= 1) && (attributeNumber < 1 + numattrs));

	Assert(StrategyEvaluationIsValid(evaluation));
	Assert(RegProcedureIsValid(procedure));

296
	strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
Bruce Momjian's avatar
Bruce Momjian committed
297 298
											  evaluation->maxStrategy,
											  attributeNumber);
299 300 301 302 303 304

	/* get a strategy number for the procedure ignoring flags for now */
	for (index = 0; index < evaluation->maxStrategy; index += 1)
	{
		if (strategyMap->entry[index].sk_procedure == procedure)
			break;
305
	}
306 307 308 309 310 311 312 313 314 315 316

	if (index == evaluation->maxStrategy)
		return InvalidStrategy;

	strategy = 1 + index;
	entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);

	Assert(!(entry->sk_flags & ~(SK_NEGATE | SK_COMMUTE)));

	switch (entry->sk_flags & (SK_NEGATE | SK_COMMUTE))
	{
317 318
		case 0x0:
			return strategy;
319

320 321 322
		case SK_NEGATE:
			strategy = evaluation->negateTransform->strategy[strategy - 1];
			break;
323

324 325 326
		case SK_COMMUTE:
			strategy = evaluation->commuteTransform->strategy[strategy - 1];
			break;
327

328 329 330
		case SK_NEGATE | SK_COMMUTE:
			strategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
			break;
331

332 333
		default:
			elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags);
334
	}
335 336 337 338 339


	if (!StrategyNumberIsInBounds(strategy, evaluation->maxStrategy))
	{
		if (!StrategyNumberIsValid(strategy))
340
			elog(ERROR, "RelationGetStrategy: corrupted evaluation");
341 342 343
	}

	return strategy;
344 345 346
}

/* ----------------
347
 *		RelationInvokeStrategy
348 349
 * ----------------
 */
350
bool							/* XXX someday, this may return Datum */
351
RelationInvokeStrategy(Relation relation,
352 353 354 355 356
					   StrategyEvaluation evaluation,
					   AttrNumber attributeNumber,
					   StrategyNumber strategy,
					   Datum left,
					   Datum right)
357
{
358 359 360
	StrategyNumber newStrategy;
	StrategyMap strategyMap;
	ScanKey		entry;
361
	StrategyTermData termData;
362
	int			numattrs;
363 364 365 366 367 368 369 370 371 372 373 374 375

	Assert(RelationIsValid(relation));
	Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
	numattrs = RelationGetNumberOfAttributes(relation);

	Assert(StrategyEvaluationIsValid(evaluation));
	Assert(AttributeNumberIsValid(attributeNumber));
	Assert((attributeNumber >= 1) && (attributeNumber < 1 + numattrs));

	Assert(StrategyNumberIsInBounds(strategy, evaluation->maxStrategy));

	termData.degree = 1;

Bruce Momjian's avatar
Bruce Momjian committed
376
	strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
377 378
											  evaluation->maxStrategy,
											  attributeNumber);
379 380 381 382 383 384 385 386

	entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);

	if (RegProcedureIsValid(entry->sk_procedure))
	{
		termData.operatorData[0].strategy = strategy;
		termData.operatorData[0].flags = 0x0;

Bruce Momjian's avatar
Bruce Momjian committed
387
		return StrategyTermEvaluate(&termData, strategyMap, left, right);
388
	}
389 390 391 392 393 394 395 396 397 398 399 400 401


	newStrategy = evaluation->negateTransform->strategy[strategy - 1];
	if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
	{

		entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);

		if (RegProcedureIsValid(entry->sk_procedure))
		{
			termData.operatorData[0].strategy = newStrategy;
			termData.operatorData[0].flags = SK_NEGATE;

Bruce Momjian's avatar
Bruce Momjian committed
402
			return StrategyTermEvaluate(&termData, strategyMap, left, right);
403
		}
404
	}
405 406 407 408 409 410 411 412 413 414 415 416

	newStrategy = evaluation->commuteTransform->strategy[strategy - 1];
	if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
	{

		entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);

		if (RegProcedureIsValid(entry->sk_procedure))
		{
			termData.operatorData[0].strategy = newStrategy;
			termData.operatorData[0].flags = SK_COMMUTE;

Bruce Momjian's avatar
Bruce Momjian committed
417
			return StrategyTermEvaluate(&termData, strategyMap, left, right);
418
		}
419
	}
420 421 422 423 424 425 426 427 428 429 430 431

	newStrategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
	if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
	{

		entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);

		if (RegProcedureIsValid(entry->sk_procedure))
		{
			termData.operatorData[0].strategy = newStrategy;
			termData.operatorData[0].flags = SK_NEGATE | SK_COMMUTE;

Bruce Momjian's avatar
Bruce Momjian committed
432
			return StrategyTermEvaluate(&termData, strategyMap, left, right);
433 434 435
		}
	}

436 437
	if (PointerIsValid(evaluation->expression[strategy - 1]))
	{
438
		StrategyTerm *termP;
439 440 441 442

		termP = &evaluation->expression[strategy - 1]->term[0];
		while (PointerIsValid(*termP))
		{
443
			Index		index;
444 445 446 447 448 449 450 451 452 453 454

			for (index = 0; index < (*termP)->degree; index += 1)
			{
				entry = StrategyMapGetScanKeyEntry(strategyMap,
								 (*termP)->operatorData[index].strategy);

				if (!RegProcedureIsValid(entry->sk_procedure))
					break;
			}

			if (index == (*termP)->degree)
Bruce Momjian's avatar
Bruce Momjian committed
455
				return StrategyTermEvaluate(*termP, strategyMap, left, right);
456 457 458 459 460

			termP += 1;
		}
	}

461
	elog(ERROR, "RelationInvokeStrategy: cannot evaluate strategy %d",
462 463 464 465
		 strategy);

	/* not reached, just to make compiler happy */
	return FALSE;
466 467 468 469 470


}

/* ----------------
471
 *		OperatorRelationFillScanKeyEntry
472 473 474 475
 * ----------------
 */
static void
OperatorRelationFillScanKeyEntry(Relation operatorRelation,
476 477
								 Oid operatorObjectId,
								 ScanKey entry)
478
{
479
	HeapTuple	tuple;
480
	HeapScanDesc scan = NULL;
481

482 483 484 485 486 487 488 489 490
	if (!IsBootstrapProcessingMode())
	{
		tuple = SearchSysCacheTuple(OPROID,
									ObjectIdGetDatum(operatorObjectId),
									0, 0, 0);
	}
	else
	{
		ScanKeyData scanKeyData;
491

492 493 494 495
		ScanKeyEntryInitialize(&scanKeyData, 0,
							   ObjectIdAttributeNumber,
							   F_OIDEQ,
							   ObjectIdGetDatum(operatorObjectId));
496

497 498
		scan = heap_beginscan(operatorRelation, false, SnapshotNow,
							  1, &scanKeyData);
499

500 501
		tuple = heap_getnext(scan, 0);
	}
502 503 504

	if (!HeapTupleIsValid(tuple))
	{
505 506
		if (IsBootstrapProcessingMode())
			heap_endscan(scan);
507
		elog(ERROR, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu",
508 509 510 511
			 (uint32) operatorObjectId);
	}

	entry->sk_flags = 0;
512
	entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
513 514
	fmgr_info(entry->sk_procedure, &entry->sk_func);
	entry->sk_nargs = entry->sk_func.fn_nargs;
515

516 517
	if (IsBootstrapProcessingMode())
		heap_endscan(scan);
518

519 520
	if (!RegProcedureIsValid(entry->sk_procedure))
	{
521
		elog(ERROR,
522 523 524
		"OperatorObjectIdFillScanKeyEntry: no procedure for operator %lu",
			 (uint32) operatorObjectId);
	}
525 526 527 528
}


/*
Bruce Momjian's avatar
Bruce Momjian committed
529
 * IndexSupportInitialize
530
 *		Initializes an index strategy and associated support procedures.
531 532 533
 */
void
IndexSupportInitialize(IndexStrategy indexStrategy,
534
					   RegProcedure *indexSupport,
535 536 537 538 539
					   Oid indexObjectId,
					   Oid accessMethodObjectId,
					   StrategyNumber maxStrategyNumber,
					   StrategyNumber maxSupportNumber,
					   AttrNumber maxAttributeNumber)
540
{
541 542 543
	Relation	relation = NULL;
	HeapScanDesc scan = NULL;
	ScanKeyData entry[2];
544 545 546 547 548 549
	Relation	operatorRelation;
	HeapTuple	tuple;
	StrategyMap map;
	AttrNumber	attributeNumber;
	int			attributeIndex;
	Oid			operatorClassObjectId[MaxIndexAttributeNumber];
550

551 552 553 554 555 556 557 558 559 560 561
	if (!IsBootstrapProcessingMode())
	{
		tuple = SearchSysCacheTuple(INDEXRELID,
									ObjectIdGetDatum(indexObjectId),
									0, 0, 0);
	}
	else
	{
		ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
							   F_OIDEQ,
							   ObjectIdGetDatum(indexObjectId));
562

563 564 565 566
		relation = heap_openr(IndexRelationName);
		scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
		tuple = heap_getnext(scan, 0);
	}
567 568

	if (!HeapTupleIsValid(tuple))
569
		elog(ERROR, "IndexSupportInitialize: corrupted catalogs");
570

571 572
	maxStrategyNumber = AMStrategies(maxStrategyNumber);

573 574
	/*
	 * XXX note that the following assumes the INDEX tuple is well formed
575
	 * and that the *key and *class are 0 terminated.
576 577
	 */
	for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++)
578
	{
579
		Form_pg_index iform;
580

581
		iform = (Form_pg_index) GETSTRUCT(tuple);
582 583 584

		if (!OidIsValid(iform->indkey[attributeIndex]))
		{
Bruce Momjian's avatar
Bruce Momjian committed
585
			if (attributeIndex == InvalidAttrNumber)
586
				elog(ERROR, "IndexSupportInitialize: no pg_index tuple");
587
			break;
588
		}
589

Bruce Momjian's avatar
Bruce Momjian committed
590
		operatorClassObjectId[attributeIndex] = iform->indclass[attributeIndex];
591
	}
592

593 594 595 596 597
	if (IsBootstrapProcessingMode())
	{
		heap_endscan(scan);
		heap_close(relation);
	}
598

599 600 601 602
	/* if support routines exist for this access method, load them */
	if (maxSupportNumber > 0)
	{
		ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
Bruce Momjian's avatar
Bruce Momjian committed
603
							   F_OIDEQ,
604 605 606
							   ObjectIdGetDatum(accessMethodObjectId));

		ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
Bruce Momjian's avatar
Bruce Momjian committed
607
							   F_OIDEQ, 0);
608 609 610

		relation = heap_openr(AccessMethodProcedureRelationName);

Bruce Momjian's avatar
Bruce Momjian committed
611
		for (attributeNumber = 1; attributeNumber <= maxAttributeNumber;
612
			 attributeNumber++)
613
		{
614
			int16		support;
615
			Form_pg_amproc aform;
616
			RegProcedure *loc;
617 618 619

			loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)];

Bruce Momjian's avatar
Bruce Momjian committed
620
			for (support = 0; support < maxSupportNumber; ++support)
621 622 623 624 625
				loc[support] = InvalidOid;

			entry[1].sk_argument =
				ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);

626
			scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
627

628
			while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
629
			{
630 631
				aform = (Form_pg_amproc) GETSTRUCT(tuple);
				loc[(aform->amprocnum - 1)] = aform->amproc;
632 633 634 635 636 637 638 639 640
			}

			heap_endscan(scan);
		}
		heap_close(relation);
	}

	ScanKeyEntryInitialize(&entry[0], 0,
						   Anum_pg_amop_amopid,
Bruce Momjian's avatar
Bruce Momjian committed
641
						   F_OIDEQ,
642 643 644 645
						   ObjectIdGetDatum(accessMethodObjectId));

	ScanKeyEntryInitialize(&entry[1], 0,
						   Anum_pg_amop_amopclaid,
Bruce Momjian's avatar
Bruce Momjian committed
646
						   F_OIDEQ, 0);
647 648 649 650

	relation = heap_openr(AccessMethodOperatorRelationName);
	operatorRelation = heap_openr(OperatorRelationName);

651
	for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
652 653
		 attributeNumber--)
	{
654
		StrategyNumber strategy;
655 656 657 658 659 660 661 662 663 664 665

		entry[1].sk_argument =
			ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);

		map = IndexStrategyGetStrategyMap(indexStrategy,
										  maxStrategyNumber,
										  attributeNumber);

		for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
			ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));

666
		scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
667

668
		while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
669
		{
670
			Form_pg_amop aform;
671

672
			aform = (Form_pg_amop) GETSTRUCT(tuple);
673
			OperatorRelationFillScanKeyEntry(operatorRelation,
674 675
											 aform->amopopr,
					StrategyMapGetScanKeyEntry(map, aform->amopstrategy));
676 677 678
		}

		heap_endscan(scan);
679
	}
680 681

	heap_close(operatorRelation);
682 683 684 685
	heap_close(relation);
}

/* ----------------
686
 *		IndexStrategyDisplay
687 688 689 690 691
 * ----------------
 */
#ifdef	ISTRATDEBUG
int
IndexStrategyDisplay(IndexStrategy indexStrategy,
692 693
					 StrategyNumber numberOfStrategies,
					 int numberOfAttributes)
694
{
695 696 697
	StrategyMap strategyMap;
	AttrNumber	attributeNumber;
	StrategyNumber strategyNumber;
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716

	for (attributeNumber = 1; attributeNumber <= numberOfAttributes;
		 attributeNumber += 1)
	{

		strategyMap = IndexStrategyGetStrategyMap(indexStrategy,
												  numberOfStrategies,
												  attributeNumber);

		for (strategyNumber = 1;
			 strategyNumber <= AMStrategies(numberOfStrategies);
			 strategyNumber += 1)
		{

			printf(":att %d\t:str %d\t:opr 0x%x(%d)\n",
				   attributeNumber, strategyNumber,
				   strategyMap->entry[strategyNumber - 1].sk_procedure,
				   strategyMap->entry[strategyNumber - 1].sk_procedure);
		}
717 718 719
	}
}

720
#endif	 /* defined(ISTRATDEBUG) */