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 --GIN
--mark built-in gin's _int4_ops as non default --mark built-in gin's _int4_ops as non default
update pg_opclass set opcdefault = 'f' where update pg_catalog.pg_opclass set opcdefault = 'f'
pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and where opcmethod = (select oid from pg_catalog.pg_am where amname='gin') and
opcname = '_int4_ops'; opcname = '_int4_ops';
CREATE FUNCTION ginint4_queryextract(internal, internal, int2) CREATE FUNCTION ginint4_queryextract(internal, internal, int2)
RETURNS internal RETURNS internal

View File

@ -124,7 +124,7 @@ DROP FUNCTION querytree(query_int);
DROP TYPE query_int CASCADE; DROP TYPE query_int CASCADE;
update pg_opclass set opcdefault = 't' where --mark built-in gin's _int4_ops as default again
pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and update pg_catalog.pg_opclass set opcdefault = 't'
opcname = '_int4_ops'; 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 Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
@ -160,7 +160,7 @@
<row> <row>
<entry><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link></entry> <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>
<row> <row>
@ -168,6 +168,11 @@
<entry>operators</entry> <entry>operators</entry>
</row> </row>
<row>
<entry><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link></entry>
<entry>access method operator families</entry>
</row>
<row> <row>
<entry><link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link></entry> <entry><link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link></entry>
<entry>template data for procedural languages</entry> <entry>template data for procedural languages</entry>
@ -516,9 +521,11 @@
</indexterm> </indexterm>
<para> <para>
The catalog <structname>pg_amop</structname> stores information about operators The catalog <structname>pg_amop</structname> stores information about
associated with index access method operator classes. There is one operators associated with access method operator families. There is one
row for each operator that is a member of an operator class. 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> </para>
<table> <table>
@ -536,18 +543,24 @@
<tbody> <tbody>
<row> <row>
<entry><structfield>amopclaid</structfield></entry> <entry><structfield>amopfamily</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry> <entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
<entry>The index operator class this entry is for</entry> <entry>The operator family this entry is for</entry>
</row> </row>
<row> <row>
<entry><structfield>amopsubtype</structfield></entry> <entry><structfield>amoplefttype</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></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; <entry>Left-hand input data type of operator</entry>
zero for default</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>
<row> <row>
@ -571,10 +584,27 @@
<entry>OID of the operator</entry> <entry>OID of the operator</entry>
</row> </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> </tbody>
</tgroup> </tgroup>
</table> </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> </sect1>
@ -586,10 +616,9 @@
</indexterm> </indexterm>
<para> <para>
The catalog <structname>pg_amproc</structname> stores information about support The catalog <structname>pg_amproc</structname> stores information about
procedures support procedures associated with access method operator families. There
associated with index access method operator classes. There is one is one row for each support procedure belonging to an operator family.
row for each support procedure belonging to an operator class.
</para> </para>
<table> <table>
@ -607,17 +636,24 @@
<tbody> <tbody>
<row> <row>
<entry><structfield>amopclaid</structfield></entry> <entry><structfield>amprocfamily</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry> <entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
<entry>The index operator class this entry is for</entry> <entry>The operator family this entry is for</entry>
</row> </row>
<row> <row>
<entry><structfield>amprocsubtype</structfield></entry> <entry><structfield>amproclefttype</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></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>
<row> <row>
@ -638,6 +674,18 @@
</tgroup> </tgroup>
</table> </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> </sect1>
@ -2843,9 +2891,11 @@
The catalog <structname>pg_opclass</structname> defines The catalog <structname>pg_opclass</structname> defines
index access method operator classes. Each operator class defines index access method operator classes. Each operator class defines
semantics for index columns of a particular data type and a particular semantics for index columns of a particular data type and a particular
index access method. Note that there can be multiple operator classes index access method. An operator class essentially specifies that a
for a given data type/access method combination, thus supporting multiple particular operator family is applicable to a particular indexable column
behaviors. 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>
<para> <para>
@ -2867,7 +2917,7 @@
<tbody> <tbody>
<row> <row>
<entry><structfield>opcamid</structfield></entry> <entry><structfield>opcmethod</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></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> <entry>Index access method operator class is for</entry>
@ -2894,6 +2944,13 @@
<entry>Owner of the operator class</entry> <entry>Owner of the operator class</entry>
</row> </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> <row>
<entry><structfield>opcintype</structfield></entry> <entry><structfield>opcintype</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
@ -2920,14 +2977,11 @@
</table> </table>
<para> <para>
The majority of the information defining an operator class is actually An operator class's <structfield>opcmethod</> must match the
not in its <structname>pg_opclass</structname> row, but in the associated <structname>opfmethod</> of its containing operator family.
rows in <structname>pg_amop</structname> and Also, there must be no more than one <structname>pg_opclass</structname>
<structname>pg_amproc</structname>. Those rows are considered to be row having <structname>opcdefault</> true for any given combination of
part of the operator class definition &mdash; this is not unlike the way <structname>opcmethod</> and <structname>opcintype</>.
that a relation is defined by a single <structname>pg_class</structname>
row plus associated rows in <structname>pg_attribute</structname> and
other tables.
</para> </para>
</sect1> </sect1>
@ -2993,6 +3047,13 @@
</entry> </entry>
</row> </row>
<row>
<entry><structfield>oprcanmerge</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>This operator supports merge joins</entry>
</row>
<row> <row>
<entry><structfield>oprcanhash</structfield></entry> <entry><structfield>oprcanhash</structfield></entry>
<entry><type>bool</type></entry> <entry><type>bool</type></entry>
@ -3035,46 +3096,6 @@
<entry>Negator of this operator, if any</entry> <entry>Negator of this operator, if any</entry>
</row> </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> <row>
<entry><structfield>oprcode</structfield></entry> <entry><structfield>oprcode</structfield></entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
@ -3107,6 +3128,86 @@
</sect1> </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"> <sect1 id="catalog-pg-pltemplate">
<title><structname>pg_pltemplate</structname></title> <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"> <chapter id="indexam">
<title>Index Access Method Interface Definition</title> <title>Index Access Method Interface Definition</title>
@ -63,13 +63,15 @@
<para> <para>
To be useful, an index access method must also have one or more To be useful, an index access method must also have one or more
<firstterm>operator families</> and
<firstterm>operator classes</> defined in <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-opclass"><structname>pg_opclass</structname></link>,
<link linkend="catalog-pg-amop"><structname>pg_amop</structname></link>, and <link linkend="catalog-pg-amop"><structname>pg_amop</structname></link>, and
<link linkend="catalog-pg-amproc"><structname>pg_amproc</structname></link>. <link linkend="catalog-pg-amproc"><structname>pg_amproc</structname></link>.
These entries allow the planner These entries allow the planner
to determine what kinds of query qualifications can be used with 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 in <xref linkend="xindex">, which is prerequisite material for reading
this chapter. this chapter.
</para> </para>
@ -409,14 +411,14 @@ amrestrpos (IndexScanDesc scan);
A scan key is the internal representation of a <literal>WHERE</> clause of A scan key is the internal representation of a <literal>WHERE</> clause of
the form <replaceable>index_key</> <replaceable>operator</> the form <replaceable>index_key</> <replaceable>operator</>
<replaceable>constant</>, where the index key is one of the columns of the <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 associated with that index column. An index scan has zero or more scan
keys, which are implicitly ANDed &mdash; the returned tuples are expected keys, which are implicitly ANDed &mdash; the returned tuples are expected
to satisfy all the indicated conditions. to satisfy all the indicated conditions.
</para> </para>
<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 particular operator; this implies that the index scan will return all the
entries that pass the scan key, plus possibly additional entries that do 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 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 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. 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</> 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 semantic analysis to determine whether they are redundant or
contradictory. As an example, given contradictory. As an example, given
<literal>WHERE x &gt; 4 AND x &gt; 14</> where <literal>x</> is a b-tree <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"> <chapter id="indexes">
<title id="indexes-title">Indexes</title> <title id="indexes-title">Indexes</title>
@ -784,12 +784,16 @@ CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target)
<sect1 id="indexes-opclass"> <sect1 id="indexes-opclass">
<title>Operator Classes</title> <title>Operator Classes and Operator Families</title>
<indexterm zone="indexes-opclass"> <indexterm zone="indexes-opclass">
<primary>operator class</primary> <primary>operator class</primary>
</indexterm> </indexterm>
<indexterm zone="indexes-opclass">
<primary>operator family</primary>
</indexterm>
<para> <para>
An index definition may specify an <firstterm>operator An index definition may specify an <firstterm>operator
class</firstterm> for each column of an index. 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, SELECT am.amname AS index_method,
opc.opcname AS opclass_name opc.opcname AS opclass_name
FROM pg_am am, pg_opclass opc FROM pg_am am, pg_opclass opc
WHERE opc.opcamid = am.oid WHERE opc.opcmethod = am.oid
ORDER BY index_method, opclass_name; ORDER BY index_method, opclass_name;
</programlisting> </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> <programlisting>
SELECT am.amname AS index_method, SELECT am.amname AS index_method,
opc.opcname AS opclass_name, opf.opfname AS opfamily_name,
opr.oid::regoperator AS opclass_operator amop.amopopr::regoperator AS opfamily_operator
FROM pg_am am, pg_opclass opc, pg_amop amop, pg_operator opr FROM pg_am am, pg_opfamily opf, pg_amop amop
WHERE opc.opcamid = am.oid AND WHERE opf.opfmethod = am.oid AND
amop.amopclaid = opc.oid AND amop.amopfamily = opf.oid
amop.amopopr = opr.oid ORDER BY index_method, opfamily_name, opfamily_operator;
ORDER BY index_method, opclass_name, opclass_operator;
</programlisting> </programlisting>
</para> </para>
</sect1> </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 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> ] [, 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> ] [, RESTRICT = <replaceable class="parameter">res_proc</replaceable> ] [, JOIN = <replaceable class="parameter">join_proc</replaceable> ]
[, HASHES ] [, MERGES ] [, 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> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -202,46 +200,6 @@ CREATE OPERATOR <replaceable>name</replaceable> (
</para> </para>
</listitem> </listitem>
</varlistentry> </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> </variablelist>
<para> <para>
@ -261,6 +219,16 @@ COMMUTATOR = OPERATOR(myschema.===) ,
Refer to <xref linkend="xoper"> for further information. Refer to <xref linkend="xoper"> for further information.
</para> </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> <para>
Use <xref linkend="sql-dropoperator" Use <xref linkend="sql-dropoperator"
endterm="sql-dropoperator-title"> to delete user-defined operators endterm="sql-dropoperator-title"> to delete user-defined operators
@ -285,11 +253,7 @@ CREATE OPERATOR === (
NEGATOR = !==, NEGATOR = !==,
RESTRICT = area_restriction_procedure, RESTRICT = area_restriction_procedure,
JOIN = area_join_procedure, JOIN = area_join_procedure,
HASHES, HASHES, MERGES
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
); );
</programlisting> </programlisting>
</para> </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"> <sect1 id="xoper">
<title>User-Defined Operators</title> <title>User-Defined Operators</title>
@ -342,13 +342,13 @@ table1.column1 OP table2.column2
<para> <para>
To be marked <literal>HASHES</literal>, the join operator must appear To be marked <literal>HASHES</literal>, the join operator must appear
in a hash index operator class. This is not enforced when you create in a hash index operator family. This is not enforced when you create
the operator, since of course the referencing operator class couldn't the operator, since of course the referencing operator family couldn't
exist yet. But attempts to use the operator in hash joins will fail 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 at run time if no such operator family exists. The system needs the
operator class to find the data-type-specific hash function for 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 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>
<para> <para>
@ -390,7 +390,7 @@ table1.column1 OP table2.column2
</sect2> </sect2>
<sect2> <sect2>
<title><literal>MERGES</> (<literal>SORT1</>, <literal>SORT2</>, <literal>LTCMP</>, <literal>GTCMP</>)</title> <title><literal>MERGES</></title>
<para> <para>
The <literal>MERGES</literal> clause, if present, tells the system that The <literal>MERGES</literal> clause, if present, tells the system that
@ -418,36 +418,13 @@ table1.column1 OP table2.column2
</para> </para>
<para> <para>
Execution of a merge join requires that the system be able to identify To be marked <literal>MERGES</literal>, the join operator must appear
four operators related to the merge-join equality operator: less-than in a btree index operator family. This is not enforced when you create
comparison for the left operand data type, less-than comparison for the the operator, since of course the referencing operator family couldn't
right operand data type, less-than comparison between the two data types, and exist yet. But the operator will not actually be used for merge joins
greater-than comparison between the two data types. (These are actually unless a matching operator family can be found. The
four distinct operators if the merge-joinable operator has two different <literal>MERGES</literal> flag thus acts as a hint to the planner that
operand data types; but when the operand types are the same the three it's worth looking for a matching operator family.
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.)
</para> </para>
<para> <para>
@ -474,13 +451,6 @@ table1.column1 OP table2.column2
be transitive. be transitive.
</para> </para>
</listitem> </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> </itemizedlist>
</para> </para>
@ -491,17 +461,5 @@ table1.column1 OP table2.column2
attempt to use the operator for a merge join. attempt to use the operator for a merge join.
</para> </para>
</note> </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> </sect2>
</sect1> </sect1>

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* These functions are stored in pg_amproc. For each operator class * 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 * The idea here is to produce a hash value compatible with the values
* produced by hashint4 and hashint2 for logically equivalent inputs; this * produced by hashint4 and hashint2 for logically equal inputs; this is
* is necessary if we ever hope to support cross-type hash joins across * necessary to support cross-type hash joins across these input types.
* these input types. Since all three types are signed, we can xor the * Since all three types are signed, we can xor the high half of the int8
* high half of the int8 value if the sign is positive, or the complement * value if the sign is positive, or the complement of the high half when
* of the high half when the sign is negative. * the sign is negative.
*/ */
#ifndef INT64_IS_BUSTED #ifndef INT64_IS_BUSTED
int64 val = PG_GETARG_INT64(0); int64 val = PG_GETARG_INT64(0);
@ -76,16 +76,26 @@ Datum
hashfloat4(PG_FUNCTION_ARGS) hashfloat4(PG_FUNCTION_ARGS)
{ {
float4 key = PG_GETARG_FLOAT4(0); float4 key = PG_GETARG_FLOAT4(0);
float8 key8;
/* /*
* On IEEE-float machines, minus zero and zero have different bit patterns * 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 * 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) if (key == (float4) 0)
PG_RETURN_UINT32(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 Datum
@ -96,7 +106,7 @@ hashfloat8(PG_FUNCTION_ARGS)
/* /*
* On IEEE-float machines, minus zero and zero have different bit patterns * 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 * 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) if (key == (float8) 0)
PG_RETURN_UINT32(0); PG_RETURN_UINT32(0);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
* index_open - open an index relation by relation OID * index_open - open an index relation by relation OID
@ -608,17 +608,27 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
/* ---------------- /* ----------------
* index_getprocid * index_getprocid
* *
* Some indexed access methods may require support routines that are * Index access methods typically require support routines that are
* not in the operator class/operator model imposed by pg_am. These * not directly the implementation of any WHERE-clause query operator
* access methods may store the OIDs of registered procedures they * and so cannot be kept in pg_amop. Instead, such routines are kept
* need in pg_amproc. These registered procedure OIDs are ordered in * in pg_amproc. These registered procedure OIDs are assigned numbers
* a way that makes sense to the access method, and used only by the * according to a convention established by the access method.
* access method. The general index code doesn't know anything about * The general index code doesn't know anything about the routines
* the routines involved; it just builds an ordered list of them for * involved; it just builds an ordered list of them for
* each attribute on which an index is defined. * each attribute on which an index is defined.
* *
* This routine returns the requested procedure OID for a particular * As of Postgres 8.3, support routines within an operator family
* indexed attribute. * 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 RegProcedure
@ -647,7 +657,8 @@ index_getprocid(Relation irel,
* index_getprocinfo * index_getprocinfo
* *
* This routine allows index AMs to keep fmgr lookup info for * 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 * Note: the return value points into cached data that will be lost during
* any relcache rebuild! Therefore, either use the callinfo right away, * 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 * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * to an insertion scan key by replacing the sk_func with the
* appropriate btree comparison function. * appropriate btree comparison function.
* *
* If scankey operator is of default subtype, we can use the * If scankey operator is of the default type for the index, we
* cached comparison function; otherwise gotta look it up in the * can use the cached comparison function; otherwise gotta look it
* catalogs. * 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; FmgrInfo *procinfo;
@ -671,7 +674,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
cur->sk_flags, cur->sk_flags,
cur->sk_attno, cur->sk_attno,
InvalidStrategy, InvalidStrategy,
InvalidOid, cur->sk_subtype,
procinfo, procinfo,
cur->sk_argument); cur->sk_argument);
} }
@ -679,9 +682,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
{ {
RegProcedure cmp_proc; RegProcedure cmp_proc;
cmp_proc = get_opclass_proc(rel->rd_indclass->values[i], cmp_proc = get_opfamily_proc(rel->rd_opfamily[i],
cur->sk_subtype, rel->rd_opcintype[i],
BTORDER_PROC); 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, ScanKeyEntryInitialize(scankeys + i,
cur->sk_flags, cur->sk_flags,
cur->sk_attno, cur->sk_attno,

View File

@ -2,7 +2,7 @@
# #
# Makefile for backend/catalog # 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/,\ 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_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_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.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_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_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_depend.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 * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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/index.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h" #include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h" #include "catalog/pg_authid.h"
#include "catalog/pg_cast.h" #include "catalog/pg_cast.h"
@ -33,6 +35,7 @@
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "catalog/pg_tablespace.h" #include "catalog/pg_tablespace.h"
@ -78,19 +81,25 @@ typedef struct
* See also getObjectClass(). * See also getObjectClass().
*/ */
static const Oid object_classes[MAX_OCLASS] = { static const Oid object_classes[MAX_OCLASS] = {
RelationRelationId, /* OCLASS_CLASS */ RelationRelationId, /* OCLASS_CLASS */
ProcedureRelationId, /* OCLASS_PROC */ ProcedureRelationId, /* OCLASS_PROC */
TypeRelationId, /* OCLASS_TYPE */ TypeRelationId, /* OCLASS_TYPE */
CastRelationId, /* OCLASS_CAST */ CastRelationId, /* OCLASS_CAST */
ConstraintRelationId, /* OCLASS_CONSTRAINT */ ConstraintRelationId, /* OCLASS_CONSTRAINT */
ConversionRelationId, /* OCLASS_CONVERSION */ ConversionRelationId, /* OCLASS_CONVERSION */
AttrDefaultRelationId, /* OCLASS_DEFAULT */ AttrDefaultRelationId, /* OCLASS_DEFAULT */
LanguageRelationId, /* OCLASS_LANGUAGE */ LanguageRelationId, /* OCLASS_LANGUAGE */
OperatorRelationId, /* OCLASS_OPERATOR */ OperatorRelationId, /* OCLASS_OPERATOR */
OperatorClassRelationId, /* OCLASS_OPCLASS */ OperatorClassRelationId, /* OCLASS_OPCLASS */
RewriteRelationId, /* OCLASS_REWRITE */ OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
TriggerRelationId, /* OCLASS_TRIGGER */ AccessMethodOperatorRelationId, /* OCLASS_AMOP */
NamespaceRelationId /* OCLASS_SCHEMA */ 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, static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
ObjectAddresses *addrs); ObjectAddresses *addrs);
static void getRelationDescription(StringInfo buffer, Oid relid); 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 * filled with some objects. Also, the deleted objects are saved in the
* alreadyDeleted list. * 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. * function.
*/ */
static void static void
@ -954,6 +964,18 @@ doDeletion(const ObjectAddress *object)
RemoveOpClassById(object->objectId); RemoveOpClassById(object->objectId);
break; 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: case OCLASS_REWRITE:
RemoveRewriteRuleById(object->objectId); RemoveRewriteRuleById(object->objectId);
break; break;
@ -966,6 +988,8 @@ doDeletion(const ObjectAddress *object)
RemoveSchemaById(object->objectId); RemoveSchemaById(object->objectId);
break; break;
/* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
default: default:
elog(ERROR, "unrecognized object class: %u", elog(ERROR, "unrecognized object class: %u",
object->classId); object->classId);
@ -1316,9 +1340,9 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0, add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
context->addrs); 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); context->addrs);
} }
/* fall through to examine arguments */ /* fall through to examine arguments */
@ -1623,6 +1647,18 @@ getObjectClass(const ObjectAddress *object)
Assert(object->objectSubId == 0); Assert(object->objectSubId == 0);
return OCLASS_OPCLASS; 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: case RewriteRelationId:
Assert(object->objectSubId == 0); Assert(object->objectSubId == 0);
return OCLASS_REWRITE; return OCLASS_REWRITE;
@ -1856,11 +1892,11 @@ getObjectDescription(const ObjectAddress *object)
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup); opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
amTup = SearchSysCache(AMOID, amTup = SearchSysCache(AMOID,
ObjectIdGetDatum(opcForm->opcamid), ObjectIdGetDatum(opcForm->opcmethod),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(amTup)) if (!HeapTupleIsValid(amTup))
elog(ERROR, "cache lookup failed for access method %u", elog(ERROR, "cache lookup failed for access method %u",
opcForm->opcamid); opcForm->opcmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup); amForm = (Form_pg_am) GETSTRUCT(amTup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
@ -1879,6 +1915,84 @@ getObjectDescription(const ObjectAddress *object)
break; 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: case OCLASS_REWRITE:
{ {
Relation ruleDesc; Relation ruleDesc;
@ -2068,3 +2182,45 @@ getRelationDescription(StringInfo buffer, Oid relid)
ReleaseSysCache(relTup); 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 * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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_namespace.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
@ -1062,7 +1063,7 @@ OpclassIsVisible(Oid opcid)
*/ */
char *opcname = NameStr(opcform->opcname); char *opcname = NameStr(opcform->opcname);
visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid); visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
} }
ReleaseSysCache(opctup); ReleaseSysCache(opctup);
@ -1070,6 +1071,89 @@ OpclassIsVisible(Oid opcid)
return visible; 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 * ConversionGetConid
* Try to resolve an unqualified conversion name. * Try to resolve an unqualified conversion name.

View File

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

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 Oid
GetDefaultOpClass(Oid type_id, Oid am_id) GetDefaultOpClass(Oid type_id, Oid am_id)
{ {
Oid result = InvalidOid;
int nexact = 0; int nexact = 0;
int ncompatible = 0; int ncompatible = 0;
Oid exactOid = InvalidOid; int ncompatiblepreferred = 0;
Oid compatibleOid = InvalidOid;
Relation rel; Relation rel;
ScanKeyData skey[1]; ScanKeyData skey[1];
SysScanDesc scan; SysScanDesc scan;
HeapTuple tup; HeapTuple tup;
CATEGORY tcategory;
/* If it's a domain, look at the base type instead */ /* If it's a domain, look at the base type instead */
type_id = getBaseType(type_id); type_id = getBaseType(type_id);
tcategory = TypeCategory(type_id);
/* /*
* We scan through all the opclasses available for the access method, * We scan through all the opclasses available for the access method,
* looking for one that is marked default and matches the target type * looking for one that is marked default and matches the target type
* (either exactly or binary-compatibly, but prefer an exact match). * (either exactly or binary-compatibly, but prefer an exact match).
* *
* We could find more than one binary-compatible match, in which case we * We could find more than one binary-compatible match. If just one is
* require the user to specify which one he wants. If we find more than * for a preferred type, use that one; otherwise we fail, forcing the user
* one exact match, then someone put bogus entries in pg_opclass. * 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); rel = heap_open(OperatorClassRelationId, AccessShareLock);
ScanKeyInit(&skey[0], ScanKeyInit(&skey[0],
Anum_pg_opclass_opcamid, Anum_pg_opclass_opcmethod,
BTEqualStrategyNumber, F_OIDEQ, BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(am_id)); ObjectIdGetDatum(am_id));
@ -837,17 +843,26 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
{ {
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup); 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++; ncompatiblepreferred++;
exactOid = HeapTupleGetOid(tup); result = HeapTupleGetOid(tup);
} }
else if (IsBinaryCoercible(type_id, opclass->opcintype)) else if (ncompatiblepreferred == 0)
{ {
ncompatible++; ncompatible++;
compatibleOid = HeapTupleGetOid(tup); result = HeapTupleGetOid(tup);
} }
} }
} }
@ -856,15 +871,17 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
heap_close(rel, AccessShareLock); heap_close(rel, AccessShareLock);
if (nexact == 1) /* raise error if pg_opclass contains inconsistent data */
return exactOid; if (nexact > 1)
if (nexact != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT), (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("there are multiple default operator classes for data type %s", errmsg("there are multiple default operator classes for data type %s",
format_type_be(type_id)))); format_type_be(type_id))));
if (ncompatible == 1)
return compatibleOid; if (nexact == 1 ||
ncompatiblepreferred == 1 ||
(ncompatiblepreferred == 0 && ncompatible == 1))
return result;
return InvalidOid; return InvalidOid;
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
@ -64,8 +64,8 @@ DefineOperator(List *names, List *parameters)
char *oprName; char *oprName;
Oid oprNamespace; Oid oprNamespace;
AclResult aclresult; AclResult aclresult;
bool canHash = false; /* operator hashes */
bool canMerge = false; /* operator merges */ bool canMerge = false; /* operator merges */
bool canHash = false; /* operator hashes */
List *functionName = NIL; /* function for operator */ List *functionName = NIL; /* function for operator */
TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName1 = NULL; /* first type name */
TypeName *typeName2 = NULL; /* second 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 *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel. procedure */ List *restrictionName = NIL; /* optional restrict. sel. procedure */
List *joinName = NIL; /* optional join 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; ListCell *pl;
/* Convert list of names to a name and namespace */ /* Convert list of names to a name and namespace */
@ -127,14 +123,15 @@ DefineOperator(List *names, List *parameters)
canHash = defGetBoolean(defel); canHash = defGetBoolean(defel);
else if (pg_strcasecmp(defel->defname, "merges") == 0) else if (pg_strcasecmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel); canMerge = defGetBoolean(defel);
/* These obsolete options are taken as meaning canMerge */
else if (pg_strcasecmp(defel->defname, "sort1") == 0) else if (pg_strcasecmp(defel->defname, "sort1") == 0)
leftSortName = defGetQualifiedName(defel); canMerge = true;
else if (pg_strcasecmp(defel->defname, "sort2") == 0) else if (pg_strcasecmp(defel->defname, "sort2") == 0)
rightSortName = defGetQualifiedName(defel); canMerge = true;
else if (pg_strcasecmp(defel->defname, "ltcmp") == 0) else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
ltCompareName = defGetQualifiedName(defel); canMerge = true;
else if (pg_strcasecmp(defel->defname, "gtcmp") == 0) else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
gtCompareName = defGetQualifiedName(defel); canMerge = true;
else else
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
@ -156,26 +153,6 @@ DefineOperator(List *names, List *parameters)
if (typeName2) if (typeName2)
typeId2 = typenameTypeId(NULL, 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.. * now have OperatorCreate do all the work..
*/ */
@ -188,11 +165,8 @@ DefineOperator(List *names, List *parameters)
negatorName, /* optional negator operator name */ negatorName, /* optional negator operator name */
restrictionName, /* optional restrict. sel. procedure */ restrictionName, /* optional restrict. sel. procedure */
joinName, /* optional join sel. procedure name */ joinName, /* optional join sel. procedure name */
canHash, /* operator hashes */ canMerge, /* operator merges */
leftSortName, /* optional left sort operator */ canHash); /* operator hashes */
rightSortName, /* optional right sort operator */
ltCompareName, /* optional < comparison op */
gtCompareName); /* optional < comparison op */
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * generate a warning if not, since otherwise costly seqscans will be
* incurred to check FK validity. * 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, ereport(WARNING,
(errmsg("foreign key constraint \"%s\" " (errmsg("foreign key constraint \"%s\" "
"will require costly sequential scans", "will require costly sequential scans",

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); outlist = lappend(outlist, estate);
} }
rstate->rargs = outlist; rstate->rargs = outlist;
Assert(list_length(rcexpr->opclasses) == nopers); Assert(list_length(rcexpr->opfamilies) == nopers);
rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo)); rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
i = 0; i = 0;
forboth(l, rcexpr->opnos, l2, rcexpr->opclasses) forboth(l, rcexpr->opnos, l2, rcexpr->opfamilies)
{ {
Oid opno = lfirst_oid(l); Oid opno = lfirst_oid(l);
Oid opclass = lfirst_oid(l2); Oid opfamily = lfirst_oid(l2);
int strategy; int strategy;
Oid subtype; Oid lefttype;
Oid righttype;
bool recheck; bool recheck;
Oid proc; Oid proc;
get_op_opclass_properties(opno, opclass, get_op_opfamily_properties(opno, opfamily,
&strategy, &subtype, &recheck); &strategy,
proc = get_opclass_proc(opclass, subtype, BTORDER_PROC); &lefttype,
&righttype,
&recheck);
proc = get_opfamily_proc(opfamily,
lefttype,
righttype,
BTORDER_PROC);
/* /*
* If we enforced permissions checks on index support * If we enforced permissions checks on index support

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; int flags = SK_ROW_MEMBER;
Datum scanvalue; Datum scanvalue;
Oid opno; Oid opno;
Oid opclass; Oid opfamily;
int op_strategy; int op_strategy;
Oid op_subtype; Oid op_lefttype;
Oid op_righttype;
bool op_recheck; bool op_recheck;
/* /*
@ -857,15 +858,21 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
if (index->rd_rel->relam != BTREE_AM_OID || if (index->rd_rel->relam != BTREE_AM_OID ||
varattno < 1 || varattno > index->rd_index->indnatts) varattno < 1 || varattno > index->rd_index->indnatts)
elog(ERROR, "bogus RowCompare index qualification"); 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, get_op_opfamily_properties(opno, opfamily,
&op_strategy, &op_subtype, &op_recheck); &op_strategy,
&op_lefttype,
&op_righttype,
&op_recheck);
if (op_strategy != rc->rctype) if (op_strategy != rc->rctype)
elog(ERROR, "RowCompare index qualification contains wrong operator"); 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 * initialize the subsidiary scan key's fields appropriately
@ -874,7 +881,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
flags, flags,
varattno, /* attribute number */ varattno, /* attribute number */
op_strategy, /* op's strategy */ op_strategy, /* op's strategy */
op_subtype, /* strategy subtype */ op_righttype, /* strategy subtype */
opfuncid, /* reg proc to use */ opfuncid, /* reg proc to use */
scanvalue); /* constant */ scanvalue); /* constant */
extra_scan_keys++; extra_scan_keys++;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * 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 * 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. * page as the underlying sort or index as to which end NULLs sort to.
*/ */
typedef enum 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; } MergeFunctionKind;
/* Runtime data for each mergejoin clause */ /* Runtime data for each mergejoin clause */
@ -132,20 +132,11 @@ typedef struct MergeJoinClauseData
bool lisnull; /* and their isnull flags */ bool lisnull; /* and their isnull flags */
bool risnull; 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 * The comparison strategy in use, and the lookup info to let us call the
* needed comparison routines. eqfinfo is the "=" operator itself. * btree comparison support function.
* cmpfinfo is either the btree comparator or the "<" operator.
*/ */
MergeFunctionKind cmpstrategy; MergeFunctionKind cmpstrategy;
FmgrInfo eqfinfo;
FmgrInfo cmpfinfo; FmgrInfo cmpfinfo;
} MergeJoinClauseData; } MergeJoinClauseData;
@ -164,34 +155,51 @@ typedef struct MergeJoinClauseData
* we will need at runtime. Each struct essentially tells us how to compare * we will need at runtime. Each struct essentially tells us how to compare
* the two expressions from the original clause. * the two expressions from the original clause.
* *
* The best, most efficient way to compare two expressions is to use a btree * In addition to the expressions themselves, the planner passes the btree
* comparison support routine, since that requires only one function call * opfamily OID and btree strategy number (BTLessStrategyNumber or
* per comparison. Hence we try to find a btree opclass that matches the * BTGreaterStrategyNumber) that identify the intended merge semantics for
* mergejoinable operator. If we cannot find one, we'll have to call both * each merge key. The mergejoinable operator is an equality operator in
* the "=" and (often) the "<" operator for each comparison. * 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 static MergeJoinClause
MJExamineQuals(List *qualList, PlanState *parent) MJExamineQuals(List *mergeclauses, List *mergefamilies, List *mergestrategies,
PlanState *parent)
{ {
MergeJoinClause clauses; MergeJoinClause clauses;
int nClauses = list_length(qualList); int nClauses = list_length(mergeclauses);
int iClause; int iClause;
ListCell *l; ListCell *cl;
ListCell *cf;
ListCell *cs;
clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData)); clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData));
iClause = 0; 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]; MergeJoinClause clause = &clauses[iClause];
Oid ltop; Oid opfamily;
Oid gtop; StrategyNumber opstrategy;
RegProcedure ltproc; int op_strategy;
RegProcedure gtproc; Oid op_lefttype;
Oid op_righttype;
bool op_recheck;
RegProcedure cmpproc;
AclResult aclresult; 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)) if (!IsA(qual, OpExpr))
elog(ERROR, "mergejoin clause is not an 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->lexpr = ExecInitExpr((Expr *) linitial(qual->args), parent);
clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent); clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
/* /* Extract the operator's declared left/right datatypes */
* Check permission to call the mergejoinable operator. For get_op_opfamily_properties(qual->opno, opfamily,
* predictability, we check this even if we end up not using it. &op_strategy,
*/ &op_lefttype,
aclresult = pg_proc_aclcheck(qual->opfuncid, GetUserId(), ACL_EXECUTE); &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) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC, aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(qual->opfuncid)); get_func_name(cmpproc));
/* Set up the fmgr lookup information */ /* Set up the fmgr lookup information */
fmgr_info(qual->opfuncid, &(clause->eqfinfo)); fmgr_info(cmpproc, &(clause->cmpfinfo));
/* 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));
iClause++; iClause++;
} }
@ -286,7 +247,7 @@ MJExamineQuals(List *qualList, PlanState *parent)
* Compute the values of the mergejoined expressions for the current * Compute the values of the mergejoined expressions for the current
* outer tuple. We also detect whether it's impossible 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 * 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 * We evaluate the values in OuterEContext, which can be reset each
* time we move to a new tuple. * time we move to a new tuple.
@ -311,7 +272,7 @@ MJEvalOuterValues(MergeJoinState *mergestate)
clause->ldatum = ExecEvalExpr(clause->lexpr, econtext, clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
&clause->lisnull, NULL); &clause->lisnull, NULL);
if (clause->lisnull && clause->mergestrict) if (clause->lisnull)
canmatch = false; canmatch = false;
} }
@ -347,7 +308,7 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
clause->rdatum = ExecEvalExpr(clause->rexpr, econtext, clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
&clause->risnull, NULL); &clause->risnull, NULL);
if (clause->risnull && clause->mergestrict) if (clause->risnull)
canmatch = false; canmatch = false;
} }
@ -391,32 +352,11 @@ MJCompare(MergeJoinState *mergestate)
/* /*
* Deal with null inputs. We treat NULL as sorting after non-NULL. * 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->lisnull)
{ {
if (clause->risnull) 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; nulleqnull = true;
continue; continue;
} }
@ -431,38 +371,26 @@ MJCompare(MergeJoinState *mergestate)
break; 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, nulleqnull = true;
NULL, NULL); continue;
fcinfo.arg[0] = clause->ldatum; }
fcinfo.arg[1] = clause->rdatum; if (DatumGetInt32(fresult) == 0)
fcinfo.argnull[0] = false; {
fcinfo.argnull[1] = false; /* equal */
fresult = FunctionCallInvoke(&fcinfo); continue;
if (fcinfo.isnull) }
{ if (clause->cmpstrategy == MERGEFUNC_CMP)
nulleqnull = true; {
continue; if (DatumGetInt32(fresult) < 0)
}
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))
{ {
/* less than */ /* less than */
result = -1; result = -1;
@ -476,26 +404,9 @@ MJCompare(MergeJoinState *mergestate)
} }
} }
else else
/* must be MERGEFUNC_CMP */
{ {
InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2, /* reverse the sort order */
NULL, NULL); if (DatumGetInt32(fresult) > 0)
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)
{ {
/* less than */ /* less than */
result = -1; result = -1;
@ -1614,6 +1525,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
*/ */
mergestate->mj_NumClauses = list_length(node->mergeclauses); mergestate->mj_NumClauses = list_length(node->mergeclauses);
mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses, mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
node->mergefamilies,
node->mergestrategies,
(PlanState *) mergestate); (PlanState *) mergestate);
/* /*

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 remainder of node
*/ */
COPY_NODE_FIELD(mergeclauses); COPY_NODE_FIELD(mergeclauses);
COPY_NODE_FIELD(mergefamilies);
COPY_NODE_FIELD(mergestrategies);
return newnode; return newnode;
} }
@ -1055,7 +1057,7 @@ _copyRowCompareExpr(RowCompareExpr *from)
COPY_SCALAR_FIELD(rctype); COPY_SCALAR_FIELD(rctype);
COPY_NODE_FIELD(opnos); COPY_NODE_FIELD(opnos);
COPY_NODE_FIELD(opclasses); COPY_NODE_FIELD(opfamilies);
COPY_NODE_FIELD(largs); COPY_NODE_FIELD(largs);
COPY_NODE_FIELD(rargs); COPY_NODE_FIELD(rargs);
@ -1307,6 +1309,7 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_SCALAR_FIELD(mergejoinoperator); COPY_SCALAR_FIELD(mergejoinoperator);
COPY_SCALAR_FIELD(left_sortop); COPY_SCALAR_FIELD(left_sortop);
COPY_SCALAR_FIELD(right_sortop); COPY_SCALAR_FIELD(right_sortop);
COPY_SCALAR_FIELD(mergeopfamily);
/* /*
* Do not copy pathkeys, since they'd not be canonical in a copied query * 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); CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
COPY_NODE_FIELD(opclassname); COPY_NODE_FIELD(opclassname);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname); COPY_STRING_FIELD(amname);
COPY_NODE_FIELD(datatype); COPY_NODE_FIELD(datatype);
COPY_NODE_FIELD(items); COPY_NODE_FIELD(items);

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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_SCALAR_FIELD(rctype);
COMPARE_NODE_FIELD(opnos); COMPARE_NODE_FIELD(opnos);
COMPARE_NODE_FIELD(opclasses); COMPARE_NODE_FIELD(opfamilies);
COMPARE_NODE_FIELD(largs); COMPARE_NODE_FIELD(largs);
COMPARE_NODE_FIELD(rargs); COMPARE_NODE_FIELD(rargs);
@ -1163,6 +1163,7 @@ static bool
_equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b) _equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
{ {
COMPARE_NODE_FIELD(opclassname); COMPARE_NODE_FIELD(opclassname);
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname); COMPARE_STRING_FIELD(amname);
COMPARE_NODE_FIELD(datatype); COMPARE_NODE_FIELD(datatype);
COMPARE_NODE_FIELD(items); COMPARE_NODE_FIELD(items);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
@ -442,6 +442,8 @@ _outMergeJoin(StringInfo str, MergeJoin *node)
_outJoinPlanInfo(str, (Join *) node); _outJoinPlanInfo(str, (Join *) node);
WRITE_NODE_FIELD(mergeclauses); WRITE_NODE_FIELD(mergeclauses);
WRITE_NODE_FIELD(mergefamilies);
WRITE_NODE_FIELD(mergestrategies);
} }
static void static void
@ -866,7 +868,7 @@ _outRowCompareExpr(StringInfo str, RowCompareExpr *node)
WRITE_ENUM_FIELD(rctype, RowCompareType); WRITE_ENUM_FIELD(rctype, RowCompareType);
WRITE_NODE_FIELD(opnos); WRITE_NODE_FIELD(opnos);
WRITE_NODE_FIELD(opclasses); WRITE_NODE_FIELD(opfamilies);
WRITE_NODE_FIELD(largs); WRITE_NODE_FIELD(largs);
WRITE_NODE_FIELD(rargs); WRITE_NODE_FIELD(rargs);
} }
@ -1167,6 +1169,8 @@ _outMergePath(StringInfo str, MergePath *node)
_outJoinPathInfo(str, (JoinPath *) node); _outJoinPathInfo(str, (JoinPath *) node);
WRITE_NODE_FIELD(path_mergeclauses); WRITE_NODE_FIELD(path_mergeclauses);
WRITE_NODE_FIELD(path_mergefamilies);
WRITE_NODE_FIELD(path_mergestrategies);
WRITE_NODE_FIELD(outersortkeys); WRITE_NODE_FIELD(outersortkeys);
WRITE_NODE_FIELD(innersortkeys); WRITE_NODE_FIELD(innersortkeys);
} }
@ -1281,6 +1285,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_OID_FIELD(mergejoinoperator); WRITE_OID_FIELD(mergejoinoperator);
WRITE_OID_FIELD(left_sortop); WRITE_OID_FIELD(left_sortop);
WRITE_OID_FIELD(right_sortop); WRITE_OID_FIELD(right_sortop);
WRITE_OID_FIELD(mergeopfamily);
WRITE_NODE_FIELD(left_pathkey); WRITE_NODE_FIELD(left_pathkey);
WRITE_NODE_FIELD(right_pathkey); WRITE_NODE_FIELD(right_pathkey);
WRITE_OID_FIELD(hashjoinoperator); WRITE_OID_FIELD(hashjoinoperator);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
@ -672,7 +672,7 @@ _readRowCompareExpr(void)
READ_ENUM_FIELD(rctype, RowCompareType); READ_ENUM_FIELD(rctype, RowCompareType);
READ_NODE_FIELD(opnos); READ_NODE_FIELD(opnos);
READ_NODE_FIELD(opclasses); READ_NODE_FIELD(opfamilies);
READ_NODE_FIELD(largs); READ_NODE_FIELD(largs);
READ_NODE_FIELD(rargs); READ_NODE_FIELD(rargs);

View File

@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 *outer_path = path->jpath.outerjoinpath;
Path *inner_path = path->jpath.innerjoinpath; Path *inner_path = path->jpath.innerjoinpath;
List *mergeclauses = path->path_mergeclauses; List *mergeclauses = path->path_mergeclauses;
List *mergefamilies = path->path_mergefamilies;
List *mergestrategies = path->path_mergestrategies;
List *outersortkeys = path->outersortkeys; List *outersortkeys = path->outersortkeys;
List *innersortkeys = path->innersortkeys; List *innersortkeys = path->innersortkeys;
Cost startup_cost = 0; 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 * Since this calculation is somewhat expensive, and will be the same for
* all mergejoin paths associated with the merge clause, we cache the * 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) if (mergeclauses && path->jpath.jointype != JOIN_FULL)
{ {
firstclause = (RestrictInfo *) linitial(mergeclauses); firstclause = (RestrictInfo *) linitial(mergeclauses);
if (firstclause->left_mergescansel < 0) /* not computed yet? */ if (firstclause->left_mergescansel < 0) /* not computed yet? */
mergejoinscansel(root, (Node *) firstclause->clause, mergejoinscansel(root, (Node *) firstclause->clause,
linitial_oid(mergefamilies),
linitial_int(mergestrategies),
&firstclause->left_mergescansel, &firstclause->left_mergescansel,
&firstclause->right_mergescansel); &firstclause->right_mergescansel);

