You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
postgres/src/backend/access/rtree/rtstrat.c

240 lines
8.2 KiB

/*-------------------------------------------------------------------------
*
* rtstrat.c
* strategy map data for rtrees.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.19 2001/10/28 06:25:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/istrat.h"
#include "access/rtree.h"
static StrategyNumber RelationGetRTStrategy(Relation r,
AttrNumber attnum, RegProcedure proc);
/*
* Note: negate, commute, and negatecommute all assume that operators are
* ordered as follows in the strategy map:
*
* left, left-or-overlap, overlap, right-or-overlap, right, same,
* contains, contained-by
*
* The negate, commute, and negatecommute arrays are used by the planner
* to plan indexed scans over data that appears in the qualificiation in
* a boolean negation, or whose operands appear in the wrong order. For
* example, if the operator "<%" means "contains", and the user says
*
* where not rel.box <% "(10,10,20,20)"::box
*
* the planner can plan an index scan by noting that rtree indices have
* an operator in their operator class for negating <%.
*
* Similarly, if the user says something like
*
* where "(10,10,20,20)"::box <% rel.box
*
* the planner can see that the rtree index on rel.box has an operator in
* its opclass for commuting <%, and plan the scan using that operator.
* This added complexity in the access methods makes the planner a lot easier
* to write.
*/
/* if a op b, what operator tells us if (not a op b)? */
static StrategyNumber RTNegate[RTNStrategies] = {
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy
};
/* if a op_1 b, what is the operator op_2 such that b op_2 a? */
static StrategyNumber RTCommute[RTNStrategies] = {
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy
};
/* if a op_1 b, what is the operator op_2 such that (b !op_2 a)? */
static StrategyNumber RTNegateCommute[RTNStrategies] = {
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy,
InvalidStrategy
};
/*
* Now do the TermData arrays. These exist in case the user doesn't give
* us a full set of operators for a particular operator class. The idea
* is that by making multiple comparisons using any one of the supplied
* operators, we can decide whether two n-dimensional polygons are equal.
* For example, if a contains b and b contains a, we may conclude that
* a and b are equal.
*
* The presence of the TermData arrays in all this is a historical accident.
* Early in the development of the POSTGRES access methods, it was believed
* that writing functions was harder than writing arrays. This is wrong;
* TermData is hard to understand and hard to get right. In general, when
* someone populates a new operator class, they populate it completely. If
* Mike Hirohama had forced Cimarron Taylor to populate the strategy map
* for btree int2_ops completely in 1988, you wouldn't have to deal with
* all this now. Too bad for you.
*
* Since you can't necessarily do this in all cases (for example, you can't
* do it given only "intersects" or "disjoint"), TermData arrays for some
* operators don't appear below.
*
* Note that if you DO supply all the operators required in a given opclass
* by inserting them into the pg_opclass system catalog, you can get away
* without doing all this TermData stuff. Since the rtree code is intended
* to be a reference for access method implementors, I'm doing TermData
* correctly here.
*
* Note on style: these are all actually of type StrategyTermData, but
* since those have variable-length data at the end of the struct we can't
* properly initialize them if we declare them to be what they are.
*/
/* if you only have "contained-by", how do you determine equality? */
static uint16 RTContainedByTermData[] = {
2, /* make two comparisons */
RTContainedByStrategyNumber, /* use "a contained-by b" */
0x0, /* without any magic */
RTContainedByStrategyNumber, /* then use contained-by, */
SK_COMMUTE /* swapping a and b */
};
/* if you only have "contains", how do you determine equality? */
static uint16 RTContainsTermData[] = {
2, /* make two comparisons */
RTContainsStrategyNumber, /* use "a contains b" */
0x0, /* without any magic */
RTContainsStrategyNumber, /* then use contains again, */
SK_COMMUTE /* swapping a and b */
};
/* now put all that together in one place for the planner */
static StrategyTerm RTEqualExpressionData[] = {
(StrategyTerm) RTContainedByTermData,
(StrategyTerm) RTContainsTermData,
NULL
};
/*
* If you were sufficiently attentive to detail, you would go through
* the ExpressionData pain above for every one of the seven strategies
* we defined. I am not. Now we declare the StrategyEvaluationData
* structure that gets shipped around to help the planner and the access
* method decide what sort of scan it should do, based on (a) what the
* user asked for, (b) what operators are defined for a particular opclass,
* and (c) the reams of information we supplied above.
*
* The idea of all of this initialized data is to make life easier on the
* user when he defines a new operator class to use this access method.
* By filling in all the data, we let him get away with leaving holes in his
* operator class, and still let him use the index. The added complexity
* in the access methods just isn't worth the trouble, though.
*/
static StrategyExpression RTEvaluationExpressions[RTNStrategies] = {
NULL, /* express left */
NULL, /* express overleft */
NULL, /* express overlap */
NULL, /* express overright */
NULL, /* express right */
(StrategyExpression) RTEqualExpressionData, /* express same */
NULL, /* express contains */
NULL /* express contained-by */
};
static StrategyEvaluationData RTEvaluationData = {
RTNStrategies, /* # of strategies */
(StrategyTransformMap) RTNegate, /* how to do (not qual) */
(StrategyTransformMap) RTCommute, /* how to swap operands */
(StrategyTransformMap) RTNegateCommute, /* how to do both */
RTEvaluationExpressions
};
/*
* Okay, now something peculiar to rtrees that doesn't apply to most other
* indexing structures: When we're searching a tree for a given value, we
* can't do the same sorts of comparisons on internal node entries as we
* do at leaves. The reason is that if we're looking for (say) all boxes
* that are the same as (0,0,10,10), then we need to find all leaf pages
* that overlap that region. So internally we search for overlap, and at
* the leaf we search for equality.
*
* This array maps leaf search operators to the internal search operators.
* We assume the normal ordering on operators:
*
* left, left-or-overlap, overlap, right-or-overlap, right, same,
* contains, contained-by
*/
static StrategyNumber RTOperMap[RTNStrategies] = {
RTOverLeftStrategyNumber,
RTOverLeftStrategyNumber,
RTOverlapStrategyNumber,
RTOverRightStrategyNumber,
RTOverRightStrategyNumber,
RTContainsStrategyNumber,
RTContainsStrategyNumber,
RTOverlapStrategyNumber
};
static StrategyNumber
RelationGetRTStrategy(Relation r,
AttrNumber attnum,
RegProcedure proc)
{
return RelationGetStrategy(r, attnum, &RTEvaluationData, proc);
}
#ifdef NOT_USED
bool
RelationInvokeRTStrategy(Relation r,
AttrNumber attnum,
StrategyNumber s,
Datum left,
Datum right)
{
return (RelationInvokeStrategy(r, &RTEvaluationData, attnum, s,
left, right));
}
#endif
RegProcedure
RTMapOperator(Relation r,
AttrNumber attnum,
RegProcedure proc)
{
StrategyNumber procstrat;
StrategyMap strategyMap;
procstrat = RelationGetRTStrategy(r, attnum, proc);
strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(r),
RTNStrategies,
attnum);
return strategyMap->entry[RTOperMap[procstrat - 1] - 1].sk_procedure;
}