istrat.c 17.3 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.21 1998/07/27 19:37:37 vadim Exp $
12 13 14 15
 *
 *-------------------------------------------------------------------------
 */

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

Bruce Momjian's avatar
Bruce Momjian committed
18 19 20 21 22 23 24 25 26
#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"
#include "fmgr.h"
#include "utils/memutils.h"		/* could have been access/itup.h */
27

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

Bruce Momjian's avatar
Bruce Momjian committed
43 44
#endif

45

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

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

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

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

	maxStrategyNum = AMStrategies(maxStrategyNum);		/* XXX */
	return
		&indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)];
100 101 102 103
}

/*
 * AttributeNumberGetIndexStrategySize --
104
 *		Computes the size of an index strategy.
105 106 107
 */
Size
AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
108
									StrategyNumber maxStrategyNumber)
109
{
110 111 112
	maxStrategyNumber = AMStrategies(maxStrategyNumber);		/* XXX */
	return
		maxAttributeNumber * maxStrategyNumber * sizeof(ScanKeyData);
113 114
}

Bruce Momjian's avatar
Bruce Momjian committed
115
#ifdef USE_ASSERT_CHECKING
116
/*
117 118 119 120
 * StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91
 */

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

/* ----------------
135
 *		StrategyTermIsValid
136 137
 * ----------------
 */
138
static bool
139
StrategyTermIsValid(StrategyTerm term,
140
					StrategyNumber maxStrategy)
141
{
142
	Index		index;
143 144 145 146 147 148 149 150 151 152 153 154

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

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

			return false;
		}
155
	}
156 157

	return true;
158 159 160
}

/* ----------------
161
 *		StrategyExpressionIsValid
162 163
 * ----------------
 */
164
static bool
165
StrategyExpressionIsValid(StrategyExpression expression,
166
						  StrategyNumber maxStrategy)
167
{
168
	StrategyTerm *termP;
169 170 171 172 173 174 175 176 177 178 179 180 181

	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));
182 183 184
}

/* ----------------
185
 *		StrategyEvaluationIsValid
186 187
 * ----------------
 */
188
static bool
189 190
StrategyEvaluationIsValid(StrategyEvaluation evaluation)
{
191
	Index		index;
192 193 194 195 196 197 198 199 200

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

		return false;
201
	}
202 203 204 205 206 207 208 209 210 211 212

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

			return false;
		}
	}
	return true;
213
}
214

Bruce Momjian's avatar
Bruce Momjian committed
215
#endif
216 217

/* ----------------
218
 *		StrategyTermEvaluate
219 220
 * ----------------
 */
221
static bool
222
StrategyTermEvaluate(StrategyTerm term,
223 224 225
					 StrategyMap map,
					 Datum left,
					 Datum right)
226
{
227 228 229
	Index		index;
	long		tmpres = 0;
	bool		result = 0;
230
	StrategyOperator operator;
231
	ScanKey		entry;
232 233 234 235 236 237 238 239 240 241 242

	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)
		{
243
			case 0x0:
244
				tmpres = (long) FMGR_PTR2(&entry->sk_func,
245 246 247 248
										  left, right);
				break;

			case SK_NEGATE:
249
				tmpres = (long) !FMGR_PTR2(&entry->sk_func,
250 251 252 253
										   left, right);
				break;

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

			case SK_NEGATE | SK_COMMUTE:
259
				tmpres = (long) !FMGR_PTR2(&entry->sk_func,
260 261 262 263 264 265
										   right, left);
				break;

			default:
				elog(FATAL, "StrategyTermEvaluate: impossible case %d",
					 operator->flags ^ entry->sk_flags);
266 267 268 269 270
		}

		result = (bool) tmpres;
		if (!result)
			return result;
271
	}
272 273

	return result;
274 275 276 277
}


/* ----------------
278
 *		RelationGetStrategy
279 280 281 282
 * ----------------
 */
StrategyNumber
RelationGetStrategy(Relation relation,
283 284 285
					AttrNumber attributeNumber,
					StrategyEvaluation evaluation,
					RegProcedure procedure)