View File

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

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 <math.h>
#include "access/skey.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
@ -39,6 +40,8 @@ static List *select_mergejoin_clauses(RelOptInfo *joinrel,
RelOptInfo *innerrel, RelOptInfo *innerrel,
List *restrictlist, List *restrictlist,
JoinType jointype); 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 *front_pathkey = (List *) lfirst(l);
List *cur_pathkeys; List *cur_pathkeys;
List *cur_mergeclauses; List *cur_mergeclauses;
List *mergefamilies;
List *mergestrategies;
List *outerkeys; List *outerkeys;
List *innerkeys; List *innerkeys;
List *merge_pathkeys; List *merge_pathkeys;
@ -269,6 +274,10 @@ sort_inner_and_outer(PlannerInfo *root,
merge_pathkeys = build_join_pathkeys(root, joinrel, jointype, merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
outerkeys); outerkeys);
/* Build opfamily info for execution */
build_mergejoin_strat_lists(cur_mergeclauses,
&mergefamilies, &mergestrategies);
/* /*
* And now we can make the path. * And now we can make the path.
*/ */
@ -281,6 +290,8 @@ sort_inner_and_outer(PlannerInfo *root,
restrictlist, restrictlist,
merge_pathkeys, merge_pathkeys,
cur_mergeclauses, cur_mergeclauses,
mergefamilies,
mergestrategies,
outerkeys, outerkeys,
innerkeys)); innerkeys));
} }
@ -410,6 +421,8 @@ match_unsorted_outer(PlannerInfo *root,
Path *outerpath = (Path *) lfirst(l); Path *outerpath = (Path *) lfirst(l);
List *merge_pathkeys; List *merge_pathkeys;
List *mergeclauses; List *mergeclauses;
List *mergefamilies;
List *mergestrategies;
List *innersortkeys; List *innersortkeys;
List *trialsortkeys; List *trialsortkeys;
Path *cheapest_startup_inner; Path *cheapest_startup_inner;
@ -516,6 +529,10 @@ match_unsorted_outer(PlannerInfo *root,
mergeclauses, mergeclauses,
innerrel); innerrel);
/* Build opfamily info for execution */
build_mergejoin_strat_lists(mergeclauses,
&mergefamilies, &mergestrategies);
/* /*
* Generate a mergejoin on the basis of sorting the cheapest inner. * Generate a mergejoin on the basis of sorting the cheapest inner.
* Since a sort will be needed, only cheapest total cost matters. (But * Since a sort will be needed, only cheapest total cost matters. (But
@ -531,6 +548,8 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist, restrictlist,
merge_pathkeys, merge_pathkeys,
mergeclauses, mergeclauses,
mergefamilies,
mergestrategies,
NIL, NIL,
innersortkeys)); innersortkeys));
@ -589,6 +608,11 @@ match_unsorted_outer(PlannerInfo *root,
} }
else else
newclauses = mergeclauses; newclauses = mergeclauses;
/* Build opfamily info for execution */
build_mergejoin_strat_lists(newclauses,
&mergefamilies, &mergestrategies);
add_path(joinrel, (Path *) add_path(joinrel, (Path *)
create_mergejoin_path(root, create_mergejoin_path(root,
joinrel, joinrel,
@ -598,6 +622,8 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist, restrictlist,
merge_pathkeys, merge_pathkeys,
newclauses, newclauses,
mergefamilies,
mergestrategies,
NIL, NIL,
NIL)); NIL));
cheapest_total_inner = innerpath; cheapest_total_inner = innerpath;
@ -633,6 +659,11 @@ match_unsorted_outer(PlannerInfo *root,
else else
newclauses = mergeclauses; newclauses = mergeclauses;
} }
/* Build opfamily info for execution */
build_mergejoin_strat_lists(newclauses,
&mergefamilies, &mergestrategies);
add_path(joinrel, (Path *) add_path(joinrel, (Path *)
create_mergejoin_path(root, create_mergejoin_path(root,
joinrel, joinrel,
@ -642,6 +673,8 @@ match_unsorted_outer(PlannerInfo *root,
restrictlist, restrictlist,
merge_pathkeys, merge_pathkeys,
newclauses, newclauses,
mergefamilies,
mergestrategies,
NIL, NIL,
NIL)); NIL));
} }
@ -946,3 +979,35 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
return result_list; 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 * 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 **indexstrategy,
List **indexsubtype); List **indexsubtype);
static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
Oid *opclass); Oid *opfamily);
static List *get_switched_clauses(List *clauses, Relids outerrelids); static List *get_switched_clauses(List *clauses, Relids outerrelids);
static List *order_qual_clauses(PlannerInfo *root, List *clauses); static List *order_qual_clauses(PlannerInfo *root, List *clauses);
static void copy_path_costsize(Plan *dest, Path *src); 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 Hash *make_hash(Plan *lefttree);
static MergeJoin *make_mergejoin(List *tlist, static MergeJoin *make_mergejoin(List *tlist,
List *joinclauses, List *otherclauses, List *joinclauses, List *otherclauses,
List *mergeclauses, List *mergeclauses, List *mergefamilies, List *mergestrategies,
Plan *lefttree, Plan *righttree, Plan *lefttree, Plan *righttree,
JoinType jointype); JoinType jointype);
static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols, static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
@ -1540,6 +1540,8 @@ create_mergejoin_plan(PlannerInfo *root,
joinclauses, joinclauses,
otherclauses, otherclauses,
mergeclauses, mergeclauses,
best_path->path_mergefamilies,
best_path->path_mergestrategies,
outer_plan, outer_plan,
inner_plan, inner_plan,
best_path->jpath.jointype); best_path->jpath.jointype);
@ -1676,9 +1678,10 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
Expr *clause; Expr *clause;
Oid clause_op; Oid clause_op;
Oid opclass; Oid opfamily;
int stratno; int stratno;
Oid stratsubtype; Oid stratlefttype;
Oid stratrighttype;
bool recheck; bool recheck;
Assert(IsA(rinfo, RestrictInfo)); 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 * 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), linitial(op->args) = fix_indexqual_operand(linitial(op->args),
index, index,
&opclass); &opfamily);
clause_op = op->opno; clause_op = op->opno;
} }
else if (IsA(clause, RowCompareExpr)) 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 * For each column in the row comparison, determine which index
* attribute this is and change the indexkey operand as needed. * attribute this is and change the indexkey operand as needed.
* *
* Save the index opclass for only the first column. We will * Save the index opfamily for only the first column. We will
* return the operator and opclass info for just the first column * return the operator and opfamily info for just the first column
* of the row comparison; the executor will have to look up the * of the row comparison; the executor will have to look up the
* rest if it needs them. * rest if it needs them.
*/ */
foreach(lc, rc->largs) foreach(lc, rc->largs)
{ {
Oid tmp_opclass; Oid tmp_opfamily;
lfirst(lc) = fix_indexqual_operand(lfirst(lc), lfirst(lc) = fix_indexqual_operand(lfirst(lc),
index, index,
&tmp_opclass); &tmp_opfamily);
if (lc == list_head(rc->largs)) if (lc == list_head(rc->largs))
opclass = tmp_opclass; opfamily = tmp_opfamily;
} }
clause_op = linitial_oid(rc->opnos); 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 * 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), linitial(saop->args) = fix_indexqual_operand(linitial(saop->args),
index, index,
&opclass); &opfamily);
clause_op = saop->opno; clause_op = saop->opno;
} }
else else
@ -1776,15 +1779,18 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
*fixed_indexquals = lappend(*fixed_indexquals, clause); *fixed_indexquals = lappend(*fixed_indexquals, clause);
/* /*
* Look up the (possibly commuted) operator in the operator class to * Look up the (possibly commuted) operator in the operator family to
* get its strategy numbers and the recheck indicator. This also * get its strategy number and the recheck indicator. This also
* double-checks that we found an operator matching the index. * double-checks that we found an operator matching the index.
*/ */
get_op_opclass_properties(clause_op, opclass, get_op_opfamily_properties(clause_op, opfamily,
&stratno, &stratsubtype, &recheck); &stratno,
&stratlefttype,
&stratrighttype,
&recheck);
*indexstrategy = lappend_int(*indexstrategy, stratno); *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 it's not lossy, add to nonlossy_indexquals */
if (!recheck) if (!recheck)
@ -1793,7 +1799,7 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
} }
static Node * 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 * 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 = (Var *) copyObject(node);
result->varattno = pos + 1; result->varattno = pos + 1;
/* return the correct opclass, too */ /* return the correct opfamily, too */
*opclass = index->classlist[pos]; *opfamily = index->opfamily[pos];
return (Node *) result; return (Node *) result;
} }
} }
@ -1853,8 +1859,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
result = makeVar(index->rel->relid, pos + 1, result = makeVar(index->rel->relid, pos + 1,
exprType(lfirst(indexpr_item)), -1, exprType(lfirst(indexpr_item)), -1,
0); 0);
/* return the correct opclass, too */ /* return the correct opfamily, too */
*opclass = index->classlist[pos]; *opfamily = index->opfamily[pos];
return (Node *) result; return (Node *) result;
} }
indexpr_item = lnext(indexpr_item); indexpr_item = lnext(indexpr_item);
@ -1863,7 +1869,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
/* Ooops... */ /* Ooops... */
elog(ERROR, "node is not an index attribute"); elog(ERROR, "node is not an index attribute");
*opclass = InvalidOid; /* keep compiler quiet */ *opfamily = InvalidOid; /* keep compiler quiet */
return NULL; return NULL;
} }
@ -2327,6 +2333,8 @@ make_mergejoin(List *tlist,
List *joinclauses, List *joinclauses,
List *otherclauses, List *otherclauses,
List *mergeclauses, List *mergeclauses,
List *mergefamilies,
List *mergestrategies,
Plan *lefttree, Plan *lefttree,
Plan *righttree, Plan *righttree,
JoinType jointype) JoinType jointype)
@ -2340,6 +2348,8 @@ make_mergejoin(List *tlist,
plan->lefttree = lefttree; plan->lefttree = lefttree;
plan->righttree = righttree; plan->righttree = righttree;
node->mergeclauses = mergeclauses; node->mergeclauses = mergeclauses;
node->mergefamilies = mergefamilies;
node->mergestrategies = mergestrategies;
node->join.jointype = jointype; node->join.jointype = jointype;
node->join.joinqual = joinclauses; node->join.joinqual = joinclauses;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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. * Let's just make sure this appears to be a compatible operator.
*
* XXX needs work
*/ */
if (pgopform->oprlsortop != sortop1 || if (pgopform->oprresult != BOOLOID)
pgopform->oprrsortop != sortop2 ||
pgopform->oprresult != BOOLOID)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("equality operator for types %s and %s should be merge-joinable, but isn't", 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, Oid opno,
leftOp, leftOp,
rightOp; rightOp;
Oid opfamily;
if (restrictinfo->pseudoconstant) if (restrictinfo->pseudoconstant)
return; return;
@ -1286,14 +1287,17 @@ check_mergejoinable(RestrictInfo *restrictinfo)
opno = ((OpExpr *) clause)->opno; opno = ((OpExpr *) clause)->opno;
if (op_mergejoinable(opno, if (op_mergejoinable(opno) &&
&leftOp,
&rightOp) &&
!contain_volatile_functions((Node *) clause)) !contain_volatile_functions((Node *) clause))
{ {
restrictinfo->mergejoinoperator = opno; /* XXX for the moment, continue to force use of particular sortops */
restrictinfo->left_sortop = leftOp; if (get_op_mergejoin_info(opno, &leftOp, &rightOp, &opfamily))
restrictinfo->right_sortop = rightOp; {
restrictinfo->mergejoinoperator = opno;
restrictinfo->left_sortop = leftOp;
restrictinfo->right_sortop = rightOp;
restrictinfo->mergeopfamily = opfamily;
}
} }
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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)); Assert(is_opclause(rinfo->clause));
strategy = strategy =
get_op_opclass_strategy(((OpExpr *) rinfo->clause)->opno, get_op_opfamily_strategy(((OpExpr *) rinfo->clause)->opno,
index->classlist[prevcol]); index->opfamily[prevcol]);
if (strategy == BTEqualStrategyNumber) if (strategy == BTEqualStrategyNumber)
break; break;
} }
@ -390,10 +390,10 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
* Does an aggregate match an index column? * Does an aggregate match an index column?
* *
* It matches if its argument is equal to the index column's data and its * 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, * We return ForwardScanDirection if match a LessThan member,
* BackwardScanDirection if match the GreaterThan member, * BackwardScanDirection if match a GreaterThan member,
* and NoMovementScanDirection if there's no match. * and NoMovementScanDirection if there's no match.
*/ */
static ScanDirection 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)) if (!match_index_to_operand((Node *) info->target, indexcol, index))
return NoMovementScanDirection; return NoMovementScanDirection;
/* Look up the operator in the opclass */ /* Look up the operator in the opfamily */
strategy = get_op_opclass_strategy(info->aggsortop, strategy = get_op_opfamily_strategy(info->aggsortop,
index->classlist[indexcol]); index->opfamily[indexcol]);
if (strategy == BTLessStrategyNumber) if (strategy == BTLessStrategyNumber)
return ForwardScanDirection; return ForwardScanDirection;
if (strategy == BTGreaterStrategyNumber) if (strategy == BTGreaterStrategyNumber)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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; return NULL;
if (sublink->testexpr && IsA(sublink->testexpr, OpExpr)) if (sublink->testexpr && IsA(sublink->testexpr, OpExpr))
{ {
List *opclasses; List *opfamilies;
List *opstrats; List *opstrats;
get_op_btree_interpretation(((OpExpr *) sublink->testexpr)->opno, get_op_btree_interpretation(((OpExpr *) sublink->testexpr)->opno,
&opclasses, &opstrats); &opfamilies, &opstrats);
if (!list_member_int(opstrats, ROWCOMPARE_EQ)) if (!list_member_int(opstrats, ROWCOMPARE_EQ))
return NULL; return NULL;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -1294,13 +1294,9 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
clause->opnos = newops; clause->opnos = newops;
/* /*
* Note: we don't bother to update the opclasses list, but just set it to * Note: we need not change the opfamilies list; we assume any btree
* empty. This is OK since this routine is currently only used for index * opfamily containing an operator will also contain its commutator.
* 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.
*/ */
clause->opclasses = NIL; /* XXX */
temp = clause->largs; temp = clause->largs;
clause->largs = clause->rargs; clause->largs = clause->rargs;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * 'pathkeys' are the path keys of the new join path
* 'mergeclauses' are the RestrictInfo nodes to use as merge clauses * 'mergeclauses' are the RestrictInfo nodes to use as merge clauses
* (this should be a subset of the restrict_clauses list) * (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 * 'outersortkeys' are the sort varkeys for the outer relation
* 'innersortkeys' are the sort varkeys for the inner relation * 'innersortkeys' are the sort varkeys for the inner relation
*/ */
@ -1164,6 +1168,8 @@ create_mergejoin_path(PlannerInfo *root,
List *restrict_clauses, List *restrict_clauses,
List *pathkeys, List *pathkeys,
List *mergeclauses, List *mergeclauses,
List *mergefamilies,
List *mergestrategies,
List *outersortkeys, List *outersortkeys,
List *innersortkeys) List *innersortkeys)
{ {
@ -1204,6 +1210,8 @@ create_mergejoin_path(PlannerInfo *root,
pathnode->jpath.joinrestrictinfo = restrict_clauses; pathnode->jpath.joinrestrictinfo = restrict_clauses;
pathnode->jpath.path.pathkeys = pathkeys; pathnode->jpath.path.pathkeys = pathkeys;
pathnode->path_mergeclauses = mergeclauses; pathnode->path_mergeclauses = mergeclauses;
pathnode->path_mergefamilies = mergefamilies;
pathnode->path_mergestrategies = mergestrategies;
pathnode->outersortkeys = outersortkeys; pathnode->outersortkeys = outersortkeys;
pathnode->innersortkeys = innersortkeys; pathnode->innersortkeys = innersortkeys;

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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; 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. * a terminating 0 at the end of each one.
*/ */
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns); 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)); info->ordering = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
for (i = 0; i < ncolumns; i++) 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]; info->indexkeys[i] = index->indkey.values[i];
} }

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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.) * already known immutable, so the clause will certainly always fail.)
* *
* Finally, we may be able to deduce something using knowledge about btree * 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 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. * that has "foo" as an input. See notes for implication case.
* *
* Finally, we may be able to deduce something using knowledge about btree * 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 static bool
@ -1062,8 +1062,8 @@ extract_not_arg(Node *clause)
* The strategy numbers defined by btree indexes (see access/skey.h) are: * The strategy numbers defined by btree indexes (see access/skey.h) are:
* (1) < (2) <= (3) = (4) >= (5) > * (1) < (2) <= (3) = (4) >= (5) >
* and in addition we use (6) to represent <>. <> is not a btree-indexable * 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 * operator, but we assume here that if an equality operator of a btree
* opclass has a negator operator, the negator behaves as <> for the opclass. * opfamily has a negator operator, the negator behaves as <> for the opfamily.
* *
* The interpretation of: * 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 * 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 * "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 * 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 * derive implications between nonidentical clauses. (Note: "foo" is known
* immutable, and constants are surely immutable, but we have to check that * 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 * operators that are merely stable, and we dare not make deductions with
* these.) * these.)
*---------- *----------
@ -1171,12 +1171,12 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
pred_op_negator, pred_op_negator,
clause_op_negator, clause_op_negator,
test_op = InvalidOid; test_op = InvalidOid;
Oid opclass_id; Oid opfamily_id;
bool found = false; bool found = false;
StrategyNumber pred_strategy, StrategyNumber pred_strategy,
clause_strategy, clause_strategy,
test_strategy; test_strategy;
Oid clause_subtype; Oid clause_righttype;
Expr *test_expr; Expr *test_expr;
ExprState *test_exprstate; ExprState *test_exprstate;
Datum test_result; 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 * implication can't be determined. Also, the pred_op has to be of
* default subtype (implying left and right input datatypes are the same); * 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 * 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 * the clause_const's type (which we take to mean that it has the same
* subtype as the original clause_operator). * 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 * determine the logical relationship of the two operators and the correct
* corresponding test operator. This should work for any logically * corresponding test operator. This should work for any logically
* consistent opclasses. * consistent opfamilies.
*/ */
catlist = SearchSysCacheList(AMOPOPID, 1, catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(pred_op), ObjectIdGetDatum(pred_op),
0, 0, 0); 0, 0, 0);
/* /*
* If we couldn't find any opclass containing the pred_op, perhaps it is a * 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 opclass. * <> operator. See if it has a negator that is in an opfamily.
*/ */
pred_op_negated = false; pred_op_negated = false;
if (catlist->n_members == 0) 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 */ /* Also may need the clause_op's negator */
clause_op_negator = get_negator(clause_op); clause_op_negator = get_negator(clause_op);
/* Now search the opclasses */ /* Now search the opfamilies */
for (i = 0; i < catlist->n_members; i++) for (i = 0; i < catlist->n_members; i++)
{ {
HeapTuple pred_tuple = &catlist->members[i]->tuple; HeapTuple pred_tuple = &catlist->members[i]->tuple;
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple); Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
HeapTuple clause_tuple; HeapTuple clause_tuple;
opclass_id = pred_form->amopclaid;
/* must be btree */ /* must be btree */
if (!opclass_is_btree(opclass_id)) if (pred_form->amopmethod != BTREE_AM_OID)
continue; continue;
/* predicate operator must be default within this opclass */ /* predicate operator must be default within this opfamily */
if (pred_form->amopsubtype != InvalidOid) if (pred_form->amoplefttype != pred_form->amoprighttype)
continue; continue;
/* Get the predicate operator's btree strategy number */ /* Get the predicate operator's btree strategy number */
opfamily_id = pred_form->amopfamily;
pred_strategy = (StrategyNumber) pred_form->amopstrategy; pred_strategy = (StrategyNumber) pred_form->amopstrategy;
Assert(pred_strategy >= 1 && pred_strategy <= 5); 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 * From the same opfamily, find a strategy number for the clause_op,
* possible * if possible
*/ */
clause_tuple = SearchSysCache(AMOPOPID, clause_tuple = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(clause_op), ObjectIdGetDatum(clause_op),
ObjectIdGetDatum(opclass_id), ObjectIdGetDatum(opfamily_id),
0, 0); 0, 0);
if (HeapTupleIsValid(clause_tuple)) if (HeapTupleIsValid(clause_tuple))
{ {
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(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; clause_strategy = (StrategyNumber) clause_form->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5); 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); ReleaseSysCache(clause_tuple);
} }
else if (OidIsValid(clause_op_negator)) else if (OidIsValid(clause_op_negator))
{ {
clause_tuple = SearchSysCache(AMOPOPID, clause_tuple = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(clause_op_negator), ObjectIdGetDatum(clause_op_negator),
ObjectIdGetDatum(opclass_id), ObjectIdGetDatum(opfamily_id),
0, 0); 0, 0);
if (HeapTupleIsValid(clause_tuple)) if (HeapTupleIsValid(clause_tuple))
{ {
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(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; clause_strategy = (StrategyNumber) clause_form->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5); 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); ReleaseSysCache(clause_tuple);
/* Only consider negators that are = */ /* 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 * See if opfamily has an operator for the test strategy and the
* datatype. * datatypes.
*/ */
if (test_strategy == BTNE) if (test_strategy == BTNE)
{ {
test_op = get_opclass_member(opclass_id, clause_subtype, test_op = get_opfamily_member(opfamily_id,
BTEqualStrategyNumber); pred_form->amoprighttype,
clause_righttype,
BTEqualStrategyNumber);
if (OidIsValid(test_op)) if (OidIsValid(test_op))
test_op = get_negator(test_op); test_op = get_negator(test_op);
} }
else else
{ {
test_op = get_opclass_member(opclass_id, clause_subtype, test_op = get_opfamily_member(opfamily_id,
test_strategy); pred_form->amoprighttype,
clause_righttype,
test_strategy);
} }
if (OidIsValid(test_op)) 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 * Note that we require only the test_op to be immutable, not the
* original clause_op. (pred_op is assumed to have been checked * original clause_op. (pred_op is assumed to have been checked
* immutable by the caller.) Essentially we are assuming that the * 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. * merely stable.
*/ */
if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE) if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE)
@ -1438,7 +1445,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
if (!found) if (!found)
{ {
/* couldn't find a btree opclass to interpret the operators */ /* couldn't find a btree opfamily to interpret the operators */
return false; return false;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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->mergejoinoperator = InvalidOid;
restrictinfo->left_sortop = InvalidOid; restrictinfo->left_sortop = InvalidOid;
restrictinfo->right_sortop = InvalidOid; restrictinfo->right_sortop = InvalidOid;
restrictinfo->mergeopfamily = InvalidOid;
restrictinfo->left_pathkey = NIL; restrictinfo->left_pathkey = NIL;
restrictinfo->right_pathkey = NIL; restrictinfo->right_pathkey = NIL;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; RowCompareType rctype;
List *opexprs; List *opexprs;
List *opnos; List *opnos;
List *opclasses; List *opfamilies;
ListCell *l, ListCell *l,
*r; *r;
List **opclass_lists; List **opfamily_lists;
List **opstrat_lists; List **opstrat_lists;
Bitmapset *strats; Bitmapset *strats;
int nopers; 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 * We don't use coerce_to_boolean here because we insist on the
* operator yielding boolean directly, not via coercion. If it * 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) if (cmp->opresulttype != BOOLOID)
ereport(ERROR, ereport(ERROR,
@ -2084,21 +2084,22 @@ make_row_comparison_op(ParseState *pstate, List *opname,
/* /*
* Now we must determine which row comparison semantics (= <> < <= > >=) * 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 * the operators, and see which interpretations (strategy numbers) exist
* for each operator. * for each operator.
*/ */
opclass_lists = (List **) palloc(nopers * sizeof(List *)); opfamily_lists = (List **) palloc(nopers * sizeof(List *));
opstrat_lists = (List **) palloc(nopers * sizeof(List *)); opstrat_lists = (List **) palloc(nopers * sizeof(List *));
strats = NULL; strats = NULL;
i = 0; i = 0;
foreach(l, opexprs) foreach(l, opexprs)
{ {
Oid opno = ((OpExpr *) lfirst(l))->opno;
Bitmapset *this_strats; Bitmapset *this_strats;
ListCell *j; ListCell *j;
get_op_btree_interpretation(((OpExpr *) lfirst(l))->opno, get_op_btree_interpretation(opno,
&opclass_lists[i], &opstrat_lists[i]); &opfamily_lists[i], &opstrat_lists[i]);
/* /*
* convert strategy number list to a Bitmapset to make the * convert strategy number list to a Bitmapset to make the
@ -2116,68 +2117,23 @@ make_row_comparison_op(ParseState *pstate, List *opname,
i++; 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 */
/* No common interpretation, so fail */ ereport(ERROR,
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine interpretation of row comparison operator %s",
errmsg("could not determine interpretation of row comparison operator %s", strVal(llast(opname))),
strVal(llast(opname))), errhint("Row comparison operators must be associated with btree operator families."),
errhint("Row comparison operators must be associated with btree operator classes."), parser_errposition(pstate, location)));
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;
}
} }
rctype = (RowCompareType) i;
/* /*
* For = and <> cases, we just combine the pairwise operators with AND or * 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); 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. * each operator.
*/ */
opclasses = NIL; opfamilies = NIL;
for (i = 0; i < nopers; i++) for (i = 0; i < nopers; i++)
{ {
Oid best_opclass = 0; Oid opfamily = InvalidOid;
int ndefault = 0;
int nmatch = 0;
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); int opstrat = lfirst_int(r);
if (opstrat == rctype) if (opstrat == rctype)
{ {
if (ndefault == 0) opfamily = lfirst_oid(l);
best_opclass = opclass; break;
if (opclass_is_default(opclass))
ndefault++;
else
nmatch++;
} }
} }
if (ndefault == 1 || (ndefault == 0 && nmatch == 1)) if (OidIsValid(opfamily))
opclasses = lappend_oid(opclasses, best_opclass); opfamilies = lappend_oid(opfamilies, opfamily);
else else /* should not happen */
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine interpretation of row comparison operator %s", 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 = makeNode(RowCompareExpr);
rcexpr->rctype = rctype; rcexpr->rctype = rctype;
rcexpr->opnos = opnos; rcexpr->opnos = opnos;
rcexpr->opclasses = opclasses; rcexpr->opfamilies = opfamilies;
rcexpr->largs = largs; rcexpr->largs = largs;
rcexpr->rargs = rargs; rcexpr->rargs = rargs;

View File

@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees * ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text * 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" #include "postgres.h"
@ -19,6 +19,7 @@
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
#include "commands/defrem.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "funcapi.h" #include "funcapi.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
@ -4717,11 +4718,6 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
Form_pg_opclass opcrec; Form_pg_opclass opcrec;
char *opcname; char *opcname;
char *nspname; 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, ht_opc = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opclass),
@ -4730,25 +4726,12 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
elog(ERROR, "cache lookup failed for opclass %u", opclass); elog(ERROR, "cache lookup failed for opclass %u", opclass);
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc); opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
/* if (!OidIsValid(actual_datatype) ||
* Special case for ARRAY_OPS: pretend it is default for any array type GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
*/
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)
{ {
/* Okay, we need the opclass name. Do we need to qualify it? */ /* Okay, we need the opclass name. Do we need to qualify it? */
opcname = NameStr(opcrec->opcname); opcname = NameStr(opcrec->opcname);
if (isvisible) if (OpclassIsVisible(opclass))
appendStringInfo(buf, " %s", quote_identifier(opcname)); appendStringInfo(buf, " %s", quote_identifier(opcname));
else else
{ {

View File

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

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) if (cache->id == INDEXRELID)
{ {
/* /*
* Since the OIDs of indexes aren't hardwired, it's painful to figure * Rather than tracking exactly which indexes have to be loaded
* out which is which. Just force all pg_index searches to be heap * before we can use indexscans (which changes from time to time),
* scans while building the relcaches. * just force all pg_index searches to be heap scans until we've
* built the critical relcaches.
*/ */
if (!criticalRelcachesBuilt) if (!criticalRelcachesBuilt)
return false; return false;
@ -1051,17 +1052,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
*/ */
return false; 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 */ /* Normal case, allow index scan */
return true; return true;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
@ -37,27 +37,27 @@
/* ---------- AMOP CACHES ---------- */ /* ---------- 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 bool
op_in_opclass(Oid opno, Oid opclass) op_in_opfamily(Oid opno, Oid opfamily)
{ {
return SearchSysCacheExists(AMOPOPID, return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opno), ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opfamily),
0, 0); 0, 0);
} }
/* /*
* get_op_opclass_strategy * get_op_opfamily_strategy
* *
* Get the operator's strategy number within the specified opclass, * Get the operator's strategy number within the specified opfamily,
* or 0 if it's not a member of the opclass. * or 0 if it's not a member of the opfamily.
*/ */
int int
get_op_opclass_strategy(Oid opno, Oid opclass) get_op_opfamily_strategy(Oid opno, Oid opfamily)
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_amop amop_tup; Form_pg_amop amop_tup;
@ -65,7 +65,7 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
tp = SearchSysCache(AMOPOPID, tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno), ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opfamily),
0, 0); 0, 0);
if (!HeapTupleIsValid(tp)) if (!HeapTupleIsValid(tp))
return 0; 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 * Get the operator's strategy number, input types, and recheck (lossy)
* within the specified opclass. * 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. * therefore we raise an error if the tuple is not found.
*/ */
void void
get_op_opclass_properties(Oid opno, Oid opclass, get_op_opfamily_properties(Oid opno, Oid opfamily,
int *strategy, Oid *subtype, bool *recheck) int *strategy,
Oid *lefttype,
Oid *righttype,
bool *recheck)
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_amop amop_tup; Form_pg_amop amop_tup;
tp = SearchSysCache(AMOPOPID, tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno), ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opfamily),
0, 0); 0, 0);
if (!HeapTupleIsValid(tp)) if (!HeapTupleIsValid(tp))
elog(ERROR, "operator %u is not a member of opclass %u", elog(ERROR, "operator %u is not a member of opfamily %u",
opno, opclass); opno, opfamily);
amop_tup = (Form_pg_amop) GETSTRUCT(tp); amop_tup = (Form_pg_amop) GETSTRUCT(tp);
*strategy = amop_tup->amopstrategy; *strategy = amop_tup->amopstrategy;
*subtype = amop_tup->amopsubtype; *lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
*recheck = amop_tup->amopreqcheck; *recheck = amop_tup->amopreqcheck;
ReleaseSysCache(tp); ReleaseSysCache(tp);
} }
/* /*
* get_opclass_member * get_opfamily_member
* Get the OID of the operator that implements the specified strategy * 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. * Returns InvalidOid if there is no pg_amop entry for the given keys.
*/ */
Oid Oid
get_opclass_member(Oid opclass, Oid subtype, int16 strategy) get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
int16 strategy)
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_amop amop_tup; Form_pg_amop amop_tup;
Oid result; Oid result;
tp = SearchSysCache(AMOPSTRATEGY, tp = SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opfamily),
ObjectIdGetDatum(subtype), ObjectIdGetDatum(lefttype),
Int16GetDatum(strategy), ObjectIdGetDatum(righttype),
0); Int16GetDatum(strategy));
if (!HeapTupleIsValid(tp)) if (!HeapTupleIsValid(tp))
return InvalidOid; return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp); amop_tup = (Form_pg_amop) GETSTRUCT(tp);
@ -132,11 +137,161 @@ get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
return result; 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_op_hash_function
* Get the OID of the datatype-specific hash function associated with * Get the OID of the datatype-specific hash function associated with
* a hashable equality operator. * 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 * Returns InvalidOid if no hash function can be found. (This indicates
* that the operator should not have been marked oprcanhash.) * that the operator should not have been marked oprcanhash.)
*/ */
@ -145,12 +300,12 @@ get_op_hash_function(Oid opno)
{ {
CatCList *catlist; CatCList *catlist;
int i; int i;
Oid opclass = InvalidOid; Oid result = InvalidOid;
/* /*
* Search pg_amop to see if the target operator is registered as the "=" * Search pg_amop to see if the target operator is registered as the "="
* operator of any hash opclass. If the operator is registered in * operator of any hash opfamily. If the operator is registered in
* multiple opclasses, assume we can use the associated hash function from * multiple opfamilies, assume we can use the associated hash function from
* any one. * any one.
*/ */
catlist = SearchSysCacheList(AMOPOPID, 1, catlist = SearchSysCacheList(AMOPOPID, 1,
@ -162,57 +317,43 @@ get_op_hash_function(Oid opno)
HeapTuple tuple = &catlist->members[i]->tuple; HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopstrategy == HTEqualStrategyNumber && if (aform->amopmethod == HASH_AM_OID &&
opclass_is_hash(aform->amopclaid)) 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; break;
} }
} }
ReleaseSysCacheList(catlist); ReleaseSysCacheList(catlist);
if (OidIsValid(opclass)) return result;
{
/* Found a suitable opclass, get its default hash support function */
return get_opclass_proc(opclass, InvalidOid, HASHPROC);
}
/* Didn't find a match... */
return InvalidOid;
} }
/* /*
* get_op_btree_interpretation * 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 * and what strategy number it has within each one. The results are
* returned as an OID list and a parallel integer list. * returned as an OID list and a parallel integer list.
* *
* In addition to the normal btree operators, we consider a <> operator to be * 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. * a "member" of an opfamily if its negator is an equality operator of the
* ROWCOMPARE_NE is returned as the strategy number for this case. * opfamily. ROWCOMPARE_NE is returned as the strategy number for this case.
*/ */
void 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; CatCList *catlist;
bool op_negated; bool op_negated;
int i; int i;
*opclasses = NIL; *opfamilies = NIL;
*opstrats = 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. * 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); 0, 0, 0);
/* /*
* If we can't find any opclass containing the op, perhaps it is a <> * 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 opclass. * operator. See if it has a negator that is in an opfamily.
*/ */
op_negated = false; op_negated = false;
if (catlist->n_members == 0) 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++) for (i = 0; i < catlist->n_members; i++)
{ {
HeapTuple op_tuple = &catlist->members[i]->tuple; HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple); Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
Oid opclass_id; Oid opfamily_id;
StrategyNumber op_strategy; StrategyNumber op_strategy;
opclass_id = op_form->amopclaid;
/* must be btree */ /* must be btree */
if (!opclass_is_btree(opclass_id)) if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* must match operator input type exactly */
if (get_opclass_input_type(opclass_id) != lefttype)
continue; continue;
/* Get the operator's btree strategy number */ /* Get the operator's btree strategy number */
opfamily_id = op_form->amopfamily;
op_strategy = (StrategyNumber) op_form->amopstrategy; op_strategy = (StrategyNumber) op_form->amopstrategy;
Assert(op_strategy >= 1 && op_strategy <= 5); 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; op_strategy = ROWCOMPARE_NE;
} }
*opclasses = lappend_oid(*opclasses, opclass_id); *opfamilies = lappend_oid(*opfamilies, opfamily_id);
*opstrats = lappend_int(*opstrats, op_strategy); *opstrats = lappend_int(*opstrats, op_strategy);
} }
@ -280,24 +416,24 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
/* ---------- AMPROC CACHES ---------- */ /* ---------- AMPROC CACHES ---------- */
/* /*
* get_opclass_proc * get_opfamily_proc
* Get the OID of the specified support function * 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. * Returns InvalidOid if there is no pg_amproc entry for the given keys.
*/ */
Oid Oid
get_opclass_proc(Oid opclass, Oid subtype, int16 procnum) get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_amproc amproc_tup; Form_pg_amproc amproc_tup;
RegProcedure result; RegProcedure result;
tp = SearchSysCache(AMPROCNUM, tp = SearchSysCache(AMPROCNUM,
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opfamily),
ObjectIdGetDatum(subtype), ObjectIdGetDatum(lefttype),
Int16GetDatum(procnum), ObjectIdGetDatum(righttype),
0); Int16GetDatum(procnum));
if (!HeapTupleIsValid(tp)) if (!HeapTupleIsValid(tp))
return InvalidOid; return InvalidOid;
amproc_tup = (Form_pg_amproc) GETSTRUCT(tp); amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
@ -477,17 +613,16 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
/* ---------- OPCLASS CACHE ---------- */ /* ---------- OPCLASS CACHE ---------- */
/* /*
* opclass_is_btree * get_opclass_family
* *
* Returns TRUE iff the specified opclass is associated with the * Returns the OID of the operator family the opclass belongs to.
* btree index access method.
*/ */
bool Oid
opclass_is_btree(Oid opclass) get_opclass_family(Oid opclass)
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_opclass cla_tup; Form_pg_opclass cla_tup;
bool result; Oid result;
tp = SearchSysCache(CLAOID, tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass), ObjectIdGetDatum(opclass),
@ -496,57 +631,7 @@ opclass_is_btree(Oid opclass)
elog(ERROR, "cache lookup failed for opclass %u", opclass); elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp); cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = (cla_tup->opcamid == BTREE_AM_OID); result = cla_tup->opcfamily;
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;
ReleaseSysCache(tp); ReleaseSysCache(tp);
return result; return result;
} }
@ -657,11 +742,13 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
/* /*
* op_mergejoinable * op_mergejoinable
* *
* Returns the left and right sort operators corresponding to a * Returns true if the operator is potentially mergejoinable. (The planner
* mergejoinable operator, or false if the operator is not mergejoinable. * 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 bool
op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp) op_mergejoinable(Oid opno)
{ {
HeapTuple tp; HeapTuple tp;
bool result = false; bool result = false;
@ -673,65 +760,17 @@ op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
{ {
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
if (optup->oprlsortop && result = optup->oprcanmerge;
optup->oprrsortop)
{
*leftOp = optup->oprlsortop;
*rightOp = optup->oprrsortop;
result = true;
}
ReleaseSysCache(tp); ReleaseSysCache(tp);
} }
return result; 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 * 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 bool
op_hashjoinable(Oid opno) op_hashjoinable(Oid opno)

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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_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 * hardcoded tuple descriptors. see include/catalog/pg_attribute.h
@ -159,7 +159,8 @@ do { \
/* /*
* Special cache for opclass-related information * 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 typedef struct opclasscacheent
{ {
@ -167,6 +168,8 @@ typedef struct opclasscacheent
bool valid; /* set TRUE after successful fill-in */ bool valid; /* set TRUE after successful fill-in */
StrategyNumber numStrats; /* max # of strategies (from pg_am) */ StrategyNumber numStrats; /* max # of strategies (from pg_am) */
StrategyNumber numSupport; /* max # of support procs (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 */ Oid *operatorOids; /* strategy operators' OIDs */
RegProcedure *supportProcs; /* support procs */ RegProcedure *supportProcs; /* support procs */
} OpClassCacheEnt; } OpClassCacheEnt;
@ -201,6 +204,8 @@ static List *insert_ordered_oid(List *list, Oid datum);
static void IndexSupportInitialize(oidvector *indclass, static void IndexSupportInitialize(oidvector *indclass,
Oid *indexOperator, Oid *indexOperator,
RegProcedure *indexSupport, RegProcedure *indexSupport,
Oid *opFamily,
Oid *opcInType,
StrategyNumber maxStrategyNumber, StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber, StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber); AttrNumber maxAttributeNumber);
@ -921,11 +926,9 @@ RelationInitIndexAccessInfo(Relation relation)
Form_pg_am aform; Form_pg_am aform;
Datum indclassDatum; Datum indclassDatum;
bool isnull; bool isnull;
oidvector *indclass;
MemoryContext indexcxt; MemoryContext indexcxt;
MemoryContext oldcontext; MemoryContext oldcontext;
Oid *operator;
RegProcedure *support;
FmgrInfo *supportinfo;
int natts; int natts;
uint16 amstrategies; uint16 amstrategies;
uint16 amsupport; uint16 amsupport;
@ -947,18 +950,6 @@ RelationInitIndexAccessInfo(Relation relation)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
ReleaseSysCache(tuple); 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 * 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 *) relation->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(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) if (amstrategies > 0)
operator = (Oid *) relation->rd_operator = (Oid *)
MemoryContextAllocZero(indexcxt, MemoryContextAllocZero(indexcxt,
natts * amstrategies * sizeof(Oid)); natts * amstrategies * sizeof(Oid));
else else
operator = NULL; relation->rd_operator = NULL;
if (amsupport > 0) if (amsupport > 0)
{ {
int nsupport = natts * amsupport; int nsupport = natts * amsupport;
support = (RegProcedure *) relation->rd_support = (RegProcedure *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure)); MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
supportinfo = (FmgrInfo *) relation->rd_supportinfo = (FmgrInfo *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo)); MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
} }
else else
{ {
support = NULL; relation->rd_support = NULL;
supportinfo = NULL; relation->rd_supportinfo = NULL;
} }
relation->rd_operator = operator; /*
relation->rd_support = support; * indclass cannot be referenced directly through the C struct, because it
relation->rd_supportinfo = supportinfo; * 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) * supportinfo are left as zeroes, and are filled on-the-fly when used)
*/ */
IndexSupportInitialize(relation->rd_indclass, IndexSupportInitialize(indclass,
operator, support, relation->rd_operator, relation->rd_support,
relation->rd_opfamily, relation->rd_opcintype,
amstrategies, amsupport, natts); amstrategies, amsupport, natts);
/* /*
@ -1048,8 +1054,8 @@ RelationInitIndexAccessInfo(Relation relation)
* Initializes an index's cached opclass information, * Initializes an index's cached opclass information,
* given the index's pg_index.indclass entry. * given the index's pg_index.indclass entry.
* *
* Data is returned into *indexOperator and *indexSupport, which are arrays * Data is returned into *indexOperator, *indexSupport, *opFamily, and
* allocated by the caller. * *opcInType, which are arrays allocated by the caller.
* *
* The caller also passes maxStrategyNumber, maxSupportNumber, and * The caller also passes maxStrategyNumber, maxSupportNumber, and
* maxAttributeNumber, since these indicate the size of the arrays * maxAttributeNumber, since these indicate the size of the arrays
@ -1061,6 +1067,8 @@ static void
IndexSupportInitialize(oidvector *indclass, IndexSupportInitialize(oidvector *indclass,
Oid *indexOperator, Oid *indexOperator,
RegProcedure *indexSupport, RegProcedure *indexSupport,
Oid *opFamily,
Oid *opcInType,
StrategyNumber maxStrategyNumber, StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber, StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber) AttrNumber maxAttributeNumber)
@ -1080,6 +1088,8 @@ IndexSupportInitialize(oidvector *indclass,
maxSupportNumber); maxSupportNumber);
/* copy cached data into relcache entry */ /* copy cached data into relcache entry */
opFamily[attIndex] = opcentry->opcfamily;
opcInType[attIndex] = opcentry->opcintype;
if (maxStrategyNumber > 0) if (maxStrategyNumber > 0)
memcpy(&indexOperator[attIndex * maxStrategyNumber], memcpy(&indexOperator[attIndex * maxStrategyNumber],
opcentry->operatorOids, opcentry->operatorOids,
@ -1116,7 +1126,7 @@ LookupOpclassInfo(Oid operatorClassOid,
bool found; bool found;
Relation rel; Relation rel;
SysScanDesc scan; SysScanDesc scan;
ScanKeyData skey[2]; ScanKeyData skey[3];
HeapTuple htup; HeapTuple htup;
bool indexOK; bool indexOK;
@ -1176,23 +1186,55 @@ LookupOpclassInfo(Oid operatorClassOid,
(operatorClassOid != OID_BTREE_OPS_OID && (operatorClassOid != OID_BTREE_OPS_OID &&
operatorClassOid != INT2_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 * 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) if (numStrats > 0)
{ {
ScanKeyInit(&skey[0], ScanKeyInit(&skey[0],
Anum_pg_amop_amopclaid, Anum_pg_amop_amopfamily,
BTEqualStrategyNumber, F_OIDEQ, BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(operatorClassOid)); ObjectIdGetDatum(opcentry->opcfamily));
ScanKeyInit(&skey[1], ScanKeyInit(&skey[1],
Anum_pg_amop_amopsubtype, Anum_pg_amop_amoplefttype,
BTEqualStrategyNumber, F_OIDEQ, 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); rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK, scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,
SnapshotNow, 2, skey); SnapshotNow, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan))) 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 * 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) if (numSupport > 0)
{ {
ScanKeyInit(&skey[0], ScanKeyInit(&skey[0],
Anum_pg_amproc_amopclaid, Anum_pg_amproc_amprocfamily,
BTEqualStrategyNumber, F_OIDEQ, BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(operatorClassOid)); ObjectIdGetDatum(opcentry->opcfamily));
ScanKeyInit(&skey[1], ScanKeyInit(&skey[1],
Anum_pg_amproc_amprocsubtype, Anum_pg_amproc_amproclefttype,
BTEqualStrategyNumber, F_OIDEQ, 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); rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK, scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
SnapshotNow, 2, skey); SnapshotNow, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan))) while (HeapTupleIsValid(htup = systable_getnext(scan)))
{ {
@ -3097,8 +3143,6 @@ load_relcache_init_file(void)
Relation rel; Relation rel;
Form_pg_class relform; Form_pg_class relform;
bool has_not_null; bool has_not_null;
Datum indclassDatum;
bool isnull;
/* first read the relation descriptor length */ /* first read the relation descriptor length */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
@ -3187,6 +3231,8 @@ load_relcache_init_file(void)
{ {
Form_pg_am am; Form_pg_am am;
MemoryContext indexcxt; MemoryContext indexcxt;
Oid *opfamily;
Oid *opcintype;
Oid *operator; Oid *operator;
RegProcedure *support; RegProcedure *support;
int nsupport; int nsupport;
@ -3207,14 +3253,6 @@ load_relcache_init_file(void)
rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE); rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple); 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 */ /* next, read the access method tuple form */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed; goto read_failed;
@ -3235,6 +3273,26 @@ load_relcache_init_file(void)
ALLOCSET_SMALL_MAXSIZE); ALLOCSET_SMALL_MAXSIZE);
rel->rd_indexcxt = indexcxt; 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 */ /* next, read the vector of operator OIDs */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed; goto read_failed;
@ -3269,10 +3327,11 @@ load_relcache_init_file(void)
Assert(rel->rd_index == NULL); Assert(rel->rd_index == NULL);
Assert(rel->rd_indextuple == NULL); Assert(rel->rd_indextuple == NULL);
Assert(rel->rd_indclass == NULL);
Assert(rel->rd_am == NULL); Assert(rel->rd_am == NULL);
Assert(rel->rd_indexcxt == NULL); Assert(rel->rd_indexcxt == NULL);
Assert(rel->rd_aminfo == NULL); Assert(rel->rd_aminfo == NULL);
Assert(rel->rd_opfamily == NULL);
Assert(rel->rd_opcintype == NULL);
Assert(rel->rd_operator == NULL); Assert(rel->rd_operator == NULL);
Assert(rel->rd_support == NULL); Assert(rel->rd_support == NULL);
Assert(rel->rd_supportinfo == NULL); Assert(rel->rd_supportinfo == NULL);
@ -3450,6 +3509,16 @@ write_relcache_init_file(void)
/* next, write the access method tuple form */ /* next, write the access method tuple form */
write_item(am, sizeof(FormData_pg_am), fp); 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 */ /* next, write the vector of operator OIDs */
write_item(rel->rd_operator, write_item(rel->rd_operator,
relform->relnatts * (am->amstrategies * sizeof(Oid)), relform->relnatts * (am->amstrategies * sizeof(Oid)),

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* These routines allow the parser/planner/executor to perform * These routines allow the parser/planner/executor to perform
@ -30,11 +30,11 @@
#include "catalog/pg_cast.h" #include "catalog/pg_cast.h"
#include "catalog/pg_conversion.h" #include "catalog/pg_conversion.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_language.h" #include "catalog/pg_language.h"
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h" #include "catalog/pg_statistic.h"
@ -135,7 +135,7 @@ static const struct cachedesc cacheinfo[] = {
2, 2,
{ {
Anum_pg_amop_amopopr, Anum_pg_amop_amopopr,
Anum_pg_amop_amopclaid, Anum_pg_amop_amopfamily,
0, 0,
0 0
}, },
@ -144,24 +144,24 @@ static const struct cachedesc cacheinfo[] = {
{AccessMethodOperatorRelationId, /* AMOPSTRATEGY */ {AccessMethodOperatorRelationId, /* AMOPSTRATEGY */
AccessMethodStrategyIndexId, AccessMethodStrategyIndexId,
0, 0,
3, 4,
{ {
Anum_pg_amop_amopclaid, Anum_pg_amop_amopfamily,
Anum_pg_amop_amopsubtype, Anum_pg_amop_amoplefttype,
Anum_pg_amop_amopstrategy, Anum_pg_amop_amoprighttype,
0 Anum_pg_amop_amopstrategy
}, },
64 64
}, },
{AccessMethodProcedureRelationId, /* AMPROCNUM */ {AccessMethodProcedureRelationId, /* AMPROCNUM */
AccessMethodProcedureIndexId, AccessMethodProcedureIndexId,
0, 0,
3, 4,
{ {
Anum_pg_amproc_amopclaid, Anum_pg_amproc_amprocfamily,
Anum_pg_amproc_amprocsubtype, Anum_pg_amproc_amproclefttype,
Anum_pg_amproc_amprocnum, Anum_pg_amproc_amprocrighttype,
0 Anum_pg_amproc_amprocnum
}, },
64 64
}, },
@ -255,7 +255,7 @@ static const struct cachedesc cacheinfo[] = {
0, 0,
3, 3,
{ {
Anum_pg_opclass_opcamid, Anum_pg_opclass_opcmethod,
Anum_pg_opclass_opcname, Anum_pg_opclass_opcname,
Anum_pg_opclass_opcnamespace, Anum_pg_opclass_opcnamespace,
0 0
@ -334,18 +334,6 @@ static const struct cachedesc cacheinfo[] = {
}, },
1024 1024
}, },
{InheritsRelationId, /* INHRELID */
InheritsRelidSeqnoIndexId,
Anum_pg_inherits_inhrelid,
2,
{
Anum_pg_inherits_inhrelid,
Anum_pg_inherits_inhseqno,
0,
0
},
256
},
{LanguageRelationId, /* LANGNAME */ {LanguageRelationId, /* LANGNAME */
LanguageNameIndexId, LanguageNameIndexId,
0, 0,
@ -418,6 +406,30 @@ static const struct cachedesc cacheinfo[] = {
}, },
1024 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 */ {ProcedureRelationId, /* PROCNAMEARGSNSP */
ProcedureNameArgsNspIndexId, ProcedureNameArgsNspIndexId,
0, 0,

View File

@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 we haven't already found the opclass, try to do so */
if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR | if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR |
TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC |
TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO)) && TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO |
typentry->btree_opc == InvalidOid) TYPECACHE_BTREE_OPFAMILY)) &&
typentry->btree_opf == InvalidOid)
{ {
typentry->btree_opc = GetDefaultOpClass(type_id, Oid opclass;
BTREE_AM_OID);
/* Only care about hash opclass if no btree opclass... */ opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
if (typentry->btree_opc == InvalidOid) if (OidIsValid(opclass))
{ {
if (typentry->hash_opc == InvalidOid) typentry->btree_opf = get_opclass_family(opclass);
typentry->hash_opc = GetDefaultOpClass(type_id, typentry->btree_opintype = get_opclass_input_type(opclass);
HASH_AM_OID); }
/* 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 else
{ {
@ -193,37 +206,42 @@ lookup_type_cache(Oid type_id, int flags)
if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) && if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
typentry->eq_opr == InvalidOid) typentry->eq_opr == InvalidOid)
{ {
if (typentry->btree_opc != InvalidOid) if (typentry->btree_opf != InvalidOid)
typentry->eq_opr = get_opclass_member(typentry->btree_opc, typentry->eq_opr = get_opfamily_member(typentry->btree_opf,
InvalidOid, typentry->btree_opintype,
BTEqualStrategyNumber); typentry->btree_opintype,
BTEqualStrategyNumber);
if (typentry->eq_opr == InvalidOid && if (typentry->eq_opr == InvalidOid &&
typentry->hash_opc != InvalidOid) typentry->hash_opf != InvalidOid)
typentry->eq_opr = get_opclass_member(typentry->hash_opc, typentry->eq_opr = get_opfamily_member(typentry->hash_opf,
InvalidOid, typentry->hash_opintype,
HTEqualStrategyNumber); typentry->hash_opintype,
HTEqualStrategyNumber);
} }
if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid) if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
{ {
if (typentry->btree_opc != InvalidOid) if (typentry->btree_opf != InvalidOid)
typentry->lt_opr = get_opclass_member(typentry->btree_opc, typentry->lt_opr = get_opfamily_member(typentry->btree_opf,
InvalidOid, typentry->btree_opintype,
BTLessStrategyNumber); typentry->btree_opintype,
BTLessStrategyNumber);
} }
if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid) if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
{ {
if (typentry->btree_opc != InvalidOid) if (typentry->btree_opf != InvalidOid)
typentry->gt_opr = get_opclass_member(typentry->btree_opc, typentry->gt_opr = get_opfamily_member(typentry->btree_opf,
InvalidOid, typentry->btree_opintype,
BTGreaterStrategyNumber); typentry->btree_opintype,
BTGreaterStrategyNumber);
} }
if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) && if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
typentry->cmp_proc == InvalidOid) typentry->cmp_proc == InvalidOid)
{ {
if (typentry->btree_opc != InvalidOid) if (typentry->btree_opf != InvalidOid)
typentry->cmp_proc = get_opclass_proc(typentry->btree_opc, typentry->cmp_proc = get_opfamily_proc(typentry->btree_opf,
InvalidOid, typentry->btree_opintype,
BTORDER_PROC); typentry->btree_opintype,
BTORDER_PROC);
} }
/* /*

View File

@ -91,7 +91,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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; int i;
HeapTuple tuple; HeapTuple tuple;
Form_pg_operator optup; 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 "<" * Search pg_amop to see if the target operator is registered as a "<"
* or ">" operator of any btree opclass. It's possible that it might be * 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" * 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 * opfamily); prefer the "<" case if so. If the operator is registered the
* registered the same way in multiple opclasses, assume we can use the * same way in multiple opfamilies, assume we can use the associated
* associated comparator function from any one. * comparator function from any one.
*/ */
catlist = SearchSysCacheList(AMOPOPID, 1, catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(sortOperator), ObjectIdGetDatum(sortOperator),
@ -2125,21 +2126,24 @@ SelectSortFunction(Oid sortOperator,
tuple = &catlist->members[i]->tuple; tuple = &catlist->members[i]->tuple;
aform = (Form_pg_amop) GETSTRUCT(tuple); aform = (Form_pg_amop) GETSTRUCT(tuple);
if (!opclass_is_btree(aform->amopclaid)) /* must be btree */
if (aform->amopmethod != BTREE_AM_OID)
continue; continue;
/* must be of default subtype, too */ /* mustn't be cross-datatype, either */
if (aform->amopsubtype != InvalidOid) if (aform->amoplefttype != aform->amoprighttype)
continue; continue;
if (aform->amopstrategy == BTLessStrategyNumber) if (aform->amopstrategy == BTLessStrategyNumber)
{ {
opclass = aform->amopclaid; opfamily = aform->amopfamily;
opinputtype = aform->amoplefttype;
*kind = SORTFUNC_CMP; *kind = SORTFUNC_CMP;
break; /* done looking */ break; /* done looking */
} }
else if (aform->amopstrategy == BTGreaterStrategyNumber) else if (aform->amopstrategy == BTGreaterStrategyNumber)
{ {
opclass = aform->amopclaid; opfamily = aform->amopfamily;
opinputtype = aform->amoplefttype;
*kind = SORTFUNC_REVCMP; *kind = SORTFUNC_REVCMP;
/* keep scanning in hopes of finding a BTLess entry */ /* keep scanning in hopes of finding a BTLess entry */
} }
@ -2147,10 +2151,13 @@ SelectSortFunction(Oid sortOperator,
ReleaseSysCacheList(catlist); ReleaseSysCacheList(catlist);
if (OidIsValid(opclass)) if (OidIsValid(opfamily))
{ {
/* Found a suitable opclass, get its default comparator function */ /* Found a suitable opfamily, get the matching comparator function */
*sortFunction = get_opclass_proc(opclass, InvalidOid, BTORDER_PROC); *sortFunction = get_opfamily_proc(opfamily,
opinputtype,
opinputtype,
BTORDER_PROC);
Assert(RegProcedureIsValid(*sortFunction)); Assert(RegProcedureIsValid(*sortFunction));
return; return;
} }

View File

@ -42,7 +42,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* Portions taken from FreeBSD. * 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. * dependencies seems hard.
* *
* Note that we deliberately do not pin the system views, which * 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 * First delete any already-made entries; PINs override all else, and
* must be the only entries for their objects. * 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' " "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_opclass;\n", " FROM pg_opclass;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' " "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", " FROM pg_rewrite;\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' " "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_trigger;\n", " FROM pg_trigger;\n",

View File

@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * 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_oprnegate;
int i_oprrest; int i_oprrest;
int i_oprjoin; int i_oprjoin;
int i_oprcanmerge;
int i_oprcanhash; int i_oprcanhash;
int i_oprlsortop;
int i_oprrsortop;
int i_oprltcmpop;
int i_oprgtcmpop;
char *oprkind; char *oprkind;
char *oprcode; char *oprcode;
char *oprleft; char *oprleft;
@ -6232,11 +6229,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
char *oprnegate; char *oprnegate;
char *oprrest; char *oprrest;
char *oprjoin; char *oprjoin;
char *oprcanmerge;
char *oprcanhash; char *oprcanhash;
char *oprlsortop;
char *oprrsortop;
char *oprltcmpop;
char *oprgtcmpop;
/* Skip if not to be dumped */ /* Skip if not to be dumped */
if (!oprinfo->dobj.dump || dataOnly) 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 */ /* Make sure we are in proper schema so regoperator works correctly */
selectSourceSchema(oprinfo->dobj.namespace->dobj.name); selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
if (g_fout->remoteVersion >= 70300) if (g_fout->remoteVersion >= 80300)
{ {
appendPQExpBuffer(query, "SELECT oprkind, " appendPQExpBuffer(query, "SELECT oprkind, "
"oprcode::pg_catalog.regprocedure, " "oprcode::pg_catalog.regprocedure, "
@ -6268,11 +6262,23 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
"oprnegate::pg_catalog.regoperator, " "oprnegate::pg_catalog.regoperator, "
"oprrest::pg_catalog.regprocedure, " "oprrest::pg_catalog.regprocedure, "
"oprjoin::pg_catalog.regprocedure, " "oprjoin::pg_catalog.regprocedure, "
"oprcanhash, " "oprcanmerge, oprcanhash "
"oprlsortop::pg_catalog.regoperator, " "from pg_catalog.pg_operator "
"oprrsortop::pg_catalog.regoperator, " "where oid = '%u'::pg_catalog.oid",
"oprltcmpop::pg_catalog.regoperator, " oprinfo->dobj.catId.oid);
"oprgtcmpop::pg_catalog.regoperator " }
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 " "from pg_catalog.pg_operator "
"where oid = '%u'::pg_catalog.oid", "where oid = '%u'::pg_catalog.oid",
oprinfo->dobj.catId.oid); oprinfo->dobj.catId.oid);
@ -6285,8 +6291,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
"CASE WHEN oprright = 0 THEN '-' " "CASE WHEN oprright = 0 THEN '-' "
"ELSE format_type(oprright, NULL) END as oprright, " "ELSE format_type(oprright, NULL) END as oprright, "
"oprcom, oprnegate, oprrest, oprjoin, " "oprcom, oprnegate, oprrest, oprjoin, "
"oprcanhash, oprlsortop, oprrsortop, " "(oprlsortop != 0) as oprcanmerge, "
"0 as oprltcmpop, 0 as oprgtcmpop " "oprcanhash "
"from pg_operator " "from pg_operator "
"where oid = '%u'::oid", "where oid = '%u'::oid",
oprinfo->dobj.catId.oid); oprinfo->dobj.catId.oid);
@ -6299,8 +6305,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
"CASE WHEN oprright = 0 THEN '-'::name " "CASE WHEN oprright = 0 THEN '-'::name "
"ELSE (select typname from pg_type where oid = oprright) END as oprright, " "ELSE (select typname from pg_type where oid = oprright) END as oprright, "
"oprcom, oprnegate, oprrest, oprjoin, " "oprcom, oprnegate, oprrest, oprjoin, "
"oprcanhash, oprlsortop, oprrsortop, " "(oprlsortop != 0) as oprcanmerge, "
"0 as oprltcmpop, 0 as oprgtcmpop " "oprcanhash "
"from pg_operator " "from pg_operator "
"where oid = '%u'::oid", "where oid = '%u'::oid",
oprinfo->dobj.catId.oid); oprinfo->dobj.catId.oid);
@ -6326,11 +6332,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
i_oprnegate = PQfnumber(res, "oprnegate"); i_oprnegate = PQfnumber(res, "oprnegate");
i_oprrest = PQfnumber(res, "oprrest"); i_oprrest = PQfnumber(res, "oprrest");
i_oprjoin = PQfnumber(res, "oprjoin"); i_oprjoin = PQfnumber(res, "oprjoin");
i_oprcanmerge = PQfnumber(res, "oprcanmerge");
i_oprcanhash = PQfnumber(res, "oprcanhash"); 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); oprkind = PQgetvalue(res, 0, i_oprkind);
oprcode = PQgetvalue(res, 0, i_oprcode); oprcode = PQgetvalue(res, 0, i_oprcode);
@ -6340,11 +6343,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
oprnegate = PQgetvalue(res, 0, i_oprnegate); oprnegate = PQgetvalue(res, 0, i_oprnegate);
oprrest = PQgetvalue(res, 0, i_oprrest); oprrest = PQgetvalue(res, 0, i_oprrest);
oprjoin = PQgetvalue(res, 0, i_oprjoin); oprjoin = PQgetvalue(res, 0, i_oprjoin);
oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
oprcanhash = PQgetvalue(res, 0, i_oprcanhash); 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", appendPQExpBuffer(details, " PROCEDURE = %s",
convertRegProcReference(oprcode)); convertRegProcReference(oprcode));
@ -6390,6 +6390,9 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
if (name) if (name)
appendPQExpBuffer(details, ",\n NEGATOR = %s", name); appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
if (strcmp(oprcanmerge, "t") == 0)
appendPQExpBuffer(details, ",\n MERGES");
if (strcmp(oprcanhash, "t") == 0) if (strcmp(oprcanhash, "t") == 0)
appendPQExpBuffer(details, ",\n HASHES"); appendPQExpBuffer(details, ",\n HASHES");
@ -6401,22 +6404,6 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
if (name) if (name)
appendPQExpBuffer(details, ",\n JOIN = %s", 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 * 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); selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
/* Get additional fields from the pg_opclass row */ /* Get additional fields from the pg_opclass row */
appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, " if (g_fout->remoteVersion >= 80300)
"opckeytype::pg_catalog.regtype, " {
"opcdefault, " appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname " "opckeytype::pg_catalog.regtype, "
"FROM pg_catalog.pg_opclass " "opcdefault, "
"WHERE oid = '%u'::pg_catalog.oid", "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
opcinfo->dobj.catId.oid); "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); res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@ -6674,12 +6674,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
*/ */
resetPQExpBuffer(query); resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, " if (g_fout->remoteVersion >= 80300)
"amopopr::pg_catalog.regoperator " {
"FROM pg_catalog.pg_amop " /*
"WHERE amopclaid = '%u'::pg_catalog.oid " * Print only those opfamily members that are tied to the opclass
"ORDER BY amopstrategy", * by pg_depend entries.
opcinfo->dobj.catId.oid); */
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); res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@ -6714,12 +6733,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
*/ */
resetPQExpBuffer(query); resetPQExpBuffer(query);
appendPQExpBuffer(query, "SELECT amprocnum, " if (g_fout->remoteVersion >= 80300)
"amproc::pg_catalog.regprocedure " {
"FROM pg_catalog.pg_amproc " /*
"WHERE amopclaid = '%u'::pg_catalog.oid " * Print only those opfamily members that are tied to the opclass
"ORDER BY amprocnum", * by pg_depend entries.
opcinfo->dobj.catId.oid); */
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); res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); 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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200612201 #define CATALOG_VERSION_NO 200612221
#endif #endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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_LANGUAGE, /* pg_language */
OCLASS_OPERATOR, /* pg_operator */ OCLASS_OPERATOR, /* pg_operator */
OCLASS_OPCLASS, /* pg_opclass */ OCLASS_OPCLASS, /* pg_opclass */
OCLASS_OPFAMILY, /* pg_opfamily */
OCLASS_AMOP, /* pg_amop */
OCLASS_AMPROC, /* pg_amproc */
OCLASS_REWRITE, /* pg_rewrite */ OCLASS_REWRITE, /* pg_rewrite */
OCLASS_TRIGGER, /* pg_trigger */ OCLASS_TRIGGER, /* pg_trigger */
OCLASS_SCHEMA, /* pg_namespace */ OCLASS_SCHEMA, /* pg_namespace */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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)); DECLARE_UNIQUE_INDEX(pg_am_oid_index, 2652, on pg_am using btree(oid oid_ops));
#define AmOidIndexId 2652 #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 #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 #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 #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)); DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops));
#define AttrDefaultIndexId 2656 #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)); DECLARE_UNIQUE_INDEX(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops));
#define NamespaceOidIndexId 2685 #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 #define OpclassAmNameNspIndexId 2686
DECLARE_UNIQUE_INDEX(pg_opclass_oid_index, 2687, on pg_opclass using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_opclass_oid_index, 2687, on pg_opclass using btree(oid oid_ops));
#define OpclassOidIndexId 2687 #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)); 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 #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)); DECLARE_UNIQUE_INDEX(pg_pltemplate_name_index, 1137, on pg_pltemplate using btree(tmplname name_ops));
#define PLTemplateNameIndexId 1137 #define PLTemplateNameIndexId 1137

