|
GiST indexes require seven support functions,
- as shown in .
+ shown in .
GiST Support Functions
- GiST
-
+ Unlike strategy operators, support functions return whichever data
+ type the particular index method expects, for example in the case
+ of the comparison function for B-trees, a signed integer.
+
+
- 1 id="xindex-operators">
-
Creating the Operators and Support Routines
+ 2 id="xindex-example">
+
An Example
- Now that we have seen the ideas, here is the promised example
- of creating a new operator class. First, we need a set of operators.
- The procedure for
- defining operators was discussed in .
- For the complex_abs_ops operator class on B-trees,
- the operators we require are:
+ Now that we have seen the ideas, here is the promised example of
+ creating a new operator class. The operator class encapsulates
+ operators that sort complex numbers in absolute value order, so we
+ choose the name complex_abs_ops. First, we need
+ a set of operators. The procedure for defining operators was
+ discussed in . For an operator class on
+ B-trees, the operators we require are:
absolute-value less-than (strategy 1)>>
- Suppose the code that implements these functions
- is stored in the file
- PGROOT/src/tutorial/complex.c,
- which we have compiled into
- PGROOT/src/tutorial/complex.so.
- Part of the C code looks like this:
+ The C code for the equality operator look like this:
#define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y)
- bool
- complex_abs_eq(Complex *a, Complex *b)
- {
- double amag = Mag(a), bmag = Mag(b);
- return (amag==bmag);
- }
+bool
+complex_abs_eq(Complex *a, Complex *b)
+{
+ double amag = Mag(a), bmag = Mag(b);
+ return (amag == bmag);
+}
- (Note that we will only show the equality operator in this text.
- The other four operators are very similar. Refer to
- complex.c or
- complex.source for the details.)
+ The other four operators are very similar. You can find their code
+ in src/tutorial/complex.c and
+ src/tutorial/complex.sql in the source
+ distribution.
-
We make the function known to PostgreSQL like this:
+ Now declare the functions and the operators based on the functions:
CREATE FUNCTION complex_abs_eq(complex, complex) RETURNS boolean
- AS 'PGROOT/src/tutorial/complex'
+ AS 'filename', 'complex_abs_eq'
LANGUAGE C;
+
+CREATE OPERATOR = (
+ leftarg = complex,
+ rightarg = complex,
+ procedure = complex_abs_eq,
+ restrict = eqsel,
+ join = eqjoinsel
+);
+ It is important to specify the restriction and join selectivity
+ functions, otherwise the optimizer will be unable to make effective
+ use of the index. Note that there less-than, equal, and
+ greater-than cases should use different selectivity functions.
- There are some important things that are happening here:
+ Other things worth noting are happening here:
- First, note that operators for less-than, less-than-or-equal, equal,
- greater-than-or-equal, and greater-than for complex
- are being defined. We can only have one operator named, say, = and
- taking type complex for both operands. In this case
- we don't have any other operator = for complex,
- but if we were building a practical data type we'd probably want = to
- be the ordinary equality operation for complex numbers. In that case,
- we'd need to use some other operator name for complex_abs_eq>.
-
+ There can only be one operator named, say, =
+ and taking type complex for both operands. In this
+ case we don't have any other operator = for
+ complex, but if we were building a practical data
+ type we'd probably want = to be the ordinary
+ equality operation for complex numbers (and not the equality of
+ the absolute values). In that case, we'd need to use some other
+ operator name for complex_abs_eq>.
+
- Second, although
PostgreSQL can cope with operators having
- the same name as long as they have different input data types, C can only
- cope with one global routine having a given name, period. So we shouldn't
- name the C function something simple like abs_eq.
- Usually it's a good practice to include the data type name in the C
- function name, so as not to conflict with functions for other data types.
-
+ Although
PostgreSQL can cope with
+ functions having the same name as long as they have different
+ argument data types, C can only cope with one global function
+ having a given name. So we shouldn't name the C function
+ something simple like abs_eq. Usually it's
+ a good practice to include the data type name in the C function
+ name, so as not to conflict with functions for other data types.
+
- Third, we could have made the
PostgreSQL name of the function
-
abs_eq, relying on
PostgreSQL to distinguish it
- by input data types from any other
PostgreSQL function of the same name.
- To keep the example simple, we make the function have the same names
- at the C level and
PostgreSQL level.
-
-
-
-
- Finally, note that these operator functions return Boolean values.
- In practice, all operators defined as index access method
- strategies must return type boolean, since they must
- appear at the top level of a WHERE> clause to be used with an index.
- (On the other hand, support functions return whatever the
- particular access method expects -- in the case of the comparison
- function for B-trees, a signed integer.)
-
+ We could have made the
PostgreSQL name
+ of the function abs_eq, relying on
+
PostgreSQL to distinguish it by
+ argument data types from any other
+
PostgreSQL function of the same name.
+ To keep the example simple, we make the function have the same
+ names at the C level and
PostgreSQL
+ level.
+
- Now we are ready to define the operators:
-
-CREATE OPERATOR = (
- leftarg = complex, rightarg = complex,
- procedure = complex_abs_eq,
- restrict = eqsel, join = eqjoinsel
- );
-
-
- The important
- things here are the procedure names (which are the C
- functions defined above) and the restriction and join selectivity
- functions. You should just use the selectivity functions used in
- the example (see complex.source).
- Note that there
- are different such functions for the less-than, equal, and greater-than
- cases. These must be supplied or the optimizer will be unable to
- make effective use of the index.
-
-
- The next step is the registration of the comparison support
- routine required by B-trees. The C code that implements this
- is in the same file that contains the operator procedures:
+ The next step is the registration of the support routine required
+ by B-trees. The example C code that implements this is in the same
+ file that contains the operator functions. This is how we declare
+ the function:
CREATE FUNCTION complex_abs_cmp(complex, complex)
RETURNS integer
- AS 'PGROOT/src/tutorial/complex'
+ AS 'filename'
LANGUAGE C;
-
-
-
-
Creating the Operator Class
Now that we have the required operators and support routine,
- And we're done! (Whew.) It should now be possible to create
+ And we're done! It should now be possible to create
and use B-tree indexes on complex columns.
default B-tree operator class for the complex data type.
If you don't, just leave out the word DEFAULT>.
- 1>
+ 2>
- 1 id="xindex-opclass-features">
+ 2 id="xindex-opclass-features">
Special Features of Operator Classes
There are two special features of operator classes that we have
not discussed yet, mainly because they are not very useful
- with the default B-tree index access method.
+ with the default B-tree index method.
Normally, declaring an operator as a member of an operator class means
- that the index access method can retrieve exactly the set of rows
- that satisfy a WHERE condition using the operator. For example,
+ that the index method can retrieve exactly the set of rows
+ that satisfy a WHERE> condition using the operator. For example,
SELECT * FROM table WHERE integer_column < 4;
can be satisfied exactly by a B-tree index on the integer column.
But there are cases where an index is useful as an inexact guide to
the matching rows. For example, if an R-tree index stores only
- bounding boxes for objects, then it cannot exactly satisfy a WHERE
+ bounding boxes for objects, then it cannot exactly satisfy a WHERE>
condition that tests overlap between nonrectangular objects such as
polygons. Yet we could use the index to find objects whose bounding
box overlaps the bounding box of the target object, and then do the
operator, and we add RECHECK> to the OPERATOR> clause
in the CREATE OPERATOR CLASS> command.
RECHECK> is valid if the index is guaranteed to return
- all the required tuples, plus perhaps some additional tuples, which
- can be eliminated by performing the original operator comparison.
+ all the required rows, plus perhaps some additional rows, which
+ can be eliminated by performing the original operator invocation.
the bounding box of a complex object such as a polygon. In this
case there's not much value in storing the whole polygon in the index
entry --- we may as well store just a simpler object of type
- <literal>box>. This situation is expressed by the STORAGE>
+ <type>box>. This situation is expressed by the STORAGE>
option in CREATE OPERATOR CLASS>: we'd write something like
STORAGE box;
- At present, only the GiST access method supports a
+ At present, only the GiST index method supports a
STORAGE> type that's different from the column data type.
The GiST compress> and decompress> support
routines must deal with data-type conversion when STORAGE>
is used.
- 1>
+ 2>
-chapter>
+sect1>