From d6efbf19561e7b45349f17e23ce2dd339ddc00f2 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" <lockhart@fourpalms.org> Date: Thu, 27 May 1999 15:44:54 +0000 Subject: [PATCH] Significant update from Vince Vielhaber. --- doc/src/sgml/xindex.sgml | 994 +++++++++++++++++++++------------------ 1 file changed, 543 insertions(+), 451 deletions(-) diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index 6cec3238647..4c0db10295c 100644 --- a/doc/src/sgml/xindex.sgml +++ b/doc/src/sgml/xindex.sgml @@ -1,87 +1,88 @@ -<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 - method. For example, regproc ids for opening, closing, and - getting instances from the access method appear here. </Entry> -</Row> -</TBody> -</TGroup> -</TABLE> -</Para> - -<Para> - 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: - -<ProgramListing> + <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 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.</entry> + </row> + </tbody> + </tgroup> + </table> + </para> + + <para> + 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: + + <programlisting> 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> - uses strategies to express these relationships between - operators and the way they can be used to scan indices. -</Para> - -<Para> - 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</Title> -<TitleAbbrev>B-tree</TitleAbbrev> -<TGroup Cols="2"> -<THead> -<Row> -<Entry>Operation</Entry> -<Entry>Index</Entry> -</Row> -</THead> -<TBody> -<Row> -<Entry>less than</Entry> -<Entry>1</Entry> -</Row> -<Row> -<Entry>less than or equal</Entry> -<Entry>2</Entry> -</Row> -<Row> -<Entry>equal</Entry> -<Entry>3</Entry> -</Row> -<Row> -<Entry>greater than or equal</Entry> -<Entry>4</Entry> -</Row> -<Row> -<Entry>greater than</Entry> -<Entry>5</Entry> -</Row> -</TBody> -</TGroup> -</TABLE> -</Para> - -<Para> - 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</Acronym> 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. -</Para> - -<Para> - 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 - method. The actual routines are listed elsewhere. -</Para> - -<Para> - 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</FileName> of - this instance is a foreign key in other classes. - -<ProgramListing> -INSERT INTO pg_opclass (opcname) VALUES ('complex_abs_ops'); - -SELECT oid, opcname + </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. + </para> + + <para> + 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</title> + <titleabbrev>B-tree</titleabbrev> + <tgroup cols="2"> + <thead> + <row> + <entry>Operation</entry> + <entry>Index</entry> + </row> + </thead> + <tbody> + <row> + <entry>less than</entry> + <entry>1</entry> + </row> + <row> + <entry>less than or equal</entry> + <entry>2</entry> + </row> + <row> + <entry>equal</entry> + <entry>3</entry> + </row> + <row> + <entry>greater than or equal</entry> + <entry>4</entry> + </row> + <row> + <entry>greater than</entry> + <entry>5</entry> + </row> + </tbody> + </tgroup> + </table> + </para> + + <para> + 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</acronym> 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. + </para> + + <para> + 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 + method. The actual routines are listed elsewhere. + </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 + <filename>pg_opclass</filename>. The <filename>oid</filename> of + this instance is a foreign key in other classes. + + <programlisting> +INSERT INTO pg_opclass (opcname, opcdeftype) + SELECT 'complex_abs_ops', oid FROM pg_type WHERE typname = 'complex_abs'; + +SELECT oid, opcname, opcdeftype FROM pg_opclass WHERE opcname = 'complex_abs_ops'; - +------+--------------+ - |oid | opcname | - +------+--------------+ - |17314 | int4_abs_ops | - +------+--------------+ -</ProgramListing> - - 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. -</Para> - -<Para> - 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: - -<ProgramListing> + +------+-----------------+------------+ + |oid | opcname | opcdeftype | + +------+-----------------+------------+ + |17314 | complex_abs_ops | 29058 | + +------+-----------------+------------+ + </programlisting> + + 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. + </para> + + <para> + 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: + + <programlisting> absolute value less-than absolute value less-than-or-equal absolute value equal absolute value greater-than-or-equal absolute value greater-than -</ProgramListing> -</Para> - -<Para> - Suppose the code that implements the functions defined - is stored in the file -<FileName>PGROOT/src/tutorial/complex.c</FileName> -</Para> - -<Para> - 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</FileName> for the details.) - -<ProgramListing> + </programlisting> + </para> + + <para> + Suppose the code that implements the functions defined + is stored in the file + <filename>PGROOT/src/tutorial/complex.c</filename> + </para> + + <para> + 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</filename> for the details.) + + <programlisting> #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); } -</ProgramListing> -</Para> - -<Para> - 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 - 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) + </programlisting> + </para> + + <para> + 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 + 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_abs, complex_abs) RETURNS bool AS 'PGROOT/tutorial/obj/complex.so' LANGUAGE 'c'; -</ProgramListing> -</Para> + </programlisting> + </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>: + <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> + <programlisting> /* * 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 ) -</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>int4_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> -<Row> -<Entry>amopselect, amopnpages</Entry> -<Entry>cost functions</Entry> -</Row> -</TBody> -</TGroup> -</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. -</Para> - -<Para> - 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: - -<ProgramListing> + </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> + <row> + <entry>amopselect, amopnpages</entry> + <entry>cost functions</entry> + </row> + </tbody> + </tgroup> + </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. + </para> + + <para> + 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>es, and pick ours out: + + <programlisting> 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, - amopselect, amopnpages) - SELECT am.oid, opcl.oid, c.opoid, 3, - '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) + </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, 1, + 'btreesel'::regproc, 'btreenpage'::regproc + 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 prname = 'int4_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> + WHERE proname = 'complex_abs_cmp'; + + +------+-----------------+ + |oid | proname | + +------+-----------------+ + |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: +--> -- GitLab