11<!--
2- $Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.32 2003/08/31 17:32:21 petere Exp $
2+ $Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.33 2003/10/21 23:28:42 tgl Exp $
33-->
44
55<sect1 id="xindex">
@@ -408,7 +408,12 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.32 2003/08/31 17:32:21 pete
408408
409409 <para>
410410 Now that we have seen the ideas, here is the promised example of
411- creating a new operator class. The operator class encapsulates
411+ creating a new operator class.
412+ (You can find a working copy of this example in
413+ <filename>src/tutorial/complex.c</filename> and
414+ <filename>src/tutorial/complex.sql</filename> in the source
415+ distribution.)
416+ The operator class encapsulates
412417 operators that sort complex numbers in absolute value order, so we
413418 choose the name <literal>complex_abs_ops</literal>. First, we need
414419 a set of operators. The procedure for defining operators was
@@ -425,40 +430,65 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.32 2003/08/31 17:32:21 pete
425430 </para>
426431
427432 <para>
428- The C code for the equality operator look like this:
433+ The least error-prone way to define a related set of comparison operators
434+ is to write the btree comparison support function first, and then write the
435+ other functions as one-line wrappers around the support function. This
436+ reduces the odds of getting inconsistent results for corner cases.
437+ Following this approach, we first write
429438
430439<programlisting>
431- #define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y)
440+ #define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y)
432441
433- bool
434- complex_abs_eq (Complex *a, Complex *b)
442+ static int
443+ complex_abs_cmp_internal (Complex *a, Complex *b)
435444{
436- double amag = Mag(a), bmag = Mag(b);
437- return (amag == bmag);
445+ double amag = Mag(a),
446+ bmag = Mag(b);
447+
448+ if (amag < bmag)
449+ return -1;
450+ if (amag > bmag)
451+ return 1;
452+ return 0;
438453}
439454</programlisting>
440- The other four operators are very similar. You can find their code
441- in <filename>src/tutorial/complex.c</filename> and
442- <filename>src/tutorial/complex.sql</filename> in the source
443- distribution.
455+
456+ Now the less-than function looks like
457+
458+ <programlisting>
459+ PG_FUNCTION_INFO_V1(complex_abs_lt);
460+
461+ Datum
462+ complex_abs_lt(PG_FUNCTION_ARGS)
463+ {
464+ Complex *a = (Complex *) PG_GETARG_POINTER(0);
465+ Complex *b = (Complex *) PG_GETARG_POINTER(1);
466+
467+ PG_RETURN_BOOL(complex_abs_cmp_internal(a, b) < 0);
468+ }
469+ </programlisting>
470+
471+ The other four functions differ only in how they compare the internal
472+ function's result to zero.
444473 </para>
445474
446475 <para>
447- Now declare the functions and the operators based on the functions:
476+ Next we declare the functions and the operators based on the functions
477+ to SQL:
478+
448479<programlisting>
449- CREATE FUNCTION complex_abs_eq(complex, complex) RETURNS boolean
450- AS '<replaceable>filename</replaceable>', 'complex_abs_eq'
451- LANGUAGE C;
452-
453- CREATE OPERATOR = (
454- leftarg = complex,
455- rightarg = complex,
456- procedure = complex_abs_eq,
457- restrict = eqsel,
458- join = eqjoinsel
480+ CREATE FUNCTION complex_abs_lt(complex, complex) RETURNS bool
481+ AS '<replaceable>filename</replaceable>', 'complex_abs_lt'
482+ LANGUAGE C IMMUTABLE STRICT;
483+
484+ CREATE OPERATOR < (
485+ leftarg = complex, rightarg = complex, procedure = complex_abs_lt,
486+ commutator = > , negator = >= ,
487+ restrict = scalarltsel, join = scalarltjoinsel
459488);
460489</programlisting>
461- It is important to specify the restriction and join selectivity
490+ It is important to specify the correct commutator and negator operators,
491+ as well as suitable restriction and join selectivity
462492 functions, otherwise the optimizer will be unable to make effective
463493 use of the index. Note that the less-than, equal, and
464494 greater-than cases should use different selectivity functions.
@@ -518,7 +548,7 @@ CREATE OPERATOR = (
518548CREATE FUNCTION complex_abs_cmp(complex, complex)
519549 RETURNS integer
520550 AS '<replaceable>filename</replaceable>'
521- LANGUAGE C;
551+ LANGUAGE C IMMUTABLE STRICT ;
522552</programlisting>
523553 </para>
524554