So now we have an access method and an operator class.
We still need a set of operators. The procedure for
defining operators was discussed in Chapter 14.
For the complex_abs_ops operator class on B-trees,
the operators we require are:

absolute-value less-than (strategy 1)

absolute-value less-than-or-equal (strategy 2)

absolute-value equal (strategy 3)

absolute-value greater-than-or-equal (strategy 4)

absolute-value greater-than (strategy 5)

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:

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.

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.

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, the support function returns whatever the
particular access method expects -- in this case, a signed
integer.)

The final routine in the file is the "support routine"
mentioned when we discussed the amsupport column of the
pg_am table. We will use this later on. For
now, ignore it.

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 to add entries for these operators to
the pg_amop relation. To do this,
we'll need the OIDs of the operators we just
defined. We'll look up the names of all the operators that take
two operands of type complex, and pick ours out:

(Again, some of your OID numbers will almost
certainly be different.) The operators we are interested in are those
with OIDs 277970 through 277974. The values you
get will probably be different, and you should substitute them for the
values below. We will do this with a select statement.

Now we are ready to insert entries into pg_amop for
our new operator class. These entries must associate the correct
B-tree strategy numbers with each of the operators we need.
The command to insert the less-than operator looks like:

Now do this for the other operators substituting for the 1 in the
second line above and the < in the last line. Note the order:
"less than" is 1, "less than or equal" is 2,
"equal" is 3, "greater than or equal" is 4, and
"greater than" is 5.

The field amopreqcheck is not discussed here; it
should always be false for B-tree operators.

The final step is the registration of the "support routine" previously
described in our discussion of pg_am. The
OID of this support routine is stored in the
pg_amproc table, keyed by the operator class
OID and the support routine number.

First, we need to register the function in
PostgreSQL (recall that we put the
C code that implements this routine in the bottom of
the file in which we implemented the operator routines):