Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
d6efbf19
Commit
d6efbf19
authored
May 27, 1999
by
Thomas G. Lockhart
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Significant update from Vince Vielhaber.
parent
874957a3
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
543 additions
and
451 deletions
+543
-451
doc/src/sgml/xindex.sgml
doc/src/sgml/xindex.sgml
+543
-451
No files found.
doc/src/sgml/xindex.sgml
View file @
d6efbf19
<Chapter Id="xindex">
<Title>Interfacing Extensions To Indices</Title>
<Para>
The procedures described thus far let you define a new
type, new functions and new operators. However, we
cannot yet define a secondary index (such as a <Acronym>B-tree</Acronym>,
<Acronym>R-tree</Acronym> or hash access method) over a new type or its
operators.
</Para>
<Para>
<chapter id="xindex">
<title>Interfacing Extensions To Indices</title>
<para>
The procedures described thus far let you define a new type, new
functions and new operators. However, we cannot yet define a secondary
index (such as a <acronym>B-tree</acronym>, <acronym>R-tree</acronym> or
hash access method) over a new type or its operators.
</para>
<para>
Look back at
<XRef LinkEnd="EXTEND-CATALOGS" EndTerm="EXTEND-CATALOGS">.
The right half shows the catalogs
that we must modify in order to tell <ProductName>Postgres</ProductName> how
to use a user-defined type and/or user-defined operators
with an index (i.e., <FileName>pg_am, pg_amop, pg_amproc</FileName> and
<FileName>pg_opclass</FileName>). Unfortunately, there is no simple command
to do this. We will demonstrate how to modify these
catalogs through a running example: a new operator
class for the <Acronym>B-tree</Acronym> access method that sorts integers
in ascending absolute value order.
</Para>
<Para>
The <FileName>pg_am</FileName> class contains one instance for every user
defined access method. Support for the heap access
method is built into <ProductName>Postgres</ProductName>, but every other access
method is described here. The schema is
<TABLE TOCENTRY="1">
<Title>Index Schema</Title>
<TitleAbbrev>Indices</TitleAbbrev>
<TGroup Cols="2">
<THead>
<Row>
<Entry>Attribute</Entry>
<Entry>Description</Entry>
</Row>
</THead>
<TBody>
<Row>
<Entry>amname</Entry>
<Entry>name of the access method</Entry>
</Row>
<Row>
<Entry>amowner</Entry>
<Entry>object id of the owner's instance in pg_user</Entry>
</Row>
<Row>
<Entry>amkind</Entry>
<Entry>not used at present, but set to 'o' as a place holder</Entry>
</Row>
<Row>
<Entry>amstrategies</Entry>
<Entry>number of strategies for this access method (see below)</Entry>
</Row>
<Row>
<Entry>amsupport</Entry>
<Entry>number of support routines for this access method (see below)</Entry>
</Row>
<Row>
<Entry>amgettuple
aminsert
...</Entry>
<Entry>procedure identifiers for interface routines to the access
<xref endterm="EXTEND-CATALOGS" linkend="EXTEND-CATALOGS">.
The right half shows the catalogs that we must modify in order to tell
<productname>Postgres</productname> how to use a user-defined type and/or
user-defined operators with an index (i.e., <filename>pg_am, pg_amop,
pg_amproc, pg_operator</filename> and <filename>pg_opclass</filename>).
Unfortunately, there is no simple command to do this. We will demonstrate
how to modify these catalogs through a running example: a new operator
class for the <acronym>B-tree</acronym> access method that stores and
sorts complex numbers in ascending absolute value order.
</para>
<para>
The <filename>pg_am</filename> class contains one instance for every user
defined access method. Support for the heap access method is built into
<productname>Postgres</productname>, but every other access method is
described here. The schema is
<table tocentry="1">
<title>Index Schema</title>
<titleabbrev>Indices</titleabbrev>
<tgroup cols="2">
<thead>
<row>
<entry>Attribute</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>amname</entry>
<entry>name of the access method</entry>
</row>
<row>
<entry>amowner</entry>
<entry>object id of the owner's instance in pg_user</entry>
</row>
<row>
<entry>amkind</entry>
<entry>not used at present, but set to 'o' as a place holder</entry>
</row>
<row>
<entry>amstrategies</entry>
<entry>number of strategies for this access method (see below)</entry>
</row>
<row>
<entry>amsupport</entry>
<entry>number of support routines for this access method (see below)</entry>
</row>
<row>
<entry>amgettuple</entry>
</row>
<row>
<entry>aminsert</entry>
</row>
<row>
<entry>...</entry>
<entry>procedure identifiers for interface routines to the access
method. For example, regproc ids for opening, closing, and
getting instances from the access method appear here. </E
ntry>
</R
ow>
</TB
ody>
</TG
roup>
</TABLE
>
</P
ara>
<P
ara>
The <Acronym>object ID</Acronym> of the instance in <FileName>pg_am</FileName> is used as a
foreign key in lots of other classes. You don't need
to add a new instance to this class; all you're interested in
is the <Acronym>object ID</Acronym> of the access method instance
you want to extend:
<ProgramL
isting>
getting instances from the access method appear here.</e
ntry>
</r
ow>
</tb
ody>
</tg
roup>
</table
>
</p
ara>
<p
ara>
The <acronym>object ID</acronym> of the instance in
<filename>pg_am</filename> is used as a foreign key in lots of other
classes. You don't need to add a new instance to this class; all
you're interested in is the <acronym>object ID</acronym> of the access
method instance
you want to extend:
<programl
isting>
SELECT oid FROM pg_am WHERE amname = 'btree';
+----+
...
...
@@ -89,181 +90,187 @@ SELECT oid FROM pg_am WHERE amname = 'btree';
+----+
|403 |
+----+
</ProgramListing>
</Para>
<Para>
The <FileName>amstrategies</FileName> attribute exists to standardize
comparisons across data types. For example, <Acronym>B-tree</Acronym>s
impose a strict ordering on keys, lesser to greater.
Since <ProductName>Postgres</ProductName> allows the user to define operators,
<ProductName>Postgres</ProductName> cannot look at the name of an operator (eg, ">"
or "<") and tell what kind of comparison it is. In fact,
some access methods don't impose any ordering at all.
For example, <Acronym>R-tree</Acronym>s express a rectangle-containment
relationship, whereas a hashed data structure expresses
only bitwise similarity based on the value of a hash
function. <ProductName>Postgres</ProductName> needs some consistent way of taking
a qualification in your query, looking at the operator
and then deciding if a usable index exists. This
implies that <ProductName>Postgres</ProductName> needs to know, for example, that
the "<=" and ">" operators partition a <Acronym>B-tree</Acronym>. <ProductName>Postgres</ProductName>
</programlisting>
We will use that <command>SELECT</command> in a <command>WHERE</command>
clause later.
</para>
<para>
The <filename>amstrategies</filename> attribute exists to standardize
comparisons across data types. For example, <acronym>B-tree</acronym>s
impose a strict ordering on keys, lesser to greater. Since
<productname>Postgres</productname> allows the user to define operators,
<productname>Postgres</productname> cannot look at the name of an operator
(eg, ">" or "<") and tell what kind of comparison it is. In fact,
some access methods don't impose any ordering at all. For example,
<acronym>R-tree</acronym>s express a rectangle-containment relationship,
whereas a hashed data structure expresses only bitwise similarity based
on the value of a hash function. <productname>Postgres</productname>
needs some consistent way of taking a qualification in your query,
looking at the operator and then deciding if a usable index exists. This
implies that <productname>Postgres</productname> needs to know, for
example, that the "<=" and ">" operators partition a
<acronym>B-tree</acronym>. <productname>Postgres</productname>
uses strategies to express these relationships between
operators and the way they can be used to scan indices.
</P
ara>
<P
ara>
Defining a new set of strategies is beyond the scope of
this discussion, but we'll explain how <Acronym>B-tree</Acronym> strategies
work because you'll need to know that to add a new
operator class. In the <FileName>pg_am</FileName> class, the amstrategies
attribute is the number of strategies defined for this
access method. For <Acronym>B-tree</Acronym>s, this number is 5. These
strategies
correspond to
<TABLE TOCENTRY
="1">
<Title>B-tree Strategies</T
itle>
<TitleAbbrev>B-tree</TitleA
bbrev>
<TGroup C
ols="2">
<TH
ead>
<R
ow>
<Entry>Operation</E
ntry>
<Entry>Index</E
ntry>
</R
ow>
</TH
ead>
<TB
ody>
<R
ow>
<Entry>less than</E
ntry>
<Entry>1</E
ntry>
</R
ow>
<R
ow>
<Entry>less than or equal</E
ntry>
<Entry>2</E
ntry>
</R
ow>
<R
ow>
<Entry>equal</E
ntry>
<Entry>3</E
ntry>
</R
ow>
<R
ow>
<Entry>greater than or equal</E
ntry>
<Entry>4</E
ntry>
</R
ow>
<R
ow>
<Entry>greater than</E
ntry>
<Entry>5</E
ntry>
</R
ow>
</TB
ody>
</TG
roup>
</TABLE
>
</P
ara>
<P
ara>
The idea is that you'll need to add procedures corresponding
to the comparisons above to the <FileName>pg_amop</FileName> relation
(see below). The access method code can use these
strategy numbers, regardless of data type, to figure
out how to partition the <Acronym>B-tree</Acronym>, compute selectivity,
and so on. Don't worry about the details of adding
procedures yet; just understand that there must be a
set of these procedures for <FileName>int2, int4, oid,</FileName> and every
other data type on which a <Acronym>B-tree</Acronym> can operate.
Sometimes, strategies aren't enough information for the
system to figure out how to use an index. Some access
methods require other support routines in order to
work. For example, the <Acronym>B-tree</Acronym> access method must be
able to compare two keys and determine whether one is
greater than, equal to, or less than the other.
Similarly, the <Acronym>R-tree</A
cronym> access method must be able to compute
</p
ara>
<p
ara>
Defining a new set of strategies is beyond the scope of this discussion,
but we'll explain how <acronym>B-tree</acronym> strategies work because
you'll need to know that to add a new operator class. In the
<filename>pg_am</filename> class, the amstrategies attribute is the
number of strategies defined for this access method. For
<acronym>B-tree</acronym>s, this number is 5. These strategies
correspond to
<table tocentry
="1">
<title>B-tree Strategies</t
itle>
<titleabbrev>B-tree</titlea
bbrev>
<tgroup c
ols="2">
<th
ead>
<r
ow>
<entry>Operation</e
ntry>
<entry>Index</e
ntry>
</r
ow>
</th
ead>
<tb
ody>
<r
ow>
<entry>less than</e
ntry>
<entry>1</e
ntry>
</r
ow>
<r
ow>
<entry>less than or equal</e
ntry>
<entry>2</e
ntry>
</r
ow>
<r
ow>
<entry>equal</e
ntry>
<entry>3</e
ntry>
</r
ow>
<r
ow>
<entry>greater than or equal</e
ntry>
<entry>4</e
ntry>
</r
ow>
<r
ow>
<entry>greater than</e
ntry>
<entry>5</e
ntry>
</r
ow>
</tb
ody>
</tg
roup>
</table
>
</p
ara>
<p
ara>
The idea is that you'll need to add procedures corresponding to the
comparisons above to the <filename>pg_amop</filename> relation (see below).
The access method code can use these strategy numbers, regardless of data
type, to figure out how to partition the <acronym>B-tree</acronym>,
compute selectivity, and so on. Don't worry about the details of adding
procedures yet; just understand that there must be a set of these
procedures for <filename>int2, int4, oid,</filename> and every other
data type on which a <acronym>B-tree</acronym> can operate.
</para>
<para>
Sometimes, strategies aren't enough information for the system to figure
out how to use an index. Some access methods require other support
routines in order to work. For example, the <acronym>B-tree</acronym>
access method must be able to compare two keys and determine whether one
is greater than, equal to, or less than the other. Similarly, the
<acronym>R-tree</a
cronym> access method must be able to compute
intersections, unions, and sizes of rectangles. These
operations do not correspond to user qualifications in
SQL queries; they are administrative routines used by
the access methods, internally.
</P
ara>
<P
ara>
In order to manage diverse support routines
consistently across all <ProductName>Postgres</ProductName> access methods, <FileName>pg_am</FileName>
includes an attribute called <FileName>amsupport</FileName>. This attribute
records the number of support routines used by an
access method. For <Acronym>B-tree</Acronym>s, this number is one -- the
routine to take two keys and return -1, 0, or +1,
depending on whether the first key is less than,
equal
</p
ara>
<p
ara>
In order to manage diverse support routines consistently across all
<productname>Postgres</productname> access methods,
<filename>pg_am</filename> includes an attribute called
<filename>amsupport</filename>. This attribute records the number of
support routines used by an access method. For <acronym>B-tree</acronym>s,
this number is one -- the routine to take two keys and return -1, 0, or
+1, depending on whether the first key is less than,
equal
to, or greater than the second.
<Note>
<Para>
Strictly speaking, this routine can return a negative
number (< 0), 0, or a non-zero positive number (> 0).
</Para>
</Note>
</para>
<Para>
The <FileName>amstrategies</FileName> entry in pg_am 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> is just
the number of support routines required by the access
<note>
<para>
Strictly speaking, this routine can return a negative
number (< 0), 0, or a non-zero positive number (> 0).
</para>
</note>
</para>
<para>
The <filename>amstrategies</filename> entry in pg_am 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>
is just the number of support routines required by the access
method. The actual routines are listed elsewhere.
</P
ara>
<P
ara>
The next class of interest is pg_opclass. This class
exists only to associate a name 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 <FileName>pg_opclass</FileName>. The <FileName>oid</FileN
ame> of
</p
ara>
<p
ara>
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
<filename>pg_opclass</filename>. The <filename>oid</filen
ame> of
this instance is a foreign key in other classes.
<ProgramListing>
INSERT INTO pg_opclass (opcname) VALUES ('complex_abs_ops');
<programlisting>
INSERT INTO pg_opclass (opcname, opcdeftype)
SELECT 'complex_abs_ops', oid FROM pg_type WHERE typname = 'complex_abs';
SELECT oid, opcname
SELECT oid, opcname
, opcdeftype
FROM pg_opclass
WHERE opcname = 'complex_abs_ops';
+------+--------------+
|oid | opcname |
+------+--------------+
|17314 |
int4_abs_ops
|
+------+--------------+
</ProgramL
isting>
+------+--------------
---+------------
+
|oid | opcname
| opcdeftype
|
+------+--------------
---+------------
+
|17314 |
complex_abs_ops | 29058
|
+------+--------------
---+------------
+
</programl
isting>
Note that the oid for your <FileName>pg_opclass</FileName> instance will be
different! You should substitute your value for 17314
wherever it appears in this discussion
.
</P
ara>
Note that the oid for your <filename>pg_opclass</filename> instance will
be different! Don't worry about this though. We'll get this number
from the system later just like we got the oid of the type here
.
</p
ara>
<P
ara>
<p
ara>
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 earlier in this manual.
For the complex_abs_ops operator class on Btrees,
the operators we require are:
<ProgramL
isting>
<programl
isting>
absolute value less-than
absolute value less-than-or-equal
absolute value equal
absolute value greater-than-or-equal
absolute value greater-than
</ProgramL
isting>
</P
ara>
</programl
isting>
</p
ara>
<P
ara>
<p
ara>
Suppose the code that implements the functions defined
is stored in the file
<FileName>PGROOT/src/tutorial/complex.c</FileN
ame>
</P
ara>
<filename>PGROOT/src/tutorial/complex.c</filen
ame>
</p
ara>
<P
ara>
Part of the code look 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.sql</FileN
ame> for the details.)
<p
ara>
Part of the code look 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</filen
ame> for the details.)
<ProgramL
isting>
<programl
isting>
#define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y)
bool
...
...
@@ -272,61 +279,57 @@ SELECT oid, opcname
double amag = Mag(a), bmag = Mag(b);
return (amag==bmag);
}
</ProgramL
isting>
</P
ara>
</programl
isting>
</p
ara>
<P
ara>
<p
ara>
There are a couple of important things that are happening below.
</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
</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.
</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.
</Para>
<Para>
<ProgramListing>
CREATE FUNCTION complex_abs_eq(complex, complex)
</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.
</para>
<para>
<programlisting>
CREATE FUNCTION complex_abs_eq(complex_abs, complex_abs)
RETURNS bool
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
</ProgramL
isting>
</P
ara>
</programl
isting>
</p
ara>
<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>:
<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>:
<ProgramL
isting>
<programl
isting>
/*
* this query uses the regular expression operator (~)
* to find three-character operator names that end in
...
...
@@ -335,95 +338,93 @@ CREATE FUNCTION complex_abs_eq(complex, complex)
SELECT *
FROM pg_operator
WHERE oprname ~ '^..&$'::text;
</ProgramListing>
</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.
<ProgramListing>
</programlisting>
</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.
<programlisting>
CREATE OPERATOR = (
leftarg = complex
, rightarg = complex
,
leftarg = complex
_abs, rightarg = complex_abs
,
procedure = complex_abs_eq,
restrict = eqsel, join = eqjoinsel
)
</ProgramL
isting>
</P
ara>
<P
ara>
Notice that five operators corresponding to less, less
equal, equal,
greater, and greater equal are defined.
</P
ara>
<P
ara>
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</T
itle>
<TitleAbbrev><FileName>pg_amproc</FileName></TitleA
bbrev>
<TGroup C
ols="2">
<TH
ead>
<R
ow>
<Entry>Attribute</E
ntry>
<Entry>Description</E
ntry>
</R
ow>
</TH
ead>
<TB
ody>
<R
ow>
<Entry>amopid</E
ntry>
<Entry>the <FileName>oid</FileName> of the <FileName>pg_am</FileN
ame> instance
for B-tree (== 403, see above)</E
ntry>
</R
ow>
<R
ow>
<Entry>amopclaid</E
ntry>
<Entry>the <FileName>oid</FileName> of the
<FileName>pg_opclass</FileName> instance for <FileName>int4_abs_ops</FileN
ame>
(== whatever you got instead of <FileName>17314</FileName>, see above)</E
ntry>
</R
ow>
<R
ow>
<Entry>amopopr</E
ntry>
<Entry>the <FileName>oid</FileN
ame>s of the operators for the opclass
(which we'll get in just a minute)</E
ntry>
</R
ow>
<R
ow>
<Entry>amopselect, amopnpages</E
ntry>
<Entry>cost functions</E
ntry>
</R
ow>
</TB
ody>
</TG
roup>
</TABLE
>
The cost functions are used by the query optimizer to
decide whether or not to use a given index in a scan
.
Fortunately, these already exist. The two functions
we'll use are <FileName>btreesel</FileName>, which estimates the selectivity
of the <Acronym>B-tree</Acronym>, and <FileName>btreenpage</FileName>, which estimates the
number of pages a
search will touch in the tree.
</P
ara>
<P
ara>
So we 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>int4</FileName>
s, and pick ours out:
<ProgramL
isting>
</programl
isting>
</p
ara>
<p
ara>
Notice that five operators corresponding to less, less equal, equal,
greater, and greater equal are defined.
</p
ara>
<p
ara>
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</t
itle>
<titleabbrev><filename>pg_amproc</filename></titlea
bbrev>
<tgroup c
ols="2">
<th
ead>
<r
ow>
<entry>Attribute</e
ntry>
<entry>Description</e
ntry>
</r
ow>
</th
ead>
<tb
ody>
<r
ow>
<entry>amopid</e
ntry>
<entry>the <filename>oid</filename> of the <filename>pg_am</filen
ame> instance
for B-tree (== 403, see above)</e
ntry>
</r
ow>
<r
ow>
<entry>amopclaid</e
ntry>
<entry>the <filename>oid</filename> of the
<filename>pg_opclass</filename> instance for <filename>complex_abs_ops</filen
ame>
(== whatever you got instead of <filename>17314</filename>, see above)</e
ntry>
</r
ow>
<r
ow>
<entry>amopopr</e
ntry>
<entry>the <filename>oid</filen
ame>s of the operators for the opclass
(which we'll get in just a minute)</e
ntry>
</r
ow>
<r
ow>
<entry>amopselect, amopnpages</e
ntry>
<entry>cost functions</e
ntry>
</r
ow>
</tb
ody>
</tg
roup>
</table
>
The cost functions are used by the query optimizer to decide whether or
not to use a given index in a scan. Fortunately, these already exist
.
The two functions we'll use are <filename>btreesel</filename>, which
estimates the selectivity of the <acronym>B-tree</acronym>, and
<filename>btreenpage</filename>, which estimates the number of pages a
search will touch in the tree.
</p
ara>
<p
ara>
So we 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>e
s, and pick ours out:
<programl
isting>
SELECT o.oid AS opoid, o.oprname
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';
and t.typname = 'complex
_abs
';
+------+---------+
|oid | oprname |
...
...
@@ -438,78 +439,169 @@ CREATE OPERATOR = (
+------+---------+
|17325 | > |
+------+---------+
</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
get will probably be different, and you should
substitute them for the values below. We can look at the
operator names and pick out the ones we just added.
</Para>
<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:
<ProgramListing>
INSERT INTO pg_amop (amopid, amopclaid,
amopopr, amopstrategy,
</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
get will probably be different, and you should substitute them for the
values below. We will do this with a select statement.
</para>
<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:
<programlisting>
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
amopselect, amopnpages)
SELECT am.oid, opcl.oid, c.opoid, 3
,
SELECT am.oid, opcl.oid, c.opoid, 1
,
'btreesel'::regproc, 'btreenpage'::regproc
FROM pg_am am, pg_opclass opcl, complex_ops_tmp c
WHERE amname = 'btree'
and opcname = 'complex_abs_ops'
and c.oprname = '=';
</ProgramListing>
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.
</Para>
<Para>
The last step (finally!) is registration of the
"support routine" previously described in our discussion of
<FileName>pg_am</FileName>. The <FileName>oid</FileName> of this support routine is stored in
the <FileName>pg_amproc</FileName> class, keyed by the access method <FileName>oid</FileName> and
the operator class <FileName>oid</FileName>. First, we need to register the
function in <ProductName>Postgres</ProductName> (recall that we put the <Acronym>C</Acronym> code
that implements this routine in the bottom of the file
in which we implemented the operator routines):
<ProgramListing>
CREATE FUNCTION int4_abs_cmp(int4, int4)
FROM pg_am am, pg_opclass opcl, complex_abs_ops_tmp c
WHERE amname = 'btree' AND
opcname = 'complex_abs_ops' AND
c.oprname = '<';
</programlisting>
Now do this for the other operators substituting for the "1" in the
third 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.
</para>
<para>
The next step is registration of the "support routine" previously
described in our discussion of <filename>pg_am</filename>. The
<filename>oid</filename> of this support routine is stored in the
<filename>pg_amproc</filename> class, keyed by the access method
<filename>oid</filename> and the operator class <filename>oid</filename>.
First, we need to register the function in
<productname>Postgres</productname> (recall that we put the
<acronym>C</acronym> code that implements this routine in the bottom of
the file in which we implemented the operator routines):
<programlisting>
CREATE FUNCTION complex_abs_cmp(complex, complex)
RETURNS int4
AS 'PGROOT/tutorial/obj/complex.so'
LANGUAGE 'c';
SELECT oid, proname FROM pg_proc
WHERE pr
name = 'int4
_abs_cmp';
WHERE pr
oname = 'complex
_abs_cmp';
+------+--------------+
+------+--------------
---
+
|oid | proname |
+------+--------------+
|17328 | int4_abs_cmp |
+------+--------------+
</ProgramListing>
(Again, your <FileName>oid</FileName> number will probably be different and
you should substitute the value you see for the value
below.) Recalling that the <Acronym>B-tree</Acronym> instance's oid is
403 and that of <FileName>int4_abs_ops</FileName> is 17314, we can add the
new instance as follows:
<ProgramListing>
+------+-----------------+
|17328 | complex_abs_cmp |
+------+-----------------+
</programlisting>
(Again, your <filename>oid</filename> number will probably be different
and you should substitute the value you see for the value below.)
We can add the new instance as follows:
<programlisting>
INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
VALUES ('403'::oid, -- btree oid
'17314'::oid, -- pg_opclass tuple
'17328'::oid, -- new pg_proc oid
'1'::int2);
</ProgramListing>
</Para>
</Chapter>
SELECT a.oid, b.oid, c.oid, 1
FROM pg_am a, pg_opclass b, pg_proc c
WHERE a.amname = 'btree' AND
b.opcname = 'complex_abs_ops' AND
c.proname = 'complex_abs_cmp';
</programlisting>
</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 sames ops.
<programlisting>
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy,
amopselect, amopnpages)
SELECT am.oid, opcl.oid, c.opoid, 1,
'hashsel'::regproc, 'hashnpage'::regproc
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 = 'intltsel'::regproc, oprjoin = 'intltjoinsel'
WHERE oprname = '<' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intltsel'::regproc, oprjoin = 'intltjoinsel'
WHERE oprname = '<=' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intgtsel'::regproc, oprjoin = 'intgtjoinsel'
WHERE oprname = '>' AND
oprleft = oprright AND
oprleft = (SELECT oid FROM pg_type WHERE typname = 'complex_abs');
UPDATE pg_operator
SET oprrest = 'intgtsel'::regproc, oprjoin = 'intgtjoinsel'
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>
</para>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"./reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment