|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
<!-- |
|
|
|
|
$Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.8 2000/02/17 03:39:39 tgl Exp $ |
|
|
|
|
$Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.9 2000/03/28 02:53:02 tgl Exp $ |
|
|
|
|
Postgres documentation |
|
|
|
|
--> |
|
|
|
|
|
|
|
|
@ -91,11 +91,10 @@ Postgres documentation |
|
|
|
|
<programlisting> |
|
|
|
|
SELECT oid FROM pg_am WHERE amname = 'btree'; |
|
|
|
|
|
|
|
|
|
+----+ |
|
|
|
|
|oid | |
|
|
|
|
+----+ |
|
|
|
|
|403 | |
|
|
|
|
+----+ |
|
|
|
|
oid |
|
|
|
|
----- |
|
|
|
|
403 |
|
|
|
|
(1 row) |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
We will use that <command>SELECT</command> in a <command>WHERE</command> |
|
|
|
@ -210,7 +209,8 @@ SELECT oid FROM pg_am WHERE amname = 'btree'; |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
The <filename>amstrategies</filename> entry in pg_am is just the number |
|
|
|
|
The <filename>amstrategies</filename> entry in <filename>pg_am</filename> |
|
|
|
|
is just the number |
|
|
|
|
of strategies defined for the access method in question. The procedures |
|
|
|
|
for less than, less equal, and so on don't appear in |
|
|
|
|
<filename>pg_am</filename>. Similarly, <filename>amsupport</filename> |
|
|
|
@ -228,28 +228,28 @@ SELECT oid FROM pg_am WHERE amname = 'btree'; |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
The next class of interest is pg_opclass. This class exists only to |
|
|
|
|
associate a name and default type with an oid. In pg_amop, every |
|
|
|
|
<acronym>B-tree</acronym> operator class has a set of procedures, one |
|
|
|
|
through five, above. Some existing opclasses are <filename>int2_ops, |
|
|
|
|
int4_ops, and oid_ops</filename>. You need to add an instance with your |
|
|
|
|
opclass name (for example, <filename>complex_abs_ops</filename>) to |
|
|
|
|
The next class of interest is <filename>pg_opclass</filename>. This class |
|
|
|
|
exists only to associate an operator class name and perhaps a default type |
|
|
|
|
with an operator class oid. Some existing opclasses are <filename>int2_ops, |
|
|
|
|
int4_ops,</filename> and <filename>oid_ops</filename>. You need to add an |
|
|
|
|
instance with your opclass name (for example, |
|
|
|
|
<filename>complex_abs_ops</filename>) to |
|
|
|
|
<filename>pg_opclass</filename>. The <filename>oid</filename> of |
|
|
|
|
this instance is a foreign key in other classes. |
|
|
|
|
this instance will be a foreign key in other classes, notably |
|
|
|
|
<filename>pg_amop</filename>. |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
INSERT INTO pg_opclass (opcname, opcdeftype) |
|
|
|
|
SELECT 'complex_abs_ops', oid FROM pg_type WHERE typname = 'complex_abs'; |
|
|
|
|
SELECT 'complex_abs_ops', oid FROM pg_type WHERE typname = 'complex'; |
|
|
|
|
|
|
|
|
|
SELECT oid, opcname, opcdeftype |
|
|
|
|
FROM pg_opclass |
|
|
|
|
WHERE opcname = 'complex_abs_ops'; |
|
|
|
|
|
|
|
|
|
+------+-----------------+------------+ |
|
|
|
|
|oid | opcname | opcdeftype | |
|
|
|
|
+------+-----------------+------------+ |
|
|
|
|
|17314 | complex_abs_ops | 29058 | |
|
|
|
|
+------+-----------------+------------+ |
|
|
|
|
oid | opcname | opcdeftype |
|
|
|
|
--------+-----------------+------------ |
|
|
|
|
277975 | complex_abs_ops | 277946 |
|
|
|
|
(1 row) |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
Note that the oid for your <filename>pg_opclass</filename> instance will |
|
|
|
@ -257,11 +257,23 @@ SELECT oid, opcname, opcdeftype |
|
|
|
|
from the system later just like we got the oid of the type here. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
The above example assumes that you want to make this new opclass the |
|
|
|
|
default index opclass for the <filename>complex</filename> datatype. |
|
|
|
|
If you don't, just insert zero into <filename>opcdeftype</filename>, |
|
|
|
|
rather than inserting the datatype's oid: |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
INSERT INTO pg_opclass (opcname, opcdeftype) VALUES ('complex_abs_ops', 0); |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
So now we have an access method and an operator class. |
|
|
|
|
We still need a set of operators; the procedure for |
|
|
|
|
We still need a set of operators. The procedure for |
|
|
|
|
defining operators was discussed earlier in this manual. |
|
|
|
|
For the complex_abs_ops operator class on Btrees, |
|
|
|
|
For the <filename>complex_abs_ops</filename> operator class on Btrees, |
|
|
|
|
the operators we require are: |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
@ -280,7 +292,7 @@ SELECT oid, opcname, opcdeftype |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
Part of the code look like this: (note that we will only show the |
|
|
|
|
Part of the C code looks like this: (note that we will only show the |
|
|
|
|
equality operator for the rest of the examples. The other four |
|
|
|
|
operators are very similar. Refer to <filename>complex.c</filename> |
|
|
|
|
or <filename>complex.source</filename> for the details.) |
|
|
|
@ -298,128 +310,83 @@ SELECT oid, opcname, opcdeftype |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
There are a couple of important things that are happening below. |
|
|
|
|
We make the function known to Postgres like this: |
|
|
|
|
<programlisting> |
|
|
|
|
CREATE FUNCTION complex_abs_eq(complex, complex) |
|
|
|
|
RETURNS bool |
|
|
|
|
AS 'PGROOT/tutorial/obj/complex.so' |
|
|
|
|
LANGUAGE 'c'; |
|
|
|
|
</programlisting> |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
First, note that operators for less-than, less-than-or equal, equal, |
|
|
|
|
greater-than-or-equal, and greater-than for <filename>int4</filename> |
|
|
|
|
are being defined. All of these operators are already defined for |
|
|
|
|
<filename>int4</filename> under the names <, <=, =, >=, |
|
|
|
|
and >. The new operators behave differently, of course. In order |
|
|
|
|
to guarantee that <productname>Postgres</productname> uses these |
|
|
|
|
new operators rather than the old ones, they need to be named differently |
|
|
|
|
from the old ones. This is a key point: you can overload operators in |
|
|
|
|
<productname>Postgres</productname>, but only if the operator isn't |
|
|
|
|
already defined for the argument types. That is, if you have < |
|
|
|
|
defined for (int4, int4), you can't define it again. |
|
|
|
|
<productname>Postgres</productname> does not check this when you define |
|
|
|
|
your operator, so be careful. To avoid this problem, odd names will be |
|
|
|
|
used for the operators. If you get this wrong, the access methods |
|
|
|
|
are likely to crash when you try to do scans. |
|
|
|
|
There are some important things that are happening here. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
The other important point is that all the operator functions return |
|
|
|
|
Boolean values. The access methods rely on this fact. (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 |
|
|
|
|
attribute of the <filename>pg_am</filename> class. We will use this |
|
|
|
|
later on. For now, ignore it. |
|
|
|
|
First, note that operators for less-than, less-than-or-equal, equal, |
|
|
|
|
greater-than-or-equal, and greater-than for <filename>complex</filename> |
|
|
|
|
are being defined. We can only have one operator named, say, = and |
|
|
|
|
taking type <filename>complex</filename> for both operands. In this case |
|
|
|
|
we don't have any other operator = for <filename>complex</filename>, |
|
|
|
|
but if we were building a practical datatype 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. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
<programlisting> |
|
|
|
|
CREATE FUNCTION complex_abs_eq(complex_abs, complex_abs) |
|
|
|
|
RETURNS bool |
|
|
|
|
AS 'PGROOT/tutorial/obj/complex.so' |
|
|
|
|
LANGUAGE 'c'; |
|
|
|
|
</programlisting> |
|
|
|
|
Second, although Postgres can cope with operators having |
|
|
|
|
the same name as long as they have different input datatypes, C can only |
|
|
|
|
cope with one global routine having a given name, period. So we shouldn't |
|
|
|
|
name the C function something simple like <filename>abs_eq</filename>. |
|
|
|
|
Usually it's a good practice to include the datatype name in the C |
|
|
|
|
function name, so as not to conflict with functions for other datatypes. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
Now define the operators that use them. As noted, the operator names |
|
|
|
|
must be unique among all operators that take two <filename>int4</filename> |
|
|
|
|
operands. In order to see if the operator names listed below are taken, |
|
|
|
|
we can do a query on <filename>pg_operator</filename>: |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
/* |
|
|
|
|
* this query uses the regular expression operator (~) |
|
|
|
|
* to find three-character operator names that end in |
|
|
|
|
* the character & |
|
|
|
|
*/ |
|
|
|
|
SELECT * |
|
|
|
|
FROM pg_operator |
|
|
|
|
WHERE oprname ~ '^..&$'::text; |
|
|
|
|
</programlisting> |
|
|
|
|
Third, we could have made the Postgres name of the function |
|
|
|
|
<filename>abs_eq</filename>, relying on Postgres to distinguish it |
|
|
|
|
by input datatypes from any other Postgres function of the same name. |
|
|
|
|
To keep the example simple, we make the function have the same names |
|
|
|
|
at the C level and Postgres level. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
Finally, note that these operator functions return Boolean values. |
|
|
|
|
The access methods rely on this fact. (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 |
|
|
|
|
attribute of the <filename>pg_am</filename> class. We will use this |
|
|
|
|
later on. For now, ignore it. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
to see if your name is taken for the types you want. The important |
|
|
|
|
things here are the procedure (which are the <acronym>C</acronym> |
|
|
|
|
functions defined above) and the restriction and join selectivity |
|
|
|
|
functions. You should just use the ones used below--note that there |
|
|
|
|
are different such functions for the less-than, equal, and greater-than |
|
|
|
|
cases. These must be supplied, or the access method will crash when it |
|
|
|
|
tries to use the operator. You should copy the names for restrict and |
|
|
|
|
join, but use the procedure names you defined in the last step. |
|
|
|
|
Now we are ready to define the operators: |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
CREATE OPERATOR = ( |
|
|
|
|
leftarg = complex_abs, rightarg = complex_abs, |
|
|
|
|
leftarg = complex, rightarg = complex, |
|
|
|
|
procedure = complex_abs_eq, |
|
|
|
|
restrict = eqsel, join = eqjoinsel |
|
|
|
|
) |
|
|
|
|
</programlisting> |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
Notice that five operators corresponding to less, less equal, equal, |
|
|
|
|
greater, and greater equal are defined. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
We're just about finished. the last thing we need to do is to update |
|
|
|
|
the <filename>pg_amop</filename> relation. To do this, we need the |
|
|
|
|
following attributes: |
|
|
|
|
|
|
|
|
|
<table tocentry="1"> |
|
|
|
|
<title><filename>pg_amproc</filename> Schema</title> |
|
|
|
|
<titleabbrev><filename>pg_amproc</filename></titleabbrev> |
|
|
|
|
<tgroup cols="2"> |
|
|
|
|
<thead> |
|
|
|
|
<row> |
|
|
|
|
<entry>Attribute</entry> |
|
|
|
|
<entry>Description</entry> |
|
|
|
|
</row> |
|
|
|
|
</thead> |
|
|
|
|
<tbody> |
|
|
|
|
<row> |
|
|
|
|
<entry>amopid</entry> |
|
|
|
|
<entry>the <filename>oid</filename> of the <filename>pg_am</filename> instance |
|
|
|
|
for B-tree (== 403, see above)</entry> |
|
|
|
|
</row> |
|
|
|
|
<row> |
|
|
|
|
<entry>amopclaid</entry> |
|
|
|
|
<entry>the <filename>oid</filename> of the |
|
|
|
|
<filename>pg_opclass</filename> instance for <filename>complex_abs_ops</filename> |
|
|
|
|
(== whatever you got instead of <filename>17314</filename>, see above)</entry> |
|
|
|
|
</row> |
|
|
|
|
<row> |
|
|
|
|
<entry>amopopr</entry> |
|
|
|
|
<entry>the <filename>oid</filename>s of the operators for the opclass |
|
|
|
|
(which we'll get in just a minute)</entry> |
|
|
|
|
</row> |
|
|
|
|
</tbody> |
|
|
|
|
</tgroup> |
|
|
|
|
</table> |
|
|
|
|
The important |
|
|
|
|
things here are the procedure names (which are the <acronym>C</acronym> |
|
|
|
|
functions defined above) and the restriction and join selectivity |
|
|
|
|
functions. You should just use the selectivity functions used in |
|
|
|
|
the example (see <filename>complex.source</filename>). |
|
|
|
|
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. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
So we need the <filename>oid</filename>s of the operators we just |
|
|
|
|
The next step is to add entries for these operators to |
|
|
|
|
the <filename>pg_amop</filename> relation. To do this, |
|
|
|
|
we'll need the <filename>oid</filename>s of the operators we just |
|
|
|
|
defined. We'll look up the names of all the operators that take |
|
|
|
|
two <filename>complex</filename>es, and pick ours out: |
|
|
|
|
|
|
|
|
@ -428,26 +395,22 @@ CREATE OPERATOR = ( |
|
|
|
|
INTO TABLE complex_ops_tmp |
|
|
|
|
FROM pg_operator o, pg_type t |
|
|
|
|
WHERE o.oprleft = t.oid and o.oprright = t.oid |
|
|
|
|
and t.typname = 'complex_abs'; |
|
|
|
|
|
|
|
|
|
+------+---------+ |
|
|
|
|
|oid | oprname | |
|
|
|
|
+------+---------+ |
|
|
|
|
|17321 | < | |
|
|
|
|
+------+---------+ |
|
|
|
|
|17322 | <= | |
|
|
|
|
+------+---------+ |
|
|
|
|
|17323 | = | |
|
|
|
|
+------+---------+ |
|
|
|
|
|17324 | >= | |
|
|
|
|
+------+---------+ |
|
|
|
|
|17325 | > | |
|
|
|
|
+------+---------+ |
|
|
|
|
and t.typname = 'complex'; |
|
|
|
|
|
|
|
|
|
opoid | oprname |
|
|
|
|
--------+--------- |
|
|
|
|
277963 | + |
|
|
|
|
277970 | < |
|
|
|
|
277971 | <= |
|
|
|
|
277972 | = |
|
|
|
|
277973 | >= |
|
|
|
|
277974 | > |
|
|
|
|
(6 rows) |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
(Again, some of your <filename>oid</filename> numbers will almost |
|
|
|
|
certainly be different.) The operators we are interested in are those |
|
|
|
|
with <filename>oid</filename>s 17321 through 17325. The values you |
|
|
|
|
with <filename>oid</filename>s 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. |
|
|
|
|
</para> |
|
|
|
@ -455,13 +418,13 @@ CREATE OPERATOR = ( |
|
|
|
|
<para> |
|
|
|
|
Now we're ready to update <filename>pg_amop</filename> with our new |
|
|
|
|
operator class. The most important thing in this entire discussion |
|
|
|
|
is that the operators are ordered, from less equal through greater |
|
|
|
|
equal, in <filename>pg_amop</filename>. We add the instances we need: |
|
|
|
|
is that the operators are ordered, from less than through greater |
|
|
|
|
than, in <filename>pg_amop</filename>. We add the instances we need: |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
|
|
|
|
SELECT am.oid, opcl.oid, c.opoid, 1 |
|
|
|
|
FROM pg_am am, pg_opclass opcl, complex_abs_ops_tmp c |
|
|
|
|
FROM pg_am am, pg_opclass opcl, complex_ops_tmp c |
|
|
|
|
WHERE amname = 'btree' AND |
|
|
|
|
opcname = 'complex_abs_ops' AND |
|
|
|
|
c.oprname = '<'; |
|
|
|
@ -493,15 +456,13 @@ CREATE OPERATOR = ( |
|
|
|
|
SELECT oid, proname FROM pg_proc |
|
|
|
|
WHERE proname = 'complex_abs_cmp'; |
|
|
|
|
|
|
|
|
|
+------+-----------------+ |
|
|
|
|
|oid | proname | |
|
|
|
|
+------+-----------------+ |
|
|
|
|
|17328 | complex_abs_cmp | |
|
|
|
|
+------+-----------------+ |
|
|
|
|
oid | proname |
|
|
|
|
--------+----------------- |
|
|
|
|
277997 | complex_abs_cmp |
|
|
|
|
(1 row) |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
(Again, your <filename>oid</filename> number will probably be different |
|
|
|
|
and you should substitute the value you see for the value below.) |
|
|
|
|
(Again, your <filename>oid</filename> number will probably be different.) |
|
|
|
|
We can add the new instance as follows: |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
@ -515,76 +476,8 @@ CREATE OPERATOR = ( |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
Now we need to add a hashing strategy to allow the type to be indexed. |
|
|
|
|
We do this by using another type in pg_am but we reuse the same ops. |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
|
|
|
|
SELECT am.oid, opcl.oid, c.opoid, 1 |
|
|
|
|
FROM pg_am am, pg_opclass opcl, complex_abs_ops_tmp c |
|
|
|
|
WHERE amname = 'hash' AND |
|
|
|
|
opcname = 'complex_abs_ops' AND |
|
|
|
|
c.oprname = '='; |
|
|
|
|
</programlisting> |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
In order to use this index in a where clause, we need to modify the |
|
|
|
|
<filename>pg_operator</filename> class as follows. |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'eqsel'::regproc, oprjoin = 'eqjoinsel' |
|
|
|
|
WHERE oprname = '=' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs'); |
|
|
|
|
|
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'neqsel'::regproc, oprjoin = 'neqjoinsel' |
|
|
|
|
WHERE oprname = '<filename>' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs'); |
|
|
|
|
|
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'neqsel'::regproc, oprjoin = 'neqjoinsel' |
|
|
|
|
WHERE oprname = '<filename>' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs'); |
|
|
|
|
|
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'scalarltsel'::regproc, oprjoin = 'scalarltjoinsel' |
|
|
|
|
WHERE oprname = '<' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs'); |
|
|
|
|
|
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'scalarltsel'::regproc, oprjoin = 'scalarltjoinsel' |
|
|
|
|
WHERE oprname = '<=' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs'); |
|
|
|
|
|
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'scalargtsel'::regproc, oprjoin = 'scalargtjoinsel' |
|
|
|
|
WHERE oprname = '>' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs'); |
|
|
|
|
|
|
|
|
|
UPDATE pg_operator |
|
|
|
|
SET oprrest = 'scalargtsel'::regproc, oprjoin = 'scalargtjoinsel' |
|
|
|
|
WHERE oprname = '>=' AND |
|
|
|
|
oprleft = oprright AND |
|
|
|
|
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');</filename></filename> |
|
|
|
|
</programlisting> |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
<para> |
|
|
|
|
And last (Finally!) we register a description of this type. |
|
|
|
|
|
|
|
|
|
<programlisting> |
|
|
|
|
INSERT INTO pg_description (objoid, description) |
|
|
|
|
SELECT oid, 'Two part G/L account' |
|
|
|
|
FROM pg_type WHERE typname = 'complex_abs'; |
|
|
|
|
</programlisting> |
|
|
|
|
And we're done! (Whew.) It should now be possible to create |
|
|
|
|
and use btree indexes on <filename>complex</filename> columns. |
|
|
|
|
</para> |
|
|
|
|
|
|
|
|
|
</chapter> |
|
|
|
|