286
{
287 288 289 290 291
	StrategyNumber strategy;
	StrategyMap strategyMap;
	ScanKey		entry;
	Index		index;
	int			numattrs;
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

	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));

	strategyMap =
		IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
									evaluation->maxStrategy,
									attributeNumber);

	/* 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;
313
	}
314 315 316 317 318 319 320 321 322 323 324

	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))
	{
325 326
		case 0x0:
			return strategy;
327

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

332 333 334
		case SK_COMMUTE:
			strategy = evaluation->commuteTransform->strategy[strategy - 1];
			break;
335

336 337 338
		case SK_NEGATE | SK_COMMUTE:
			strategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
			break;
339

340 341
		default:
			elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags);
342
	}
343 344 345 346 347


	if (!StrategyNumberIsInBounds(strategy, evaluation->maxStrategy))
	{
		if (!StrategyNumberIsValid(strategy))
348
			elog(ERROR, "RelationGetStrategy: corrupted evaluation");
349 350 351
	}

	return strategy;
352 353 354
}

/* ----------------
355
 *		RelationInvokeStrategy
356 357
 * ----------------
 */
358
bool							/* XXX someday, this may return Datum */
359
RelationInvokeStrategy(Relation relation,
360 361 362 363 364
					   StrategyEvaluation evaluation,
					   AttrNumber attributeNumber,
					   StrategyNumber strategy,
					   Datum left,
					   Datum right)
365
{
366 367 368
	StrategyNumber newStrategy;
	StrategyMap strategyMap;
	ScanKey		entry;
369
	StrategyTermData termData;
370
	int			numattrs;
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397

	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;

	strategyMap =
		IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
									evaluation->maxStrategy,
									attributeNumber);

	entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);

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

		return
			StrategyTermEvaluate(&termData, strategyMap, left, right);
398
	}
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414


	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;

			return
				StrategyTermEvaluate(&termData, strategyMap, left, right);
		}
415
	}
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430

	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;

			return
				StrategyTermEvaluate(&termData, strategyMap, left, right);
		}
431
	}
432 433 434 435 436 437 438 439 440 441 442 443 444 445

	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;

			return
				StrategyTermEvaluate(&termData, strategyMap, left, right);
446 447 448
		}
	}

449 450
	if (PointerIsValid(evaluation->expression[strategy - 1]))
	{
451
		StrategyTerm *termP;
452 453 454 455

		termP = &evaluation->expression[strategy - 1]->term[0];
		while (PointerIsValid(*termP))
		{
456
			Index		index;
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

			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)
			{
				return
					StrategyTermEvaluate(*termP, strategyMap, left, right);
			}

			termP += 1;
		}
	}

477
	elog(ERROR, "RelationInvokeStrategy: cannot evaluate strategy %d",
478 479 480 481
		 strategy);

	/* not reached, just to make compiler happy */
	return FALSE;
482 483 484 485 486


}

/* ----------------
487
 *		OperatorRelationFillScanKeyEntry
488 489 490 491
 * ----------------
 */
static void
OperatorRelationFillScanKeyEntry(Relation operatorRelation,
492 493
								 Oid operatorObjectId,
								 ScanKey entry)
494
{
495 496 497
	HeapScanDesc scan;
	ScanKeyData scanKeyData;
	HeapTuple	tuple;
498 499 500

	ScanKeyEntryInitialize(&scanKeyData, 0,
						   ObjectIdAttributeNumber,
Bruce Momjian's avatar
Bruce Momjian committed
501
						   F_OIDEQ,
502 503
						   ObjectIdGetDatum(operatorObjectId));

504
	scan = heap_beginscan(operatorRelation, false, SnapshotNow,
505 506 507 508 509
						  1, &scanKeyData);

	tuple = heap_getnext(scan, false, (Buffer *) NULL);
	if (!HeapTupleIsValid(tuple))
	{
510
		elog(ERROR, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu",
511 512 513 514 515 516
			 (uint32) operatorObjectId);
	}

	entry->sk_flags = 0;
	entry->sk_procedure =
		((OperatorTupleForm) GETSTRUCT(tuple))->oprcode;
517 518
	fmgr_info(entry->sk_procedure, &entry->sk_func);
	entry->sk_nargs = entry->sk_func.fn_nargs;
519 520 521

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

	heap_endscan(scan);
528 529 530 531 532
}