View File

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

View File

@ -4,16 +4,17 @@
* definition of the system "opclass" relation (pg_opclass) * definition of the system "opclass" relation (pg_opclass)
* along with the relation's initial contents. * along with the relation's initial contents.
* *
* New definition for Postgres 7.2: the primary key for this table is * The primary key for this table is <opcmethod, opcname, opcnamespace> ---
* <opcamid, opcname> --- that is, there is a row for each valid combination * that is, there is a row for each valid combination of opclass name and
* of opclass name and index access method type. This row specifies the * index access method type. This row specifies the expected input data type
* expected input data type for the opclass (the type of the heap column, * for the opclass (the type of the heap column, or the expression output type
* or the expression output type in the case of an index expression). Note * in the case of an index expression). Note that types binary-coercible to
* that types binary-coercible to the specified type will be accepted too. * 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 * 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 * Normally opckeytype = InvalidOid (zero), indicating that the data stored
* in the index is the same as the data in the indexed column. If opckeytype * 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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -54,10 +55,11 @@
CATALOG(pg_opclass,2616) 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 */ NameData opcname; /* name of this opclass */
Oid opcnamespace; /* namespace of this opclass */ Oid opcnamespace; /* namespace of this opclass */
Oid opcowner; /* opclass owner */ Oid opcowner; /* opclass owner */
Oid opcfamily; /* containing operator family */
Oid opcintype; /* type of data indexed by opclass */ Oid opcintype; /* type of data indexed by opclass */
bool opcdefault; /* T if opclass is default for opcintype */ bool opcdefault; /* T if opclass is default for opcintype */
Oid opckeytype; /* type of data in index, or InvalidOid */ 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 * compiler constants for pg_opclass
* ---------------- * ----------------
*/ */
#define Natts_pg_opclass 7 #define Natts_pg_opclass 8
#define Anum_pg_opclass_opcamid 1 #define Anum_pg_opclass_opcmethod 1
#define Anum_pg_opclass_opcname 2 #define Anum_pg_opclass_opcname 2
#define Anum_pg_opclass_opcnamespace 3 #define Anum_pg_opclass_opcnamespace 3
#define Anum_pg_opclass_opcowner 4 #define Anum_pg_opclass_opcowner 4
#define Anum_pg_opclass_opcintype 5 #define Anum_pg_opclass_opcfamily 5
#define Anum_pg_opclass_opcdefault 6 #define Anum_pg_opclass_opcintype 6
#define Anum_pg_opclass_opckeytype 7 #define Anum_pg_opclass_opcdefault 7
#define Anum_pg_opclass_opckeytype 8
/* ---------------- /* ----------------
* initial contents of pg_opclass * 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 ( 403 abstime_ops PGNSP PGUID 421 702 t 0 ));
DATA(insert OID = 397 ( 403 array_ops PGNSP PGUID 2277 t 0 )); DATA(insert ( 403 array_ops PGNSP PGUID 397 2277 t 0 ));
#define ARRAY_BTREE_OPS_OID 397 DATA(insert ( 403 bit_ops PGNSP PGUID 423 1560 t 0 ));
DATA(insert OID = 423 ( 403 bit_ops PGNSP PGUID 1560 t 0 )); DATA(insert ( 403 bool_ops PGNSP PGUID 424 16 t 0 ));
DATA(insert OID = 424 ( 403 bool_ops PGNSP PGUID 16 t 0 )); DATA(insert ( 403 bpchar_ops PGNSP PGUID 426 1042 t 0 ));
#define BOOL_BTREE_OPS_OID 424 DATA(insert ( 405 bpchar_ops PGNSP PGUID 427 1042 t 0 ));
DATA(insert OID = 426 ( 403 bpchar_ops PGNSP PGUID 1042 t 0 )); DATA(insert ( 403 bytea_ops PGNSP PGUID 428 17 t 0 ));
#define BPCHAR_BTREE_OPS_OID 426 DATA(insert ( 403 char_ops PGNSP PGUID 429 18 t 0 ));
DATA(insert OID = 427 ( 405 bpchar_ops PGNSP PGUID 1042 t 0 )); DATA(insert ( 405 char_ops PGNSP PGUID 431 18 t 0 ));
DATA(insert OID = 428 ( 403 bytea_ops PGNSP PGUID 17 t 0 )); DATA(insert ( 403 cidr_ops PGNSP PGUID 1974 869 f 0 ));
#define BYTEA_BTREE_OPS_OID 428 DATA(insert ( 405 cidr_ops PGNSP PGUID 1975 869 f 0 ));
DATA(insert OID = 429 ( 403 char_ops PGNSP PGUID 18 t 0 )); DATA(insert ( 403 date_ops PGNSP PGUID 434 1082 t 0 ));
DATA(insert OID = 431 ( 405 char_ops PGNSP PGUID 18 t 0 )); DATA(insert ( 405 date_ops PGNSP PGUID 435 1082 t 0 ));
DATA(insert OID = 432 ( 403 cidr_ops PGNSP PGUID 650 t 0 )); DATA(insert ( 403 float4_ops PGNSP PGUID 1970 700 t 0 ));
#define CIDR_BTREE_OPS_OID 432 DATA(insert ( 405 float4_ops PGNSP PGUID 1971 700 t 0 ));
DATA(insert OID = 433 ( 405 cidr_ops PGNSP PGUID 650 t 0 )); DATA(insert ( 403 float8_ops PGNSP PGUID 1970 701 t 0 ));
DATA(insert OID = 434 ( 403 date_ops PGNSP PGUID 1082 t 0 )); DATA(insert ( 405 float8_ops PGNSP PGUID 1971 701 t 0 ));
DATA(insert OID = 435 ( 405 date_ops PGNSP PGUID 1082 t 0 )); DATA(insert ( 403 inet_ops PGNSP PGUID 1974 869 t 0 ));
DATA(insert OID = 1970 ( 403 float4_ops PGNSP PGUID 700 t 0 )); DATA(insert ( 405 inet_ops PGNSP PGUID 1975 869 t 0 ));
DATA(insert OID = 1971 ( 405 float4_ops PGNSP PGUID 700 t 0 )); DATA(insert OID = 1979 ( 403 int2_ops PGNSP PGUID 1976 21 t 0 ));
DATA(insert OID = 1972 ( 403 float8_ops PGNSP PGUID 701 t 0 )); #define INT2_BTREE_OPS_OID 1979
DATA(insert OID = 1973 ( 405 float8_ops PGNSP PGUID 701 t 0 )); DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 ));
DATA(insert OID = 1974 ( 403 inet_ops PGNSP PGUID 869 t 0 )); DATA(insert OID = 1978 ( 403 int4_ops PGNSP PGUID 1976 23 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 ));
#define INT4_BTREE_OPS_OID 1978 #define INT4_BTREE_OPS_OID 1978
DATA(insert OID = 1979 ( 405 int4_ops PGNSP PGUID 23 t 0 )); DATA(insert ( 405 int4_ops PGNSP PGUID 1977 23 t 0 ));
DATA(insert OID = 1980 ( 403 int8_ops PGNSP PGUID 20 t 0 )); DATA(insert ( 403 int8_ops PGNSP PGUID 1976 20 t 0 ));
DATA(insert OID = 1981 ( 405 int8_ops PGNSP PGUID 20 t 0 )); DATA(insert ( 405 int8_ops PGNSP PGUID 1977 20 t 0 ));
DATA(insert OID = 1982 ( 403 interval_ops PGNSP PGUID 1186 t 0 )); DATA(insert ( 403 interval_ops PGNSP PGUID 1982 1186 t 0 ));
DATA(insert OID = 1983 ( 405 interval_ops PGNSP PGUID 1186 t 0 )); DATA(insert ( 405 interval_ops PGNSP PGUID 1983 1186 t 0 ));
DATA(insert OID = 1984 ( 403 macaddr_ops PGNSP PGUID 829 t 0 )); DATA(insert ( 403 macaddr_ops PGNSP PGUID 1984 829 t 0 ));
DATA(insert OID = 1985 ( 405 macaddr_ops PGNSP PGUID 829 t 0 )); DATA(insert ( 405 macaddr_ops PGNSP PGUID 1985 829 t 0 ));
DATA(insert OID = 1986 ( 403 name_ops PGNSP PGUID 19 t 0 )); DATA(insert ( 403 name_ops PGNSP PGUID 1986 19 t 0 ));
#define NAME_BTREE_OPS_OID 1986 DATA(insert ( 405 name_ops PGNSP PGUID 1987 19 t 0 ));
DATA(insert OID = 1987 ( 405 name_ops PGNSP PGUID 19 t 0 )); DATA(insert ( 403 numeric_ops PGNSP PGUID 1988 1700 t 0 ));
DATA(insert OID = 1988 ( 403 numeric_ops PGNSP PGUID 1700 t 0 )); DATA(insert OID = 1981 ( 403 oid_ops PGNSP PGUID 1989 26 t 0 ));
DATA(insert OID = 1989 ( 403 oid_ops PGNSP PGUID 26 t 0 )); #define OID_BTREE_OPS_OID 1981
#define OID_BTREE_OPS_OID 1989 DATA(insert ( 405 oid_ops PGNSP PGUID 1990 26 t 0 ));
DATA(insert OID = 1990 ( 405 oid_ops PGNSP PGUID 26 t 0 )); DATA(insert ( 403 oidvector_ops PGNSP PGUID 1991 30 t 0 ));
DATA(insert OID = 1991 ( 403 oidvector_ops PGNSP PGUID 30 t 0 )); DATA(insert ( 405 oidvector_ops PGNSP PGUID 1992 30 t 0 ));
DATA(insert OID = 1992 ( 405 oidvector_ops PGNSP PGUID 30 t 0 )); DATA(insert ( 403 text_ops PGNSP PGUID 1994 25 t 0 ));
DATA(insert OID = 1994 ( 403 text_ops PGNSP PGUID 25 t 0 )); DATA(insert ( 405 text_ops PGNSP PGUID 1995 25 t 0 ));
#define TEXT_BTREE_OPS_OID 1994 DATA(insert ( 403 time_ops PGNSP PGUID 1996 1083 t 0 ));
DATA(insert OID = 1995 ( 405 text_ops PGNSP PGUID 25 t 0 )); DATA(insert ( 405 time_ops PGNSP PGUID 1997 1083 t 0 ));
DATA(insert OID = 1996 ( 403 time_ops PGNSP PGUID 1083 t 0 )); DATA(insert ( 403 timestamptz_ops PGNSP PGUID 434 1184 t 0 ));
DATA(insert OID = 1997 ( 405 time_ops PGNSP PGUID 1083 t 0 )); DATA(insert ( 405 timestamptz_ops PGNSP PGUID 1999 1184 t 0 ));
DATA(insert OID = 1998 ( 403 timestamptz_ops PGNSP PGUID 1184 t 0 )); DATA(insert ( 403 timetz_ops PGNSP PGUID 2000 1266 t 0 ));
DATA(insert OID = 1999 ( 405 timestamptz_ops PGNSP PGUID 1184 t 0 )); DATA(insert ( 405 timetz_ops PGNSP PGUID 2001 1266 t 0 ));
DATA(insert OID = 2000 ( 403 timetz_ops PGNSP PGUID 1266 t 0 )); DATA(insert ( 403 varbit_ops PGNSP PGUID 2002 1562 t 0 ));
DATA(insert OID = 2001 ( 405 timetz_ops PGNSP PGUID 1266 t 0 )); DATA(insert ( 403 varchar_ops PGNSP PGUID 1994 25 f 0 ));
DATA(insert OID = 2002 ( 403 varbit_ops PGNSP PGUID 1562 t 0 )); DATA(insert ( 405 varchar_ops PGNSP PGUID 1995 25 f 0 ));
DATA(insert OID = 2003 ( 403 varchar_ops PGNSP PGUID 1043 t 0 )); DATA(insert ( 403 timestamp_ops PGNSP PGUID 434 1114 t 0 ));
#define VARCHAR_BTREE_OPS_OID 2003 DATA(insert ( 405 timestamp_ops PGNSP PGUID 2040 1114 t 0 ));
DATA(insert OID = 2004 ( 405 varchar_ops PGNSP PGUID 1043 t 0 )); DATA(insert ( 403 text_pattern_ops PGNSP PGUID 2095 25 f 0 ));
DATA(insert OID = 2039 ( 403 timestamp_ops PGNSP PGUID 1114 t 0 )); DATA(insert ( 403 varchar_pattern_ops PGNSP PGUID 2095 25 f 0 ));
DATA(insert OID = 2040 ( 405 timestamp_ops PGNSP PGUID 1114 t 0 )); DATA(insert ( 403 bpchar_pattern_ops PGNSP PGUID 2097 1042 f 0 ));
DATA(insert OID = 2095 ( 403 text_pattern_ops PGNSP PGUID 25 f 0 )); DATA(insert ( 403 name_pattern_ops PGNSP PGUID 2098 19 f 0 ));
#define TEXT_PATTERN_BTREE_OPS_OID 2095 DATA(insert ( 403 money_ops PGNSP PGUID 2099 790 t 0 ));
DATA(insert OID = 2096 ( 403 varchar_pattern_ops PGNSP PGUID 1043 f 0 )); DATA(insert ( 405 bool_ops PGNSP PGUID 2222 16 t 0 ));
#define VARCHAR_PATTERN_BTREE_OPS_OID 2096 DATA(insert ( 405 bytea_ops PGNSP PGUID 2223 17 t 0 ));
DATA(insert OID = 2097 ( 403 bpchar_pattern_ops PGNSP PGUID 1042 f 0 )); DATA(insert ( 405 int2vector_ops PGNSP PGUID 2224 22 t 0 ));
#define BPCHAR_PATTERN_BTREE_OPS_OID 2097 DATA(insert ( 403 tid_ops PGNSP PGUID 2789 27 t 0 ));
DATA(insert OID = 2098 ( 403 name_pattern_ops PGNSP PGUID 19 f 0 )); DATA(insert ( 405 xid_ops PGNSP PGUID 2225 28 t 0 ));
#define NAME_PATTERN_BTREE_OPS_OID 2098 DATA(insert ( 405 cid_ops PGNSP PGUID 2226 29 t 0 ));
DATA(insert OID = 2099 ( 403 money_ops PGNSP PGUID 790 t 0 )); DATA(insert ( 405 abstime_ops PGNSP PGUID 2227 702 t 0 ));
DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID 16 t 0 )); DATA(insert ( 405 reltime_ops PGNSP PGUID 2228 703 t 0 ));
#define BOOL_HASH_OPS_OID 2222 DATA(insert ( 405 text_pattern_ops PGNSP PGUID 2229 25 f 0 ));
DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID 17 t 0 )); DATA(insert ( 405 varchar_pattern_ops PGNSP PGUID 2229 25 f 0 ));
DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID 22 t 0 )); DATA(insert ( 405 bpchar_pattern_ops PGNSP PGUID 2231 1042 f 0 ));
DATA(insert OID = 2789 ( 403 tid_ops PGNSP PGUID 27 t 0 )); DATA(insert ( 405 name_pattern_ops PGNSP PGUID 2232 19 f 0 ));
DATA(insert OID = 2225 ( 405 xid_ops PGNSP PGUID 28 t 0 )); DATA(insert ( 403 reltime_ops PGNSP PGUID 2233 703 t 0 ));
DATA(insert OID = 2226 ( 405 cid_ops PGNSP PGUID 29 t 0 )); DATA(insert ( 403 tinterval_ops PGNSP PGUID 2234 704 t 0 ));
DATA(insert OID = 2227 ( 405 abstime_ops PGNSP PGUID 702 t 0 )); DATA(insert ( 405 aclitem_ops PGNSP PGUID 2235 1033 t 0 ));
DATA(insert OID = 2228 ( 405 reltime_ops PGNSP PGUID 703 t 0 )); DATA(insert ( 783 box_ops PGNSP PGUID 2593 603 t 0 ));
DATA(insert OID = 2229 ( 405 text_pattern_ops PGNSP PGUID 25 f 0 )); DATA(insert ( 783 poly_ops PGNSP PGUID 2594 604 t 603 ));
DATA(insert OID = 2230 ( 405 varchar_pattern_ops PGNSP PGUID 1043 f 0 )); DATA(insert ( 783 circle_ops PGNSP PGUID 2595 718 t 603 ));
DATA(insert OID = 2231 ( 405 bpchar_pattern_ops PGNSP PGUID 1042 f 0 )); DATA(insert ( 2742 _int4_ops PGNSP PGUID 2745 1007 t 23 ));
DATA(insert OID = 2232 ( 405 name_pattern_ops PGNSP PGUID 19 f 0 )); DATA(insert ( 2742 _text_ops PGNSP PGUID 2745 1009 t 25 ));
DATA(insert OID = 2233 ( 403 reltime_ops PGNSP PGUID 703 t 0 )); DATA(insert ( 2742 _abstime_ops PGNSP PGUID 2745 1023 t 702 ));
DATA(insert OID = 2234 ( 403 tinterval_ops PGNSP PGUID 704 t 0 )); DATA(insert ( 2742 _bit_ops PGNSP PGUID 2745 1561 t 1560 ));
DATA(insert OID = 2235 ( 405 aclitem_ops PGNSP PGUID 1033 t 0 )); DATA(insert ( 2742 _bool_ops PGNSP PGUID 2745 1000 t 16 ));
DATA(insert OID = 2593 ( 783 box_ops PGNSP PGUID 603 t 0 )); DATA(insert ( 2742 _bpchar_ops PGNSP PGUID 2745 1014 t 1042 ));
DATA(insert OID = 2594 ( 783 poly_ops PGNSP PGUID 604 t 603 )); DATA(insert ( 2742 _bytea_ops PGNSP PGUID 2745 1001 t 17 ));
DATA(insert OID = 2595 ( 783 circle_ops PGNSP PGUID 718 t 603 )); DATA(insert ( 2742 _char_ops PGNSP PGUID 2745 1002 t 18 ));
DATA(insert OID = 2745 ( 2742 _int4_ops PGNSP PGUID 1007 t 23 )); DATA(insert ( 2742 _cidr_ops PGNSP PGUID 2745 651 t 650 ));
DATA(insert OID = 2746 ( 2742 _text_ops PGNSP PGUID 1009 t 25 )); DATA(insert ( 2742 _date_ops PGNSP PGUID 2745 1182 t 1082 ));
DATA(insert OID = 2753 ( 2742 _abstime_ops PGNSP PGUID 1023 t 702 )); DATA(insert ( 2742 _float4_ops PGNSP PGUID 2745 1021 t 700 ));
DATA(insert OID = 2754 ( 2742 _bit_ops PGNSP PGUID 1561 t 1560 )); DATA(insert ( 2742 _float8_ops PGNSP PGUID 2745 1022 t 701 ));
DATA(insert OID = 2755 ( 2742 _bool_ops PGNSP PGUID 1000 t 16 )); DATA(insert ( 2742 _inet_ops PGNSP PGUID 2745 1041 t 869 ));
DATA(insert OID = 2756 ( 2742 _bpchar_ops PGNSP PGUID 1014 t 1042 )); DATA(insert ( 2742 _int2_ops PGNSP PGUID 2745 1005 t 21 ));
DATA(insert OID = 2757 ( 2742 _bytea_ops PGNSP PGUID 1001 t 17 )); DATA(insert ( 2742 _int8_ops PGNSP PGUID 2745 1016 t 20 ));
DATA(insert OID = 2758 ( 2742 _char_ops PGNSP PGUID 1002 t 18 )); DATA(insert ( 2742 _interval_ops PGNSP PGUID 2745 1187 t 1186 ));
DATA(insert OID = 2759 ( 2742 _cidr_ops PGNSP PGUID 651 t 650 )); DATA(insert ( 2742 _macaddr_ops PGNSP PGUID 2745 1040 t 829 ));
DATA(insert OID = 2760 ( 2742 _date_ops PGNSP PGUID 1182 t 1082 )); DATA(insert ( 2742 _name_ops PGNSP PGUID 2745 1003 t 19 ));
DATA(insert OID = 2761 ( 2742 _float4_ops PGNSP PGUID 1021 t 700 )); DATA(insert ( 2742 _numeric_ops PGNSP PGUID 2745 1231 t 1700 ));
DATA(insert OID = 2762 ( 2742 _float8_ops PGNSP PGUID 1022 t 701 )); DATA(insert ( 2742 _oid_ops PGNSP PGUID 2745 1028 t 26 ));
DATA(insert OID = 2763 ( 2742 _inet_ops PGNSP PGUID 1041 t 869 )); DATA(insert ( 2742 _oidvector_ops PGNSP PGUID 2745 1013 t 30 ));
DATA(insert OID = 2764 ( 2742 _int2_ops PGNSP PGUID 1005 t 21 )); DATA(insert ( 2742 _time_ops PGNSP PGUID 2745 1183 t 1083 ));
DATA(insert OID = 2765 ( 2742 _int8_ops PGNSP PGUID 1016 t 20 )); DATA(insert ( 2742 _timestamptz_ops PGNSP PGUID 2745 1185 t 1184 ));
DATA(insert OID = 2766 ( 2742 _interval_ops PGNSP PGUID 1187 t 1186 )); DATA(insert ( 2742 _timetz_ops PGNSP PGUID 2745 1270 t 1266 ));
DATA(insert OID = 2767 ( 2742 _macaddr_ops PGNSP PGUID 1040 t 829 )); DATA(insert ( 2742 _varbit_ops PGNSP PGUID 2745 1563 t 1562 ));
DATA(insert OID = 2768 ( 2742 _name_ops PGNSP PGUID 1003 t 19 )); DATA(insert ( 2742 _varchar_ops PGNSP PGUID 2745 1015 t 1043 ));
DATA(insert OID = 2769 ( 2742 _numeric_ops PGNSP PGUID 1231 t 1700 )); DATA(insert ( 2742 _timestamp_ops PGNSP PGUID 2745 1115 t 1114 ));
DATA(insert OID = 2770 ( 2742 _oid_ops PGNSP PGUID 1028 t 26 )); DATA(insert ( 2742 _money_ops PGNSP PGUID 2745 791 t 790 ));
DATA(insert OID = 2771 ( 2742 _oidvector_ops PGNSP PGUID 1013 t 30 )); DATA(insert ( 2742 _reltime_ops PGNSP PGUID 2745 1024 t 703 ));
DATA(insert OID = 2772 ( 2742 _time_ops PGNSP PGUID 1183 t 1083 )); DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 ));
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 ));
#endif /* PG_OPCLASS_H */ #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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 DefineOpClass(CreateOpClassStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt); extern void RemoveOpClass(RemoveOpClassStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid); 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 RenameOpClass(List *name, const char *access_method, const char *newname);
extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId); 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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; NodeTag type;
List *opclassname; /* qualified name (list of Value strings) */ 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 */ char *amname; /* name of index AM opclass is for */
TypeName *datatype; /* datatype of indexed column */ TypeName *datatype; /* datatype of indexed column */
List *items; /* List of CreateOpClassItem nodes */ List *items; /* List of CreateOpClassItem nodes */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 typedef struct MergeJoin
{ {
Join join; 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; } MergeJoin;
/* ---------------- /* ----------------

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * We support row comparison for any operator that can be determined to
* act like =, <>, <, <=, >, or >= (we determine this by looking for the * 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 * map to a different operator for each pair of row elements, since the
* element datatypes can vary. * element datatypes can vary.
* *
@ -679,7 +679,7 @@ typedef struct RowCompareExpr
Expr xpr; Expr xpr;
RowCompareType rctype; /* LT LE GE or GT, never EQ or NE */ RowCompareType rctype; /* LT LE GE or GT, never EQ or NE */
List *opnos; /* OID list of pairwise comparison ops */ 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 *largs; /* the left-hand input arguments */
List *rargs; /* the right-hand input arguments */ List *rargs; /* the right-hand input arguments */
} RowCompareExpr; } RowCompareExpr;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * and indexes, but that created confusion without actually doing anything
* useful. So now we have a separate IndexOptInfo struct for indexes. * 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 * Zeroes in the indexkeys[] array indicate index columns that are
* expressions; there is one element in indexprs for each such column. * 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 * an extra entry that is always zero. Some code scans until it sees a
* zero entry, rather than looking at ncolumns. * zero entry, rather than looking at ncolumns.
* *
@ -326,7 +326,7 @@ typedef struct IndexOptInfo
/* index descriptor information */ /* index descriptor information */
int ncolumns; /* number of columns in index */ 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 */ int *indexkeys; /* column numbers of index's keys, or 0 */
Oid *ordering; /* OIDs of sort operators for each column */ Oid *ordering; /* OIDs of sort operators for each column */
Oid relam; /* OID of the access method (in pg_am) */ Oid relam; /* OID of the access method (in pg_am) */
@ -611,7 +611,9 @@ typedef JoinPath NestPath;
* A mergejoin path has these fields. * A mergejoin path has these fields.
* *
* path_mergeclauses lists the clauses (in the form of RestrictInfos) * 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 * Note that the mergeclauses are a subset of the parent relation's
* restriction-clause list. Any join clauses that are not mergejoinable * restriction-clause list. Any join clauses that are not mergejoinable
@ -628,6 +630,8 @@ typedef struct MergePath
{ {
JoinPath jpath; JoinPath jpath;
List *path_mergeclauses; /* join clauses to be used for merge */ 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 *outersortkeys; /* keys for explicit sort, if any */
List *innersortkeys; /* keys for explicit sort, if any */ List *innersortkeys; /* keys for explicit sort, if any */
} MergePath; } MergePath;
@ -780,6 +784,7 @@ typedef struct RestrictInfo
Oid mergejoinoperator; /* copy of clause operator */ Oid mergejoinoperator; /* copy of clause operator */
Oid left_sortop; /* leftside sortop needed for mergejoin */ Oid left_sortop; /* leftside sortop needed for mergejoin */
Oid right_sortop; /* rightside 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 */ /* cache space for mergeclause processing; NIL if not yet set */
List *left_pathkey; /* canonical pathkey for left side */ 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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 *restrict_clauses,
List *pathkeys, List *pathkeys,
List *mergeclauses, List *mergeclauses,
List *mergefamilies,
List *mergestrategies,
List *outersortkeys, List *outersortkeys,
List *innersortkeys); List *innersortkeys);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 IOFunc_send
} IOFuncSelector; } IOFuncSelector;
extern bool op_in_opclass(Oid opno, Oid opclass); extern bool op_in_opfamily(Oid opno, Oid opfamily);
extern int get_op_opclass_strategy(Oid opno, Oid opclass); extern int get_op_opfamily_strategy(Oid opno, Oid opfamily);
extern void get_op_opclass_properties(Oid opno, Oid opclass, extern void get_op_opfamily_properties(Oid opno, Oid opfamily,
int *strategy, Oid *subtype, int *strategy,
Oid *lefttype,
Oid *righttype,
bool *recheck); 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 Oid get_op_hash_function(Oid opno);
extern void get_op_btree_interpretation(Oid opno, extern void get_op_btree_interpretation(Oid opno,
List **opclasses, List **opstrats); List **opfamilies, List **opstrats);
extern Oid get_opclass_proc(Oid opclass, Oid subtype, int16 procnum); extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype,
int16 procnum);
extern char *get_attname(Oid relid, AttrNumber attnum); extern char *get_attname(Oid relid, AttrNumber attnum);
extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum); extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
extern AttrNumber get_attnum(Oid relid, const char *attname); 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 int32 get_atttypmod(Oid relid, AttrNumber attnum);
extern void get_atttypetypmod(Oid relid, AttrNumber attnum, extern void get_atttypetypmod(Oid relid, AttrNumber attnum,
Oid *typid, int32 *typmod); Oid *typid, int32 *typmod);
extern bool opclass_is_btree(Oid opclass); extern Oid get_opclass_family(Oid opclass);
extern bool opclass_is_hash(Oid opclass);
extern bool opclass_is_default(Oid opclass);
extern Oid get_opclass_input_type(Oid opclass); extern Oid get_opclass_input_type(Oid opclass);
extern RegProcedure get_opcode(Oid opno); extern RegProcedure get_opcode(Oid opno);
extern char *get_opname(Oid opno); extern char *get_opname(Oid opno);
extern void op_input_types(Oid opno, Oid *lefttype, Oid *righttype); extern void op_input_types(Oid opno, Oid *lefttype, Oid *righttype);
extern bool op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp); extern bool op_mergejoinable(Oid opno);
extern void op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
RegProcedure *ltproc, RegProcedure *gtproc);
extern bool op_hashjoinable(Oid opno); extern bool op_hashjoinable(Oid opno);
extern bool op_strict(Oid opno); extern bool op_strict(Oid opno);
extern char op_volatile(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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 */ Form_pg_index rd_index; /* pg_index tuple describing this index */
struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */
/* "struct HeapTupleData *" avoids need to include htup.h here */ /* "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 */ Form_pg_am rd_am; /* pg_am tuple for index's AM */
/* /*
* index access support info (used only for an index relation) * index access support info (used only for an index relation)
* *
* Note: only default operators and support procs for each opclass are * Note: only default operators and support procs for each opclass are
* cached, namely those with subtype zero. The arrays are indexed by * cached, namely those with lefttype and righttype equal to the opclass's
* strategy or support number, which is a sufficient identifier given that * opcintype. The arrays are indexed by strategy or support number,
* restriction. * which is a sufficient identifier given that restriction.
* *
* Note: rd_amcache is available for index AMs to cache private data about * 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 * 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 */ MemoryContext rd_indexcxt; /* private memory cxt for this stuff */
RelationAmInfo *rd_aminfo; /* lookup info for funcs found in pg_am */ 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 */ Oid *rd_operator; /* OIDs of index operators */
RegProcedure *rd_support; /* OIDs of support procedures */ RegProcedure *rd_support; /* OIDs of support procedures */
FmgrInfo *rd_supportinfo; /* lookup info for 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) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); int varRelid, JoinType jointype);
extern void mergejoinscansel(PlannerInfo *root, Node *clause, extern void mergejoinscansel(PlannerInfo *root, Node *clause,
Oid opfamily, int strategy,
Selectivity *leftscan, Selectivity *leftscan,
Selectivity *rightscan); Selectivity *rightscan);

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 CONOID 17
#define DATABASEOID 18 #define DATABASEOID 18
#define INDEXRELID 19 #define INDEXRELID 19
#define INHRELID 20 #define LANGNAME 20
#define LANGNAME 21 #define LANGOID 21
#define LANGOID 22 #define NAMESPACENAME 22
#define NAMESPACENAME 23 #define NAMESPACEOID 23
#define NAMESPACEOID 24 #define OPERNAMENSP 24
#define OPERNAMENSP 25 #define OPEROID 25
#define OPEROID 26 #define OPFAMILYAMNAMENSP 26
#define PROCNAMEARGSNSP 27 #define OPFAMILYOID 27
#define PROCOID 28 #define PROCNAMEARGSNSP 28
#define RELNAMENSP 29 #define PROCOID 29
#define RELOID 30 #define RELNAMENSP 30
#define RULERELNAME 31 #define RELOID 31
#define STATRELATT 32 #define RULERELNAME 32
#define TYPENAMENSP 33 #define STATRELATT 33
#define TYPEOID 34 #define TYPENAMENSP 34
#define TYPEOID 35
extern void InitCatalogCache(void); extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void); extern void InitCatalogCachePhase2(void);

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; 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 * These will be InvalidOid if no match could be found, or if the
* information hasn't yet been requested. * information hasn't yet been requested.
*/ */
Oid btree_opc; /* OID of the default btree opclass */ Oid btree_opf; /* the default btree opclass' family */
Oid hash_opc; /* OID of the default hash opclass */ Oid btree_opintype; /* the default btree opclass' opcintype */
Oid eq_opr; /* OID of the equality operator */ Oid hash_opf; /* the default hash opclass' family */
Oid lt_opr; /* OID of the less-than operator */ Oid hash_opintype; /* the default hash opclass' opcintype */
Oid gt_opr; /* OID of the greater-than operator */ Oid eq_opr; /* the equality operator */
Oid cmp_proc; /* OID of the btree comparison function */ 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 * 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_EQ_OPR_FINFO 0x0010
#define TYPECACHE_CMP_PROC_FINFO 0x0020 #define TYPECACHE_CMP_PROC_FINFO 0x0020
#define TYPECACHE_TUPDESC 0x0040 #define TYPECACHE_TUPDESC 0x0040
#define TYPECACHE_BTREE_OPFAMILY 0x0080
extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags); extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);

