Restructure operator classes to allow improved handling of cross-data-type

cases.  Operator classes now exist within "operator families".  While most
families are equivalent to a single class, related classes can be grouped
into one family to represent the fact that they are semantically compatible.
Cross-type operators are now naturally adjunct parts of a family, without
having to wedge them into a particular opclass as we had done originally.

This commit restructures the catalogs and cleans up enough of the fallout so
that everything still works at least as well as before, but most of the work
needed to actually improve the planner's behavior will come later.  Also,
there are not yet CREATE/DROP/ALTER OPERATOR FAMILY commands; the only way
to create a new family right now is to allow CREATE OPERATOR CLASS to make
one by default.  I owe some more documentation work, too.  But that can all
be done in smaller pieces once this infrastructure is in place.
This commit is contained in:
Tom Lane 2006-12-23 00:43:13 +00:00
parent d31ccb6c3e
commit a78fcfb512
76 changed files with 4753 additions and 4100 deletions

View File

@ -459,9 +459,9 @@ AS
--GIN
--mark built-in gin's _int4_ops as non default
update pg_opclass set opcdefault = 'f' where
pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and
opcname = '_int4_ops';
update pg_catalog.pg_opclass set opcdefault = 'f'
where opcmethod = (select oid from pg_catalog.pg_am where amname='gin') and
opcname = '_int4_ops';
CREATE FUNCTION ginint4_queryextract(internal, internal, int2)
RETURNS internal

View File

@ -124,7 +124,7 @@ DROP FUNCTION querytree(query_int);
DROP TYPE query_int CASCADE;
update pg_opclass set opcdefault = 't' where
pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and
opcname = '_int4_ops';
--mark built-in gin's _int4_ops as default again
update pg_catalog.pg_opclass set opcdefault = 't'
where opcmethod = (select oid from pg_catalog.pg_am where amname='gin') and
opcname = '_int4_ops';

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.138 2006/12/18 18:56:28 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.139 2006/12/23 00:43:08 tgl Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
@ -160,7 +160,7 @@
<row>
<entry><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link></entry>
<entry>index access method operator classes</entry>
<entry>access method operator classes</entry>
</row>
<row>
@ -168,6 +168,11 @@
<entry>operators</entry>
</row>
<row>
<entry><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link></entry>
<entry>access method operator families</entry>
</row>
<row>
<entry><link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link></entry>
<entry>template data for procedural languages</entry>
@ -516,9 +521,11 @@
</indexterm>
<para>
The catalog <structname>pg_amop</structname> stores information about operators
associated with index access method operator classes. There is one
row for each operator that is a member of an operator class.
The catalog <structname>pg_amop</structname> stores information about
operators associated with access method operator families. There is one
row for each operator that is a member of an operator family. An operator
can appear in more than one family, but may not appear in more than one
position within a family.
</para>
<table>
@ -536,18 +543,24 @@
<tbody>
<row>
<entry><structfield>amopclaid</structfield></entry>
<entry><structfield>amopfamily</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
<entry>The index operator class this entry is for</entry>
<entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
<entry>The operator family this entry is for</entry>
</row>
<row>
<entry><structfield>amopsubtype</structfield></entry>
<entry><structfield>amoplefttype</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Subtype to distinguish multiple entries for one strategy;
zero for default</entry>
<entry>Left-hand input data type of operator</entry>
</row>
<row>
<entry><structfield>amoprighttype</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Right-hand input data type of operator</entry>
</row>
<row>
@ -571,10 +584,27 @@
<entry>OID of the operator</entry>
</row>
<row>
<entry><structfield>amopmethod</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></entry>
<entry>Index access method operator family is for</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
An entry's <structfield>amopmethod</> must match the
<structname>opfmethod</> of its containing operator family (including
<structfield>amopmethod</> here is an intentional denormalization of the
catalog structure for performance reasons). Also,
<structfield>amoplefttype</> and <structfield>amoprighttype</> must match
the <structfield>oprleft</> and <structfield>oprright</> fields of the
referenced <structname>pg_operator</> entry.
</para>
</sect1>
@ -586,10 +616,9 @@
</indexterm>
<para>
The catalog <structname>pg_amproc</structname> stores information about support
procedures
associated with index access method operator classes. There is one
row for each support procedure belonging to an operator class.
The catalog <structname>pg_amproc</structname> stores information about
support procedures associated with access method operator families. There
is one row for each support procedure belonging to an operator family.
</para>
<table>
@ -607,17 +636,24 @@
<tbody>
<row>
<entry><structfield>amopclaid</structfield></entry>
<entry><structfield>amprocfamily</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
<entry>The index operator class this entry is for</entry>
<entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
<entry>The operator family this entry is for</entry>
</row>
<row>
<entry><structfield>amprocsubtype</structfield></entry>
<entry><structfield>amproclefttype</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Subtype, if cross-type routine, else zero</entry>
<entry>Left-hand input data type of associated operator</entry>
</row>
<row>
<entry><structfield>amprocrighttype</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
<entry>Right-hand input data type of associated operator</entry>
</row>
<row>
@ -638,6 +674,18 @@
</tgroup>
</table>
<para>
The usual interpretation of the
<structfield>amproclefttype</> and <structfield>amprocrighttype</> fields
is that they identify the left and right input types of the operator(s)
that a particular support procedure supports. For some access methods
these match the input data type(s) of the support procedure itself, for
others not. There is a notion of <quote>default</> support procedures for
an index, which are those with <structfield>amproclefttype</> and
<structfield>amprocrighttype</> both equal to the index opclass's
<structfield>opcintype</>.
</para>
</sect1>
@ -2843,9 +2891,11 @@
The catalog <structname>pg_opclass</structname> defines
index access method operator classes. Each operator class defines
semantics for index columns of a particular data type and a particular
index access method. Note that there can be multiple operator classes
for a given data type/access method combination, thus supporting multiple
behaviors.
index access method. An operator class essentially specifies that a
particular operator family is applicable to a particular indexable column
data type. The set of operators from the family that are actually usable
with the indexed column are whichever ones accept the column's data type
as their lefthand input.
</para>
<para>
@ -2867,7 +2917,7 @@
<tbody>
<row>
<entry><structfield>opcamid</structfield></entry>
<entry><structfield>opcmethod</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></entry>
<entry>Index access method operator class is for</entry>
@ -2894,6 +2944,13 @@
<entry>Owner of the operator class</entry>
</row>
<row>
<entry><structfield>opcfamily</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
<entry>Operator family containing the operator class</entry>
</row>
<row>
<entry><structfield>opcintype</structfield></entry>
<entry><type>oid</type></entry>
@ -2920,14 +2977,11 @@
</table>
<para>
The majority of the information defining an operator class is actually
not in its <structname>pg_opclass</structname> row, but in the associated
rows in <structname>pg_amop</structname> and
<structname>pg_amproc</structname>. Those rows are considered to be
part of the operator class definition &mdash; this is not unlike the way
that a relation is defined by a single <structname>pg_class</structname>
row plus associated rows in <structname>pg_attribute</structname> and
other tables.
An operator class's <structfield>opcmethod</> must match the
<structname>opfmethod</> of its containing operator family.
Also, there must be no more than one <structname>pg_opclass</structname>
row having <structname>opcdefault</> true for any given combination of
<structname>opcmethod</> and <structname>opcintype</>.
</para>
</sect1>
@ -2993,6 +3047,13 @@
</entry>
</row>
<row>
<entry><structfield>oprcanmerge</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>This operator supports merge joins</entry>
</row>
<row>
<entry><structfield>oprcanhash</structfield></entry>
<entry><type>bool</type></entry>
@ -3035,46 +3096,6 @@
<entry>Negator of this operator, if any</entry>
</row>
<row>
<entry><structfield>oprlsortop</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
<entry>
If this operator supports merge joins, the operator that sorts
the type of the left-hand operand (<literal>L&lt;L</>)
</entry>
</row>
<row>
<entry><structfield>oprrsortop</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
<entry>
If this operator supports merge joins, the operator that sorts
the type of the right-hand operand (<literal>R&lt;R</>)
</entry>
</row>
<row>
<entry><structfield>oprltcmpop</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
<entry>
If this operator supports merge joins, the less-than operator that
compares the left and right operand types (<literal>L&lt;R</>)
</entry>
</row>
<row>
<entry><structfield>oprgtcmpop</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
<entry>
If this operator supports merge joins, the greater-than operator that
compares the left and right operand types (<literal>L&gt;R</>)
</entry>
</row>
<row>
<entry><structfield>oprcode</structfield></entry>
<entry><type>regproc</type></entry>
@ -3107,6 +3128,86 @@
</sect1>
<sect1 id="catalog-pg-opfamily">
<title><structname>pg_opfamily</structname></title>
<indexterm zone="catalog-pg-opfamily">
<primary>pg_opfamily</primary>
</indexterm>
<para>
The catalog <structname>pg_opfamily</structname> defines operator families.
Each operator family is a collection of operators and associated
support routines that implement the semantics specified for a particular
index access method. Furthermore, the operators in a family are all
<quote>compatible</>, in a way that depends on the access method.
The operator family concept allows cross-data-type operators to be used
with indexes and to be reasoned about using knowledge of access method
semantics.
</para>
<para>
Operator families are described at length in <xref linkend="xindex">.
</para>
<table>
<title><structname>pg_opfamily</> Columns</title>
<tgroup cols=4>
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>References</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>opfmethod</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></entry>
<entry>Index access method operator family is for</entry>
</row>
<row>
<entry><structfield>opfname</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
<entry>Name of this operator family</entry>
</row>
<row>
<entry><structfield>opfnamespace</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.oid</literal></entry>
<entry>Namespace of this operator family</entry>
</row>
<row>
<entry><structfield>opfowner</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
<entry>Owner of the operator family</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The majority of the information defining an operator family is not in its
<structname>pg_opfamily</structname> row, but in the associated rows in
<link linkend="catalog-pg-amop"><structname>pg_amop</structname></link>,
<link linkend="catalog-pg-amproc"><structname>pg_amproc</structname></link>,
and
<link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.
</para>
</sect1>
<sect1 id="catalog-pg-pltemplate">
<title><structname>pg_pltemplate</structname></title>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.18 2006/09/16 00:30:14 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.19 2006/12/23 00:43:08 tgl Exp $ -->
<chapter id="indexam">
<title>Index Access Method Interface Definition</title>
@ -63,13 +63,15 @@
<para>
To be useful, an index access method must also have one or more
<firstterm>operator families</> and
<firstterm>operator classes</> defined in
<link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>,
<link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>,
<link linkend="catalog-pg-amop"><structname>pg_amop</structname></link>, and
<link linkend="catalog-pg-amproc"><structname>pg_amproc</structname></link>.
These entries allow the planner
to determine what kinds of query qualifications can be used with
indexes of this access method. Operator classes are described
indexes of this access method. Operator families and classes are described
in <xref linkend="xindex">, which is prerequisite material for reading
this chapter.
</para>
@ -409,14 +411,14 @@ amrestrpos (IndexScanDesc scan);
A scan key is the internal representation of a <literal>WHERE</> clause of
the form <replaceable>index_key</> <replaceable>operator</>
<replaceable>constant</>, where the index key is one of the columns of the
index and the operator is one of the members of the operator class
index and the operator is one of the members of the operator family
associated with that index column. An index scan has zero or more scan
keys, which are implicitly ANDed &mdash; the returned tuples are expected
to satisfy all the indicated conditions.
</para>
<para>
The operator class may indicate that the index is <firstterm>lossy</> for a
The operator family may indicate that the index is <firstterm>lossy</> for a
particular operator; this implies that the index scan will return all the
entries that pass the scan key, plus possibly additional entries that do
not. The core system's index-scan machinery will then apply that operator
@ -429,7 +431,7 @@ amrestrpos (IndexScanDesc scan);
Note that it is entirely up to the access method to ensure that it
correctly finds all and only the entries passing all the given scan keys.
Also, the core system will simply hand off all the <literal>WHERE</>
clauses that match the index keys and operator classes, without any
clauses that match the index keys and operator families, without any
semantic analysis to determine whether they are redundant or
contradictory. As an example, given
<literal>WHERE x &gt; 4 AND x &gt; 14</> where <literal>x</> is a b-tree

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.66 2006/12/01 23:46:46 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.67 2006/12/23 00:43:08 tgl Exp $ -->
<chapter id="indexes">
<title id="indexes-title">Indexes</title>
@ -784,12 +784,16 @@ CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target)
<sect1 id="indexes-opclass">
<title>Operator Classes</title>
<title>Operator Classes and Operator Families</title>
<indexterm zone="indexes-opclass">
<primary>operator class</primary>
</indexterm>
<indexterm zone="indexes-opclass">
<primary>operator family</primary>
</indexterm>
<para>
An index definition may specify an <firstterm>operator
class</firstterm> for each column of an index.
@ -854,20 +858,32 @@ CREATE INDEX test_index ON test_table (col varchar_pattern_ops);
SELECT am.amname AS index_method,
opc.opcname AS opclass_name
FROM pg_am am, pg_opclass opc
WHERE opc.opcamid = am.oid
WHERE opc.opcmethod = am.oid
ORDER BY index_method, opclass_name;
</programlisting>
</para>
It can be extended to show all the operators included in each class:
<para>
An operator class is actually just a subset of a larger structure called an
<firstterm>operator family</>. In cases where several data types have
similar behaviors, it is frequently useful to define cross-data-type
operators and allow these to work with indexes. To do this, the operator
classes for each of the types must be grouped into the same operator
family. The cross-type operators are members of the family, but are not
associated with any single class within the family.
</para>
<para>
This query shows all defined operator families and all
the operators included in each family:
<programlisting>
SELECT am.amname AS index_method,
opc.opcname AS opclass_name,
opr.oid::regoperator AS opclass_operator
FROM pg_am am, pg_opclass opc, pg_amop amop, pg_operator opr
WHERE opc.opcamid = am.oid AND
amop.amopclaid = opc.oid AND
amop.amopopr = opr.oid
ORDER BY index_method, opclass_name, opclass_operator;
opf.opfname AS opfamily_name,
amop.amopopr::regoperator AS opfamily_operator
FROM pg_am am, pg_opfamily opf, pg_amop amop
WHERE opf.opfmethod = am.oid AND
amop.amopfamily = opf.oid
ORDER BY index_method, opfamily_name, opfamily_operator;
</programlisting>
</para>
</sect1>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.45 2006/09/16 00:30:17 momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.46 2006/12/23 00:43:08 tgl Exp $
PostgreSQL documentation
-->
@ -26,8 +26,6 @@ CREATE OPERATOR <replaceable>name</replaceable> (
[, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
[, RESTRICT = <replaceable class="parameter">res_proc</replaceable> ] [, JOIN = <replaceable class="parameter">join_proc</replaceable> ]
[, HASHES ] [, MERGES ]
[, SORT1 = <replaceable class="parameter">left_sort_op</replaceable> ] [, SORT2 = <replaceable class="parameter">right_sort_op</replaceable> ]
[, LTCMP = <replaceable class="parameter">less_than_op</replaceable> ] [, GTCMP = <replaceable class="parameter">greater_than_op</replaceable> ]
)
</synopsis>
</refsynopsisdiv>
@ -202,46 +200,6 @@ CREATE OPERATOR <replaceable>name</replaceable> (
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">left_sort_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the less-than
operator that sorts the left-hand data type of this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">right_sort_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the less-than
operator that sorts the right-hand data type of this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">less_than_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the less-than
operator that compares the input data types of this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">greater_than_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the greater-than
operator that compares the input data types of this operator.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
@ -261,6 +219,16 @@ COMMUTATOR = OPERATOR(myschema.===) ,
Refer to <xref linkend="xoper"> for further information.
</para>
<para>
The obsolete options <literal>SORT1</>, <literal>SORT2</>,
<literal>LTCMP</>, and <literal>GTCMP</> were formerly used to
specify the names of sort operators associated with a mergejoinable
operator. This is no longer necessary, since information about
associated operators is found by looking at btree operator families
instead. If one of these options is given, it is ignored except
for implicitly setting <literal>MERGES</> true.
</para>
<para>
Use <xref linkend="sql-dropoperator"
endterm="sql-dropoperator-title"> to delete user-defined operators
@ -285,11 +253,7 @@ CREATE OPERATOR === (
NEGATOR = !==,
RESTRICT = area_restriction_procedure,
JOIN = area_join_procedure,
HASHES,
SORT1 = &lt;&lt;&lt;,
SORT2 = &lt;&lt;&lt;
-- Since sort operators were given, MERGES is implied.
-- LTCMP and GTCMP are assumed to be &lt; and &gt; respectively
HASHES, MERGES
);
</programlisting>
</para>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/xoper.sgml,v 1.36 2006/09/16 00:30:16 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/xoper.sgml,v 1.37 2006/12/23 00:43:08 tgl Exp $ -->
<sect1 id="xoper">
<title>User-Defined Operators</title>
@ -342,13 +342,13 @@ table1.column1 OP table2.column2
<para>
To be marked <literal>HASHES</literal>, the join operator must appear
in a hash index operator class. This is not enforced when you create
the operator, since of course the referencing operator class couldn't
in a hash index operator family. This is not enforced when you create
the operator, since of course the referencing operator family couldn't
exist yet. But attempts to use the operator in hash joins will fail
at run time if no such operator class exists. The system needs the
operator class to find the data-type-specific hash function for the
at run time if no such operator family exists. The system needs the
operator family to find the data-type-specific hash function for the
operator's input data type. Of course, you must also supply a suitable
hash function before you can create the operator class.
hash function before you can create the operator family.
</para>
<para>
@ -390,7 +390,7 @@ table1.column1 OP table2.column2
</sect2>
<sect2>
<title><literal>MERGES</> (<literal>SORT1</>, <literal>SORT2</>, <literal>LTCMP</>, <literal>GTCMP</>)</title>
<title><literal>MERGES</></title>
<para>
The <literal>MERGES</literal> clause, if present, tells the system that
@ -418,36 +418,13 @@ table1.column1 OP table2.column2
</para>
<para>
Execution of a merge join requires that the system be able to identify
four operators related to the merge-join equality operator: less-than
comparison for the left operand data type, less-than comparison for the
right operand data type, less-than comparison between the two data types, and
greater-than comparison between the two data types. (These are actually
four distinct operators if the merge-joinable operator has two different
operand data types; but when the operand types are the same the three
less-than operators are all the same operator.)
It is possible to
specify these operators individually by name, as the <literal>SORT1</>,
<literal>SORT2</>, <literal>LTCMP</>, and <literal>GTCMP</> options
respectively. The system will fill in the default names
<literal>&lt;</>, <literal>&lt;</>, <literal>&lt;</>, <literal>&gt;</>
respectively if any of these are omitted when <literal>MERGES</> is
specified. Also, <literal>MERGES</> will be assumed to be implied if any
of these four operator options appear, so it is possible to specify
just some of them and let the system fill in the rest.
</para>
<para>
The operand data types of the four comparison operators can be deduced
from the operand types of the merge-joinable operator, so just as with
<literal>COMMUTATOR</>, only the operator names need be given in these
clauses. Unless you are using peculiar choices of operator names,
it's sufficient to write <literal>MERGES</> and let the system fill in
the details.
(As with <literal>COMMUTATOR</> and <literal>NEGATOR</>, the system is
able to make dummy
operator entries if you happen to define the equality operator before
the other ones.)
To be marked <literal>MERGES</literal>, the join operator must appear
in a btree index operator family. This is not enforced when you create
the operator, since of course the referencing operator family couldn't
exist yet. But the operator will not actually be used for merge joins
unless a matching operator family can be found. The
<literal>MERGES</literal> flag thus acts as a hint to the planner that
it's worth looking for a matching operator family.
</para>
<para>
@ -474,13 +451,6 @@ table1.column1 OP table2.column2
be transitive.
</para>
</listitem>
<listitem>
<para>
Bizarre results will ensue at run time if the four comparison
operators you name do not sort the data values compatibly.
</para>
</listitem>
</itemizedlist>
</para>
@ -491,17 +461,5 @@ table1.column1 OP table2.column2
attempt to use the operator for a merge join.
</para>
</note>
<note>
<para>
In <productname>PostgreSQL</productname> versions before 7.3,
the <literal>MERGES</> shorthand was not available: to make a
merge-joinable operator one had to write both <literal>SORT1</> and
<literal>SORT2</> explicitly. Also, the <literal>LTCMP</> and
<literal>GTCMP</>
options did not exist; the names of those operators were hardwired as
<literal>&lt;</> and <literal>&gt;</> respectively.
</para>
</note>
</sect2>
</sect1>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.48 2006/10/04 00:29:48 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.49 2006/12/23 00:43:08 tgl Exp $
*
* NOTES
* These functions are stored in pg_amproc. For each operator class
@ -46,11 +46,11 @@ hashint8(PG_FUNCTION_ARGS)
{
/*
* The idea here is to produce a hash value compatible with the values
* produced by hashint4 and hashint2 for logically equivalent inputs; this
* is necessary if we ever hope to support cross-type hash joins across
* these input types. Since all three types are signed, we can xor the
* high half of the int8 value if the sign is positive, or the complement
* of the high half when the sign is negative.
* produced by hashint4 and hashint2 for logically equal inputs; this is
* necessary to support cross-type hash joins across these input types.
* Since all three types are signed, we can xor the high half of the int8
* value if the sign is positive, or the complement of the high half when
* the sign is negative.
*/
#ifndef INT64_IS_BUSTED
int64 val = PG_GETARG_INT64(0);
@ -76,16 +76,26 @@ Datum
hashfloat4(PG_FUNCTION_ARGS)
{
float4 key = PG_GETARG_FLOAT4(0);
float8 key8;
/*
* On IEEE-float machines, minus zero and zero have different bit patterns
* but should compare as equal. We must ensure that they have the same
* hash value, which is most easily done this way:
* hash value, which is most reliably done this way:
*/
if (key == (float4) 0)
PG_RETURN_UINT32(0);
return hash_any((unsigned char *) &key, sizeof(key));
/*
* To support cross-type hashing of float8 and float4, we want to return
* the same hash value hashfloat8 would produce for an equal float8 value.
* So, widen the value to float8 and hash that. (We must do this rather
* than have hashfloat8 try to narrow its value to float4; that could
* fail on overflow.)
*/
key8 = key;
return hash_any((unsigned char *) &key8, sizeof(key8));
}
Datum
@ -96,7 +106,7 @@ hashfloat8(PG_FUNCTION_ARGS)
/*
* On IEEE-float machines, minus zero and zero have different bit patterns
* but should compare as equal. We must ensure that they have the same
* hash value, which is most easily done this way:
* hash value, which is most reliably done this way:
*/
if (key == (float8) 0)
PG_RETURN_UINT32(0);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.95 2006/10/04 00:29:48 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.96 2006/12/23 00:43:08 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relation OID
@ -608,17 +608,27 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
/* ----------------
* index_getprocid
*
* Some indexed access methods may require support routines that are
* not in the operator class/operator model imposed by pg_am. These
* access methods may store the OIDs of registered procedures they
* need in pg_amproc. These registered procedure OIDs are ordered in
* a way that makes sense to the access method, and used only by the
* access method. The general index code doesn't know anything about
* the routines involved; it just builds an ordered list of them for
* Index access methods typically require support routines that are
* not directly the implementation of any WHERE-clause query operator
* and so cannot be kept in pg_amop. Instead, such routines are kept
* in pg_amproc. These registered procedure OIDs are assigned numbers
* according to a convention established by the access method.
* The general index code doesn't know anything about the routines
* involved; it just builds an ordered list of them for
* each attribute on which an index is defined.
*
* This routine returns the requested procedure OID for a particular
* indexed attribute.
* As of Postgres 8.3, support routines within an operator family
* are further subdivided by the "left type" and "right type" of the
* query operator(s) that they support. The "default" functions for a
* particular indexed attribute are those with both types equal to
* the index opclass' opcintype (note that this is subtly different
* from the indexed attribute's own type: it may be a binary-compatible
* type instead). Only the default functions are stored in relcache
* entries --- access methods can use the syscache to look up non-default
* functions.
*
* This routine returns the requested default procedure OID for a
* particular indexed attribute.
* ----------------
*/
RegProcedure
@ -647,7 +657,8 @@ index_getprocid(Relation irel,
* index_getprocinfo
*
* This routine allows index AMs to keep fmgr lookup info for
* support procs in the relcache.
* support procs in the relcache. As above, only the "default"
* functions for any particular indexed attribute are cached.
*
* Note: the return value points into cached data that will be lost during
* any relcache rebuild! Therefore, either use the callinfo right away,

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.107 2006/10/04 00:29:49 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.108 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -658,11 +658,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
* to an insertion scan key by replacing the sk_func with the
* appropriate btree comparison function.
*
* If scankey operator is of default subtype, we can use the
* cached comparison function; otherwise gotta look it up in the
* catalogs.
* If scankey operator is of the default type for the index, we
* can use the cached comparison function; otherwise gotta look it
* up in the catalogs. Also, we support the convention that
* sk_subtype == 0 means the default type; this is a hack to
* simplify life for ScanKeyInit().
*/
if (cur->sk_subtype == InvalidOid)
if (cur->sk_subtype == rel->rd_opcintype[i] ||
cur->sk_subtype == InvalidOid)
{
FmgrInfo *procinfo;
@ -671,7 +674,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
cur->sk_flags,
cur->sk_attno,
InvalidStrategy,
InvalidOid,
cur->sk_subtype,
procinfo,
cur->sk_argument);
}
@ -679,9 +682,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
{
RegProcedure cmp_proc;
cmp_proc = get_opclass_proc(rel->rd_indclass->values[i],
cur->sk_subtype,
BTORDER_PROC);
cmp_proc = get_opfamily_proc(rel->rd_opfamily[i],
rel->rd_opcintype[i],
cur->sk_subtype,
BTORDER_PROC);
if (!RegProcedureIsValid(cmp_proc))
elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
BTORDER_PROC, rel->rd_opcintype[i], cur->sk_subtype,
cur->sk_attno, RelationGetRelationName(rel));
ScanKeyEntryInitialize(scankeys + i,
cur->sk_flags,
cur->sk_attno,

View File

@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.60 2006/07/31 01:16:36 tgl Exp $
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.61 2006/12/23 00:43:09 tgl Exp $
#
#-------------------------------------------------------------------------
@ -28,8 +28,8 @@ SUBSYS.o: $(OBJS)
POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_depend.h \

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.60 2006/10/04 00:29:50 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.61 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,6 +22,8 @@
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
@ -33,6 +35,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_tablespace.h"
@ -78,19 +81,25 @@ typedef struct
* See also getObjectClass().
*/
static const Oid object_classes[MAX_OCLASS] = {
RelationRelationId, /* OCLASS_CLASS */
ProcedureRelationId, /* OCLASS_PROC */
TypeRelationId, /* OCLASS_TYPE */
CastRelationId, /* OCLASS_CAST */
ConstraintRelationId, /* OCLASS_CONSTRAINT */
ConversionRelationId, /* OCLASS_CONVERSION */
AttrDefaultRelationId, /* OCLASS_DEFAULT */
LanguageRelationId, /* OCLASS_LANGUAGE */
OperatorRelationId, /* OCLASS_OPERATOR */
OperatorClassRelationId, /* OCLASS_OPCLASS */
RewriteRelationId, /* OCLASS_REWRITE */
TriggerRelationId, /* OCLASS_TRIGGER */
NamespaceRelationId /* OCLASS_SCHEMA */
RelationRelationId, /* OCLASS_CLASS */
ProcedureRelationId, /* OCLASS_PROC */
TypeRelationId, /* OCLASS_TYPE */
CastRelationId, /* OCLASS_CAST */
ConstraintRelationId, /* OCLASS_CONSTRAINT */
ConversionRelationId, /* OCLASS_CONVERSION */
AttrDefaultRelationId, /* OCLASS_DEFAULT */
LanguageRelationId, /* OCLASS_LANGUAGE */
OperatorRelationId, /* OCLASS_OPERATOR */
OperatorClassRelationId, /* OCLASS_OPCLASS */
OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
AccessMethodOperatorRelationId, /* OCLASS_AMOP */
AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
RewriteRelationId, /* OCLASS_REWRITE */
TriggerRelationId, /* OCLASS_TRIGGER */
NamespaceRelationId, /* OCLASS_SCHEMA */
AuthIdRelationId, /* OCLASS_ROLE */
DatabaseRelationId, /* OCLASS_DATABASE */
TableSpaceRelationId /* OCLASS_TBLSPACE */
};
@ -122,6 +131,7 @@ static int object_address_comparator(const void *a, const void *b);
static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
ObjectAddresses *addrs);
static void getRelationDescription(StringInfo buffer, Oid relid);
static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
/*
@ -185,7 +195,7 @@ performDeletion(const ObjectAddress *object,
* filled with some objects. Also, the deleted objects are saved in the
* alreadyDeleted list.
*
* XXX performDeletion could be refactored to be a thin wrapper to this
* XXX performDeletion could be refactored to be a thin wrapper around this
* function.
*/
static void
@ -954,6 +964,18 @@ doDeletion(const ObjectAddress *object)
RemoveOpClassById(object->objectId);
break;
case OCLASS_OPFAMILY:
RemoveOpFamilyById(object->objectId);
break;
case OCLASS_AMOP:
RemoveAmOpEntryById(object->objectId);
break;
case OCLASS_AMPROC:
RemoveAmProcEntryById(object->objectId);
break;
case OCLASS_REWRITE:
RemoveRewriteRuleById(object->objectId);
break;
@ -966,6 +988,8 @@ doDeletion(const ObjectAddress *object)
RemoveSchemaById(object->objectId);
break;
/* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
default:
elog(ERROR, "unrecognized object class: %u",
object->classId);
@ -1316,9 +1340,9 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
context->addrs);
}
foreach(l, rcexpr->opclasses)
foreach(l, rcexpr->opfamilies)
{
add_object_address(OCLASS_OPCLASS, lfirst_oid(l), 0,
add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
context->addrs);
}
/* fall through to examine arguments */
@ -1623,6 +1647,18 @@ getObjectClass(const ObjectAddress *object)
Assert(object->objectSubId == 0);
return OCLASS_OPCLASS;
case OperatorFamilyRelationId:
Assert(object->objectSubId == 0);
return OCLASS_OPFAMILY;
case AccessMethodOperatorRelationId:
Assert(object->objectSubId == 0);
return OCLASS_AMOP;
case AccessMethodProcedureRelationId:
Assert(object->objectSubId == 0);
return OCLASS_AMPROC;
case RewriteRelationId:
Assert(object->objectSubId == 0);
return OCLASS_REWRITE;
@ -1856,11 +1892,11 @@ getObjectDescription(const ObjectAddress *object)
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
amTup = SearchSysCache(AMOID,
ObjectIdGetDatum(opcForm->opcamid),
ObjectIdGetDatum(opcForm->opcmethod),
0, 0, 0);
if (!HeapTupleIsValid(amTup))
elog(ERROR, "cache lookup failed for access method %u",
opcForm->opcamid);
opcForm->opcmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup);
/* Qualify the name if not visible in search path */
@ -1879,6 +1915,84 @@ getObjectDescription(const ObjectAddress *object)
break;
}
case OCLASS_OPFAMILY:
getOpFamilyDescription(&buffer, object->objectId);
break;
case OCLASS_AMOP:
{
Relation amopDesc;
ScanKeyData skey[1];
SysScanDesc amscan;
HeapTuple tup;
Form_pg_amop amopForm;
amopDesc = heap_open(AccessMethodOperatorRelationId,
AccessShareLock);
ScanKeyInit(&skey[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(object->objectId));
amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
SnapshotNow, 1, skey);
tup = systable_getnext(amscan);
if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amop entry %u",
object->objectId);
amopForm = (Form_pg_amop) GETSTRUCT(tup);
appendStringInfo(&buffer, _("operator %d %s of "),
amopForm->amopstrategy,
format_operator(amopForm->amopopr));
getOpFamilyDescription(&buffer, amopForm->amopfamily);
systable_endscan(amscan);
heap_close(amopDesc, AccessShareLock);
break;
}
case OCLASS_AMPROC:
{
Relation amprocDesc;
ScanKeyData skey[1];
SysScanDesc amscan;
HeapTuple tup;
Form_pg_amproc amprocForm;
amprocDesc = heap_open(AccessMethodProcedureRelationId,
AccessShareLock);
ScanKeyInit(&skey[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(object->objectId));
amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
SnapshotNow, 1, skey);
tup = systable_getnext(amscan);
if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amproc entry %u",
object->objectId);
amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
appendStringInfo(&buffer, _("function %d %s of "),
amprocForm->amprocnum,
format_procedure(amprocForm->amproc));
getOpFamilyDescription(&buffer, amprocForm->amprocfamily);
systable_endscan(amscan);
heap_close(amprocDesc, AccessShareLock);
break;
}
case OCLASS_REWRITE:
{
Relation ruleDesc;
@ -2068,3 +2182,45 @@ getRelationDescription(StringInfo buffer, Oid relid)
ReleaseSysCache(relTup);
}
/*
* subroutine for getObjectDescription: describe an operator family
*/
static void
getOpFamilyDescription(StringInfo buffer, Oid opfid)
{
HeapTuple opfTup;
Form_pg_opfamily opfForm;
HeapTuple amTup;
Form_pg_am amForm;
char *nspname;
opfTup = SearchSysCache(OPFAMILYOID,
ObjectIdGetDatum(opfid),
0, 0, 0);
if (!HeapTupleIsValid(opfTup))
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
amTup = SearchSysCache(AMOID,
ObjectIdGetDatum(opfForm->opfmethod),
0, 0, 0);
if (!HeapTupleIsValid(amTup))
elog(ERROR, "cache lookup failed for access method %u",
opfForm->opfmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup);
/* Qualify the name if not visible in search path */
if (OpfamilyIsVisible(opfid))
nspname = NULL;
else
nspname = get_namespace_name(opfForm->opfnamespace);
appendStringInfo(buffer, _("operator family %s for access method %s"),
quote_qualified_identifier(nspname,
NameStr(opfForm->opfname)),
NameStr(amForm->amname));
ReleaseSysCache(amTup);
ReleaseSysCache(opfTup);
}

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.88 2006/10/04 00:29:50 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.89 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -27,6 +27,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
@ -1062,7 +1063,7 @@ OpclassIsVisible(Oid opcid)
*/
char *opcname = NameStr(opcform->opcname);
visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid);
visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
}
ReleaseSysCache(opctup);
@ -1070,6 +1071,89 @@ OpclassIsVisible(Oid opcid)
return visible;
}
/*
* OpfamilynameGetOpfid
* Try to resolve an unqualified index opfamily name.
* Returns OID if opfamily found in search path, else InvalidOid.
*
* This is essentially the same as TypenameGetTypid, but we have to have
* an extra argument for the index AM OID.
*/
Oid
OpfamilynameGetOpfid(Oid amid, const char *opfname)
{
Oid opfid;
ListCell *l;
recomputeNamespacePath();
foreach(l, namespaceSearchPath)
{
Oid namespaceId = lfirst_oid(l);
opfid = GetSysCacheOid(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amid),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceId),
0);
if (OidIsValid(opfid))
return opfid;
}
/* Not found in path */
return InvalidOid;
}
/*
* OpfamilyIsVisible
* Determine whether an opfamily (identified by OID) is visible in the
* current search path. Visible means "would be found by searching
* for the unqualified opfamily name".
*/
bool
OpfamilyIsVisible(Oid opfid)
{
HeapTuple opftup;
Form_pg_opfamily opfform;
Oid opfnamespace;
bool visible;
opftup = SearchSysCache(OPFAMILYOID,
ObjectIdGetDatum(opfid),
0, 0, 0);
if (!HeapTupleIsValid(opftup))
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
recomputeNamespacePath();
/*
* Quick check: if it ain't in the path at all, it ain't visible. Items in
* the system namespace are surely in the path and so we needn't even do
* list_member_oid() for them.
*/
opfnamespace = opfform->opfnamespace;
if (opfnamespace != PG_CATALOG_NAMESPACE &&
!list_member_oid(namespaceSearchPath, opfnamespace))
visible = false;
else
{
/*
* If it is in the path, it might still not be visible; it could be
* hidden by another opfamily of the same name earlier in the path. So
* we must do a slow check to see if this opfamily would be found by
* OpfamilynameGetOpfid.
*/
char *opfname = NameStr(opfform->opfname);
visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
}
ReleaseSysCache(opftup);
return visible;
}
/*
* ConversionGetConid
* Try to resolve an unqualified conversion name.

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.98 2006/07/14 14:52:18 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.99 2006/12/23 00:43:09 tgl Exp $
*
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
@ -238,16 +238,13 @@ OperatorShellMake(const char *operatorName,
values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */
values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
values[i++] = BoolGetDatum(false); /* oprcanmerge */
values[i++] = BoolGetDatum(false); /* oprcanhash */
values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */
@ -296,11 +293,8 @@ OperatorShellMake(const char *operatorName,
* negatorName X negator operator
* restrictionName X restriction sel. procedure
* joinName X join sel. procedure
* canMerge merge join can be used with this operator
* canHash hash join can be used with this operator
* leftSortName X left sort operator (for merge join)
* rightSortName X right sort operator (for merge join)
* ltCompareName X L<R compare operator (for merge join)
* gtCompareName X L>R compare operator (for merge join)
*
* This routine gets complicated because it allows the user to
* specify operators that do not exist. For example, if operator
@ -326,6 +320,7 @@ OperatorShellMake(const char *operatorName,
* operatorName
* owner id (simply the user id of the caller)
* operator "kind" either "b" for binary or "l" for left unary
* canMerge boolean
* canHash boolean
* leftTypeObjectId -- type must already be defined
* rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
@ -341,8 +336,6 @@ OperatorShellMake(const char *operatorName,
* (We are creating a self-commutating operator.)
* The link will be fixed later by OperatorUpd.
* negatorObjectId -- same as for commutatorObjectId
* leftSortObjectId -- same as for commutatorObjectId
* rightSortObjectId -- same as for commutatorObjectId
* operatorProcedure -- must access the pg_procedure catalog to get the
* ObjectId of the procedure that actually does the operator
* actions this is required. Do a lookup to find out the
@ -369,11 +362,8 @@ OperatorCreate(const char *operatorName,
List *negatorName,
List *restrictionName,
List *joinName,
bool canHash,
List *leftSortName,
List *rightSortName,
List *ltCompareName,
List *gtCompareName)
bool canMerge,
bool canHash)
{
Relation pg_operator_desc;
HeapTuple tup;
@ -386,10 +376,6 @@ OperatorCreate(const char *operatorName,
Oid operResultType;
Oid commutatorId,
negatorId,
leftSortId,
rightSortId,
ltCompareId,
gtCompareId,
restOid,
joinOid;
bool selfCommutator = false;
@ -424,14 +410,14 @@ OperatorCreate(const char *operatorName,
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only binary operators can have join selectivity")));
if (canMerge)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only binary operators can merge join")));
if (canHash)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only binary operators can hash")));
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only binary operators can merge join")));
}
operatorObjectId = OperatorGet(operatorName,
@ -522,6 +508,7 @@ OperatorCreate(const char *operatorName,
values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */
values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
values[i++] = BoolGetDatum(canMerge); /* oprcanmerge */
values[i++] = BoolGetDatum(canHash); /* oprcanhash */
values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
@ -565,58 +552,6 @@ OperatorCreate(const char *operatorName,
negatorId = InvalidOid;
values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */
if (leftSortName)
{
/* left sort op takes left-side data type */
leftSortId = get_other_operator(leftSortName,
leftTypeId, leftTypeId,
operatorName, operatorNamespace,
leftTypeId, rightTypeId,
false);
}
else
leftSortId = InvalidOid;
values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */
if (rightSortName)
{
/* right sort op takes right-side data type */
rightSortId = get_other_operator(rightSortName,
rightTypeId, rightTypeId,
operatorName, operatorNamespace,
leftTypeId, rightTypeId,
false);
}
else
rightSortId = InvalidOid;
values[i++] = ObjectIdGetDatum(rightSortId); /* oprrsortop */
if (ltCompareName)
{
/* comparator has same arg types */
ltCompareId = get_other_operator(ltCompareName,
leftTypeId, rightTypeId,
operatorName, operatorNamespace,
leftTypeId, rightTypeId,
false);
}
else
ltCompareId = InvalidOid;
values[i++] = ObjectIdGetDatum(ltCompareId); /* oprltcmpop */
if (gtCompareName)
{
/* comparator has same arg types */
gtCompareId = get_other_operator(gtCompareName,
leftTypeId, rightTypeId,
operatorName, operatorNamespace,
leftTypeId, rightTypeId,
false);
}
else
gtCompareId = InvalidOid;
values[i++] = ObjectIdGetDatum(gtCompareId); /* oprgtcmpop */
values[i++] = ObjectIdGetDatum(procOid); /* oprcode */
values[i++] = ObjectIdGetDatum(restOid); /* oprrest */
values[i++] = ObjectIdGetDatum(joinOid); /* oprjoin */
@ -930,12 +865,11 @@ makeOperatorDependencies(HeapTuple tuple)
/*
* NOTE: we do not consider the operator to depend on the associated
* operators oprcom, oprnegate, oprlsortop, oprrsortop, oprltcmpop,
* oprgtcmpop. We would not want to delete this operator if those go
* away, but only reset the link fields; which is not a function that the
* dependency code can presently handle. (Something could perhaps be done
* with objectSubId though.) For now, it's okay to let those links dangle
* if a referenced operator is removed.
* operators oprcom and oprnegate. We would not want to delete this
* operator if those go away, but only reset the link fields; which is not
* a function that the dependency code can presently handle. (Something
* could perhaps be done with objectSubId though.) For now, it's okay to
* let those links dangle if a referenced operator is removed.
*/
/* Dependency on implementation function */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.149 2006/10/04 00:29:51 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.150 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -802,31 +802,37 @@ GetIndexOpClass(List *opclass, Oid attrType,
Oid
GetDefaultOpClass(Oid type_id, Oid am_id)
{
Oid result = InvalidOid;
int nexact = 0;
int ncompatible = 0;
Oid exactOid = InvalidOid;
Oid compatibleOid = InvalidOid;
int ncompatiblepreferred = 0;
Relation rel;
ScanKeyData skey[1];
SysScanDesc scan;
HeapTuple tup;
CATEGORY tcategory;
/* If it's a domain, look at the base type instead */
type_id = getBaseType(type_id);
tcategory = TypeCategory(type_id);
/*
* We scan through all the opclasses available for the access method,
* looking for one that is marked default and matches the target type
* (either exactly or binary-compatibly, but prefer an exact match).
*
* We could find more than one binary-compatible match, in which case we
* require the user to specify which one he wants. If we find more than
* one exact match, then someone put bogus entries in pg_opclass.
* We could find more than one binary-compatible match. If just one is
* for a preferred type, use that one; otherwise we fail, forcing the user
* to specify which one he wants. (The preferred-type special case is a
* kluge for varchar: it's binary-compatible to both text and bpchar, so
* we need a tiebreaker.) If we find more than one exact match, then
* someone put bogus entries in pg_opclass.
*/
rel = heap_open(OperatorClassRelationId, AccessShareLock);
ScanKeyInit(&skey[0],
Anum_pg_opclass_opcamid,
Anum_pg_opclass_opcmethod,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(am_id));
@ -837,17 +843,26 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
if (opclass->opcdefault)
/* ignore altogether if not a default opclass */
if (!opclass->opcdefault)
continue;
if (opclass->opcintype == type_id)
{
if (opclass->opcintype == type_id)
nexact++;
result = HeapTupleGetOid(tup);
}
else if (nexact == 0 &&
IsBinaryCoercible(type_id, opclass->opcintype))
{
if (IsPreferredType(tcategory, opclass->opcintype))
{
nexact++;
exactOid = HeapTupleGetOid(tup);
ncompatiblepreferred++;
result = HeapTupleGetOid(tup);
}
else if (IsBinaryCoercible(type_id, opclass->opcintype))
else if (ncompatiblepreferred == 0)
{
ncompatible++;
compatibleOid = HeapTupleGetOid(tup);
result = HeapTupleGetOid(tup);
}
}
}
@ -856,15 +871,17 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
heap_close(rel, AccessShareLock);
if (nexact == 1)
return exactOid;
if (nexact != 0)
/* raise error if pg_opclass contains inconsistent data */
if (nexact > 1)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("there are multiple default operator classes for data type %s",
format_type_be(type_id))));
if (ncompatible == 1)
return compatibleOid;
if (nexact == 1 ||
ncompatiblepreferred == 1 ||
(ncompatiblepreferred == 0 && ncompatible == 1))
return result;
return InvalidOid;
}

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.33 2006/10/04 00:29:51 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.34 2006/12/23 00:43:09 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -64,8 +64,8 @@ DefineOperator(List *names, List *parameters)
char *oprName;
Oid oprNamespace;
AclResult aclresult;
bool canHash = false; /* operator hashes */
bool canMerge = false; /* operator merges */
bool canHash = false; /* operator hashes */
List *functionName = NIL; /* function for operator */
TypeName *typeName1 = NULL; /* first type name */
TypeName *typeName2 = NULL; /* second type name */
@ -75,10 +75,6 @@ DefineOperator(List *names, List *parameters)
List *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel. procedure */
List *joinName = NIL; /* optional join sel. procedure */
List *leftSortName = NIL; /* optional left sort operator */
List *rightSortName = NIL; /* optional right sort operator */
List *ltCompareName = NIL; /* optional < compare operator */
List *gtCompareName = NIL; /* optional > compare operator */
ListCell *pl;
/* Convert list of names to a name and namespace */
@ -127,14 +123,15 @@ DefineOperator(List *names, List *parameters)
canHash = defGetBoolean(defel);
else if (pg_strcasecmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
else if (pg_strcasecmp(defel->defname, "sort1") == 0)
leftSortName = defGetQualifiedName(defel);
canMerge = true;
else if (pg_strcasecmp(defel->defname, "sort2") == 0)
rightSortName = defGetQualifiedName(defel);
canMerge = true;
else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
ltCompareName = defGetQualifiedName(defel);
canMerge = true;
else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
gtCompareName = defGetQualifiedName(defel);
canMerge = true;
else
ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR),
@ -156,26 +153,6 @@ DefineOperator(List *names, List *parameters)
if (typeName2)
typeId2 = typenameTypeId(NULL, typeName2);
/*
* If any of the mergejoin support operators were given, then canMerge is
* implicit. If canMerge is specified or implicit, fill in default
* operator names for any missing mergejoin support operators.
*/
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
canMerge = true;
if (canMerge)
{
if (!leftSortName)
leftSortName = list_make1(makeString("<"));
if (!rightSortName)
rightSortName = list_make1(makeString("<"));
if (!ltCompareName)
ltCompareName = list_make1(makeString("<"));
if (!gtCompareName)
gtCompareName = list_make1(makeString(">"));
}
/*
* now have OperatorCreate do all the work..
*/
@ -188,11 +165,8 @@ DefineOperator(List *names, List *parameters)
negatorName, /* optional negator operator name */
restrictionName, /* optional restrict. sel. procedure */
joinName, /* optional join sel. procedure name */
canHash, /* operator hashes */
leftSortName, /* optional left sort operator */
rightSortName, /* optional right sort operator */
ltCompareName, /* optional < comparison op */
gtCompareName); /* optional < comparison op */
canMerge, /* operator merges */
canHash); /* operator hashes */
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.206 2006/10/13 21:43:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.207 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -4145,7 +4145,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
* generate a warning if not, since otherwise costly seqscans will be
* incurred to check FK validity.
*/
if (!op_in_opclass(oprid(o), opclasses[i]))
if (!op_in_opfamily(oprid(o), get_opclass_family(opclasses[i])))
ereport(WARNING,
(errmsg("foreign key constraint \"%s\" "
"will require costly sequential scans",

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.200 2006/12/21 16:05:13 petere Exp $
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.201 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -3700,21 +3700,28 @@ ExecInitExpr(Expr *node, PlanState *parent)
outlist = lappend(outlist, estate);
}
rstate->rargs = outlist;
Assert(list_length(rcexpr->opclasses) == nopers);
Assert(list_length(rcexpr->opfamilies) == nopers);
rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
i = 0;
forboth(l, rcexpr->opnos, l2, rcexpr->opclasses)
forboth(l, rcexpr->opnos, l2, rcexpr->opfamilies)
{
Oid opno = lfirst_oid(l);
Oid opclass = lfirst_oid(l2);
Oid opfamily = lfirst_oid(l2);
int strategy;
Oid subtype;
Oid lefttype;
Oid righttype;
bool recheck;
Oid proc;
get_op_opclass_properties(opno, opclass,
&strategy, &subtype, &recheck);
proc = get_opclass_proc(opclass, subtype, BTORDER_PROC);
get_op_opfamily_properties(opno, opfamily,
&strategy,
&lefttype,
&righttype,
&recheck);
proc = get_opfamily_proc(opfamily,
lefttype,
righttype,
BTORDER_PROC);
/*
* If we enforced permissions checks on index support

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.117 2006/10/04 00:29:52 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.118 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -797,9 +797,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
int flags = SK_ROW_MEMBER;
Datum scanvalue;
Oid opno;
Oid opclass;
Oid opfamily;
int op_strategy;
Oid op_subtype;
Oid op_lefttype;
Oid op_righttype;
bool op_recheck;
/*
@ -857,15 +858,21 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
if (index->rd_rel->relam != BTREE_AM_OID ||
varattno < 1 || varattno > index->rd_index->indnatts)
elog(ERROR, "bogus RowCompare index qualification");
opclass = index->rd_indclass->values[varattno - 1];
opfamily = index->rd_opfamily[varattno - 1];
get_op_opclass_properties(opno, opclass,
&op_strategy, &op_subtype, &op_recheck);
get_op_opfamily_properties(opno, opfamily,
&op_strategy,
&op_lefttype,
&op_righttype,
&op_recheck);
if (op_strategy != rc->rctype)
elog(ERROR, "RowCompare index qualification contains wrong operator");
opfuncid = get_opclass_proc(opclass, op_subtype, BTORDER_PROC);
opfuncid = get_opfamily_proc(opfamily,
op_lefttype,
op_righttype,
BTORDER_PROC);
/*
* initialize the subsidiary scan key's fields appropriately
@ -874,7 +881,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
flags,
varattno, /* attribute number */
op_strategy, /* op's strategy */
op_subtype, /* strategy subtype */
op_righttype, /* strategy subtype */
opfuncid, /* reg proc to use */
scanvalue); /* constant */
extra_scan_keys++;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.82 2006/10/04 00:29:52 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.83 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -106,14 +106,14 @@
/*
* Comparison strategies supported by MJCompare
*
* XXX eventually should extend these to support descending-order sorts.
* XXX eventually should extend MJCompare to support descending-order sorts.
* There are some tricky issues however about being sure we are on the same
* page as the underlying sort or index as to which end NULLs sort to.
*/
typedef enum
{
MERGEFUNC_LT, /* raw "<" operator */
MERGEFUNC_CMP /* -1 / 0 / 1 three-way comparator */
MERGEFUNC_CMP, /* -1 / 0 / 1 three-way comparator */
MERGEFUNC_REV_CMP /* same, reversing the sense of the result */
} MergeFunctionKind;
/* Runtime data for each mergejoin clause */
@ -132,20 +132,11 @@ typedef struct MergeJoinClauseData
bool lisnull; /* and their isnull flags */
bool risnull;
/*
* Remember whether mergejoin operator is strict (usually it will be).
* NOTE: if it's not strict, we still assume it cannot return true for one
* null and one non-null input.
*/
bool mergestrict;
/*
* The comparison strategy in use, and the lookup info to let us call the
* needed comparison routines. eqfinfo is the "=" operator itself.
* cmpfinfo is either the btree comparator or the "<" operator.
* btree comparison support function.
*/
MergeFunctionKind cmpstrategy;
FmgrInfo eqfinfo;
FmgrInfo cmpfinfo;
} MergeJoinClauseData;
@ -164,34 +155,51 @@ typedef struct MergeJoinClauseData
* we will need at runtime. Each struct essentially tells us how to compare
* the two expressions from the original clause.
*
* The best, most efficient way to compare two expressions is to use a btree
* comparison support routine, since that requires only one function call
* per comparison. Hence we try to find a btree opclass that matches the
* mergejoinable operator. If we cannot find one, we'll have to call both
* the "=" and (often) the "<" operator for each comparison.
* In addition to the expressions themselves, the planner passes the btree
* opfamily OID and btree strategy number (BTLessStrategyNumber or
* BTGreaterStrategyNumber) that identify the intended merge semantics for
* each merge key. The mergejoinable operator is an equality operator in
* this opfamily, and the two inputs are guaranteed to be ordered in either
* increasing or decreasing (respectively) order according to this opfamily.
* This allows us to obtain the needed comparison functions from the opfamily.
*/
static MergeJoinClause
MJExamineQuals(List *qualList, PlanState *parent)
MJExamineQuals(List *mergeclauses, List *mergefamilies, List *mergestrategies,
PlanState *parent)
{
MergeJoinClause clauses;
int nClauses = list_length(qualList);
int nClauses = list_length(mergeclauses);
int iClause;
ListCell *l;
ListCell *cl;
ListCell *cf;
ListCell *cs;
clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData));
iClause = 0;
foreach(l, qualList)
cf = list_head(mergefamilies);
cs = list_head(mergestrategies);
foreach(cl, mergeclauses)
{
OpExpr *qual = (OpExpr *) lfirst(l);
OpExpr *qual = (OpExpr *) lfirst(cl);
MergeJoinClause clause = &clauses[iClause];
Oid ltop;
Oid gtop;
RegProcedure ltproc;
RegProcedure gtproc;
Oid opfamily;
StrategyNumber opstrategy;
int op_strategy;
Oid op_lefttype;
Oid op_righttype;
bool op_recheck;
RegProcedure cmpproc;
AclResult aclresult;
CatCList *catlist;
int i;
opfamily = lfirst_oid(cf);
cf = lnext(cf);
opstrategy = lfirst_int(cs);
cs = lnext(cs);
/* Later we'll support both ascending and descending sort... */
Assert(opstrategy == BTLessStrategyNumber);
clause->cmpstrategy = MERGEFUNC_CMP;
if (!IsA(qual, OpExpr))
elog(ERROR, "mergejoin clause is not an OpExpr");
@ -202,77 +210,30 @@ MJExamineQuals(List *qualList, PlanState *parent)
clause->lexpr = ExecInitExpr((Expr *) linitial(qual->args), parent);
clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
/*
* Check permission to call the mergejoinable operator. For
* predictability, we check this even if we end up not using it.
*/
aclresult = pg_proc_aclcheck(qual->opfuncid, GetUserId(), ACL_EXECUTE);
/* Extract the operator's declared left/right datatypes */
get_op_opfamily_properties(qual->opno, opfamily,
&op_strategy,
&op_lefttype,
&op_righttype,
&op_recheck);
Assert(op_strategy == BTEqualStrategyNumber);
Assert(!op_recheck);
/* And get the matching support procedure (comparison function) */
cmpproc = get_opfamily_proc(opfamily,
op_lefttype,
op_righttype,
BTORDER_PROC);
Assert(RegProcedureIsValid(cmpproc));
/* Check permission to call cmp function */
aclresult = pg_proc_aclcheck(cmpproc, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(qual->opfuncid));
get_func_name(cmpproc));
/* Set up the fmgr lookup information */
fmgr_info(qual->opfuncid, &(clause->eqfinfo));
/* And remember strictness */
clause->mergestrict = clause->eqfinfo.fn_strict;
/*
* Lookup the comparison operators that go with the mergejoinable
* top-level operator. (This will elog if the operator isn't
* mergejoinable, which would be the planner's mistake.)
*/
op_mergejoin_crossops(qual->opno,
&ltop,
&gtop,
&ltproc,
&gtproc);
clause->cmpstrategy = MERGEFUNC_LT;
/*
* Look for a btree opclass including all three operators. This is
* much like SelectSortFunction except we insist on matching all the
* operators provided, and it can be a cross-type opclass.
*
* XXX for now, insist on forward sort so that NULLs can be counted on
* to be high.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(qual->opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
Oid opcid = aform->amopclaid;
if (aform->amopstrategy != BTEqualStrategyNumber)
continue;
if (!opclass_is_btree(opcid))
continue;
if (get_op_opclass_strategy(ltop, opcid) == BTLessStrategyNumber &&
get_op_opclass_strategy(gtop, opcid) == BTGreaterStrategyNumber)
{
clause->cmpstrategy = MERGEFUNC_CMP;
ltproc = get_opclass_proc(opcid, aform->amopsubtype,
BTORDER_PROC);
Assert(RegProcedureIsValid(ltproc));
break; /* done looking */
}
}
ReleaseSysCacheList(catlist);
/* Check permission to call "<" operator or cmp function */
aclresult = pg_proc_aclcheck(ltproc, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(ltproc));
/* Set up the fmgr lookup information */
fmgr_info(ltproc, &(clause->cmpfinfo));
fmgr_info(cmpproc, &(clause->cmpfinfo));
iClause++;
}
@ -286,7 +247,7 @@ MJExamineQuals(List *qualList, PlanState *parent)
* Compute the values of the mergejoined expressions for the current
* outer tuple. We also detect whether it's impossible for the current
* outer tuple to match anything --- this is true if it yields a NULL
* input for any strict mergejoin operator.
* input, since we assume mergejoin operators are strict.
*
* We evaluate the values in OuterEContext, which can be reset each
* time we move to a new tuple.
@ -311,7 +272,7 @@ MJEvalOuterValues(MergeJoinState *mergestate)
clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
&clause->lisnull, NULL);
if (clause->lisnull && clause->mergestrict)
if (clause->lisnull)
canmatch = false;
}
@ -347,7 +308,7 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
&clause->risnull, NULL);
if (clause->risnull && clause->mergestrict)
if (clause->risnull)
canmatch = false;
}
@ -391,32 +352,11 @@ MJCompare(MergeJoinState *mergestate)
/*
* Deal with null inputs. We treat NULL as sorting after non-NULL.
*
* If both inputs are NULL, and the comparison function isn't strict,
* then we call it and check for a true result (this allows operators
* that behave like IS NOT DISTINCT to be mergejoinable). If the
* function is strict or returns false, we temporarily pretend NULL ==
* NULL and contine checking remaining columns.
*/
if (clause->lisnull)
{
if (clause->risnull)
{
if (!clause->eqfinfo.fn_strict)
{
InitFunctionCallInfoData(fcinfo, &(clause->eqfinfo), 2,
NULL, NULL);
fcinfo.arg[0] = clause->ldatum;
fcinfo.arg[1] = clause->rdatum;
fcinfo.argnull[0] = true;
fcinfo.argnull[1] = true;
fresult = FunctionCallInvoke(&fcinfo);
if (!fcinfo.isnull && DatumGetBool(fresult))
{
/* treat nulls as really equal */
continue;
}
}
nulleqnull = true;
continue;
}
@ -431,38 +371,26 @@ MJCompare(MergeJoinState *mergestate)
break;
}
if (clause->cmpstrategy == MERGEFUNC_LT)
InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
NULL, NULL);
fcinfo.arg[0] = clause->ldatum;
fcinfo.arg[1] = clause->rdatum;
fcinfo.argnull[0] = false;
fcinfo.argnull[1] = false;
fresult = FunctionCallInvoke(&fcinfo);
if (fcinfo.isnull)
{
InitFunctionCallInfoData(fcinfo, &(clause->eqfinfo), 2,
NULL, NULL);
fcinfo.arg[0] = clause->ldatum;
fcinfo.arg[1] = clause->rdatum;
fcinfo.argnull[0] = false;
fcinfo.argnull[1] = false;
fresult = FunctionCallInvoke(&fcinfo);
if (fcinfo.isnull)
{
nulleqnull = true;
continue;
}
else if (DatumGetBool(fresult))
{
/* equal */
continue;
}
InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
NULL, NULL);
fcinfo.arg[0] = clause->ldatum;
fcinfo.arg[1] = clause->rdatum;
fcinfo.argnull[0] = false;
fcinfo.argnull[1] = false;
fresult = FunctionCallInvoke(&fcinfo);
if (fcinfo.isnull)
{
nulleqnull = true;
continue;
}
else if (DatumGetBool(fresult))
nulleqnull = true;
continue;
}
if (DatumGetInt32(fresult) == 0)
{
/* equal */
continue;
}
if (clause->cmpstrategy == MERGEFUNC_CMP)
{
if (DatumGetInt32(fresult) < 0)
{
/* less than */
result = -1;
@ -476,26 +404,9 @@ MJCompare(MergeJoinState *mergestate)
}
}
else
/* must be MERGEFUNC_CMP */
{
InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
NULL, NULL);
fcinfo.arg[0] = clause->ldatum;
fcinfo.arg[1] = clause->rdatum;
fcinfo.argnull[0] = false;
fcinfo.argnull[1] = false;
fresult = FunctionCallInvoke(&fcinfo);
if (fcinfo.isnull)
{
nulleqnull = true;
continue;
}
else if (DatumGetInt32(fresult) == 0)
{
/* equal */
continue;
}
else if (DatumGetInt32(fresult) < 0)
/* reverse the sort order */
if (DatumGetInt32(fresult) > 0)
{
/* less than */
result = -1;
@ -1614,6 +1525,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
*/
mergestate->mj_NumClauses = list_length(node->mergeclauses);
mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
node->mergefamilies,
node->mergestrategies,
(PlanState *) mergestate);
/*

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.355 2006/12/21 16:05:13 petere Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.356 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -449,6 +449,8 @@ _copyMergeJoin(MergeJoin *from)
* copy remainder of node
*/
COPY_NODE_FIELD(mergeclauses);
COPY_NODE_FIELD(mergefamilies);
COPY_NODE_FIELD(mergestrategies);
return newnode;
}
@ -1055,7 +1057,7 @@ _copyRowCompareExpr(RowCompareExpr *from)
COPY_SCALAR_FIELD(rctype);
COPY_NODE_FIELD(opnos);
COPY_NODE_FIELD(opclasses);
COPY_NODE_FIELD(opfamilies);
COPY_NODE_FIELD(largs);
COPY_NODE_FIELD(rargs);
@ -1307,6 +1309,7 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_SCALAR_FIELD(mergejoinoperator);
COPY_SCALAR_FIELD(left_sortop);
COPY_SCALAR_FIELD(right_sortop);
COPY_SCALAR_FIELD(mergeopfamily);
/*
* Do not copy pathkeys, since they'd not be canonical in a copied query
@ -2291,6 +2294,7 @@ _copyCreateOpClassStmt(CreateOpClassStmt *from)
CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
COPY_NODE_FIELD(opclassname);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
COPY_NODE_FIELD(datatype);
COPY_NODE_FIELD(items);

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.289 2006/12/21 16:05:13 petere Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.290 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -428,7 +428,7 @@ _equalRowCompareExpr(RowCompareExpr *a, RowCompareExpr *b)
{
COMPARE_SCALAR_FIELD(rctype);
COMPARE_NODE_FIELD(opnos);
COMPARE_NODE_FIELD(opclasses);
COMPARE_NODE_FIELD(opfamilies);
COMPARE_NODE_FIELD(largs);
COMPARE_NODE_FIELD(rargs);
@ -1163,6 +1163,7 @@ static bool
_equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
{
COMPARE_NODE_FIELD(opclassname);
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
COMPARE_NODE_FIELD(datatype);
COMPARE_NODE_FIELD(items);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.287 2006/12/21 16:05:13 petere Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.288 2006/12/23 00:43:10 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@ -442,6 +442,8 @@ _outMergeJoin(StringInfo str, MergeJoin *node)
_outJoinPlanInfo(str, (Join *) node);
WRITE_NODE_FIELD(mergeclauses);
WRITE_NODE_FIELD(mergefamilies);
WRITE_NODE_FIELD(mergestrategies);
}
static void
@ -866,7 +868,7 @@ _outRowCompareExpr(StringInfo str, RowCompareExpr *node)
WRITE_ENUM_FIELD(rctype, RowCompareType);
WRITE_NODE_FIELD(opnos);
WRITE_NODE_FIELD(opclasses);
WRITE_NODE_FIELD(opfamilies);
WRITE_NODE_FIELD(largs);
WRITE_NODE_FIELD(rargs);
}
@ -1167,6 +1169,8 @@ _outMergePath(StringInfo str, MergePath *node)
_outJoinPathInfo(str, (JoinPath *) node);
WRITE_NODE_FIELD(path_mergeclauses);
WRITE_NODE_FIELD(path_mergefamilies);
WRITE_NODE_FIELD(path_mergestrategies);
WRITE_NODE_FIELD(outersortkeys);
WRITE_NODE_FIELD(innersortkeys);
}
@ -1281,6 +1285,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_OID_FIELD(mergejoinoperator);
WRITE_OID_FIELD(left_sortop);
WRITE_OID_FIELD(right_sortop);
WRITE_OID_FIELD(mergeopfamily);
WRITE_NODE_FIELD(left_pathkey);
WRITE_NODE_FIELD(right_pathkey);
WRITE_OID_FIELD(hashjoinoperator);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.197 2006/12/21 16:05:13 petere Exp $
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.198 2006/12/23 00:43:10 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@ -672,7 +672,7 @@ _readRowCompareExpr(void)
READ_ENUM_FIELD(rctype, RowCompareType);
READ_NODE_FIELD(opnos);
READ_NODE_FIELD(opclasses);
READ_NODE_FIELD(opfamilies);
READ_NODE_FIELD(largs);
READ_NODE_FIELD(rargs);

View File

@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.170 2006/12/15 18:42:26 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.171 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1258,6 +1258,8 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
Path *outer_path = path->jpath.outerjoinpath;
Path *inner_path = path->jpath.innerjoinpath;
List *mergeclauses = path->path_mergeclauses;
List *mergefamilies = path->path_mergefamilies;
List *mergestrategies = path->path_mergestrategies;
List *outersortkeys = path->outersortkeys;
List *innersortkeys = path->innersortkeys;
Cost startup_cost = 0;
@ -1347,13 +1349,16 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
*
* Since this calculation is somewhat expensive, and will be the same for
* all mergejoin paths associated with the merge clause, we cache the
* results in the RestrictInfo node.
* results in the RestrictInfo node. XXX that won't work anymore once
* we support multiple possible orderings!
*/
if (mergeclauses && path->jpath.jointype != JOIN_FULL)
{
firstclause = (RestrictInfo *) linitial(mergeclauses);
if (firstclause->left_mergescansel < 0) /* not computed yet? */
mergejoinscansel(root, (Node *) firstclause->clause,
linitial_oid(mergefamilies),
linitial_int(mergestrategies),
&firstclause->left_mergescansel,
&firstclause->right_mergescansel);

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.212 2006/10/04 00:29:54 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.213 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -19,8 +19,8 @@
#include "access/skey.h"
#include "catalog/pg_am.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
@ -40,10 +40,10 @@
/*
* DoneMatchingIndexKeys() - MACRO
*/
#define DoneMatchingIndexKeys(classes) (classes[0] == InvalidOid)
#define DoneMatchingIndexKeys(families) (families[0] == InvalidOid)
#define IsBooleanOpclass(opclass) \
((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
#define IsBooleanOpfamily(opfamily) \
((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
@ -61,15 +61,15 @@ static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,
static List *pull_indexpath_quals(Path *bitmapqual);
static bool lists_intersect_ptr(List *list1, List *list2);
static bool match_clause_to_indexcol(IndexOptInfo *index,
int indexcol, Oid opclass,
int indexcol, Oid opfamily,
RestrictInfo *rinfo,
Relids outer_relids,
SaOpControl saop_control);
static bool is_indexable_operator(Oid expr_op, Oid opclass,
static bool is_indexable_operator(Oid expr_op, Oid opfamily,
bool indexkey_on_left);
static bool match_rowcompare_to_indexcol(IndexOptInfo *index,
int indexcol,
Oid opclass,
Oid opfamily,
RowCompareExpr *clause,
Relids outer_relids);
static Relids indexable_outerrelids(RelOptInfo *rel);
@ -89,17 +89,17 @@ static bool match_index_to_query_keys(PlannerInfo *root,
List *ignorables);
static bool match_boolean_index_clause(Node *clause, int indexcol,
IndexOptInfo *index);
static bool match_special_index_operator(Expr *clause, Oid opclass,
static bool match_special_index_operator(Expr *clause, Oid opfamily,
bool indexkey_on_left);
static Expr *expand_boolean_index_clause(Node *clause, int indexcol,
IndexOptInfo *index);
static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass);
static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily);
static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo,
IndexOptInfo *index,
int indexcol);
static List *prefix_quals(Node *leftop, Oid opclass,
static List *prefix_quals(Node *leftop, Oid opfamily,
Const *prefix, Pattern_Prefix_Status pstatus);
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass,
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily,
Datum rightop);
static Datum string_to_datum(const char *str, Oid datatype);
static Const *string_to_const(const char *str, Oid datatype);
@ -858,7 +858,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
List *clausegroup_list = NIL;
bool found_outer_clause = false;
int indexcol = 0;
Oid *classes = index->classlist;
Oid *families = index->opfamily;
*found_clause = false; /* default result */
@ -867,7 +867,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
do
{
Oid curClass = classes[0];
Oid curFamily = families[0];
List *clausegroup = NIL;
ListCell *l;
@ -879,7 +879,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
Assert(IsA(rinfo, RestrictInfo));
if (match_clause_to_indexcol(index,
indexcol,
curClass,
curFamily,
rinfo,
outer_relids,
saop_control))
@ -899,7 +899,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
Assert(IsA(rinfo, RestrictInfo));
if (match_clause_to_indexcol(index,
indexcol,
curClass,
curFamily,
rinfo,
outer_relids,
saop_control))
@ -918,9 +918,9 @@ group_clauses_by_indexkey(IndexOptInfo *index,
clausegroup_list = lappend(clausegroup_list, clausegroup);
indexcol++;
classes++;
families++;
} while (!DoneMatchingIndexKeys(classes));
} while (!DoneMatchingIndexKeys(families));
if (!*found_clause && !found_outer_clause)
return NIL; /* no indexable clauses anywhere */
@ -937,7 +937,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
*
* (1) must be in the form (indexkey op const) or (const op indexkey);
* and
* (2) must contain an operator which is in the same class as the index
* (2) must contain an operator which is in the same family as the index
* operator for this column, or is a "special" operator as recognized
* by match_special_index_operator().
*
@ -978,7 +978,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
*
* 'index' is the index of interest.
* 'indexcol' is a column number of 'index' (counting from 0).
* 'opclass' is the corresponding operator class.
* 'opfamily' is the corresponding operator family.
* 'rinfo' is the clause to be tested (as a RestrictInfo node).
* 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used.
*
@ -990,7 +990,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
static bool
match_clause_to_indexcol(IndexOptInfo *index,
int indexcol,
Oid opclass,
Oid opfamily,
RestrictInfo *rinfo,
Relids outer_relids,
SaOpControl saop_control)
@ -1013,7 +1013,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
return false;
/* First check for boolean-index cases. */
if (IsBooleanOpclass(opclass))
if (IsBooleanOpfamily(opfamily))
{
if (match_boolean_index_clause((Node *) clause, indexcol, index))
return true;
@ -1052,7 +1052,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
}
else if (clause && IsA(clause, RowCompareExpr))
{
return match_rowcompare_to_indexcol(index, indexcol, opclass,
return match_rowcompare_to_indexcol(index, indexcol, opfamily,
(RowCompareExpr *) clause,
outer_relids);
}
@ -1067,15 +1067,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(right_relids, outer_relids) &&
!contain_volatile_functions(rightop))
{
if (is_indexable_operator(expr_op, opclass, true))
if (is_indexable_operator(expr_op, opfamily, true))
return true;
/*
* If we didn't find a member of the index's opclass, see whether it
* If we didn't find a member of the index's opfamily, see whether it
* is a "special" indexable operator.
*/
if (plain_op &&
match_special_index_operator(clause, opclass, true))
match_special_index_operator(clause, opfamily, true))
return true;
return false;
}
@ -1085,14 +1085,14 @@ match_clause_to_indexcol(IndexOptInfo *index,
bms_is_subset(left_relids, outer_relids) &&
!contain_volatile_functions(leftop))
{
if (is_indexable_operator(expr_op, opclass, false))
if (is_indexable_operator(expr_op, opfamily, false))
return true;
/*
* If we didn't find a member of the index's opclass, see whether it
* If we didn't find a member of the index's opfamily, see whether it
* is a "special" indexable operator.
*/
if (match_special_index_operator(clause, opclass, false))
if (match_special_index_operator(clause, opfamily, false))
return true;
return false;
}
@ -1102,14 +1102,14 @@ match_clause_to_indexcol(IndexOptInfo *index,
/*
* is_indexable_operator
* Does the operator match the specified index opclass?
* Does the operator match the specified index opfamily?
*
* If the indexkey is on the right, what we actually want to know
* is whether the operator has a commutator operator that matches
* the opclass.
* the opfamily.
*/
static bool
is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
{
/* Get the commuted operator if necessary */
if (!indexkey_on_left)
@ -1119,8 +1119,8 @@ is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
return false;
}
/* OK if the (commuted) operator is a member of the index's opclass */
return op_in_opclass(expr_op, opclass);
/* OK if the (commuted) operator is a member of the index's opfamily */
return op_in_opfamily(expr_op, opfamily);
}
/*
@ -1131,7 +1131,7 @@ is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
static bool
match_rowcompare_to_indexcol(IndexOptInfo *index,
int indexcol,
Oid opclass,
Oid opfamily,
RowCompareExpr *clause,
Relids outer_relids)
{
@ -1144,13 +1144,14 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
return false;
/*
* We could do the matching on the basis of insisting that the opclass
* shown in the RowCompareExpr be the same as the index column's opclass,
* but that does not work well for cross-type comparisons (the opclass
* could be for the other datatype). Also it would fail to handle indexes
* using reverse-sort opclasses. Instead, match if the operator listed in
* the RowCompareExpr is the < <= > or >= member of the index opclass
* (after commutation, if the indexkey is on the right).
* We could do the matching on the basis of insisting that the opfamily
* shown in the RowCompareExpr be the same as the index column's opfamily,
* but that could fail in the presence of reverse-sort opfamilies: it'd
* be a matter of chance whether RowCompareExpr had picked the forward
* or reverse-sort family. So look only at the operator, and match
* if it is a member of the index's opfamily (after commutation, if the
* indexkey is on the right). We'll worry later about whether any
* additional operators are matchable to the index.
*/
leftop = (Node *) linitial(clause->largs);
rightop = (Node *) linitial(clause->rargs);
@ -1177,8 +1178,8 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
else
return false;
/* We're good if the operator is the right type of opclass member */
switch (get_op_opclass_strategy(expr_op, opclass))
/* We're good if the operator is the right type of opfamily member */
switch (get_op_opfamily_strategy(expr_op, opfamily))
{
case BTLessStrategyNumber:
case BTLessEqualStrategyNumber:
@ -1316,23 +1317,23 @@ matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
int indexcol = 0;
Oid *classes = index->classlist;
Oid *families = index->opfamily;
do
{
Oid curClass = classes[0];
Oid curFamily = families[0];
if (match_clause_to_indexcol(index,
indexcol,
curClass,
curFamily,
rinfo,
outer_relids,
SAOP_ALLOW))
return true;
indexcol++;
classes++;
} while (!DoneMatchingIndexKeys(classes));
families++;
} while (!DoneMatchingIndexKeys(families));
}
return false;
@ -1601,11 +1602,11 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
* Note: it would be possible to similarly ignore useless ORDER BY items;
* that is, an index on just y could be considered to match the ordering of
* ... WHERE x = 42 ORDER BY x, y;
* But proving that this is safe would require finding a btree opclass
* But proving that this is safe would require finding a btree opfamily
* containing both the = operator and the < or > operator in the ORDER BY
* item. That's significantly more expensive than what we do here, since
* we'd have to look at restriction clauses unrelated to the current index
* and search for opclasses without any hint from the index. The practical
* and search for opfamilies without any hint from the index. The practical
* use-cases seem to be mostly covered by ignoring index columns, so that's
* all we do for now.
*
@ -1627,7 +1628,7 @@ match_variant_ordering(PlannerInfo *root,
/*
* Forget the whole thing if not a btree index; our check for ignorable
* columns assumes we are dealing with btree opclasses. (It'd be possible
* columns assumes we are dealing with btree opfamilies. (It'd be possible
* to factor out just the try for backwards indexscan, but considering
* that we presently have no orderable indexes except btrees anyway, it's
* hardly worth contorting this code for that case.)
@ -1685,7 +1686,7 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
foreach(l, restrictclauses)
{
List *sublist = (List *) lfirst(l);
Oid opclass = index->classlist[indexcol];
Oid opfamily = index->opfamily[indexcol];
ListCell *l2;
foreach(l2, sublist)
@ -1698,7 +1699,7 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
bool ispc;
/* First check for boolean-index cases. */
if (IsBooleanOpclass(opclass))
if (IsBooleanOpfamily(opfamily))
{
if (match_boolean_index_clause((Node *) clause, indexcol,
index))
@ -1729,18 +1730,18 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
{
Assert(match_index_to_operand(lsecond(clause->args), indexcol,
index));
/* Must flip operator to get the opclass member */
/* Must flip operator to get the opfamily member */
clause_op = get_commutator(clause_op);
varonleft = false;
}
if (!OidIsValid(clause_op))
continue; /* ignore non match, per next comment */
op_strategy = get_op_opclass_strategy(clause_op, opclass);
op_strategy = get_op_opfamily_strategy(clause_op, opfamily);
/*
* You might expect to see Assert(op_strategy != 0) here, but you
* won't: the clause might contain a special indexable operator
* rather than an ordinary opclass member. Currently none of the
* rather than an ordinary opfamily member. Currently none of the
* special operators are very likely to expand to an equality
* operator; we do not bother to check, but just assume no match.
*/
@ -1968,7 +1969,7 @@ match_index_to_operand(Node *operand,
*
* match_special_index_operator() is just an auxiliary function for
* match_clause_to_indexcol(); after the latter fails to recognize a
* restriction opclause's operator as a member of an index's opclass,
* restriction opclause's operator as a member of an index's opfamily,
* it asks match_special_index_operator() whether the clause should be
* considered an indexqual anyway.
*
@ -1978,7 +1979,7 @@ match_index_to_operand(Node *operand,
* expand_indexqual_conditions() converts a list of lists of RestrictInfo
* nodes (with implicit AND semantics across list elements) into
* a list of clauses that the executor can actually handle. For operators
* that are members of the index's opclass this transformation is a no-op,
* that are members of the index's opfamily this transformation is a no-op,
* but clauses recognized by match_special_index_operator() or
* match_boolean_index_clause() must be converted into one or more "regular"
* indexqual conditions.
@ -1989,8 +1990,8 @@ match_index_to_operand(Node *operand,
* match_boolean_index_clause
* Recognize restriction clauses that can be matched to a boolean index.
*
* This should be called only when IsBooleanOpclass() recognizes the
* index's operator class. We check to see if the clause matches the
* This should be called only when IsBooleanOpfamily() recognizes the
* index's operator family. We check to see if the clause matches the
* index's key.
*/
static bool
@ -2034,11 +2035,11 @@ match_boolean_index_clause(Node *clause,
*
* The given clause is already known to be a binary opclause having
* the form (indexkey OP pseudoconst) or (pseudoconst OP indexkey),
* but the OP proved not to be one of the index's opclass operators.
* but the OP proved not to be one of the index's opfamily operators.
* Return 'true' if we can do something with it anyway.
*/
static bool
match_special_index_operator(Expr *clause, Oid opclass,
match_special_index_operator(Expr *clause, Oid opfamily,
bool indexkey_on_left)
{
bool isIndexable = false;
@ -2122,12 +2123,12 @@ match_special_index_operator(Expr *clause, Oid opclass,
return false;
/*
* Must also check that index's opclass supports the operators we will
* Must also check that index's opfamily supports the operators we will
* want to apply. (A hash index, for example, will not support ">=".)
* Currently, only btree supports the operators we need.
*
* We insist on the opclass being the specific one we expect, else we'd do
* the wrong thing if someone were to make a reverse-sort opclass with the
* We insist on the opfamily being the specific one we expect, else we'd do
* the wrong thing if someone were to make a reverse-sort opfamily with the
* same operators.
*/
switch (expr_op)
@ -2136,12 +2137,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
case OID_TEXT_ICLIKE_OP:
case OID_TEXT_REGEXEQ_OP:
case OID_TEXT_ICREGEXEQ_OP:
/* text operators will be used for varchar inputs, too */
isIndexable =
(opclass == TEXT_PATTERN_BTREE_OPS_OID) ||
(opclass == TEXT_BTREE_OPS_OID && lc_collate_is_c()) ||
(opclass == VARCHAR_PATTERN_BTREE_OPS_OID) ||
(opclass == VARCHAR_BTREE_OPS_OID && lc_collate_is_c());
(opfamily == TEXT_PATTERN_BTREE_FAM_OID) ||
(opfamily == TEXT_BTREE_FAM_OID && lc_collate_is_c());
break;
case OID_BPCHAR_LIKE_OP:
@ -2149,8 +2147,8 @@ match_special_index_operator(Expr *clause, Oid opclass,
case OID_BPCHAR_REGEXEQ_OP:
case OID_BPCHAR_ICREGEXEQ_OP:
isIndexable =
(opclass == BPCHAR_PATTERN_BTREE_OPS_OID) ||
(opclass == BPCHAR_BTREE_OPS_OID && lc_collate_is_c());
(opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) ||
(opfamily == BPCHAR_BTREE_FAM_OID && lc_collate_is_c());
break;
case OID_NAME_LIKE_OP:
@ -2158,18 +2156,17 @@ match_special_index_operator(Expr *clause, Oid opclass,
case OID_NAME_REGEXEQ_OP:
case OID_NAME_ICREGEXEQ_OP:
isIndexable =
(opclass == NAME_PATTERN_BTREE_OPS_OID) ||
(opclass == NAME_BTREE_OPS_OID && lc_collate_is_c());
(opfamily == NAME_PATTERN_BTREE_FAM_OID) ||
(opfamily == NAME_BTREE_FAM_OID && lc_collate_is_c());
break;
case OID_BYTEA_LIKE_OP:
isIndexable = (opclass == BYTEA_BTREE_OPS_OID);
isIndexable = (opfamily == BYTEA_BTREE_FAM_OID);
break;
case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP:
isIndexable = (opclass == INET_BTREE_OPS_OID ||
opclass == CIDR_BTREE_OPS_OID);
isIndexable = (opfamily == NETWORK_BTREE_FAM_OID);
break;
}
@ -2180,7 +2177,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
* expand_indexqual_conditions
* Given a list of sublists of RestrictInfo nodes, produce a flat list
* of index qual clauses. Standard qual clauses (those in the index's
* opclass) are passed through unchanged. Boolean clauses and "special"
* opfamily) are passed through unchanged. Boolean clauses and "special"
* index operators are expanded into clauses that the indexscan machinery
* will know what to do with. RowCompare clauses are simplified if
* necessary to create a clause that is fully checkable by the index.
@ -2196,7 +2193,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
List *resultquals = NIL;
ListCell *clausegroup_item;
int indexcol = 0;
Oid *classes = index->classlist;
Oid *families = index->opfamily;
if (clausegroups == NIL)
return NIL;
@ -2204,7 +2201,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
clausegroup_item = list_head(clausegroups);
do
{
Oid curClass = classes[0];
Oid curFamily = families[0];
ListCell *l;
foreach(l, (List *) lfirst(clausegroup_item))
@ -2213,7 +2210,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
Expr *clause = rinfo->clause;
/* First check for boolean cases */
if (IsBooleanOpclass(curClass))
if (IsBooleanOpfamily(curFamily))
{
Expr *boolqual;
@ -2240,7 +2237,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{
resultquals = list_concat(resultquals,
expand_indexqual_opclause(rinfo,
curClass));
curFamily));
}
else if (IsA(clause, ScalarArrayOpExpr))
{
@ -2262,8 +2259,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
clausegroup_item = lnext(clausegroup_item);
indexcol++;
classes++;
} while (clausegroup_item != NULL && !DoneMatchingIndexKeys(classes));
families++;
} while (clausegroup_item != NULL && !DoneMatchingIndexKeys(families));
Assert(clausegroup_item == NULL); /* else more groups than indexkeys */
@ -2337,7 +2334,7 @@ expand_boolean_index_clause(Node *clause,
* The input is a single RestrictInfo, the output a list of RestrictInfos
*/
static List *
expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
{
Expr *clause = rinfo->clause;
@ -2354,7 +2351,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
switch (expr_op)
{
/*
* LIKE and regex operators are not members of any index opclass,
* LIKE and regex operators are not members of any index opfamily,
* so if we find one in an indexqual list we can assume that it
* was accepted by match_special_index_operator().
*/
@ -2364,7 +2361,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
case OID_BYTEA_LIKE_OP:
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
&prefix, &rest);
result = prefix_quals(leftop, opclass, prefix, pstatus);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
case OID_TEXT_ICLIKE_OP:
@ -2373,7 +2370,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
&prefix, &rest);
result = prefix_quals(leftop, opclass, prefix, pstatus);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
case OID_TEXT_REGEXEQ_OP:
@ -2382,7 +2379,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
&prefix, &rest);
result = prefix_quals(leftop, opclass, prefix, pstatus);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
case OID_TEXT_ICREGEXEQ_OP:
@ -2391,12 +2388,12 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
/* the right-hand const is type text for all of these */
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
&prefix, &rest);
result = prefix_quals(leftop, opclass, prefix, pstatus);
result = prefix_quals(leftop, opfamily, prefix, pstatus);
break;
case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP:
result = network_prefix_quals(leftop, expr_op, opclass,
result = network_prefix_quals(leftop, expr_op, opfamily,
patt->constvalue);
break;
@ -2416,7 +2413,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
* the specified column of the index. We can use additional columns of the
* row comparison as index qualifications, so long as they match the index
* in the "same direction", ie, the indexkeys are all on the same side of the
* clause and the operators are all the same-type members of the opclasses.
* clause and the operators are all the same-type members of the opfamilies.
* If all the columns of the RowCompareExpr match in this way, we just use it
* as-is. Otherwise, we build a shortened RowCompareExpr (if more than one
* column matches) or a simple OpExpr (if the first-column match is all
@ -2433,12 +2430,14 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
bool var_on_left;
int op_strategy;
Oid op_subtype;
Oid op_lefttype;
Oid op_righttype;
bool op_recheck;
int matching_cols;
Oid expr_op;
List *opclasses;
List *subtypes;
List *opfamilies;
List *lefttypes;
List *righttypes;
List *new_ops;
ListCell *largs_cell;
ListCell *rargs_cell;
@ -2453,11 +2452,15 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
expr_op = linitial_oid(clause->opnos);
if (!var_on_left)
expr_op = get_commutator(expr_op);
get_op_opclass_properties(expr_op, index->classlist[indexcol],
&op_strategy, &op_subtype, &op_recheck);
/* Build lists of the opclasses and operator subtypes in case needed */
opclasses = list_make1_oid(index->classlist[indexcol]);
subtypes = list_make1_oid(op_subtype);
get_op_opfamily_properties(expr_op, index->opfamily[indexcol],
&op_strategy,
&op_lefttype,
&op_righttype,
&op_recheck);
/* Build lists of the opfamilies and operator datatypes in case needed */
opfamilies = list_make1_oid(index->opfamily[indexcol]);
lefttypes = list_make1_oid(op_lefttype);
righttypes = list_make1_oid(op_righttype);
/*
* See how many of the remaining columns match some index column in the
@ -2513,15 +2516,19 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
break; /* no match found */
/* Now, do we have the right operator for this column? */
if (get_op_opclass_strategy(expr_op, index->classlist[i])
if (get_op_opfamily_strategy(expr_op, index->opfamily[i])
!= op_strategy)
break;
/* Add opclass and subtype to lists */
get_op_opclass_properties(expr_op, index->classlist[i],
&op_strategy, &op_subtype, &op_recheck);
opclasses = lappend_oid(opclasses, index->classlist[i]);
subtypes = lappend_oid(subtypes, op_subtype);
/* Add opfamily and datatypes to lists */
get_op_opfamily_properties(expr_op, index->opfamily[i],
&op_strategy,
&op_lefttype,
&op_righttype,
&op_recheck);
opfamilies = lappend_oid(opfamilies, index->opfamily[i]);
lefttypes = lappend_oid(lefttypes, op_lefttype);
righttypes = lappend_oid(righttypes, op_righttype);
/* This column matches, keep scanning */
matching_cols++;
@ -2547,8 +2554,9 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
}
else
{
ListCell *opclasses_cell;
ListCell *subtypes_cell;
ListCell *opfamilies_cell;
ListCell *lefttypes_cell;
ListCell *righttypes_cell;
if (op_strategy == BTLessStrategyNumber)
op_strategy = BTLessEqualStrategyNumber;
@ -2557,23 +2565,30 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
else
elog(ERROR, "unexpected strategy number %d", op_strategy);
new_ops = NIL;
forboth(opclasses_cell, opclasses, subtypes_cell, subtypes)
lefttypes_cell = list_head(lefttypes);
righttypes_cell = list_head(righttypes);
foreach(opfamilies_cell, opfamilies)
{
expr_op = get_opclass_member(lfirst_oid(opclasses_cell),
lfirst_oid(subtypes_cell),
op_strategy);
Oid opfam = lfirst_oid(opfamilies_cell);
Oid lefttype = lfirst_oid(lefttypes_cell);
Oid righttype = lfirst_oid(righttypes_cell);
expr_op = get_opfamily_member(opfam, lefttype, righttype,
op_strategy);
if (!OidIsValid(expr_op)) /* should not happen */
elog(ERROR, "could not find member %d of opclass %u",
op_strategy, lfirst_oid(opclasses_cell));
elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
op_strategy, lefttype, righttype, opfam);
if (!var_on_left)
{
expr_op = get_commutator(expr_op);
if (!OidIsValid(expr_op)) /* should not happen */
elog(ERROR, "could not find commutator of member %d of opclass %u",
op_strategy, lfirst_oid(opclasses_cell));
elog(ERROR, "could not find commutator of member %d(%u,%u) of opfamily %u",
op_strategy, lefttype, righttype, opfam);
}
new_ops = lappend_oid(new_ops, expr_op);
}
lefttypes_cell = lnext(lefttypes_cell);
righttypes_cell = lnext(righttypes_cell);
}
/* If we have more than one matching col, create a subset rowcompare */
@ -2587,8 +2602,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
rc->rctype = (op_strategy == BTLessEqualStrategyNumber) ?
ROWCOMPARE_GE : ROWCOMPARE_LE;
rc->opnos = new_ops;
rc->opclasses = list_truncate(list_copy(clause->opclasses),
matching_cols);
rc->opfamilies = list_truncate(list_copy(clause->opfamilies),
matching_cols);
rc->largs = list_truncate((List *) copyObject(clause->largs),
matching_cols);
rc->rargs = list_truncate((List *) copyObject(clause->rargs),
@ -2608,12 +2623,12 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
/*
* Given a fixed prefix that all the "leftop" values must have,
* generate suitable indexqual condition(s). opclass is the index
* operator class; we use it to deduce the appropriate comparison
* generate suitable indexqual condition(s). opfamily is the index
* operator family; we use it to deduce the appropriate comparison
* operators and operand datatypes.
*/
static List *
prefix_quals(Node *leftop, Oid opclass,
prefix_quals(Node *leftop, Oid opfamily,
Const *prefix_const, Pattern_Prefix_Status pstatus)
{
List *result;
@ -2624,35 +2639,30 @@ prefix_quals(Node *leftop, Oid opclass,
Assert(pstatus != Pattern_Prefix_None);
switch (opclass)
switch (opfamily)
{
case TEXT_BTREE_OPS_OID:
case TEXT_PATTERN_BTREE_OPS_OID:
case TEXT_BTREE_FAM_OID:
case TEXT_PATTERN_BTREE_FAM_OID:
datatype = TEXTOID;
break;
case VARCHAR_BTREE_OPS_OID:
case VARCHAR_PATTERN_BTREE_OPS_OID:
datatype = VARCHAROID;
break;
case BPCHAR_BTREE_OPS_OID:
case BPCHAR_PATTERN_BTREE_OPS_OID:
case BPCHAR_BTREE_FAM_OID:
case BPCHAR_PATTERN_BTREE_FAM_OID:
datatype = BPCHAROID;
break;
case NAME_BTREE_OPS_OID:
case NAME_PATTERN_BTREE_OPS_OID:
case NAME_BTREE_FAM_OID:
case NAME_PATTERN_BTREE_FAM_OID:
datatype = NAMEOID;
break;
case BYTEA_BTREE_OPS_OID:
case BYTEA_BTREE_FAM_OID:
datatype = BYTEAOID;
break;
default:
/* shouldn't get here */
elog(ERROR, "unexpected opclass: %u", opclass);
elog(ERROR, "unexpected opfamily: %u", opfamily);
return NIL;
}
@ -2688,10 +2698,10 @@ prefix_quals(Node *leftop, Oid opclass,
*/
if (pstatus == Pattern_Prefix_Exact)
{
oproid = get_opclass_member(opclass, InvalidOid,
BTEqualStrategyNumber);
oproid = get_opfamily_member(opfamily, datatype, datatype,
BTEqualStrategyNumber);
if (oproid == InvalidOid)
elog(ERROR, "no = operator for opclass %u", opclass);
elog(ERROR, "no = operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const);
result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
@ -2703,10 +2713,10 @@ prefix_quals(Node *leftop, Oid opclass,
*
* We can always say "x >= prefix".
*/
oproid = get_opclass_member(opclass, InvalidOid,
BTGreaterEqualStrategyNumber);
oproid = get_opfamily_member(opfamily, datatype, datatype,
BTGreaterEqualStrategyNumber);
if (oproid == InvalidOid)
elog(ERROR, "no >= operator for opclass %u", opclass);
elog(ERROR, "no >= operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const);
result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
@ -2719,10 +2729,10 @@ prefix_quals(Node *leftop, Oid opclass,
greaterstr = make_greater_string(prefix_const);
if (greaterstr)
{
oproid = get_opclass_member(opclass, InvalidOid,
BTLessStrategyNumber);
oproid = get_opfamily_member(opfamily, datatype, datatype,
BTLessStrategyNumber);
if (oproid == InvalidOid)
elog(ERROR, "no < operator for opclass %u", opclass);
elog(ERROR, "no < operator for opfamily %u", opfamily);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) greaterstr);
result = lappend(result,
@ -2733,12 +2743,12 @@ prefix_quals(Node *leftop, Oid opclass,
}
/*
* Given a leftop and a rightop, and a inet-class sup/sub operator,
* Given a leftop and a rightop, and a inet-family sup/sub operator,
* generate suitable indexqual condition(s). expr_op is the original
* operator, and opclass is the index opclass.
* operator, and opfamily is the index opfamily.
*/
static List *
network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
{
bool is_eq;
Oid datatype;
@ -2770,17 +2780,17 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
*/
if (is_eq)
{
opr1oid = get_opclass_member(opclass, InvalidOid,
BTGreaterEqualStrategyNumber);
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
BTGreaterEqualStrategyNumber);
if (opr1oid == InvalidOid)
elog(ERROR, "no >= operator for opclass %u", opclass);
elog(ERROR, "no >= operator for opfamily %u", opfamily);
}
else
{
opr1oid = get_opclass_member(opclass, InvalidOid,
BTGreaterStrategyNumber);
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
BTGreaterStrategyNumber);
if (opr1oid == InvalidOid)
elog(ERROR, "no > operator for opclass %u", opclass);
elog(ERROR, "no > operator for opfamily %u", opfamily);
}
opr1right = network_scan_first(rightop);
@ -2793,10 +2803,10 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
/* create clause "key <= network_scan_last( rightop )" */
opr2oid = get_opclass_member(opclass, InvalidOid,
BTLessEqualStrategyNumber);
opr2oid = get_opfamily_member(opfamily, datatype, datatype,
BTLessEqualStrategyNumber);
if (opr2oid == InvalidOid)
elog(ERROR, "no <= operator for opclass %u", opclass);
elog(ERROR, "no <= operator for opfamily %u", opfamily);
opr2right = network_scan_last(rightop);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.107 2006/10/04 00:29:54 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.108 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,7 @@
#include <math.h>
#include "access/skey.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
@ -39,6 +40,8 @@ static List *select_mergejoin_clauses(RelOptInfo *joinrel,
RelOptInfo *innerrel,
List *restrictlist,
JoinType jointype);
static void build_mergejoin_strat_lists(List *mergeclauses,
List **mergefamilies, List **mergestrategies);
/*
@ -225,6 +228,8 @@ sort_inner_and_outer(PlannerInfo *root,
List *front_pathkey = (List *) lfirst(l);
List *cur_pathkeys;
List *cur_mergeclauses;
List *mergefamilies;
List *mergestrategies;
List *outerkeys;
List *innerkeys;
List *merge_pathkeys;
@ -269,6 +274,10 @@ sort_inner_and_outer(PlannerInfo *root,
merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
outerkeys);
/* Build opfamily info for execution */
build_mergejoin_strat_lists(cur_mergeclauses,
&mergefamilies, &mergestrategies);
/*
* And now we can make the path.
*/
@ -281,6 +290,8 @@ sort_inner_and_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
cur_mergeclauses,
mergefamilies,
mergestrategies,
outerkeys,
innerkeys));
}
@ -410,6 +421,8 @@ match_unsorted_outer(PlannerInfo *root,
Path *outerpath = (Path *) lfirst(l);
List *merge_pathkeys;
List *mergeclauses;
List *mergefamilies;
List *mergestrategies;
List *innersortkeys;
List *trialsortkeys;
Path *cheapest_startup_inner;
@ -516,6 +529,10 @@ match_unsorted_outer(PlannerInfo *root,
mergeclauses,
innerrel);
/* Build opfamily info for execution */
build_mergejoin_strat_lists(mergeclauses,
&mergefamilies, &mergestrategies);
/*
* Generate a mergejoin on the basis of sorting the cheapest inner.
* Since a sort will be needed, only cheapest total cost matters. (But
@ -531,6 +548,8 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
mergeclauses,
mergefamilies,
mergestrategies,
NIL,
innersortkeys));
@ -589,6 +608,11 @@ match_unsorted_outer(PlannerInfo *root,
}
else
newclauses = mergeclauses;
/* Build opfamily info for execution */
build_mergejoin_strat_lists(newclauses,
&mergefamilies, &mergestrategies);
add_path(joinrel, (Path *)
create_mergejoin_path(root,
joinrel,
@ -598,6 +622,8 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
newclauses,
mergefamilies,
mergestrategies,
NIL,
NIL));
cheapest_total_inner = innerpath;
@ -633,6 +659,11 @@ match_unsorted_outer(PlannerInfo *root,
else
newclauses = mergeclauses;
}
/* Build opfamily info for execution */
build_mergejoin_strat_lists(newclauses,
&mergefamilies, &mergestrategies);
add_path(joinrel, (Path *)
create_mergejoin_path(root,
joinrel,
@ -642,6 +673,8 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist,
merge_pathkeys,
newclauses,
mergefamilies,
mergestrategies,
NIL,
NIL));
}
@ -946,3 +979,35 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
return result_list;
}
/*
* Temporary hack to build opfamily and strategy lists needed for mergejoin
* by the executor. We need to rethink the planner's handling of merge
* planning so that it can deal with multiple possible merge orders, but
* that's not done yet.
*/
static void
build_mergejoin_strat_lists(List *mergeclauses,
List **mergefamilies, List **mergestrategies)
{
ListCell *l;
*mergefamilies = NIL;
*mergestrategies = NIL;
foreach(l, mergeclauses)
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
/*
* We do not need to worry about whether the mergeclause will be
* commuted at runtime --- it's the same opfamily either way.
*/
*mergefamilies = lappend_oid(*mergefamilies, restrictinfo->mergeopfamily);
/*
* For the moment, strategy must always be LessThan --- see
* hack version of get_op_mergejoin_info
*/
*mergestrategies = lappend_int(*mergestrategies, BTLessStrategyNumber);
}
}

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.217 2006/10/04 00:29:54 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.218 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -73,7 +73,7 @@ static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
List **indexstrategy,
List **indexsubtype);
static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
Oid *opclass);
Oid *opfamily);
static List *get_switched_clauses(List *clauses, Relids outerrelids);
static List *order_qual_clauses(PlannerInfo *root, List *clauses);
static void copy_path_costsize(Plan *dest, Path *src);
@ -113,7 +113,7 @@ static HashJoin *make_hashjoin(List *tlist,
static Hash *make_hash(Plan *lefttree);
static MergeJoin *make_mergejoin(List *tlist,
List *joinclauses, List *otherclauses,
List *mergeclauses,
List *mergeclauses, List *mergefamilies, List *mergestrategies,
Plan *lefttree, Plan *righttree,
JoinType jointype);
static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
@ -1540,6 +1540,8 @@ create_mergejoin_plan(PlannerInfo *root,
joinclauses,
otherclauses,
mergeclauses,
best_path->path_mergefamilies,
best_path->path_mergestrategies,
outer_plan,
inner_plan,
best_path->jpath.jointype);
@ -1676,9 +1678,10 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
Expr *clause;
Oid clause_op;
Oid opclass;
Oid opfamily;
int stratno;
Oid stratsubtype;
Oid stratlefttype;
Oid stratrighttype;
bool recheck;
Assert(IsA(rinfo, RestrictInfo));
@ -1709,11 +1712,11 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
/*
* Now, determine which index attribute this is, change the
* indexkey operand as needed, and get the index opclass.
* indexkey operand as needed, and get the index opfamily.
*/
linitial(op->args) = fix_indexqual_operand(linitial(op->args),
index,
&opclass);
&opfamily);
clause_op = op->opno;
}
else if (IsA(clause, RowCompareExpr))
@ -1734,20 +1737,20 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
* For each column in the row comparison, determine which index
* attribute this is and change the indexkey operand as needed.
*
* Save the index opclass for only the first column. We will
* return the operator and opclass info for just the first column
* Save the index opfamily for only the first column. We will
* return the operator and opfamily info for just the first column
* of the row comparison; the executor will have to look up the
* rest if it needs them.
*/
foreach(lc, rc->largs)
{
Oid tmp_opclass;
Oid tmp_opfamily;
lfirst(lc) = fix_indexqual_operand(lfirst(lc),
index,
&tmp_opclass);
&tmp_opfamily);
if (lc == list_head(rc->largs))
opclass = tmp_opclass;
opfamily = tmp_opfamily;
}
clause_op = linitial_oid(rc->opnos);
}
@ -1759,11 +1762,11 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
/*
* Now, determine which index attribute this is, change the
* indexkey operand as needed, and get the index opclass.
* indexkey operand as needed, and get the index opfamily.
*/
linitial(saop->args) = fix_indexqual_operand(linitial(saop->args),
index,
&opclass);
&opfamily);
clause_op = saop->opno;
}
else
@ -1776,15 +1779,18 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
*fixed_indexquals = lappend(*fixed_indexquals, clause);
/*
* Look up the (possibly commuted) operator in the operator class to
* get its strategy numbers and the recheck indicator. This also
* Look up the (possibly commuted) operator in the operator family to
* get its strategy number and the recheck indicator. This also
* double-checks that we found an operator matching the index.
*/
get_op_opclass_properties(clause_op, opclass,
&stratno, &stratsubtype, &recheck);
get_op_opfamily_properties(clause_op, opfamily,
&stratno,
&stratlefttype,
&stratrighttype,
&recheck);
*indexstrategy = lappend_int(*indexstrategy, stratno);
*indexsubtype = lappend_oid(*indexsubtype, stratsubtype);
*indexsubtype = lappend_oid(*indexsubtype, stratrighttype);
/* If it's not lossy, add to nonlossy_indexquals */
if (!recheck)
@ -1793,7 +1799,7 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
}
static Node *
fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opfamily)
{
/*
* We represent index keys by Var nodes having the varno of the base table
@ -1826,8 +1832,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
{
result = (Var *) copyObject(node);
result->varattno = pos + 1;
/* return the correct opclass, too */
*opclass = index->classlist[pos];
/* return the correct opfamily, too */
*opfamily = index->opfamily[pos];
return (Node *) result;
}
}
@ -1853,8 +1859,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
result = makeVar(index->rel->relid, pos + 1,
exprType(lfirst(indexpr_item)), -1,
0);
/* return the correct opclass, too */
*opclass = index->classlist[pos];
/* return the correct opfamily, too */
*opfamily = index->opfamily[pos];
return (Node *) result;
}
indexpr_item = lnext(indexpr_item);
@ -1863,7 +1869,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
/* Ooops... */
elog(ERROR, "node is not an index attribute");
*opclass = InvalidOid; /* keep compiler quiet */
*opfamily = InvalidOid; /* keep compiler quiet */
return NULL;
}
@ -2327,6 +2333,8 @@ make_mergejoin(List *tlist,
List *joinclauses,
List *otherclauses,
List *mergeclauses,
List *mergefamilies,
List *mergestrategies,
Plan *lefttree,
Plan *righttree,
JoinType jointype)
@ -2340,6 +2348,8 @@ make_mergejoin(List *tlist,
plan->lefttree = lefttree;
plan->righttree = righttree;
node->mergeclauses = mergeclauses;
node->mergefamilies = mergefamilies;
node->mergestrategies = mergestrategies;
node->join.jointype = jointype;
node->join.joinqual = joinclauses;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.124 2006/12/07 19:33:40 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.125 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1109,10 +1109,10 @@ process_implied_equality(PlannerInfo *root,
/*
* Let's just make sure this appears to be a compatible operator.
*
* XXX needs work
*/
if (pgopform->oprlsortop != sortop1 ||
pgopform->oprrsortop != sortop2 ||
pgopform->oprresult != BOOLOID)
if (pgopform->oprresult != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("equality operator for types %s and %s should be merge-joinable, but isn't",
@ -1276,6 +1276,7 @@ check_mergejoinable(RestrictInfo *restrictinfo)
Oid opno,
leftOp,
rightOp;
Oid opfamily;
if (restrictinfo->pseudoconstant)
return;
@ -1286,14 +1287,17 @@ check_mergejoinable(RestrictInfo *restrictinfo)
opno = ((OpExpr *) clause)->opno;
if (op_mergejoinable(opno,
&leftOp,
&rightOp) &&
if (op_mergejoinable(opno) &&
!contain_volatile_functions((Node *) clause))
{
restrictinfo->mergejoinoperator = opno;
restrictinfo->left_sortop = leftOp;
restrictinfo->right_sortop = rightOp;
/* XXX for the moment, continue to force use of particular sortops */
if (get_op_mergejoin_info(opno, &leftOp, &rightOp, &opfamily))
{
restrictinfo->mergejoinoperator = opno;
restrictinfo->left_sortop = leftOp;
restrictinfo->right_sortop = rightOp;
restrictinfo->mergeopfamily = opfamily;
}
}
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.22 2006/10/04 00:29:54 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.23 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -340,8 +340,8 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
Assert(is_opclause(rinfo->clause));
strategy =
get_op_opclass_strategy(((OpExpr *) rinfo->clause)->opno,
index->classlist[prevcol]);
get_op_opfamily_strategy(((OpExpr *) rinfo->clause)->opno,
index->opfamily[prevcol]);
if (strategy == BTEqualStrategyNumber)
break;
}
@ -390,10 +390,10 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
* Does an aggregate match an index column?
*
* It matches if its argument is equal to the index column's data and its
* sortop is either the LessThan or GreaterThan member of the column's opclass.
* sortop is either a LessThan or GreaterThan member of the column's opfamily.
*
* We return ForwardScanDirection if match the LessThan member,
* BackwardScanDirection if match the GreaterThan member,
* We return ForwardScanDirection if match a LessThan member,
* BackwardScanDirection if match a GreaterThan member,
* and NoMovementScanDirection if there's no match.
*/
static ScanDirection
@ -405,9 +405,9 @@ match_agg_to_index_col(MinMaxAggInfo *info, IndexOptInfo *index, int indexcol)
if (!match_index_to_operand((Node *) info->target, indexcol, index))
return NoMovementScanDirection;
/* Look up the operator in the opclass */
strategy = get_op_opclass_strategy(info->aggsortop,
index->classlist[indexcol]);
/* Look up the operator in the opfamily */
strategy = get_op_opfamily_strategy(info->aggsortop,
index->opfamily[indexcol]);
if (strategy == BTLessStrategyNumber)
return ForwardScanDirection;
if (strategy == BTGreaterStrategyNumber)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.114 2006/12/10 22:13:26 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.115 2006/12/23 00:43:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -689,11 +689,11 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
return NULL;
if (sublink->testexpr && IsA(sublink->testexpr, OpExpr))
{
List *opclasses;
List *opfamilies;
List *opstrats;
get_op_btree_interpretation(((OpExpr *) sublink->testexpr)->opno,
&opclasses, &opstrats);
&opfamilies, &opstrats);
if (!list_member_int(opstrats, ROWCOMPARE_EQ))
return NULL;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.224 2006/12/21 16:05:13 petere Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.225 2006/12/23 00:43:10 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -1294,13 +1294,9 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
clause->opnos = newops;
/*
* Note: we don't bother to update the opclasses list, but just set it to
* empty. This is OK since this routine is currently only used for index
* quals, and the index machinery won't use the opclass information. The
* original opclass list is NOT valid if we have commuted any cross-type
* comparisons, so don't leave it in place.
* Note: we need not change the opfamilies list; we assume any btree
* opfamily containing an operator will also contain its commutator.
*/
clause->opclasses = NIL; /* XXX */
temp = clause->largs;
clause->largs = clause->rargs;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.133 2006/10/04 00:29:55 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.134 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1152,6 +1152,10 @@ create_nestloop_path(PlannerInfo *root,
* 'pathkeys' are the path keys of the new join path
* 'mergeclauses' are the RestrictInfo nodes to use as merge clauses
* (this should be a subset of the restrict_clauses list)
* 'mergefamilies' are the btree opfamily OIDs identifying the merge
* ordering for each merge clause
* 'mergestrategies' are the btree operator strategies identifying the merge
* ordering for each merge clause
* 'outersortkeys' are the sort varkeys for the outer relation
* 'innersortkeys' are the sort varkeys for the inner relation
*/
@ -1164,6 +1168,8 @@ create_mergejoin_path(PlannerInfo *root,
List *restrict_clauses,
List *pathkeys,
List *mergeclauses,
List *mergefamilies,
List *mergestrategies,
List *outersortkeys,
List *innersortkeys)
{
@ -1204,6 +1210,8 @@ create_mergejoin_path(PlannerInfo *root,
pathnode->jpath.joinrestrictinfo = restrict_clauses;
pathnode->jpath.path.pathkeys = pathkeys;
pathnode->path_mergeclauses = mergeclauses;
pathnode->path_mergefamilies = mergefamilies;
pathnode->path_mergestrategies = mergestrategies;
pathnode->outersortkeys = outersortkeys;
pathnode->innersortkeys = innersortkeys;

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.128 2006/12/18 18:56:28 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.129 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -169,16 +169,16 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->ncolumns = ncolumns = index->indnatts;
/*
* Need to make classlist and ordering arrays large enough to put
* Need to make opfamily and ordering arrays large enough to put
* a terminating 0 at the end of each one.
*/
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
info->classlist = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
info->opfamily = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
info->ordering = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
for (i = 0; i < ncolumns; i++)
{
info->classlist[i] = indexRelation->rd_indclass->values[i];
info->opfamily[i] = indexRelation->rd_opfamily[i];
info->indexkeys[i] = index->indkey.values[i];
}

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.10 2006/10/04 00:29:55 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.11 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -939,7 +939,7 @@ arrayexpr_cleanup_fn(PredIterInfo info)
* already known immutable, so the clause will certainly always fail.)
*
* Finally, we may be able to deduce something using knowledge about btree
* operator classes; this is encapsulated in btree_predicate_proof().
* operator families; this is encapsulated in btree_predicate_proof().
*----------
*/
static bool
@ -989,7 +989,7 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
* that has "foo" as an input. See notes for implication case.
*
* Finally, we may be able to deduce something using knowledge about btree
* operator classes; this is encapsulated in btree_predicate_proof().
* operator families; this is encapsulated in btree_predicate_proof().
*----------
*/
static bool
@ -1062,8 +1062,8 @@ extract_not_arg(Node *clause)
* The strategy numbers defined by btree indexes (see access/skey.h) are:
* (1) < (2) <= (3) = (4) >= (5) >
* and in addition we use (6) to represent <>. <> is not a btree-indexable
* operator, but we assume here that if the equality operator of a btree
* opclass has a negator operator, the negator behaves as <> for the opclass.
* operator, but we assume here that if an equality operator of a btree
* opfamily has a negator operator, the negator behaves as <> for the opfamily.
*
* The interpretation of:
*
@ -1146,10 +1146,10 @@ static const StrategyNumber BT_refute_table[6][6] = {
* What we look for here is binary boolean opclauses of the form
* "foo op constant", where "foo" is the same in both clauses. The operators
* and constants can be different but the operators must be in the same btree
* operator class. We use the above operator implication tables to
* operator family. We use the above operator implication tables to
* derive implications between nonidentical clauses. (Note: "foo" is known
* immutable, and constants are surely immutable, but we have to check that
* the operators are too. As of 8.0 it's possible for opclasses to contain
* the operators are too. As of 8.0 it's possible for opfamilies to contain
* operators that are merely stable, and we dare not make deductions with
* these.)
*----------
@ -1171,12 +1171,12 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
pred_op_negator,
clause_op_negator,
test_op = InvalidOid;
Oid opclass_id;
Oid opfamily_id;
bool found = false;
StrategyNumber pred_strategy,
clause_strategy,
test_strategy;
Oid clause_subtype;
Oid clause_righttype;
Expr *test_expr;
ExprState *test_exprstate;
Datum test_result;
@ -1272,28 +1272,30 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
}
/*
* Try to find a btree opclass containing the needed operators.
* Try to find a btree opfamily containing the needed operators.
*
* We must find a btree opclass that contains both operators, else the
* XXX this needs work!!!!!!!!!!!!!!!!!!!!!!!
*
* We must find a btree opfamily that contains both operators, else the
* implication can't be determined. Also, the pred_op has to be of
* default subtype (implying left and right input datatypes are the same);
* otherwise it's unsafe to put the pred_const on the left side of the
* test. Also, the opclass must contain a suitable test operator matching
* test. Also, the opfamily must contain a suitable test operator matching
* the clause_const's type (which we take to mean that it has the same
* subtype as the original clause_operator).
*
* If there are multiple matching opclasses, assume we can use any one to
* If there are multiple matching opfamilies, assume we can use any one to
* determine the logical relationship of the two operators and the correct
* corresponding test operator. This should work for any logically
* consistent opclasses.
* consistent opfamilies.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(pred_op),
0, 0, 0);
/*
* If we couldn't find any opclass containing the pred_op, perhaps it is a
* <> operator. See if it has a negator that is in an opclass.
* If we couldn't find any opfamily containing the pred_op, perhaps it is a
* <> operator. See if it has a negator that is in an opfamily.
*/
pred_op_negated = false;
if (catlist->n_members == 0)
@ -1312,23 +1314,22 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
/* Also may need the clause_op's negator */
clause_op_negator = get_negator(clause_op);
/* Now search the opclasses */
/* Now search the opfamilies */
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple pred_tuple = &catlist->members[i]->tuple;
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
HeapTuple clause_tuple;
opclass_id = pred_form->amopclaid;
/* must be btree */
if (!opclass_is_btree(opclass_id))
if (pred_form->amopmethod != BTREE_AM_OID)
continue;
/* predicate operator must be default within this opclass */
if (pred_form->amopsubtype != InvalidOid)
/* predicate operator must be default within this opfamily */
if (pred_form->amoplefttype != pred_form->amoprighttype)
continue;
/* Get the predicate operator's btree strategy number */
opfamily_id = pred_form->amopfamily;
pred_strategy = (StrategyNumber) pred_form->amopstrategy;
Assert(pred_strategy >= 1 && pred_strategy <= 5);
@ -1341,37 +1342,39 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
}
/*
* From the same opclass, find a strategy number for the clause_op, if
* possible
* From the same opfamily, find a strategy number for the clause_op,
* if possible
*/
clause_tuple = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(clause_op),
ObjectIdGetDatum(opclass_id),
ObjectIdGetDatum(opfamily_id),
0, 0);
if (HeapTupleIsValid(clause_tuple))
{
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
/* Get the restriction clause operator's strategy/subtype */
/* Get the restriction clause operator's strategy/datatype */
clause_strategy = (StrategyNumber) clause_form->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5);
clause_subtype = clause_form->amopsubtype;
Assert(clause_form->amoplefttype == pred_form->amoplefttype);
clause_righttype = clause_form->amoprighttype;
ReleaseSysCache(clause_tuple);
}
else if (OidIsValid(clause_op_negator))
{
clause_tuple = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(clause_op_negator),
ObjectIdGetDatum(opclass_id),
ObjectIdGetDatum(opfamily_id),
0, 0);
if (HeapTupleIsValid(clause_tuple))
{
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
/* Get the restriction clause operator's strategy/subtype */
/* Get the restriction clause operator's strategy/datatype */
clause_strategy = (StrategyNumber) clause_form->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5);
clause_subtype = clause_form->amopsubtype;
Assert(clause_form->amoplefttype == pred_form->amoplefttype);
clause_righttype = clause_form->amoprighttype;
ReleaseSysCache(clause_tuple);
/* Only consider negators that are = */
@ -1400,20 +1403,24 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
}
/*
* See if opclass has an operator for the test strategy and the clause
* datatype.
* See if opfamily has an operator for the test strategy and the
* datatypes.
*/
if (test_strategy == BTNE)
{
test_op = get_opclass_member(opclass_id, clause_subtype,
BTEqualStrategyNumber);
test_op = get_opfamily_member(opfamily_id,
pred_form->amoprighttype,
clause_righttype,
BTEqualStrategyNumber);
if (OidIsValid(test_op))
test_op = get_negator(test_op);
}
else
{
test_op = get_opclass_member(opclass_id, clause_subtype,
test_strategy);
test_op = get_opfamily_member(opfamily_id,
pred_form->amoprighttype,
clause_righttype,
test_strategy);
}
if (OidIsValid(test_op))
{
@ -1423,7 +1430,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
* Note that we require only the test_op to be immutable, not the
* original clause_op. (pred_op is assumed to have been checked
* immutable by the caller.) Essentially we are assuming that the
* opclass is consistent even if it contains operators that are
* opfamily is consistent even if it contains operators that are
* merely stable.
*/
if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE)
@ -1438,7 +1445,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
if (!found)
{
/* couldn't find a btree opclass to interpret the operators */
/* couldn't find a btree opfamily to interpret the operators */
return false;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.49 2006/10/04 00:29:55 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.50 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -342,6 +342,7 @@ make_restrictinfo_internal(Expr *clause,
restrictinfo->mergejoinoperator = InvalidOid;
restrictinfo->left_sortop = InvalidOid;
restrictinfo->right_sortop = InvalidOid;
restrictinfo->mergeopfamily = InvalidOid;
restrictinfo->left_pathkey = NIL;
restrictinfo->right_pathkey = NIL;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.200 2006/12/21 16:05:14 petere Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.201 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -2014,10 +2014,10 @@ make_row_comparison_op(ParseState *pstate, List *opname,
RowCompareType rctype;
List *opexprs;
List *opnos;
List *opclasses;
List *opfamilies;
ListCell *l,
*r;
List **opclass_lists;
List **opfamily_lists;
List **opstrat_lists;
Bitmapset *strats;
int nopers;
@ -2057,7 +2057,7 @@ make_row_comparison_op(ParseState *pstate, List *opname,
/*
* We don't use coerce_to_boolean here because we insist on the
* operator yielding boolean directly, not via coercion. If it
* doesn't yield bool it won't be in any index opclasses...
* doesn't yield bool it won't be in any index opfamilies...
*/
if (cmp->opresulttype != BOOLOID)
ereport(ERROR,
@ -2084,21 +2084,22 @@ make_row_comparison_op(ParseState *pstate, List *opname,
/*
* Now we must determine which row comparison semantics (= <> < <= > >=)
* apply to this set of operators. We look for btree opclasses containing
* apply to this set of operators. We look for btree opfamilies containing
* the operators, and see which interpretations (strategy numbers) exist
* for each operator.
*/
opclass_lists = (List **) palloc(nopers * sizeof(List *));
opfamily_lists = (List **) palloc(nopers * sizeof(List *));
opstrat_lists = (List **) palloc(nopers * sizeof(List *));
strats = NULL;
i = 0;
foreach(l, opexprs)
{
Oid opno = ((OpExpr *) lfirst(l))->opno;
Bitmapset *this_strats;
ListCell *j;
get_op_btree_interpretation(((OpExpr *) lfirst(l))->opno,
&opclass_lists[i], &opstrat_lists[i]);
get_op_btree_interpretation(opno,
&opfamily_lists[i], &opstrat_lists[i]);
/*
* convert strategy number list to a Bitmapset to make the
@ -2116,68 +2117,23 @@ make_row_comparison_op(ParseState *pstate, List *opname,
i++;
}
switch (bms_membership(strats))
/*
* If there are multiple common interpretations, we may use any one of
* them ... this coding arbitrarily picks the lowest btree strategy
* number.
*/
i = bms_first_member(strats);
if (i < 0)
{
case BMS_EMPTY_SET:
/* No common interpretation, so fail */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine interpretation of row comparison operator %s",
strVal(llast(opname))),
errhint("Row comparison operators must be associated with btree operator classes."),
parser_errposition(pstate, location)));
rctype = 0; /* keep compiler quiet */
break;
case BMS_SINGLETON:
/* Simple case: just one possible interpretation */
rctype = bms_singleton_member(strats);
break;
case BMS_MULTIPLE:
default: /* keep compiler quiet */
{
/*
* Prefer the interpretation with the most default opclasses.
*/
int best_defaults = 0;
bool multiple_best = false;
int this_rctype;
rctype = 0; /* keep compiler quiet */
while ((this_rctype = bms_first_member(strats)) >= 0)
{
int ndefaults = 0;
for (i = 0; i < nopers; i++)
{
forboth(l, opclass_lists[i], r, opstrat_lists[i])
{
Oid opclass = lfirst_oid(l);
int opstrat = lfirst_int(r);
if (opstrat == this_rctype &&
opclass_is_default(opclass))
ndefaults++;
}
}
if (ndefaults > best_defaults)
{
best_defaults = ndefaults;
rctype = this_rctype;
multiple_best = false;
}
else if (ndefaults == best_defaults)
multiple_best = true;
}
if (best_defaults == 0 || multiple_best)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine interpretation of row comparison operator %s",
strVal(llast(opname))),
errdetail("There are multiple equally-plausible candidates."),
parser_errposition(pstate, location)));
break;
}
/* No common interpretation, so fail */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine interpretation of row comparison operator %s",
strVal(llast(opname))),
errhint("Row comparison operators must be associated with btree operator families."),
parser_errposition(pstate, location)));
}
rctype = (RowCompareType) i;
/*
* For = and <> cases, we just combine the pairwise operators with AND or
@ -2193,34 +2149,27 @@ make_row_comparison_op(ParseState *pstate, List *opname,
return (Node *) makeBoolExpr(OR_EXPR, opexprs);
/*
* Otherwise we need to determine exactly which opclass to associate with
* Otherwise we need to choose exactly which opfamily to associate with
* each operator.
*/
opclasses = NIL;
opfamilies = NIL;
for (i = 0; i < nopers; i++)
{
Oid best_opclass = 0;
int ndefault = 0;
int nmatch = 0;
Oid opfamily = InvalidOid;
forboth(l, opclass_lists[i], r, opstrat_lists[i])
forboth(l, opfamily_lists[i], r, opstrat_lists[i])
{
Oid opclass = lfirst_oid(l);
int opstrat = lfirst_int(r);
if (opstrat == rctype)
{
if (ndefault == 0)
best_opclass = opclass;
if (opclass_is_default(opclass))
ndefault++;
else
nmatch++;
opfamily = lfirst_oid(l);
break;
}
}
if (ndefault == 1 || (ndefault == 0 && nmatch == 1))
opclasses = lappend_oid(opclasses, best_opclass);
else
if (OidIsValid(opfamily))
opfamilies = lappend_oid(opfamilies, opfamily);
else /* should not happen */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine interpretation of row comparison operator %s",
@ -2250,7 +2199,7 @@ make_row_comparison_op(ParseState *pstate, List *opname,
rcexpr = makeNode(RowCompareExpr);
rcexpr->rctype = rctype;
rcexpr->opnos = opnos;
rcexpr->opclasses = opclasses;
rcexpr->opfamilies = opfamilies;
rcexpr->largs = largs;
rcexpr->rargs = rargs;

View File

@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.236 2006/12/21 16:05:15 petere Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.237 2006/12/23 00:43:11 tgl Exp $
**********************************************************************/
#include "postgres.h"
@ -19,6 +19,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_trigger.h"
#include "commands/defrem.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "nodes/makefuncs.h"
@ -4717,11 +4718,6 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
Form_pg_opclass opcrec;
char *opcname;
char *nspname;
bool isvisible;
/* Domains use their base type's default opclass */
if (OidIsValid(actual_datatype))
actual_datatype = getBaseType(actual_datatype);
ht_opc = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
@ -4730,25 +4726,12 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
elog(ERROR, "cache lookup failed for opclass %u", opclass);
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
/*
* Special case for ARRAY_OPS: pretend it is default for any array type
*/
if (OidIsValid(actual_datatype))
{
if (opcrec->opcintype == ANYARRAYOID &&
OidIsValid(get_element_type(actual_datatype)))
actual_datatype = opcrec->opcintype;
}
/* Must force use of opclass name if not in search path */
isvisible = OpclassIsVisible(opclass);
if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault ||
!isvisible)
if (!OidIsValid(actual_datatype) ||
GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
{
/* Okay, we need the opclass name. Do we need to qualify it? */
opcname = NameStr(opcrec->opcname);
if (isvisible)
if (OpclassIsVisible(opclass))
appendStringInfo(buf, " %s", quote_identifier(opcname));
else
{

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.215 2006/12/15 18:42:26 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.216 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -76,7 +76,7 @@
#include <ctype.h>
#include <math.h>
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
@ -128,7 +128,7 @@ static double convert_timevalue_to_scalar(Datum value, Oid typid);
static bool get_variable_maximum(PlannerInfo *root, VariableStatData *vardata,
Oid sortop, Datum *max);
static Selectivity prefix_selectivity(VariableStatData *vardata,
Oid opclass, Const *prefixcon);
Oid vartype, Oid opfamily, Const *prefixcon);
static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
static Datum string_to_datum(const char *str, Oid datatype);
static Const *string_to_const(const char *str, Oid datatype);
@ -911,7 +911,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
Datum constval;
Oid consttype;
Oid vartype;
Oid opclass;
Oid opfamily;
Pattern_Prefix_Status pstatus;
Const *patt = NULL;
Const *prefix = NULL;
@ -960,9 +960,9 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
* Similarly, the exposed type of the left-hand side should be one of
* those we know. (Do not look at vardata.atttype, which might be
* something binary-compatible but different.) We can use it to choose
* the index opclass from which we must draw the comparison operators.
* the index opfamily from which we must draw the comparison operators.
*
* NOTE: It would be more correct to use the PATTERN opclasses than the
* NOTE: It would be more correct to use the PATTERN opfamilies than the
* simple ones, but at the moment ANALYZE will not generate statistics for
* the PATTERN operators. But our results are so approximate anyway that
* it probably hardly matters.
@ -972,19 +972,16 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
switch (vartype)
{
case TEXTOID:
opclass = TEXT_BTREE_OPS_OID;
break;
case VARCHAROID:
opclass = VARCHAR_BTREE_OPS_OID;
opfamily = TEXT_BTREE_FAM_OID;
break;
case BPCHAROID:
opclass = BPCHAR_BTREE_OPS_OID;
opfamily = BPCHAR_BTREE_FAM_OID;
break;
case NAMEOID:
opclass = NAME_BTREE_OPS_OID;
opfamily = NAME_BTREE_FAM_OID;
break;
case BYTEAOID:
opclass = BYTEA_BTREE_OPS_OID;
opfamily = BYTEA_BTREE_FAM_OID;
break;
default:
ReleaseVariableStats(vardata);
@ -1028,12 +1025,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
/*
* Pattern specifies an exact match, so pretend operator is '='
*/
Oid eqopr = get_opclass_member(opclass, InvalidOid,
BTEqualStrategyNumber);
Oid eqopr = get_opfamily_member(opfamily, vartype, vartype,
BTEqualStrategyNumber);
List *eqargs;
if (eqopr == InvalidOid)
elog(ERROR, "no = operator for opclass %u", opclass);
elog(ERROR, "no = operator for opfamily %u", opfamily);
eqargs = list_make2(variable, prefix);
result = DatumGetFloat8(DirectFunctionCall4(eqsel,
PointerGetDatum(root),
@ -1074,7 +1071,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
Selectivity restsel;
if (pstatus == Pattern_Prefix_Partial)
prefixsel = prefix_selectivity(&vardata, opclass, prefix);
prefixsel = prefix_selectivity(&vardata, vartype,
opfamily, prefix);
else
prefixsel = 1.0;
restsel = pattern_selectivity(rest, ptype);
@ -2114,7 +2112,8 @@ icnlikejoinsel(PG_FUNCTION_ARGS)
* we can estimate how much of the input will actually be read. This
* can have a considerable impact on the cost when using indexscans.
*
* clause should be a clause already known to be mergejoinable.
* clause should be a clause already known to be mergejoinable. opfamily and
* strategy specify the sort ordering being used.
*
* *leftscan is set to the fraction of the left-hand variable expected
* to be scanned (0 to 1), and similarly *rightscan for the right-hand
@ -2122,6 +2121,7 @@ icnlikejoinsel(PG_FUNCTION_ARGS)
*/
void
mergejoinscansel(PlannerInfo *root, Node *clause,
Oid opfamily, int strategy,
Selectivity *leftscan,
Selectivity *rightscan)
{
@ -2129,15 +2129,14 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
*right;
VariableStatData leftvar,
rightvar;
Oid lefttype,
righttype;
int op_strategy;
Oid op_lefttype;
Oid op_righttype;
bool op_recheck;
Oid opno,
lsortop,
rsortop,
ltop,
gtop,
leop,
revgtop,
revleop;
Datum leftmax,
rightmax;
@ -2159,15 +2158,51 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
examine_variable(root, left, 0, &leftvar);
examine_variable(root, right, 0, &rightvar);
/* Get the direct input types of the operator */
lefttype = exprType(left);
righttype = exprType(right);
/* Extract the operator's declared left/right datatypes */
get_op_opfamily_properties(opno, opfamily,
&op_strategy,
&op_lefttype,
&op_righttype,
&op_recheck);
Assert(op_strategy == BTEqualStrategyNumber);
Assert(!op_recheck);
/* Verify mergejoinability and get left and right "<" operators */
if (!op_mergejoinable(opno,
&lsortop,
&rsortop))
goto fail; /* shouldn't happen */
/*
* Look up the various operators we need. If we don't find them all,
* it probably means the opfamily is broken, but we cope anyway.
*/
switch (strategy)
{
case BTLessStrategyNumber:
lsortop = get_opfamily_member(opfamily, op_lefttype, op_lefttype,
BTLessStrategyNumber);
rsortop = get_opfamily_member(opfamily, op_righttype, op_righttype,
BTLessStrategyNumber);
leop = get_opfamily_member(opfamily, op_lefttype, op_righttype,
BTLessEqualStrategyNumber);
revleop = get_opfamily_member(opfamily, op_righttype, op_lefttype,
BTLessEqualStrategyNumber);
break;
case BTGreaterStrategyNumber:
/* descending-order case */
lsortop = get_opfamily_member(opfamily, op_lefttype, op_lefttype,
BTGreaterStrategyNumber);
rsortop = get_opfamily_member(opfamily, op_righttype, op_righttype,
BTGreaterStrategyNumber);
leop = get_opfamily_member(opfamily, op_lefttype, op_righttype,
BTGreaterEqualStrategyNumber);
revleop = get_opfamily_member(opfamily, op_righttype, op_lefttype,
BTGreaterEqualStrategyNumber);
break;
default:
goto fail; /* shouldn't get here */
}
if (!OidIsValid(lsortop) ||
!OidIsValid(rsortop) ||
!OidIsValid(leop) ||
!OidIsValid(revleop))
goto fail; /* insufficient info in catalogs */
/* Try to get maximum values of both inputs */
if (!get_variable_maximum(root, &leftvar, lsortop, &leftmax))
@ -2176,37 +2211,19 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
if (!get_variable_maximum(root, &rightvar, rsortop, &rightmax))
goto fail; /* no max available from stats */
/* Look up the "left < right" and "left > right" operators */
op_mergejoin_crossops(opno, &ltop, &gtop, NULL, NULL);
/* Look up the "left <= right" operator */
leop = get_negator(gtop);
if (!OidIsValid(leop))
goto fail; /* insufficient info in catalogs */
/* Look up the "right > left" operator */
revgtop = get_commutator(ltop);
if (!OidIsValid(revgtop))
goto fail; /* insufficient info in catalogs */
/* Look up the "right <= left" operator */
revleop = get_negator(revgtop);
if (!OidIsValid(revleop))
goto fail; /* insufficient info in catalogs */
/*
* Now, the fraction of the left variable that will be scanned is the
* fraction that's <= the right-side maximum value. But only believe
* non-default estimates, else stick with our 1.0.
*/
selec = scalarineqsel(root, leop, false, &leftvar,
rightmax, righttype);
rightmax, op_righttype);
if (selec != DEFAULT_INEQ_SEL)
*leftscan = selec;
/* And similarly for the right variable. */
selec = scalarineqsel(root, revleop, false, &rightvar,
leftmax, lefttype);
leftmax, op_lefttype);
if (selec != DEFAULT_INEQ_SEL)
*rightscan = selec;
@ -3486,7 +3503,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
* statistics.
*
* XXX it's conceivable that there are multiple matches with different
* index opclasses; if so, we need to pick one that matches the
* index opfamilies; if so, we need to pick one that matches the
* operator we are estimating for. FIXME later.
*/
ListCell *ilist;
@ -4100,7 +4117,7 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
* population represented by the histogram --- the caller must fold this
* together with info about MCVs and NULLs.
*
* We use the >= and < operators from the specified btree opclass to do the
* We use the >= and < operators from the specified btree opfamily to do the
* estimation. The given variable and Const must be of the associated
* datatype.
*
@ -4110,17 +4127,18 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
* more useful to use the upper-bound code than not.
*/
static Selectivity
prefix_selectivity(VariableStatData *vardata, Oid opclass, Const *prefixcon)
prefix_selectivity(VariableStatData *vardata,
Oid vartype, Oid opfamily, Const *prefixcon)
{
Selectivity prefixsel;
Oid cmpopr;
FmgrInfo opproc;
Const *greaterstrcon;
cmpopr = get_opclass_member(opclass, InvalidOid,
BTGreaterEqualStrategyNumber);
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
BTGreaterEqualStrategyNumber);
if (cmpopr == InvalidOid)
elog(ERROR, "no >= operator for opclass %u", opclass);
elog(ERROR, "no >= operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
prefixsel = ineq_histogram_selectivity(vardata, &opproc, true,
@ -4143,10 +4161,10 @@ prefix_selectivity(VariableStatData *vardata, Oid opclass, Const *prefixcon)
{
Selectivity topsel;
cmpopr = get_opclass_member(opclass, InvalidOid,
BTLessStrategyNumber);
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
BTLessStrategyNumber);
if (cmpopr == InvalidOid)
elog(ERROR, "no < operator for opclass %u", opclass);
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
topsel = ineq_histogram_selectivity(vardata, &opproc, false,
@ -4921,7 +4939,7 @@ btcostestimate(PG_FUNCTION_ARGS)
}
else if (match_index_to_operand(rightop, indexcol, index))
{
/* Must flip operator to get the opclass member */
/* Must flip operator to get the opfamily member */
clause_op = get_commutator(clause_op);
}
else
@ -4937,7 +4955,7 @@ btcostestimate(PG_FUNCTION_ARGS)
}
else if (match_index_to_operand(rightop, indexcol, index))
{
/* Must flip operator to get the opclass member */
/* Must flip operator to get the opfamily member */
clause_op = get_commutator(clause_op);
}
else
@ -4946,9 +4964,9 @@ btcostestimate(PG_FUNCTION_ARGS)
break;
}
}
op_strategy = get_op_opclass_strategy(clause_op,
index->classlist[indexcol]);
Assert(op_strategy != 0); /* not a member of opclass?? */
op_strategy = get_op_opfamily_strategy(clause_op,
index->opfamily[indexcol]);
Assert(op_strategy != 0); /* not a member of opfamily?? */
if (op_strategy == BTEqualStrategyNumber)
eqQualHere = true;
/* count up number of SA scans induced by indexBoundQuals only */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.134 2006/10/06 18:23:35 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.135 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1033,9 +1033,10 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
if (cache->id == INDEXRELID)
{
/*
* Since the OIDs of indexes aren't hardwired, it's painful to figure
* out which is which. Just force all pg_index searches to be heap
* scans while building the relcaches.
* Rather than tracking exactly which indexes have to be loaded
* before we can use indexscans (which changes from time to time),
* just force all pg_index searches to be heap scans until we've
* built the critical relcaches.
*/
if (!criticalRelcachesBuilt)
return false;
@ -1051,17 +1052,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
*/
return false;
}
else if (cache->id == OPEROID)
{
if (!criticalRelcachesBuilt)
{
/* Looking for an OID comparison function? */
Oid lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
return false;
}
}
/* Normal case, allow index scan */
return true;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.138 2006/10/04 00:30:00 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.139 2006/12/23 00:43:11 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@ -37,27 +37,27 @@
/* ---------- AMOP CACHES ---------- */
/*
* op_in_opclass
* op_in_opfamily
*
* Return t iff operator 'opno' is in operator class 'opclass'.
* Return t iff operator 'opno' is in operator family 'opfamily'.
*/
bool
op_in_opclass(Oid opno, Oid opclass)
op_in_opfamily(Oid opno, Oid opfamily)
{
return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(opfamily),
0, 0);
}
/*
* get_op_opclass_strategy
* get_op_opfamily_strategy
*
* Get the operator's strategy number within the specified opclass,
* or 0 if it's not a member of the opclass.
* Get the operator's strategy number within the specified opfamily,
* or 0 if it's not a member of the opfamily.
*/
int
get_op_opclass_strategy(Oid opno, Oid opclass)
get_op_opfamily_strategy(Oid opno, Oid opfamily)
{
HeapTuple tp;
Form_pg_amop amop_tup;
@ -65,7 +65,7 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(opfamily),
0, 0);
if (!HeapTupleIsValid(tp))
return 0;
@ -76,54 +76,59 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
}
/*
* get_op_opclass_properties
* get_op_opfamily_properties
*
* Get the operator's strategy number, subtype, and recheck (lossy) flag
* within the specified opclass.
* Get the operator's strategy number, input types, and recheck (lossy)
* flag within the specified opfamily.
*
* Caller should already have verified that opno is a member of opclass,
* Caller should already have verified that opno is a member of opfamily,
* therefore we raise an error if the tuple is not found.
*/
void
get_op_opclass_properties(Oid opno, Oid opclass,
int *strategy, Oid *subtype, bool *recheck)
get_op_opfamily_properties(Oid opno, Oid opfamily,
int *strategy,
Oid *lefttype,
Oid *righttype,
bool *recheck)
{
HeapTuple tp;
Form_pg_amop amop_tup;
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(opfamily),
0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "operator %u is not a member of opclass %u",
opno, opclass);
elog(ERROR, "operator %u is not a member of opfamily %u",
opno, opfamily);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
*strategy = amop_tup->amopstrategy;
*subtype = amop_tup->amopsubtype;
*lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
*recheck = amop_tup->amopreqcheck;
ReleaseSysCache(tp);
}
/*
* get_opclass_member
* get_opfamily_member
* Get the OID of the operator that implements the specified strategy
* with the specified subtype for the specified opclass.
* with the specified datatypes for the specified opfamily.
*
* Returns InvalidOid if there is no pg_amop entry for the given keys.
*/
Oid
get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
int16 strategy)
{
HeapTuple tp;
Form_pg_amop amop_tup;
Oid result;
tp = SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(subtype),
Int16GetDatum(strategy),
0);
ObjectIdGetDatum(opfamily),
ObjectIdGetDatum(lefttype),
ObjectIdGetDatum(righttype),
Int16GetDatum(strategy));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
@ -132,11 +137,161 @@ get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
return result;
}
/*
* get_op_mergejoin_info
* Given the OIDs of a (putatively) mergejoinable equality operator
* and a sortop defining the sort ordering of the lefthand input of
* the merge clause, determine whether this sort ordering is actually
* usable for merging. If so, return the required sort ordering op
* for the righthand input, as well as the btree opfamily OID containing
* these operators and the operator strategy number of the two sortops
* (either BTLessStrategyNumber or BTGreaterStrategyNumber).
*
* We can mergejoin if we find the two operators in the same opfamily as
* equality and either less-than or greater-than respectively. If there
* are multiple such opfamilies, assume we can use any one.
*/
#ifdef NOT_YET
/* eventually should look like this */
bool
get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
Oid *right_sortop, Oid *opfamily, int *opstrategy)
{
bool result = false;
Oid lefttype;
Oid righttype;
CatCList *catlist;
int i;
/* Make sure output args are initialized even on failure */
*right_sortop = InvalidOid;
*opfamily = InvalidOid;
*opstrategy = 0;
/* Need the righthand input datatype */
op_input_types(eq_op, &lefttype, &righttype);
/*
* Search through all the pg_amop entries containing the equality operator
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(eq_op),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opfamily_id;
StrategyNumber op_strategy;
/* must be btree */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* must use the operator as equality */
if (op_form->amopstrategy != BTEqualStrategyNumber)
continue;
/* See if sort operator is also in this opclass with OK semantics */
opfamily_id = op_form->amopfamily;
op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
if (op_strategy == BTLessStrategyNumber ||
op_strategy == BTGreaterStrategyNumber)
{
/* Yes, so find the corresponding righthand sortop */
*right_sortop = get_opfamily_member(opfamily_id,
righttype,
righttype,
op_strategy);
if (OidIsValid(*right_sortop))
{
/* Found a workable mergejoin semantics */
*opfamily = opfamily_id;
*opstrategy = op_strategy;
result = true;
break;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
#else
/* temp implementation until planner gets smarter: left_sortop is output */
bool
get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
Oid *right_sortop, Oid *opfamily)
{
bool result = false;
Oid lefttype;
Oid righttype;
CatCList *catlist;
int i;
/* Make sure output args are initialized even on failure */
*left_sortop = InvalidOid;
*right_sortop = InvalidOid;
*opfamily = InvalidOid;
/* Need the input datatypes */
op_input_types(eq_op, &lefttype, &righttype);
/*
* Search through all the pg_amop entries containing the equality operator
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(eq_op),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opfamily_id;
/* must be btree */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* must use the operator as equality */
if (op_form->amopstrategy != BTEqualStrategyNumber)
continue;
opfamily_id = op_form->amopfamily;
/* Find the matching sortops */
*left_sortop = get_opfamily_member(opfamily_id,
lefttype,
lefttype,
BTLessStrategyNumber);
*right_sortop = get_opfamily_member(opfamily_id,
righttype,
righttype,
BTLessStrategyNumber);
if (OidIsValid(*left_sortop) && OidIsValid(*right_sortop))
{
/* Found a workable mergejoin semantics */
*opfamily = opfamily_id;
result = true;
break;
}
}
ReleaseSysCacheList(catlist);
return result;
}
#endif
/*
* get_op_hash_function
* Get the OID of the datatype-specific hash function associated with
* a hashable equality operator.
*
* XXX API needs to be generalized for the case of different left and right
* datatypes.
*
* Returns InvalidOid if no hash function can be found. (This indicates
* that the operator should not have been marked oprcanhash.)
*/
@ -145,12 +300,12 @@ get_op_hash_function(Oid opno)
{
CatCList *catlist;
int i;
Oid opclass = InvalidOid;
Oid result = InvalidOid;
/*
* Search pg_amop to see if the target operator is registered as the "="
* operator of any hash opclass. If the operator is registered in
* multiple opclasses, assume we can use the associated hash function from
* operator of any hash opfamily. If the operator is registered in
* multiple opfamilies, assume we can use the associated hash function from
* any one.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
@ -162,57 +317,43 @@ get_op_hash_function(Oid opno)
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopstrategy == HTEqualStrategyNumber &&
opclass_is_hash(aform->amopclaid))
if (aform->amopmethod == HASH_AM_OID &&
aform->amopstrategy == HTEqualStrategyNumber)
{
opclass = aform->amopclaid;
/* Found a suitable opfamily, get matching hash support function */
result = get_opfamily_proc(aform->amopfamily,
aform->amoplefttype,
aform->amoprighttype,
HASHPROC);
break;
}
}
ReleaseSysCacheList(catlist);
if (OidIsValid(opclass))
{
/* Found a suitable opclass, get its default hash support function */
return get_opclass_proc(opclass, InvalidOid, HASHPROC);
}
/* Didn't find a match... */
return InvalidOid;
return result;
}
/*
* get_op_btree_interpretation
* Given an operator's OID, find out which btree opclasses it belongs to,
* Given an operator's OID, find out which btree opfamilies it belongs to,
* and what strategy number it has within each one. The results are
* returned as an OID list and a parallel integer list.
*
* In addition to the normal btree operators, we consider a <> operator to be
* a "member" of an opclass if its negator is the opclass' equality operator.
* ROWCOMPARE_NE is returned as the strategy number for this case.
* a "member" of an opfamily if its negator is an equality operator of the
* opfamily. ROWCOMPARE_NE is returned as the strategy number for this case.
*/
void
get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
{
Oid lefttype,
righttype;
CatCList *catlist;
bool op_negated;
int i;
*opclasses = NIL;
*opfamilies = NIL;
*opstrats = NIL;
/*
* Get the nominal left-hand input type of the operator; we will ignore
* opclasses that don't have that as the expected input datatype. This is
* a kluge to avoid being confused by binary-compatible opclasses (such as
* text_ops and varchar_ops, which share the same operators).
*/
op_input_types(opno, &lefttype, &righttype);
Assert(OidIsValid(lefttype));
/*
* Find all the pg_amop entries containing the operator.
*/
@ -221,8 +362,8 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
0, 0, 0);
/*
* If we can't find any opclass containing the op, perhaps it is a <>
* operator. See if it has a negator that is in an opclass.
* If we can't find any opfamily containing the op, perhaps it is a <>
* operator. See if it has a negator that is in an opfamily.
*/
op_negated = false;
if (catlist->n_members == 0)
@ -239,25 +380,20 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
}
}
/* Now search the opclasses */
/* Now search the opfamilies */
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opclass_id;
Oid opfamily_id;
StrategyNumber op_strategy;
opclass_id = op_form->amopclaid;
/* must be btree */
if (!opclass_is_btree(opclass_id))
continue;
/* must match operator input type exactly */
if (get_opclass_input_type(opclass_id) != lefttype)
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* Get the operator's btree strategy number */
opfamily_id = op_form->amopfamily;
op_strategy = (StrategyNumber) op_form->amopstrategy;
Assert(op_strategy >= 1 && op_strategy <= 5);
@ -269,7 +405,7 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
op_strategy = ROWCOMPARE_NE;
}
*opclasses = lappend_oid(*opclasses, opclass_id);
*opfamilies = lappend_oid(*opfamilies, opfamily_id);
*opstrats = lappend_int(*opstrats, op_strategy);
}
@ -280,24 +416,24 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
/* ---------- AMPROC CACHES ---------- */
/*
* get_opclass_proc
* get_opfamily_proc
* Get the OID of the specified support function
* for the specified opclass and subtype.
* for the specified opfamily and datatypes.
*
* Returns InvalidOid if there is no pg_amproc entry for the given keys.
*/
Oid
get_opclass_proc(Oid opclass, Oid subtype, int16 procnum)
get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
{
HeapTuple tp;
Form_pg_amproc amproc_tup;
RegProcedure result;
tp = SearchSysCache(AMPROCNUM,
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(subtype),
Int16GetDatum(procnum),
0);
ObjectIdGetDatum(opfamily),
ObjectIdGetDatum(lefttype),
ObjectIdGetDatum(righttype),
Int16GetDatum(procnum));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
@ -477,17 +613,16 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
/* ---------- OPCLASS CACHE ---------- */
/*
* opclass_is_btree
* get_opclass_family
*
* Returns TRUE iff the specified opclass is associated with the
* btree index access method.
* Returns the OID of the operator family the opclass belongs to.
*/
bool
opclass_is_btree(Oid opclass)
Oid
get_opclass_family(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
bool result;
Oid result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
@ -496,57 +631,7 @@ opclass_is_btree(Oid opclass)
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = (cla_tup->opcamid == BTREE_AM_OID);
ReleaseSysCache(tp);
return result;
}
/*
* opclass_is_hash
*
* Returns TRUE iff the specified opclass is associated with the
* hash index access method.
*/
bool
opclass_is_hash(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
bool result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = (cla_tup->opcamid == HASH_AM_OID);
ReleaseSysCache(tp);
return result;
}
/*
* opclass_is_default
*
* Returns TRUE iff the specified opclass is the default for its
* index access method and input data type.
*/
bool
opclass_is_default(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
bool result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = cla_tup->opcdefault;
result = cla_tup->opcfamily;
ReleaseSysCache(tp);
return result;
}
@ -657,11 +742,13 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
/*
* op_mergejoinable
*
* Returns the left and right sort operators corresponding to a
* mergejoinable operator, or false if the operator is not mergejoinable.
* Returns true if the operator is potentially mergejoinable. (The planner
* will fail to find any mergejoin plans unless there are suitable btree
* opfamily entries for this operator and associated sortops. The pg_operator
* flag is just a hint to tell the planner whether to bother looking.)
*/
bool
op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
op_mergejoinable(Oid opno)
{
HeapTuple tp;
bool result = false;
@ -673,65 +760,17 @@ op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
if (optup->oprlsortop &&
optup->oprrsortop)
{
*leftOp = optup->oprlsortop;
*rightOp = optup->oprrsortop;
result = true;
}
result = optup->oprcanmerge;
ReleaseSysCache(tp);
}
return result;
}
/*
* op_mergejoin_crossops
*
* Returns the cross-type comparison operators (ltype "<" rtype and
* ltype ">" rtype) for an operator previously determined to be
* mergejoinable. Optionally, fetches the regproc ids of these
* operators, as well as their operator OIDs.
*/
void
op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
RegProcedure *ltproc, RegProcedure *gtproc)
{
HeapTuple tp;
Form_pg_operator optup;
/*
* Get the declared comparison operators of the operator.
*/
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for operator %u", opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
*ltop = optup->oprltcmpop;
*gtop = optup->oprgtcmpop;
ReleaseSysCache(tp);
/* Check < op provided */
if (!OidIsValid(*ltop))
elog(ERROR, "mergejoin operator %u has no matching < operator",
opno);
if (ltproc)
*ltproc = get_opcode(*ltop);
/* Check > op provided */
if (!OidIsValid(*gtop))
elog(ERROR, "mergejoin operator %u has no matching > operator",
opno);
if (gtproc)
*gtproc = get_opcode(*gtop);
}
/*
* op_hashjoinable
*
* Returns true if the operator is hashjoinable.
* Returns true if the operator is hashjoinable. (There must be a suitable
* hash opfamily entry for this operator if it is so marked.)
*/
bool
op_hashjoinable(Oid opno)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.250 2006/11/05 23:40:30 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.251 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -69,7 +69,7 @@
*/
#define RELCACHE_INIT_FILENAME "pg_internal.init"
#define RELCACHE_INIT_FILEMAGIC 0x573263 /* version ID value */
#define RELCACHE_INIT_FILEMAGIC 0x573264 /* version ID value */
/*
* hardcoded tuple descriptors. see include/catalog/pg_attribute.h
@ -159,7 +159,8 @@ do { \
/*
* Special cache for opclass-related information
*
* Note: only default-subtype operators and support procs get cached
* Note: only default operators and support procs get cached, ie, those with
* lefttype = righttype = opcintype.
*/
typedef struct opclasscacheent
{
@ -167,6 +168,8 @@ typedef struct opclasscacheent
bool valid; /* set TRUE after successful fill-in */
StrategyNumber numStrats; /* max # of strategies (from pg_am) */
StrategyNumber numSupport; /* max # of support procs (from pg_am) */
Oid opcfamily; /* OID of opclass's family */
Oid opcintype; /* OID of opclass's declared input type */
Oid *operatorOids; /* strategy operators' OIDs */
RegProcedure *supportProcs; /* support procs */
} OpClassCacheEnt;
@ -201,6 +204,8 @@ static List *insert_ordered_oid(List *list, Oid datum);
static void IndexSupportInitialize(oidvector *indclass,
Oid *indexOperator,
RegProcedure *indexSupport,
Oid *opFamily,
Oid *opcInType,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber);
@ -921,11 +926,9 @@ RelationInitIndexAccessInfo(Relation relation)
Form_pg_am aform;
Datum indclassDatum;
bool isnull;
oidvector *indclass;
MemoryContext indexcxt;
MemoryContext oldcontext;
Oid *operator;
RegProcedure *support;
FmgrInfo *supportinfo;
int natts;
uint16 amstrategies;
uint16 amsupport;
@ -947,18 +950,6 @@ RelationInitIndexAccessInfo(Relation relation)
MemoryContextSwitchTo(oldcontext);
ReleaseSysCache(tuple);
/*
* indclass cannot be referenced directly through the C struct, because it
* is after the variable-width indkey field. Therefore we extract the
* datum the hard way and provide a direct link in the relcache.
*/
indclassDatum = fastgetattr(relation->rd_indextuple,
Anum_pg_index_indclass,
GetPgIndexDescriptor(),
&isnull);
Assert(!isnull);
relation->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum);
/*
* Make a copy of the pg_am entry for the index's access method
*/
@ -1001,38 +992,53 @@ RelationInitIndexAccessInfo(Relation relation)
relation->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
relation->rd_opfamily = (Oid *)
MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
relation->rd_opcintype = (Oid *)
MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
if (amstrategies > 0)
operator = (Oid *)
relation->rd_operator = (Oid *)
MemoryContextAllocZero(indexcxt,
natts * amstrategies * sizeof(Oid));
else
operator = NULL;
relation->rd_operator = NULL;
if (amsupport > 0)
{
int nsupport = natts * amsupport;
support = (RegProcedure *)
relation->rd_support = (RegProcedure *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
supportinfo = (FmgrInfo *)
relation->rd_supportinfo = (FmgrInfo *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
}
else
{
support = NULL;
supportinfo = NULL;
relation->rd_support = NULL;
relation->rd_supportinfo = NULL;
}
relation->rd_operator = operator;
relation->rd_support = support;
relation->rd_supportinfo = supportinfo;
/*
* indclass cannot be referenced directly through the C struct, because it
* comes after the variable-width indkey field. Must extract the
* datum the hard way...
*/
indclassDatum = fastgetattr(relation->rd_indextuple,
Anum_pg_index_indclass,
GetPgIndexDescriptor(),
&isnull);
Assert(!isnull);
indclass = (oidvector *) DatumGetPointer(indclassDatum);
/*
* Fill the operator and support procedure OID arrays. (aminfo and
* Fill the operator and support procedure OID arrays, as well as the
* info about opfamilies and opclass input types. (aminfo and
* supportinfo are left as zeroes, and are filled on-the-fly when used)
*/
IndexSupportInitialize(relation->rd_indclass,
operator, support,
IndexSupportInitialize(indclass,
relation->rd_operator, relation->rd_support,
relation->rd_opfamily, relation->rd_opcintype,
amstrategies, amsupport, natts);
/*
@ -1048,8 +1054,8 @@ RelationInitIndexAccessInfo(Relation relation)
* Initializes an index's cached opclass information,
* given the index's pg_index.indclass entry.
*
* Data is returned into *indexOperator and *indexSupport, which are arrays
* allocated by the caller.
* Data is returned into *indexOperator, *indexSupport, *opFamily, and
* *opcInType, which are arrays allocated by the caller.
*
* The caller also passes maxStrategyNumber, maxSupportNumber, and
* maxAttributeNumber, since these indicate the size of the arrays
@ -1061,6 +1067,8 @@ static void
IndexSupportInitialize(oidvector *indclass,
Oid *indexOperator,
RegProcedure *indexSupport,
Oid *opFamily,
Oid *opcInType,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber)
@ -1080,6 +1088,8 @@ IndexSupportInitialize(oidvector *indclass,
maxSupportNumber);
/* copy cached data into relcache entry */
opFamily[attIndex] = opcentry->opcfamily;
opcInType[attIndex] = opcentry->opcintype;
if (maxStrategyNumber > 0)
memcpy(&indexOperator[attIndex * maxStrategyNumber],
opcentry->operatorOids,
@ -1116,7 +1126,7 @@ LookupOpclassInfo(Oid operatorClassOid,
bool found;
Relation rel;
SysScanDesc scan;
ScanKeyData skey[2];
ScanKeyData skey[3];
HeapTuple htup;
bool indexOK;
@ -1176,23 +1186,55 @@ LookupOpclassInfo(Oid operatorClassOid,
(operatorClassOid != OID_BTREE_OPS_OID &&
operatorClassOid != INT2_BTREE_OPS_OID);
/*
* We have to fetch the pg_opclass row to determine its opfamily and
* opcintype, which are needed to look up the operators and functions.
* It'd be convenient to use the syscache here, but that probably doesn't
* work while bootstrapping.
*/
ScanKeyInit(&skey[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(operatorClassOid));
rel = heap_open(OperatorClassRelationId, AccessShareLock);
scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
SnapshotNow, 1, skey);
if (HeapTupleIsValid(htup = systable_getnext(scan)))
{
Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
opcentry->opcfamily = opclassform->opcfamily;
opcentry->opcintype = opclassform->opcintype;
}
else
elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
systable_endscan(scan);
heap_close(rel, AccessShareLock);
/*
* Scan pg_amop to obtain operators for the opclass. We only fetch the
* default ones (those with subtype zero).
* default ones (those with lefttype = righttype = opcintype).
*/
if (numStrats > 0)
{
ScanKeyInit(&skey[0],
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopfamily,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(operatorClassOid));
ObjectIdGetDatum(opcentry->opcfamily));
ScanKeyInit(&skey[1],
Anum_pg_amop_amopsubtype,
Anum_pg_amop_amoplefttype,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(InvalidOid));
ObjectIdGetDatum(opcentry->opcintype));
ScanKeyInit(&skey[2],
Anum_pg_amop_amoprighttype,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(opcentry->opcintype));
rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,
SnapshotNow, 2, skey);
SnapshotNow, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan)))
{
@ -1212,21 +1254,25 @@ LookupOpclassInfo(Oid operatorClassOid,
/*
* Scan pg_amproc to obtain support procs for the opclass. We only fetch
* the default ones (those with subtype zero).
* the default ones (those with lefttype = righttype = opcintype).
*/
if (numSupport > 0)
{
ScanKeyInit(&skey[0],
Anum_pg_amproc_amopclaid,
Anum_pg_amproc_amprocfamily,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(operatorClassOid));
ObjectIdGetDatum(opcentry->opcfamily));
ScanKeyInit(&skey[1],
Anum_pg_amproc_amprocsubtype,
Anum_pg_amproc_amproclefttype,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(InvalidOid));
ObjectIdGetDatum(opcentry->opcintype));
ScanKeyInit(&skey[2],
Anum_pg_amproc_amprocrighttype,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(opcentry->opcintype));
rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
SnapshotNow, 2, skey);
SnapshotNow, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan)))
{
@ -3097,8 +3143,6 @@ load_relcache_init_file(void)
Relation rel;
Form_pg_class relform;
bool has_not_null;
Datum indclassDatum;
bool isnull;
/* first read the relation descriptor length */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
@ -3187,6 +3231,8 @@ load_relcache_init_file(void)
{
Form_pg_am am;
MemoryContext indexcxt;
Oid *opfamily;
Oid *opcintype;
Oid *operator;
RegProcedure *support;
int nsupport;
@ -3207,14 +3253,6 @@ load_relcache_init_file(void)
rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple);
/* fix up indclass pointer too */
indclassDatum = fastgetattr(rel->rd_indextuple,
Anum_pg_index_indclass,
GetPgIndexDescriptor(),
&isnull);
Assert(!isnull);
rel->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum);
/* next, read the access method tuple form */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
@ -3235,6 +3273,26 @@ load_relcache_init_file(void)
ALLOCSET_SMALL_MAXSIZE);
rel->rd_indexcxt = indexcxt;
/* next, read the vector of opfamily OIDs */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
if ((nread = fread(opfamily, 1, len, fp)) != len)
goto read_failed;
rel->rd_opfamily = opfamily;
/* next, read the vector of opcintype OIDs */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
if ((nread = fread(opcintype, 1, len, fp)) != len)
goto read_failed;
rel->rd_opcintype = opcintype;
/* next, read the vector of operator OIDs */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
@ -3269,10 +3327,11 @@ load_relcache_init_file(void)
Assert(rel->rd_index == NULL);
Assert(rel->rd_indextuple == NULL);
Assert(rel->rd_indclass == NULL);
Assert(rel->rd_am == NULL);
Assert(rel->rd_indexcxt == NULL);
Assert(rel->rd_aminfo == NULL);
Assert(rel->rd_opfamily == NULL);
Assert(rel->rd_opcintype == NULL);
Assert(rel->rd_operator == NULL);
Assert(rel->rd_support == NULL);
Assert(rel->rd_supportinfo == NULL);
@ -3450,6 +3509,16 @@ write_relcache_init_file(void)
/* next, write the access method tuple form */
write_item(am, sizeof(FormData_pg_am), fp);
/* next, write the vector of opfamily OIDs */
write_item(rel->rd_opfamily,
relform->relnatts * sizeof(Oid),
fp);
/* next, write the vector of opcintype OIDs */
write_item(rel->rd_opcintype,
relform->relnatts * sizeof(Oid),
fp);
/* next, write the vector of operator OIDs */
write_item(rel->rd_operator,
relform->relnatts * (am->amstrategies * sizeof(Oid)),

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.108 2006/10/06 18:23:35 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.109 2006/12/23 00:43:11 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@ -30,11 +30,11 @@
#include "catalog/pg_cast.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h"
@ -135,7 +135,7 @@ static const struct cachedesc cacheinfo[] = {
2,
{
Anum_pg_amop_amopopr,
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopfamily,
0,
0
},
@ -144,24 +144,24 @@ static const struct cachedesc cacheinfo[] = {
{AccessMethodOperatorRelationId, /* AMOPSTRATEGY */
AccessMethodStrategyIndexId,
0,
3,
4,
{
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopsubtype,
Anum_pg_amop_amopstrategy,
0
Anum_pg_amop_amopfamily,
Anum_pg_amop_amoplefttype,
Anum_pg_amop_amoprighttype,
Anum_pg_amop_amopstrategy
},
64
},
{AccessMethodProcedureRelationId, /* AMPROCNUM */
AccessMethodProcedureIndexId,
0,
3,
4,
{
Anum_pg_amproc_amopclaid,
Anum_pg_amproc_amprocsubtype,
Anum_pg_amproc_amprocnum,
0
Anum_pg_amproc_amprocfamily,
Anum_pg_amproc_amproclefttype,
Anum_pg_amproc_amprocrighttype,
Anum_pg_amproc_amprocnum
},
64
},
@ -255,7 +255,7 @@ static const struct cachedesc cacheinfo[] = {
0,
3,
{
Anum_pg_opclass_opcamid,
Anum_pg_opclass_opcmethod,
Anum_pg_opclass_opcname,
Anum_pg_opclass_opcnamespace,
0
@ -334,18 +334,6 @@ static const struct cachedesc cacheinfo[] = {
},
1024
},
{InheritsRelationId, /* INHRELID */
InheritsRelidSeqnoIndexId,
Anum_pg_inherits_inhrelid,
2,
{
Anum_pg_inherits_inhrelid,
Anum_pg_inherits_inhseqno,
0,
0
},
256
},
{LanguageRelationId, /* LANGNAME */
LanguageNameIndexId,
0,
@ -418,6 +406,30 @@ static const struct cachedesc cacheinfo[] = {
},
1024
},
{OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */
OpfamilyAmNameNspIndexId,
0,
3,
{
Anum_pg_opfamily_opfmethod,
Anum_pg_opfamily_opfname,
Anum_pg_opfamily_opfnamespace,
0
},
64
},
{OperatorFamilyRelationId, /* OPFAMILYOID */
OpfamilyOidIndexId,
0,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
},
64
},
{ProcedureRelationId, /* PROCNAMEARGSNSP */
ProcedureNameArgsNspIndexId,
0,

View File

@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.22 2006/10/04 00:30:01 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.23 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -165,17 +165,30 @@ lookup_type_cache(Oid type_id, int flags)
/* If we haven't already found the opclass, try to do so */
if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR |
TYPECACHE_CMP_PROC |
TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO)) &&
typentry->btree_opc == InvalidOid)
TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO |
TYPECACHE_BTREE_OPFAMILY)) &&
typentry->btree_opf == InvalidOid)
{
typentry->btree_opc = GetDefaultOpClass(type_id,
BTREE_AM_OID);
/* Only care about hash opclass if no btree opclass... */
if (typentry->btree_opc == InvalidOid)
Oid opclass;
opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
if (OidIsValid(opclass))
{
if (typentry->hash_opc == InvalidOid)
typentry->hash_opc = GetDefaultOpClass(type_id,
HASH_AM_OID);
typentry->btree_opf = get_opclass_family(opclass);
typentry->btree_opintype = get_opclass_input_type(opclass);
}
/* Only care about hash opclass if no btree opclass... */
if (typentry->btree_opf == InvalidOid)
{
if (typentry->hash_opf == InvalidOid)
{
opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
if (OidIsValid(opclass))
{
typentry->hash_opf = get_opclass_family(opclass);
typentry->hash_opintype = get_opclass_input_type(opclass);
}
}
}
else
{
@ -193,37 +206,42 @@ lookup_type_cache(Oid type_id, int flags)
if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
typentry->eq_opr == InvalidOid)
{
if (typentry->btree_opc != InvalidOid)
typentry->eq_opr = get_opclass_member(typentry->btree_opc,
InvalidOid,
BTEqualStrategyNumber);
if (typentry->btree_opf != InvalidOid)
typentry->eq_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
BTEqualStrategyNumber);
if (typentry->eq_opr == InvalidOid &&
typentry->hash_opc != InvalidOid)
typentry->eq_opr = get_opclass_member(typentry->hash_opc,
InvalidOid,
HTEqualStrategyNumber);
typentry->hash_opf != InvalidOid)
typentry->eq_opr = get_opfamily_member(typentry->hash_opf,
typentry->hash_opintype,
typentry->hash_opintype,
HTEqualStrategyNumber);
}
if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
{
if (typentry->btree_opc != InvalidOid)
typentry->lt_opr = get_opclass_member(typentry->btree_opc,
InvalidOid,
BTLessStrategyNumber);
if (typentry->btree_opf != InvalidOid)
typentry->lt_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
BTLessStrategyNumber);
}
if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
{
if (typentry->btree_opc != InvalidOid)
typentry->gt_opr = get_opclass_member(typentry->btree_opc,
InvalidOid,
BTGreaterStrategyNumber);
if (typentry->btree_opf != InvalidOid)
typentry->gt_opr = get_opfamily_member(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
BTGreaterStrategyNumber);
}
if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
typentry->cmp_proc == InvalidOid)
{
if (typentry->btree_opc != InvalidOid)
typentry->cmp_proc = get_opclass_proc(typentry->btree_opc,
InvalidOid,
BTORDER_PROC);
if (typentry->btree_opf != InvalidOid)
typentry->cmp_proc = get_opfamily_proc(typentry->btree_opf,
typentry->btree_opintype,
typentry->btree_opintype,
BTORDER_PROC);
}
/*

View File

@ -91,7 +91,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.70 2006/10/04 00:30:04 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.71 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -2104,15 +2104,16 @@ SelectSortFunction(Oid sortOperator,
int i;
HeapTuple tuple;
Form_pg_operator optup;
Oid opclass = InvalidOid;
Oid opfamily = InvalidOid;
Oid opinputtype = InvalidOid;
/*
* Search pg_amop to see if the target operator is registered as the "<"
* or ">" operator of any btree opclass. It's possible that it might be
* Search pg_amop to see if the target operator is registered as a "<"
* or ">" operator of any btree opfamily. It's possible that it might be
* registered both ways (eg, if someone were to build a "reverse sort"
* opclass for some reason); prefer the "<" case if so. If the operator is
* registered the same way in multiple opclasses, assume we can use the
* associated comparator function from any one.
* opfamily); prefer the "<" case if so. If the operator is registered the
* same way in multiple opfamilies, assume we can use the associated
* comparator function from any one.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(sortOperator),
@ -2125,21 +2126,24 @@ SelectSortFunction(Oid sortOperator,
tuple = &catlist->members[i]->tuple;
aform = (Form_pg_amop) GETSTRUCT(tuple);
if (!opclass_is_btree(aform->amopclaid))
/* must be btree */
if (aform->amopmethod != BTREE_AM_OID)
continue;
/* must be of default subtype, too */
if (aform->amopsubtype != InvalidOid)
/* mustn't be cross-datatype, either */
if (aform->amoplefttype != aform->amoprighttype)
continue;
if (aform->amopstrategy == BTLessStrategyNumber)
{
opclass = aform->amopclaid;
opfamily = aform->amopfamily;
opinputtype = aform->amoplefttype;
*kind = SORTFUNC_CMP;
break; /* done looking */
}
else if (aform->amopstrategy == BTGreaterStrategyNumber)
{
opclass = aform->amopclaid;
opfamily = aform->amopfamily;
opinputtype = aform->amoplefttype;
*kind = SORTFUNC_REVCMP;
/* keep scanning in hopes of finding a BTLess entry */
}
@ -2147,10 +2151,13 @@ SelectSortFunction(Oid sortOperator,
ReleaseSysCacheList(catlist);
if (OidIsValid(opclass))
if (OidIsValid(opfamily))
{
/* Found a suitable opclass, get its default comparator function */
*sortFunction = get_opclass_proc(opclass, InvalidOid, BTORDER_PROC);
/* Found a suitable opfamily, get the matching comparator function */
*sortFunction = get_opfamily_proc(opfamily,
opinputtype,
opinputtype,
BTORDER_PROC);
Assert(RegProcedureIsValid(*sortFunction));
return;
}

View File

@ -42,7 +42,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
* Portions taken from FreeBSD.
*
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.125 2006/10/04 18:58:08 tgl Exp $
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.126 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1590,7 +1590,8 @@ setup_depend(void)
* dependencies seems hard.
*
* Note that we deliberately do not pin the system views, which
* haven't been created yet.
* haven't been created yet. Also, no conversions, databases,
* or tablespaces are pinned.
*
* First delete any already-made entries; PINs override all else, and
* must be the only entries for their objects.
@ -1619,6 +1620,12 @@ setup_depend(void)
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_opclass;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_opfamily;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_amop;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_amproc;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_rewrite;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_trigger;\n",

View File

@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.453 2006/10/09 23:36:59 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.454 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -6219,11 +6219,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
int i_oprnegate;
int i_oprrest;
int i_oprjoin;
int i_oprcanmerge;
int i_oprcanhash;
int i_oprlsortop;
int i_oprrsortop;
int i_oprltcmpop;
int i_oprgtcmpop;
char *oprkind;
char *oprcode;
char *oprleft;
@ -6232,11 +6229,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
char *oprnegate;
char *oprrest;
char *oprjoin;
char *oprcanmerge;
char *oprcanhash;
char *oprlsortop;
char *oprrsortop;
char *oprltcmpop;
char *oprgtcmpop;
/* Skip if not to be dumped */
if (!oprinfo->dobj.dump || dataOnly)
@ -6258,7 +6252,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
/* Make sure we are in proper schema so regoperator works correctly */
selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
if (g_fout->remoteVersion >= 70300)
if (g_fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT oprkind, "
"oprcode::pg_catalog.regprocedure, "
@ -6268,11 +6262,23 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
"oprnegate::pg_catalog.regoperator, "
"oprrest::pg_catalog.regprocedure, "
"oprjoin::pg_catalog.regprocedure, "
"oprcanhash, "
"oprlsortop::pg_catalog.regoperator, "
"oprrsortop::pg_catalog.regoperator, "
"oprltcmpop::pg_catalog.regoperator, "
"oprgtcmpop::pg_catalog.regoperator "
"oprcanmerge, oprcanhash "
"from pg_catalog.pg_operator "
"where oid = '%u'::pg_catalog.oid",
oprinfo->dobj.catId.oid);
}
else if (g_fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query, "SELECT oprkind, "
"oprcode::pg_catalog.regprocedure, "
"oprleft::pg_catalog.regtype, "
"oprright::pg_catalog.regtype, "
"oprcom::pg_catalog.regoperator, "
"oprnegate::pg_catalog.regoperator, "
"oprrest::pg_catalog.regprocedure, "
"oprjoin::pg_catalog.regprocedure, "
"(oprlsortop != 0) as oprcanmerge, "
"oprcanhash "
"from pg_catalog.pg_operator "
"where oid = '%u'::pg_catalog.oid",
oprinfo->dobj.catId.oid);
@ -6285,8 +6291,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
"CASE WHEN oprright = 0 THEN '-' "
"ELSE format_type(oprright, NULL) END as oprright, "
"oprcom, oprnegate, oprrest, oprjoin, "
"oprcanhash, oprlsortop, oprrsortop, "
"0 as oprltcmpop, 0 as oprgtcmpop "
"(oprlsortop != 0) as oprcanmerge, "
"oprcanhash "
"from pg_operator "
"where oid = '%u'::oid",
oprinfo->dobj.catId.oid);
@ -6299,8 +6305,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
"CASE WHEN oprright = 0 THEN '-'::name "
"ELSE (select typname from pg_type where oid = oprright) END as oprright, "
"oprcom, oprnegate, oprrest, oprjoin, "
"oprcanhash, oprlsortop, oprrsortop, "
"0 as oprltcmpop, 0 as oprgtcmpop "
"(oprlsortop != 0) as oprcanmerge, "
"oprcanhash "
"from pg_operator "
"where oid = '%u'::oid",
oprinfo->dobj.catId.oid);
@ -6326,11 +6332,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
i_oprnegate = PQfnumber(res, "oprnegate");
i_oprrest = PQfnumber(res, "oprrest");
i_oprjoin = PQfnumber(res, "oprjoin");
i_oprcanmerge = PQfnumber(res, "oprcanmerge");
i_oprcanhash = PQfnumber(res, "oprcanhash");
i_oprlsortop = PQfnumber(res, "oprlsortop");
i_oprrsortop = PQfnumber(res, "oprrsortop");
i_oprltcmpop = PQfnumber(res, "oprltcmpop");
i_oprgtcmpop = PQfnumber(res, "oprgtcmpop");
oprkind = PQgetvalue(res, 0, i_oprkind);
oprcode = PQgetvalue(res, 0, i_oprcode);
@ -6340,11 +6343,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
oprnegate = PQgetvalue(res, 0, i_oprnegate);
oprrest = PQgetvalue(res, 0, i_oprrest);
oprjoin = PQgetvalue(res, 0, i_oprjoin);
oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
oprlsortop = PQgetvalue(res, 0, i_oprlsortop);
oprrsortop = PQgetvalue(res, 0, i_oprrsortop);
oprltcmpop = PQgetvalue(res, 0, i_oprltcmpop);
oprgtcmpop = PQgetvalue(res, 0, i_oprgtcmpop);
appendPQExpBuffer(details, " PROCEDURE = %s",
convertRegProcReference(oprcode));
@ -6390,6 +6390,9 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
if (name)
appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
if (strcmp(oprcanmerge, "t") == 0)
appendPQExpBuffer(details, ",\n MERGES");
if (strcmp(oprcanhash, "t") == 0)
appendPQExpBuffer(details, ",\n HASHES");
@ -6401,22 +6404,6 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
if (name)
appendPQExpBuffer(details, ",\n JOIN = %s", name);
name = convertOperatorReference(oprlsortop);
if (name)
appendPQExpBuffer(details, ",\n SORT1 = %s", name);
name = convertOperatorReference(oprrsortop);
if (name)
appendPQExpBuffer(details, ",\n SORT2 = %s", name);
name = convertOperatorReference(oprltcmpop);
if (name)
appendPQExpBuffer(details, ",\n LTCMP = %s", name);
name = convertOperatorReference(oprgtcmpop);
if (name)
appendPQExpBuffer(details, ",\n GTCMP = %s", name);
/*
* DROP must be fully qualified in case same name appears in pg_catalog
*/
@ -6608,13 +6595,26 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
/* Get additional fields from the pg_opclass row */
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
"opckeytype::pg_catalog.regtype, "
"opcdefault, "
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
"FROM pg_catalog.pg_opclass "
"WHERE oid = '%u'::pg_catalog.oid",
opcinfo->dobj.catId.oid);
if (g_fout->remoteVersion >= 80300)
{
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
"opckeytype::pg_catalog.regtype, "
"opcdefault, "
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
"FROM pg_catalog.pg_opclass "
"WHERE oid = '%u'::pg_catalog.oid",
opcinfo->dobj.catId.oid);
}
else
{
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
"opckeytype::pg_catalog.regtype, "
"opcdefault, "
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
"FROM pg_catalog.pg_opclass "
"WHERE oid = '%u'::pg_catalog.oid",
opcinfo->dobj.catId.oid);
}
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@ -6674,12 +6674,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
*/
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
"amopopr::pg_catalog.regoperator "
"FROM pg_catalog.pg_amop "
"WHERE amopclaid = '%u'::pg_catalog.oid "
"ORDER BY amopstrategy",
opcinfo->dobj.catId.oid);
if (g_fout->remoteVersion >= 80300)
{
/*
* Print only those opfamily members that are tied to the opclass
* by pg_depend entries.
*/
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
"amopopr::pg_catalog.regoperator "
"FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
"WHERE refclassid = 'pg_catalog.pg_opclass'::regclass "
"AND refobjid = '%u'::pg_catalog.oid "
"AND classid = 'pg_catalog.pg_amop'::regclass "
"AND objid = ao.oid "
"ORDER BY amopstrategy",
opcinfo->dobj.catId.oid);
}
else
{
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
"amopopr::pg_catalog.regoperator "
"FROM pg_catalog.pg_amop "
"WHERE amopclaid = '%u'::pg_catalog.oid "
"ORDER BY amopstrategy",
opcinfo->dobj.catId.oid);
}
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@ -6714,12 +6733,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
*/
resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT amprocnum, "
"amproc::pg_catalog.regprocedure "
"FROM pg_catalog.pg_amproc "
"WHERE amopclaid = '%u'::pg_catalog.oid "
"ORDER BY amprocnum",
opcinfo->dobj.catId.oid);
if (g_fout->remoteVersion >= 80300)
{
/*
* Print only those opfamily members that are tied to the opclass
* by pg_depend entries.
*/
appendPQExpBuffer(query, "SELECT amprocnum, "
"amproc::pg_catalog.regprocedure "
"FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
"WHERE refclassid = 'pg_catalog.pg_opclass'::regclass "
"AND refobjid = '%u'::pg_catalog.oid "
"AND classid = 'pg_catalog.pg_amproc'::regclass "
"AND objid = ap.oid "
"ORDER BY amprocnum",
opcinfo->dobj.catId.oid);
}
else
{
appendPQExpBuffer(query, "SELECT amprocnum, "
"amproc::pg_catalog.regprocedure "
"FROM pg_catalog.pg_amproc "
"WHERE amopclaid = '%u'::pg_catalog.oid "
"ORDER BY amprocnum",
opcinfo->dobj.catId.oid);
}
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.364 2006/12/21 18:32:56 petere Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.365 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200612201
#define CATALOG_VERSION_NO 200612221
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.27 2006/08/21 00:57:26 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.28 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -131,6 +131,9 @@ typedef enum ObjectClass
OCLASS_LANGUAGE, /* pg_language */
OCLASS_OPERATOR, /* pg_operator */
OCLASS_OPCLASS, /* pg_opclass */
OCLASS_OPFAMILY, /* pg_opfamily */
OCLASS_AMOP, /* pg_amop */
OCLASS_AMPROC, /* pg_amproc */
OCLASS_REWRITE, /* pg_rewrite */
OCLASS_TRIGGER, /* pg_trigger */
OCLASS_SCHEMA, /* pg_namespace */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.95 2006/07/13 17:47:01 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.96 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -65,13 +65,17 @@ DECLARE_UNIQUE_INDEX(pg_am_name_index, 2651, on pg_am using btree(amname name_op
DECLARE_UNIQUE_INDEX(pg_am_oid_index, 2652, on pg_am using btree(oid oid_ops));
#define AmOidIndexId 2652
DECLARE_UNIQUE_INDEX(pg_amop_opc_strat_index, 2653, on pg_amop using btree(amopclaid oid_ops, amopsubtype oid_ops, amopstrategy int2_ops));
DECLARE_UNIQUE_INDEX(pg_amop_fam_strat_index, 2653, on pg_amop using btree(amopfamily oid_ops, amoplefttype oid_ops, amoprighttype oid_ops, amopstrategy int2_ops));
#define AccessMethodStrategyIndexId 2653
DECLARE_UNIQUE_INDEX(pg_amop_opr_opc_index, 2654, on pg_amop using btree(amopopr oid_ops, amopclaid oid_ops));
DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amopfamily oid_ops));
#define AccessMethodOperatorIndexId 2654
DECLARE_UNIQUE_INDEX(pg_amop_oid_index, 2756, on pg_amop using btree(oid oid_ops));
#define AccessMethodOperatorOidIndexId 2756
DECLARE_UNIQUE_INDEX(pg_amproc_opc_proc_index, 2655, on pg_amproc using btree(amopclaid oid_ops, amprocsubtype oid_ops, amprocnum int2_ops));
DECLARE_UNIQUE_INDEX(pg_amproc_fam_proc_index, 2655, on pg_amproc using btree(amprocfamily oid_ops, amproclefttype oid_ops, amprocrighttype oid_ops, amprocnum int2_ops));
#define AccessMethodProcedureIndexId 2655
DECLARE_UNIQUE_INDEX(pg_amproc_oid_index, 2757, on pg_amproc using btree(oid oid_ops));
#define AccessMethodProcedureOidIndexId 2757
DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops));
#define AttrDefaultIndexId 2656
@ -164,7 +168,7 @@ DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btr
DECLARE_UNIQUE_INDEX(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops));
#define NamespaceOidIndexId 2685
DECLARE_UNIQUE_INDEX(pg_opclass_am_name_nsp_index, 2686, on pg_opclass using btree(opcamid oid_ops, opcname name_ops, opcnamespace oid_ops));
DECLARE_UNIQUE_INDEX(pg_opclass_am_name_nsp_index, 2686, on pg_opclass using btree(opcmethod oid_ops, opcname name_ops, opcnamespace oid_ops));
#define OpclassAmNameNspIndexId 2686
DECLARE_UNIQUE_INDEX(pg_opclass_oid_index, 2687, on pg_opclass using btree(oid oid_ops));
#define OpclassOidIndexId 2687
@ -174,6 +178,11 @@ DECLARE_UNIQUE_INDEX(pg_operator_oid_index, 2688, on pg_operator using btree(oid
DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index, 2689, on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops));
#define OperatorNameNspIndexId 2689
DECLARE_UNIQUE_INDEX(pg_opfamily_am_name_nsp_index, 2754, on pg_opfamily using btree(opfmethod oid_ops, opfname name_ops, opfnamespace oid_ops));
#define OpfamilyAmNameNspIndexId 2754
DECLARE_UNIQUE_INDEX(pg_opfamily_oid_index, 2755, on pg_opfamily using btree(oid oid_ops));
#define OpfamilyOidIndexId 2755
DECLARE_UNIQUE_INDEX(pg_pltemplate_name_index, 1137, on pg_pltemplate using btree(tmplname name_ops));
#define PLTemplateNameIndexId 1137

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.42 2006/05/01 23:22:43 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.43 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -51,6 +51,9 @@ extern bool OperatorIsVisible(Oid oprid);
extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname);
extern bool OpclassIsVisible(Oid opcid);
extern Oid OpfamilynameGetOpfid(Oid amid, const char *opfname);
extern bool OpfamilyIsVisible(Oid opfid);
extern Oid ConversionGetConid(const char *conname);
extern bool ConversionIsVisible(Oid conid);

File diff suppressed because it is too large Load Diff

View File

@ -5,21 +5,24 @@
* along with the relation's initial contents.
*
* The amproc table identifies support procedures associated with index
* opclasses. These procedures can't be listed in pg_amop since they are
* not the implementation of any indexable operator for the opclass.
* operator families and classes. These procedures can't be listed in pg_amop
* since they are not the implementation of any indexable operator.
*
* The primary key for this table is <amopclaid, amprocsubtype, amprocnum>.
* amprocsubtype is equal to zero for an opclass's "default" procedures.
* Usually a nondefault amprocsubtype indicates a support procedure to be
* used with operators having the same nondefault amopsubtype. The exact
* behavior depends on the index AM, however, and some don't pay attention
* to subtype at all.
* The primary key for this table is <amprocfamily, amproclefttype,
* amprocrighttype, amprocnum>. The "default" support functions for a
* particular opclass within the family are those with amproclefttype =
* amprocrighttype = opclass's opcintype. These are the ones loaded into the
* relcache for an index and typically used for internal index operations.
* Other support functions are typically used to handle cross-type indexable
* operators with oprleft/oprright matching the entry's amproclefttype and
* amprocrighttype. The exact behavior depends on the index AM, however, and
* some don't pay attention to non-default functions at all.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.60 2006/10/04 00:30:07 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.61 2006/12/23 00:43:12 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -44,12 +47,13 @@
*/
#define AccessMethodProcedureRelationId 2603
CATALOG(pg_amproc,2603) BKI_WITHOUT_OIDS
CATALOG(pg_amproc,2603)
{
Oid amopclaid; /* the index opclass this entry is for */
Oid amprocsubtype; /* procedure subtype, or zero if default */
int2 amprocnum; /* support procedure index */
regproc amproc; /* OID of the proc */
Oid amprocfamily; /* the index opfamily this entry is for */
Oid amproclefttype; /* procedure's left input data type */
Oid amprocrighttype; /* procedure's right input data type */
int2 amprocnum; /* support procedure index */
regproc amproc; /* OID of the proc */
} FormData_pg_amproc;
/* ----------------
@ -63,11 +67,12 @@ typedef FormData_pg_amproc *Form_pg_amproc;
* compiler constants for pg_amproc
* ----------------
*/
#define Natts_pg_amproc 4
#define Anum_pg_amproc_amopclaid 1
#define Anum_pg_amproc_amprocsubtype 2
#define Anum_pg_amproc_amprocnum 3
#define Anum_pg_amproc_amproc 4
#define Natts_pg_amproc 5
#define Anum_pg_amproc_amprocfamily 1
#define Anum_pg_amproc_amproclefttype 2
#define Anum_pg_amproc_amprocrighttype 3
#define Anum_pg_amproc_amprocnum 4
#define Anum_pg_amproc_amproc 5
/* ----------------
* initial contents of pg_amproc
@ -75,237 +80,223 @@ typedef FormData_pg_amproc *Form_pg_amproc;
*/
/* btree */
DATA(insert ( 397 0 1 382 ));
DATA(insert ( 421 0 1 357 ));
DATA(insert ( 423 0 1 1596 ));
DATA(insert ( 424 0 1 1693 ));
DATA(insert ( 426 0 1 1078 ));
DATA(insert ( 428 0 1 1954 ));
DATA(insert ( 429 0 1 358 ));
DATA(insert ( 432 0 1 926 ));
DATA(insert ( 434 0 1 1092 ));
DATA(insert ( 434 1114 1 2344 ));
DATA(insert ( 434 1184 1 2357 ));
DATA(insert ( 1970 0 1 354 ));
DATA(insert ( 1970 701 1 2194 ));
DATA(insert ( 1972 0 1 355 ));
DATA(insert ( 1972 700 1 2195 ));
DATA(insert ( 1974 0 1 926 ));
DATA(insert ( 1976 0 1 350 ));
DATA(insert ( 1976 23 1 2190 ));
DATA(insert ( 1976 20 1 2192 ));
DATA(insert ( 1978 0 1 351 ));
DATA(insert ( 1978 20 1 2188 ));
DATA(insert ( 1978 21 1 2191 ));
DATA(insert ( 1980 0 1 842 ));
DATA(insert ( 1980 23 1 2189 ));
DATA(insert ( 1980 21 1 2193 ));
DATA(insert ( 1982 0 1 1315 ));
DATA(insert ( 1984 0 1 836 ));
DATA(insert ( 1986 0 1 359 ));
DATA(insert ( 1988 0 1 1769 ));
DATA(insert ( 1989 0 1 356 ));
DATA(insert ( 1991 0 1 404 ));
DATA(insert ( 1994 0 1 360 ));
DATA(insert ( 1996 0 1 1107 ));
DATA(insert ( 1998 0 1 1314 ));
DATA(insert ( 1998 1082 1 2383 ));
DATA(insert ( 1998 1114 1 2533 ));
DATA(insert ( 2000 0 1 1358 ));
DATA(insert ( 2002 0 1 1672 ));
DATA(insert ( 2003 0 1 360 ));
DATA(insert ( 2039 0 1 2045 ));
DATA(insert ( 2039 1082 1 2370 ));
DATA(insert ( 2039 1184 1 2526 ));
DATA(insert ( 2095 0 1 2166 ));
DATA(insert ( 2096 0 1 2166 ));
DATA(insert ( 2097 0 1 2180 ));
DATA(insert ( 2098 0 1 2187 ));
DATA(insert ( 2099 0 1 377 ));
DATA(insert ( 2233 0 1 380 ));
DATA(insert ( 2234 0 1 381 ));
DATA(insert ( 2789 0 1 2794 ));
DATA(insert ( 397 2277 2277 1 382 ));
DATA(insert ( 421 702 702 1 357 ));
DATA(insert ( 423 1560 1560 1 1596 ));
DATA(insert ( 424 16 16 1 1693 ));
DATA(insert ( 426 1042 1042 1 1078 ));
DATA(insert ( 428 17 17 1 1954 ));
DATA(insert ( 429 18 18 1 358 ));
DATA(insert ( 434 1082 1082 1 1092 ));
DATA(insert ( 434 1082 1114 1 2344 ));
DATA(insert ( 434 1082 1184 1 2357 ));
DATA(insert ( 434 1114 1114 1 2045 ));
DATA(insert ( 434 1114 1082 1 2370 ));
DATA(insert ( 434 1114 1184 1 2526 ));
DATA(insert ( 434 1184 1184 1 1314 ));
DATA(insert ( 434 1184 1082 1 2383 ));
DATA(insert ( 434 1184 1114 1 2533 ));
DATA(insert ( 1970 700 700 1 354 ));
DATA(insert ( 1970 700 701 1 2194 ));
DATA(insert ( 1970 701 701 1 355 ));
DATA(insert ( 1970 701 700 1 2195 ));
DATA(insert ( 1974 869 869 1 926 ));
DATA(insert ( 1976 21 21 1 350 ));
DATA(insert ( 1976 21 23 1 2190 ));
DATA(insert ( 1976 21 20 1 2192 ));
DATA(insert ( 1976 23 23 1 351 ));
DATA(insert ( 1976 23 20 1 2188 ));
DATA(insert ( 1976 23 21 1 2191 ));
DATA(insert ( 1976 20 20 1 842 ));
DATA(insert ( 1976 20 23 1 2189 ));
DATA(insert ( 1976 20 21 1 2193 ));
DATA(insert ( 1982 1186 1186 1 1315 ));
DATA(insert ( 1984 829 829 1 836 ));
DATA(insert ( 1986 19 19 1 359 ));
DATA(insert ( 1988 1700 1700 1 1769 ));
DATA(insert ( 1989 26 26 1 356 ));
DATA(insert ( 1991 30 30 1 404 ));
DATA(insert ( 1994 25 25 1 360 ));
DATA(insert ( 1996 1083 1083 1 1107 ));
DATA(insert ( 2000 1266 1266 1 1358 ));
DATA(insert ( 2002 1562 1562 1 1672 ));
DATA(insert ( 2095 25 25 1 2166 ));
DATA(insert ( 2097 1042 1042 1 2180 ));
DATA(insert ( 2098 19 19 1 2187 ));
DATA(insert ( 2099 790 790 1 377 ));
DATA(insert ( 2233 703 703 1 380 ));
DATA(insert ( 2234 704 704 1 381 ));
DATA(insert ( 2789 27 27 1 2794 ));
/* hash */
DATA(insert ( 427 0 1 1080 ));
DATA(insert ( 431 0 1 454 ));
DATA(insert ( 433 0 1 422 ));
DATA(insert ( 435 0 1 450 ));
DATA(insert ( 1971 0 1 451 ));
DATA(insert ( 1973 0 1 452 ));
DATA(insert ( 1975 0 1 422 ));
DATA(insert ( 1977 0 1 449 ));
DATA(insert ( 1979 0 1 450 ));
DATA(insert ( 1981 0 1 949 ));
DATA(insert ( 1983 0 1 1697 ));
DATA(insert ( 1985 0 1 399 ));
DATA(insert ( 1987 0 1 455 ));
DATA(insert ( 1990 0 1 453 ));
DATA(insert ( 1992 0 1 457 ));
DATA(insert ( 1995 0 1 400 ));
DATA(insert ( 1997 0 1 452 ));
DATA(insert ( 1999 0 1 452 ));
DATA(insert ( 2001 0 1 1696 ));
DATA(insert ( 2004 0 1 400 ));
DATA(insert ( 2040 0 1 452 ));
DATA(insert ( 2222 0 1 454 ));
DATA(insert ( 2223 0 1 456 ));
DATA(insert ( 2224 0 1 398 ));
DATA(insert ( 2225 0 1 450 ));
DATA(insert ( 2226 0 1 450 ));
DATA(insert ( 2227 0 1 450 ));
DATA(insert ( 2228 0 1 450 ));
DATA(insert ( 2229 0 1 456 ));
DATA(insert ( 2230 0 1 456 ));
DATA(insert ( 2231 0 1 456 ));
DATA(insert ( 2232 0 1 455 ));
DATA(insert ( 2235 0 1 329 ));
DATA(insert ( 427 1042 1042 1 1080 ));
DATA(insert ( 431 18 18 1 454 ));
DATA(insert ( 435 1082 1082 1 450 ));
DATA(insert ( 1971 700 700 1 451 ));
DATA(insert ( 1971 701 701 1 452 ));
DATA(insert ( 1975 869 869 1 422 ));
DATA(insert ( 1977 21 21 1 449 ));
DATA(insert ( 1977 23 23 1 450 ));
DATA(insert ( 1977 20 20 1 949 ));
DATA(insert ( 1983 1186 1186 1 1697 ));
DATA(insert ( 1985 829 829 1 399 ));
DATA(insert ( 1987 19 19 1 455 ));
DATA(insert ( 1990 26 26 1 453 ));
DATA(insert ( 1992 30 30 1 457 ));
DATA(insert ( 1995 25 25 1 400 ));
DATA(insert ( 1997 1083 1083 1 452 ));
DATA(insert ( 1999 1184 1184 1 452 ));
DATA(insert ( 2001 1266 1266 1 1696 ));
DATA(insert ( 2040 1114 1114 1 452 ));
DATA(insert ( 2222 16 16 1 454 ));
DATA(insert ( 2223 17 17 1 456 ));
DATA(insert ( 2224 22 22 1 398 ));
DATA(insert ( 2225 28 28 1 450 ));
DATA(insert ( 2226 29 29 1 450 ));
DATA(insert ( 2227 702 702 1 450 ));
DATA(insert ( 2228 703 703 1 450 ));
DATA(insert ( 2229 25 25 1 456 ));
DATA(insert ( 2231 1042 1042 1 456 ));
DATA(insert ( 2232 19 19 1 455 ));
DATA(insert ( 2235 1033 1033 1 329 ));
/* gist */
DATA(insert ( 2593 0 1 2578 ));
DATA(insert ( 2593 0 2 2583 ));
DATA(insert ( 2593 0 3 2579 ));
DATA(insert ( 2593 0 4 2580 ));
DATA(insert ( 2593 0 5 2581 ));
DATA(insert ( 2593 0 6 2582 ));
DATA(insert ( 2593 0 7 2584 ));
DATA(insert ( 2594 0 1 2585 ));
DATA(insert ( 2594 0 2 2583 ));
DATA(insert ( 2594 0 3 2586 ));
DATA(insert ( 2594 0 4 2580 ));
DATA(insert ( 2594 0 5 2581 ));
DATA(insert ( 2594 0 6 2582 ));
DATA(insert ( 2594 0 7 2584 ));
DATA(insert ( 2595 0 1 2591 ));
DATA(insert ( 2595 0 2 2583 ));
DATA(insert ( 2595 0 3 2592 ));
DATA(insert ( 2595 0 4 2580 ));
DATA(insert ( 2595 0 5 2581 ));
DATA(insert ( 2595 0 6 2582 ));
DATA(insert ( 2595 0 7 2584 ));
DATA(insert ( 2593 603 603 1 2578 ));
DATA(insert ( 2593 603 603 2 2583 ));
DATA(insert ( 2593 603 603 3 2579 ));
DATA(insert ( 2593 603 603 4 2580 ));
DATA(insert ( 2593 603 603 5 2581 ));
DATA(insert ( 2593 603 603 6 2582 ));
DATA(insert ( 2593 603 603 7 2584 ));
DATA(insert ( 2594 604 604 1 2585 ));
DATA(insert ( 2594 604 604 2 2583 ));
DATA(insert ( 2594 604 604 3 2586 ));
DATA(insert ( 2594 604 604 4 2580 ));
DATA(insert ( 2594 604 604 5 2581 ));
DATA(insert ( 2594 604 604 6 2582 ));
DATA(insert ( 2594 604 604 7 2584 ));
DATA(insert ( 2595 718 718 1 2591 ));
DATA(insert ( 2595 718 718 2 2583 ));
DATA(insert ( 2595 718 718 3 2592 ));
DATA(insert ( 2595 718 718 4 2580 ));
DATA(insert ( 2595 718 718 5 2581 ));
DATA(insert ( 2595 718 718 6 2582 ));
DATA(insert ( 2595 718 718 7 2584 ));
/* gin */
DATA(insert ( 2745 0 1 351 ));
DATA(insert ( 2745 0 2 2743 ));
DATA(insert ( 2745 0 3 2743 ));
DATA(insert ( 2745 0 4 2744 ));
DATA(insert ( 2746 0 1 360 ));
DATA(insert ( 2746 0 2 2743 ));
DATA(insert ( 2746 0 3 2743 ));
DATA(insert ( 2746 0 4 2744 ));
DATA(insert ( 2753 0 1 357 ));
DATA(insert ( 2753 0 2 2743 ));
DATA(insert ( 2753 0 3 2743 ));
DATA(insert ( 2753 0 4 2744 ));
DATA(insert ( 2754 0 1 1596 ));
DATA(insert ( 2754 0 2 2743 ));
DATA(insert ( 2754 0 3 2743 ));
DATA(insert ( 2754 0 4 2744 ));
DATA(insert ( 2755 0 1 1693 ));
DATA(insert ( 2755 0 2 2743 ));
DATA(insert ( 2755 0 3 2743 ));
DATA(insert ( 2755 0 4 2744 ));
DATA(insert ( 2756 0 1 1078 ));
DATA(insert ( 2756 0 2 2743 ));
DATA(insert ( 2756 0 3 2743 ));
DATA(insert ( 2756 0 4 2744 ));
DATA(insert ( 2757 0 1 1954 ));
DATA(insert ( 2757 0 2 2743 ));
DATA(insert ( 2757 0 3 2743 ));
DATA(insert ( 2757 0 4 2744 ));
DATA(insert ( 2758 0 1 358 ));
DATA(insert ( 2758 0 2 2743 ));
DATA(insert ( 2758 0 3 2743 ));
DATA(insert ( 2758 0 4 2744 ));
DATA(insert ( 2759 0 1 926 ));
DATA(insert ( 2759 0 2 2743 ));
DATA(insert ( 2759 0 3 2743 ));
DATA(insert ( 2759 0 4 2744 ));
DATA(insert ( 2760 0 1 1092 ));
DATA(insert ( 2760 0 2 2743 ));
DATA(insert ( 2760 0 3 2743 ));
DATA(insert ( 2760 0 4 2744 ));
DATA(insert ( 2761 0 1 354 ));
DATA(insert ( 2761 0 2 2743 ));
DATA(insert ( 2761 0 3 2743 ));
DATA(insert ( 2761 0 4 2744 ));
DATA(insert ( 2762 0 1 355 ));
DATA(insert ( 2762 0 2 2743 ));
DATA(insert ( 2762 0 3 2743 ));
DATA(insert ( 2762 0 4 2744 ));
DATA(insert ( 2763 0 1 926 ));
DATA(insert ( 2763 0 2 2743 ));
DATA(insert ( 2763 0 3 2743 ));
DATA(insert ( 2763 0 4 2744 ));
DATA(insert ( 2764 0 1 350 ));
DATA(insert ( 2764 0 2 2743 ));
DATA(insert ( 2764 0 3 2743 ));
DATA(insert ( 2764 0 4 2744 ));
DATA(insert ( 2765 0 1 842 ));
DATA(insert ( 2765 0 2 2743 ));
DATA(insert ( 2765 0 3 2743 ));
DATA(insert ( 2765 0 4 2744 ));
DATA(insert ( 2766 0 1 1315 ));
DATA(insert ( 2766 0 2 2743 ));
DATA(insert ( 2766 0 3 2743 ));
DATA(insert ( 2766 0 4 2744 ));
DATA(insert ( 2767 0 1 836 ));
DATA(insert ( 2767 0 2 2743 ));
DATA(insert ( 2767 0 3 2743 ));
DATA(insert ( 2767 0 4 2744 ));
DATA(insert ( 2768 0 1 359 ));
DATA(insert ( 2768 0 2 2743 ));
DATA(insert ( 2768 0 3 2743 ));
DATA(insert ( 2768 0 4 2744 ));
DATA(insert ( 2769 0 1 1769 ));
DATA(insert ( 2769 0 2 2743 ));
DATA(insert ( 2769 0 3 2743 ));
DATA(insert ( 2769 0 4 2744 ));
DATA(insert ( 2770 0 1 356 ));
DATA(insert ( 2770 0 2 2743 ));
DATA(insert ( 2770 0 3 2743 ));
DATA(insert ( 2770 0 4 2744 ));
DATA(insert ( 2771 0 1 404 ));
DATA(insert ( 2771 0 2 2743 ));
DATA(insert ( 2771 0 3 2743 ));
DATA(insert ( 2771 0 4 2744 ));
DATA(insert ( 2772 0 1 1107 ));
DATA(insert ( 2772 0 2 2743 ));
DATA(insert ( 2772 0 3 2743 ));
DATA(insert ( 2772 0 4 2744 ));
DATA(insert ( 2773 0 1 1314 ));
DATA(insert ( 2773 0 2 2743 ));
DATA(insert ( 2773 0 3 2743 ));
DATA(insert ( 2773 0 4 2744 ));
DATA(insert ( 2774 0 1 1358 ));
DATA(insert ( 2774 0 2 2743 ));
DATA(insert ( 2774 0 3 2743 ));
DATA(insert ( 2774 0 4 2744 ));
DATA(insert ( 2775 0 1 1672 ));
DATA(insert ( 2775 0 2 2743 ));
DATA(insert ( 2775 0 3 2743 ));
DATA(insert ( 2775 0 4 2744 ));
DATA(insert ( 2776 0 1 360 ));
DATA(insert ( 2776 0 2 2743 ));
DATA(insert ( 2776 0 3 2743 ));
DATA(insert ( 2776 0 4 2744 ));
DATA(insert ( 2777 0 1 2045 ));
DATA(insert ( 2777 0 2 2743 ));
DATA(insert ( 2777 0 3 2743 ));
DATA(insert ( 2777 0 4 2744 ));
DATA(insert ( 2778 0 1 377 ));
DATA(insert ( 2778 0 2 2743 ));
DATA(insert ( 2778 0 3 2743 ));
DATA(insert ( 2778 0 4 2744 ));
DATA(insert ( 2779 0 1 380 ));
DATA(insert ( 2779 0 2 2743 ));
DATA(insert ( 2779 0 3 2743 ));
DATA(insert ( 2779 0 4 2744 ));
DATA(insert ( 2780 0 1 381 ));
DATA(insert ( 2780 0 2 2743 ));
DATA(insert ( 2780 0 3 2743 ));
DATA(insert ( 2780 0 4 2744 ));
DATA(insert ( 2745 1007 1007 1 351 ));
DATA(insert ( 2745 1007 1007 2 2743 ));
DATA(insert ( 2745 1007 1007 3 2743 ));
DATA(insert ( 2745 1007 1007 4 2744 ));
DATA(insert ( 2745 1009 1009 1 360 ));
DATA(insert ( 2745 1009 1009 2 2743 ));
DATA(insert ( 2745 1009 1009 3 2743 ));
DATA(insert ( 2745 1009 1009 4 2744 ));
DATA(insert ( 2745 1023 1023 1 357 ));
DATA(insert ( 2745 1023 1023 2 2743 ));
DATA(insert ( 2745 1023 1023 3 2743 ));
DATA(insert ( 2745 1023 1023 4 2744 ));
DATA(insert ( 2745 1561 1561 1 1596 ));
DATA(insert ( 2745 1561 1561 2 2743 ));
DATA(insert ( 2745 1561 1561 3 2743 ));
DATA(insert ( 2745 1561 1561 4 2744 ));
DATA(insert ( 2745 1000 1000 1 1693 ));
DATA(insert ( 2745 1000 1000 2 2743 ));
DATA(insert ( 2745 1000 1000 3 2743 ));
DATA(insert ( 2745 1000 1000 4 2744 ));
DATA(insert ( 2745 1014 1014 1 1078 ));
DATA(insert ( 2745 1014 1014 2 2743 ));
DATA(insert ( 2745 1014 1014 3 2743 ));
DATA(insert ( 2745 1014 1014 4 2744 ));
DATA(insert ( 2745 1001 1001 1 1954 ));
DATA(insert ( 2745 1001 1001 2 2743 ));
DATA(insert ( 2745 1001 1001 3 2743 ));
DATA(insert ( 2745 1001 1001 4 2744 ));
DATA(insert ( 2745 1002 1002 1 358 ));
DATA(insert ( 2745 1002 1002 2 2743 ));
DATA(insert ( 2745 1002 1002 3 2743 ));
DATA(insert ( 2745 1002 1002 4 2744 ));
DATA(insert ( 2745 1182 1182 1 1092 ));
DATA(insert ( 2745 1182 1182 2 2743 ));
DATA(insert ( 2745 1182 1182 3 2743 ));
DATA(insert ( 2745 1182 1182 4 2744 ));
DATA(insert ( 2745 1021 1021 1 354 ));
DATA(insert ( 2745 1021 1021 2 2743 ));
DATA(insert ( 2745 1021 1021 3 2743 ));
DATA(insert ( 2745 1021 1021 4 2744 ));
DATA(insert ( 2745 1022 1022 1 355 ));
DATA(insert ( 2745 1022 1022 2 2743 ));
DATA(insert ( 2745 1022 1022 3 2743 ));
DATA(insert ( 2745 1022 1022 4 2744 ));
DATA(insert ( 2745 1041 1041 1 926 ));
DATA(insert ( 2745 1041 1041 2 2743 ));
DATA(insert ( 2745 1041 1041 3 2743 ));
DATA(insert ( 2745 1041 1041 4 2744 ));
DATA(insert ( 2745 1005 1005 1 350 ));
DATA(insert ( 2745 1005 1005 2 2743 ));
DATA(insert ( 2745 1005 1005 3 2743 ));
DATA(insert ( 2745 1005 1005 4 2744 ));
DATA(insert ( 2745 1016 1016 1 842 ));
DATA(insert ( 2745 1016 1016 2 2743 ));
DATA(insert ( 2745 1016 1016 3 2743 ));
DATA(insert ( 2745 1016 1016 4 2744 ));
DATA(insert ( 2745 1187 1187 1 1315 ));
DATA(insert ( 2745 1187 1187 2 2743 ));
DATA(insert ( 2745 1187 1187 3 2743 ));
DATA(insert ( 2745 1187 1187 4 2744 ));
DATA(insert ( 2745 1040 1040 1 836 ));
DATA(insert ( 2745 1040 1040 2 2743 ));
DATA(insert ( 2745 1040 1040 3 2743 ));
DATA(insert ( 2745 1040 1040 4 2744 ));
DATA(insert ( 2745 1003 1003 1 359 ));
DATA(insert ( 2745 1003 1003 2 2743 ));
DATA(insert ( 2745 1003 1003 3 2743 ));
DATA(insert ( 2745 1003 1003 4 2744 ));
DATA(insert ( 2745 1231 1231 1 1769 ));
DATA(insert ( 2745 1231 1231 2 2743 ));
DATA(insert ( 2745 1231 1231 3 2743 ));
DATA(insert ( 2745 1231 1231 4 2744 ));
DATA(insert ( 2745 1028 1028 1 356 ));
DATA(insert ( 2745 1028 1028 2 2743 ));
DATA(insert ( 2745 1028 1028 3 2743 ));
DATA(insert ( 2745 1028 1028 4 2744 ));
DATA(insert ( 2745 1013 1013 1 404 ));
DATA(insert ( 2745 1013 1013 2 2743 ));
DATA(insert ( 2745 1013 1013 3 2743 ));
DATA(insert ( 2745 1013 1013 4 2744 ));
DATA(insert ( 2745 1183 1183 1 1107 ));
DATA(insert ( 2745 1183 1183 2 2743 ));
DATA(insert ( 2745 1183 1183 3 2743 ));
DATA(insert ( 2745 1183 1183 4 2744 ));
DATA(insert ( 2745 1185 1185 1 1314 ));
DATA(insert ( 2745 1185 1185 2 2743 ));
DATA(insert ( 2745 1185 1185 3 2743 ));
DATA(insert ( 2745 1185 1185 4 2744 ));
DATA(insert ( 2745 1270 1270 1 1358 ));
DATA(insert ( 2745 1270 1270 2 2743 ));
DATA(insert ( 2745 1270 1270 3 2743 ));
DATA(insert ( 2745 1270 1270 4 2744 ));
DATA(insert ( 2745 1563 1563 1 1672 ));
DATA(insert ( 2745 1563 1563 2 2743 ));
DATA(insert ( 2745 1563 1563 3 2743 ));
DATA(insert ( 2745 1563 1563 4 2744 ));
DATA(insert ( 2745 1115 1115 1 2045 ));
DATA(insert ( 2745 1115 1115 2 2743 ));
DATA(insert ( 2745 1115 1115 3 2743 ));
DATA(insert ( 2745 1115 1115 4 2744 ));
DATA(insert ( 2745 791 791 1 377 ));
DATA(insert ( 2745 791 791 2 2743 ));
DATA(insert ( 2745 791 791 3 2743 ));
DATA(insert ( 2745 791 791 4 2744 ));
DATA(insert ( 2745 1024 1024 1 380 ));
DATA(insert ( 2745 1024 1024 2 2743 ));
DATA(insert ( 2745 1024 1024 3 2743 ));
DATA(insert ( 2745 1024 1024 4 2744 ));
DATA(insert ( 2745 1025 1025 1 381 ));
DATA(insert ( 2745 1025 1025 2 2743 ));
DATA(insert ( 2745 1025 1025 3 2743 ));
DATA(insert ( 2745 1025 1025 4 2744 ));
#endif /* PG_AMPROC_H */

View File

@ -4,16 +4,17 @@
* definition of the system "opclass" relation (pg_opclass)
* along with the relation's initial contents.
*
* New definition for Postgres 7.2: the primary key for this table is
* <opcamid, opcname> --- that is, there is a row for each valid combination
* of opclass name and index access method type. This row specifies the
* expected input data type for the opclass (the type of the heap column,
* or the expression output type in the case of an index expression). Note
* that types binary-coercible to the specified type will be accepted too.
* The primary key for this table is <opcmethod, opcname, opcnamespace> ---
* that is, there is a row for each valid combination of opclass name and
* index access method type. This row specifies the expected input data type
* for the opclass (the type of the heap column, or the expression output type
* in the case of an index expression). Note that types binary-coercible to
* the specified type will be accepted too.
*
* For a given <opcamid, opcintype> pair, there can be at most one row that
* For a given <opcmethod, opcintype> pair, there can be at most one row that
* has opcdefault = true; this row is the default opclass for such data in
* such an index.
* such an index. (This is not currently enforced by an index, because we
* don't support partial indexes on system catalogs.)
*
* Normally opckeytype = InvalidOid (zero), indicating that the data stored
* in the index is the same as the data in the indexed column. If opckeytype
@ -27,7 +28,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.71 2006/07/21 20:51:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.72 2006/12/23 00:43:12 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -54,10 +55,11 @@
CATALOG(pg_opclass,2616)
{
Oid opcamid; /* index access method opclass is for */
Oid opcmethod; /* index access method opclass is for */
NameData opcname; /* name of this opclass */
Oid opcnamespace; /* namespace of this opclass */
Oid opcowner; /* opclass owner */
Oid opcfamily; /* containing operator family */
Oid opcintype; /* type of data indexed by opclass */
bool opcdefault; /* T if opclass is default for opcintype */
Oid opckeytype; /* type of data in index, or InvalidOid */
@ -74,138 +76,129 @@ typedef FormData_pg_opclass *Form_pg_opclass;
* compiler constants for pg_opclass
* ----------------
*/
#define Natts_pg_opclass 7
#define Anum_pg_opclass_opcamid 1
#define Natts_pg_opclass 8
#define Anum_pg_opclass_opcmethod 1
#define Anum_pg_opclass_opcname 2
#define Anum_pg_opclass_opcnamespace 3
#define Anum_pg_opclass_opcowner 4
#define Anum_pg_opclass_opcintype 5
#define Anum_pg_opclass_opcdefault 6
#define Anum_pg_opclass_opckeytype 7
#define Anum_pg_opclass_opcfamily 5
#define Anum_pg_opclass_opcintype 6
#define Anum_pg_opclass_opcdefault 7
#define Anum_pg_opclass_opckeytype 8
/* ----------------
* initial contents of pg_opclass
*
* Note: we hard-wire an OID only for a few entries that have to be explicitly
* referenced in the C code for bootstrapping purposes. The rest get OIDs
* assigned on-the-fly during initdb.
* ----------------
*/
DATA(insert OID = 421 ( 403 abstime_ops PGNSP PGUID 702 t 0 ));
DATA(insert OID = 397 ( 403 array_ops PGNSP PGUID 2277 t 0 ));
#define ARRAY_BTREE_OPS_OID 397
DATA(insert OID = 423 ( 403 bit_ops PGNSP PGUID 1560 t 0 ));
DATA(insert OID = 424 ( 403 bool_ops PGNSP PGUID 16 t 0 ));
#define BOOL_BTREE_OPS_OID 424
DATA(insert OID = 426 ( 403 bpchar_ops PGNSP PGUID 1042 t 0 ));
#define BPCHAR_BTREE_OPS_OID 426
DATA(insert OID = 427 ( 405 bpchar_ops PGNSP PGUID 1042 t 0 ));
DATA(insert OID = 428 ( 403 bytea_ops PGNSP PGUID 17 t 0 ));
#define BYTEA_BTREE_OPS_OID 428
DATA(insert OID = 429 ( 403 char_ops PGNSP PGUID 18 t 0 ));
DATA(insert OID = 431 ( 405 char_ops PGNSP PGUID 18 t 0 ));
DATA(insert OID = 432 ( 403 cidr_ops PGNSP PGUID 650 t 0 ));
#define CIDR_BTREE_OPS_OID 432
DATA(insert OID = 433 ( 405 cidr_ops PGNSP PGUID 650 t 0 ));
DATA(insert OID = 434 ( 403 date_ops PGNSP PGUID 1082 t 0 ));
DATA(insert OID = 435 ( 405 date_ops PGNSP PGUID 1082 t 0 ));
DATA(insert OID = 1970 ( 403 float4_ops PGNSP PGUID 700 t 0 ));
DATA(insert OID = 1971 ( 405 float4_ops PGNSP PGUID 700 t 0 ));
DATA(insert OID = 1972 ( 403 float8_ops PGNSP PGUID 701 t 0 ));
DATA(insert OID = 1973 ( 405 float8_ops PGNSP PGUID 701 t 0 ));
DATA(insert OID = 1974 ( 403 inet_ops PGNSP PGUID 869 t 0 ));
#define INET_BTREE_OPS_OID 1974
DATA(insert OID = 1975 ( 405 inet_ops PGNSP PGUID 869 t 0 ));
DATA(insert OID = 1976 ( 403 int2_ops PGNSP PGUID 21 t 0 ));
#define INT2_BTREE_OPS_OID 1976
DATA(insert OID = 1977 ( 405 int2_ops PGNSP PGUID 21 t 0 ));
DATA(insert OID = 1978 ( 403 int4_ops PGNSP PGUID 23 t 0 ));
DATA(insert ( 403 abstime_ops PGNSP PGUID 421 702 t 0 ));
DATA(insert ( 403 array_ops PGNSP PGUID 397 2277 t 0 ));
DATA(insert ( 403 bit_ops PGNSP PGUID 423 1560 t 0 ));
DATA(insert ( 403 bool_ops PGNSP PGUID 424 16 t 0 ));
DATA(insert ( 403 bpchar_ops PGNSP PGUID 426 1042 t 0 ));
DATA(insert ( 405 bpchar_ops PGNSP PGUID 427 1042 t 0 ));
DATA(insert ( 403 bytea_ops PGNSP PGUID 428 17 t 0 ));
DATA(insert ( 403 char_ops PGNSP PGUID 429 18 t 0 ));
DATA(insert ( 405 char_ops PGNSP PGUID 431 18 t 0 ));
DATA(insert ( 403 cidr_ops PGNSP PGUID 1974 869 f 0 ));
DATA(insert ( 405 cidr_ops PGNSP PGUID 1975 869 f 0 ));
DATA(insert ( 403 date_ops PGNSP PGUID 434 1082 t 0 ));
DATA(insert ( 405 date_ops PGNSP PGUID 435 1082 t 0 ));
DATA(insert ( 403 float4_ops PGNSP PGUID 1970 700 t 0 ));
DATA(insert ( 405 float4_ops PGNSP PGUID 1971 700 t 0 ));
DATA(insert ( 403 float8_ops PGNSP PGUID 1970 701 t 0 ));
DATA(insert ( 405 float8_ops PGNSP PGUID 1971 701 t 0 ));
DATA(insert ( 403 inet_ops PGNSP PGUID 1974 869 t 0 ));
DATA(insert ( 405 inet_ops PGNSP PGUID 1975 869 t 0 ));
DATA(insert OID = 1979 ( 403 int2_ops PGNSP PGUID 1976 21 t 0 ));
#define INT2_BTREE_OPS_OID 1979
DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 ));
DATA(insert OID = 1978 ( 403 int4_ops PGNSP PGUID 1976 23 t 0 ));
#define INT4_BTREE_OPS_OID 1978
DATA(insert OID = 1979 ( 405 int4_ops PGNSP PGUID 23 t 0 ));
DATA(insert OID = 1980 ( 403 int8_ops PGNSP PGUID 20 t 0 ));
DATA(insert OID = 1981 ( 405 int8_ops PGNSP PGUID 20 t 0 ));
DATA(insert OID = 1982 ( 403 interval_ops PGNSP PGUID 1186 t 0 ));
DATA(insert OID = 1983 ( 405 interval_ops PGNSP PGUID 1186 t 0 ));
DATA(insert OID = 1984 ( 403 macaddr_ops PGNSP PGUID 829 t 0 ));
DATA(insert OID = 1985 ( 405 macaddr_ops PGNSP PGUID 829 t 0 ));
DATA(insert OID = 1986 ( 403 name_ops PGNSP PGUID 19 t 0 ));
#define NAME_BTREE_OPS_OID 1986
DATA(insert OID = 1987 ( 405 name_ops PGNSP PGUID 19 t 0 ));
DATA(insert OID = 1988 ( 403 numeric_ops PGNSP PGUID 1700 t 0 ));
DATA(insert OID = 1989 ( 403 oid_ops PGNSP PGUID 26 t 0 ));
#define OID_BTREE_OPS_OID 1989
DATA(insert OID = 1990 ( 405 oid_ops PGNSP PGUID 26 t 0 ));
DATA(insert OID = 1991 ( 403 oidvector_ops PGNSP PGUID 30 t 0 ));
DATA(insert OID = 1992 ( 405 oidvector_ops PGNSP PGUID 30 t 0 ));
DATA(insert OID = 1994 ( 403 text_ops PGNSP PGUID 25 t 0 ));
#define TEXT_BTREE_OPS_OID 1994
DATA(insert OID = 1995 ( 405 text_ops PGNSP PGUID 25 t 0 ));
DATA(insert OID = 1996 ( 403 time_ops PGNSP PGUID 1083 t 0 ));
DATA(insert OID = 1997 ( 405 time_ops PGNSP PGUID 1083 t 0 ));
DATA(insert OID = 1998 ( 403 timestamptz_ops PGNSP PGUID 1184 t 0 ));
DATA(insert OID = 1999 ( 405 timestamptz_ops PGNSP PGUID 1184 t 0 ));
DATA(insert OID = 2000 ( 403 timetz_ops PGNSP PGUID 1266 t 0 ));
DATA(insert OID = 2001 ( 405 timetz_ops PGNSP PGUID 1266 t 0 ));
DATA(insert OID = 2002 ( 403 varbit_ops PGNSP PGUID 1562 t 0 ));
DATA(insert OID = 2003 ( 403 varchar_ops PGNSP PGUID 1043 t 0 ));
#define VARCHAR_BTREE_OPS_OID 2003
DATA(insert OID = 2004 ( 405 varchar_ops PGNSP PGUID 1043 t 0 ));
DATA(insert OID = 2039 ( 403 timestamp_ops PGNSP PGUID 1114 t 0 ));
DATA(insert OID = 2040 ( 405 timestamp_ops PGNSP PGUID 1114 t 0 ));
DATA(insert OID = 2095 ( 403 text_pattern_ops PGNSP PGUID 25 f 0 ));
#define TEXT_PATTERN_BTREE_OPS_OID 2095
DATA(insert OID = 2096 ( 403 varchar_pattern_ops PGNSP PGUID 1043 f 0 ));
#define VARCHAR_PATTERN_BTREE_OPS_OID 2096
DATA(insert OID = 2097 ( 403 bpchar_pattern_ops PGNSP PGUID 1042 f 0 ));
#define BPCHAR_PATTERN_BTREE_OPS_OID 2097
DATA(insert OID = 2098 ( 403 name_pattern_ops PGNSP PGUID 19 f 0 ));
#define NAME_PATTERN_BTREE_OPS_OID 2098
DATA(insert OID = 2099 ( 403 money_ops PGNSP PGUID 790 t 0 ));
DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID 16 t 0 ));
#define BOOL_HASH_OPS_OID 2222
DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID 17 t 0 ));
DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID 22 t 0 ));
DATA(insert OID = 2789 ( 403 tid_ops PGNSP PGUID 27 t 0 ));
DATA(insert OID = 2225 ( 405 xid_ops PGNSP PGUID 28 t 0 ));
DATA(insert OID = 2226 ( 405 cid_ops PGNSP PGUID 29 t 0 ));
DATA(insert OID = 2227 ( 405 abstime_ops PGNSP PGUID 702 t 0 ));
DATA(insert OID = 2228 ( 405 reltime_ops PGNSP PGUID 703 t 0 ));
DATA(insert OID = 2229 ( 405 text_pattern_ops PGNSP PGUID 25 f 0 ));
DATA(insert OID = 2230 ( 405 varchar_pattern_ops PGNSP PGUID 1043 f 0 ));
DATA(insert OID = 2231 ( 405 bpchar_pattern_ops PGNSP PGUID 1042 f 0 ));
DATA(insert OID = 2232 ( 405 name_pattern_ops PGNSP PGUID 19 f 0 ));
DATA(insert OID = 2233 ( 403 reltime_ops PGNSP PGUID 703 t 0 ));
DATA(insert OID = 2234 ( 403 tinterval_ops PGNSP PGUID 704 t 0 ));
DATA(insert OID = 2235 ( 405 aclitem_ops PGNSP PGUID 1033 t 0 ));
DATA(insert OID = 2593 ( 783 box_ops PGNSP PGUID 603 t 0 ));
DATA(insert OID = 2594 ( 783 poly_ops PGNSP PGUID 604 t 603 ));
DATA(insert OID = 2595 ( 783 circle_ops PGNSP PGUID 718 t 603 ));
DATA(insert OID = 2745 ( 2742 _int4_ops PGNSP PGUID 1007 t 23 ));
DATA(insert OID = 2746 ( 2742 _text_ops PGNSP PGUID 1009 t 25 ));
DATA(insert OID = 2753 ( 2742 _abstime_ops PGNSP PGUID 1023 t 702 ));
DATA(insert OID = 2754 ( 2742 _bit_ops PGNSP PGUID 1561 t 1560 ));
DATA(insert OID = 2755 ( 2742 _bool_ops PGNSP PGUID 1000 t 16 ));
DATA(insert OID = 2756 ( 2742 _bpchar_ops PGNSP PGUID 1014 t 1042 ));
DATA(insert OID = 2757 ( 2742 _bytea_ops PGNSP PGUID 1001 t 17 ));
DATA(insert OID = 2758 ( 2742 _char_ops PGNSP PGUID 1002 t 18 ));
DATA(insert OID = 2759 ( 2742 _cidr_ops PGNSP PGUID 651 t 650 ));
DATA(insert OID = 2760 ( 2742 _date_ops PGNSP PGUID 1182 t 1082 ));
DATA(insert OID = 2761 ( 2742 _float4_ops PGNSP PGUID 1021 t 700 ));
DATA(insert OID = 2762 ( 2742 _float8_ops PGNSP PGUID 1022 t 701 ));
DATA(insert OID = 2763 ( 2742 _inet_ops PGNSP PGUID 1041 t 869 ));
DATA(insert OID = 2764 ( 2742 _int2_ops PGNSP PGUID 1005 t 21 ));
DATA(insert OID = 2765 ( 2742 _int8_ops PGNSP PGUID 1016 t 20 ));
DATA(insert OID = 2766 ( 2742 _interval_ops PGNSP PGUID 1187 t 1186 ));
DATA(insert OID = 2767 ( 2742 _macaddr_ops PGNSP PGUID 1040 t 829 ));
DATA(insert OID = 2768 ( 2742 _name_ops PGNSP PGUID 1003 t 19 ));
DATA(insert OID = 2769 ( 2742 _numeric_ops PGNSP PGUID 1231 t 1700 ));
DATA(insert OID = 2770 ( 2742 _oid_ops PGNSP PGUID 1028 t 26 ));
DATA(insert OID = 2771 ( 2742 _oidvector_ops PGNSP PGUID 1013 t 30 ));
DATA(insert OID = 2772 ( 2742 _time_ops PGNSP PGUID 1183 t 1083 ));
DATA(insert OID = 2773 ( 2742 _timestamptz_ops PGNSP PGUID 1185 t 1184 ));
DATA(insert OID = 2774 ( 2742 _timetz_ops PGNSP PGUID 1270 t 1266 ));
DATA(insert OID = 2775 ( 2742 _varbit_ops PGNSP PGUID 1563 t 1562 ));
DATA(insert OID = 2776 ( 2742 _varchar_ops PGNSP PGUID 1015 t 1043 ));
DATA(insert OID = 2777 ( 2742 _timestamp_ops PGNSP PGUID 1115 t 1114 ));
DATA(insert OID = 2778 ( 2742 _money_ops PGNSP PGUID 791 t 790 ));
DATA(insert OID = 2779 ( 2742 _reltime_ops PGNSP PGUID 1024 t 703 ));
DATA(insert OID = 2780 ( 2742 _tinterval_ops PGNSP PGUID 1025 t 704 ));
DATA(insert ( 405 int4_ops PGNSP PGUID 1977 23 t 0 ));
DATA(insert ( 403 int8_ops PGNSP PGUID 1976 20 t 0 ));
DATA(insert ( 405 int8_ops PGNSP PGUID 1977 20 t 0 ));
DATA(insert ( 403 interval_ops PGNSP PGUID 1982 1186 t 0 ));
DATA(insert ( 405 interval_ops PGNSP PGUID 1983 1186 t 0 ));
DATA(insert ( 403 macaddr_ops PGNSP PGUID 1984 829 t 0 ));
DATA(insert ( 405 macaddr_ops PGNSP PGUID 1985 829 t 0 ));
DATA(insert ( 403 name_ops PGNSP PGUID 1986 19 t 0 ));
DATA(insert ( 405 name_ops PGNSP PGUID 1987 19 t 0 ));
DATA(insert ( 403 numeric_ops PGNSP PGUID 1988 1700 t 0 ));
DATA(insert OID = 1981 ( 403 oid_ops PGNSP PGUID 1989 26 t 0 ));
#define OID_BTREE_OPS_OID 1981
DATA(insert ( 405 oid_ops PGNSP PGUID 1990 26 t 0 ));
DATA(insert ( 403 oidvector_ops PGNSP PGUID 1991 30 t 0 ));
DATA(insert ( 405 oidvector_ops PGNSP PGUID 1992 30 t 0 ));
DATA(insert ( 403 text_ops PGNSP PGUID 1994 25 t 0 ));
DATA(insert ( 405 text_ops PGNSP PGUID 1995 25 t 0 ));
DATA(insert ( 403 time_ops PGNSP PGUID 1996 1083 t 0 ));
DATA(insert ( 405 time_ops PGNSP PGUID 1997 1083 t 0 ));
DATA(insert ( 403 timestamptz_ops PGNSP PGUID 434 1184 t 0 ));
DATA(insert ( 405 timestamptz_ops PGNSP PGUID 1999 1184 t 0 ));
DATA(insert ( 403 timetz_ops PGNSP PGUID 2000 1266 t 0 ));
DATA(insert ( 405 timetz_ops PGNSP PGUID 2001 1266 t 0 ));
DATA(insert ( 403 varbit_ops PGNSP PGUID 2002 1562 t 0 ));
DATA(insert ( 403 varchar_ops PGNSP PGUID 1994 25 f 0 ));
DATA(insert ( 405 varchar_ops PGNSP PGUID 1995 25 f 0 ));
DATA(insert ( 403 timestamp_ops PGNSP PGUID 434 1114 t 0 ));
DATA(insert ( 405 timestamp_ops PGNSP PGUID 2040 1114 t 0 ));
DATA(insert ( 403 text_pattern_ops PGNSP PGUID 2095 25 f 0 ));
DATA(insert ( 403 varchar_pattern_ops PGNSP PGUID 2095 25 f 0 ));
DATA(insert ( 403 bpchar_pattern_ops PGNSP PGUID 2097 1042 f 0 ));
DATA(insert ( 403 name_pattern_ops PGNSP PGUID 2098 19 f 0 ));
DATA(insert ( 403 money_ops PGNSP PGUID 2099 790 t 0 ));
DATA(insert ( 405 bool_ops PGNSP PGUID 2222 16 t 0 ));
DATA(insert ( 405 bytea_ops PGNSP PGUID 2223 17 t 0 ));
DATA(insert ( 405 int2vector_ops PGNSP PGUID 2224 22 t 0 ));
DATA(insert ( 403 tid_ops PGNSP PGUID 2789 27 t 0 ));
DATA(insert ( 405 xid_ops PGNSP PGUID 2225 28 t 0 ));
DATA(insert ( 405 cid_ops PGNSP PGUID 2226 29 t 0 ));
DATA(insert ( 405 abstime_ops PGNSP PGUID 2227 702 t 0 ));
DATA(insert ( 405 reltime_ops PGNSP PGUID 2228 703 t 0 ));
DATA(insert ( 405 text_pattern_ops PGNSP PGUID 2229 25 f 0 ));
DATA(insert ( 405 varchar_pattern_ops PGNSP PGUID 2229 25 f 0 ));
DATA(insert ( 405 bpchar_pattern_ops PGNSP PGUID 2231 1042 f 0 ));
DATA(insert ( 405 name_pattern_ops PGNSP PGUID 2232 19 f 0 ));
DATA(insert ( 403 reltime_ops PGNSP PGUID 2233 703 t 0 ));
DATA(insert ( 403 tinterval_ops PGNSP PGUID 2234 704 t 0 ));
DATA(insert ( 405 aclitem_ops PGNSP PGUID 2235 1033 t 0 ));
DATA(insert ( 783 box_ops PGNSP PGUID 2593 603 t 0 ));
DATA(insert ( 783 poly_ops PGNSP PGUID 2594 604 t 603 ));
DATA(insert ( 783 circle_ops PGNSP PGUID 2595 718 t 603 ));
DATA(insert ( 2742 _int4_ops PGNSP PGUID 2745 1007 t 23 ));
DATA(insert ( 2742 _text_ops PGNSP PGUID 2745 1009 t 25 ));
DATA(insert ( 2742 _abstime_ops PGNSP PGUID 2745 1023 t 702 ));
DATA(insert ( 2742 _bit_ops PGNSP PGUID 2745 1561 t 1560 ));
DATA(insert ( 2742 _bool_ops PGNSP PGUID 2745 1000 t 16 ));
DATA(insert ( 2742 _bpchar_ops PGNSP PGUID 2745 1014 t 1042 ));
DATA(insert ( 2742 _bytea_ops PGNSP PGUID 2745 1001 t 17 ));
DATA(insert ( 2742 _char_ops PGNSP PGUID 2745 1002 t 18 ));
DATA(insert ( 2742 _cidr_ops PGNSP PGUID 2745 651 t 650 ));
DATA(insert ( 2742 _date_ops PGNSP PGUID 2745 1182 t 1082 ));
DATA(insert ( 2742 _float4_ops PGNSP PGUID 2745 1021 t 700 ));
DATA(insert ( 2742 _float8_ops PGNSP PGUID 2745 1022 t 701 ));
DATA(insert ( 2742 _inet_ops PGNSP PGUID 2745 1041 t 869 ));
DATA(insert ( 2742 _int2_ops PGNSP PGUID 2745 1005 t 21 ));
DATA(insert ( 2742 _int8_ops PGNSP PGUID 2745 1016 t 20 ));
DATA(insert ( 2742 _interval_ops PGNSP PGUID 2745 1187 t 1186 ));
DATA(insert ( 2742 _macaddr_ops PGNSP PGUID 2745 1040 t 829 ));
DATA(insert ( 2742 _name_ops PGNSP PGUID 2745 1003 t 19 ));
DATA(insert ( 2742 _numeric_ops PGNSP PGUID 2745 1231 t 1700 ));
DATA(insert ( 2742 _oid_ops PGNSP PGUID 2745 1028 t 26 ));
DATA(insert ( 2742 _oidvector_ops PGNSP PGUID 2745 1013 t 30 ));
DATA(insert ( 2742 _time_ops PGNSP PGUID 2745 1183 t 1083 ));
DATA(insert ( 2742 _timestamptz_ops PGNSP PGUID 2745 1185 t 1184 ));
DATA(insert ( 2742 _timetz_ops PGNSP PGUID 2745 1270 t 1266 ));
DATA(insert ( 2742 _varbit_ops PGNSP PGUID 2745 1563 t 1562 ));
DATA(insert ( 2742 _varchar_ops PGNSP PGUID 2745 1015 t 1043 ));
DATA(insert ( 2742 _timestamp_ops PGNSP PGUID 2745 1115 t 1114 ));
DATA(insert ( 2742 _money_ops PGNSP PGUID 2745 791 t 790 ));
DATA(insert ( 2742 _reltime_ops PGNSP PGUID 2745 1024 t 703 ));
DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 ));
#endif /* PG_OPCLASS_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/*-------------------------------------------------------------------------
*
* pg_opfamily.h
* definition of the system "opfamily" relation (pg_opfamily)
* along with the relation's initial contents.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_opfamily.h,v 1.1 2006/12/23 00:43:12 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
* information from the DATA() statements.
*
*-------------------------------------------------------------------------
*/
#ifndef PG_OPFAMILY_H
#define PG_OPFAMILY_H
/* ----------------
* postgres.h contains the system type definitions and the
* CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file
* can be read by both genbki.sh and the C compiler.
* ----------------
*/
/* ----------------
* pg_opfamily definition. cpp turns this into
* typedef struct FormData_pg_opfamily
* ----------------
*/
#define OperatorFamilyRelationId 2753
CATALOG(pg_opfamily,2753)
{
Oid opfmethod; /* index access method opfamily is for */
NameData opfname; /* name of this opfamily */
Oid opfnamespace; /* namespace of this opfamily */
Oid opfowner; /* opfamily owner */
} FormData_pg_opfamily;
/* ----------------
* Form_pg_opfamily corresponds to a pointer to a tuple with
* the format of pg_opfamily relation.
* ----------------
*/
typedef FormData_pg_opfamily *Form_pg_opfamily;
/* ----------------
* compiler constants for pg_opfamily
* ----------------
*/
#define Natts_pg_opfamily 4
#define Anum_pg_opfamily_opfmethod 1
#define Anum_pg_opfamily_opfname 2
#define Anum_pg_opfamily_opfnamespace 3
#define Anum_pg_opfamily_opfowner 4
/* ----------------
* initial contents of pg_opfamily
* ----------------
*/
DATA(insert OID = 421 ( 403 abstime_ops PGNSP PGUID ));
DATA(insert OID = 397 ( 403 array_ops PGNSP PGUID ));
DATA(insert OID = 423 ( 403 bit_ops PGNSP PGUID ));
DATA(insert OID = 424 ( 403 bool_ops PGNSP PGUID ));
#define BOOL_BTREE_FAM_OID 424
DATA(insert OID = 426 ( 403 bpchar_ops PGNSP PGUID ));
#define BPCHAR_BTREE_FAM_OID 426
DATA(insert OID = 427 ( 405 bpchar_ops PGNSP PGUID ));
DATA(insert OID = 428 ( 403 bytea_ops PGNSP PGUID ));
#define BYTEA_BTREE_FAM_OID 428
DATA(insert OID = 429 ( 403 char_ops PGNSP PGUID ));
DATA(insert OID = 431 ( 405 char_ops PGNSP PGUID ));
DATA(insert OID = 434 ( 403 datetime_ops PGNSP PGUID ));
DATA(insert OID = 435 ( 405 date_ops PGNSP PGUID ));
DATA(insert OID = 1970 ( 403 float_ops PGNSP PGUID ));
DATA(insert OID = 1971 ( 405 float_ops PGNSP PGUID ));
DATA(insert OID = 1974 ( 403 network_ops PGNSP PGUID ));
#define NETWORK_BTREE_FAM_OID 1974
DATA(insert OID = 1975 ( 405 network_ops PGNSP PGUID ));
DATA(insert OID = 1976 ( 403 integer_ops PGNSP PGUID ));
#define INTEGER_BTREE_FAM_OID 1976
DATA(insert OID = 1977 ( 405 integer_ops PGNSP PGUID ));
DATA(insert OID = 1982 ( 403 interval_ops PGNSP PGUID ));
DATA(insert OID = 1983 ( 405 interval_ops PGNSP PGUID ));
DATA(insert OID = 1984 ( 403 macaddr_ops PGNSP PGUID ));
DATA(insert OID = 1985 ( 405 macaddr_ops PGNSP PGUID ));
DATA(insert OID = 1986 ( 403 name_ops PGNSP PGUID ));
#define NAME_BTREE_FAM_OID 1986
DATA(insert OID = 1987 ( 405 name_ops PGNSP PGUID ));
DATA(insert OID = 1988 ( 403 numeric_ops PGNSP PGUID ));
DATA(insert OID = 1989 ( 403 oid_ops PGNSP PGUID ));
#define OID_BTREE_FAM_OID 1989
DATA(insert OID = 1990 ( 405 oid_ops PGNSP PGUID ));
DATA(insert OID = 1991 ( 403 oidvector_ops PGNSP PGUID ));
DATA(insert OID = 1992 ( 405 oidvector_ops PGNSP PGUID ));
DATA(insert OID = 1994 ( 403 text_ops PGNSP PGUID ));
#define TEXT_BTREE_FAM_OID 1994
DATA(insert OID = 1995 ( 405 text_ops PGNSP PGUID ));
DATA(insert OID = 1996 ( 403 time_ops PGNSP PGUID ));
DATA(insert OID = 1997 ( 405 time_ops PGNSP PGUID ));
DATA(insert OID = 1999 ( 405 timestamptz_ops PGNSP PGUID ));
DATA(insert OID = 2000 ( 403 timetz_ops PGNSP PGUID ));
DATA(insert OID = 2001 ( 405 timetz_ops PGNSP PGUID ));
DATA(insert OID = 2002 ( 403 varbit_ops PGNSP PGUID ));
DATA(insert OID = 2040 ( 405 timestamp_ops PGNSP PGUID ));
DATA(insert OID = 2095 ( 403 text_pattern_ops PGNSP PGUID ));
#define TEXT_PATTERN_BTREE_FAM_OID 2095
DATA(insert OID = 2097 ( 403 bpchar_pattern_ops PGNSP PGUID ));
#define BPCHAR_PATTERN_BTREE_FAM_OID 2097
DATA(insert OID = 2098 ( 403 name_pattern_ops PGNSP PGUID ));
#define NAME_PATTERN_BTREE_FAM_OID 2098
DATA(insert OID = 2099 ( 403 money_ops PGNSP PGUID ));
DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID ));
#define BOOL_HASH_FAM_OID 2222
DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID ));
DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID ));
DATA(insert OID = 2789 ( 403 tid_ops PGNSP PGUID ));
DATA(insert OID = 2225 ( 405 xid_ops PGNSP PGUID ));
DATA(insert OID = 2226 ( 405 cid_ops PGNSP PGUID ));
DATA(insert OID = 2227 ( 405 abstime_ops PGNSP PGUID ));
DATA(insert OID = 2228 ( 405 reltime_ops PGNSP PGUID ));
DATA(insert OID = 2229 ( 405 text_pattern_ops PGNSP PGUID ));
DATA(insert OID = 2231 ( 405 bpchar_pattern_ops PGNSP PGUID ));
DATA(insert OID = 2232 ( 405 name_pattern_ops PGNSP PGUID ));
DATA(insert OID = 2233 ( 403 reltime_ops PGNSP PGUID ));
DATA(insert OID = 2234 ( 403 tinterval_ops PGNSP PGUID ));
DATA(insert OID = 2235 ( 405 aclitem_ops PGNSP PGUID ));
DATA(insert OID = 2593 ( 783 box_ops PGNSP PGUID ));
DATA(insert OID = 2594 ( 783 poly_ops PGNSP PGUID ));
DATA(insert OID = 2595 ( 783 circle_ops PGNSP PGUID ));
DATA(insert OID = 2745 ( 2742 array_ops PGNSP PGUID ));
#endif /* PG_OPFAMILY_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.77 2006/10/04 00:30:08 momjian Exp $
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.78 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -81,6 +81,9 @@ extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
extern void DefineOpClass(CreateOpClassStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid);
extern void RemoveOpFamilyById(Oid opfamilyOid);
extern void RemoveAmOpEntryById(Oid entryOid);
extern void RemoveAmProcEntryById(Oid entryOid);
extern void RenameOpClass(List *name, const char *access_method, const char *newname);
extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.334 2006/11/05 22:42:10 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.335 2006/12/23 00:43:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1318,6 +1318,7 @@ typedef struct CreateOpClassStmt
{
NodeTag type;
List *opclassname; /* qualified name (list of Value strings) */
List *opfamilyname; /* qualified name (ditto); NIL if omitted */
char *amname; /* name of index AM opclass is for */
TypeName *datatype; /* datatype of indexed column */
List *items; /* List of CreateOpClassItem nodes */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.85 2006/08/02 01:59:47 joe Exp $
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.86 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -351,7 +351,9 @@ typedef struct NestLoop
typedef struct MergeJoin
{
Join join;
List *mergeclauses;
List *mergeclauses; /* mergeclauses as expression trees */
List *mergefamilies; /* OID list of btree opfamilies */
List *mergestrategies; /* integer list of btree strategies */
} MergeJoin;
/* ----------------

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.119 2006/12/21 16:05:16 petere Exp $
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.120 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -654,7 +654,7 @@ typedef struct RowExpr
*
* We support row comparison for any operator that can be determined to
* act like =, <>, <, <=, >, or >= (we determine this by looking for the
* operator in btree opclasses). Note that the same operator name might
* operator in btree opfamilies). Note that the same operator name might
* map to a different operator for each pair of row elements, since the
* element datatypes can vary.
*
@ -679,7 +679,7 @@ typedef struct RowCompareExpr
Expr xpr;
RowCompareType rctype; /* LT LE GE or GT, never EQ or NE */
List *opnos; /* OID list of pairwise comparison ops */
List *opclasses; /* OID list of containing operator classes */
List *opfamilies; /* OID list of containing operator families */
List *largs; /* the left-hand input arguments */
List *rargs; /* the right-hand input arguments */
} RowCompareExpr;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.128 2006/10/04 00:30:09 momjian Exp $
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.129 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -300,11 +300,11 @@ typedef struct RelOptInfo
* and indexes, but that created confusion without actually doing anything
* useful. So now we have a separate IndexOptInfo struct for indexes.
*
* classlist[], indexkeys[], and ordering[] have ncolumns entries.
* opfamily[], indexkeys[], and ordering[] have ncolumns entries.
* Zeroes in the indexkeys[] array indicate index columns that are
* expressions; there is one element in indexprs for each such column.
*
* Note: for historical reasons, the classlist and ordering arrays have
* Note: for historical reasons, the opfamily and ordering arrays have
* an extra entry that is always zero. Some code scans until it sees a
* zero entry, rather than looking at ncolumns.
*
@ -326,7 +326,7 @@ typedef struct IndexOptInfo
/* index descriptor information */
int ncolumns; /* number of columns in index */
Oid *classlist; /* OIDs of operator classes for columns */
Oid *opfamily; /* OIDs of operator families for columns */
int *indexkeys; /* column numbers of index's keys, or 0 */
Oid *ordering; /* OIDs of sort operators for each column */
Oid relam; /* OID of the access method (in pg_am) */
@ -611,7 +611,9 @@ typedef JoinPath NestPath;
* A mergejoin path has these fields.
*
* path_mergeclauses lists the clauses (in the form of RestrictInfos)
* that will be used in the merge.
* that will be used in the merge. The parallel lists path_mergefamilies
* and path_mergestrategies specify the merge semantics for each clause
* (in effect, defining the relevant sort ordering for each clause).
*
* Note that the mergeclauses are a subset of the parent relation's
* restriction-clause list. Any join clauses that are not mergejoinable
@ -628,6 +630,8 @@ typedef struct MergePath
{
JoinPath jpath;
List *path_mergeclauses; /* join clauses to be used for merge */
List *path_mergefamilies; /* OID list of btree opfamilies */
List *path_mergestrategies; /* integer list of btree strategies */
List *outersortkeys; /* keys for explicit sort, if any */
List *innersortkeys; /* keys for explicit sort, if any */
} MergePath;
@ -780,6 +784,7 @@ typedef struct RestrictInfo
Oid mergejoinoperator; /* copy of clause operator */
Oid left_sortop; /* leftside sortop needed for mergejoin */
Oid right_sortop; /* rightside sortop needed for mergejoin */
Oid mergeopfamily; /* btree opfamily relating these ops */
/* cache space for mergeclause processing; NIL if not yet set */
List *left_pathkey; /* canonical pathkey for left side */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.72 2006/10/04 00:30:09 momjian Exp $
* $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.73 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -71,6 +71,8 @@ extern MergePath *create_mergejoin_path(PlannerInfo *root,
List *restrict_clauses,
List *pathkeys,
List *mergeclauses,
List *mergefamilies,
List *mergestrategies,
List *outersortkeys,
List *innersortkeys);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.107 2006/10/04 00:30:10 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.108 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -26,16 +26,22 @@ typedef enum IOFuncSelector
IOFunc_send
} IOFuncSelector;
extern bool op_in_opclass(Oid opno, Oid opclass);
extern int get_op_opclass_strategy(Oid opno, Oid opclass);
extern void get_op_opclass_properties(Oid opno, Oid opclass,
int *strategy, Oid *subtype,
extern bool op_in_opfamily(Oid opno, Oid opfamily);
extern int get_op_opfamily_strategy(Oid opno, Oid opfamily);
extern void get_op_opfamily_properties(Oid opno, Oid opfamily,
int *strategy,
Oid *lefttype,
Oid *righttype,
bool *recheck);
extern Oid get_opclass_member(Oid opclass, Oid subtype, int16 strategy);
extern Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
int16 strategy);
extern bool get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
Oid *right_sortop, Oid *opfamily);
extern Oid get_op_hash_function(Oid opno);
extern void get_op_btree_interpretation(Oid opno,
List **opclasses, List **opstrats);
extern Oid get_opclass_proc(Oid opclass, Oid subtype, int16 procnum);
List **opfamilies, List **opstrats);
extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype,
int16 procnum);
extern char *get_attname(Oid relid, AttrNumber attnum);
extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
extern AttrNumber get_attnum(Oid relid, const char *attname);
@ -43,16 +49,12 @@ extern Oid get_atttype(Oid relid, AttrNumber attnum);
extern int32 get_atttypmod(Oid relid, AttrNumber attnum);
extern void get_atttypetypmod(Oid relid, AttrNumber attnum,
Oid *typid, int32 *typmod);
extern bool opclass_is_btree(Oid opclass);
extern bool opclass_is_hash(Oid opclass);
extern bool opclass_is_default(Oid opclass);
extern Oid get_opclass_family(Oid opclass);
extern Oid get_opclass_input_type(Oid opclass);
extern RegProcedure get_opcode(Oid opno);
extern char *get_opname(Oid opno);
extern void op_input_types(Oid opno, Oid *lefttype, Oid *righttype);
extern bool op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp);
extern void op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
RegProcedure *ltproc, RegProcedure *gtproc);
extern bool op_mergejoinable(Oid opno);
extern bool op_hashjoinable(Oid opno);
extern bool op_strict(Oid opno);
extern char op_volatile(Oid opno);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.92 2006/10/04 00:30:10 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.93 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -165,16 +165,15 @@ typedef struct RelationData
Form_pg_index rd_index; /* pg_index tuple describing this index */
struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */
/* "struct HeapTupleData *" avoids need to include htup.h here */
oidvector *rd_indclass; /* extracted pointer to rd_index field */
Form_pg_am rd_am; /* pg_am tuple for index's AM */
/*
* index access support info (used only for an index relation)
*
* Note: only default operators and support procs for each opclass are
* cached, namely those with subtype zero. The arrays are indexed by
* strategy or support number, which is a sufficient identifier given that
* restriction.
* cached, namely those with lefttype and righttype equal to the opclass's
* opcintype. The arrays are indexed by strategy or support number,
* which is a sufficient identifier given that restriction.
*
* Note: rd_amcache is available for index AMs to cache private data about
* an index. This must be just a cache since it may get reset at any time
@ -185,6 +184,8 @@ typedef struct RelationData
*/
MemoryContext rd_indexcxt; /* private memory cxt for this stuff */
RelationAmInfo *rd_aminfo; /* lookup info for funcs found in pg_am */
Oid *rd_opfamily; /* OIDs of op families for each index col */
Oid *rd_opcintype; /* OIDs of opclass declared input data types */
Oid *rd_operator; /* OIDs of index operators */
RegProcedure *rd_support; /* OIDs of support procedures */
FmgrInfo *rd_supportinfo; /* lookup info for support procedures */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.36 2006/10/04 00:30:11 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/selfuncs.h,v 1.37 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -160,6 +160,7 @@ extern Selectivity rowcomparesel(PlannerInfo *root,
int varRelid, JoinType jointype);
extern void mergejoinscansel(PlannerInfo *root, Node *clause,
Oid opfamily, int strategy,
Selectivity *leftscan,
Selectivity *rightscan);

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.65 2006/07/13 18:01:02 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.66 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -48,21 +48,22 @@
#define CONOID 17
#define DATABASEOID 18
#define INDEXRELID 19
#define INHRELID 20
#define LANGNAME 21
#define LANGOID 22
#define NAMESPACENAME 23
#define NAMESPACEOID 24
#define OPERNAMENSP 25
#define OPEROID 26
#define PROCNAMEARGSNSP 27
#define PROCOID 28
#define RELNAMENSP 29
#define RELOID 30
#define RULERELNAME 31
#define STATRELATT 32
#define TYPENAMENSP 33
#define TYPEOID 34
#define LANGNAME 20
#define LANGOID 21
#define NAMESPACENAME 22
#define NAMESPACEOID 23
#define OPERNAMENSP 24
#define OPEROID 25
#define OPFAMILYAMNAMENSP 26
#define OPFAMILYOID 27
#define PROCNAMEARGSNSP 28
#define PROCOID 29
#define RELNAMENSP 30
#define RELOID 31
#define RULERELNAME 32
#define STATRELATT 33
#define TYPENAMENSP 34
#define TYPEOID 35
extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void);

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/typcache.h,v 1.12 2006/10/04 00:30:11 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/typcache.h,v 1.13 2006/12/23 00:43:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -33,17 +33,19 @@ typedef struct TypeCacheEntry
Oid typrelid;
/*
* Information obtained from opclass entries
* Information obtained from opfamily entries
*
* These will be InvalidOid if no match could be found, or if the
* information hasn't yet been requested.
*/
Oid btree_opc; /* OID of the default btree opclass */
Oid hash_opc; /* OID of the default hash opclass */
Oid eq_opr; /* OID of the equality operator */
Oid lt_opr; /* OID of the less-than operator */
Oid gt_opr; /* OID of the greater-than operator */
Oid cmp_proc; /* OID of the btree comparison function */
Oid btree_opf; /* the default btree opclass' family */
Oid btree_opintype; /* the default btree opclass' opcintype */
Oid hash_opf; /* the default hash opclass' family */
Oid hash_opintype; /* the default hash opclass' opcintype */
Oid eq_opr; /* the equality operator */
Oid lt_opr; /* the less-than operator */
Oid gt_opr; /* the greater-than operator */
Oid cmp_proc; /* the btree comparison function */
/*
* Pre-set-up fmgr call info for the equality operator and the btree
@ -71,6 +73,7 @@ typedef struct TypeCacheEntry
#define TYPECACHE_EQ_OPR_FINFO 0x0010
#define TYPECACHE_CMP_PROC_FINFO 0x0020
#define TYPECACHE_TUPDESC 0x0040
#define TYPECACHE_BTREE_OPFAMILY 0x0080
extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);

View File

@ -137,20 +137,36 @@ WHERE amcostestimate != 0 AND
------+----------------
(0 rows)
SELECT ctid, amopclaid
FROM pg_catalog.pg_amop fk
WHERE amopclaid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid);
ctid | amopclaid
SELECT ctid, amoptions
FROM pg_catalog.pg_am fk
WHERE amoptions != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
ctid | amoptions
------+-----------
(0 rows)
SELECT ctid, amopsubtype
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopsubtype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amopsubtype);
ctid | amopsubtype
------+-------------
WHERE amopfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
ctid | amopfamily
------+------------
(0 rows)
SELECT ctid, amoplefttype
FROM pg_catalog.pg_amop fk
WHERE amoplefttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype);
ctid | amoplefttype
------+--------------
(0 rows)
SELECT ctid, amoprighttype
FROM pg_catalog.pg_amop fk
WHERE amoprighttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype);
ctid | amoprighttype
------+---------------
(0 rows)
SELECT ctid, amopopr
@ -161,20 +177,36 @@ WHERE amopopr != 0 AND
------+---------
(0 rows)
SELECT ctid, amopclaid
FROM pg_catalog.pg_amproc fk
WHERE amopclaid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid);
ctid | amopclaid
------+-----------
SELECT ctid, amopmethod
FROM pg_catalog.pg_amop fk
WHERE amopmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
ctid | amopmethod
------+------------
(0 rows)
SELECT ctid, amprocsubtype
SELECT ctid, amprocfamily
FROM pg_catalog.pg_amproc fk
WHERE amprocsubtype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocsubtype);
ctid | amprocsubtype
------+---------------
WHERE amprocfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
ctid | amprocfamily
------+--------------
(0 rows)
SELECT ctid, amproclefttype
FROM pg_catalog.pg_amproc fk
WHERE amproclefttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype);
ctid | amproclefttype
------+----------------
(0 rows)
SELECT ctid, amprocrighttype
FROM pg_catalog.pg_amproc fk
WHERE amprocrighttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype);
ctid | amprocrighttype
------+-----------------
(0 rows)
SELECT ctid, amproc
@ -241,6 +273,14 @@ WHERE reltype != 0 AND
------+---------
(0 rows)
SELECT ctid, relowner
FROM pg_catalog.pg_class fk
WHERE relowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner);
ctid | relowner
------+----------
(0 rows)
SELECT ctid, relam
FROM pg_catalog.pg_class fk
WHERE relam != 0 AND
@ -297,6 +337,14 @@ WHERE connamespace != 0 AND
------+--------------
(0 rows)
SELECT ctid, conowner
FROM pg_catalog.pg_conversion fk
WHERE conowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner);
ctid | conowner
------+----------
(0 rows)
SELECT ctid, conproc
FROM pg_catalog.pg_conversion fk
WHERE conproc != 0 AND
@ -305,6 +353,14 @@ WHERE conproc != 0 AND
------+---------
(0 rows)
SELECT ctid, datdba
FROM pg_catalog.pg_database fk
WHERE datdba != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba);
ctid | datdba
------+--------
(0 rows)
SELECT ctid, dattablespace
FROM pg_catalog.pg_database fk
WHERE dattablespace != 0 AND
@ -361,12 +417,20 @@ WHERE lanvalidator != 0 AND
------+--------------
(0 rows)
SELECT ctid, opcamid
SELECT ctid, nspowner
FROM pg_catalog.pg_namespace fk
WHERE nspowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner);
ctid | nspowner
------+----------
(0 rows)
SELECT ctid, opcmethod
FROM pg_catalog.pg_opclass fk
WHERE opcamid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcamid);
ctid | opcamid
------+---------
WHERE opcmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
ctid | opcmethod
------+-----------
(0 rows)
SELECT ctid, opcnamespace
@ -377,6 +441,22 @@ WHERE opcnamespace != 0 AND
------+--------------
(0 rows)
SELECT ctid, opcowner
FROM pg_catalog.pg_opclass fk
WHERE opcowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner);
ctid | opcowner
------+----------
(0 rows)
SELECT ctid, opcfamily
FROM pg_catalog.pg_opclass fk
WHERE opcfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily);
ctid | opcfamily
------+-----------
(0 rows)
SELECT ctid, opcintype
FROM pg_catalog.pg_opclass fk
WHERE opcintype != 0 AND
@ -385,6 +465,14 @@ WHERE opcintype != 0 AND
------+-----------
(0 rows)
SELECT ctid, opckeytype
FROM pg_catalog.pg_opclass fk
WHERE opckeytype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype);
ctid | opckeytype
------+------------
(0 rows)
SELECT ctid, oprnamespace
FROM pg_catalog.pg_operator fk
WHERE oprnamespace != 0 AND
@ -393,6 +481,14 @@ WHERE oprnamespace != 0 AND
------+--------------
(0 rows)
SELECT ctid, oprowner
FROM pg_catalog.pg_operator fk
WHERE oprowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner);
ctid | oprowner
------+----------
(0 rows)
SELECT ctid, oprleft
FROM pg_catalog.pg_operator fk
WHERE oprleft != 0 AND
@ -433,38 +529,6 @@ WHERE oprnegate != 0 AND
------+-----------
(0 rows)
SELECT ctid, oprlsortop
FROM pg_catalog.pg_operator fk
WHERE oprlsortop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprlsortop);
ctid | oprlsortop
------+------------
(0 rows)
SELECT ctid, oprrsortop
FROM pg_catalog.pg_operator fk
WHERE oprrsortop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprrsortop);
ctid | oprrsortop
------+------------
(0 rows)
SELECT ctid, oprltcmpop
FROM pg_catalog.pg_operator fk
WHERE oprltcmpop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprltcmpop);
ctid | oprltcmpop
------+------------
(0 rows)
SELECT ctid, oprgtcmpop
FROM pg_catalog.pg_operator fk
WHERE oprgtcmpop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprgtcmpop);
ctid | oprgtcmpop
------+------------
(0 rows)
SELECT ctid, oprcode
FROM pg_catalog.pg_operator fk
WHERE oprcode != 0 AND
@ -489,6 +553,30 @@ WHERE oprjoin != 0 AND
------+---------
(0 rows)
SELECT ctid, opfmethod
FROM pg_catalog.pg_opfamily fk
WHERE opfmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod);
ctid | opfmethod
------+-----------
(0 rows)
SELECT ctid, opfnamespace
FROM pg_catalog.pg_opfamily fk
WHERE opfnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace);
ctid | opfnamespace
------+--------------
(0 rows)
SELECT ctid, opfowner
FROM pg_catalog.pg_opfamily fk
WHERE opfowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
ctid | opfowner
------+----------
(0 rows)
SELECT ctid, pronamespace
FROM pg_catalog.pg_proc fk
WHERE pronamespace != 0 AND
@ -497,6 +585,14 @@ WHERE pronamespace != 0 AND
------+--------------
(0 rows)
SELECT ctid, proowner
FROM pg_catalog.pg_proc fk
WHERE proowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner);
ctid | proowner
------+----------
(0 rows)
SELECT ctid, prolang
FROM pg_catalog.pg_proc fk
WHERE prolang != 0 AND
@ -521,6 +617,22 @@ WHERE ev_class != 0 AND
------+----------
(0 rows)
SELECT ctid, refclassid
FROM pg_catalog.pg_shdepend fk
WHERE refclassid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
ctid | refclassid
------+------------
(0 rows)
SELECT ctid, classoid
FROM pg_catalog.pg_shdescription fk
WHERE classoid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
ctid | classoid
------+----------
(0 rows)
SELECT ctid, starelid
FROM pg_catalog.pg_statistic fk
WHERE starelid != 0 AND
@ -553,6 +665,14 @@ WHERE staop3 != 0 AND
------+--------
(0 rows)
SELECT ctid, spcowner
FROM pg_catalog.pg_tablespace fk
WHERE spcowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner);
ctid | spcowner
------+----------
(0 rows)
SELECT ctid, tgrelid
FROM pg_catalog.pg_trigger fk
WHERE tgrelid != 0 AND
@ -577,6 +697,14 @@ WHERE typnamespace != 0 AND
------+--------------
(0 rows)
SELECT ctid, typowner
FROM pg_catalog.pg_type fk
WHERE typowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner);
ctid | typowner
------+----------
(0 rows)
SELECT ctid, typrelid
FROM pg_catalog.pg_type fk
WHERE typrelid != 0 AND

View File

@ -1,7 +1,8 @@
--
-- OPR_SANITY
-- Sanity checks for common errors in making operator/procedure system tables:
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am,
-- pg_amop, pg_amproc, pg_opclass, pg_opfamily.
--
-- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-).
@ -374,158 +375,58 @@ WHERE p1.oprnegate = p2.oid AND
-----+---------+-----+---------
(0 rows)
-- Look for mergejoin operators that don't match their links.
-- An lsortop/rsortop link leads from an '=' operator to the
-- sort operator ('<' operator) that's appropriate for
-- its left-side or right-side data type.
-- An ltcmpop/gtcmpop link leads from an '=' operator to the
-- '<' or '>' operator of the same input datatypes.
-- (If the '=' operator has identical L and R input datatypes,
-- then lsortop, rsortop, and ltcmpop are all the same operator.)
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprlsortop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('<', '~<~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprleft != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
oid | oprcode | oid | oprcode
-----+---------+-----+---------
(0 rows)
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprrsortop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('<', '~<~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprright != p2.oprleft OR
p1.oprright != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
oid | oprcode | oid | oprcode
-----+---------+-----+---------
(0 rows)
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprltcmpop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('<', '~<~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprright != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
oid | oprcode | oid | oprcode
-----+---------+-----+---------
(0 rows)
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprgtcmpop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('>', '~>~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprright != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
oid | oprcode | oid | oprcode
-----+---------+-----+---------
(0 rows)
-- Make sure all four links are specified if any are.
SELECT p1.oid, p1.oprcode
FROM pg_operator AS p1
WHERE NOT ((oprlsortop = 0 AND oprrsortop = 0 AND
oprltcmpop = 0 AND oprgtcmpop = 0) OR
(oprlsortop != 0 AND oprrsortop != 0 AND
oprltcmpop != 0 AND oprgtcmpop != 0));
oid | oprcode
-----+---------
(0 rows)
-- A mergejoinable = operator must have a commutator (usually itself).
-- A mergejoinable or hashjoinable operator must be binary, must return
-- boolean, and must have a commutator (itself, unless it's a cross-type
-- operator).
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
WHERE p1.oprlsortop != 0 AND
p1.oprcom = 0;
WHERE (p1.oprcanmerge OR p1.oprcanhash) AND NOT
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND p1.oprcom != 0);
oid | oprname
-----+---------
(0 rows)
-- Mergejoinable operators across datatypes must come in closed sets, that
-- is if you provide int2 = int4 and int4 = int8 then you must also provide
-- int2 = int8 (and commutators of all these). This is necessary because
-- the planner tries to deduce additional qual clauses from transitivity
-- of mergejoinable operators. If there are clauses int2var = int4var and
-- int4var = int8var, the planner will deduce int2var = int8var ... and it
-- had better have a way to represent it.
SELECT p1.oid, p2.oid FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprlsortop != p1.oprrsortop AND
p1.oprrsortop = p2.oprlsortop AND
p2.oprlsortop != p2.oprrsortop AND
NOT EXISTS (SELECT 1 FROM pg_operator p3 WHERE
p3.oprlsortop = p1.oprlsortop AND p3.oprrsortop = p2.oprrsortop);
oid | oid
-----+-----
(0 rows)
-- Hashing only works on simple equality operators "type = sametype",
-- since the hash itself depends on the bitwise representation of the type.
-- Check that allegedly hashable operators look like they might be "=".
-- Mergejoinable operators should appear as equality members of btree index
-- opfamilies.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
p1.oprleft = p1.oprright AND p1.oprname IN ('=', '~=~') AND
p1.oprcom = p1.oid);
oid | oprname
-----+---------
(0 rows)
-- In 6.5 we accepted hashable array equality operators when the array element
-- type is hashable. However, what we actually need to make hashjoin work on
-- an array is a hashable element type *and* no padding between elements in
-- the array storage (or, perhaps, guaranteed-zero padding). Currently,
-- since the padding code in arrayfuncs.c is pretty bogus, it seems safest
-- to just forbid hashjoin on array equality ops.
-- This should be reconsidered someday.
-- -- Look for array equality operators that are hashable when the underlying
-- -- type is not, or vice versa. This is presumably bogus.
--
-- SELECT p1.oid, p1.oprcanhash, p2.oid, p2.oprcanhash, t1.typname, t2.typname
-- FROM pg_operator AS p1, pg_operator AS p2, pg_type AS t1, pg_type AS t2
-- WHERE p1.oprname = '=' AND p1.oprleft = p1.oprright AND
-- p2.oprname = '=' AND p2.oprleft = p2.oprright AND
-- p1.oprleft = t1.oid AND p2.oprleft = t2.oid AND t1.typelem = t2.oid AND
-- p1.oprcanhash != p2.oprcanhash;
-- Substitute check: forbid hashable array ops, period.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprcanhash AND p1.oprcode = p2.oid AND p2.proname = 'array_eq';
oid | oprname
-----+---------
(0 rows)
-- Hashable operators should appear as members of hash index opclasses.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT EXISTS
(SELECT 1 FROM pg_opclass op JOIN pg_amop p ON op.oid = amopclaid
WHERE opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') AND
amopopr = p1.oid);
WHERE p1.oprcanmerge AND NOT EXISTS
(SELECT 1 FROM pg_amop
WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
amopopr = p1.oid AND amopstrategy = 3);
oid | oprname
-----+---------
(0 rows)
-- And the converse.
SELECT p1.oid, p1.oprname, op.opcname
FROM pg_operator AS p1, pg_opclass op, pg_amop p
WHERE amopopr = p1.oid AND amopclaid = op.oid
AND opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash')
SELECT p1.oid, p1.oprname, p.amopfamily
FROM pg_operator AS p1, pg_amop p
WHERE amopopr = p1.oid
AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND amopstrategy = 3
AND NOT p1.oprcanmerge;
oid | oprname | amopfamily
-----+---------+------------
(0 rows)
-- Hashable operators should appear as members of hash index opfamilies.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT EXISTS
(SELECT 1 FROM pg_amop
WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') AND
amopopr = p1.oid AND amopstrategy = 1);
oid | oprname
-----+---------
(0 rows)
-- And the converse.
SELECT p1.oid, p1.oprname, p.amopfamily
FROM pg_operator AS p1, pg_amop p
WHERE amopopr = p1.oid
AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND NOT p1.oprcanhash;
oid | oprname | opcname
-----+---------+---------
oid | oprname | amopfamily
-----+---------+------------
(0 rows)
-- Check that each operator defined in pg_operator matches its oprcode entry
@ -571,7 +472,7 @@ WHERE p1.oprcode = p2.oid AND
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprcode = p2.oid AND
(p1.oprlsortop != 0 OR p1.oprcanhash) AND
(p1.oprcanmerge OR p1.oprcanhash) AND
p2.provolatile = 'v';
oid | oprname | oid | proname
-----+---------+-----+---------
@ -720,14 +621,15 @@ WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
----------+-----
(0 rows)
-- Check operator is a suitable btree opclass member
-- Check operator is a suitable btree opfamily member
SELECT a.aggfnoid::oid, o.oid
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
NOT EXISTS(SELECT 1 FROM pg_amop ao, pg_opclass oc
WHERE amopclaid = oc.oid AND amopsubtype = 0
AND amopopr = o.oid AND opcamid = 403
AND opcintype = o.oprleft AND opcdefault);
NOT EXISTS(SELECT 1 FROM pg_amop
WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND amopopr = o.oid
AND amoplefttype = o.oprleft
AND amoprighttype = o.oprright);
aggfnoid | oid
----------+-----
(0 rows)
@ -735,31 +637,50 @@ WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
-- Check correspondence of btree strategies and names
SELECT DISTINCT proname, oprname, amopstrategy
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p,
pg_amop as ao, pg_opclass oc
pg_amop as ao
WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
amopclaid = oc.oid AND amopopr = o.oid AND opcamid = 403
ORDER BY 1;
amopopr = o.oid AND
amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
ORDER BY 1, 2;
proname | oprname | amopstrategy
---------+---------+--------------
max | > | 5
min | < | 1
(2 rows)
-- **************** pg_opclass ****************
-- Look for illegal values in pg_opclass fields
-- **************** pg_opfamily ****************
-- Look for illegal values in pg_opfamily fields
SELECT p1.oid
FROM pg_opclass as p1
WHERE p1.opcamid = 0 OR p1.opcintype = 0;
FROM pg_opfamily as p1
WHERE p1.opfmethod = 0 OR p1.opfnamespace = 0;
oid
-----
(0 rows)
-- **************** pg_opclass ****************
-- Look for illegal values in pg_opclass fields
SELECT p1.oid
FROM pg_opclass AS p1
WHERE p1.opcmethod = 0 OR p1.opcnamespace = 0 OR p1.opcfamily = 0
OR p1.opcintype = 0;
oid
-----
(0 rows)
-- opcmethod must match owning opfamily's opfmethod
SELECT p1.oid, p2.oid
FROM pg_opclass AS p1, pg_opfamily AS p2
WHERE p1.opcfamily = p2.oid AND p1.opcmethod != p2.opfmethod;
oid | oid
-----+-----
(0 rows)
-- There should not be multiple entries in pg_opclass with opcdefault true
-- and the same opcamid/opcintype combination.
-- and the same opcmethod/opcintype combination.
SELECT p1.oid, p2.oid
FROM pg_opclass AS p1, pg_opclass AS p2
WHERE p1.oid != p2.oid AND
p1.opcamid = p2.opcamid AND p1.opcintype = p2.opcintype AND
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
oid | oid
-----+-----
@ -767,181 +688,221 @@ WHERE p1.oid != p2.oid AND
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopclaid, p1.amopstrategy
SELECT p1.amopfamily, p1.amopstrategy
FROM pg_amop as p1
WHERE p1.amopclaid = 0 OR p1.amopstrategy <= 0 OR p1.amopopr = 0;
amopclaid | amopstrategy
-----------+--------------
WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
OR p1.amopopr = 0 OR p1.amopmethod = 0 OR p1.amopstrategy < 1;
amopfamily | amopstrategy
------------+--------------
(0 rows)
-- amoplefttype/amoprighttype must match the operator
SELECT p1.oid, p2.oid
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND NOT
(p1.amoplefttype = p2.oprleft AND p1.amoprighttype = p2.oprright);
oid | oid
-----+-----
(0 rows)
-- amopmethod must match owning opfamily's opfmethod
SELECT p1.oid, p2.oid
FROM pg_amop AS p1, pg_opfamily AS p2
WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
oid | oid
-----+-----
(0 rows)
-- Cross-check amopstrategy index against parent AM
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
amopclaid | amopopr | oid | amname
-----------+---------+-----+--------
amopfamily | amopopr | oid | amname
------------+---------+-----+--------
(0 rows)
-- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each opclass for the AM. When nondefault subtypes are
-- present, enforce condition separately for each subtype.
-- as AM expects for each datatype combination supported by the opfamily.
-- We can't check this for AMs with variable strategy sets.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amopsubtype
FROM pg_am AS p1, pg_opclass AS p2, pg_amop AS p3
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
p1.amstrategies <> 0 AND
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p4
WHERE p4.amopclaid = p2.oid AND
p4.amopsubtype = p3.amopsubtype);
oid | amname | oid | opcname | amopsubtype
-----+--------+-----+---------+-------------
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype);
amname | amoplefttype | amoprighttype
--------+--------------+---------------
(0 rows)
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator yielding boolean.
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
amopclaid | amopopr | oid | oprname
-----------+---------+-----+---------
amopfamily | amopopr | oid | oprname
------------+---------+-----+---------
(0 rows)
-- Make a list of all the distinct operator names being used in particular
-- strategy slots. This is a bit hokey, since the list might need to change
-- in future releases, but it's an effective way of spotting mistakes such as
-- swapping two operators within a class.
SELECT DISTINCT opcamid, amopstrategy, oprname
FROM pg_amop p1 LEFT JOIN pg_opclass p2 ON amopclaid = p2.oid
LEFT JOIN pg_operator p3 ON amopopr = p3.oid
-- swapping two operators within a family.
SELECT DISTINCT amopmethod, amopstrategy, oprname
FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
ORDER BY 1, 2, 3;
opcamid | amopstrategy | oprname
---------+--------------+---------
403 | 1 | <
403 | 1 | ~<~
403 | 2 | <=
403 | 2 | ~<=~
403 | 3 | =
403 | 3 | ~=~
403 | 4 | >=
403 | 4 | ~>=~
403 | 5 | >
403 | 5 | ~>~
405 | 1 | =
405 | 1 | ~=~
783 | 1 | <<
783 | 2 | &<
783 | 3 | &&
783 | 4 | &>
783 | 5 | >>
783 | 6 | ~=
783 | 7 | @>
783 | 8 | <@
783 | 9 | &<|
783 | 10 | <<|
783 | 11 | |>>
783 | 12 | |&>
783 | 13 | ~
783 | 14 | @
2742 | 1 | &&
2742 | 2 | @>
2742 | 3 | <@
2742 | 4 | =
amopmethod | amopstrategy | oprname
------------+--------------+---------
403 | 1 | <
403 | 1 | ~<~
403 | 2 | <=
403 | 2 | ~<=~
403 | 3 | =
403 | 3 | ~=~
403 | 4 | >=
403 | 4 | ~>=~
403 | 5 | >
403 | 5 | ~>~
405 | 1 | =
405 | 1 | ~=~
783 | 1 | <<
783 | 2 | &<
783 | 3 | &&
783 | 4 | &>
783 | 5 | >>
783 | 6 | ~=
783 | 7 | @>
783 | 8 | <@
783 | 9 | &<|
783 | 10 | <<|
783 | 11 | |>>
783 | 12 | |&>
783 | 13 | ~
783 | 14 | @
2742 | 1 | &&
2742 | 2 | @>
2742 | 3 | <@
2742 | 4 | =
(30 rows)
-- Check that all operators linked to by opclass entries have selectivity
-- estimators. This is not absolutely required, but it seems a reasonable
-- thing to insist on for all standard datatypes.
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND
(p2.oprrest = 0 OR p2.oprjoin = 0);
amopclaid | amopopr | oid | oprname
-----------+---------+-----+---------
amopfamily | amopopr | oid | oprname
------------+---------+-----+---------
(0 rows)
-- Check that operator input types match the opclass
-- For 8.0, we require that oprleft match opcintype (possibly by coercion).
-- When amopsubtype is zero (default), oprright must equal oprleft;
-- when amopsubtype is not zero, oprright must equal amopsubtype.
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
NOT binary_coercible(p3.opcintype, p2.oprleft);
amopclaid | amopopr | oid | oprname | opcname
-----------+---------+-----+---------+---------
(0 rows)
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
p1.amopsubtype = 0 AND
p2.oprleft != p2.oprright;
amopclaid | amopopr | oid | oprname | opcname
-----------+---------+-----+---------+---------
(0 rows)
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
p1.amopsubtype != 0 AND
p1.amopsubtype != p2.oprright;
amopclaid | amopopr | oid | oprname | opcname
-----------+---------+-----+---------+---------
-- Check that each opclass in an opfamily has associated operators, that is
-- ones whose oprleft matches opcintype (possibly by coercion).
SELECT p1.opcname, p1.opcfamily
FROM pg_opclass AS p1
WHERE NOT EXISTS(SELECT 1 FROM pg_amop AS p2
WHERE p2.amopfamily = p1.opcfamily
AND binary_coercible(p1.opcintype, p2.amoplefttype));
opcname | opcfamily
---------+-----------
(0 rows)
-- Operators that are primary members of opclasses must be immutable (else
-- it suggests that the index ordering isn't fixed). Operators that are
-- cross-type members need only be stable, since they are just shorthands
-- for index probe queries.
SELECT p1.amopclaid, p1.amopopr, p2.oprname, p3.prosrc
SELECT p1.amopfamily, p1.amopopr, p2.oprname, p3.prosrc
FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype = 0 AND
p1.amoplefttype = p1.amoprighttype AND
p3.provolatile != 'i';
amopclaid | amopopr | oprname | prosrc
-----------+---------+---------+--------
amopfamily | amopopr | oprname | prosrc
------------+---------+---------+--------
(0 rows)
SELECT p1.amopclaid, p1.amopopr, p2.oprname, p3.prosrc
SELECT p1.amopfamily, p1.amopopr, p2.oprname, p3.prosrc
FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype != 0 AND
p1.amoplefttype != p1.amoprighttype AND
p3.provolatile = 'v';
amopclaid | amopopr | oprname | prosrc
-----------+---------+---------+--------
amopfamily | amopopr | oprname | prosrc
------------+---------+---------+--------
(0 rows)
-- Multiple-datatype btree opclasses should provide closed sets of equality
-- operators; that is if you provide int2 = int4 and int4 = int8 then you
-- must also provide int2 = int8 (and commutators of all these). This is
-- necessary because the planner tries to deduce additional qual clauses from
-- transitivity of mergejoinable operators. If there are clauses
-- int2var = int4var and int4var = int8var, the planner will deduce
-- int2var = int8var ... and it had better have a way to represent it.
-- check commutative closure
SELECT p1.amoplefttype, p1.amoprighttype
FROM pg_amop AS p1
WHERE p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p1.amopstrategy = 3 AND
p1.amoplefttype != p1.amoprighttype AND
NOT EXISTS(SELECT 1 FROM pg_amop p2 WHERE
p2.amopfamily = p1.amopfamily AND
p2.amoplefttype = p1.amoprighttype AND
p2.amoprighttype = p1.amoplefttype AND
p2.amopstrategy = 3);
amoplefttype | amoprighttype
--------------+---------------
(0 rows)
-- check transitive closure
SELECT p1.amoplefttype, p1.amoprighttype, p2.amoprighttype
FROM pg_amop AS p1, pg_amop AS p2
WHERE p1.amopfamily = p2.amopfamily AND
p1.amoprighttype = p2.amoplefttype AND
p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p2.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p1.amopstrategy = 3 AND p2.amopstrategy = 3 AND
p1.amoplefttype != p1.amoprighttype AND
p2.amoplefttype != p2.amoprighttype AND
NOT EXISTS(SELECT 1 FROM pg_amop p3 WHERE
p3.amopfamily = p1.amopfamily AND
p3.amoplefttype = p1.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
p3.amopstrategy = 3);
amoplefttype | amoprighttype | amoprighttype
--------------+---------------+---------------
(0 rows)
-- **************** pg_amproc ****************
-- Look for illegal values in pg_amproc fields
SELECT p1.amopclaid, p1.amprocnum
SELECT p1.amprocfamily, p1.amprocnum
FROM pg_amproc as p1
WHERE p1.amopclaid = 0 OR p1.amprocnum <= 0 OR p1.amproc = 0;
amopclaid | amprocnum
-----------+-----------
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
amprocfamily | amprocnum
--------------+-----------
(0 rows)
-- Cross-check amprocnum index against parent AM
SELECT p1.amopclaid, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opclass AS p3
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
p1.amprocnum > p2.amsupport;
amopclaid | amprocnum | oid | amname
-----------+-----------+-----+--------
amprocfamily | amprocnum | oid | amname
--------------+-----------+-----+--------
(0 rows)
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each opclass for the AM. When nondefault subtypes are
-- present, enforce condition separately for each subtype.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amprocsubtype
FROM pg_am AS p1, pg_opclass AS p2, pg_amproc AS p3
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
-- as AM expects for each datatype combination supported by the opfamily.
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4
WHERE p4.amopclaid = p2.oid AND
p4.amprocsubtype = p3.amprocsubtype);
oid | amname | oid | opcname | amprocsubtype
-----+--------+-----+---------+---------------
WHERE p4.amprocfamily = p2.oid AND
p4.amproclefttype = p3.amproclefttype AND
p4.amprocrighttype = p3.amprocrighttype);
amname | opfname | amproclefttype | amprocrighttype
--------+---------+----------------+-----------------
(0 rows)
-- Unfortunately, we can't check the amproc link very well because the
@ -950,101 +911,79 @@ WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
-- We can check that all the referenced instances of the same support
-- routine number take the same number of parameters, but that's about it
-- for a general check...
SELECT p1.amopclaid, p1.amprocnum,
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname,
p4.amopclaid, p4.amprocnum,
p3.opfname,
p4.amprocfamily, p4.amprocnum,
p5.oid, p5.proname,
p6.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3,
pg_amproc AS p4, pg_proc AS p5, pg_opclass AS p6
WHERE p1.amopclaid = p3.oid AND p4.amopclaid = p6.oid AND
p3.opcamid = p6.opcamid AND p1.amprocnum = p4.amprocnum AND
p6.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3,
pg_amproc AS p4, pg_proc AS p5, pg_opfamily AS p6
WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND
p3.opfmethod = p6.opfmethod AND p1.amprocnum = p4.amprocnum AND
p1.amproc = p2.oid AND p4.amproc = p5.oid AND
(p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs);
amopclaid | amprocnum | oid | proname | opcname | amopclaid | amprocnum | oid | proname | opcname
-----------+-----------+-----+---------+---------+-----------+-----------+-----+---------+---------
amprocfamily | amprocnum | oid | proname | opfname | amprocfamily | amprocnum | oid | proname | opfname
--------------+-----------+-----+---------+---------+--------------+-----------+-----+---------+---------
(0 rows)
-- For btree, though, we can do better since we know the support routines
-- must be of the form cmp(input, input) returns int4 in the default case
-- (subtype = 0), and cmp(input, subtype) returns int4 when subtype != 0.
SELECT p1.amopclaid, p1.amprocnum,
-- must be of the form cmp(lefttype, righttype) returns int4.
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND
amprocsubtype = 0 AND
(opckeytype != 0
OR amprocnum != 1
p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
(amprocnum != 1
OR proretset
OR prorettype != 23
OR prorettype != 'int4'::regtype
OR pronargs != 2
OR NOT binary_coercible(opcintype, proargtypes[0])
OR proargtypes[0] != proargtypes[1]);
amopclaid | amprocnum | oid | proname | opcname
-----------+-----------+-----+---------+---------
(0 rows)
SELECT p1.amopclaid, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND
amprocsubtype != 0 AND
(opckeytype != 0
OR amprocnum != 1
OR proretset
OR prorettype != 23
OR pronargs != 2
OR NOT binary_coercible(opcintype, proargtypes[0])
OR proargtypes[1] != amprocsubtype);
amopclaid | amprocnum | oid | proname | opcname
-----------+-----------+-----+---------+---------
OR proargtypes[0] != amproclefttype
OR proargtypes[1] != amprocrighttype);
amprocfamily | amprocnum | oid | proname | opfname
--------------+-----------+-----+---------+---------
(0 rows)
-- For hash we can also do a little better: the support routines must be
-- of the form hash(something) returns int4. Ideally we'd check that the
-- opcintype is binary-coercible to the function's input, but there are
-- enough cases where that fails that I'll just leave out the check for now.
SELECT p1.amopclaid, p1.amprocnum,
-- of the form hash(lefttype) returns int4. There are several cases where
-- we cheat and use a hash function that is physically compatible with the
-- datatype even though there's no cast, so for now we can't check that.
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND
(opckeytype != 0
OR amprocnum != 1
p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
(amprocnum != 1
OR proretset
OR prorettype != 23
OR prorettype != 'int4'::regtype
OR pronargs != 1
-- OR NOT physically_coercible(opcintype, proargtypes[0])
);
amopclaid | amprocnum | oid | proname | opcname
-----------+-----------+-----+---------+---------
-- OR NOT physically_coercible(amproclefttype, proargtypes[0])
OR amproclefttype != amprocrighttype);
amprocfamily | amprocnum | oid | proname | opfname
--------------+-----------+-----+---------+---------
(0 rows)
-- Support routines that are primary members of opclasses must be immutable
-- Support routines that are primary members of opfamilies must be immutable
-- (else it suggests that the index ordering isn't fixed). But cross-type
-- members need only be stable, since they are just shorthands
-- for index probe queries.
SELECT p1.amopclaid, p1.amproc, p2.prosrc
SELECT p1.amprocfamily, p1.amproc, p2.prosrc
FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND
p1.amprocsubtype = 0 AND
p1.amproclefttype = p1.amprocrighttype AND
p2.provolatile != 'i';
amopclaid | amproc | prosrc
-----------+--------+--------
amprocfamily | amproc | prosrc
--------------+--------+--------
(0 rows)
SELECT p1.amopclaid, p1.amproc, p2.prosrc
SELECT p1.amprocfamily, p1.amproc, p2.prosrc
FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND
p1.amprocsubtype != 0 AND
p1.amproclefttype != p1.amprocrighttype AND
p2.provolatile = 'v';
amopclaid | amproc | prosrc
-----------+--------+--------
amprocfamily | amproc | prosrc
--------------+--------+--------
(0 rows)

View File

@ -203,7 +203,7 @@ select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
ERROR: could not determine interpretation of row comparison operator ~~
LINE 1: select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
^
HINT: Row comparison operators must be associated with btree operator classes.
HINT: Row comparison operators must be associated with btree operator families.
-- Check row comparison with a subselect
select unique1, unique2 from tenk1
where (unique1, unique2) < any (select ten, ten from tenk1 where hundred < 3);

View File

@ -105,6 +105,7 @@ SELECT relname, relhasindex
pg_namespace | t
pg_opclass | t
pg_operator | t
pg_opfamily | t
pg_pltemplate | t
pg_proc | t
pg_rewrite | t
@ -140,7 +141,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
(129 rows)
(130 rows)
--
-- another sanity check: every system catalog that has OIDs should have

View File

@ -69,26 +69,42 @@ SELECT ctid, amcostestimate
FROM pg_catalog.pg_am fk
WHERE amcostestimate != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
SELECT ctid, amopclaid
SELECT ctid, amoptions
FROM pg_catalog.pg_am fk
WHERE amoptions != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk
WHERE amopclaid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid);
SELECT ctid, amopsubtype
WHERE amopfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
SELECT ctid, amoplefttype
FROM pg_catalog.pg_amop fk
WHERE amopsubtype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amopsubtype);
WHERE amoplefttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoplefttype);
SELECT ctid, amoprighttype
FROM pg_catalog.pg_amop fk
WHERE amoprighttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amoprighttype);
SELECT ctid, amopopr
FROM pg_catalog.pg_amop fk
WHERE amopopr != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr);
SELECT ctid, amopclaid
SELECT ctid, amopmethod
FROM pg_catalog.pg_amop fk
WHERE amopmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
SELECT ctid, amprocfamily
FROM pg_catalog.pg_amproc fk
WHERE amopclaid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid);
SELECT ctid, amprocsubtype
WHERE amprocfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
SELECT ctid, amproclefttype
FROM pg_catalog.pg_amproc fk
WHERE amprocsubtype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocsubtype);
WHERE amproclefttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amproclefttype);
SELECT ctid, amprocrighttype
FROM pg_catalog.pg_amproc fk
WHERE amprocrighttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocrighttype);
SELECT ctid, amproc
FROM pg_catalog.pg_amproc fk
WHERE amproc != 0 AND
@ -121,6 +137,10 @@ SELECT ctid, reltype
FROM pg_catalog.pg_class fk
WHERE reltype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype);
SELECT ctid, relowner
FROM pg_catalog.pg_class fk
WHERE relowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.relowner);
SELECT ctid, relam
FROM pg_catalog.pg_class fk
WHERE relam != 0 AND
@ -149,10 +169,18 @@ SELECT ctid, connamespace
FROM pg_catalog.pg_conversion fk
WHERE connamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace);
SELECT ctid, conowner
FROM pg_catalog.pg_conversion fk
WHERE conowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.conowner);
SELECT ctid, conproc
FROM pg_catalog.pg_conversion fk
WHERE conproc != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc);
SELECT ctid, datdba
FROM pg_catalog.pg_database fk
WHERE datdba != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.datdba);
SELECT ctid, dattablespace
FROM pg_catalog.pg_database fk
WHERE dattablespace != 0 AND
@ -181,22 +209,42 @@ SELECT ctid, lanvalidator
FROM pg_catalog.pg_language fk
WHERE lanvalidator != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator);
SELECT ctid, opcamid
SELECT ctid, nspowner
FROM pg_catalog.pg_namespace fk
WHERE nspowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.nspowner);
SELECT ctid, opcmethod
FROM pg_catalog.pg_opclass fk
WHERE opcamid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcamid);
WHERE opcmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
SELECT ctid, opcnamespace
FROM pg_catalog.pg_opclass fk
WHERE opcnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace);
SELECT ctid, opcowner
FROM pg_catalog.pg_opclass fk
WHERE opcowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opcowner);
SELECT ctid, opcfamily
FROM pg_catalog.pg_opclass fk
WHERE opcfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.opcfamily);
SELECT ctid, opcintype
FROM pg_catalog.pg_opclass fk
WHERE opcintype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype);
SELECT ctid, opckeytype
FROM pg_catalog.pg_opclass fk
WHERE opckeytype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opckeytype);
SELECT ctid, oprnamespace
FROM pg_catalog.pg_operator fk
WHERE oprnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace);
SELECT ctid, oprowner
FROM pg_catalog.pg_operator fk
WHERE oprowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.oprowner);
SELECT ctid, oprleft
FROM pg_catalog.pg_operator fk
WHERE oprleft != 0 AND
@ -217,22 +265,6 @@ SELECT ctid, oprnegate
FROM pg_catalog.pg_operator fk
WHERE oprnegate != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate);
SELECT ctid, oprlsortop
FROM pg_catalog.pg_operator fk
WHERE oprlsortop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprlsortop);
SELECT ctid, oprrsortop
FROM pg_catalog.pg_operator fk
WHERE oprrsortop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprrsortop);
SELECT ctid, oprltcmpop
FROM pg_catalog.pg_operator fk
WHERE oprltcmpop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprltcmpop);
SELECT ctid, oprgtcmpop
FROM pg_catalog.pg_operator fk
WHERE oprgtcmpop != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprgtcmpop);
SELECT ctid, oprcode
FROM pg_catalog.pg_operator fk
WHERE oprcode != 0 AND
@ -245,10 +277,26 @@ SELECT ctid, oprjoin
FROM pg_catalog.pg_operator fk
WHERE oprjoin != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin);
SELECT ctid, opfmethod
FROM pg_catalog.pg_opfamily fk
WHERE opfmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opfmethod);
SELECT ctid, opfnamespace
FROM pg_catalog.pg_opfamily fk
WHERE opfnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opfnamespace);
SELECT ctid, opfowner
FROM pg_catalog.pg_opfamily fk
WHERE opfowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
SELECT ctid, pronamespace
FROM pg_catalog.pg_proc fk
WHERE pronamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace);
SELECT ctid, proowner
FROM pg_catalog.pg_proc fk
WHERE proowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.proowner);
SELECT ctid, prolang
FROM pg_catalog.pg_proc fk
WHERE prolang != 0 AND
@ -261,6 +309,14 @@ SELECT ctid, ev_class
FROM pg_catalog.pg_rewrite fk
WHERE ev_class != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class);
SELECT ctid, refclassid
FROM pg_catalog.pg_shdepend fk
WHERE refclassid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.refclassid);
SELECT ctid, classoid
FROM pg_catalog.pg_shdescription fk
WHERE classoid != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.classoid);
SELECT ctid, starelid
FROM pg_catalog.pg_statistic fk
WHERE starelid != 0 AND
@ -277,6 +333,10 @@ SELECT ctid, staop3
FROM pg_catalog.pg_statistic fk
WHERE staop3 != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3);
SELECT ctid, spcowner
FROM pg_catalog.pg_tablespace fk
WHERE spcowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.spcowner);
SELECT ctid, tgrelid
FROM pg_catalog.pg_trigger fk
WHERE tgrelid != 0 AND
@ -289,6 +349,10 @@ SELECT ctid, typnamespace
FROM pg_catalog.pg_type fk
WHERE typnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace);
SELECT ctid, typowner
FROM pg_catalog.pg_type fk
WHERE typowner != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.typowner);
SELECT ctid, typrelid
FROM pg_catalog.pg_type fk
WHERE typrelid != 0 AND

View File

@ -1,7 +1,8 @@
--
-- OPR_SANITY
-- Sanity checks for common errors in making operator/procedure system tables:
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am,
-- pg_amop, pg_amproc, pg_opclass, pg_opfamily.
--
-- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-).
@ -307,135 +308,48 @@ WHERE p1.oprnegate = p2.oid AND
p1.oid != p2.oprnegate OR
p1.oid = p2.oid);
-- Look for mergejoin operators that don't match their links.
-- An lsortop/rsortop link leads from an '=' operator to the
-- sort operator ('<' operator) that's appropriate for
-- its left-side or right-side data type.
-- An ltcmpop/gtcmpop link leads from an '=' operator to the
-- '<' or '>' operator of the same input datatypes.
-- (If the '=' operator has identical L and R input datatypes,
-- then lsortop, rsortop, and ltcmpop are all the same operator.)
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprlsortop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('<', '~<~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprleft != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprrsortop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('<', '~<~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprright != p2.oprleft OR
p1.oprright != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprltcmpop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('<', '~<~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprright != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprgtcmpop = p2.oid AND
(p1.oprname NOT IN ('=', '~=~') OR p2.oprname NOT IN ('>', '~>~') OR
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprright != p2.oprright OR
p1.oprresult != 'bool'::regtype OR
p2.oprresult != 'bool'::regtype);
-- Make sure all four links are specified if any are.
SELECT p1.oid, p1.oprcode
FROM pg_operator AS p1
WHERE NOT ((oprlsortop = 0 AND oprrsortop = 0 AND
oprltcmpop = 0 AND oprgtcmpop = 0) OR
(oprlsortop != 0 AND oprrsortop != 0 AND
oprltcmpop != 0 AND oprgtcmpop != 0));
-- A mergejoinable = operator must have a commutator (usually itself).
-- A mergejoinable or hashjoinable operator must be binary, must return
-- boolean, and must have a commutator (itself, unless it's a cross-type
-- operator).
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
WHERE p1.oprlsortop != 0 AND
p1.oprcom = 0;
WHERE (p1.oprcanmerge OR p1.oprcanhash) AND NOT
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND p1.oprcom != 0);
-- Mergejoinable operators across datatypes must come in closed sets, that
-- is if you provide int2 = int4 and int4 = int8 then you must also provide
-- int2 = int8 (and commutators of all these). This is necessary because
-- the planner tries to deduce additional qual clauses from transitivity
-- of mergejoinable operators. If there are clauses int2var = int4var and
-- int4var = int8var, the planner will deduce int2var = int8var ... and it
-- had better have a way to represent it.
SELECT p1.oid, p2.oid FROM pg_operator AS p1, pg_operator AS p2
WHERE p1.oprlsortop != p1.oprrsortop AND
p1.oprrsortop = p2.oprlsortop AND
p2.oprlsortop != p2.oprrsortop AND
NOT EXISTS (SELECT 1 FROM pg_operator p3 WHERE
p3.oprlsortop = p1.oprlsortop AND p3.oprrsortop = p2.oprrsortop);
-- Hashing only works on simple equality operators "type = sametype",
-- since the hash itself depends on the bitwise representation of the type.
-- Check that allegedly hashable operators look like they might be "=".
-- Mergejoinable operators should appear as equality members of btree index
-- opfamilies.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
p1.oprleft = p1.oprright AND p1.oprname IN ('=', '~=~') AND
p1.oprcom = p1.oid);
WHERE p1.oprcanmerge AND NOT EXISTS
(SELECT 1 FROM pg_amop
WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
amopopr = p1.oid AND amopstrategy = 3);
-- In 6.5 we accepted hashable array equality operators when the array element
-- type is hashable. However, what we actually need to make hashjoin work on
-- an array is a hashable element type *and* no padding between elements in
-- the array storage (or, perhaps, guaranteed-zero padding). Currently,
-- since the padding code in arrayfuncs.c is pretty bogus, it seems safest
-- to just forbid hashjoin on array equality ops.
-- This should be reconsidered someday.
-- And the converse.
-- -- Look for array equality operators that are hashable when the underlying
-- -- type is not, or vice versa. This is presumably bogus.
--
-- SELECT p1.oid, p1.oprcanhash, p2.oid, p2.oprcanhash, t1.typname, t2.typname
-- FROM pg_operator AS p1, pg_operator AS p2, pg_type AS t1, pg_type AS t2
-- WHERE p1.oprname = '=' AND p1.oprleft = p1.oprright AND
-- p2.oprname = '=' AND p2.oprleft = p2.oprright AND
-- p1.oprleft = t1.oid AND p2.oprleft = t2.oid AND t1.typelem = t2.oid AND
-- p1.oprcanhash != p2.oprcanhash;
SELECT p1.oid, p1.oprname, p.amopfamily
FROM pg_operator AS p1, pg_amop p
WHERE amopopr = p1.oid
AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND amopstrategy = 3
AND NOT p1.oprcanmerge;
-- Substitute check: forbid hashable array ops, period.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprcanhash AND p1.oprcode = p2.oid AND p2.proname = 'array_eq';
-- Hashable operators should appear as members of hash index opclasses.
-- Hashable operators should appear as members of hash index opfamilies.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT EXISTS
(SELECT 1 FROM pg_opclass op JOIN pg_amop p ON op.oid = amopclaid
WHERE opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') AND
amopopr = p1.oid);
(SELECT 1 FROM pg_amop
WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') AND
amopopr = p1.oid AND amopstrategy = 1);
-- And the converse.
SELECT p1.oid, p1.oprname, op.opcname
FROM pg_operator AS p1, pg_opclass op, pg_amop p
WHERE amopopr = p1.oid AND amopclaid = op.oid
AND opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash')
SELECT p1.oid, p1.oprname, p.amopfamily
FROM pg_operator AS p1, pg_amop p
WHERE amopopr = p1.oid
AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND NOT p1.oprcanhash;
-- Check that each operator defined in pg_operator matches its oprcode entry
@ -474,7 +388,7 @@ WHERE p1.oprcode = p2.oid AND
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprcode = p2.oid AND
(p1.oprlsortop != 0 OR p1.oprcanhash) AND
(p1.oprcanmerge OR p1.oprcanhash) AND
p2.provolatile = 'v';
-- If oprrest is set, the operator must return boolean,
@ -596,74 +510,105 @@ WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
(oprkind != 'b' OR oprresult != 'boolean'::regtype
OR oprleft != p.proargtypes[0] OR oprright != p.proargtypes[0]);
-- Check operator is a suitable btree opclass member
-- Check operator is a suitable btree opfamily member
SELECT a.aggfnoid::oid, o.oid
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
NOT EXISTS(SELECT 1 FROM pg_amop ao, pg_opclass oc
WHERE amopclaid = oc.oid AND amopsubtype = 0
AND amopopr = o.oid AND opcamid = 403
AND opcintype = o.oprleft AND opcdefault);
NOT EXISTS(SELECT 1 FROM pg_amop
WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND amopopr = o.oid
AND amoplefttype = o.oprleft
AND amoprighttype = o.oprright);
-- Check correspondence of btree strategies and names
SELECT DISTINCT proname, oprname, amopstrategy
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p,
pg_amop as ao, pg_opclass oc
pg_amop as ao
WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
amopclaid = oc.oid AND amopopr = o.oid AND opcamid = 403
ORDER BY 1;
amopopr = o.oid AND
amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
ORDER BY 1, 2;
-- **************** pg_opfamily ****************
-- Look for illegal values in pg_opfamily fields
SELECT p1.oid
FROM pg_opfamily as p1
WHERE p1.opfmethod = 0 OR p1.opfnamespace = 0;
-- **************** pg_opclass ****************
-- Look for illegal values in pg_opclass fields
SELECT p1.oid
FROM pg_opclass as p1
WHERE p1.opcamid = 0 OR p1.opcintype = 0;
FROM pg_opclass AS p1
WHERE p1.opcmethod = 0 OR p1.opcnamespace = 0 OR p1.opcfamily = 0
OR p1.opcintype = 0;
-- opcmethod must match owning opfamily's opfmethod
SELECT p1.oid, p2.oid
FROM pg_opclass AS p1, pg_opfamily AS p2
WHERE p1.opcfamily = p2.oid AND p1.opcmethod != p2.opfmethod;
-- There should not be multiple entries in pg_opclass with opcdefault true
-- and the same opcamid/opcintype combination.
-- and the same opcmethod/opcintype combination.
SELECT p1.oid, p2.oid
FROM pg_opclass AS p1, pg_opclass AS p2
WHERE p1.oid != p2.oid AND
p1.opcamid = p2.opcamid AND p1.opcintype = p2.opcintype AND
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
p1.opcdefault AND p2.opcdefault;
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT p1.amopclaid, p1.amopstrategy
SELECT p1.amopfamily, p1.amopstrategy
FROM pg_amop as p1
WHERE p1.amopclaid = 0 OR p1.amopstrategy <= 0 OR p1.amopopr = 0;
WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
OR p1.amopopr = 0 OR p1.amopmethod = 0 OR p1.amopstrategy < 1;
-- amoplefttype/amoprighttype must match the operator
SELECT p1.oid, p2.oid
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND NOT
(p1.amoplefttype = p2.oprleft AND p1.amoprighttype = p2.oprright);
-- amopmethod must match owning opfamily's opfmethod
SELECT p1.oid, p2.oid
FROM pg_amop AS p1, pg_opfamily AS p2
WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
-- Cross-check amopstrategy index against parent AM
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopmethod = p2.oid AND
p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each opclass for the AM. When nondefault subtypes are
-- present, enforce condition separately for each subtype.
-- as AM expects for each datatype combination supported by the opfamily.
-- We can't check this for AMs with variable strategy sets.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amopsubtype
FROM pg_am AS p1, pg_opclass AS p2, pg_amop AS p3
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_amop AS p2
WHERE p2.amopmethod = p1.oid AND
p1.amstrategies <> 0 AND
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p4
WHERE p4.amopclaid = p2.oid AND
p4.amopsubtype = p3.amopsubtype);
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p3.amopfamily = p2.amopfamily AND
p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype);
-- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator yielding boolean.
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
@ -671,86 +616,109 @@ WHERE p1.amopopr = p2.oid AND
-- Make a list of all the distinct operator names being used in particular
-- strategy slots. This is a bit hokey, since the list might need to change
-- in future releases, but it's an effective way of spotting mistakes such as
-- swapping two operators within a class.
-- swapping two operators within a family.
SELECT DISTINCT opcamid, amopstrategy, oprname
FROM pg_amop p1 LEFT JOIN pg_opclass p2 ON amopclaid = p2.oid
LEFT JOIN pg_operator p3 ON amopopr = p3.oid
SELECT DISTINCT amopmethod, amopstrategy, oprname
FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
ORDER BY 1, 2, 3;
-- Check that all operators linked to by opclass entries have selectivity
-- estimators. This is not absolutely required, but it seems a reasonable
-- thing to insist on for all standard datatypes.
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND
(p2.oprrest = 0 OR p2.oprjoin = 0);
-- Check that operator input types match the opclass
-- For 8.0, we require that oprleft match opcintype (possibly by coercion).
-- When amopsubtype is zero (default), oprright must equal oprleft;
-- when amopsubtype is not zero, oprright must equal amopsubtype.
-- Check that each opclass in an opfamily has associated operators, that is
-- ones whose oprleft matches opcintype (possibly by coercion).
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
NOT binary_coercible(p3.opcintype, p2.oprleft);
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
p1.amopsubtype = 0 AND
p2.oprleft != p2.oprright;
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
p1.amopsubtype != 0 AND
p1.amopsubtype != p2.oprright;
SELECT p1.opcname, p1.opcfamily
FROM pg_opclass AS p1
WHERE NOT EXISTS(SELECT 1 FROM pg_amop AS p2
WHERE p2.amopfamily = p1.opcfamily
AND binary_coercible(p1.opcintype, p2.amoplefttype));
-- Operators that are primary members of opclasses must be immutable (else
-- it suggests that the index ordering isn't fixed). Operators that are
-- cross-type members need only be stable, since they are just shorthands
-- for index probe queries.
SELECT p1.amopclaid, p1.amopopr, p2.oprname, p3.prosrc
SELECT p1.amopfamily, p1.amopopr, p2.oprname, p3.prosrc
FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype = 0 AND
p1.amoplefttype = p1.amoprighttype AND
p3.provolatile != 'i';
SELECT p1.amopclaid, p1.amopopr, p2.oprname, p3.prosrc
SELECT p1.amopfamily, p1.amopopr, p2.oprname, p3.prosrc
FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype != 0 AND
p1.amoplefttype != p1.amoprighttype AND
p3.provolatile = 'v';
-- Multiple-datatype btree opclasses should provide closed sets of equality
-- operators; that is if you provide int2 = int4 and int4 = int8 then you
-- must also provide int2 = int8 (and commutators of all these). This is
-- necessary because the planner tries to deduce additional qual clauses from
-- transitivity of mergejoinable operators. If there are clauses
-- int2var = int4var and int4var = int8var, the planner will deduce
-- int2var = int8var ... and it had better have a way to represent it.
-- check commutative closure
SELECT p1.amoplefttype, p1.amoprighttype
FROM pg_amop AS p1
WHERE p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p1.amopstrategy = 3 AND
p1.amoplefttype != p1.amoprighttype AND
NOT EXISTS(SELECT 1 FROM pg_amop p2 WHERE
p2.amopfamily = p1.amopfamily AND
p2.amoplefttype = p1.amoprighttype AND
p2.amoprighttype = p1.amoplefttype AND
p2.amopstrategy = 3);
-- check transitive closure
SELECT p1.amoplefttype, p1.amoprighttype, p2.amoprighttype
FROM pg_amop AS p1, pg_amop AS p2
WHERE p1.amopfamily = p2.amopfamily AND
p1.amoprighttype = p2.amoplefttype AND
p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p2.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p1.amopstrategy = 3 AND p2.amopstrategy = 3 AND
p1.amoplefttype != p1.amoprighttype AND
p2.amoplefttype != p2.amoprighttype AND
NOT EXISTS(SELECT 1 FROM pg_amop p3 WHERE
p3.amopfamily = p1.amopfamily AND
p3.amoplefttype = p1.amoplefttype AND
p3.amoprighttype = p2.amoprighttype AND
p3.amopstrategy = 3);
-- **************** pg_amproc ****************
-- Look for illegal values in pg_amproc fields
SELECT p1.amopclaid, p1.amprocnum
SELECT p1.amprocfamily, p1.amprocnum
FROM pg_amproc as p1
WHERE p1.amopclaid = 0 OR p1.amprocnum <= 0 OR p1.amproc = 0;
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
OR p1.amprocnum < 1 OR p1.amproc = 0;
-- Cross-check amprocnum index against parent AM
SELECT p1.amopclaid, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opclass AS p3
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
p1.amprocnum > p2.amsupport;
-- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each opclass for the AM. When nondefault subtypes are
-- present, enforce condition separately for each subtype.
-- as AM expects for each datatype combination supported by the opfamily.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amprocsubtype
FROM pg_am AS p1, pg_opclass AS p2, pg_amproc AS p3
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4
WHERE p4.amopclaid = p2.oid AND
p4.amprocsubtype = p3.amprocsubtype);
WHERE p4.amprocfamily = p2.oid AND
p4.amproclefttype = p3.amproclefttype AND
p4.amprocrighttype = p3.amprocrighttype);
-- Unfortunately, we can't check the amproc link very well because the
-- signature of the function may be different for different support routines
@ -759,85 +727,66 @@ WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
-- routine number take the same number of parameters, but that's about it
-- for a general check...
SELECT p1.amopclaid, p1.amprocnum,
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname,
p4.amopclaid, p4.amprocnum,
p3.opfname,
p4.amprocfamily, p4.amprocnum,
p5.oid, p5.proname,
p6.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3,
pg_amproc AS p4, pg_proc AS p5, pg_opclass AS p6
WHERE p1.amopclaid = p3.oid AND p4.amopclaid = p6.oid AND
p3.opcamid = p6.opcamid AND p1.amprocnum = p4.amprocnum AND
p6.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3,
pg_amproc AS p4, pg_proc AS p5, pg_opfamily AS p6
WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND
p3.opfmethod = p6.opfmethod AND p1.amprocnum = p4.amprocnum AND
p1.amproc = p2.oid AND p4.amproc = p5.oid AND
(p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs);
-- For btree, though, we can do better since we know the support routines
-- must be of the form cmp(input, input) returns int4 in the default case
-- (subtype = 0), and cmp(input, subtype) returns int4 when subtype != 0.
-- must be of the form cmp(lefttype, righttype) returns int4.
SELECT p1.amopclaid, p1.amprocnum,
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND
amprocsubtype = 0 AND
(opckeytype != 0
OR amprocnum != 1
p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
(amprocnum != 1
OR proretset
OR prorettype != 23
OR prorettype != 'int4'::regtype
OR pronargs != 2
OR NOT binary_coercible(opcintype, proargtypes[0])
OR proargtypes[0] != proargtypes[1]);
SELECT p1.amopclaid, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND
amprocsubtype != 0 AND
(opckeytype != 0
OR amprocnum != 1
OR proretset
OR prorettype != 23
OR pronargs != 2
OR NOT binary_coercible(opcintype, proargtypes[0])
OR proargtypes[1] != amprocsubtype);
OR proargtypes[0] != amproclefttype
OR proargtypes[1] != amprocrighttype);
-- For hash we can also do a little better: the support routines must be
-- of the form hash(something) returns int4. Ideally we'd check that the
-- opcintype is binary-coercible to the function's input, but there are
-- enough cases where that fails that I'll just leave out the check for now.
-- of the form hash(lefttype) returns int4. There are several cases where
-- we cheat and use a hash function that is physically compatible with the
-- datatype even though there's no cast, so for now we can't check that.
SELECT p1.amopclaid, p1.amprocnum,
SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname,
p3.opcname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND
(opckeytype != 0
OR amprocnum != 1
p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
(amprocnum != 1
OR proretset
OR prorettype != 23
OR prorettype != 'int4'::regtype
OR pronargs != 1
-- OR NOT physically_coercible(opcintype, proargtypes[0])
);
-- OR NOT physically_coercible(amproclefttype, proargtypes[0])
OR amproclefttype != amprocrighttype);
-- Support routines that are primary members of opclasses must be immutable
-- Support routines that are primary members of opfamilies must be immutable
-- (else it suggests that the index ordering isn't fixed). But cross-type
-- members need only be stable, since they are just shorthands
-- for index probe queries.
SELECT p1.amopclaid, p1.amproc, p2.prosrc
SELECT p1.amprocfamily, p1.amproc, p2.prosrc
FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND
p1.amprocsubtype = 0 AND
p1.amproclefttype = p1.amprocrighttype AND
p2.provolatile != 'i';
SELECT p1.amopclaid, p1.amproc, p2.prosrc
SELECT p1.amprocfamily, p1.amproc, p2.prosrc
FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND
p1.amprocsubtype != 0 AND
p1.amproclefttype != p1.amprocrighttype AND
p2.provolatile = 'v';

View File

@ -7,13 +7,16 @@ anything but an empty database, such as template1; else it's likely to
be very slow.
Run on an empty database, it returns the system join relationships (shown
below for 8.1). Note that unexpected matches may indicate bogus entries
below for 8.3). Note that unexpected matches may indicate bogus entries
in system tables --- don't accept a peculiar match without question.
In particular, a field shown as joining to more than one target table is
probably messed up. In 8.1, the *only* fields that should join to more
than one target are pg_description.objoid, pg_depend.objid, and
pg_depend.refobjid. (Running make_oidjoins_check is an easy way to spot
fields joining to more than one table, BTW.)
probably messed up. In 8.3, the *only* fields that should join to more
than one target are pg_description.objoid, pg_depend.objid,
pg_depend.refobjid, pg_shdescription.objoid, pg_shdepend.objid, and
pg_shdepend.refobjid. (Running make_oidjoins_check is an easy way to spot
fields joining to more than one table, BTW.) NOTE: in an empty database,
findoidjoins may not report joins for pg_shdescription and pg_shdepend for
lack of any entries there.
The shell script make_oidjoins_check converts findoidjoins' output
into an SQL script that checks for dangling links (entries in an
@ -26,7 +29,7 @@ revision in the patterns of cross-links between system tables.
(Ideally we'd just regenerate the script as part of the regression
tests themselves, but that seems too slow...)
NOTE: in 8.1, make_oidjoins_check produces two bogus join checks:
NOTE: in 8.3, make_oidjoins_check produces two bogus join checks:
Join pg_catalog.pg_class.relfilenode => pg_catalog.pg_class.oid
Join pg_catalog.pg_database.datlastsysoid => pg_catalog.pg_database.oid
These are artifacts and should not be added to the oidjoins regress test.
@ -50,11 +53,15 @@ Join pg_catalog.pg_am.ambuild => pg_catalog.pg_proc.oid
Join pg_catalog.pg_am.ambulkdelete => pg_catalog.pg_proc.oid
Join pg_catalog.pg_am.amvacuumcleanup => pg_catalog.pg_proc.oid
Join pg_catalog.pg_am.amcostestimate => pg_catalog.pg_proc.oid
Join pg_catalog.pg_amop.amopclaid => pg_catalog.pg_opclass.oid
Join pg_catalog.pg_amop.amopsubtype => pg_catalog.pg_type.oid
Join pg_catalog.pg_am.amoptions => pg_catalog.pg_proc.oid
Join pg_catalog.pg_amop.amopfamily => pg_catalog.pg_opfamily.oid
Join pg_catalog.pg_amop.amoplefttype => pg_catalog.pg_type.oid
Join pg_catalog.pg_amop.amoprighttype => pg_catalog.pg_type.oid
Join pg_catalog.pg_amop.amopopr => pg_catalog.pg_operator.oid
Join pg_catalog.pg_amproc.amopclaid => pg_catalog.pg_opclass.oid
Join pg_catalog.pg_amproc.amprocsubtype => pg_catalog.pg_type.oid
Join pg_catalog.pg_amop.amopmethod => pg_catalog.pg_am.oid
Join pg_catalog.pg_amproc.amprocfamily => pg_catalog.pg_opfamily.oid
Join pg_catalog.pg_amproc.amproclefttype => pg_catalog.pg_type.oid
Join pg_catalog.pg_amproc.amprocrighttype => pg_catalog.pg_type.oid
Join pg_catalog.pg_amproc.amproc => pg_catalog.pg_proc.oid
Join pg_catalog.pg_attribute.attrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_attribute.atttypid => pg_catalog.pg_type.oid
@ -63,6 +70,7 @@ Join pg_catalog.pg_cast.casttarget => pg_catalog.pg_type.oid
Join pg_catalog.pg_cast.castfunc => pg_catalog.pg_proc.oid
Join pg_catalog.pg_class.relnamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_class.reltype => pg_catalog.pg_type.oid
Join pg_catalog.pg_class.relowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_class.relam => pg_catalog.pg_am.oid
Join pg_catalog.pg_class.reltablespace => pg_catalog.pg_tablespace.oid
Join pg_catalog.pg_class.reltoastrelid => pg_catalog.pg_class.oid
@ -70,7 +78,9 @@ Join pg_catalog.pg_class.reltoastidxid => pg_catalog.pg_class.oid
Join pg_catalog.pg_constraint.connamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_constraint.contypid => pg_catalog.pg_type.oid
Join pg_catalog.pg_conversion.connamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_conversion.conowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_conversion.conproc => pg_catalog.pg_proc.oid
Join pg_catalog.pg_database.datdba => pg_catalog.pg_authid.oid
Join pg_catalog.pg_database.dattablespace => pg_catalog.pg_tablespace.oid
Join pg_catalog.pg_depend.classid => pg_catalog.pg_class.oid
Join pg_catalog.pg_depend.refclassid => pg_catalog.pg_class.oid
@ -78,33 +88,42 @@ Join pg_catalog.pg_description.classoid => pg_catalog.pg_class.oid
Join pg_catalog.pg_index.indexrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_index.indrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_language.lanvalidator => pg_catalog.pg_proc.oid
Join pg_catalog.pg_opclass.opcamid => pg_catalog.pg_am.oid
Join pg_catalog.pg_namespace.nspowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_opclass.opcmethod => pg_catalog.pg_am.oid
Join pg_catalog.pg_opclass.opcnamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_opclass.opcowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_opclass.opcfamily => pg_catalog.pg_opfamily.oid
Join pg_catalog.pg_opclass.opcintype => pg_catalog.pg_type.oid
Join pg_catalog.pg_opclass.opckeytype => pg_catalog.pg_type.oid
Join pg_catalog.pg_operator.oprnamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_operator.oprowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_operator.oprleft => pg_catalog.pg_type.oid
Join pg_catalog.pg_operator.oprright => pg_catalog.pg_type.oid
Join pg_catalog.pg_operator.oprresult => pg_catalog.pg_type.oid
Join pg_catalog.pg_operator.oprcom => pg_catalog.pg_operator.oid
Join pg_catalog.pg_operator.oprnegate => pg_catalog.pg_operator.oid
Join pg_catalog.pg_operator.oprlsortop => pg_catalog.pg_operator.oid
Join pg_catalog.pg_operator.oprrsortop => pg_catalog.pg_operator.oid
Join pg_catalog.pg_operator.oprltcmpop => pg_catalog.pg_operator.oid
Join pg_catalog.pg_operator.oprgtcmpop => pg_catalog.pg_operator.oid
Join pg_catalog.pg_operator.oprcode => pg_catalog.pg_proc.oid
Join pg_catalog.pg_operator.oprrest => pg_catalog.pg_proc.oid
Join pg_catalog.pg_operator.oprjoin => pg_catalog.pg_proc.oid
Join pg_catalog.pg_opfamily.opfmethod => pg_catalog.pg_am.oid
Join pg_catalog.pg_opfamily.opfnamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_opfamily.opfowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_proc.pronamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_proc.proowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_proc.prolang => pg_catalog.pg_language.oid
Join pg_catalog.pg_proc.prorettype => pg_catalog.pg_type.oid
Join pg_catalog.pg_rewrite.ev_class => pg_catalog.pg_class.oid
Join pg_catalog.pg_shdepend.refclassid => pg_catalog.pg_class.oid
Join pg_catalog.pg_shdescription.classoid => pg_catalog.pg_class.oid
Join pg_catalog.pg_statistic.starelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_statistic.staop1 => pg_catalog.pg_operator.oid
Join pg_catalog.pg_statistic.staop2 => pg_catalog.pg_operator.oid
Join pg_catalog.pg_statistic.staop3 => pg_catalog.pg_operator.oid
Join pg_catalog.pg_tablespace.spcowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_trigger.tgrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_trigger.tgfoid => pg_catalog.pg_proc.oid
Join pg_catalog.pg_type.typnamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_type.typowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_type.typrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_type.typelem => pg_catalog.pg_type.oid
Join pg_catalog.pg_type.typinput => pg_catalog.pg_proc.oid

View File

@ -7,7 +7,7 @@
-- Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
-- Portions Copyright (c) 1994, Regents of the University of California
--
-- $PostgreSQL: pgsql/src/tutorial/syscat.source,v 1.16 2006/03/05 15:59:11 momjian Exp $
-- $PostgreSQL: pgsql/src/tutorial/syscat.source,v 1.17 2006/12/23 00:43:13 tgl Exp $
--
---------------------------------------------------------------------------
@ -165,18 +165,18 @@ SELECT n.nspname, p.proname, format_type(t.oid, null) as typname
--
-- lists all the operator classes that can be used with each access method
-- as well as the operators that cn be used with the respective operator
-- classes
-- lists all the operator families that can be used with each access method
-- as well as the operators that can be used with the respective operator
-- families
--
SELECT n.nspname, am.amname, opc.opcname, opr.oprname
FROM pg_namespace n, pg_am am, pg_opclass opc,
SELECT am.amname, n.nspname, opf.opfname, opr.oprname
FROM pg_namespace n, pg_am am, pg_opfamily opf,
pg_amop amop, pg_operator opr
WHERE opc.opcnamespace = n.oid
and opc.opcamid = am.oid
and amop.amopclaid = opc.oid
WHERE opf.opfnamespace = n.oid
and opf.opfmethod = am.oid
and amop.amopfamily = opf.oid
and amop.amopopr = opr.oid
ORDER BY nspname, amname, opcname, oprname;
ORDER BY nspname, amname, opfname, oprname;
--
-- Reset the search path