/*
 * IndexSupportInitialize --
533
 *		Initializes an index strategy and associated support procedures.
534 535 536
 */
void
IndexSupportInitialize(IndexStrategy indexStrategy,
537
					   RegProcedure *indexSupport,
538 539 540 541 542
					   Oid indexObjectId,
					   Oid accessMethodObjectId,
					   StrategyNumber maxStrategyNumber,
					   StrategyNumber maxSupportNumber,
					   AttrNumber maxAttributeNumber)
543
{
544 545 546 547 548 549 550 551 552
	Relation	relation;
	Relation	operatorRelation;
	HeapScanDesc scan;
	HeapTuple	tuple;
	ScanKeyData entry[2];
	StrategyMap map;
	AttrNumber	attributeNumber;
	int			attributeIndex;
	Oid			operatorClassObjectId[MaxIndexAttributeNumber];
553 554 555 556

	maxStrategyNumber = AMStrategies(maxStrategyNumber);

	ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
Bruce Momjian's avatar
Bruce Momjian committed
557
						   F_OIDEQ,
558 559 560
						   ObjectIdGetDatum(indexObjectId));

	relation = heap_openr(IndexRelationName);
561
	scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
562 563
	tuple = heap_getnext(scan, 0, (Buffer *) NULL);
	if (!HeapTupleIsValid(tuple))
564
		elog(ERROR, "IndexSupportInitialize: corrupted catalogs");
565 566 567 568 569 570

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

		iform = (IndexTupleForm) GETSTRUCT(tuple);

		if (!OidIsValid(iform->indkey[attributeIndex]))
		{
			if (attributeIndex == 0)
579
				elog(ERROR, "IndexSupportInitialize: no pg_index tuple");
580
			break;
581
		}
582 583 584

		operatorClassObjectId[attributeIndex]
			= iform->indclass[attributeIndex];
585
	}
586 587 588 589 590 591 592 593 594

	heap_endscan(scan);
	heap_close(relation);

	/* 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
595
							   F_OIDEQ,
596 597 598
							   ObjectIdGetDatum(accessMethodObjectId));

		ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
Bruce Momjian's avatar
Bruce Momjian committed
599
							   F_OIDEQ, 0);
600 601 602 603 604 605 606 607 608

/*		relation = heap_openr(Name_pg_amproc); */
		relation = heap_openr(AccessMethodProcedureRelationName);


		for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
			 attributeNumber--)
		{

609 610 611
			int16		support;
			Form_pg_amproc form;
			RegProcedure *loc;
612 613 614 615 616 617 618 619 620

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

			for (support = maxSupportNumber; --support >= 0;)
				loc[support] = InvalidOid;

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

621
			scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637

			while (tuple = heap_getnext(scan, 0, (Buffer *) NULL),
				   HeapTupleIsValid(tuple))
			{

				form = (Form_pg_amproc) GETSTRUCT(tuple);
				loc[(form->amprocnum - 1)] = form->amproc;
			}

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

	ScanKeyEntryInitialize(&entry[0], 0,
						   Anum_pg_amop_amopid,
Bruce Momjian's avatar
Bruce Momjian committed
638
						   F_OIDEQ,
639 640 641 642
						   ObjectIdGetDatum(accessMethodObjectId));

	ScanKeyEntryInitialize(&entry[1], 0,
						   Anum_pg_amop_amopclaid,
Bruce Momjian's avatar
Bruce Momjian committed
643
						   F_OIDEQ, 0);
644 645 646 647

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

648
	for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
649 650 651
		 attributeNumber--)
	{

652
		StrategyNumber strategy;
653 654 655 656 657 658 659 660 661 662 663

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

		map = IndexStrategyGetStrategyMap(indexStrategy,
										  maxStrategyNumber,
										  attributeNumber);

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

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

		while (tuple = heap_getnext(scan, 0, (Buffer *) NULL),
			   HeapTupleIsValid(tuple))
		{
669
			Form_pg_amop form;
670 671 672 673 674 675 676 677 678

			form = (Form_pg_amop) GETSTRUCT(tuple);

			OperatorRelationFillScanKeyEntry(operatorRelation,
											 form->amopopr,
					StrategyMapGetScanKeyEntry(map, form->amopstrategy));
		}

		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) */