View File

@ -137,20 +137,36 @@ WHERE amcostestimate != 0 AND
------+---------------- ------+----------------
(0 rows) (0 rows)
SELECT ctid, amopclaid SELECT ctid, amoptions
FROM pg_catalog.pg_amop fk FROM pg_catalog.pg_am fk
WHERE amopclaid != 0 AND WHERE amoptions != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
ctid | amopclaid ctid | amoptions
------+----------- ------+-----------
(0 rows) (0 rows)
SELECT ctid, amopsubtype SELECT ctid, amopfamily
FROM pg_catalog.pg_amop fk FROM pg_catalog.pg_amop fk
WHERE amopsubtype != 0 AND WHERE amopfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amopsubtype); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
ctid | amopsubtype 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) (0 rows)
SELECT ctid, amopopr SELECT ctid, amopopr
@ -161,20 +177,36 @@ WHERE amopopr != 0 AND
------+--------- ------+---------
(0 rows) (0 rows)
SELECT ctid, amopclaid SELECT ctid, amopmethod
FROM pg_catalog.pg_amproc fk FROM pg_catalog.pg_amop fk
WHERE amopclaid != 0 AND WHERE amopmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.amopmethod);
ctid | amopclaid ctid | amopmethod
------+----------- ------+------------
(0 rows) (0 rows)
SELECT ctid, amprocsubtype SELECT ctid, amprocfamily
FROM pg_catalog.pg_amproc fk FROM pg_catalog.pg_amproc fk
WHERE amprocsubtype != 0 AND WHERE amprocfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocsubtype); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
ctid | amprocsubtype 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) (0 rows)
SELECT ctid, amproc SELECT ctid, amproc
@ -241,6 +273,14 @@ WHERE reltype != 0 AND
------+--------- ------+---------
(0 rows) (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 SELECT ctid, relam
FROM pg_catalog.pg_class fk FROM pg_catalog.pg_class fk
WHERE relam != 0 AND WHERE relam != 0 AND
@ -297,6 +337,14 @@ WHERE connamespace != 0 AND
------+-------------- ------+--------------
(0 rows) (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 SELECT ctid, conproc
FROM pg_catalog.pg_conversion fk FROM pg_catalog.pg_conversion fk
WHERE conproc != 0 AND WHERE conproc != 0 AND
@ -305,6 +353,14 @@ WHERE conproc != 0 AND
------+--------- ------+---------
(0 rows) (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 SELECT ctid, dattablespace
FROM pg_catalog.pg_database fk FROM pg_catalog.pg_database fk
WHERE dattablespace != 0 AND WHERE dattablespace != 0 AND
@ -361,12 +417,20 @@ WHERE lanvalidator != 0 AND
------+-------------- ------+--------------
(0 rows) (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 FROM pg_catalog.pg_opclass fk
WHERE opcamid != 0 AND WHERE opcmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcamid); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
ctid | opcamid ctid | opcmethod
------+--------- ------+-----------
(0 rows) (0 rows)
SELECT ctid, opcnamespace SELECT ctid, opcnamespace
@ -377,6 +441,22 @@ WHERE opcnamespace != 0 AND
------+-------------- ------+--------------
(0 rows) (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 SELECT ctid, opcintype
FROM pg_catalog.pg_opclass fk FROM pg_catalog.pg_opclass fk
WHERE opcintype != 0 AND WHERE opcintype != 0 AND
@ -385,6 +465,14 @@ WHERE opcintype != 0 AND
------+----------- ------+-----------
(0 rows) (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 SELECT ctid, oprnamespace
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprnamespace != 0 AND WHERE oprnamespace != 0 AND
@ -393,6 +481,14 @@ WHERE oprnamespace != 0 AND
------+-------------- ------+--------------
(0 rows) (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 SELECT ctid, oprleft
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprleft != 0 AND WHERE oprleft != 0 AND
@ -433,38 +529,6 @@ WHERE oprnegate != 0 AND
------+----------- ------+-----------
(0 rows) (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 SELECT ctid, oprcode
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprcode != 0 AND WHERE oprcode != 0 AND
@ -489,6 +553,30 @@ WHERE oprjoin != 0 AND
------+--------- ------+---------
(0 rows) (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 SELECT ctid, pronamespace
FROM pg_catalog.pg_proc fk FROM pg_catalog.pg_proc fk
WHERE pronamespace != 0 AND WHERE pronamespace != 0 AND
@ -497,6 +585,14 @@ WHERE pronamespace != 0 AND
------+-------------- ------+--------------
(0 rows) (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 SELECT ctid, prolang
FROM pg_catalog.pg_proc fk FROM pg_catalog.pg_proc fk
WHERE prolang != 0 AND WHERE prolang != 0 AND
@ -521,6 +617,22 @@ WHERE ev_class != 0 AND
------+---------- ------+----------
(0 rows) (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 SELECT ctid, starelid
FROM pg_catalog.pg_statistic fk FROM pg_catalog.pg_statistic fk
WHERE starelid != 0 AND WHERE starelid != 0 AND
@ -553,6 +665,14 @@ WHERE staop3 != 0 AND
------+-------- ------+--------
(0 rows) (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 SELECT ctid, tgrelid
FROM pg_catalog.pg_trigger fk FROM pg_catalog.pg_trigger fk
WHERE tgrelid != 0 AND WHERE tgrelid != 0 AND
@ -577,6 +697,14 @@ WHERE typnamespace != 0 AND
------+-------------- ------+--------------
(0 rows) (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 SELECT ctid, typrelid
FROM pg_catalog.pg_type fk FROM pg_catalog.pg_type fk
WHERE typrelid != 0 AND WHERE typrelid != 0 AND

View File

@ -1,7 +1,8 @@
-- --
-- OPR_SANITY -- OPR_SANITY
-- Sanity checks for common errors in making operator/procedure system tables: -- 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, -- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-). -- so the expected output is easy to maintain ;-).
@ -374,158 +375,58 @@ WHERE p1.oprnegate = p2.oid AND
-----+---------+-----+--------- -----+---------+-----+---------
(0 rows) (0 rows)
-- Look for mergejoin operators that don't match their links. -- A mergejoinable or hashjoinable operator must be binary, must return
-- An lsortop/rsortop link leads from an '=' operator to the -- boolean, and must have a commutator (itself, unless it's a cross-type
-- sort operator ('<' operator) that's appropriate for -- operator).
-- 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).
SELECT p1.oid, p1.oprname FROM pg_operator AS p1 SELECT p1.oid, p1.oprname FROM pg_operator AS p1
WHERE p1.oprlsortop != 0 AND WHERE (p1.oprcanmerge OR p1.oprcanhash) AND NOT
p1.oprcom = 0; (p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND p1.oprcom != 0);
oid | oprname oid | oprname
-----+--------- -----+---------
(0 rows) (0 rows)
-- Mergejoinable operators across datatypes must come in closed sets, that -- Mergejoinable operators should appear as equality members of btree index
-- is if you provide int2 = int4 and int4 = int8 then you must also provide -- opfamilies.
-- 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 "=".
SELECT p1.oid, p1.oprname SELECT p1.oid, p1.oprname
FROM pg_operator AS p1 FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT WHERE p1.oprcanmerge AND NOT EXISTS
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND (SELECT 1 FROM pg_amop
p1.oprleft = p1.oprright AND p1.oprname IN ('=', '~=~') AND WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p1.oprcom = p1.oid); amopopr = p1.oid AND amopstrategy = 3);
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);
oid | oprname oid | oprname
-----+--------- -----+---------
(0 rows) (0 rows)
-- And the converse. -- And the converse.
SELECT p1.oid, p1.oprname, op.opcname SELECT p1.oid, p1.oprname, p.amopfamily
FROM pg_operator AS p1, pg_opclass op, pg_amop p FROM pg_operator AS p1, pg_amop p
WHERE amopopr = p1.oid AND amopclaid = op.oid WHERE amopopr = p1.oid
AND opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') 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; AND NOT p1.oprcanhash;
oid | oprname | opcname oid | oprname | amopfamily
-----+---------+--------- -----+---------+------------
(0 rows) (0 rows)
-- Check that each operator defined in pg_operator matches its oprcode entry -- 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 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2 FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprcode = p2.oid AND WHERE p1.oprcode = p2.oid AND
(p1.oprlsortop != 0 OR p1.oprcanhash) AND (p1.oprcanmerge OR p1.oprcanhash) AND
p2.provolatile = 'v'; p2.provolatile = 'v';
oid | oprname | oid | proname oid | oprname | oid | proname
-----+---------+-----+--------- -----+---------+-----+---------
@ -720,14 +621,15 @@ WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
----------+----- ----------+-----
(0 rows) (0 rows)
-- Check operator is a suitable btree opclass member -- Check operator is a suitable btree opfamily member
SELECT a.aggfnoid::oid, o.oid SELECT a.aggfnoid::oid, o.oid
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
NOT EXISTS(SELECT 1 FROM pg_amop ao, pg_opclass oc NOT EXISTS(SELECT 1 FROM pg_amop
WHERE amopclaid = oc.oid AND amopsubtype = 0 WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND amopopr = o.oid AND opcamid = 403 AND amopopr = o.oid
AND opcintype = o.oprleft AND opcdefault); AND amoplefttype = o.oprleft
AND amoprighttype = o.oprright);
aggfnoid | oid aggfnoid | oid
----------+----- ----------+-----
(0 rows) (0 rows)
@ -735,31 +637,50 @@ WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
-- Check correspondence of btree strategies and names -- Check correspondence of btree strategies and names
SELECT DISTINCT proname, oprname, amopstrategy SELECT DISTINCT proname, oprname, amopstrategy
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p, 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 WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
amopclaid = oc.oid AND amopopr = o.oid AND opcamid = 403 amopopr = o.oid AND
ORDER BY 1; amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
ORDER BY 1, 2;
proname | oprname | amopstrategy proname | oprname | amopstrategy
---------+---------+-------------- ---------+---------+--------------
max | > | 5 max | > | 5
min | < | 1 min | < | 1
(2 rows) (2 rows)
-- **************** pg_opclass **************** -- **************** pg_opfamily ****************
-- Look for illegal values in pg_opclass fields -- Look for illegal values in pg_opfamily fields
SELECT p1.oid SELECT p1.oid
FROM pg_opclass as p1 FROM pg_opfamily as p1
WHERE p1.opcamid = 0 OR p1.opcintype = 0; WHERE p1.opfmethod = 0 OR p1.opfnamespace = 0;
oid oid
----- -----
(0 rows) (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 -- 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 SELECT p1.oid, p2.oid
FROM pg_opclass AS p1, pg_opclass AS p2 FROM pg_opclass AS p1, pg_opclass AS p2
WHERE p1.oid != p2.oid AND 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; p1.opcdefault AND p2.opcdefault;
oid | oid oid | oid
-----+----- -----+-----
@ -767,181 +688,221 @@ WHERE p1.oid != p2.oid AND
-- **************** pg_amop **************** -- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields -- Look for illegal values in pg_amop fields
SELECT p1.amopclaid, p1.amopstrategy SELECT p1.amopfamily, p1.amopstrategy
FROM pg_amop as p1 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
amopclaid | amopstrategy 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) (0 rows)
-- Cross-check amopstrategy index against parent AM -- Cross-check amopstrategy index against parent AM
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3 FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND WHERE p1.amopmethod = p2.oid AND
p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
amopclaid | amopopr | oid | amname amopfamily | amopopr | oid | amname
-----------+---------+-----+-------- ------------+---------+-----+--------
(0 rows) (0 rows)
-- Detect missing pg_amop entries: should have as many strategy operators -- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each opclass for the AM. When nondefault subtypes are -- as AM expects for each datatype combination supported by the opfamily.
-- present, enforce condition separately for each subtype.
-- We can't check this for AMs with variable strategy sets. -- We can't check this for AMs with variable strategy sets.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amopsubtype SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_opclass AS p2, pg_amop AS p3 FROM pg_am AS p1, pg_amop AS p2
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND WHERE p2.amopmethod = p1.oid AND
p1.amstrategies <> 0 AND p1.amstrategies <> 0 AND
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p4 p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p4.amopclaid = p2.oid AND WHERE p3.amopfamily = p2.amopfamily AND
p4.amopsubtype = p3.amopsubtype); p3.amoplefttype = p2.amoplefttype AND
oid | amname | oid | opcname | amopsubtype p3.amoprighttype = p2.amoprighttype);
-----+--------+-----+---------+------------- amname | amoplefttype | amoprighttype
--------+--------------+---------------
(0 rows) (0 rows)
-- Check that amopopr points at a reasonable-looking operator, ie a binary -- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator yielding boolean. -- 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 FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND WHERE p1.amopopr = p2.oid AND
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype); (p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
amopclaid | amopopr | oid | oprname amopfamily | amopopr | oid | oprname
-----------+---------+-----+--------- ------------+---------+-----+---------
(0 rows) (0 rows)
-- Make a list of all the distinct operator names being used in particular -- 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 -- 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 -- 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 SELECT DISTINCT amopmethod, amopstrategy, oprname
FROM pg_amop p1 LEFT JOIN pg_opclass p2 ON amopclaid = p2.oid FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
LEFT JOIN pg_operator p3 ON amopopr = p3.oid
ORDER BY 1, 2, 3; ORDER BY 1, 2, 3;
opcamid | amopstrategy | oprname amopmethod | amopstrategy | oprname
---------+--------------+--------- ------------+--------------+---------
403 | 1 | < 403 | 1 | <
403 | 1 | ~<~ 403 | 1 | ~<~
403 | 2 | <= 403 | 2 | <=
403 | 2 | ~<=~ 403 | 2 | ~<=~
403 | 3 | = 403 | 3 | =
403 | 3 | ~=~ 403 | 3 | ~=~
403 | 4 | >= 403 | 4 | >=
403 | 4 | ~>=~ 403 | 4 | ~>=~
403 | 5 | > 403 | 5 | >
403 | 5 | ~>~ 403 | 5 | ~>~
405 | 1 | = 405 | 1 | =
405 | 1 | ~=~ 405 | 1 | ~=~
783 | 1 | << 783 | 1 | <<
783 | 2 | &< 783 | 2 | &<
783 | 3 | && 783 | 3 | &&
783 | 4 | &> 783 | 4 | &>
783 | 5 | >> 783 | 5 | >>
783 | 6 | ~= 783 | 6 | ~=
783 | 7 | @> 783 | 7 | @>
783 | 8 | <@ 783 | 8 | <@
783 | 9 | &<| 783 | 9 | &<|
783 | 10 | <<| 783 | 10 | <<|
783 | 11 | |>> 783 | 11 | |>>
783 | 12 | |&> 783 | 12 | |&>
783 | 13 | ~ 783 | 13 | ~
783 | 14 | @ 783 | 14 | @
2742 | 1 | && 2742 | 1 | &&
2742 | 2 | @> 2742 | 2 | @>
2742 | 3 | <@ 2742 | 3 | <@
2742 | 4 | = 2742 | 4 | =
(30 rows) (30 rows)
-- Check that all operators linked to by opclass entries have selectivity -- Check that all operators linked to by opclass entries have selectivity
-- estimators. This is not absolutely required, but it seems a reasonable -- estimators. This is not absolutely required, but it seems a reasonable
-- thing to insist on for all standard datatypes. -- 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 FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND WHERE p1.amopopr = p2.oid AND
(p2.oprrest = 0 OR p2.oprjoin = 0); (p2.oprrest = 0 OR p2.oprjoin = 0);
amopclaid | amopopr | oid | oprname amopfamily | amopopr | oid | oprname
-----------+---------+-----+--------- ------------+---------+-----+---------
(0 rows) (0 rows)
-- Check that operator input types match the opclass -- Check that each opclass in an opfamily has associated operators, that is
-- For 8.0, we require that oprleft match opcintype (possibly by coercion). -- ones whose oprleft matches opcintype (possibly by coercion).
-- When amopsubtype is zero (default), oprright must equal oprleft; SELECT p1.opcname, p1.opcfamily
-- when amopsubtype is not zero, oprright must equal amopsubtype. FROM pg_opclass AS p1
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname WHERE NOT EXISTS(SELECT 1 FROM pg_amop AS p2
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3 WHERE p2.amopfamily = p1.opcfamily
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND AND binary_coercible(p1.opcintype, p2.amoplefttype));
NOT binary_coercible(p3.opcintype, p2.oprleft); opcname | opcfamily
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
-----------+---------+-----+---------+---------
(0 rows) (0 rows)
-- Operators that are primary members of opclasses must be immutable (else -- Operators that are primary members of opclasses must be immutable (else
-- it suggests that the index ordering isn't fixed). Operators that are -- it suggests that the index ordering isn't fixed). Operators that are
-- cross-type members need only be stable, since they are just shorthands -- cross-type members need only be stable, since they are just shorthands
-- for index probe queries. -- 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 FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype = 0 AND p1.amoplefttype = p1.amoprighttype AND
p3.provolatile != 'i'; p3.provolatile != 'i';
amopclaid | amopopr | oprname | prosrc amopfamily | amopopr | oprname | prosrc
-----------+---------+---------+-------- ------------+---------+---------+--------
(0 rows) (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 FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype != 0 AND p1.amoplefttype != p1.amoprighttype AND
p3.provolatile = 'v'; 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) (0 rows)
-- **************** pg_amproc **************** -- **************** pg_amproc ****************
-- Look for illegal values in pg_amproc fields -- Look for illegal values in pg_amproc fields
SELECT p1.amopclaid, p1.amprocnum SELECT p1.amprocfamily, p1.amprocnum
FROM pg_amproc as p1 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
amopclaid | amprocnum OR p1.amprocnum < 1 OR p1.amproc = 0;
-----------+----------- amprocfamily | amprocnum
--------------+-----------
(0 rows) (0 rows)
-- Cross-check amprocnum index against parent AM -- Cross-check amprocnum index against parent AM
SELECT p1.amopclaid, p1.amprocnum, p2.oid, p2.amname SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opclass AS p3 FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
p1.amprocnum > p2.amsupport; p1.amprocnum > p2.amsupport;
amopclaid | amprocnum | oid | amname amprocfamily | amprocnum | oid | amname
-----------+-----------+-----+-------- --------------+-----------+-----+--------
(0 rows) (0 rows)
-- Detect missing pg_amproc entries: should have as many support functions -- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each opclass for the AM. When nondefault subtypes are -- as AM expects for each datatype combination supported by the opfamily.
-- present, enforce condition separately for each subtype. SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amprocsubtype FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
FROM pg_am AS p1, pg_opclass AS p2, pg_amproc AS p3 WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND
p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4 p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4
WHERE p4.amopclaid = p2.oid AND WHERE p4.amprocfamily = p2.oid AND
p4.amprocsubtype = p3.amprocsubtype); p4.amproclefttype = p3.amproclefttype AND
oid | amname | oid | opcname | amprocsubtype p4.amprocrighttype = p3.amprocrighttype);
-----+--------+-----+---------+--------------- amname | opfname | amproclefttype | amprocrighttype
--------+---------+----------------+-----------------
(0 rows) (0 rows)
-- Unfortunately, we can't check the amproc link very well because the -- 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 -- 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 -- routine number take the same number of parameters, but that's about it
-- for a general check... -- for a general check...
SELECT p1.amopclaid, p1.amprocnum, SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname, p2.oid, p2.proname,
p3.opcname, p3.opfname,
p4.amopclaid, p4.amprocnum, p4.amprocfamily, p4.amprocnum,
p5.oid, p5.proname, p5.oid, p5.proname,
p6.opcname p6.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3, FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3,
pg_amproc AS p4, pg_proc AS p5, pg_opclass AS p6 pg_amproc AS p4, pg_proc AS p5, pg_opfamily AS p6
WHERE p1.amopclaid = p3.oid AND p4.amopclaid = p6.oid AND WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND
p3.opcamid = p6.opcamid AND p1.amprocnum = p4.amprocnum AND p3.opfmethod = p6.opfmethod AND p1.amprocnum = p4.amprocnum AND
p1.amproc = p2.oid AND p4.amproc = p5.oid AND p1.amproc = p2.oid AND p4.amproc = p5.oid AND
(p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs); (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) (0 rows)
-- For btree, though, we can do better since we know the support routines -- 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 -- must be of the form cmp(lefttype, righttype) returns int4.
-- (subtype = 0), and cmp(input, subtype) returns int4 when subtype != 0. SELECT p1.amprocfamily, p1.amprocnum,
SELECT p1.amopclaid, p1.amprocnum,
p2.oid, p2.proname, p2.oid, p2.proname,
p3.opcname p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3 FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree') WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
amprocsubtype = 0 AND (amprocnum != 1
(opckeytype != 0
OR amprocnum != 1
OR proretset OR proretset
OR prorettype != 23 OR prorettype != 'int4'::regtype
OR pronargs != 2 OR pronargs != 2
OR NOT binary_coercible(opcintype, proargtypes[0]) OR proargtypes[0] != amproclefttype
OR proargtypes[0] != proargtypes[1]); OR proargtypes[1] != amprocrighttype);
amopclaid | amprocnum | oid | proname | opcname amprocfamily | amprocnum | oid | proname | opfname
-----------+-----------+-----+---------+--------- --------------+-----------+-----+---------+---------
(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
-----------+-----------+-----+---------+---------
(0 rows) (0 rows)
-- For hash we can also do a little better: the support routines must be -- 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 -- of the form hash(lefttype) returns int4. There are several cases where
-- opcintype is binary-coercible to the function's input, but there are -- we cheat and use a hash function that is physically compatible with the
-- enough cases where that fails that I'll just leave out the check for now. -- 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, p2.oid, p2.proname,
p3.opcname p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3 FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
(opckeytype != 0 (amprocnum != 1
OR amprocnum != 1
OR proretset OR proretset
OR prorettype != 23 OR prorettype != 'int4'::regtype
OR pronargs != 1 OR pronargs != 1
-- OR NOT physically_coercible(opcintype, proargtypes[0]) -- OR NOT physically_coercible(amproclefttype, proargtypes[0])
); OR amproclefttype != amprocrighttype);
amopclaid | amprocnum | oid | proname | opcname amprocfamily | amprocnum | oid | proname | opfname
-----------+-----------+-----+---------+--------- --------------+-----------+-----+---------+---------
(0 rows) (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 -- (else it suggests that the index ordering isn't fixed). But cross-type
-- members need only be stable, since they are just shorthands -- members need only be stable, since they are just shorthands
-- for index probe queries. -- 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 FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND WHERE p1.amproc = p2.oid AND
p1.amprocsubtype = 0 AND p1.amproclefttype = p1.amprocrighttype AND
p2.provolatile != 'i'; p2.provolatile != 'i';
amopclaid | amproc | prosrc amprocfamily | amproc | prosrc
-----------+--------+-------- --------------+--------+--------
(0 rows) (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 FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND WHERE p1.amproc = p2.oid AND
p1.amprocsubtype != 0 AND p1.amproclefttype != p1.amprocrighttype AND
p2.provolatile = 'v'; p2.provolatile = 'v';
amopclaid | amproc | prosrc amprocfamily | amproc | prosrc
-----------+--------+-------- --------------+--------+--------
(0 rows) (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 ~~ ERROR: could not determine interpretation of row comparison operator ~~
LINE 1: select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail; 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 -- Check row comparison with a subselect
select unique1, unique2 from tenk1 select unique1, unique2 from tenk1
where (unique1, unique2) < any (select ten, ten from tenk1 where hundred < 3); 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_namespace | t
pg_opclass | t pg_opclass | t
pg_operator | t pg_operator | t
pg_opfamily | t
pg_pltemplate | t pg_pltemplate | t
pg_proc | t pg_proc | t
pg_rewrite | t pg_rewrite | t
@ -140,7 +141,7 @@ SELECT relname, relhasindex
timetz_tbl | f timetz_tbl | f
tinterval_tbl | f tinterval_tbl | f
varchar_tbl | f varchar_tbl | f
(129 rows) (130 rows)
-- --
-- another sanity check: every system catalog that has OIDs should have -- 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 FROM pg_catalog.pg_am fk
WHERE amcostestimate != 0 AND WHERE amcostestimate != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate); 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 FROM pg_catalog.pg_amop fk
WHERE amopclaid != 0 AND WHERE amopfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amopfamily);
SELECT ctid, amopsubtype SELECT ctid, amoplefttype
FROM pg_catalog.pg_amop fk FROM pg_catalog.pg_amop fk
WHERE amopsubtype != 0 AND WHERE amoplefttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amopsubtype); 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 SELECT ctid, amopopr
FROM pg_catalog.pg_amop fk FROM pg_catalog.pg_amop fk
WHERE amopopr != 0 AND WHERE amopopr != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.amopopr); 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 FROM pg_catalog.pg_amproc fk
WHERE amopclaid != 0 AND WHERE amprocfamily != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opclass pk WHERE pk.oid = fk.amopclaid); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_opfamily pk WHERE pk.oid = fk.amprocfamily);
SELECT ctid, amprocsubtype SELECT ctid, amproclefttype
FROM pg_catalog.pg_amproc fk FROM pg_catalog.pg_amproc fk
WHERE amprocsubtype != 0 AND WHERE amproclefttype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amprocsubtype); 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 SELECT ctid, amproc
FROM pg_catalog.pg_amproc fk FROM pg_catalog.pg_amproc fk
WHERE amproc != 0 AND WHERE amproc != 0 AND
@ -121,6 +137,10 @@ SELECT ctid, reltype
FROM pg_catalog.pg_class fk FROM pg_catalog.pg_class fk
WHERE reltype != 0 AND WHERE reltype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.reltype); 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 SELECT ctid, relam
FROM pg_catalog.pg_class fk FROM pg_catalog.pg_class fk
WHERE relam != 0 AND WHERE relam != 0 AND
@ -149,10 +169,18 @@ SELECT ctid, connamespace
FROM pg_catalog.pg_conversion fk FROM pg_catalog.pg_conversion fk
WHERE connamespace != 0 AND WHERE connamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.connamespace); 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 SELECT ctid, conproc
FROM pg_catalog.pg_conversion fk FROM pg_catalog.pg_conversion fk
WHERE conproc != 0 AND WHERE conproc != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.conproc); 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 SELECT ctid, dattablespace
FROM pg_catalog.pg_database fk FROM pg_catalog.pg_database fk
WHERE dattablespace != 0 AND WHERE dattablespace != 0 AND
@ -181,22 +209,42 @@ SELECT ctid, lanvalidator
FROM pg_catalog.pg_language fk FROM pg_catalog.pg_language fk
WHERE lanvalidator != 0 AND WHERE lanvalidator != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.lanvalidator); 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 FROM pg_catalog.pg_opclass fk
WHERE opcamid != 0 AND WHERE opcmethod != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcamid); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_am pk WHERE pk.oid = fk.opcmethod);
SELECT ctid, opcnamespace SELECT ctid, opcnamespace
FROM pg_catalog.pg_opclass fk FROM pg_catalog.pg_opclass fk
WHERE opcnamespace != 0 AND WHERE opcnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.opcnamespace); 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 SELECT ctid, opcintype
FROM pg_catalog.pg_opclass fk FROM pg_catalog.pg_opclass fk
WHERE opcintype != 0 AND WHERE opcintype != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.opcintype); 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 SELECT ctid, oprnamespace
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprnamespace != 0 AND WHERE oprnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.oprnamespace); 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 SELECT ctid, oprleft
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprleft != 0 AND WHERE oprleft != 0 AND
@ -217,22 +265,6 @@ SELECT ctid, oprnegate
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprnegate != 0 AND WHERE oprnegate != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.oprnegate); 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 SELECT ctid, oprcode
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprcode != 0 AND WHERE oprcode != 0 AND
@ -245,10 +277,26 @@ SELECT ctid, oprjoin
FROM pg_catalog.pg_operator fk FROM pg_catalog.pg_operator fk
WHERE oprjoin != 0 AND WHERE oprjoin != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.oprjoin); 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 SELECT ctid, pronamespace
FROM pg_catalog.pg_proc fk FROM pg_catalog.pg_proc fk
WHERE pronamespace != 0 AND WHERE pronamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.pronamespace); 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 SELECT ctid, prolang
FROM pg_catalog.pg_proc fk FROM pg_catalog.pg_proc fk
WHERE prolang != 0 AND WHERE prolang != 0 AND
@ -261,6 +309,14 @@ SELECT ctid, ev_class
FROM pg_catalog.pg_rewrite fk FROM pg_catalog.pg_rewrite fk
WHERE ev_class != 0 AND WHERE ev_class != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.ev_class); 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 SELECT ctid, starelid
FROM pg_catalog.pg_statistic fk FROM pg_catalog.pg_statistic fk
WHERE starelid != 0 AND WHERE starelid != 0 AND
@ -277,6 +333,10 @@ SELECT ctid, staop3
FROM pg_catalog.pg_statistic fk FROM pg_catalog.pg_statistic fk
WHERE staop3 != 0 AND WHERE staop3 != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.staop3); 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 SELECT ctid, tgrelid
FROM pg_catalog.pg_trigger fk FROM pg_catalog.pg_trigger fk
WHERE tgrelid != 0 AND WHERE tgrelid != 0 AND
@ -289,6 +349,10 @@ SELECT ctid, typnamespace
FROM pg_catalog.pg_type fk FROM pg_catalog.pg_type fk
WHERE typnamespace != 0 AND WHERE typnamespace != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace pk WHERE pk.oid = fk.typnamespace); 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 SELECT ctid, typrelid
FROM pg_catalog.pg_type fk FROM pg_catalog.pg_type fk
WHERE typrelid != 0 AND WHERE typrelid != 0 AND

