mirror of
https://github.com/postgres/postgres.git
synced 2025-07-17 06:41:09 +03:00
Add operator strategy and comparison-value datatype fields to ScanKey.
Remove the 'strategy map' code, which was a large amount of mechanism that no longer had any use except reverse-mapping from procedure OID to strategy number. Passing the strategy number to the index AM in the first place is simpler and faster. This is a preliminary step in planned support for cross-datatype index operations. I'm committing it now since the ScanKeyEntryInitialize() API change touches quite a lot of files, and I want to commit those changes before the tree drifts under me.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/Attic/indexvalid.c,v 1.29 2003/08/04 02:39:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/Attic/indexvalid.c,v 1.30 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -57,12 +57,9 @@ index_keytest(IndexTuple tuple,
|
||||
if (key->sk_flags & SK_ISNULL)
|
||||
return false;
|
||||
|
||||
if (key->sk_flags & SK_COMMUTE)
|
||||
test = FunctionCall2(&key->sk_func, key->sk_argument, datum);
|
||||
else
|
||||
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
|
||||
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
|
||||
|
||||
if (DatumGetBool(test) == !!(key->sk_flags & SK_NEGATE))
|
||||
if (!DatumGetBool(test))
|
||||
return false;
|
||||
|
||||
key++;
|
||||
|
@ -1,73 +1,46 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* scan.c
|
||||
* scan direction and key code
|
||||
* scankey.c
|
||||
* scan key support code
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.22 2003/08/04 02:39:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.23 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/skey.h"
|
||||
|
||||
/*
|
||||
* ScanKeyEntryIsLegal
|
||||
* True iff the scan key entry is legal.
|
||||
*/
|
||||
#define ScanKeyEntryIsLegal(entry) \
|
||||
( \
|
||||
AssertMacro(PointerIsValid(entry)), \
|
||||
AttributeNumberIsValid((entry)->sk_attno) \
|
||||
)
|
||||
|
||||
/*
|
||||
* ScanKeyEntrySetIllegal
|
||||
* Marks a scan key entry as illegal.
|
||||
*/
|
||||
void
|
||||
ScanKeyEntrySetIllegal(ScanKey entry)
|
||||
{
|
||||
|
||||
Assert(PointerIsValid(entry));
|
||||
|
||||
entry->sk_flags = 0; /* just in case... */
|
||||
entry->sk_attno = InvalidAttrNumber;
|
||||
entry->sk_procedure = 0; /* should be InvalidRegProcedure */
|
||||
entry->sk_func.fn_oid = InvalidOid;
|
||||
entry->sk_argument = (Datum) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ScanKeyEntryInitialize
|
||||
* Initializes a scan key entry.
|
||||
* Initializes a scan key entry given all the field values.
|
||||
* The target procedure is specified by OID.
|
||||
*
|
||||
* Note:
|
||||
* Assumes the scan key entry is valid.
|
||||
* Assumes the intialized scan key entry will be legal.
|
||||
* Note: CurrentMemoryContext at call should be as long-lived as the ScanKey
|
||||
* itself, because that's what will be used for any subsidiary info attached
|
||||
* to the ScanKey's FmgrInfo record.
|
||||
*/
|
||||
void
|
||||
ScanKeyEntryInitialize(ScanKey entry,
|
||||
bits16 flags,
|
||||
int flags,
|
||||
AttrNumber attributeNumber,
|
||||
StrategyNumber strategy,
|
||||
RegProcedure procedure,
|
||||
Datum argument)
|
||||
Datum argument,
|
||||
Oid argtype)
|
||||
{
|
||||
Assert(PointerIsValid(entry));
|
||||
|
||||
entry->sk_flags = flags;
|
||||
entry->sk_attno = attributeNumber;
|
||||
entry->sk_procedure = procedure;
|
||||
entry->sk_strategy = strategy;
|
||||
entry->sk_argument = argument;
|
||||
entry->sk_argtype = argtype;
|
||||
fmgr_info(procedure, &entry->sk_func);
|
||||
|
||||
Assert(ScanKeyEntryIsLegal(entry));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -75,25 +48,23 @@ ScanKeyEntryInitialize(ScanKey entry,
|
||||
* Initializes a scan key entry using an already-completed FmgrInfo
|
||||
* function lookup record.
|
||||
*
|
||||
* mcxt is the memory context holding the scan key; it'll be used for
|
||||
* any subsidiary info attached to the scankey's FmgrInfo record.
|
||||
* Note: CurrentMemoryContext at call should be as long-lived as the ScanKey
|
||||
* itself, because that's what will be used for any subsidiary info attached
|
||||
* to the ScanKey's FmgrInfo record.
|
||||
*/
|
||||
void
|
||||
ScanKeyEntryInitializeWithInfo(ScanKey entry,
|
||||
bits16 flags,
|
||||
int flags,
|
||||
AttrNumber attributeNumber,
|
||||
StrategyNumber strategy,
|
||||
FmgrInfo *finfo,
|
||||
MemoryContext mcxt,
|
||||
Datum argument)
|
||||
Datum argument,
|
||||
Oid argtype)
|
||||
{
|
||||
Assert(PointerIsValid(entry));
|
||||
Assert(RegProcedureIsValid(finfo->fn_oid));
|
||||
|
||||
entry->sk_flags = flags;
|
||||
entry->sk_attno = attributeNumber;
|
||||
entry->sk_procedure = finfo->fn_oid;
|
||||
entry->sk_strategy = strategy;
|
||||
entry->sk_argument = argument;
|
||||
fmgr_info_copy(&entry->sk_func, finfo, mcxt);
|
||||
|
||||
Assert(ScanKeyEntryIsLegal(entry));
|
||||
entry->sk_argtype = argtype;
|
||||
fmgr_info_copy(&entry->sk_func, finfo, CurrentMemoryContext);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
# Makefile for access/gist
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/gist/Makefile,v 1.10 2000/08/31 16:09:31 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/gist/Makefile,v 1.11 2003/11/09 21:30:35 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -12,7 +12,7 @@ subdir = src/backend/access/gist
|
||||
top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = gist.o gistget.o gistscan.o giststrat.o
|
||||
OBJS = gist.o gistget.o gistscan.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.36 2003/08/04 02:39:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.37 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -249,26 +249,16 @@ gistindex_keytest(IndexTuple tuple,
|
||||
IndexTupleSize(tuple) - sizeof(IndexTupleData),
|
||||
FALSE, isNull);
|
||||
|
||||
if (key[0].sk_flags & SK_COMMUTE)
|
||||
{
|
||||
test = FunctionCall3(&key[0].sk_func,
|
||||
key[0].sk_argument,
|
||||
PointerGetDatum(&de),
|
||||
ObjectIdGetDatum(key[0].sk_procedure));
|
||||
}
|
||||
else
|
||||
{
|
||||
test = FunctionCall3(&key[0].sk_func,
|
||||
PointerGetDatum(&de),
|
||||
key[0].sk_argument,
|
||||
ObjectIdGetDatum(key[0].sk_procedure));
|
||||
}
|
||||
test = FunctionCall3(&key[0].sk_func,
|
||||
PointerGetDatum(&de),
|
||||
key[0].sk_argument,
|
||||
Int32GetDatum(key[0].sk_strategy));
|
||||
|
||||
if (de.key != datum && !isAttByVal(giststate, key[0].sk_attno - 1))
|
||||
if (DatumGetPointer(de.key) != NULL)
|
||||
pfree(DatumGetPointer(de.key));
|
||||
|
||||
if (DatumGetBool(test) == !!(key[0].sk_flags & SK_NEGATE))
|
||||
if (!DatumGetBool(test))
|
||||
return false;
|
||||
|
||||
scanKeySize--;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.47 2003/08/04 02:39:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.48 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -106,17 +106,13 @@ gistrescan(PG_FUNCTION_ARGS)
|
||||
s->numberOfKeys * sizeof(ScanKeyData));
|
||||
|
||||
/*
|
||||
* Play games here with the scan key to use the Consistent
|
||||
* function for all comparisons: 1) the sk_procedure field will
|
||||
* now be used to hold the strategy number 2) the sk_func field
|
||||
* will point to the Consistent function
|
||||
* Modify the scan key so that the Consistent function is called
|
||||
* for all comparisons. The original operator is passed to the
|
||||
* Consistent function in the form of its strategy number, which
|
||||
* is available from the sk_strategy field.
|
||||
*/
|
||||
for (i = 0; i < s->numberOfKeys; i++)
|
||||
{
|
||||
s->keyData[i].sk_procedure =
|
||||
RelationGetGISTStrategy(s->indexRelation,
|
||||
s->keyData[i].sk_attno,
|
||||
s->keyData[i].sk_procedure);
|
||||
s->keyData[i].sk_func = p->giststate->consistentFn[s->keyData[i].sk_attno - 1];
|
||||
}
|
||||
}
|
||||
|
@ -1,125 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* giststrat.c
|
||||
* strategy map data for GiSTs.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/Attic/giststrat.c,v 1.21 2003/08/04 02:39:57 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/gist.h"
|
||||
#include "access/istrat.h"
|
||||
|
||||
|
||||
/*
|
||||
* Note: negate, commute, and negatecommute all assume that operators are
|
||||
* ordered as follows in the strategy map:
|
||||
*
|
||||
* 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 GiST 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 GiST 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 GISTNegate[GISTNStrategies] = {
|
||||
InvalidStrategy,
|
||||
InvalidStrategy,
|
||||
InvalidStrategy
|
||||
};
|
||||
|
||||
/* if a op_1 b, what is the operator op_2 such that b op_2 a? */
|
||||
static StrategyNumber GISTCommute[GISTNStrategies] = {
|
||||
InvalidStrategy,
|
||||
InvalidStrategy,
|
||||
InvalidStrategy
|
||||
};
|
||||
|
||||
/* if a op_1 b, what is the operator op_2 such that (b !op_2 a)? */
|
||||
static StrategyNumber GISTNegateCommute[GISTNStrategies] = {
|
||||
InvalidStrategy,
|
||||
InvalidStrategy,
|
||||
InvalidStrategy
|
||||
};
|
||||
|
||||
/*
|
||||
* GiSTs do not currently support TermData (see rtree/rtstrat.c for
|
||||
* discussion of
|
||||
* TermData) -- such logic must be encoded in the user's Consistent function.
|
||||
*/
|
||||
|
||||
static StrategyExpression GISTEvaluationExpressions[GISTNStrategies] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* If you were sufficiently attentive to detail, you would go through
|
||||
* the ExpressionData pain above for every one of the 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 StrategyEvaluationData GISTEvaluationData = {
|
||||
GISTNStrategies, /* # of strategies */
|
||||
(StrategyTransformMap) GISTNegate, /* how to do (not qual) */
|
||||
(StrategyTransformMap) GISTCommute, /* how to swap operands */
|
||||
(StrategyTransformMap) GISTNegateCommute, /* how to do both */
|
||||
GISTEvaluationExpressions
|
||||
};
|
||||
|
||||
|
||||
StrategyNumber
|
||||
RelationGetGISTStrategy(Relation r,
|
||||
AttrNumber attnum,
|
||||
RegProcedure proc)
|
||||
{
|
||||
return RelationGetStrategy(r, attnum, &GISTEvaluationData, proc);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
bool
|
||||
RelationInvokeGISTStrategy(Relation r,
|
||||
AttrNumber attnum,
|
||||
StrategyNumber s,
|
||||
Datum left,
|
||||
Datum right)
|
||||
{
|
||||
return (RelationInvokeStrategy(r, &GISTEvaluationData, attnum, s,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
@ -4,7 +4,7 @@
|
||||
# Makefile for access/hash
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/hash/Makefile,v 1.10 2000/08/31 16:09:33 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/hash/Makefile,v 1.11 2003/11/09 21:30:35 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -13,7 +13,7 @@ top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = hash.o hashfunc.o hashinsert.o hashovfl.o hashpage.o hashscan.o \
|
||||
hashsearch.o hashstrat.o hashutil.o
|
||||
hashsearch.o hashutil.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hashstrat.c
|
||||
* Strategy map entries for the hash indexed access method
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/Attic/hashstrat.c,v 1.23 2003/08/04 02:39:57 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/hash.h"
|
||||
|
||||
|
||||
/*
|
||||
* only one valid strategy for hash tables: equality.
|
||||
*/
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
static StrategyNumber HTNegate[HTMaxStrategyNumber] = {
|
||||
InvalidStrategy
|
||||
};
|
||||
|
||||
static StrategyNumber HTCommute[HTMaxStrategyNumber] = {
|
||||
HTEqualStrategyNumber
|
||||
};
|
||||
|
||||
static StrategyNumber HTNegateCommute[HTMaxStrategyNumber] = {
|
||||
InvalidStrategy
|
||||
};
|
||||
|
||||
static StrategyExpression HTEvaluationExpressions[HTMaxStrategyNumber] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static StrategyEvaluationData HTEvaluationData = {
|
||||
HTMaxStrategyNumber,
|
||||
(StrategyTransformMap) HTNegate,
|
||||
(StrategyTransformMap) HTCommute,
|
||||
(StrategyTransformMap) HTNegateCommute,
|
||||
HTEvaluationExpressions
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* RelationGetHashStrategy
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef NOT_USED
|
||||
static StrategyNumber
|
||||
_hash_getstrat(Relation rel,
|
||||
AttrNumber attno,
|
||||
RegProcedure proc)
|
||||
{
|
||||
StrategyNumber strat;
|
||||
|
||||
strat = RelationGetStrategy(rel, attno, &HTEvaluationData, proc);
|
||||
|
||||
Assert(StrategyNumberIsValid(strat));
|
||||
|
||||
return strat;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
static bool
|
||||
_hash_invokestrat(Relation rel,
|
||||
AttrNumber attno,
|
||||
StrategyNumber strat,
|
||||
Datum left,
|
||||
Datum right)
|
||||
{
|
||||
return (RelationInvokeStrategy(rel, &HTEvaluationData, attno, strat,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.38 2003/08/04 23:59:37 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.39 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -31,6 +31,7 @@
|
||||
#include "access/genam.h"
|
||||
#include "access/tuptoaster.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
@ -967,11 +968,11 @@ toast_delete_datum(Relation rel, Datum value)
|
||||
* Setup a scan key to fetch from the index by va_valueid (we don't
|
||||
* particularly care whether we see them in sequence or not)
|
||||
*/
|
||||
ScanKeyEntryInitialize(&toastkey,
|
||||
(bits16) 0,
|
||||
ScanKeyEntryInitialize(&toastkey, 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid),
|
||||
OIDOID);
|
||||
|
||||
/*
|
||||
* Find the chunks by index
|
||||
@ -1039,11 +1040,11 @@ toast_fetch_datum(varattrib *attr)
|
||||
/*
|
||||
* Setup a scan key to fetch from the index by va_valueid
|
||||
*/
|
||||
ScanKeyEntryInitialize(&toastkey,
|
||||
(bits16) 0,
|
||||
ScanKeyEntryInitialize(&toastkey, 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid),
|
||||
OIDOID);
|
||||
|
||||
/*
|
||||
* Read the chunks by index
|
||||
@ -1194,37 +1195,33 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
|
||||
* Setup a scan key to fetch from the index. This is either two keys
|
||||
* or three depending on the number of chunks.
|
||||
*/
|
||||
ScanKeyEntryInitialize(&toastkey[0],
|
||||
(bits16) 0,
|
||||
ScanKeyEntryInitialize(&toastkey[0], 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid),
|
||||
OIDOID);
|
||||
|
||||
/*
|
||||
* Now dependent on number of chunks:
|
||||
* Use equality condition for one chunk, a range condition otherwise:
|
||||
*/
|
||||
|
||||
if (numchunks == 1)
|
||||
{
|
||||
ScanKeyEntryInitialize(&toastkey[1],
|
||||
(bits16) 0,
|
||||
ScanKeyEntryInitialize(&toastkey[1], 0,
|
||||
(AttrNumber) 2,
|
||||
(RegProcedure) F_INT4EQ,
|
||||
Int32GetDatum(startchunk));
|
||||
BTEqualStrategyNumber, F_INT4EQ,
|
||||
Int32GetDatum(startchunk), INT4OID);
|
||||
nscankeys = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScanKeyEntryInitialize(&toastkey[1],
|
||||
(bits16) 0,
|
||||
ScanKeyEntryInitialize(&toastkey[1], 0,
|
||||
(AttrNumber) 2,
|
||||
(RegProcedure) F_INT4GE,
|
||||
Int32GetDatum(startchunk));
|
||||
ScanKeyEntryInitialize(&toastkey[2],
|
||||
(bits16) 0,
|
||||
BTGreaterEqualStrategyNumber, F_INT4GE,
|
||||
Int32GetDatum(startchunk), INT4OID);
|
||||
ScanKeyEntryInitialize(&toastkey[2], 0,
|
||||
(AttrNumber) 2,
|
||||
(RegProcedure) F_INT4LE,
|
||||
Int32GetDatum(endchunk));
|
||||
BTLessEqualStrategyNumber, F_INT4LE,
|
||||
Int32GetDatum(endchunk), INT4OID);
|
||||
nscankeys = 3;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# Makefile for access/index
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/index/Makefile,v 1.10 2000/08/31 16:09:36 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/index/Makefile,v 1.11 2003/11/09 21:30:35 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -12,7 +12,7 @@ subdir = src/backend/access/index
|
||||
top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = genam.o indexam.o istrat.o
|
||||
OBJS = genam.o indexam.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
@ -1,479 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* istrat.c
|
||||
* index scan strategy manipulation code and index strategy manipulation
|
||||
* operator code.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.60 2003/08/04 02:39:57 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/istrat.h"
|
||||
|
||||
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
|
||||
static bool StrategyExpressionIsValid(StrategyExpression expression,
|
||||
StrategyNumber maxStrategy);
|
||||
static bool StrategyOperatorIsValid(StrategyOperator operator,
|
||||
StrategyNumber maxStrategy);
|
||||
static bool StrategyTermIsValid(StrategyTerm term,
|
||||
StrategyNumber maxStrategy);
|
||||
#endif
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* 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);
|
||||
}
|
||||
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
/*
|
||||
* StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* StrategyOperatorIsValid
|
||||
* ----------------
|
||||
*/
|
||||
static bool
|
||||
StrategyOperatorIsValid(StrategyOperator operator,
|
||||
StrategyNumber maxStrategy)
|
||||
{
|
||||
return (bool)
|
||||
(PointerIsValid(operator) &&
|
||||
StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
|
||||
!(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* StrategyTermIsValid
|
||||
* ----------------
|
||||
*/
|
||||
static 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
|
||||
* ----------------
|
||||
*/
|
||||
static 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
|
||||
* ----------------
|
||||
*/
|
||||
static 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
/* ----------------
|
||||
* StrategyTermEvaluate
|
||||
* ----------------
|
||||
*/
|
||||
static bool
|
||||
StrategyTermEvaluate(StrategyTerm term,
|
||||
StrategyMap map,
|
||||
Datum left,
|
||||
Datum right)
|
||||
{
|
||||
bool result = false;
|
||||
Index index;
|
||||
StrategyOperator operator;
|
||||
|
||||
for (index = 0, operator = &term->operatorData[0];
|
||||
index < term->degree; index += 1, operator += 1)
|
||||
{
|
||||
ScanKey entry;
|
||||
|
||||
entry = &map->entry[operator->strategy - 1];
|
||||
|
||||
Assert(RegProcedureIsValid(entry->sk_procedure));
|
||||
|
||||
switch (operator->flags ^ entry->sk_flags)
|
||||
{
|
||||
case 0x0:
|
||||
result = DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
left, right));
|
||||
break;
|
||||
|
||||
case SK_NEGATE:
|
||||
result = !DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
left, right));
|
||||
break;
|
||||
|
||||
case SK_COMMUTE:
|
||||
result = DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
right, left));
|
||||
break;
|
||||
|
||||
case SK_NEGATE | SK_COMMUTE:
|
||||
result = !DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
right, left));
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "impossible strategy case: %d",
|
||||
operator->flags ^ entry->sk_flags);
|
||||
}
|
||||
if (!result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
* RelationGetStrategy
|
||||
*
|
||||
* Identify strategy number that describes given procedure, if there is one.
|
||||
* ----------------
|
||||
*/
|
||||
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((attributeNumber >= 1) && (attributeNumber <= 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(ERROR, "impossible strategy case: %d",
|
||||
entry->sk_flags);
|
||||
}
|
||||
|
||||
if (!StrategyNumberIsInBounds(strategy, evaluation->maxStrategy))
|
||||
{
|
||||
if (!StrategyNumberIsValid(strategy))
|
||||
elog(ERROR, "corrupted strategy evaluation");
|
||||
}
|
||||
|
||||
return strategy;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
/* ----------------
|
||||
* 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(ERROR, "cannot evaluate strategy %d", strategy);
|
||||
|
||||
/* not reached, just to make compiler happy */
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
* 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) */
|
@ -4,7 +4,7 @@
|
||||
# Makefile for access/nbtree
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/nbtree/Makefile,v 1.12 2003/02/21 00:06:21 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/access/nbtree/Makefile,v 1.13 2003/11/09 21:30:35 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -13,7 +13,7 @@ top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = nbtcompare.o nbtinsert.o nbtpage.o nbtree.o nbtsearch.o \
|
||||
nbtstrat.o nbtutils.o nbtsort.o nbtxlog.o
|
||||
nbtutils.o nbtsort.o nbtxlog.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* btinsert.c
|
||||
* nbtinsert.c
|
||||
* Item insertion in Lehman and Yao btrees for Postgres.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.106 2003/09/25 06:57:57 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.107 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.80 2003/08/08 21:41:27 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.81 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -488,8 +488,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
/* if we didn't find a boundary for the preceding attr, quit */
|
||||
if (attno > keysCount + 1)
|
||||
break;
|
||||
strat = _bt_getstrat(rel, attno,
|
||||
so->keyData[i].sk_procedure);
|
||||
|
||||
/*
|
||||
* Can we use this key as a starting boundary for this attr?
|
||||
@ -497,6 +495,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
* We can use multiple keys if they look like, say, = >= = but we
|
||||
* have to stop after accepting a > or < boundary.
|
||||
*/
|
||||
strat = so->keyData[i].sk_strategy;
|
||||
if (strat == strat_total ||
|
||||
strat == BTEqualStrategyNumber)
|
||||
nKeyIs[keysCount++] = i;
|
||||
@ -555,13 +554,17 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
elog(ERROR, "btree doesn't support is(not)null, yet");
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* XXX what if sk_argtype is not same as index?
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
ScanKeyEntryInitializeWithInfo(scankeys + i,
|
||||
so->keyData[j].sk_flags,
|
||||
i + 1,
|
||||
InvalidStrategy,
|
||||
procinfo,
|
||||
CurrentMemoryContext,
|
||||
so->keyData[j].sk_argument);
|
||||
so->keyData[j].sk_argument,
|
||||
so->keyData[j].sk_argtype);
|
||||
}
|
||||
if (nKeyIs)
|
||||
pfree(nKeyIs);
|
||||
|
@ -1,138 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* nbtstrat.c
|
||||
* Strategy map entries for the btree indexed access method
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.18 2003/08/04 02:39:57 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/istrat.h"
|
||||
#include "access/nbtree.h"
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* StrategyNegate, StrategyCommute, and StrategyNegateCommute
|
||||
* assume <, <=, ==, >=, > ordering.
|
||||
*/
|
||||
static StrategyNumber BTNegate[BTMaxStrategyNumber] = {
|
||||
BTGreaterEqualStrategyNumber,
|
||||
BTGreaterStrategyNumber,
|
||||
InvalidStrategy,
|
||||
BTLessStrategyNumber,
|
||||
BTLessEqualStrategyNumber
|
||||
};
|
||||
|
||||
static StrategyNumber BTCommute[BTMaxStrategyNumber] = {
|
||||
BTGreaterStrategyNumber,
|
||||
BTGreaterEqualStrategyNumber,
|
||||
InvalidStrategy,
|
||||
BTLessEqualStrategyNumber,
|
||||
BTLessStrategyNumber
|
||||
};
|
||||
|
||||
static StrategyNumber BTNegateCommute[BTMaxStrategyNumber] = {
|
||||
BTLessEqualStrategyNumber,
|
||||
BTLessStrategyNumber,
|
||||
InvalidStrategy,
|
||||
BTGreaterStrategyNumber,
|
||||
BTGreaterEqualStrategyNumber
|
||||
};
|
||||
|
||||
static uint16 BTLessTermData[] = { /* XXX type clash */
|
||||
2,
|
||||
BTLessStrategyNumber,
|
||||
SK_NEGATE,
|
||||
BTLessStrategyNumber,
|
||||
SK_NEGATE | SK_COMMUTE
|
||||
};
|
||||
|
||||
static uint16 BTLessEqualTermData[] = { /* XXX type clash */
|
||||
2,
|
||||
BTLessEqualStrategyNumber,
|
||||
0x0,
|
||||
BTLessEqualStrategyNumber,
|
||||
SK_COMMUTE
|
||||
};
|
||||
|
||||
static uint16 BTGreaterEqualTermData[] = { /* XXX type clash */
|
||||
2,
|
||||
BTGreaterEqualStrategyNumber,
|
||||
0x0,
|
||||
BTGreaterEqualStrategyNumber,
|
||||
SK_COMMUTE
|
||||
};
|
||||
|
||||
static uint16 BTGreaterTermData[] = { /* XXX type clash */
|
||||
2,
|
||||
BTGreaterStrategyNumber,
|
||||
SK_NEGATE,
|
||||
BTGreaterStrategyNumber,
|
||||
SK_NEGATE | SK_COMMUTE
|
||||
};
|
||||
|
||||
static StrategyTerm BTEqualExpressionData[] = {
|
||||
(StrategyTerm) BTLessTermData, /* XXX */
|
||||
(StrategyTerm) BTLessEqualTermData, /* XXX */
|
||||
(StrategyTerm) BTGreaterEqualTermData, /* XXX */
|
||||
(StrategyTerm) BTGreaterTermData, /* XXX */
|
||||
NULL
|
||||
};
|
||||
|
||||
static StrategyExpression BTEvaluationExpressions[BTMaxStrategyNumber] = {
|
||||
NULL,
|
||||
NULL,
|
||||
(StrategyExpression) BTEqualExpressionData,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static StrategyEvaluationData BTEvaluationData = {
|
||||
BTMaxStrategyNumber,
|
||||
(StrategyTransformMap) BTNegate,
|
||||
(StrategyTransformMap) BTCommute,
|
||||
(StrategyTransformMap) BTNegateCommute,
|
||||
BTEvaluationExpressions
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* RelationGetBTStrategy
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
StrategyNumber
|
||||
_bt_getstrat(Relation rel,
|
||||
AttrNumber attno,
|
||||
RegProcedure proc)
|
||||
{
|
||||
StrategyNumber strat;
|
||||
|
||||
strat = RelationGetStrategy(rel, attno, &BTEvaluationData, proc);
|
||||
|
||||
Assert(StrategyNumberIsValid(strat));
|
||||
|
||||
return strat;
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
bool
|
||||
_bt_invokestrat(Relation rel,
|
||||
AttrNumber attno,
|
||||
StrategyNumber strat,
|
||||
Datum left,
|
||||
Datum right)
|
||||
{
|
||||
return (RelationInvokeStrategy(rel, &BTEvaluationData, attno, strat,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* btutils.c
|
||||
* nbtutils.c
|
||||
* Utility code for Postgres btree implementation.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.54 2003/08/04 02:39:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.55 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,13 +16,10 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/istrat.h"
|
||||
#include "access/nbtree.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "executor/execdebug.h"
|
||||
|
||||
|
||||
static int _bt_getstrategynumber(RegProcedure sk_procedure, StrategyMap map);
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -39,10 +36,6 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
TupleDesc itupdesc;
|
||||
int natts;
|
||||
int i;
|
||||
FmgrInfo *procinfo;
|
||||
Datum arg;
|
||||
bool null;
|
||||
bits16 flag;
|
||||
|
||||
itupdesc = RelationGetDescr(rel);
|
||||
natts = RelationGetNumberOfAttributes(rel);
|
||||
@ -51,15 +44,23 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
|
||||
for (i = 0; i < natts; i++)
|
||||
{
|
||||
FmgrInfo *procinfo;
|
||||
Datum arg;
|
||||
bool null;
|
||||
|
||||
/*
|
||||
* We can use the cached support procs since no cross-type comparison
|
||||
* can be needed.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
||||
flag = null ? SK_ISNULL : 0x0;
|
||||
ScanKeyEntryInitializeWithInfo(&skey[i],
|
||||
flag,
|
||||
null ? SK_ISNULL : 0,
|
||||
(AttrNumber) (i + 1),
|
||||
InvalidStrategy,
|
||||
procinfo,
|
||||
CurrentMemoryContext,
|
||||
arg);
|
||||
arg,
|
||||
itupdesc->attrs[i]->atttypid);
|
||||
}
|
||||
|
||||
return skey;
|
||||
@ -68,33 +69,42 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||
/*
|
||||
* _bt_mkscankey_nodata
|
||||
* Build a scan key that contains comparator routines appropriate to
|
||||
* the key datatypes, but no comparison data.
|
||||
* the key datatypes, but no comparison data. The comparison data
|
||||
* ultimately used must match the key datatypes.
|
||||
*
|
||||
* The result cannot be used with _bt_compare(). Currently this
|
||||
* routine is only called by utils/sort/tuplesort.c, which has its
|
||||
* own comparison routine.
|
||||
* routine is only called by nbtsort.c and tuplesort.c, which have
|
||||
* their own comparison routines.
|
||||
*/
|
||||
ScanKey
|
||||
_bt_mkscankey_nodata(Relation rel)
|
||||
{
|
||||
ScanKey skey;
|
||||
TupleDesc itupdesc;
|
||||
int natts;
|
||||
int i;
|
||||
FmgrInfo *procinfo;
|
||||
|
||||
itupdesc = RelationGetDescr(rel);
|
||||
natts = RelationGetNumberOfAttributes(rel);
|
||||
|
||||
skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
|
||||
|
||||
for (i = 0; i < natts; i++)
|
||||
{
|
||||
FmgrInfo *procinfo;
|
||||
|
||||
/*
|
||||
* We can use the cached support procs since no cross-type comparison
|
||||
* can be needed.
|
||||
*/
|
||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||
ScanKeyEntryInitializeWithInfo(&skey[i],
|
||||
SK_ISNULL,
|
||||
(AttrNumber) (i + 1),
|
||||
InvalidStrategy,
|
||||
procinfo,
|
||||
CurrentMemoryContext,
|
||||
(Datum) 0);
|
||||
(Datum) 0,
|
||||
itupdesc->attrs[i]->atttypid);
|
||||
}
|
||||
|
||||
return skey;
|
||||
@ -185,17 +195,6 @@ _bt_formitem(IndexTuple itup)
|
||||
* The initial ordering of the keys is expected to be by attribute already
|
||||
* (see group_clauses_by_indexkey() in indxpath.c). The task here is to
|
||||
* standardize the appearance of multiple keys for the same attribute.
|
||||
*
|
||||
* XXX this routine is one of many places that fail to handle SK_COMMUTE
|
||||
* scankeys properly. Currently, the planner is careful never to generate
|
||||
* any indexquals that would require SK_COMMUTE to be set. Someday we ought
|
||||
* to try to fix this, though it's not real critical as long as indexable
|
||||
* operators all have commutators...
|
||||
*
|
||||
* Note: this routine invokes comparison operators via OidFunctionCallN,
|
||||
* ie, without caching function lookups. No point in trying to be smarter,
|
||||
* since these comparisons are executed only when the user expresses a
|
||||
* hokey qualification, and happen only once per scan anyway.
|
||||
*----------
|
||||
*/
|
||||
void
|
||||
@ -208,7 +207,6 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
int numberOfKeys = so->numberOfKeys;
|
||||
ScanKey key;
|
||||
ScanKey cur;
|
||||
StrategyMap map;
|
||||
Datum test;
|
||||
int i,
|
||||
j;
|
||||
@ -229,6 +227,32 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
if (cur->sk_attno != 1)
|
||||
elog(ERROR, "key(s) for attribute 1 missed");
|
||||
|
||||
#if 0
|
||||
/* XXX verify that operator strategy info is correct */
|
||||
/* XXX this is temporary for debugging; it's pretty expensive */
|
||||
/* XXX can't do it during bootstrap, else will recurse infinitely */
|
||||
{
|
||||
extern bool criticalRelcachesBuilt;
|
||||
static bool inRecursion = false;
|
||||
|
||||
if (criticalRelcachesBuilt && !inRecursion)
|
||||
{
|
||||
inRecursion = true;
|
||||
for (i = 0; i < numberOfKeys; i++)
|
||||
{
|
||||
AttrNumber attno = key[i].sk_attno;
|
||||
Oid opclass;
|
||||
Oid chk_oper;
|
||||
|
||||
opclass = relation->rd_index->indclass[attno-1];
|
||||
chk_oper = get_opclass_member(opclass, key[i].sk_strategy);
|
||||
Assert(key[i].sk_func.fn_oid == get_opcode(chk_oper));
|
||||
}
|
||||
inRecursion = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We can short-circuit most of the work if there's just one key */
|
||||
if (numberOfKeys == 1)
|
||||
{
|
||||
@ -243,11 +267,7 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
relation->rd_rel->relnatts == 1)
|
||||
{
|
||||
/* it's a unique index, do we have an equality qual? */
|
||||
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
BTMaxStrategyNumber,
|
||||
1);
|
||||
j = _bt_getstrategynumber(cur->sk_procedure, map);
|
||||
if (j == (BTEqualStrategyNumber - 1))
|
||||
if (cur->sk_strategy == BTEqualStrategyNumber)
|
||||
scan->keys_are_unique = true;
|
||||
}
|
||||
so->numberOfRequiredKeys = 1;
|
||||
@ -267,9 +287,6 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
* any; init[i] is TRUE if we have found such a key for this attr.
|
||||
*/
|
||||
attno = 1;
|
||||
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
BTMaxStrategyNumber,
|
||||
attno);
|
||||
MemSet(xform, 0, sizeof(xform)); /* not really necessary */
|
||||
MemSet(init, 0, sizeof(init));
|
||||
|
||||
@ -324,9 +341,9 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
j == (BTEqualStrategyNumber - 1))
|
||||
continue;
|
||||
chk = &xform[j];
|
||||
test = OidFunctionCall2(chk->sk_procedure,
|
||||
eq->sk_argument,
|
||||
chk->sk_argument);
|
||||
test = FunctionCall2(&chk->sk_func,
|
||||
eq->sk_argument,
|
||||
chk->sk_argument);
|
||||
if (!DatumGetBool(test))
|
||||
so->qual_ok = false;
|
||||
}
|
||||
@ -350,9 +367,9 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
ScanKeyData *lt = &xform[BTLessStrategyNumber - 1];
|
||||
ScanKeyData *le = &xform[BTLessEqualStrategyNumber - 1];
|
||||
|
||||
test = OidFunctionCall2(le->sk_procedure,
|
||||
lt->sk_argument,
|
||||
le->sk_argument);
|
||||
test = FunctionCall2(&le->sk_func,
|
||||
lt->sk_argument,
|
||||
le->sk_argument);
|
||||
if (DatumGetBool(test))
|
||||
init[BTLessEqualStrategyNumber - 1] = false;
|
||||
else
|
||||
@ -366,9 +383,9 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
ScanKeyData *gt = &xform[BTGreaterStrategyNumber - 1];
|
||||
ScanKeyData *ge = &xform[BTGreaterEqualStrategyNumber - 1];
|
||||
|
||||
test = OidFunctionCall2(ge->sk_procedure,
|
||||
gt->sk_argument,
|
||||
ge->sk_argument);
|
||||
test = FunctionCall2(&ge->sk_func,
|
||||
gt->sk_argument,
|
||||
ge->sk_argument);
|
||||
if (DatumGetBool(test))
|
||||
init[BTGreaterEqualStrategyNumber - 1] = false;
|
||||
else
|
||||
@ -404,15 +421,12 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
|
||||
/* Re-initialize for new attno */
|
||||
attno = cur->sk_attno;
|
||||
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
BTMaxStrategyNumber,
|
||||
attno);
|
||||
MemSet(xform, 0, sizeof(xform)); /* not really necessary */
|
||||
MemSet(init, 0, sizeof(init));
|
||||
}
|
||||
|
||||
/* figure out which strategy this key's operator corresponds to */
|
||||
j = _bt_getstrategynumber(cur->sk_procedure, map);
|
||||
j = cur->sk_strategy - 1;
|
||||
|
||||
/* have we seen one of these before? */
|
||||
if (init[j])
|
||||
@ -446,25 +460,6 @@ _bt_orderkeys(IndexScanDesc scan)
|
||||
scan->keys_are_unique = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine which btree strategy an operator procedure matches.
|
||||
*
|
||||
* Result is strategy number minus 1.
|
||||
*/
|
||||
static int
|
||||
_bt_getstrategynumber(RegProcedure sk_procedure, StrategyMap map)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = BTMaxStrategyNumber; --j >= 0;)
|
||||
{
|
||||
if (sk_procedure == map->entry[j].sk_procedure)
|
||||
return j;
|
||||
}
|
||||
elog(ERROR, "could not identify operator %u", sk_procedure);
|
||||
return -1; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether an indextuple satisfies all the scankey conditions.
|
||||
*
|
||||
@ -533,14 +528,9 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key->sk_flags & SK_COMMUTE)
|
||||
test = FunctionCall2(&key->sk_func,
|
||||
key->sk_argument, datum);
|
||||
else
|
||||
test = FunctionCall2(&key->sk_func,
|
||||
datum, key->sk_argument);
|
||||
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
|
||||
|
||||
if (DatumGetBool(test) == !!(key->sk_flags & SK_NEGATE))
|
||||
if (!DatumGetBool(test))
|
||||
{
|
||||
/*
|
||||
* Tuple fails this qual. If it's a required qual, then we
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.47 2003/08/04 02:39:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.48 2003/11/09 21:30:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/rtree.h"
|
||||
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
/* routines defined and used here */
|
||||
@ -71,7 +71,6 @@ rtrescan(PG_FUNCTION_ARGS)
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(1);
|
||||
RTreeScanOpaque p;
|
||||
RegProcedure internal_proc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@ -116,14 +115,23 @@ rtrescan(PG_FUNCTION_ARGS)
|
||||
*/
|
||||
for (i = 0; i < s->numberOfKeys; i++)
|
||||
{
|
||||
internal_proc = RTMapOperator(s->indexRelation,
|
||||
s->keyData[i].sk_attno,
|
||||
s->keyData[i].sk_procedure);
|
||||
AttrNumber attno = s->keyData[i].sk_attno;
|
||||
Oid opclass;
|
||||
StrategyNumber int_strategy;
|
||||
Oid int_oper;
|
||||
RegProcedure int_proc;
|
||||
|
||||
opclass = s->indexRelation->rd_index->indclass[attno-1];
|
||||
int_strategy = RTMapToInternalOperator(s->keyData[i].sk_strategy);
|
||||
int_oper = get_opclass_member(opclass, int_strategy);
|
||||
int_proc = get_opcode(int_oper);
|
||||
ScanKeyEntryInitialize(&(p->s_internalKey[i]),
|
||||
s->keyData[i].sk_flags,
|
||||
s->keyData[i].sk_attno,
|
||||
internal_proc,
|
||||
s->keyData[i].sk_argument);
|
||||
attno,
|
||||
int_strategy,
|
||||
int_proc,
|
||||
s->keyData[i].sk_argument,
|
||||
s->keyData[i].sk_argtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,176 +8,18 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.21 2003/08/04 02:39:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.22 2003/11/09 21:30:35 tgl 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
|
||||
* Here's 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
|
||||
@ -191,7 +33,7 @@ static StrategyEvaluationData RTEvaluationData = {
|
||||
* left, left-or-overlap, overlap, right-or-overlap, right, same,
|
||||
* contains, contained-by
|
||||
*/
|
||||
static StrategyNumber RTOperMap[RTNStrategies] = {
|
||||
static const StrategyNumber RTOperMap[RTNStrategies] = {
|
||||
RTOverLeftStrategyNumber,
|
||||
RTOverLeftStrategyNumber,
|
||||
RTOverlapStrategyNumber,
|
||||
@ -202,39 +44,10 @@ static StrategyNumber RTOperMap[RTNStrategies] = {
|
||||
RTOverlapStrategyNumber
|
||||
};
|
||||
|
||||
static StrategyNumber
|
||||
RelationGetRTStrategy(Relation r,
|
||||
AttrNumber attnum,
|
||||
RegProcedure proc)
|
||||
|
||||
StrategyNumber
|
||||
RTMapToInternalOperator(StrategyNumber strat)
|
||||
{
|
||||
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;
|
||||
Assert(strat > 0 && strat <= RTNStrategies);
|
||||
return RTOperMap[strat - 1];
|
||||
}
|
||||
|
Reference in New Issue
Block a user