Add optional compression method to SP-GiST
Patch allows to have different types of column and value stored in leaf tuples of SP-GiST. The main application of feature is to transform complex column type to simple indexed type or for truncating too long value, transformation could be lossy. Simple example: polygons are converted to their bounding boxes, this opclass follows. Authors: me, Heikki Linnakangas, Alexander Korotkov, Nikita Glukhov Reviewed-By: all authors + Darafei Praliaskouski Discussions: https://www.postgresql.org/message-id/5447B3FF.2080406@sigaev.ru https://www.postgresql.org/message-id/flat/54907069.1030506@sigaev.ru#54907069.1030506@sigaev.ru
This commit is contained in:
parent
9373baa0f7
commit
854823fa33
@ -240,20 +240,22 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are five user-defined methods that an index operator class for
|
There are five user-defined methods that an index operator class for
|
||||||
<acronym>SP-GiST</acronym> must provide. All five follow the convention
|
<acronym>SP-GiST</acronym> must provide, and one is optional. All five
|
||||||
of accepting two <type>internal</type> arguments, the first of which is a
|
mandatory methods follow the convention of accepting two <type>internal</type>
|
||||||
pointer to a C struct containing input values for the support method,
|
arguments, the first of which is a pointer to a C struct containing input
|
||||||
while the second argument is a pointer to a C struct where output values
|
values for the support method, while the second argument is a pointer to a
|
||||||
must be placed. Four of the methods just return <type>void</type>, since
|
C struct where output values must be placed. Four of the mandatory methods just
|
||||||
all their results appear in the output struct; but
|
return <type>void</type>, since all their results appear in the output struct; but
|
||||||
<function>leaf_consistent</function> additionally returns a <type>boolean</type> result.
|
<function>leaf_consistent</function> additionally returns a <type>boolean</type> result.
|
||||||
The methods must not modify any fields of their input structs. In all
|
The methods must not modify any fields of their input structs. In all
|
||||||
cases, the output struct is initialized to zeroes before calling the
|
cases, the output struct is initialized to zeroes before calling the
|
||||||
user-defined method.
|
user-defined method. Optional sixth method <function>compress</function>
|
||||||
|
accepts datum to be indexed as the only argument and returns value suitable
|
||||||
|
for physical storage in leaf tuple.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The five user-defined methods are:
|
The five mandatory user-defined methods are:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
@ -283,6 +285,7 @@ typedef struct spgConfigOut
|
|||||||
{
|
{
|
||||||
Oid prefixType; /* Data type of inner-tuple prefixes */
|
Oid prefixType; /* Data type of inner-tuple prefixes */
|
||||||
Oid labelType; /* Data type of inner-tuple node labels */
|
Oid labelType; /* Data type of inner-tuple node labels */
|
||||||
|
Oid leafType; /* Data type of leaf-tuple values */
|
||||||
bool canReturnData; /* Opclass can reconstruct original data */
|
bool canReturnData; /* Opclass can reconstruct original data */
|
||||||
bool longValuesOK; /* Opclass can cope with values > 1 page */
|
bool longValuesOK; /* Opclass can cope with values > 1 page */
|
||||||
} spgConfigOut;
|
} spgConfigOut;
|
||||||
@ -305,6 +308,22 @@ typedef struct spgConfigOut
|
|||||||
class is capable of segmenting long values by repeated suffixing
|
class is capable of segmenting long values by repeated suffixing
|
||||||
(see <xref linkend="spgist-limits"/>).
|
(see <xref linkend="spgist-limits"/>).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<structfield>leafType</structfield> is typically the same as
|
||||||
|
<structfield>attType</structfield>. For the reasons of backward
|
||||||
|
compatibility, method <function>config</function> can
|
||||||
|
leave <structfield>leafType</structfield> uninitialized; that would
|
||||||
|
give the same effect as setting <structfield>leafType</structfield> equal
|
||||||
|
to <structfield>attType</structfield>. When <structfield>attType</structfield>
|
||||||
|
and <structfield>leafType</structfield> are different, then optional
|
||||||
|
method <function>compress</function> must be provided.
|
||||||
|
Method <function>compress</function> is responsible
|
||||||
|
for transformation of datums to be indexed from <structfield>attType</structfield>
|
||||||
|
to <structfield>leafType</structfield>.
|
||||||
|
Note: both consistent functions will get <structfield>scankeys</structfield>
|
||||||
|
unchanged, without transformation using <function>compress</function>.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@ -380,10 +399,16 @@ typedef struct spgChooseOut
|
|||||||
} spgChooseOut;
|
} spgChooseOut;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<structfield>datum</structfield> is the original datum that was to be inserted
|
<structfield>datum</structfield> is the original datum of
|
||||||
into the index.
|
<structname>spgConfigIn</structname>.<structfield>attType</structfield>
|
||||||
<structfield>leafDatum</structfield> is initially the same as
|
type that was to be inserted into the index.
|
||||||
<structfield>datum</structfield>, but can change at lower levels of the tree
|
<structfield>leafDatum</structfield> is a value of
|
||||||
|
<structname>spgConfigOut</structname>.<structfield>leafType</structfield>
|
||||||
|
type which is initially an result of method
|
||||||
|
<function>compress</function> applied to <structfield>datum</structfield>
|
||||||
|
when method <function>compress</function> is provided, or same value as
|
||||||
|
<structfield>datum</structfield> otherwise.
|
||||||
|
<structfield>leafDatum</structfield> can change at lower levels of the tree
|
||||||
if the <function>choose</function> or <function>picksplit</function>
|
if the <function>choose</function> or <function>picksplit</function>
|
||||||
methods change it. When the insertion search reaches a leaf page,
|
methods change it. When the insertion search reaches a leaf page,
|
||||||
the current value of <structfield>leafDatum</structfield> is what will be stored
|
the current value of <structfield>leafDatum</structfield> is what will be stored
|
||||||
@ -418,7 +443,7 @@ typedef struct spgChooseOut
|
|||||||
Set <structfield>levelAdd</structfield> to the increment in
|
Set <structfield>levelAdd</structfield> to the increment in
|
||||||
<structfield>level</structfield> caused by descending through that node,
|
<structfield>level</structfield> caused by descending through that node,
|
||||||
or leave it as zero if the operator class does not use levels.
|
or leave it as zero if the operator class does not use levels.
|
||||||
Set <structfield>restDatum</structfield> to equal <structfield>datum</structfield>
|
Set <structfield>restDatum</structfield> to equal <structfield>leafDatum</structfield>
|
||||||
if the operator class does not modify datums from one level to the
|
if the operator class does not modify datums from one level to the
|
||||||
next, or otherwise set it to the modified value to be used as
|
next, or otherwise set it to the modified value to be used as
|
||||||
<structfield>leafDatum</structfield> at the next level.
|
<structfield>leafDatum</structfield> at the next level.
|
||||||
@ -509,7 +534,9 @@ typedef struct spgPickSplitOut
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<structfield>nTuples</structfield> is the number of leaf tuples provided.
|
<structfield>nTuples</structfield> is the number of leaf tuples provided.
|
||||||
<structfield>datums</structfield> is an array of their datum values.
|
<structfield>datums</structfield> is an array of their datum values of
|
||||||
|
<structname>spgConfigOut</structname>.<structfield>leafType</structfield>
|
||||||
|
type.
|
||||||
<structfield>level</structfield> is the current level that all the leaf tuples
|
<structfield>level</structfield> is the current level that all the leaf tuples
|
||||||
share, which will become the level of the new inner tuple.
|
share, which will become the level of the new inner tuple.
|
||||||
</para>
|
</para>
|
||||||
@ -624,7 +651,8 @@ typedef struct spgInnerConsistentOut
|
|||||||
<structfield>reconstructedValue</structfield> is the value reconstructed for the
|
<structfield>reconstructedValue</structfield> is the value reconstructed for the
|
||||||
parent tuple; it is <literal>(Datum) 0</literal> at the root level or if the
|
parent tuple; it is <literal>(Datum) 0</literal> at the root level or if the
|
||||||
<function>inner_consistent</function> function did not provide a value at the
|
<function>inner_consistent</function> function did not provide a value at the
|
||||||
parent level.
|
parent level. <structfield>reconstructedValue</structfield> is always of
|
||||||
|
<structname>spgConfigOut</structname>.<structfield>leafType</structfield> type.
|
||||||
<structfield>traversalValue</structfield> is a pointer to any traverse data
|
<structfield>traversalValue</structfield> is a pointer to any traverse data
|
||||||
passed down from the previous call of <function>inner_consistent</function>
|
passed down from the previous call of <function>inner_consistent</function>
|
||||||
on the parent index tuple, or NULL at the root level.
|
on the parent index tuple, or NULL at the root level.
|
||||||
@ -659,6 +687,7 @@ typedef struct spgInnerConsistentOut
|
|||||||
necessarily so, so an array is used.)
|
necessarily so, so an array is used.)
|
||||||
If value reconstruction is needed, set
|
If value reconstruction is needed, set
|
||||||
<structfield>reconstructedValues</structfield> to an array of the values
|
<structfield>reconstructedValues</structfield> to an array of the values
|
||||||
|
of <structname>spgConfigOut</structname>.<structfield>leafType</structfield> type
|
||||||
reconstructed for each child node to be visited; otherwise, leave
|
reconstructed for each child node to be visited; otherwise, leave
|
||||||
<structfield>reconstructedValues</structfield> as NULL.
|
<structfield>reconstructedValues</structfield> as NULL.
|
||||||
If it is desired to pass down additional out-of-band information
|
If it is desired to pass down additional out-of-band information
|
||||||
@ -730,7 +759,8 @@ typedef struct spgLeafConsistentOut
|
|||||||
<structfield>reconstructedValue</structfield> is the value reconstructed for the
|
<structfield>reconstructedValue</structfield> is the value reconstructed for the
|
||||||
parent tuple; it is <literal>(Datum) 0</literal> at the root level or if the
|
parent tuple; it is <literal>(Datum) 0</literal> at the root level or if the
|
||||||
<function>inner_consistent</function> function did not provide a value at the
|
<function>inner_consistent</function> function did not provide a value at the
|
||||||
parent level.
|
parent level. <structfield>reconstructedValue</structfield> is always of
|
||||||
|
<structname>spgConfigOut</structname>.<structfield>leafType</structfield> type.
|
||||||
<structfield>traversalValue</structfield> is a pointer to any traverse data
|
<structfield>traversalValue</structfield> is a pointer to any traverse data
|
||||||
passed down from the previous call of <function>inner_consistent</function>
|
passed down from the previous call of <function>inner_consistent</function>
|
||||||
on the parent index tuple, or NULL at the root level.
|
on the parent index tuple, or NULL at the root level.
|
||||||
@ -739,16 +769,18 @@ typedef struct spgLeafConsistentOut
|
|||||||
<structfield>returnData</structfield> is <literal>true</literal> if reconstructed data is
|
<structfield>returnData</structfield> is <literal>true</literal> if reconstructed data is
|
||||||
required for this query; this will only be so if the
|
required for this query; this will only be so if the
|
||||||
<function>config</function> function asserted <structfield>canReturnData</structfield>.
|
<function>config</function> function asserted <structfield>canReturnData</structfield>.
|
||||||
<structfield>leafDatum</structfield> is the key value stored in the current
|
<structfield>leafDatum</structfield> is the key value of
|
||||||
leaf tuple.
|
<structname>spgConfigOut</structname>.<structfield>leafType</structfield>
|
||||||
|
stored in the current leaf tuple.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The function must return <literal>true</literal> if the leaf tuple matches the
|
The function must return <literal>true</literal> if the leaf tuple matches the
|
||||||
query, or <literal>false</literal> if not. In the <literal>true</literal> case,
|
query, or <literal>false</literal> if not. In the <literal>true</literal> case,
|
||||||
if <structfield>returnData</structfield> is <literal>true</literal> then
|
if <structfield>returnData</structfield> is <literal>true</literal> then
|
||||||
<structfield>leafValue</structfield> must be set to the value originally supplied
|
<structfield>leafValue</structfield> must be set to the value of
|
||||||
to be indexed for this leaf tuple. Also,
|
<structname>spgConfigIn</structname>.<structfield>attType</structfield> type
|
||||||
|
originally supplied to be indexed for this leaf tuple. Also,
|
||||||
<structfield>recheck</structfield> may be set to <literal>true</literal> if the match
|
<structfield>recheck</structfield> may be set to <literal>true</literal> if the match
|
||||||
is uncertain and so the operator(s) must be re-applied to the actual
|
is uncertain and so the operator(s) must be re-applied to the actual
|
||||||
heap tuple to verify the match.
|
heap tuple to verify the match.
|
||||||
@ -757,6 +789,26 @@ typedef struct spgLeafConsistentOut
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The optional user-defined method is:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><function>Datum compress(Datum in)</function></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Converts the data item into a format suitable for physical storage in
|
||||||
|
a leaf tuple of index page. It accepts
|
||||||
|
<structname>spgConfigIn</structname>.<structfield>attType</structfield>
|
||||||
|
value and return
|
||||||
|
<structname>spgConfigOut</structname>.<structfield>leafType</structfield>
|
||||||
|
value. Output value should not be toasted.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
All the SP-GiST support methods are normally called in a short-lived
|
All the SP-GiST support methods are normally called in a short-lived
|
||||||
memory context; that is, <varname>CurrentMemoryContext</varname> will be reset
|
memory context; that is, <varname>CurrentMemoryContext</varname> will be reset
|
||||||
|
@ -1906,14 +1906,37 @@ spgdoinsert(Relation index, SpGistState *state,
|
|||||||
procinfo = index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC);
|
procinfo = index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we don't use index_form_tuple in this AM, we have to make sure
|
* Prepare the leaf datum to insert.
|
||||||
|
*
|
||||||
|
* If an optional "compress" method is provided, then call it to form
|
||||||
|
* the leaf datum from the input datum. Otherwise store the input datum as
|
||||||
|
* is. Since we don't use index_form_tuple in this AM, we have to make sure
|
||||||
* value to be inserted is not toasted; FormIndexDatum doesn't guarantee
|
* value to be inserted is not toasted; FormIndexDatum doesn't guarantee
|
||||||
* that.
|
* that. But we assume the "compress" method to return an untoasted value.
|
||||||
*/
|
*/
|
||||||
if (!isnull && state->attType.attlen == -1)
|
if (!isnull)
|
||||||
datum = PointerGetDatum(PG_DETOAST_DATUM(datum));
|
{
|
||||||
|
if (OidIsValid(index_getprocid(index, 1, SPGIST_COMPRESS_PROC)))
|
||||||
|
{
|
||||||
|
FmgrInfo *compressProcinfo = NULL;
|
||||||
|
|
||||||
leafDatum = datum;
|
compressProcinfo = index_getprocinfo(index, 1, SPGIST_COMPRESS_PROC);
|
||||||
|
leafDatum = FunctionCall1Coll(compressProcinfo,
|
||||||
|
index->rd_indcollation[0],
|
||||||
|
datum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert(state->attLeafType.type == state->attType.type);
|
||||||
|
|
||||||
|
if (state->attType.attlen == -1)
|
||||||
|
leafDatum = PointerGetDatum(PG_DETOAST_DATUM(datum));
|
||||||
|
else
|
||||||
|
leafDatum = datum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
leafDatum = (Datum) 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute space needed for a leaf tuple containing the given datum.
|
* Compute space needed for a leaf tuple containing the given datum.
|
||||||
@ -1923,7 +1946,7 @@ spgdoinsert(Relation index, SpGistState *state,
|
|||||||
*/
|
*/
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
|
leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
|
||||||
SpGistGetTypeSize(&state->attType, leafDatum);
|
SpGistGetTypeSize(&state->attLeafType, leafDatum);
|
||||||
else
|
else
|
||||||
leafSize = SGDTSIZE + sizeof(ItemIdData);
|
leafSize = SGDTSIZE + sizeof(ItemIdData);
|
||||||
|
|
||||||
@ -2138,7 +2161,7 @@ spgdoinsert(Relation index, SpGistState *state,
|
|||||||
{
|
{
|
||||||
leafDatum = out.result.matchNode.restDatum;
|
leafDatum = out.result.matchNode.restDatum;
|
||||||
leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
|
leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
|
||||||
SpGistGetTypeSize(&state->attType, leafDatum);
|
SpGistGetTypeSize(&state->attLeafType, leafDatum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -40,7 +40,7 @@ typedef struct ScanStackEntry
|
|||||||
static void
|
static void
|
||||||
freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
|
freeScanStackEntry(SpGistScanOpaque so, ScanStackEntry *stackEntry)
|
||||||
{
|
{
|
||||||
if (!so->state.attType.attbyval &&
|
if (!so->state.attLeafType.attbyval &&
|
||||||
DatumGetPointer(stackEntry->reconstructedValue) != NULL)
|
DatumGetPointer(stackEntry->reconstructedValue) != NULL)
|
||||||
pfree(DatumGetPointer(stackEntry->reconstructedValue));
|
pfree(DatumGetPointer(stackEntry->reconstructedValue));
|
||||||
if (stackEntry->traversalValue)
|
if (stackEntry->traversalValue)
|
||||||
@ -527,8 +527,8 @@ redirect:
|
|||||||
if (out.reconstructedValues)
|
if (out.reconstructedValues)
|
||||||
newEntry->reconstructedValue =
|
newEntry->reconstructedValue =
|
||||||
datumCopy(out.reconstructedValues[i],
|
datumCopy(out.reconstructedValues[i],
|
||||||
so->state.attType.attbyval,
|
so->state.attLeafType.attbyval,
|
||||||
so->state.attType.attlen);
|
so->state.attLeafType.attlen);
|
||||||
else
|
else
|
||||||
newEntry->reconstructedValue = (Datum) 0;
|
newEntry->reconstructedValue = (Datum) 0;
|
||||||
|
|
||||||
|
@ -125,6 +125,22 @@ spgGetCache(Relation index)
|
|||||||
|
|
||||||
/* Get the information we need about each relevant datatype */
|
/* Get the information we need about each relevant datatype */
|
||||||
fillTypeDesc(&cache->attType, atttype);
|
fillTypeDesc(&cache->attType, atttype);
|
||||||
|
|
||||||
|
if (OidIsValid(cache->config.leafType) &&
|
||||||
|
cache->config.leafType != atttype)
|
||||||
|
{
|
||||||
|
if (!OidIsValid(index_getprocid(index, 1, SPGIST_COMPRESS_PROC)))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("compress method must not defined when leaf type is different from input type")));
|
||||||
|
|
||||||
|
fillTypeDesc(&cache->attLeafType, cache->config.leafType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cache->attLeafType = cache->attType;
|
||||||
|
}
|
||||||
|
|
||||||
fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
|
fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
|
||||||
fillTypeDesc(&cache->attLabelType, cache->config.labelType);
|
fillTypeDesc(&cache->attLabelType, cache->config.labelType);
|
||||||
|
|
||||||
@ -164,6 +180,7 @@ initSpGistState(SpGistState *state, Relation index)
|
|||||||
|
|
||||||
state->config = cache->config;
|
state->config = cache->config;
|
||||||
state->attType = cache->attType;
|
state->attType = cache->attType;
|
||||||
|
state->attLeafType = cache->attLeafType;
|
||||||
state->attPrefixType = cache->attPrefixType;
|
state->attPrefixType = cache->attPrefixType;
|
||||||
state->attLabelType = cache->attLabelType;
|
state->attLabelType = cache->attLabelType;
|
||||||
|
|
||||||
@ -618,7 +635,7 @@ spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr,
|
|||||||
/* compute space needed (note result is already maxaligned) */
|
/* compute space needed (note result is already maxaligned) */
|
||||||
size = SGLTHDRSZ;
|
size = SGLTHDRSZ;
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
size += SpGistGetTypeSize(&state->attType, datum);
|
size += SpGistGetTypeSize(&state->attLeafType, datum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that we can replace the tuple with a dead tuple later. This
|
* Ensure that we can replace the tuple with a dead tuple later. This
|
||||||
@ -634,7 +651,7 @@ spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr,
|
|||||||
tup->nextOffset = InvalidOffsetNumber;
|
tup->nextOffset = InvalidOffsetNumber;
|
||||||
tup->heapPtr = *heapPtr;
|
tup->heapPtr = *heapPtr;
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
memcpyDatum(SGLTDATAPTR(tup), &state->attType, datum);
|
memcpyDatum(SGLTDATAPTR(tup), &state->attLeafType, datum);
|
||||||
|
|
||||||
return tup;
|
return tup;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "catalog/pg_opfamily.h"
|
#include "catalog/pg_opfamily.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/regproc.h"
|
#include "utils/regproc.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
@ -52,6 +53,10 @@ spgvalidate(Oid opclassoid)
|
|||||||
OpFamilyOpFuncGroup *opclassgroup;
|
OpFamilyOpFuncGroup *opclassgroup;
|
||||||
int i;
|
int i;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
spgConfigIn configIn;
|
||||||
|
spgConfigOut configOut;
|
||||||
|
Oid configOutLefttype = InvalidOid;
|
||||||
|
Oid configOutRighttype = InvalidOid;
|
||||||
|
|
||||||
/* Fetch opclass information */
|
/* Fetch opclass information */
|
||||||
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
|
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
|
||||||
@ -74,6 +79,7 @@ spgvalidate(Oid opclassoid)
|
|||||||
/* Fetch all operators and support functions of the opfamily */
|
/* Fetch all operators and support functions of the opfamily */
|
||||||
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
|
oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
|
||||||
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
|
proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
|
||||||
|
grouplist = identify_opfamily_groups(oprlist, proclist);
|
||||||
|
|
||||||
/* Check individual support functions */
|
/* Check individual support functions */
|
||||||
for (i = 0; i < proclist->n_members; i++)
|
for (i = 0; i < proclist->n_members; i++)
|
||||||
@ -100,6 +106,40 @@ spgvalidate(Oid opclassoid)
|
|||||||
switch (procform->amprocnum)
|
switch (procform->amprocnum)
|
||||||
{
|
{
|
||||||
case SPGIST_CONFIG_PROC:
|
case SPGIST_CONFIG_PROC:
|
||||||
|
ok = check_amproc_signature(procform->amproc, VOIDOID, true,
|
||||||
|
2, 2, INTERNALOID, INTERNALOID);
|
||||||
|
configIn.attType = procform->amproclefttype;
|
||||||
|
memset(&configOut, 0, sizeof(configOut));
|
||||||
|
|
||||||
|
OidFunctionCall2(procform->amproc,
|
||||||
|
PointerGetDatum(&configIn),
|
||||||
|
PointerGetDatum(&configOut));
|
||||||
|
|
||||||
|
configOutLefttype = procform->amproclefttype;
|
||||||
|
configOutRighttype = procform->amprocrighttype;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When leaf and attribute types are the same, compress function
|
||||||
|
* is not required and we set corresponding bit in functionset
|
||||||
|
* for later group consistency check.
|
||||||
|
*/
|
||||||
|
if (!OidIsValid(configOut.leafType) ||
|
||||||
|
configOut.leafType == configIn.attType)
|
||||||
|
{
|
||||||
|
foreach(lc, grouplist)
|
||||||
|
{
|
||||||
|
OpFamilyOpFuncGroup *group = lfirst(lc);
|
||||||
|
|
||||||
|
if (group->lefttype == procform->amproclefttype &&
|
||||||
|
group->righttype == procform->amprocrighttype)
|
||||||
|
{
|
||||||
|
group->functionset |=
|
||||||
|
((uint64) 1) << SPGIST_COMPRESS_PROC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SPGIST_CHOOSE_PROC:
|
case SPGIST_CHOOSE_PROC:
|
||||||
case SPGIST_PICKSPLIT_PROC:
|
case SPGIST_PICKSPLIT_PROC:
|
||||||
case SPGIST_INNER_CONSISTENT_PROC:
|
case SPGIST_INNER_CONSISTENT_PROC:
|
||||||
@ -110,6 +150,15 @@ spgvalidate(Oid opclassoid)
|
|||||||
ok = check_amproc_signature(procform->amproc, BOOLOID, true,
|
ok = check_amproc_signature(procform->amproc, BOOLOID, true,
|
||||||
2, 2, INTERNALOID, INTERNALOID);
|
2, 2, INTERNALOID, INTERNALOID);
|
||||||
break;
|
break;
|
||||||
|
case SPGIST_COMPRESS_PROC:
|
||||||
|
if (configOutLefttype != procform->amproclefttype ||
|
||||||
|
configOutRighttype != procform->amprocrighttype)
|
||||||
|
ok = false;
|
||||||
|
else
|
||||||
|
ok = check_amproc_signature(procform->amproc,
|
||||||
|
configOut.leafType, true,
|
||||||
|
1, 1, procform->amproclefttype);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ereport(INFO,
|
ereport(INFO,
|
||||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
@ -178,7 +227,6 @@ spgvalidate(Oid opclassoid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now check for inconsistent groups of operators/functions */
|
/* Now check for inconsistent groups of operators/functions */
|
||||||
grouplist = identify_opfamily_groups(oprlist, proclist);
|
|
||||||
opclassgroup = NULL;
|
opclassgroup = NULL;
|
||||||
foreach(lc, grouplist)
|
foreach(lc, grouplist)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
#define SPGIST_PICKSPLIT_PROC 3
|
#define SPGIST_PICKSPLIT_PROC 3
|
||||||
#define SPGIST_INNER_CONSISTENT_PROC 4
|
#define SPGIST_INNER_CONSISTENT_PROC 4
|
||||||
#define SPGIST_LEAF_CONSISTENT_PROC 5
|
#define SPGIST_LEAF_CONSISTENT_PROC 5
|
||||||
#define SPGISTNProc 5
|
#define SPGIST_COMPRESS_PROC 6
|
||||||
|
#define SPGISTNRequiredProc 5
|
||||||
|
#define SPGISTNProc 6
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Argument structs for spg_config method
|
* Argument structs for spg_config method
|
||||||
@ -44,6 +46,7 @@ typedef struct spgConfigOut
|
|||||||
{
|
{
|
||||||
Oid prefixType; /* Data type of inner-tuple prefixes */
|
Oid prefixType; /* Data type of inner-tuple prefixes */
|
||||||
Oid labelType; /* Data type of inner-tuple node labels */
|
Oid labelType; /* Data type of inner-tuple node labels */
|
||||||
|
Oid leafType; /* Data type of leaf-tuple values */
|
||||||
bool canReturnData; /* Opclass can reconstruct original data */
|
bool canReturnData; /* Opclass can reconstruct original data */
|
||||||
bool longValuesOK; /* Opclass can cope with values > 1 page */
|
bool longValuesOK; /* Opclass can cope with values > 1 page */
|
||||||
} spgConfigOut;
|
} spgConfigOut;
|
||||||
|
@ -119,7 +119,8 @@ typedef struct SpGistState
|
|||||||
{
|
{
|
||||||
spgConfigOut config; /* filled in by opclass config method */
|
spgConfigOut config; /* filled in by opclass config method */
|
||||||
|
|
||||||
SpGistTypeDesc attType; /* type of input data and leaf values */
|
SpGistTypeDesc attType; /* type of values to be indexed/restored */
|
||||||
|
SpGistTypeDesc attLeafType; /* type of leaf-tuple values */
|
||||||
SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */
|
SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */
|
||||||
SpGistTypeDesc attLabelType; /* type of node label values */
|
SpGistTypeDesc attLabelType; /* type of node label values */
|
||||||
|
|
||||||
@ -178,7 +179,8 @@ typedef struct SpGistCache
|
|||||||
{
|
{
|
||||||
spgConfigOut config; /* filled in by opclass config method */
|
spgConfigOut config; /* filled in by opclass config method */
|
||||||
|
|
||||||
SpGistTypeDesc attType; /* type of input data and leaf values */
|
SpGistTypeDesc attType; /* type of values to be indexed/restored */
|
||||||
|
SpGistTypeDesc attLeafType; /* type of leaf-tuple values */
|
||||||
SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */
|
SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */
|
||||||
SpGistTypeDesc attLabelType; /* type of node label values */
|
SpGistTypeDesc attLabelType; /* type of node label values */
|
||||||
|
|
||||||
@ -300,7 +302,7 @@ typedef SpGistLeafTupleData *SpGistLeafTuple;
|
|||||||
|
|
||||||
#define SGLTHDRSZ MAXALIGN(sizeof(SpGistLeafTupleData))
|
#define SGLTHDRSZ MAXALIGN(sizeof(SpGistLeafTupleData))
|
||||||
#define SGLTDATAPTR(x) (((char *) (x)) + SGLTHDRSZ)
|
#define SGLTDATAPTR(x) (((char *) (x)) + SGLTHDRSZ)
|
||||||
#define SGLTDATUM(x, s) ((s)->attType.attbyval ? \
|
#define SGLTDATUM(x, s) ((s)->attLeafType.attbyval ? \
|
||||||
*(Datum *) SGLTDATAPTR(x) : \
|
*(Datum *) SGLTDATAPTR(x) : \
|
||||||
PointerGetDatum(SGLTDATAPTR(x)))
|
PointerGetDatum(SGLTDATAPTR(x)))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user