diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/access/index/istrat.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/access/index/istrat.c')
-rw-r--r-- | src/backend/access/index/istrat.c | 679 |
1 files changed, 679 insertions, 0 deletions
diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c new file mode 100644 index 00000000000..602d2bd9e94 --- /dev/null +++ b/src/backend/access/index/istrat.c @@ -0,0 +1,679 @@ +/*------------------------------------------------------------------------- + * + * istrat.c-- + * index scan strategy manipulation code and index strategy manipulation + * operator code. + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.1.1.1 1996/07/09 06:21:11 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/attnum.h" +#include "access/heapam.h" +#include "access/istrat.h" +#include "access/itup.h" /* for MaxIndexAttributeNumber */ +#include "access/skey.h" +#include "utils/tqual.h" /* for NowTimeQual */ + +#include "fmgr.h" +#include "utils/elog.h" +#include "utils/rel.h" + +#include "catalog/catname.h" +#include "catalog/pg_amop.h" +#include "catalog/pg_amproc.h" +#include "catalog/pg_index.h" +#include "catalog/pg_proc.h" + +/* ---------------------------------------------------------------- + * misc strategy support routines + * ---------------------------------------------------------------- + */ + +/* + * StrategyNumberIsValid + * StrategyNumberIsInBounds + * StrategyMapIsValid + * StrategyTransformMapIsValid + * IndexStrategyIsValid + * + * ... are now macros in istrat.h -cim 4/27/91 + */ + +/* + * StrategyMapGetScanKeyEntry -- + * Returns a scan key entry of a index strategy mapping member. + * + * Note: + * Assumes that the index strategy mapping is valid. + * Assumes that the index strategy number is valid. + * Bounds checking should be done outside this routine. + */ +ScanKey +StrategyMapGetScanKeyEntry(StrategyMap map, + StrategyNumber strategyNumber) +{ + Assert(StrategyMapIsValid(map)); + Assert(StrategyNumberIsValid(strategyNumber)); + return (&map->entry[strategyNumber - 1]); +} + +/* + * IndexStrategyGetStrategyMap -- + * Returns an index strategy mapping of an index strategy. + * + * Note: + * Assumes that the index strategy is valid. + * Assumes that the number of index strategies is valid. + * Bounds checking should be done outside this routine. + */ +StrategyMap +IndexStrategyGetStrategyMap(IndexStrategy indexStrategy, + StrategyNumber maxStrategyNum, + AttrNumber attrNum) +{ + Assert(IndexStrategyIsValid(indexStrategy)); + Assert(StrategyNumberIsValid(maxStrategyNum)); + Assert(AttributeNumberIsValid(attrNum)); + + maxStrategyNum = AMStrategies(maxStrategyNum); /* XXX */ + return + &indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)]; +} + +/* + * AttributeNumberGetIndexStrategySize -- + * Computes the size of an index strategy. + */ +Size +AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber, + StrategyNumber maxStrategyNumber) +{ + maxStrategyNumber = AMStrategies(maxStrategyNumber); /* XXX */ + return + maxAttributeNumber * maxStrategyNumber * sizeof (ScanKeyData); +} + +/* + * StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91 + */ + +/* ---------------- + * StrategyOperatorIsValid + * ---------------- + */ +bool +StrategyOperatorIsValid(StrategyOperator operator, + StrategyNumber maxStrategy) +{ + return (bool) + (PointerIsValid(operator) && + StrategyNumberIsInBounds(operator->strategy, maxStrategy) && + !(operator->flags & ~(SK_NEGATE | SK_COMMUTE))); +} + +/* ---------------- + * StrategyTermIsValid + * ---------------- + */ +bool +StrategyTermIsValid(StrategyTerm term, + StrategyNumber maxStrategy) +{ + Index index; + + if (! PointerIsValid(term) || term->degree == 0) + return false; + + for (index = 0; index < term->degree; index += 1) { + if (! StrategyOperatorIsValid(&term->operatorData[index], + maxStrategy)) { + + return false; + } + } + + return true; +} + +/* ---------------- + * StrategyExpressionIsValid + * ---------------- + */ +bool +StrategyExpressionIsValid(StrategyExpression expression, + StrategyNumber maxStrategy) +{ + StrategyTerm *termP; + + 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)); +} + +/* ---------------- + * StrategyEvaluationIsValid + * ---------------- + */ +bool +StrategyEvaluationIsValid(StrategyEvaluation evaluation) +{ + Index index; + + if (! PointerIsValid(evaluation) || + ! StrategyNumberIsValid(evaluation->maxStrategy) || + ! StrategyTransformMapIsValid(evaluation->negateTransform) || + ! StrategyTransformMapIsValid(evaluation->commuteTransform) || + ! StrategyTransformMapIsValid(evaluation->negateCommuteTransform)) { + + return false; + } + + for (index = 0; index < evaluation->maxStrategy; index += 1) { + if (! StrategyExpressionIsValid(evaluation->expression[index], + evaluation->maxStrategy)) { + + return false; + } + } + return true; +} + +/* ---------------- + * StrategyTermEvaluate + * ---------------- + */ +static bool +StrategyTermEvaluate(StrategyTerm term, + StrategyMap map, + Datum left, + Datum right) +{ + Index index; + long tmpres; + bool result; + StrategyOperator operator; + ScanKey entry; + + 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) { + case 0x0: + tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure, + left, right); + break; + + case SK_NEGATE: + tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure, + left, right); + break; + + case SK_COMMUTE: + tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure, + right, left); + break; + + case SK_NEGATE | SK_COMMUTE: + tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure, + right, left); + break; + + default: + elog(FATAL, "StrategyTermEvaluate: impossible case %d", + operator->flags ^ entry->sk_flags); + } + + result = (bool) tmpres; + if (!result) + return result; + } + + return result; +} + + +/* ---------------- + * RelationGetStrategy + * ---------------- + */ +StrategyNumber +RelationGetStrategy(Relation relation, + AttrNumber attributeNumber, + StrategyEvaluation evaluation, + RegProcedure procedure) +{ + StrategyNumber strategy; + StrategyMap strategyMap; + ScanKey entry; + Index index; + int numattrs; + + 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; + } + } + + 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)) { + case 0x0: + return strategy; + + case SK_NEGATE: + strategy = evaluation->negateTransform->strategy[strategy - 1]; + break; + + case SK_COMMUTE: + strategy = evaluation->commuteTransform->strategy[strategy - 1]; + break; + + case SK_NEGATE | SK_COMMUTE: + strategy = evaluation->negateCommuteTransform->strategy[strategy - 1]; + break; + + default: + elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags); + } + + + if (! StrategyNumberIsInBounds(strategy, evaluation->maxStrategy)) { + if (! StrategyNumberIsValid(strategy)) { + elog(WARN, "RelationGetStrategy: corrupted evaluation"); + } + } + + return strategy; +} + +/* ---------------- + * RelationInvokeStrategy + * ---------------- + */ +bool /* XXX someday, this may return Datum */ +RelationInvokeStrategy(Relation relation, + StrategyEvaluation evaluation, + AttrNumber attributeNumber, + StrategyNumber strategy, + Datum left, + Datum right) +{ + StrategyNumber newStrategy; + StrategyMap strategyMap; + ScanKey entry; + StrategyTermData termData; + int numattrs; + + 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); + } + + + 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); + } + } + + 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); + } + } + + 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); + } + } + + if (PointerIsValid(evaluation->expression[strategy - 1])) { + StrategyTerm *termP; + + termP = &evaluation->expression[strategy - 1]->term[0]; + while (PointerIsValid(*termP)) { + Index index; + + 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; + } + } + + elog(WARN, "RelationInvokeStrategy: cannot evaluate strategy %d", + strategy); + + /* not reached, just to make compiler happy */ + return FALSE; + + +} + +/* ---------------- + * OperatorRelationFillScanKeyEntry + * ---------------- + */ +static void +OperatorRelationFillScanKeyEntry(Relation operatorRelation, + Oid operatorObjectId, + ScanKey entry) +{ + HeapScanDesc scan; + ScanKeyData scanKeyData; + HeapTuple tuple; + + ScanKeyEntryInitialize(&scanKeyData, 0, + ObjectIdAttributeNumber, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(operatorObjectId)); + + scan = heap_beginscan(operatorRelation, false, NowTimeQual, + 1, &scanKeyData); + + tuple = heap_getnext(scan, false, (Buffer *)NULL); + if (! HeapTupleIsValid(tuple)) { + elog(WARN, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu", + (uint32) operatorObjectId); + } + + entry->sk_flags = 0; + entry->sk_procedure = + ((OperatorTupleForm) GETSTRUCT(tuple))->oprcode; + fmgr_info(entry->sk_procedure, &entry->sk_func, &entry->sk_nargs); + + if (! RegProcedureIsValid(entry->sk_procedure)) { + elog(WARN, + "OperatorObjectIdFillScanKeyEntry: no procedure for operator %lu", + (uint32) operatorObjectId); + } + + heap_endscan(scan); +} + + +/* + * IndexSupportInitialize -- + * Initializes an index strategy and associated support procedures. + */ +void +IndexSupportInitialize(IndexStrategy indexStrategy, + RegProcedure *indexSupport, + Oid indexObjectId, + Oid accessMethodObjectId, + StrategyNumber maxStrategyNumber, + StrategyNumber maxSupportNumber, + AttrNumber maxAttributeNumber) +{ + Relation relation; + Relation operatorRelation; + HeapScanDesc scan; + HeapTuple tuple; + ScanKeyData entry[2]; + StrategyMap map; + AttrNumber attributeNumber; + int attributeIndex; + Oid operatorClassObjectId[ MaxIndexAttributeNumber ]; + + maxStrategyNumber = AMStrategies(maxStrategyNumber); + + ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(indexObjectId)); + + relation = heap_openr(IndexRelationName); + scan = heap_beginscan(relation, false, NowTimeQual, 1, entry); + tuple = heap_getnext(scan, 0, (Buffer *)NULL); + if (! HeapTupleIsValid(tuple)) + elog(WARN, "IndexSupportInitialize: corrupted catalogs"); + + /* + * 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++) + { + IndexTupleForm iform; + + iform = (IndexTupleForm) GETSTRUCT(tuple); + + if (!OidIsValid(iform->indkey[attributeIndex])) { + if (attributeIndex == 0) { + elog(WARN, "IndexSupportInitialize: no pg_index tuple"); + } + break; + } + + operatorClassObjectId[attributeIndex] + = iform->indclass[attributeIndex]; + } + + 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, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(accessMethodObjectId)); + + ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid, + ObjectIdEqualRegProcedure, 0); + +/* relation = heap_openr(Name_pg_amproc); */ + relation = heap_openr(AccessMethodProcedureRelationName); + + + for (attributeNumber = maxAttributeNumber; attributeNumber > 0; + attributeNumber--) { + + int16 support; + Form_pg_amproc form; + RegProcedure *loc; + + loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)]; + + for (support = maxSupportNumber; --support >= 0; ) { + loc[support] = InvalidOid; + } + + entry[1].sk_argument = + ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]); + + scan = heap_beginscan(relation, false, NowTimeQual, 2, entry); + + 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, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(accessMethodObjectId)); + + ScanKeyEntryInitialize(&entry[1], 0, + Anum_pg_amop_amopclaid, + ObjectIdEqualRegProcedure, 0); + + relation = heap_openr(AccessMethodOperatorRelationName); + operatorRelation = heap_openr(OperatorRelationName); + + for (attributeNumber = maxAttributeNumber; attributeNumber > 0; + attributeNumber--) { + + StrategyNumber strategy; + + entry[1].sk_argument = + ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]); + + map = IndexStrategyGetStrategyMap(indexStrategy, + maxStrategyNumber, + attributeNumber); + + for (strategy = 1; strategy <= maxStrategyNumber; strategy++) + ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy)); + + scan = heap_beginscan(relation, false, NowTimeQual, 2, entry); + + while (tuple = heap_getnext(scan, 0, (Buffer *)NULL), + HeapTupleIsValid(tuple)) { + Form_pg_amop form; + + form = (Form_pg_amop) GETSTRUCT(tuple); + + OperatorRelationFillScanKeyEntry(operatorRelation, + form->amopopr, + StrategyMapGetScanKeyEntry(map, form->amopstrategy)); + } + + heap_endscan(scan); + } + + heap_close(operatorRelation); + heap_close(relation); +} + +/* ---------------- + * IndexStrategyDisplay + * ---------------- + */ +#ifdef ISTRATDEBUG +int +IndexStrategyDisplay(IndexStrategy indexStrategy, + StrategyNumber numberOfStrategies, + int numberOfAttributes) +{ + StrategyMap strategyMap; + AttrNumber attributeNumber; + StrategyNumber strategyNumber; + + 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); + } + } +} +#endif /* defined(ISTRATDEBUG) */ + + |