data_type *key = DatumGetDataType(entry->key);
bool retval;
/*
* determine return value as a function of strategy, key and query.
*
* Use GIST_LEAF(entry) to know where you're called in the index tree,
* which comes handy when supporting the = operator for example (you could
* check for non empty union() in non-leaf nodes and equality in leaf
* nodes).
*/
*recheck = true; /* or false if check is exact */
PG_RETURN_BOOL(retval);
}
</programlisting>
Here, <varname>key</varname> is an element in the index and <varname>query</varname>
the value being looked up in the index. The <literal>StrategyNumber</literal>
parameter indicates which operator of your operator class is being
applied — it matches one of the operator numbers in the
<command>CREATE OPERATOR CLASS</command> command.
</para>
<para>
Depending on which operators you have included in the class, the data
type of <varname>query</varname> could vary with the operator, since it will
be whatever type is on the right-hand side of the operator, which might
be different from the indexed data type appearing on the left-hand side.
(The above code skeleton assumes that only one type is possible; if
not, fetching the <varname>query</varname> argument value would have to depend
on the operator.) It is recommended that the SQL declaration of
the <function>consistent</function> function use the opclass's indexed data
type for the <varname>query</varname> argument, even though the actual type
might be something else depending on the operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><function>union</function></term>
<listitem>
<para>
This method consolidates information in the tree. Given a set of
entries, this function generates a new index entry that represents
all the given entries.
</para>
<para>
The <acronym>SQL</acronym> declaration of the function must look like this:
<programlisting>
CREATE OR REPLACE FUNCTION my_union(internal, internal)
RETURNS storage_type
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT;
</programlisting>
And the matching code in the C module could then follow this skeleton:
<programlisting>
PG_FUNCTION_INFO_V1(my_union);
Datum
my_union(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
GISTENTRY *ent = entryvec->vector;
data_type *out,
*tmp,
*old;
int numranges,
i = 0;
numranges = entryvec->n;
tmp = DatumGetDataType(ent[0].key);
out = tmp;
if (numranges == 1)
{
out = data_type_deep_copy(tmp);
PG_RETURN_DATA_TYPE_P(out);
}
for (i = 1; i < numranges; i++)
{
old = out;
tmp = DatumGetDataType(ent[i].key);
out = my_union_implementation(out, tmp);
}
PG_RETURN_DATA_TYPE_P(out);
}
</programlisting>
</para>
<para>
As you can see, in this skeleton we're dealing with a data type
where <literal>union(X, Y, Z) = union(union(X, Y), Z)</literal>. It's easy
enough to support data types where this is not the case, by
implementing the proper union algorithm in this
<acronym>GiST</acronym> support method.
</para>
<para>
The result of the <function>union</function> function must be a value of the
index's storage type, whatever that is (it might or might not be
different from the indexed column's type). The <function>union</function>
function should return a pointer to newly <function>palloc()</function>ed
memory. You can't just return the input value as-is, even if there is
no type change.
</para>
<para>
As shown above, the <function>union</function>