View File

@ -1,7 +1,8 @@
-- --
-- OPR_SANITY -- OPR_SANITY
-- Sanity checks for common errors in making operator/procedure system tables: -- 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, -- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-). -- 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.oprnegate OR
p1.oid = p2.oid); p1.oid = p2.oid);
-- Look for mergejoin operators that don't match their links. -- A mergejoinable or hashjoinable operator must be binary, must return
-- An lsortop/rsortop link leads from an '=' operator to the -- boolean, and must have a commutator (itself, unless it's a cross-type
-- sort operator ('<' operator) that's appropriate for -- operator).
-- 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).
SELECT p1.oid, p1.oprname FROM pg_operator AS p1 SELECT p1.oid, p1.oprname FROM pg_operator AS p1
WHERE p1.oprlsortop != 0 AND WHERE (p1.oprcanmerge OR p1.oprcanhash) AND NOT
p1.oprcom = 0; (p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND p1.oprcom != 0);
-- Mergejoinable operators across datatypes must come in closed sets, that -- Mergejoinable operators should appear as equality members of btree index
-- is if you provide int2 = int4 and int4 = int8 then you must also provide -- opfamilies.
-- 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 "=".
SELECT p1.oid, p1.oprname SELECT p1.oid, p1.oprname
FROM pg_operator AS p1 FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT WHERE p1.oprcanmerge AND NOT EXISTS
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND (SELECT 1 FROM pg_amop
p1.oprleft = p1.oprright AND p1.oprname IN ('=', '~=~') AND WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
p1.oprcom = p1.oid); amopopr = p1.oid AND amopstrategy = 3);
-- In 6.5 we accepted hashable array equality operators when the array element -- And the converse.
-- 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 SELECT p1.oid, p1.oprname, p.amopfamily
-- -- type is not, or vice versa. This is presumably bogus. FROM pg_operator AS p1, pg_amop p
-- WHERE amopopr = p1.oid
-- SELECT p1.oid, p1.oprcanhash, p2.oid, p2.oprcanhash, t1.typname, t2.typname AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
-- FROM pg_operator AS p1, pg_operator AS p2, pg_type AS t1, pg_type AS t2 AND amopstrategy = 3
-- WHERE p1.oprname = '=' AND p1.oprleft = p1.oprright AND AND NOT p1.oprcanmerge;
-- 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. -- Hashable operators should appear as members of hash index opfamilies.
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.
SELECT p1.oid, p1.oprname SELECT p1.oid, p1.oprname
FROM pg_operator AS p1 FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT EXISTS WHERE p1.oprcanhash AND NOT EXISTS
(SELECT 1 FROM pg_opclass op JOIN pg_amop p ON op.oid = amopclaid (SELECT 1 FROM pg_amop
WHERE opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') AND WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') AND
amopopr = p1.oid); amopopr = p1.oid AND amopstrategy = 1);
-- And the converse. -- And the converse.
SELECT p1.oid, p1.oprname, op.opcname SELECT p1.oid, p1.oprname, p.amopfamily
FROM pg_operator AS p1, pg_opclass op, pg_amop p FROM pg_operator AS p1, pg_amop p
WHERE amopopr = p1.oid AND amopclaid = op.oid WHERE amopopr = p1.oid
AND opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND NOT p1.oprcanhash; AND NOT p1.oprcanhash;
-- Check that each operator defined in pg_operator matches its oprcode entry -- 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 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2 FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprcode = p2.oid AND WHERE p1.oprcode = p2.oid AND
(p1.oprlsortop != 0 OR p1.oprcanhash) AND (p1.oprcanmerge OR p1.oprcanhash) AND
p2.provolatile = 'v'; p2.provolatile = 'v';
-- If oprrest is set, the operator must return boolean, -- 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 (oprkind != 'b' OR oprresult != 'boolean'::regtype
OR oprleft != p.proargtypes[0] OR oprright != p.proargtypes[0]); 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 SELECT a.aggfnoid::oid, o.oid
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
NOT EXISTS(SELECT 1 FROM pg_amop ao, pg_opclass oc NOT EXISTS(SELECT 1 FROM pg_amop
WHERE amopclaid = oc.oid AND amopsubtype = 0 WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND amopopr = o.oid AND opcamid = 403 AND amopopr = o.oid
AND opcintype = o.oprleft AND opcdefault); AND amoplefttype = o.oprleft
AND amoprighttype = o.oprright);
-- Check correspondence of btree strategies and names -- Check correspondence of btree strategies and names
SELECT DISTINCT proname, oprname, amopstrategy SELECT DISTINCT proname, oprname, amopstrategy
FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p, 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 WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
amopclaid = oc.oid AND amopopr = o.oid AND opcamid = 403 amopopr = o.oid AND
ORDER BY 1; 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 **************** -- **************** pg_opclass ****************
-- Look for illegal values in pg_opclass fields -- Look for illegal values in pg_opclass fields
SELECT p1.oid SELECT p1.oid
FROM pg_opclass as p1 FROM pg_opclass AS p1
WHERE p1.opcamid = 0 OR p1.opcintype = 0; 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 -- 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 SELECT p1.oid, p2.oid
FROM pg_opclass AS p1, pg_opclass AS p2 FROM pg_opclass AS p1, pg_opclass AS p2
WHERE p1.oid != p2.oid AND 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; p1.opcdefault AND p2.opcdefault;
-- **************** pg_amop **************** -- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields -- Look for illegal values in pg_amop fields
SELECT p1.amopclaid, p1.amopstrategy SELECT p1.amopfamily, p1.amopstrategy
FROM pg_amop as p1 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 -- Cross-check amopstrategy index against parent AM
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3 FROM pg_amop AS p1, pg_am AS p2
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND WHERE p1.amopmethod = p2.oid AND
p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
-- Detect missing pg_amop entries: should have as many strategy operators -- Detect missing pg_amop entries: should have as many strategy operators
-- as AM expects for each opclass for the AM. When nondefault subtypes are -- as AM expects for each datatype combination supported by the opfamily.
-- present, enforce condition separately for each subtype.
-- We can't check this for AMs with variable strategy sets. -- We can't check this for AMs with variable strategy sets.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amopsubtype SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
FROM pg_am AS p1, pg_opclass AS p2, pg_amop AS p3 FROM pg_am AS p1, pg_amop AS p2
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND WHERE p2.amopmethod = p1.oid AND
p1.amstrategies <> 0 AND p1.amstrategies <> 0 AND
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p4 p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
WHERE p4.amopclaid = p2.oid AND WHERE p3.amopfamily = p2.amopfamily AND
p4.amopsubtype = p3.amopsubtype); p3.amoplefttype = p2.amoplefttype AND
p3.amoprighttype = p2.amoprighttype);
-- Check that amopopr points at a reasonable-looking operator, ie a binary -- Check that amopopr points at a reasonable-looking operator, ie a binary
-- operator yielding boolean. -- 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 FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND WHERE p1.amopopr = p2.oid AND
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype); (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 -- 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 -- 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 -- 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 SELECT DISTINCT amopmethod, amopstrategy, oprname
FROM pg_amop p1 LEFT JOIN pg_opclass p2 ON amopclaid = p2.oid FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
LEFT JOIN pg_operator p3 ON amopopr = p3.oid
ORDER BY 1, 2, 3; ORDER BY 1, 2, 3;
-- Check that all operators linked to by opclass entries have selectivity -- Check that all operators linked to by opclass entries have selectivity
-- estimators. This is not absolutely required, but it seems a reasonable -- estimators. This is not absolutely required, but it seems a reasonable
-- thing to insist on for all standard datatypes. -- 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 FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND WHERE p1.amopopr = p2.oid AND
(p2.oprrest = 0 OR p2.oprjoin = 0); (p2.oprrest = 0 OR p2.oprjoin = 0);
-- Check that operator input types match the opclass -- Check that each opclass in an opfamily has associated operators, that is
-- For 8.0, we require that oprleft match opcintype (possibly by coercion). -- ones whose oprleft matches 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 SELECT p1.opcname, p1.opcfamily
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3 FROM pg_opclass AS p1
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND WHERE NOT EXISTS(SELECT 1 FROM pg_amop AS p2
NOT binary_coercible(p3.opcintype, p2.oprleft); WHERE p2.amopfamily = p1.opcfamily
AND binary_coercible(p1.opcintype, p2.amoplefttype));
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;
-- Operators that are primary members of opclasses must be immutable (else -- Operators that are primary members of opclasses must be immutable (else
-- it suggests that the index ordering isn't fixed). Operators that are -- it suggests that the index ordering isn't fixed). Operators that are
-- cross-type members need only be stable, since they are just shorthands -- cross-type members need only be stable, since they are just shorthands
-- for index probe queries. -- 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 FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype = 0 AND p1.amoplefttype = p1.amoprighttype AND
p3.provolatile != 'i'; 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 FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3
WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND
p1.amopsubtype != 0 AND p1.amoplefttype != p1.amoprighttype AND
p3.provolatile = 'v'; 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 **************** -- **************** pg_amproc ****************
-- Look for illegal values in pg_amproc fields -- Look for illegal values in pg_amproc fields
SELECT p1.amopclaid, p1.amprocnum SELECT p1.amprocfamily, p1.amprocnum
FROM pg_amproc as p1 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 -- Cross-check amprocnum index against parent AM
SELECT p1.amopclaid, p1.amprocnum, p2.oid, p2.amname SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
FROM pg_amproc AS p1, pg_am AS p2, pg_opclass AS p3 FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
p1.amprocnum > p2.amsupport; p1.amprocnum > p2.amsupport;
-- Detect missing pg_amproc entries: should have as many support functions -- Detect missing pg_amproc entries: should have as many support functions
-- as AM expects for each opclass for the AM. When nondefault subtypes are -- as AM expects for each datatype combination supported by the opfamily.
-- present, enforce condition separately for each subtype.
SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amprocsubtype SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
FROM pg_am AS p1, pg_opclass AS p2, pg_amproc AS p3 FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND
p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4 p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4
WHERE p4.amopclaid = p2.oid AND WHERE p4.amprocfamily = p2.oid AND
p4.amprocsubtype = p3.amprocsubtype); p4.amproclefttype = p3.amproclefttype AND
p4.amprocrighttype = p3.amprocrighttype);
-- Unfortunately, we can't check the amproc link very well because the -- Unfortunately, we can't check the amproc link very well because the
-- signature of the function may be different for different support routines -- 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 -- routine number take the same number of parameters, but that's about it
-- for a general check... -- for a general check...
SELECT p1.amopclaid, p1.amprocnum, SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname, p2.oid, p2.proname,
p3.opcname, p3.opfname,
p4.amopclaid, p4.amprocnum, p4.amprocfamily, p4.amprocnum,
p5.oid, p5.proname, p5.oid, p5.proname,
p6.opcname p6.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3, FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3,
pg_amproc AS p4, pg_proc AS p5, pg_opclass AS p6 pg_amproc AS p4, pg_proc AS p5, pg_opfamily AS p6
WHERE p1.amopclaid = p3.oid AND p4.amopclaid = p6.oid AND WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND
p3.opcamid = p6.opcamid AND p1.amprocnum = p4.amprocnum AND p3.opfmethod = p6.opfmethod AND p1.amprocnum = p4.amprocnum AND
p1.amproc = p2.oid AND p4.amproc = p5.oid AND p1.amproc = p2.oid AND p4.amproc = p5.oid AND
(p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs); (p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs);
-- For btree, though, we can do better since we know the support routines -- 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 -- must be of the form cmp(lefttype, righttype) returns int4.
-- (subtype = 0), and cmp(input, subtype) returns int4 when subtype != 0.
SELECT p1.amopclaid, p1.amprocnum, SELECT p1.amprocfamily, p1.amprocnum,
p2.oid, p2.proname, p2.oid, p2.proname,
p3.opcname p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3 FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree') WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
amprocsubtype = 0 AND (amprocnum != 1
(opckeytype != 0
OR amprocnum != 1
OR proretset OR proretset
OR prorettype != 23 OR prorettype != 'int4'::regtype
OR pronargs != 2 OR pronargs != 2
OR NOT binary_coercible(opcintype, proargtypes[0]) OR proargtypes[0] != amproclefttype
OR proargtypes[0] != proargtypes[1]); OR proargtypes[1] != amprocrighttype);
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);
-- For hash we can also do a little better: the support routines must be -- 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 -- of the form hash(lefttype) returns int4. There are several cases where
-- opcintype is binary-coercible to the function's input, but there are -- we cheat and use a hash function that is physically compatible with the
-- enough cases where that fails that I'll just leave out the check for now. -- 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, p2.oid, p2.proname,
p3.opcname p3.opfname
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3 FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3
WHERE p3.opcamid = (SELECT oid FROM pg_am WHERE amname = 'hash') WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash')
AND p1.amopclaid = p3.oid AND p1.amproc = p2.oid AND AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND
(opckeytype != 0 (amprocnum != 1
OR amprocnum != 1
OR proretset OR proretset
OR prorettype != 23 OR prorettype != 'int4'::regtype
OR pronargs != 1 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 -- (else it suggests that the index ordering isn't fixed). But cross-type
-- members need only be stable, since they are just shorthands -- members need only be stable, since they are just shorthands
-- for index probe queries. -- 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 FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND WHERE p1.amproc = p2.oid AND
p1.amprocsubtype = 0 AND p1.amproclefttype = p1.amprocrighttype AND
p2.provolatile != 'i'; 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 FROM pg_amproc AS p1, pg_proc AS p2
WHERE p1.amproc = p2.oid AND WHERE p1.amproc = p2.oid AND
p1.amprocsubtype != 0 AND p1.amproclefttype != p1.amprocrighttype AND
p2.provolatile = 'v'; 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. be very slow.
Run on an empty database, it returns the system join relationships (shown 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 system tables --- don't accept a peculiar match without question.
In particular, a field shown as joining to more than one target table is 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 probably messed up. In 8.3, the *only* fields that should join to more
than one target are pg_description.objoid, pg_depend.objid, and than one target are pg_description.objoid, pg_depend.objid,
pg_depend.refobjid. (Running make_oidjoins_check is an easy way to spot pg_depend.refobjid, pg_shdescription.objoid, pg_shdepend.objid, and
fields joining to more than one table, BTW.) 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 The shell script make_oidjoins_check converts findoidjoins' output
into an SQL script that checks for dangling links (entries in an 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 (Ideally we'd just regenerate the script as part of the regression
tests themselves, but that seems too slow...) 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_class.relfilenode => pg_catalog.pg_class.oid
Join pg_catalog.pg_database.datlastsysoid => pg_catalog.pg_database.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. 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.ambulkdelete => pg_catalog.pg_proc.oid
Join pg_catalog.pg_am.amvacuumcleanup => 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_am.amcostestimate => pg_catalog.pg_proc.oid
Join pg_catalog.pg_amop.amopclaid => pg_catalog.pg_opclass.oid Join pg_catalog.pg_am.amoptions => pg_catalog.pg_proc.oid
Join pg_catalog.pg_amop.amopsubtype => pg_catalog.pg_type.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_amop.amopopr => pg_catalog.pg_operator.oid
Join pg_catalog.pg_amproc.amopclaid => pg_catalog.pg_opclass.oid Join pg_catalog.pg_amop.amopmethod => pg_catalog.pg_am.oid
Join pg_catalog.pg_amproc.amprocsubtype => pg_catalog.pg_type.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_amproc.amproc => pg_catalog.pg_proc.oid
Join pg_catalog.pg_attribute.attrelid => pg_catalog.pg_class.oid Join pg_catalog.pg_attribute.attrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_attribute.atttypid => pg_catalog.pg_type.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_cast.castfunc => pg_catalog.pg_proc.oid
Join pg_catalog.pg_class.relnamespace => pg_catalog.pg_namespace.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.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.relam => pg_catalog.pg_am.oid
Join pg_catalog.pg_class.reltablespace => pg_catalog.pg_tablespace.oid Join pg_catalog.pg_class.reltablespace => pg_catalog.pg_tablespace.oid
Join pg_catalog.pg_class.reltoastrelid => pg_catalog.pg_class.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.connamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_constraint.contypid => pg_catalog.pg_type.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.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_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_database.dattablespace => pg_catalog.pg_tablespace.oid
Join pg_catalog.pg_depend.classid => pg_catalog.pg_class.oid Join pg_catalog.pg_depend.classid => pg_catalog.pg_class.oid
Join pg_catalog.pg_depend.refclassid => 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.indexrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_index.indrelid => 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_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.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.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.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.oprleft => pg_catalog.pg_type.oid
Join pg_catalog.pg_operator.oprright => 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.oprresult => pg_catalog.pg_type.oid
Join pg_catalog.pg_operator.oprcom => pg_catalog.pg_operator.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.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.oprcode => pg_catalog.pg_proc.oid
Join pg_catalog.pg_operator.oprrest => 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_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.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.prolang => pg_catalog.pg_language.oid
Join pg_catalog.pg_proc.prorettype => pg_catalog.pg_type.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_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.starelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_statistic.staop1 => pg_catalog.pg_operator.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.staop2 => pg_catalog.pg_operator.oid
Join pg_catalog.pg_statistic.staop3 => 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.tgrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_trigger.tgfoid => pg_catalog.pg_proc.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.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.typrelid => pg_catalog.pg_class.oid
Join pg_catalog.pg_type.typelem => pg_catalog.pg_type.oid Join pg_catalog.pg_type.typelem => pg_catalog.pg_type.oid
Join pg_catalog.pg_type.typinput => pg_catalog.pg_proc.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) 1996-2006, PostgreSQL Global Development Group
-- Portions Copyright (c) 1994, Regents of the University of California -- 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 -- lists all the operator families that can be used with each access method
-- as well as the operators that cn be used with the respective operator -- as well as the operators that can be used with the respective operator
-- classes -- families
-- --
SELECT n.nspname, am.amname, opc.opcname, opr.oprname SELECT am.amname, n.nspname, opf.opfname, opr.oprname
FROM pg_namespace n, pg_am am, pg_opclass opc, FROM pg_namespace n, pg_am am, pg_opfamily opf,
pg_amop amop, pg_operator opr pg_amop amop, pg_operator opr
WHERE opc.opcnamespace = n.oid WHERE opf.opfnamespace = n.oid
and opc.opcamid = am.oid and opf.opfmethod = am.oid
and amop.amopclaid = opc.oid and amop.amopfamily = opf.oid
and amop.amopopr = opr.oid and amop.amopopr = opr.oid
ORDER BY nspname, amname, opcname, oprname; ORDER BY nspname, amname, opfname, oprname;
-- --
-- Reset the search path -- Reset the search path