Restructure operator classes to allow improved handling of cross-data-type
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 23 Dec 2006 00:43:13 +0000 (00:43 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 23 Dec 2006 00:43:13 +0000 (00:43 +0000)
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.

76 files changed:
contrib/intarray/_int.sql.in
contrib/intarray/uninstall__int.sql
doc/src/sgml/catalogs.sgml
doc/src/sgml/indexam.sgml
doc/src/sgml/indices.sgml
doc/src/sgml/ref/create_operator.sgml
doc/src/sgml/xoper.sgml
src/backend/access/hash/hashfunc.c
src/backend/access/index/indexam.c
src/backend/access/nbtree/nbtsearch.c
src/backend/catalog/Makefile
src/backend/catalog/dependency.c
src/backend/catalog/namespace.c
src/backend/catalog/pg_operator.c
src/backend/commands/indexcmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/operatorcmds.c
src/backend/commands/tablecmds.c
src/backend/executor/execQual.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeMergejoin.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/joinpath.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/pathnode.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/predtest.c
src/backend/optimizer/util/restrictinfo.c
src/backend/parser/parse_expr.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/cache/catcache.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/relcache.c
src/backend/utils/cache/syscache.c
src/backend/utils/cache/typcache.c
src/backend/utils/sort/tuplesort.c
src/bin/initdb/initdb.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h
src/include/catalog/dependency.h
src/include/catalog/indexing.h
src/include/catalog/namespace.h
src/include/catalog/pg_amop.h
src/include/catalog/pg_amproc.h
src/include/catalog/pg_opclass.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_opfamily.h [new file with mode: 0644]
src/include/commands/defrem.h
src/include/nodes/parsenodes.h
src/include/nodes/plannodes.h
src/include/nodes/primnodes.h
src/include/nodes/relation.h
src/include/optimizer/pathnode.h
src/include/utils/lsyscache.h
src/include/utils/rel.h
src/include/utils/selfuncs.h
src/include/utils/syscache.h
src/include/utils/typcache.h
src/test/regress/expected/oidjoins.out
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/rowtypes.out
src/test/regress/expected/sanity_check.out
src/test/regress/sql/oidjoins.sql
src/test/regress/sql/opr_sanity.sql
src/tools/findoidjoins/README
src/tutorial/syscat.source

index 37530a9062c6402c7826fc0a3f5071e8c9538996..44efc857002e8da86713e7ea83e7123d8d020df8 100644 (file)
@@ -459,9 +459,9 @@ AS
 
 --GIN
 --mark built-in gin's _int4_ops as non default
-update pg_opclass set opcdefault = 'f' where 
-       pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and
-       opcname = '_int4_ops';
+update pg_catalog.pg_opclass set opcdefault = 'f'
+where opcmethod = (select oid from pg_catalog.pg_am where amname='gin') and
+      opcname = '_int4_ops';
 
 CREATE FUNCTION ginint4_queryextract(internal, internal, int2)
 RETURNS internal
index 6f5b863fea21d6a427af6fd8b10305a6865fb331..2f3b20fda0302dc52ce5d9f474f843f9054d98be 100644 (file)
@@ -124,7 +124,7 @@ DROP FUNCTION querytree(query_int);
 
 DROP TYPE query_int CASCADE;
 
-update pg_opclass set opcdefault = 't' where
-    pg_opclass.opcamid = (select pg_am.oid from pg_am where amname='gin') and
-       opcname = '_int4_ops';
-
+--mark built-in gin's _int4_ops as default again
+update pg_catalog.pg_opclass set opcdefault = 't'
+where opcmethod = (select oid from pg_catalog.pg_am where amname='gin') and
+      opcname = '_int4_ops';
index ee5896b2818affff07676ba97948e8c36fcf248d..a906623ac9afe3e1787da19fd85a61f75a8aa244 100644 (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
  -->
 
      <row>
       <entry><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link></entry>
-      <entry>index access method operator classes</entry>
+      <entry>access method operator classes</entry>
      </row>
 
      <row>
       <entry>operators</entry>
      </row>
 
+     <row>
+      <entry><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link></entry>
+      <entry>access method operator families</entry>
+     </row>
+
      <row>
       <entry><link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link></entry>
       <entry>template data for procedural languages</entry>
   </indexterm>
 
   <para>
-   The catalog <structname>pg_amop</structname> stores information about operators
-   associated with index access method operator classes.  There is one
-   row for each operator that is a member of an operator class.
+   The catalog <structname>pg_amop</structname> stores information about
+   operators associated with access method operator families.  There is one
+   row for each operator that is a member of an operator family.  An operator
+   can appear in more than one family, but may not appear in more than one
+   position within a family.
   </para>
 
   <table>
     <tbody>
 
      <row>
-      <entry><structfield>amopclaid</structfield></entry>
+      <entry><structfield>amopfamily</structfield></entry>
       <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
-      <entry>The index operator class this entry is for</entry>
+      <entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
+      <entry>The operator family this entry is for</entry>
      </row>
 
      <row>
-      <entry><structfield>amopsubtype</structfield></entry>
+      <entry><structfield>amoplefttype</structfield></entry>
       <entry><type>oid</type></entry>
       <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
-      <entry>Subtype to distinguish multiple entries for one strategy;
-             zero for default</entry>
+      <entry>Left-hand input data type of operator</entry>
+     </row>
+
+     <row>
+      <entry><structfield>amoprighttype</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
+      <entry>Right-hand input data type of operator</entry>
      </row>
 
      <row>
       <entry>OID of the operator</entry>
      </row>
 
+     <row>
+      <entry><structfield>amopmethod</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></entry>
+      <entry>Index access method operator family is for</entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
 
+  <para>
+   An entry's <structfield>amopmethod</> must match the
+   <structname>opfmethod</> of its containing operator family (including
+   <structfield>amopmethod</> here is an intentional denormalization of the
+   catalog structure for performance reasons).  Also,
+   <structfield>amoplefttype</> and <structfield>amoprighttype</> must match
+   the <structfield>oprleft</> and <structfield>oprright</> fields of the
+   referenced <structname>pg_operator</> entry.
+  </para>
+
  </sect1>
 
 
   </indexterm>
 
   <para>
-   The catalog <structname>pg_amproc</structname> stores information about support
-   procedures
-   associated with index access method operator classes.  There is one
-   row for each support procedure belonging to an operator class.
+   The catalog <structname>pg_amproc</structname> stores information about
+   support procedures associated with access method operator families.  There
+   is one row for each support procedure belonging to an operator family.
   </para>
 
   <table>
     <tbody>
 
      <row>
-      <entry><structfield>amopclaid</structfield></entry>
+      <entry><structfield>amprocfamily</structfield></entry>
       <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
-      <entry>The index operator class this entry is for</entry>
+      <entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
+      <entry>The operator family this entry is for</entry>
+     </row>
+
+     <row>
+      <entry><structfield>amproclefttype</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
+      <entry>Left-hand input data type of associated operator</entry>
      </row>
 
      <row>
-      <entry><structfield>amprocsubtype</structfield></entry>
+      <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>Subtype, if cross-type routine, else zero</entry>
+      <entry>Right-hand input data type of associated operator</entry>
      </row>
 
      <row>
    </tgroup>
   </table>
 
+  <para>
+   The usual interpretation of the
+   <structfield>amproclefttype</> and <structfield>amprocrighttype</> fields
+   is that they identify the left and right input types of the operator(s)
+   that a particular support procedure supports.  For some access methods
+   these match the input data type(s) of the support procedure itself, for
+   others not.  There is a notion of <quote>default</> support procedures for
+   an index, which are those with <structfield>amproclefttype</> and
+   <structfield>amprocrighttype</> both equal to the index opclass's
+   <structfield>opcintype</>.
+  </para>
+
  </sect1>
 
 
    The catalog <structname>pg_opclass</structname> defines
    index access method operator classes.  Each operator class defines
    semantics for index columns of a particular data type and a particular
-   index access method.  Note that there can be multiple operator classes
-   for a given data type/access method combination, thus supporting multiple
-   behaviors.
+   index access method.  An operator class essentially specifies that a
+   particular operator family is applicable to a particular indexable column
+   data type.  The set of operators from the family that are actually usable
+   with the indexed column are whichever ones accept the column's data type
+   as their lefthand input.
   </para>
 
   <para>
     <tbody>
 
      <row>
-      <entry><structfield>opcamid</structfield></entry>
+      <entry><structfield>opcmethod</structfield></entry>
       <entry><type>oid</type></entry>
       <entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></entry>
       <entry>Index access method operator class is for</entry>
       <entry>Owner of the operator class</entry>
      </row>
 
+     <row>
+      <entry><structfield>opcfamily</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
+      <entry>Operator family containing the operator class</entry>
+     </row>
+
      <row>
       <entry><structfield>opcintype</structfield></entry>
       <entry><type>oid</type></entry>
   </table>
 
   <para>
-   The majority of the information defining an operator class is actually
-   not in its <structname>pg_opclass</structname> row, but in the associated
-   rows in <structname>pg_amop</structname> and
-   <structname>pg_amproc</structname>.  Those rows are considered to be
-   part of the operator class definition &mdash; this is not unlike the way
-   that a relation is defined by a single <structname>pg_class</structname>
-   row plus associated rows in <structname>pg_attribute</structname> and
-   other tables.
+   An operator class's <structfield>opcmethod</> must match the
+   <structname>opfmethod</> of its containing operator family.
+   Also, there must be no more than one <structname>pg_opclass</structname>
+   row having <structname>opcdefault</> true for any given combination of
+   <structname>opcmethod</> and <structname>opcintype</>.
   </para>
 
  </sect1>
       </entry>
      </row>
 
+     <row>
+      <entry><structfield>oprcanmerge</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>This operator supports merge joins</entry>
+     </row>
+
      <row>
       <entry><structfield>oprcanhash</structfield></entry>
       <entry><type>bool</type></entry>
       <entry>Negator of this operator, if any</entry>
      </row>
 
-     <row>
-      <entry><structfield>oprlsortop</structfield></entry>
-      <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
-      <entry>
-       If this operator supports merge joins, the operator that sorts
-       the type of the left-hand operand (<literal>L&lt;L</>)
-      </entry>
-     </row>
-
-     <row>
-      <entry><structfield>oprrsortop</structfield></entry>
-      <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
-      <entry>
-       If this operator supports merge joins, the operator that sorts
-       the type of the right-hand operand (<literal>R&lt;R</>)
-      </entry>
-     </row>
-
-     <row>
-      <entry><structfield>oprltcmpop</structfield></entry>
-      <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
-      <entry>
-       If this operator supports merge joins, the less-than operator that
-       compares the left and right operand types (<literal>L&lt;R</>)
-      </entry>
-     </row>
-
-     <row>
-      <entry><structfield>oprgtcmpop</structfield></entry>
-      <entry><type>oid</type></entry>
-      <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
-      <entry>
-       If this operator supports merge joins, the greater-than operator that
-       compares the left and right operand types (<literal>L&gt;R</>)
-      </entry>
-     </row>
-
      <row>
       <entry><structfield>oprcode</structfield></entry>
       <entry><type>regproc</type></entry>
  </sect1>
 
 
+ <sect1 id="catalog-pg-opfamily">
+  <title><structname>pg_opfamily</structname></title>
+
+  <indexterm zone="catalog-pg-opfamily">
+   <primary>pg_opfamily</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_opfamily</structname> defines operator families.
+   Each operator family is a collection of operators and associated
+   support routines that implement the semantics specified for a particular
+   index access method.  Furthermore, the operators in a family are all
+   <quote>compatible</>, in a way that depends on the access method.
+   The operator family concept allows cross-data-type operators to be used
+   with indexes and to be reasoned about using knowledge of access method
+   semantics.
+  </para>
+
+  <para>
+   Operator families are described at length in <xref linkend="xindex">.
+  </para>
+
+  <table>
+   <title><structname>pg_opfamily</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody>
+
+     <row>
+      <entry><structfield>opfmethod</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-am"><structname>pg_am</structname></link>.oid</literal></entry>
+      <entry>Index access method operator family is for</entry>
+     </row>
+
+     <row>
+      <entry><structfield>opfname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry></entry>
+      <entry>Name of this operator family</entry>
+     </row>
+
+     <row>
+      <entry><structfield>opfnamespace</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.oid</literal></entry>
+      <entry>Namespace of this operator family</entry>
+     </row>
+
+     <row>
+      <entry><structfield>opfowner</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>Owner of the operator family</entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   The majority of the information defining an operator family is not in its
+   <structname>pg_opfamily</structname> row, but in the associated rows in
+   <link linkend="catalog-pg-amop"><structname>pg_amop</structname></link>,
+   <link linkend="catalog-pg-amproc"><structname>pg_amproc</structname></link>,
+   and
+   <link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.
+  </para>
+
+ </sect1>
+
+
  <sect1 id="catalog-pg-pltemplate">
   <title><structname>pg_pltemplate</structname></title>
 
index 44dac1183e2d803f471fd071c9a281616f7968d5..658cdd709666270dd7e9adc72de613ab3cf4a847 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.18 2006/09/16 00:30:14 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.19 2006/12/23 00:43:08 tgl Exp $ -->
 
 <chapter id="indexam">
  <title>Index Access Method Interface Definition</title>
 
   <para>
    To be useful, an index access method must also have one or more
+   <firstterm>operator families</> and
    <firstterm>operator classes</> defined in
+   <link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>,
    <link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>,
    <link linkend="catalog-pg-amop"><structname>pg_amop</structname></link>, and
    <link linkend="catalog-pg-amproc"><structname>pg_amproc</structname></link>.
    These entries allow the planner
    to determine what kinds of query qualifications can be used with
-   indexes of this access method.  Operator classes are described
+   indexes of this access method.  Operator families and classes are described
    in <xref linkend="xindex">, which is prerequisite material for reading
    this chapter.
   </para>
@@ -409,14 +411,14 @@ amrestrpos (IndexScanDesc scan);
    A scan key is the internal representation of a <literal>WHERE</> clause of
    the form <replaceable>index_key</> <replaceable>operator</>
    <replaceable>constant</>, where the index key is one of the columns of the
-   index and the operator is one of the members of the operator class
+   index and the operator is one of the members of the operator family
    associated with that index column.  An index scan has zero or more scan
    keys, which are implicitly ANDed &mdash; the returned tuples are expected
    to satisfy all the indicated conditions.
   </para>
 
   <para>
-   The operator class may indicate that the index is <firstterm>lossy</> for a
+   The operator family may indicate that the index is <firstterm>lossy</> for a
    particular operator; this implies that the index scan will return all the
    entries that pass the scan key, plus possibly additional entries that do
    not.  The core system's index-scan machinery will then apply that operator
@@ -429,7 +431,7 @@ amrestrpos (IndexScanDesc scan);
    Note that it is entirely up to the access method to ensure that it
    correctly finds all and only the entries passing all the given scan keys.
    Also, the core system will simply hand off all the <literal>WHERE</>
-   clauses that match the index keys and operator classes, without any
+   clauses that match the index keys and operator families, without any
    semantic analysis to determine whether they are redundant or
    contradictory.  As an example, given
    <literal>WHERE x &gt; 4 AND x &gt; 14</> where <literal>x</> is a b-tree
index 1edceebd2d5f7619b7890aa13493d2491a747b94..6ff9c4d4b4f2fadbaf09e94f347eb1578fd3b30e 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.66 2006/12/01 23:46:46 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/indices.sgml,v 1.67 2006/12/23 00:43:08 tgl Exp $ -->
 
 <chapter id="indexes">
  <title id="indexes-title">Indexes</title>
@@ -784,12 +784,16 @@ CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target)
 
 
  <sect1 id="indexes-opclass">
-  <title>Operator Classes</title>
+  <title>Operator Classes and Operator Families</title>
 
   <indexterm zone="indexes-opclass">
    <primary>operator class</primary>
   </indexterm>
 
+  <indexterm zone="indexes-opclass">
+   <primary>operator family</primary>
+  </indexterm>
+
   <para>
    An index definition may specify an <firstterm>operator
    class</firstterm> for each column of an index.
@@ -854,20 +858,32 @@ CREATE INDEX test_index ON test_table (col varchar_pattern_ops);
 SELECT am.amname AS index_method,
        opc.opcname AS opclass_name
     FROM pg_am am, pg_opclass opc
-    WHERE opc.opcamid = am.oid
+    WHERE opc.opcmethod = am.oid
     ORDER BY index_method, opclass_name;
 </programlisting>
+  </para>
 
-    It can be extended to show all the operators included in each class:
+  <para>
+   An operator class is actually just a subset of a larger structure called an
+   <firstterm>operator family</>.  In cases where several data types have
+   similar behaviors, it is frequently useful to define cross-data-type
+   operators and allow these to work with indexes.  To do this, the operator
+   classes for each of the types must be grouped into the same operator
+   family.  The cross-type operators are members of the family, but are not
+   associated with any single class within the family.
+  </para>
+
+  <para>
+    This query shows all defined operator families and all
+    the operators included in each family:
 <programlisting>
 SELECT am.amname AS index_method,
-       opc.opcname AS opclass_name,
-       opr.oid::regoperator AS opclass_operator
-    FROM pg_am am, pg_opclass opc, pg_amop amop, pg_operator opr
-    WHERE opc.opcamid = am.oid AND
-          amop.amopclaid = opc.oid AND
-          amop.amopopr = opr.oid
-    ORDER BY index_method, opclass_name, opclass_operator;
+       opf.opfname AS opfamily_name,
+       amop.amopopr::regoperator AS opfamily_operator
+    FROM pg_am am, pg_opfamily opf, pg_amop amop
+    WHERE opf.opfmethod = am.oid AND
+          amop.amopfamily = opf.oid
+    ORDER BY index_method, opfamily_name, opfamily_operator;
 </programlisting>
   </para>
  </sect1>
index 023a9e7cbed6b494814ad96c14dd2a63a83d812d..955d9dbb2d1b685cbc870b3c7f972478997e392b 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.45 2006/09/16 00:30:17 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.46 2006/12/23 00:43:08 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -26,8 +26,6 @@ CREATE OPERATOR <replaceable>name</replaceable> (
     [, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
     [, RESTRICT = <replaceable class="parameter">res_proc</replaceable> ] [, JOIN = <replaceable class="parameter">join_proc</replaceable> ]
     [, HASHES ] [, MERGES ]
-    [, SORT1 = <replaceable class="parameter">left_sort_op</replaceable> ] [, SORT2 = <replaceable class="parameter">right_sort_op</replaceable> ]
-    [, LTCMP = <replaceable class="parameter">less_than_op</replaceable> ] [, GTCMP = <replaceable class="parameter">greater_than_op</replaceable> ]
 )
 </synopsis>
  </refsynopsisdiv>
@@ -202,46 +200,6 @@ CREATE OPERATOR <replaceable>name</replaceable> (
        </para>
       </listitem>
      </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="parameter">left_sort_op</replaceable></term>
-      <listitem>
-       <para>
-        If this operator can support a merge join, the less-than
-        operator that sorts the left-hand data type of this operator.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="parameter">right_sort_op</replaceable></term>
-      <listitem>
-       <para>
-        If this operator can support a merge join, the less-than
-        operator that sorts the right-hand data type of this operator.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="parameter">less_than_op</replaceable></term>
-      <listitem>
-       <para>
-        If this operator can support a merge join, the less-than
-        operator that compares the input data types of this operator.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><replaceable class="parameter">greater_than_op</replaceable></term>
-      <listitem>
-       <para>
-        If this operator can support a merge join, the greater-than
-        operator that compares the input data types of this operator.
-       </para>
-      </listitem>
-     </varlistentry>
     </variablelist>
 
   <para>
@@ -261,6 +219,16 @@ COMMUTATOR = OPERATOR(myschema.===) ,
    Refer to <xref linkend="xoper"> for further information.
   </para>
 
+  <para>
+   The obsolete options <literal>SORT1</>, <literal>SORT2</>,
+   <literal>LTCMP</>, and <literal>GTCMP</> were formerly used to
+   specify the names of sort operators associated with a mergejoinable
+   operator.  This is no longer necessary, since information about
+   associated operators is found by looking at btree operator families
+   instead.  If one of these options is given, it is ignored except
+   for implicitly setting <literal>MERGES</> true.
+  </para>
+
   <para>
    Use <xref linkend="sql-dropoperator"
    endterm="sql-dropoperator-title"> to delete user-defined operators
@@ -285,11 +253,7 @@ CREATE OPERATOR === (
     NEGATOR = !==,
     RESTRICT = area_restriction_procedure,
     JOIN = area_join_procedure,
-    HASHES,
-    SORT1 = &lt;&lt;&lt;,
-    SORT2 = &lt;&lt;&lt;
-    -- Since sort operators were given, MERGES is implied.
-    -- LTCMP and GTCMP are assumed to be &lt; and &gt; respectively
+    HASHES, MERGES
 );
 </programlisting>  
   </para>
index 8a9801858569762ce451d612a74125156fd1a9bf..5f84393ed20f254e96892c426e59ef49bbb8e55c 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/xoper.sgml,v 1.36 2006/09/16 00:30:16 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/xoper.sgml,v 1.37 2006/12/23 00:43:08 tgl Exp $ -->
 
  <sect1 id="xoper">
   <title>User-Defined Operators</title>
@@ -342,13 +342,13 @@ table1.column1 OP table2.column2
 
     <para>
      To be marked <literal>HASHES</literal>, the join operator must appear
-     in a hash index operator class.  This is not enforced when you create
-     the operator, since of course the referencing operator class couldn't
+     in a hash index operator family.  This is not enforced when you create
+     the operator, since of course the referencing operator family couldn't
      exist yet.  But attempts to use the operator in hash joins will fail
-     at run time if no such operator class exists.  The system needs the
-     operator class to find the data-type-specific hash function for the
+     at run time if no such operator family exists.  The system needs the
+     operator family to find the data-type-specific hash function for the
      operator's input data type.  Of course, you must also supply a suitable
-     hash function before you can create the operator class.
+     hash function before you can create the operator family.
     </para>
 
     <para>
@@ -390,7 +390,7 @@ table1.column1 OP table2.column2
    </sect2>
 
    <sect2>
-    <title><literal>MERGES</> (<literal>SORT1</>, <literal>SORT2</>, <literal>LTCMP</>, <literal>GTCMP</>)</title>
+    <title><literal>MERGES</></title>
 
     <para>
      The <literal>MERGES</literal> clause, if present, tells the system that
@@ -418,36 +418,13 @@ table1.column1 OP table2.column2
     </para>
 
     <para>
-     Execution of a merge join requires that the system be able to identify
-     four operators related to the merge-join equality operator: less-than
-     comparison for the left operand data type, less-than comparison for the
-     right operand data type, less-than comparison between the two data types, and
-     greater-than comparison between the two data types.  (These are actually
-     four distinct operators if the merge-joinable operator has two different
-     operand data types; but when the operand types are the same the three
-     less-than operators are all the same operator.)
-     It is possible to
-     specify these operators individually by name, as the <literal>SORT1</>,
-     <literal>SORT2</>, <literal>LTCMP</>, and <literal>GTCMP</> options
-     respectively.  The system will fill in the default names
-     <literal>&lt;</>, <literal>&lt;</>, <literal>&lt;</>, <literal>&gt;</>
-     respectively if any of these are omitted when <literal>MERGES</> is
-     specified.  Also, <literal>MERGES</> will be assumed to be implied if any
-     of these four operator options appear, so it is possible to specify
-     just some of them and let the system fill in the rest.
-    </para>
-
-    <para>
-     The operand data types of the four comparison operators can be deduced
-     from the operand types of the merge-joinable operator, so just as with
-     <literal>COMMUTATOR</>, only the operator names need be given in these
-     clauses.  Unless you are using peculiar choices of operator names,
-     it's sufficient to write <literal>MERGES</> and let the system fill in
-     the details.
-     (As with <literal>COMMUTATOR</> and <literal>NEGATOR</>, the system is
-     able to make dummy
-     operator entries if you happen to define the equality operator before
-     the other ones.)
+     To be marked <literal>MERGES</literal>, the join operator must appear
+     in a btree index operator family.  This is not enforced when you create
+     the operator, since of course the referencing operator family couldn't
+     exist yet.  But the operator will not actually be used for merge joins
+     unless a matching operator family can be found.  The
+     <literal>MERGES</literal> flag thus acts as a hint to the planner that
+     it's worth looking for a matching operator family.
     </para>
 
     <para>
@@ -474,13 +451,6 @@ table1.column1 OP table2.column2
        be transitive.
        </para>
       </listitem>
-
-      <listitem>
-       <para>
-        Bizarre results will ensue at run time if the four comparison
-       operators you name do not sort the data values compatibly.
-       </para>
-      </listitem>
      </itemizedlist>
     </para>
 
@@ -491,17 +461,5 @@ table1.column1 OP table2.column2
      attempt to use the operator for a merge join.
     </para>
     </note>
-
-    <note>
-    <para>
-     In <productname>PostgreSQL</productname> versions before 7.3,
-     the <literal>MERGES</> shorthand was not available: to make a
-     merge-joinable operator one had to write both <literal>SORT1</> and
-     <literal>SORT2</> explicitly.  Also, the <literal>LTCMP</> and
-     <literal>GTCMP</>
-     options did not exist; the names of those operators were hardwired as
-     <literal>&lt;</> and <literal>&gt;</> respectively.
-    </para>
-    </note>
    </sect2>
   </sect1>
index 1e2d779a14cfe58d914a126326d6714bbb1758f3..f6b39bada2affb3f55d9ce711d08795a40cc61d3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.48 2006/10/04 00:29:48 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.49 2006/12/23 00:43:08 tgl Exp $
  *
  * NOTES
  *       These functions are stored in pg_amproc.      For each operator class
@@ -46,11 +46,11 @@ hashint8(PG_FUNCTION_ARGS)
 {
        /*
         * The idea here is to produce a hash value compatible with the values
-        * produced by hashint4 and hashint2 for logically equivalent inputs; this
-        * is necessary if we ever hope to support cross-type hash joins across
-        * these input types.  Since all three types are signed, we can xor the
-        * high half of the int8 value if the sign is positive, or the complement
-        * of the high half when the sign is negative.
+        * produced by hashint4 and hashint2 for logically equal inputs; this is
+        * necessary to support cross-type hash joins across these input types.
+        * Since all three types are signed, we can xor the high half of the int8
+        * value if the sign is positive, or the complement of the high half when
+        * the sign is negative.
         */
 #ifndef INT64_IS_BUSTED
        int64           val = PG_GETARG_INT64(0);
@@ -76,16 +76,26 @@ Datum
 hashfloat4(PG_FUNCTION_ARGS)
 {
        float4          key = PG_GETARG_FLOAT4(0);
+       float8          key8;
 
        /*
         * On IEEE-float machines, minus zero and zero have different bit patterns
         * but should compare as equal.  We must ensure that they have the same
-        * hash value, which is most easily done this way:
+        * hash value, which is most reliably done this way:
         */
        if (key == (float4) 0)
                PG_RETURN_UINT32(0);
 
-       return hash_any((unsigned char *) &key, sizeof(key));
+       /*
+        * To support cross-type hashing of float8 and float4, we want to return
+        * the same hash value hashfloat8 would produce for an equal float8 value.
+        * So, widen the value to float8 and hash that.  (We must do this rather
+        * than have hashfloat8 try to narrow its value to float4; that could
+        * fail on overflow.)
+        */
+       key8 = key;
+
+       return hash_any((unsigned char *) &key8, sizeof(key8));
 }
 
 Datum
@@ -96,7 +106,7 @@ hashfloat8(PG_FUNCTION_ARGS)
        /*
         * On IEEE-float machines, minus zero and zero have different bit patterns
         * but should compare as equal.  We must ensure that they have the same
-        * hash value, which is most easily done this way:
+        * hash value, which is most reliably done this way:
         */
        if (key == (float8) 0)
                PG_RETURN_UINT32(0);
index 493e9f0ad008b053f539dc73289df9fbfbe1c83b..6d60f4617845a372d6a3273613a6c979b1082464 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.95 2006/10/04 00:29:48 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.96 2006/12/23 00:43:08 tgl Exp $
  *
  * INTERFACE ROUTINES
  *             index_open              - open an index relation by relation OID
@@ -608,17 +608,27 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
 /* ----------------
  *             index_getprocid
  *
- *             Some indexed access methods may require support routines that are
- *             not in the operator class/operator model imposed by pg_am.      These
- *             access methods may store the OIDs of registered procedures they
- *             need in pg_amproc.      These registered procedure OIDs are ordered in
- *             a way that makes sense to the access method, and used only by the
- *             access method.  The general index code doesn't know anything about
- *             the routines involved; it just builds an ordered list of them for
+ *             Index access methods typically require support routines that are
+ *             not directly the implementation of any WHERE-clause query operator
+ *             and so cannot be kept in pg_amop.  Instead, such routines are kept
+ *             in pg_amproc.  These registered procedure OIDs are assigned numbers
+ *             according to a convention established by the access method.
+ *             The general index code doesn't know anything about the routines
+ *             involved; it just builds an ordered list of them for
  *             each attribute on which an index is defined.
  *
- *             This routine returns the requested procedure OID for a particular
- *             indexed attribute.
+ *             As of Postgres 8.3, support routines within an operator family
+ *             are further subdivided by the "left type" and "right type" of the
+ *             query operator(s) that they support.  The "default" functions for a
+ *             particular indexed attribute are those with both types equal to
+ *             the index opclass' opcintype (note that this is subtly different
+ *             from the indexed attribute's own type: it may be a binary-compatible
+ *             type instead).  Only the default functions are stored in relcache
+ *             entries --- access methods can use the syscache to look up non-default
+ *             functions.
+ *
+ *             This routine returns the requested default procedure OID for a
+ *             particular indexed attribute.
  * ----------------
  */
 RegProcedure
@@ -647,7 +657,8 @@ index_getprocid(Relation irel,
  *             index_getprocinfo
  *
  *             This routine allows index AMs to keep fmgr lookup info for
- *             support procs in the relcache.
+ *             support procs in the relcache.  As above, only the "default"
+ *             functions for any particular indexed attribute are cached.
  *
  * Note: the return value points into cached data that will be lost during
  * any relcache rebuild!  Therefore, either use the callinfo right away,
index 6d9be1b0176636f17f90792eacb5df206914eb63..284b92e0d284226e8a042782e9479eee805ac5b2 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.107 2006/10/04 00:29:49 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.108 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -658,11 +658,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
                         * to an insertion scan key by replacing the sk_func with the
                         * appropriate btree comparison function.
                         *
-                        * If scankey operator is of default subtype, we can use the
-                        * cached comparison function; otherwise gotta look it up in the
-                        * catalogs.
+                        * If scankey operator is of the default type for the index, we
+                        * can use the cached comparison function; otherwise gotta look it
+                        * up in the catalogs.  Also, we support the convention that
+                        * sk_subtype == 0 means the default type; this is a hack to
+                        * simplify life for ScanKeyInit().
                         */
-                       if (cur->sk_subtype == InvalidOid)
+                       if (cur->sk_subtype == rel->rd_opcintype[i] ||
+                               cur->sk_subtype == InvalidOid)
                        {
                                FmgrInfo   *procinfo;
 
@@ -671,7 +674,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
                                                                                           cur->sk_flags,
                                                                                           cur->sk_attno,
                                                                                           InvalidStrategy,
-                                                                                          InvalidOid,
+                                                                                          cur->sk_subtype,
                                                                                           procinfo,
                                                                                           cur->sk_argument);
                        }
@@ -679,9 +682,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
                        {
                                RegProcedure cmp_proc;
 
-                               cmp_proc = get_opclass_proc(rel->rd_indclass->values[i],
-                                                                                       cur->sk_subtype,
-                                                                                       BTORDER_PROC);
+                               cmp_proc = get_opfamily_proc(rel->rd_opfamily[i],
+                                                                                        rel->rd_opcintype[i],
+                                                                                        cur->sk_subtype,
+                                                                                        BTORDER_PROC);
+                               if (!RegProcedureIsValid(cmp_proc))
+                                       elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
+                                                BTORDER_PROC, rel->rd_opcintype[i], cur->sk_subtype,
+                                                cur->sk_attno, RelationGetRelationName(rel));
                                ScanKeyEntryInitialize(scankeys + i,
                                                                           cur->sk_flags,
                                                                           cur->sk_attno,
index 2e2d885f894da3716cefb57aa372ce1884aeb694..110619425b1d298a0311c1b45e0ab8097347468b 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.60 2006/07/31 01:16:36 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.61 2006/12/23 00:43:09 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -28,8 +28,8 @@ SUBSYS.o: $(OBJS)
 
 POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
        pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
-       pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
-       pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
+       pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
+       pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
        pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
        pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
        pg_namespace.h pg_conversion.h pg_depend.h \
index cab4f1006bc6c1f4e97ffc389bee146d1dbf042d..770b189606ef8086773f65d660ed245a3818c8ab 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.60 2006/10/04 00:29:50 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.61 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,8 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_cast.h"
@@ -33,6 +35,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_tablespace.h"
@@ -78,19 +81,25 @@ typedef struct
  * See also getObjectClass().
  */
 static const Oid object_classes[MAX_OCLASS] = {
-       RelationRelationId,                     /* OCLASS_CLASS */
-       ProcedureRelationId,            /* OCLASS_PROC */
-       TypeRelationId,                         /* OCLASS_TYPE */
-       CastRelationId,                         /* OCLASS_CAST */
-       ConstraintRelationId,           /* OCLASS_CONSTRAINT */
-       ConversionRelationId,           /* OCLASS_CONVERSION */
-       AttrDefaultRelationId,          /* OCLASS_DEFAULT */
-       LanguageRelationId,                     /* OCLASS_LANGUAGE */
-       OperatorRelationId,                     /* OCLASS_OPERATOR */
-       OperatorClassRelationId,        /* OCLASS_OPCLASS */
-       RewriteRelationId,                      /* OCLASS_REWRITE */
-       TriggerRelationId,                      /* OCLASS_TRIGGER */
-       NamespaceRelationId                     /* OCLASS_SCHEMA */
+       RelationRelationId,                                     /* OCLASS_CLASS */
+       ProcedureRelationId,                            /* OCLASS_PROC */
+       TypeRelationId,                                         /* OCLASS_TYPE */
+       CastRelationId,                                         /* OCLASS_CAST */
+       ConstraintRelationId,                           /* OCLASS_CONSTRAINT */
+       ConversionRelationId,                           /* OCLASS_CONVERSION */
+       AttrDefaultRelationId,                          /* OCLASS_DEFAULT */
+       LanguageRelationId,                                     /* OCLASS_LANGUAGE */
+       OperatorRelationId,                                     /* OCLASS_OPERATOR */
+       OperatorClassRelationId,                        /* OCLASS_OPCLASS */
+       OperatorFamilyRelationId,                       /* OCLASS_OPFAMILY */
+       AccessMethodOperatorRelationId,         /* OCLASS_AMOP */
+       AccessMethodProcedureRelationId,        /* OCLASS_AMPROC */
+       RewriteRelationId,                                      /* OCLASS_REWRITE */
+       TriggerRelationId,                                      /* OCLASS_TRIGGER */
+       NamespaceRelationId,                            /* OCLASS_SCHEMA */
+       AuthIdRelationId,                                       /* OCLASS_ROLE */
+       DatabaseRelationId,                                     /* OCLASS_DATABASE */
+       TableSpaceRelationId                            /* OCLASS_TBLSPACE */
 };
 
 
@@ -122,6 +131,7 @@ static int  object_address_comparator(const void *a, const void *b);
 static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
                                   ObjectAddresses *addrs);
 static void getRelationDescription(StringInfo buffer, Oid relid);
+static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
 
 
 /*
@@ -185,7 +195,7 @@ performDeletion(const ObjectAddress *object,
  * filled with some objects.  Also, the deleted objects are saved in the
  * alreadyDeleted list.
  *
- * XXX performDeletion could be refactored to be a thin wrapper to this
+ * XXX performDeletion could be refactored to be a thin wrapper around this
  * function.
  */
 static void
@@ -954,6 +964,18 @@ doDeletion(const ObjectAddress *object)
                        RemoveOpClassById(object->objectId);
                        break;
 
+               case OCLASS_OPFAMILY:
+                       RemoveOpFamilyById(object->objectId);
+                       break;
+
+               case OCLASS_AMOP:
+                       RemoveAmOpEntryById(object->objectId);
+                       break;
+
+               case OCLASS_AMPROC:
+                       RemoveAmProcEntryById(object->objectId);
+                       break;
+
                case OCLASS_REWRITE:
                        RemoveRewriteRuleById(object->objectId);
                        break;
@@ -966,6 +988,8 @@ doDeletion(const ObjectAddress *object)
                        RemoveSchemaById(object->objectId);
                        break;
 
+               /* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
+
                default:
                        elog(ERROR, "unrecognized object class: %u",
                                 object->classId);
@@ -1316,9 +1340,9 @@ find_expr_references_walker(Node *node,
                        add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
                                                           context->addrs);
                }
-               foreach(l, rcexpr->opclasses)
+               foreach(l, rcexpr->opfamilies)
                {
-                       add_object_address(OCLASS_OPCLASS, lfirst_oid(l), 0,
+                       add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
                                                           context->addrs);
                }
                /* fall through to examine arguments */
@@ -1623,6 +1647,18 @@ getObjectClass(const ObjectAddress *object)
                        Assert(object->objectSubId == 0);
                        return OCLASS_OPCLASS;
 
+               case OperatorFamilyRelationId:
+                       Assert(object->objectSubId == 0);
+                       return OCLASS_OPFAMILY;
+
+               case AccessMethodOperatorRelationId:
+                       Assert(object->objectSubId == 0);
+                       return OCLASS_AMOP;
+
+               case AccessMethodProcedureRelationId:
+                       Assert(object->objectSubId == 0);
+                       return OCLASS_AMPROC;
+
                case RewriteRelationId:
                        Assert(object->objectSubId == 0);
                        return OCLASS_REWRITE;
@@ -1856,11 +1892,11 @@ getObjectDescription(const ObjectAddress *object)
                                opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
 
                                amTup = SearchSysCache(AMOID,
-                                                                          ObjectIdGetDatum(opcForm->opcamid),
+                                                                          ObjectIdGetDatum(opcForm->opcmethod),
                                                                           0, 0, 0);
                                if (!HeapTupleIsValid(amTup))
                                        elog(ERROR, "cache lookup failed for access method %u",
-                                                opcForm->opcamid);
+                                                opcForm->opcmethod);
                                amForm = (Form_pg_am) GETSTRUCT(amTup);
 
                                /* Qualify the name if not visible in search path */
@@ -1879,6 +1915,84 @@ getObjectDescription(const ObjectAddress *object)
                                break;
                        }
 
+               case OCLASS_OPFAMILY:
+                       getOpFamilyDescription(&buffer, object->objectId);
+                       break;
+
+               case OCLASS_AMOP:
+                       {
+                               Relation        amopDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc amscan;
+                               HeapTuple       tup;
+                               Form_pg_amop amopForm;
+
+                               amopDesc = heap_open(AccessMethodOperatorRelationId,
+                                                                        AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(amscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for amop entry %u",
+                                                object->objectId);
+
+                               amopForm = (Form_pg_amop) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, _("operator %d %s of "),
+                                                                amopForm->amopstrategy,
+                                                                format_operator(amopForm->amopopr));
+                               getOpFamilyDescription(&buffer, amopForm->amopfamily);
+
+                               systable_endscan(amscan);
+                               heap_close(amopDesc, AccessShareLock);
+                               break;
+                       }
+
+               case OCLASS_AMPROC:
+                       {
+                               Relation        amprocDesc;
+                               ScanKeyData skey[1];
+                               SysScanDesc amscan;
+                               HeapTuple       tup;
+                               Form_pg_amproc amprocForm;
+
+                               amprocDesc = heap_open(AccessMethodProcedureRelationId,
+                                                                          AccessShareLock);
+
+                               ScanKeyInit(&skey[0],
+                                                       ObjectIdAttributeNumber,
+                                                       BTEqualStrategyNumber, F_OIDEQ,
+                                                       ObjectIdGetDatum(object->objectId));
+
+                               amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
+                                                                                       SnapshotNow, 1, skey);
+
+                               tup = systable_getnext(amscan);
+
+                               if (!HeapTupleIsValid(tup))
+                                       elog(ERROR, "could not find tuple for amproc entry %u",
+                                                object->objectId);
+
+                               amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
+
+                               appendStringInfo(&buffer, _("function %d %s of "),
+                                                                amprocForm->amprocnum,
+                                                                format_procedure(amprocForm->amproc));
+                               getOpFamilyDescription(&buffer, amprocForm->amprocfamily);
+
+                               systable_endscan(amscan);
+                               heap_close(amprocDesc, AccessShareLock);
+                               break;
+                       }
+
                case OCLASS_REWRITE:
                        {
                                Relation        ruleDesc;
@@ -2068,3 +2182,45 @@ getRelationDescription(StringInfo buffer, Oid relid)
 
        ReleaseSysCache(relTup);
 }
+
+/*
+ * subroutine for getObjectDescription: describe an operator family
+ */
+static void
+getOpFamilyDescription(StringInfo buffer, Oid opfid)
+{
+       HeapTuple       opfTup;
+       Form_pg_opfamily opfForm;
+       HeapTuple       amTup;
+       Form_pg_am      amForm;
+       char       *nspname;
+
+       opfTup = SearchSysCache(OPFAMILYOID,
+                                                       ObjectIdGetDatum(opfid),
+                                                       0, 0, 0);
+       if (!HeapTupleIsValid(opfTup))
+               elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+       opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
+
+       amTup = SearchSysCache(AMOID,
+                                                  ObjectIdGetDatum(opfForm->opfmethod),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(amTup))
+               elog(ERROR, "cache lookup failed for access method %u",
+                        opfForm->opfmethod);
+       amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+       /* Qualify the name if not visible in search path */
+       if (OpfamilyIsVisible(opfid))
+               nspname = NULL;
+       else
+               nspname = get_namespace_name(opfForm->opfnamespace);
+
+       appendStringInfo(buffer, _("operator family %s for access method %s"),
+                                        quote_qualified_identifier(nspname,
+                                                                                               NameStr(opfForm->opfname)),
+                                        NameStr(amForm->amname));
+
+       ReleaseSysCache(amTup);
+       ReleaseSysCache(opfTup);
+}
index 1d6162ca12e458c6f57c16f08c9611dfd7d8d7bf..5c661a098bb4128d38679a3544dc889a78cebd24 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.88 2006/10/04 00:29:50 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.89 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "commands/dbcommands.h"
@@ -1062,7 +1063,7 @@ OpclassIsVisible(Oid opcid)
                 */
                char       *opcname = NameStr(opcform->opcname);
 
-               visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid);
+               visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
        }
 
        ReleaseSysCache(opctup);
@@ -1070,6 +1071,89 @@ OpclassIsVisible(Oid opcid)
        return visible;
 }
 
+/*
+ * OpfamilynameGetOpfid
+ *             Try to resolve an unqualified index opfamily name.
+ *             Returns OID if opfamily found in search path, else InvalidOid.
+ *
+ * This is essentially the same as TypenameGetTypid, but we have to have
+ * an extra argument for the index AM OID.
+ */
+Oid
+OpfamilynameGetOpfid(Oid amid, const char *opfname)
+{
+       Oid                     opfid;
+       ListCell   *l;
+
+       recomputeNamespacePath();
+
+       foreach(l, namespaceSearchPath)
+       {
+               Oid                     namespaceId = lfirst_oid(l);
+
+               opfid = GetSysCacheOid(OPFAMILYAMNAMENSP,
+                                                          ObjectIdGetDatum(amid),
+                                                          PointerGetDatum(opfname),
+                                                          ObjectIdGetDatum(namespaceId),
+                                                          0);
+               if (OidIsValid(opfid))
+                       return opfid;
+       }
+
+       /* Not found in path */
+       return InvalidOid;
+}
+
+/*
+ * OpfamilyIsVisible
+ *             Determine whether an opfamily (identified by OID) is visible in the
+ *             current search path.  Visible means "would be found by searching
+ *             for the unqualified opfamily name".
+ */
+bool
+OpfamilyIsVisible(Oid opfid)
+{
+       HeapTuple       opftup;
+       Form_pg_opfamily opfform;
+       Oid                     opfnamespace;
+       bool            visible;
+
+       opftup = SearchSysCache(OPFAMILYOID,
+                                                       ObjectIdGetDatum(opfid),
+                                                       0, 0, 0);
+       if (!HeapTupleIsValid(opftup))
+               elog(ERROR, "cache lookup failed for opfamily %u", opfid);
+       opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
+
+       recomputeNamespacePath();
+
+       /*
+        * Quick check: if it ain't in the path at all, it ain't visible. Items in
+        * the system namespace are surely in the path and so we needn't even do
+        * list_member_oid() for them.
+        */
+       opfnamespace = opfform->opfnamespace;
+       if (opfnamespace != PG_CATALOG_NAMESPACE &&
+               !list_member_oid(namespaceSearchPath, opfnamespace))
+               visible = false;
+       else
+       {
+               /*
+                * If it is in the path, it might still not be visible; it could be
+                * hidden by another opfamily of the same name earlier in the path. So
+                * we must do a slow check to see if this opfamily would be found by
+                * OpfamilynameGetOpfid.
+                */
+               char       *opfname = NameStr(opfform->opfname);
+
+               visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
+       }
+
+       ReleaseSysCache(opftup);
+
+       return visible;
+}
+
 /*
  * ConversionGetConid
  *             Try to resolve an unqualified conversion name.
index 13efb7227ad25c6272918e191cf144e39baa862f..65ecb65b9265d7049cdd78dcc5ccaf4e2db95b55 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.98 2006/07/14 14:52:18 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.99 2006/12/23 00:43:09 tgl Exp $
  *
  * NOTES
  *       these routines moved here from commands/define.c and somewhat cleaned up.
@@ -238,16 +238,13 @@ OperatorShellMake(const char *operatorName,
        values[i++] = ObjectIdGetDatum(operatorNamespace);      /* oprnamespace */
        values[i++] = ObjectIdGetDatum(GetUserId());            /* oprowner */
        values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');       /* oprkind */
+       values[i++] = BoolGetDatum(false);      /* oprcanmerge */
        values[i++] = BoolGetDatum(false);      /* oprcanhash */
        values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
        values[i++] = ObjectIdGetDatum(rightTypeId);            /* oprright */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */
@@ -296,11 +293,8 @@ OperatorShellMake(const char *operatorName,
  *             negatorName                             X negator operator
  *             restrictionName                 X restriction sel. procedure
  *             joinName                                X join sel. procedure
+ *             canMerge                                merge join can be used with this operator
  *             canHash                                 hash join can be used with this operator
- *             leftSortName                    X left sort operator (for merge join)
- *             rightSortName                   X right sort operator (for merge join)
- *             ltCompareName                   X L<R compare operator (for merge join)
- *             gtCompareName                   X L>R compare operator (for merge join)
  *
  * This routine gets complicated because it allows the user to
  * specify operators that do not exist.  For example, if operator
@@ -326,6 +320,7 @@ OperatorShellMake(const char *operatorName,
  *      operatorName
  *      owner id (simply the user id of the caller)
  *      operator "kind" either "b" for binary or "l" for left unary
+ *      canMerge boolean
  *      canHash boolean
  *      leftTypeObjectId -- type must already be defined
  *      rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
@@ -341,8 +336,6 @@ OperatorShellMake(const char *operatorName,
  *                                             (We are creating a self-commutating operator.)
  *                                             The link will be fixed later by OperatorUpd.
  *      negatorObjectId   -- same as for commutatorObjectId
- *      leftSortObjectId  -- same as for commutatorObjectId
- *      rightSortObjectId -- same as for commutatorObjectId
  *      operatorProcedure -- must access the pg_procedure catalog to get the
  *                                ObjectId of the procedure that actually does the operator
  *                                actions this is required.  Do a lookup to find out the
@@ -369,11 +362,8 @@ OperatorCreate(const char *operatorName,
                           List *negatorName,
                           List *restrictionName,
                           List *joinName,
-                          bool canHash,
-                          List *leftSortName,
-                          List *rightSortName,
-                          List *ltCompareName,
-                          List *gtCompareName)
+                          bool canMerge,
+                          bool canHash)
 {
        Relation        pg_operator_desc;
        HeapTuple       tup;
@@ -386,10 +376,6 @@ OperatorCreate(const char *operatorName,
        Oid                     operResultType;
        Oid                     commutatorId,
                                negatorId,
-                               leftSortId,
-                               rightSortId,
-                               ltCompareId,
-                               gtCompareId,
                                restOid,
                                joinOid;
        bool            selfCommutator = false;
@@ -424,14 +410,14 @@ OperatorCreate(const char *operatorName,
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                                 errmsg("only binary operators can have join selectivity")));
-               if (canHash)
+               if (canMerge)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-                                        errmsg("only binary operators can hash")));
-               if (leftSortName || rightSortName || ltCompareName || gtCompareName)
+                                        errmsg("only binary operators can merge join")));
+               if (canHash)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-                                        errmsg("only binary operators can merge join")));
+                                        errmsg("only binary operators can hash")));
        }
 
        operatorObjectId = OperatorGet(operatorName,
@@ -522,6 +508,7 @@ OperatorCreate(const char *operatorName,
        values[i++] = ObjectIdGetDatum(operatorNamespace);      /* oprnamespace */
        values[i++] = ObjectIdGetDatum(GetUserId());            /* oprowner */
        values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');       /* oprkind */
+       values[i++] = BoolGetDatum(canMerge);           /* oprcanmerge */
        values[i++] = BoolGetDatum(canHash);            /* oprcanhash */
        values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
        values[i++] = ObjectIdGetDatum(rightTypeId);            /* oprright */
@@ -565,58 +552,6 @@ OperatorCreate(const char *operatorName,
                negatorId = InvalidOid;
        values[i++] = ObjectIdGetDatum(negatorId);      /* oprnegate */
 
-       if (leftSortName)
-       {
-               /* left sort op takes left-side data type */
-               leftSortId = get_other_operator(leftSortName,
-                                                                               leftTypeId, leftTypeId,
-                                                                               operatorName, operatorNamespace,
-                                                                               leftTypeId, rightTypeId,
-                                                                               false);
-       }
-       else
-               leftSortId = InvalidOid;
-       values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */
-
-       if (rightSortName)
-       {
-               /* right sort op takes right-side data type */
-               rightSortId = get_other_operator(rightSortName,
-                                                                                rightTypeId, rightTypeId,
-                                                                                operatorName, operatorNamespace,
-                                                                                leftTypeId, rightTypeId,
-                                                                                false);
-       }
-       else
-               rightSortId = InvalidOid;
-       values[i++] = ObjectIdGetDatum(rightSortId);            /* oprrsortop */
-
-       if (ltCompareName)
-       {
-               /* comparator has same arg types */
-               ltCompareId = get_other_operator(ltCompareName,
-                                                                                leftTypeId, rightTypeId,
-                                                                                operatorName, operatorNamespace,
-                                                                                leftTypeId, rightTypeId,
-                                                                                false);
-       }
-       else
-               ltCompareId = InvalidOid;
-       values[i++] = ObjectIdGetDatum(ltCompareId);            /* oprltcmpop */
-
-       if (gtCompareName)
-       {
-               /* comparator has same arg types */
-               gtCompareId = get_other_operator(gtCompareName,
-                                                                                leftTypeId, rightTypeId,
-                                                                                operatorName, operatorNamespace,
-                                                                                leftTypeId, rightTypeId,
-                                                                                false);
-       }
-       else
-               gtCompareId = InvalidOid;
-       values[i++] = ObjectIdGetDatum(gtCompareId);            /* oprgtcmpop */
-
        values[i++] = ObjectIdGetDatum(procOid);        /* oprcode */
        values[i++] = ObjectIdGetDatum(restOid);        /* oprrest */
        values[i++] = ObjectIdGetDatum(joinOid);        /* oprjoin */
@@ -930,12 +865,11 @@ makeOperatorDependencies(HeapTuple tuple)
 
        /*
         * NOTE: we do not consider the operator to depend on the associated
-        * operators oprcom, oprnegate, oprlsortop, oprrsortop, oprltcmpop,
-        * oprgtcmpop.  We would not want to delete this operator if those go
-        * away, but only reset the link fields; which is not a function that the
-        * dependency code can presently handle.  (Something could perhaps be done
-        * with objectSubId though.)  For now, it's okay to let those links dangle
-        * if a referenced operator is removed.
+        * operators oprcom and oprnegate. We would not want to delete this
+        * operator if those go away, but only reset the link fields; which is not
+        * a function that the dependency code can presently handle.  (Something
+        * could perhaps be done with objectSubId though.)  For now, it's okay to
+        * let those links dangle if a referenced operator is removed.
         */
 
        /* Dependency on implementation function */
index 5f54f66f59148f31d82df519870b76419dc78d62..a5cc047c69bcc990e743353d4926e94d9e94ed70 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.149 2006/10/04 00:29:51 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.150 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -802,31 +802,37 @@ GetIndexOpClass(List *opclass, Oid attrType,
 Oid
 GetDefaultOpClass(Oid type_id, Oid am_id)
 {
+       Oid                     result = InvalidOid;
        int                     nexact = 0;
        int                     ncompatible = 0;
-       Oid                     exactOid = InvalidOid;
-       Oid                     compatibleOid = InvalidOid;
+       int                     ncompatiblepreferred = 0;
        Relation        rel;
        ScanKeyData skey[1];
        SysScanDesc scan;
        HeapTuple       tup;
+       CATEGORY        tcategory;
 
        /* If it's a domain, look at the base type instead */
        type_id = getBaseType(type_id);
 
+       tcategory = TypeCategory(type_id);
+
        /*
         * We scan through all the opclasses available for the access method,
         * looking for one that is marked default and matches the target type
         * (either exactly or binary-compatibly, but prefer an exact match).
         *
-        * We could find more than one binary-compatible match, in which case we
-        * require the user to specify which one he wants.      If we find more than
-        * one exact match, then someone put bogus entries in pg_opclass.
+        * We could find more than one binary-compatible match.  If just one is
+        * for a preferred type, use that one; otherwise we fail, forcing the user
+        * to specify which one he wants.  (The preferred-type special case is a
+        * kluge for varchar: it's binary-compatible to both text and bpchar, so
+        * we need a tiebreaker.)  If we find more than one exact match, then
+        * someone put bogus entries in pg_opclass.
         */
        rel = heap_open(OperatorClassRelationId, AccessShareLock);
 
        ScanKeyInit(&skey[0],
-                               Anum_pg_opclass_opcamid,
+                               Anum_pg_opclass_opcmethod,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(am_id));
 
@@ -837,17 +843,26 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
        {
                Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
 
-               if (opclass->opcdefault)
+               /* ignore altogether if not a default opclass */
+               if (!opclass->opcdefault)
+                       continue;
+               if (opclass->opcintype == type_id)
                {
-                       if (opclass->opcintype == type_id)
+                       nexact++;
+                       result = HeapTupleGetOid(tup);
+               }
+               else if (nexact == 0 &&
+                                IsBinaryCoercible(type_id, opclass->opcintype))
+               {
+                       if (IsPreferredType(tcategory, opclass->opcintype))
                        {
-                               nexact++;
-                               exactOid = HeapTupleGetOid(tup);
+                               ncompatiblepreferred++;
+                               result = HeapTupleGetOid(tup);
                        }
-                       else if (IsBinaryCoercible(type_id, opclass->opcintype))
+                       else if (ncompatiblepreferred == 0)
                        {
                                ncompatible++;
-                               compatibleOid = HeapTupleGetOid(tup);
+                               result = HeapTupleGetOid(tup);
                        }
                }
        }
@@ -856,15 +871,17 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
 
        heap_close(rel, AccessShareLock);
 
-       if (nexact == 1)
-               return exactOid;
-       if (nexact != 0)
+       /* raise error if pg_opclass contains inconsistent data */
+       if (nexact > 1)
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
                errmsg("there are multiple default operator classes for data type %s",
                           format_type_be(type_id))));
-       if (ncompatible == 1)
-               return compatibleOid;
+
+       if (nexact == 1 ||
+               ncompatiblepreferred == 1 ||
+               (ncompatiblepreferred == 0 && ncompatible == 1))
+               return result;
 
        return InvalidOid;
 }
index d4dec746501321be0a248950eb0bcb1d6ef8408e..8b1b27ef3e7461e0d2c3d90a52d8a91cf605b458 100644 (file)
@@ -2,14 +2,14 @@
  *
  * opclasscmds.c
  *
- *       Routines for opclass manipulation commands
+ *       Routines for opclass (and opfamily) manipulation commands
  *
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.50 2006/12/18 18:56:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.51 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
 
 /*
  * We use lists of this struct type to keep track of both operators and
- * procedures during DefineOpClass.
+ * procedures while building or adding to an opfamily.
  */
 typedef struct
 {
        Oid                     object;                 /* operator or support proc's OID */
        int                     number;                 /* strategy or support proc number */
-       Oid                     subtype;                /* subtype */
+       Oid                     lefttype;               /* lefttype */
+       Oid                     righttype;              /* righttype */
        bool            recheck;                /* oper recheck flag (unused for proc) */
-} OpClassMember;
+} OpFamilyMember;
 
 
-static Oid     assignOperSubtype(Oid amoid, Oid typeoid, Oid operOid);
-static Oid     assignProcSubtype(Oid amoid, Oid typeoid, Oid procOid);
-static void addClassMember(List **list, OpClassMember *member, bool isProc);
-static void storeOperators(Oid opclassoid, List *operators);
-static void storeProcedures(Oid opclassoid, List *procedures);
+static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
+static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
+static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
+static void storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid,
+                                                  List *operators);
+static void storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid,
+                                                       List *procedures);
 static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
                                                   Oid newOwnerId);
 
 
+/*
+ * OpFamilyCacheLookup
+ *             Look up an existing opfamily by name.
+ *
+ * Returns a syscache tuple reference, or NULL if not found.
+ */
+static HeapTuple
+OpFamilyCacheLookup(Oid amID, List *opfamilyname)
+{
+       char       *schemaname;
+       char       *opfname;
+
+       /* deconstruct the name list */
+       DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
+
+       if (schemaname)
+       {
+               /* Look in specific schema only */
+               Oid                     namespaceId;
+
+               namespaceId = LookupExplicitNamespace(schemaname);
+               return SearchSysCache(OPFAMILYAMNAMENSP,
+                                                         ObjectIdGetDatum(amID),
+                                                         PointerGetDatum(opfname),
+                                                         ObjectIdGetDatum(namespaceId),
+                                                         0);
+       }
+       else
+       {
+               /* Unqualified opfamily name, so search the search path */
+               Oid             opfID = OpfamilynameGetOpfid(amID, opfname);
+
+               if (!OidIsValid(opfID))
+                       return NULL;
+               return SearchSysCache(OPFAMILYOID,
+                                                         ObjectIdGetDatum(opfID),
+                                                         0, 0, 0);
+       }
+}
+
+/*
+ * OpClassCacheLookup
+ *             Look up an existing opclass by name.
+ *
+ * Returns a syscache tuple reference, or NULL if not found.
+ */
+static HeapTuple
+OpClassCacheLookup(Oid amID, List *opclassname)
+{
+       char       *schemaname;
+       char       *opcname;
+
+       /* deconstruct the name list */
+       DeconstructQualifiedName(opclassname, &schemaname, &opcname);
+
+       if (schemaname)
+       {
+               /* Look in specific schema only */
+               Oid                     namespaceId;
+
+               namespaceId = LookupExplicitNamespace(schemaname);
+               return SearchSysCache(CLAAMNAMENSP,
+                                                         ObjectIdGetDatum(amID),
+                                                         PointerGetDatum(opcname),
+                                                         ObjectIdGetDatum(namespaceId),
+                                                         0);
+       }
+       else
+       {
+               /* Unqualified opclass name, so search the search path */
+               Oid             opcID = OpclassnameGetOpcid(amID, opcname);
+
+               if (!OidIsValid(opcID))
+                       return NULL;
+               return SearchSysCache(CLAOID,
+                                                         ObjectIdGetDatum(opcID),
+                                                         0, 0, 0);
+       }
+}
+
+/*
+ * CreateOpFamily
+ *             Internal routine to make the catalog entry for a new operator family.
+ *
+ * Caller must have done permissions checks etc. already.
+ */
+static Oid
+CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
+{
+       Oid                     opfamilyoid;
+       Relation        rel;
+       HeapTuple       tup;
+       Datum           values[Natts_pg_opfamily];
+       char            nulls[Natts_pg_opfamily];
+       NameData        opfName;
+       ObjectAddress myself,
+                               referenced;
+
+       rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+
+       /*
+        * Make sure there is no existing opfamily of this name (this is just to
+        * give a more friendly error message than "duplicate key").
+        */
+       if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
+                                                        ObjectIdGetDatum(amoid),
+                                                        CStringGetDatum(opfname),
+                                                        ObjectIdGetDatum(namespaceoid),
+                                                        0))
+               ereport(ERROR,
+                               (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                errmsg("operator family \"%s\" for access method \"%s\" already exists",
+                                               opfname, amname)));
+
+       /*
+        * Okay, let's create the pg_opfamily entry.
+        */
+       memset(values, 0, sizeof(values));
+       memset(nulls, ' ', sizeof(nulls));
+
+       values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
+       namestrcpy(&opfName, opfname);
+       values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
+       values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
+       values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
+
+       tup = heap_formtuple(rel->rd_att, values, nulls);
+
+       opfamilyoid = simple_heap_insert(rel, tup);
+
+       CatalogUpdateIndexes(rel, tup);
+
+       heap_freetuple(tup);
+
+       /*
+        * Create dependencies for the opfamily proper.  Note: we do not create a
+        * dependency link to the AM, because we don't currently support DROP
+        * ACCESS METHOD.
+        */
+       myself.classId = OperatorFamilyRelationId;
+       myself.objectId = opfamilyoid;
+       myself.objectSubId = 0;
+
+       /* dependency on namespace */
+       referenced.classId = NamespaceRelationId;
+       referenced.objectId = namespaceoid;
+       referenced.objectSubId = 0;
+       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+       /* dependency on owner */
+       recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
+
+       heap_close(rel, RowExclusiveLock);
+
+       return opfamilyoid;
+}
+
 /*
  * DefineOpClass
  *             Define a new index operator class.
@@ -74,12 +235,13 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                typeoid,                /* indexable datatype oid */
                                storageoid,             /* storage datatype oid, if any */
                                namespaceoid,   /* namespace to create opclass in */
+                               opfamilyoid,    /* oid of containing opfamily */
                                opclassoid;             /* oid of opclass we create */
        int                     maxOpNumber,    /* amstrategies value */
                                maxProcNumber;  /* amsupport value */
        bool            amstorage;              /* amstorage flag */
-       List       *operators;          /* OpClassMember list for operators */
-       List       *procedures;         /* OpClassMember list for support procs */
+       List       *operators;          /* OpFamilyMember list for operators */
+       List       *procedures;         /* OpFamilyMember list for support procs */
        ListCell   *l;
        Relation        rel;
        HeapTuple       tup;
@@ -88,7 +250,6 @@ DefineOpClass(CreateOpClassStmt *stmt)
        char            nulls[Natts_pg_opclass];
        AclResult       aclresult;
        NameData        opcName;
-       int                     i;
        ObjectAddress myself,
                                referenced;
 
@@ -161,6 +322,52 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                           format_type_be(typeoid));
 #endif
 
+       /*
+        * Look up the containing operator family, or create one if FAMILY option
+        * was omitted and there's not a match already.
+        */
+       if (stmt->opfamilyname)
+       {
+               tup = OpFamilyCacheLookup(amoid, stmt->opfamilyname);
+               if (!HeapTupleIsValid(tup))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                        errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+                                                       NameListToString(stmt->opfamilyname), stmt->amname)));
+               opfamilyoid = HeapTupleGetOid(tup);
+               /*
+                * XXX given the superuser check above, there's no need for an
+                * ownership check here
+                */
+               ReleaseSysCache(tup);
+       }
+       else
+       {
+               /* Lookup existing family of same name and namespace */
+               tup = SearchSysCache(OPFAMILYAMNAMENSP,
+                                                        ObjectIdGetDatum(amoid),
+                                                        PointerGetDatum(opcname),
+                                                        ObjectIdGetDatum(namespaceoid),
+                                                        0);
+               if (HeapTupleIsValid(tup))
+               {
+                       opfamilyoid = HeapTupleGetOid(tup);
+                       /*
+                        * XXX given the superuser check above, there's no need for an
+                        * ownership check here
+                        */
+                       ReleaseSysCache(tup);
+               }
+               else
+               {
+                       /*
+                        * Create it ... again no need for more permissions ...
+                        */
+                       opfamilyoid = CreateOpFamily(stmt->amname, opcname,
+                                                                                namespaceoid, amoid);
+               }
+       }
+
        operators = NIL;
        procedures = NIL;
 
@@ -175,7 +382,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
                CreateOpClassItem *item = lfirst(l);
                Oid                     operOid;
                Oid                     funcOid;
-               OpClassMember *member;
+               OpFamilyMember *member;
 
                Assert(IsA(item, CreateOpClassItem));
                switch (item->itemtype)
@@ -217,12 +424,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
 #endif
 
                                /* Save the info */
-                               member = (OpClassMember *) palloc0(sizeof(OpClassMember));
+                               member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                                member->object = operOid;
                                member->number = item->number;
-                               member->subtype = assignOperSubtype(amoid, typeoid, operOid);
                                member->recheck = item->recheck;
-                               addClassMember(&operators, member, false);
+                               assignOperTypes(member, amoid, typeoid);
+                               addFamilyMember(&operators, member, false);
                                break;
                        case OPCLASS_ITEM_FUNCTION:
                                if (item->number <= 0 || item->number > maxProcNumber)
@@ -242,11 +449,11 @@ DefineOpClass(CreateOpClassStmt *stmt)
 #endif
 
                                /* Save the info */
-                               member = (OpClassMember *) palloc0(sizeof(OpClassMember));
+                               member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                                member->object = funcOid;
                                member->number = item->number;
-                               member->subtype = assignProcSubtype(amoid, typeoid, funcOid);
-                               addClassMember(&procedures, member, true);
+                               assignProcTypes(member, amoid, typeoid);
+                               addFamilyMember(&procedures, member, true);
                                break;
                        case OPCLASS_ITEM_STORAGETYPE:
                                if (OidIsValid(storageoid))
@@ -311,7 +518,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
                SysScanDesc scan;
 
                ScanKeyInit(&skey[0],
-                                       Anum_pg_opclass_opcamid,
+                                       Anum_pg_opclass_opcmethod,
                                        BTEqualStrategyNumber, F_OIDEQ,
                                        ObjectIdGetDatum(amoid));
 
@@ -338,21 +545,18 @@ DefineOpClass(CreateOpClassStmt *stmt)
        /*
         * Okay, let's create the pg_opclass entry.
         */
-       for (i = 0; i < Natts_pg_opclass; ++i)
-       {
-               nulls[i] = ' ';
-               values[i] = (Datum) NULL;               /* redundant, but safe */
-       }
+       memset(values, 0, sizeof(values));
+       memset(nulls, ' ', sizeof(nulls));
 
-       i = 0;
-       values[i++] = ObjectIdGetDatum(amoid);          /* opcamid */
+       values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
        namestrcpy(&opcName, opcname);
-       values[i++] = NameGetDatum(&opcName);           /* opcname */
-       values[i++] = ObjectIdGetDatum(namespaceoid);           /* opcnamespace */
-       values[i++] = ObjectIdGetDatum(GetUserId());            /* opcowner */
-       values[i++] = ObjectIdGetDatum(typeoid);        /* opcintype */
-       values[i++] = BoolGetDatum(stmt->isDefault);            /* opcdefault */
-       values[i++] = ObjectIdGetDatum(storageoid); /* opckeytype */
+       values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
+       values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
+       values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
+       values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
+       values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
+       values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
+       values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
 
        tup = heap_formtuple(rel->rd_att, values, nulls);
 
@@ -364,14 +568,15 @@ DefineOpClass(CreateOpClassStmt *stmt)
 
        /*
         * Now add tuples to pg_amop and pg_amproc tying in the operators and
-        * functions.
+        * functions.  Dependencies on them are inserted, too.
         */
-       storeOperators(opclassoid, operators);
-       storeProcedures(opclassoid, procedures);
+       storeOperators(amoid, opfamilyoid, opclassoid, operators);
+       storeProcedures(amoid, opfamilyoid, opclassoid, procedures);
 
        /*
-        * Create dependencies.  Note: we do not create a dependency link to the
-        * AM, because we don't currently support DROP ACCESS METHOD.
+        * Create dependencies for the opclass proper.  Note: we do not create a
+        * dependency link to the AM, because we don't currently support DROP
+        * ACCESS METHOD.
         */
        myself.classId = OperatorClassRelationId;
        myself.objectId = opclassoid;
@@ -383,6 +588,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
+       /* dependency on opfamily */
+       referenced.classId = OperatorFamilyRelationId;
+       referenced.objectId = opfamilyoid;
+       referenced.objectSubId = 0;
+       recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+
        /* dependency on indexed datatype */
        referenced.classId = TypeRelationId;
        referenced.objectId = typeoid;
@@ -398,28 +609,6 @@ DefineOpClass(CreateOpClassStmt *stmt)
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
 
-       /* dependencies on operators */
-       foreach(l, operators)
-       {
-               OpClassMember *op = (OpClassMember *) lfirst(l);
-
-               referenced.classId = OperatorRelationId;
-               referenced.objectId = op->object;
-               referenced.objectSubId = 0;
-               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-       }
-
-       /* dependencies on procedures */
-       foreach(l, procedures)
-       {
-               OpClassMember *proc = (OpClassMember *) lfirst(l);
-
-               referenced.classId = ProcedureRelationId;
-               referenced.objectId = proc->object;
-               referenced.objectSubId = 0;
-               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-       }
-
        /* dependency on owner */
        recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
 
@@ -427,139 +616,158 @@ DefineOpClass(CreateOpClassStmt *stmt)
 }
 
 /*
- * Determine the subtype to assign to an operator, and do any validity
- * checking we can manage
- *
- * Currently this is done using hardwired rules; we don't let the user
- * specify it directly.
+ * Determine the lefttype/righttype to assign to an operator,
+ * and do any validity checking we can manage.
  */
-static Oid
-assignOperSubtype(Oid amoid, Oid typeoid, Oid operOid)
+static void
+assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
 {
-       Oid                     subtype;
        Operator        optup;
        Form_pg_operator opform;
 
-       /* Subtypes are currently only supported by btree, others use 0 */
-       if (amoid != BTREE_AM_OID)
-               return InvalidOid;
-
+       /* Fetch the operator definition */
        optup = SearchSysCache(OPEROID,
-                                                  ObjectIdGetDatum(operOid),
+                                                  ObjectIdGetDatum(member->object),
                                                   0, 0, 0);
        if (optup == NULL)
-               elog(ERROR, "cache lookup failed for operator %u", operOid);
+               elog(ERROR, "cache lookup failed for operator %u", member->object);
        opform = (Form_pg_operator) GETSTRUCT(optup);
 
        /*
-        * btree operators must be binary ops returning boolean, and the left-side
-        * input type must match the operator class' input type.
+        * Opfamily operators must be binary ops returning boolean.
         */
        if (opform->oprkind != 'b')
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("btree operators must be binary")));
+                                errmsg("index operators must be binary")));
        if (opform->oprresult != BOOLOID)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("btree operators must return boolean")));
-       if (opform->oprleft != typeoid)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                         errmsg("btree operators must have index type as left input")));
+                                errmsg("index operators must return boolean")));
 
        /*
-        * The subtype is "default" (0) if oprright matches the operator class,
-        * otherwise it is oprright.
+        * If lefttype/righttype isn't specified, use the operator's input types
         */
-       if (opform->oprright == typeoid)
-               subtype = InvalidOid;
-       else
-               subtype = opform->oprright;
+       if (!OidIsValid(member->lefttype))
+               member->lefttype = opform->oprleft;
+       if (!OidIsValid(member->righttype))
+               member->righttype = opform->oprright;
+
        ReleaseSysCache(optup);
-       return subtype;
 }
 
 /*
- * Determine the subtype to assign to a support procedure, and do any validity
- * checking we can manage
- *
- * Currently this is done using hardwired rules; we don't let the user
- * specify it directly.
+ * Determine the lefttype/righttype to assign to a support procedure,
+ * and do any validity checking we can manage.
  */
-static Oid
-assignProcSubtype(Oid amoid, Oid typeoid, Oid procOid)
+static void
+assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
 {
-       Oid                     subtype;
        HeapTuple       proctup;
        Form_pg_proc procform;
 
-       /* Subtypes are currently only supported by btree, others use 0 */
-       if (amoid != BTREE_AM_OID)
-               return InvalidOid;
-
+       /* Fetch the procedure definition */
        proctup = SearchSysCache(PROCOID,
-                                                        ObjectIdGetDatum(procOid),
+                                                        ObjectIdGetDatum(member->object),
                                                         0, 0, 0);
        if (proctup == NULL)
-               elog(ERROR, "cache lookup failed for function %u", procOid);
+               elog(ERROR, "cache lookup failed for function %u", member->object);
        procform = (Form_pg_proc) GETSTRUCT(proctup);
 
        /*
-        * btree support procs must be 2-arg procs returning int4, and the first
-        * input type must match the operator class' input type.
+        * btree support procs must be 2-arg procs returning int4; hash support
+        * procs must be 1-arg procs returning int4; otherwise we don't know.
         */
-       if (procform->pronargs != 2)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("btree procedures must have two arguments")));
-       if (procform->prorettype != INT4OID)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("btree procedures must return integer")));
-       if (procform->proargtypes.values[0] != typeoid)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                       errmsg("btree procedures must have index type as first input")));
+       if (amoid == BTREE_AM_OID)
+       {
+               if (procform->pronargs != 2)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("btree procedures must have two arguments")));
+               if (procform->prorettype != INT4OID)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("btree procedures must return integer")));
 
-       /*
-        * The subtype is "default" (0) if second input type matches the operator
-        * class, otherwise it is the second input type.
-        */
-       if (procform->proargtypes.values[1] == typeoid)
-               subtype = InvalidOid;
+               /*
+                * If lefttype/righttype isn't specified, use the proc's input types
+                */
+               if (!OidIsValid(member->lefttype))
+                       member->lefttype = procform->proargtypes.values[0];
+               if (!OidIsValid(member->righttype))
+                       member->righttype = procform->proargtypes.values[1];
+       }
+       else if (amoid == HASH_AM_OID)
+       {
+               if (procform->pronargs != 1)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("hash procedures must have one argument")));
+               if (procform->prorettype != INT4OID)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("hash procedures must return integer")));
+
+               /*
+                * If lefttype/righttype isn't specified, use the proc's input type
+                */
+               if (!OidIsValid(member->lefttype))
+                       member->lefttype = procform->proargtypes.values[0];
+               if (!OidIsValid(member->righttype))
+                       member->righttype = procform->proargtypes.values[0];
+       }
        else
-               subtype = procform->proargtypes.values[1];
+       {
+               /*
+                * The default for GiST and GIN in CREATE OPERATOR CLASS is to use
+                * the class' opcintype as lefttype and righttype.  In CREATE or
+                * ALTER OPERATOR FAMILY, opcintype isn't available, so make the
+                * user specify the types.
+                */
+               if (!OidIsValid(member->lefttype))
+                       member->lefttype = typeoid;
+               if (!OidIsValid(member->righttype))
+                       member->righttype = typeoid;
+               if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("associated data types must be specified for index support procedure")));
+       }
+
        ReleaseSysCache(proctup);
-       return subtype;
 }
 
 /*
- * Add a new class member to the appropriate list, after checking for
+ * Add a new family member to the appropriate list, after checking for
  * duplicated strategy or proc number.
  */
 static void
-addClassMember(List **list, OpClassMember *member, bool isProc)
+addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
 {
        ListCell   *l;
 
        foreach(l, *list)
        {
-               OpClassMember *old = (OpClassMember *) lfirst(l);
+               OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
 
                if (old->number == member->number &&
-                       old->subtype == member->subtype)
+                       old->lefttype == member->lefttype &&
+                       old->righttype == member->righttype)
                {
                        if (isProc)
                                ereport(ERROR,
                                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                                errmsg("procedure number %d appears more than once",
-                                                               member->number)));
+                                                errmsg("procedure number %d for (%s,%s) appears more than once",
+                                                               member->number,
+                                                               format_type_be(member->lefttype),
+                                                               format_type_be(member->righttype))));
                        else
                                ereport(ERROR,
                                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                                errmsg("operator number %d appears more than once",
-                                                               member->number)));
+                                                errmsg("operator number %d for (%s,%s) appears more than once",
+                                                               member->number,
+                                                               format_type_be(member->lefttype),
+                                                               format_type_be(member->righttype))));
                }
        }
        *list = lappend(*list, member);
@@ -567,43 +775,80 @@ addClassMember(List **list, OpClassMember *member, bool isProc)
 
 /*
  * Dump the operators to pg_amop
+ *
+ * We also make dependency entries in pg_depend for the opfamily entries.
+ * If opclassoid is valid then make an INTERNAL dependency on that opclass,
+ * else make an AUTO dependency on the opfamily.
  */
 static void
-storeOperators(Oid opclassoid, List *operators)
+storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
 {
        Relation        rel;
        Datum           values[Natts_pg_amop];
        char            nulls[Natts_pg_amop];
        HeapTuple       tup;
+       Oid                     entryoid;
+       ObjectAddress myself,
+                               referenced;
        ListCell   *l;
-       int                     i;
 
        rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
 
        foreach(l, operators)
        {
-               OpClassMember *op = (OpClassMember *) lfirst(l);
+               OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
 
-               for (i = 0; i < Natts_pg_amop; ++i)
-               {
-                       nulls[i] = ' ';
-                       values[i] = (Datum) NULL;
-               }
+               /* Create the pg_amop entry */
+               memset(values, 0, sizeof(values));
+               memset(nulls, ' ', sizeof(nulls));
 
-               i = 0;
-               values[i++] = ObjectIdGetDatum(opclassoid);             /* amopclaid */
-               values[i++] = ObjectIdGetDatum(op->subtype);    /* amopsubtype */
-               values[i++] = Int16GetDatum(op->number);                /* amopstrategy */
-               values[i++] = BoolGetDatum(op->recheck);                /* amopreqcheck */
-               values[i++] = ObjectIdGetDatum(op->object);             /* amopopr */
+               values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
+               values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
+               values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
+               values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
+               values[Anum_pg_amop_amopreqcheck - 1] = BoolGetDatum(op->recheck);
+               values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
+               values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
 
                tup = heap_formtuple(rel->rd_att, values, nulls);
 
-               simple_heap_insert(rel, tup);
+               entryoid = simple_heap_insert(rel, tup);
 
                CatalogUpdateIndexes(rel, tup);
 
                heap_freetuple(tup);
+
+               /* Make its dependencies */
+               myself.classId = AccessMethodOperatorRelationId;
+               myself.objectId = entryoid;
+               myself.objectSubId = 0;
+
+               referenced.classId = OperatorRelationId;
+               referenced.objectId = op->object;
+               referenced.objectSubId = 0;
+
+               if (OidIsValid(opclassoid))
+               {
+                       /* if contained in an opclass, use a NORMAL dep on operator */
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+                       /* ... and an INTERNAL dep on the opclass */
+                       referenced.classId = OperatorClassRelationId;
+                       referenced.objectId = opclassoid;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+               }
+               else
+               {
+                       /* if "loose" in the opfamily, use a AUTO dep on operator */
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+
+                       /* ... and an AUTO dep on the opfamily */
+                       referenced.classId = OperatorFamilyRelationId;
+                       referenced.objectId = opfamilyoid;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+               }
        }
 
        heap_close(rel, RowExclusiveLock);
@@ -611,42 +856,78 @@ storeOperators(Oid opclassoid, List *operators)
 
 /*
  * Dump the procedures (support routines) to pg_amproc
+ *
+ * We also make dependency entries in pg_depend for the opfamily entries.
+ * If opclassoid is valid then make an INTERNAL dependency on that opclass,
+ * else make an AUTO dependency on the opfamily.
  */
 static void
-storeProcedures(Oid opclassoid, List *procedures)
+storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
 {
        Relation        rel;
        Datum           values[Natts_pg_amproc];
        char            nulls[Natts_pg_amproc];
        HeapTuple       tup;
+       Oid                     entryoid;
+       ObjectAddress myself,
+                               referenced;
        ListCell   *l;
-       int                     i;
 
        rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
 
        foreach(l, procedures)
        {
-               OpClassMember *proc = (OpClassMember *) lfirst(l);
+               OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
 
-               for (i = 0; i < Natts_pg_amproc; ++i)
-               {
-                       nulls[i] = ' ';
-                       values[i] = (Datum) NULL;
-               }
+               /* Create the pg_amproc entry */
+               memset(values, 0, sizeof(values));
+               memset(nulls, ' ', sizeof(nulls));
 
-               i = 0;
-               values[i++] = ObjectIdGetDatum(opclassoid);             /* amopclaid */
-               values[i++] = ObjectIdGetDatum(proc->subtype);  /* amprocsubtype */
-               values[i++] = Int16GetDatum(proc->number);              /* amprocnum */
-               values[i++] = ObjectIdGetDatum(proc->object);   /* amproc */
+               values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
+               values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
+               values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
+               values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
+               values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
 
                tup = heap_formtuple(rel->rd_att, values, nulls);
 
-               simple_heap_insert(rel, tup);
+               entryoid = simple_heap_insert(rel, tup);
 
                CatalogUpdateIndexes(rel, tup);
 
                heap_freetuple(tup);
+
+               /* Make its dependencies */
+               myself.classId = AccessMethodProcedureRelationId;
+               myself.objectId = entryoid;
+               myself.objectSubId = 0;
+
+               referenced.classId = ProcedureRelationId;
+               referenced.objectId = proc->object;
+               referenced.objectSubId = 0;
+
+               if (OidIsValid(opclassoid))
+               {
+                       /* if contained in an opclass, use a NORMAL dep on procedure */
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+                       /* ... and an INTERNAL dep on the opclass */
+                       referenced.classId = OperatorClassRelationId;
+                       referenced.objectId = opclassoid;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+               }
+               else
+               {
+                       /* if "loose" in the opfamily, use a AUTO dep on procedure */
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+
+                       /* ... and an AUTO dep on the opfamily */
+                       referenced.classId = OperatorFamilyRelationId;
+                       referenced.objectId = opfamilyoid;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+               }
        }
 
        heap_close(rel, RowExclusiveLock);
@@ -662,8 +943,6 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
 {
        Oid                     amID,
                                opcID;
-       char       *schemaname;
-       char       *opcname;
        HeapTuple       tuple;
        ObjectAddress object;
 
@@ -682,49 +961,9 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
        /*
         * Look up the opclass.
         */
-
-       /* deconstruct the name list */
-       DeconstructQualifiedName(stmt->opclassname, &schemaname, &opcname);
-
-       if (schemaname)
-       {
-               /* Look in specific schema only */
-               Oid                     namespaceId;
-
-               namespaceId = LookupExplicitNamespace(schemaname);
-               tuple = SearchSysCache(CLAAMNAMENSP,
-                                                          ObjectIdGetDatum(amID),
-                                                          PointerGetDatum(opcname),
-                                                          ObjectIdGetDatum(namespaceId),
-                                                          0);
-       }
-       else
-       {
-               /* Unqualified opclass name, so search the search path */
-               opcID = OpclassnameGetOpcid(amID, opcname);
-               if (!OidIsValid(opcID))
-               {
-                       if (!stmt->missing_ok)
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                                errmsg("operator class \"%s\" does not exist for access method \"%s\"",
-                                                               opcname, stmt->amname)));
-                       else
-                               ereport(NOTICE,
-                                               (errmsg("operator class \"%s\" does not exist for access method \"%s\"",
-                                                               opcname, stmt->amname)));
-
-                       return;
-               }
-
-               tuple = SearchSysCache(CLAOID,
-                                                          ObjectIdGetDatum(opcID),
-                                                          0, 0, 0);
-       }
-
+       tuple = OpClassCacheLookup(amID, stmt->opclassname);
        if (!HeapTupleIsValid(tuple))
        {
-
                if (!stmt->missing_ok)
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -759,19 +998,35 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
 }
 
 /*
- * Guts of opclass deletion.
+ * Deletion subroutines for use by dependency.c.
  */
+void
+RemoveOpFamilyById(Oid opfamilyOid)
+{
+       Relation        rel;
+       HeapTuple       tup;
+
+       rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+
+       tup = SearchSysCache(OPFAMILYOID,
+                                                ObjectIdGetDatum(opfamilyOid),
+                                                0, 0, 0);
+       if (!HeapTupleIsValid(tup)) /* should not happen */
+               elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+
+       simple_heap_delete(rel, &tup->t_self);
+
+       ReleaseSysCache(tup);
+
+       heap_close(rel, RowExclusiveLock);
+}
+
 void
 RemoveOpClassById(Oid opclassOid)
 {
        Relation        rel;
        HeapTuple       tup;
-       ScanKeyData skey[1];
-       SysScanDesc scan;
 
-       /*
-        * First remove the pg_opclass entry itself.
-        */
        rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
 
        tup = SearchSysCache(CLAOID,
@@ -785,41 +1040,61 @@ RemoveOpClassById(Oid opclassOid)
        ReleaseSysCache(tup);
 
        heap_close(rel, RowExclusiveLock);
+}
+
+void
+RemoveAmOpEntryById(Oid entryOid)
+{
+       Relation        rel;
+       HeapTuple       tup;
+       ScanKeyData skey[1];
+       SysScanDesc scan;
 
-       /*
-        * Remove associated entries in pg_amop.
-        */
        ScanKeyInit(&skey[0],
-                               Anum_pg_amop_amopclaid,
+                               ObjectIdAttributeNumber,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(opclassOid));
+                               ObjectIdGetDatum(entryOid));
 
        rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
 
-       scan = systable_beginscan(rel, AccessMethodStrategyIndexId, true,
+       scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
                                                          SnapshotNow, 1, skey);
 
-       while (HeapTupleIsValid(tup = systable_getnext(scan)))
-               simple_heap_delete(rel, &tup->t_self);
+       /* we expect exactly one match */
+       tup = systable_getnext(scan);
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "could not find tuple for amop entry %u", entryOid);
+
+       simple_heap_delete(rel, &tup->t_self);
 
        systable_endscan(scan);
        heap_close(rel, RowExclusiveLock);
+}
+
+void
+RemoveAmProcEntryById(Oid entryOid)
+{
+       Relation        rel;
+       HeapTuple       tup;
+       ScanKeyData skey[1];
+       SysScanDesc scan;
 
-       /*
-        * Remove associated entries in pg_amproc.
-        */
        ScanKeyInit(&skey[0],
-                               Anum_pg_amproc_amopclaid,
+                               ObjectIdAttributeNumber,
                                BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(opclassOid));
+                               ObjectIdGetDatum(entryOid));
 
        rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
 
-       scan = systable_beginscan(rel, AccessMethodProcedureIndexId, true,
+       scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
                                                          SnapshotNow, 1, skey);
 
-       while (HeapTupleIsValid(tup = systable_getnext(scan)))
-               simple_heap_delete(rel, &tup->t_self);
+       /* we expect exactly one match */
+       tup = systable_getnext(scan);
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
+
+       simple_heap_delete(rel, &tup->t_self);
 
        systable_endscan(scan);
        heap_close(rel, RowExclusiveLock);
@@ -1022,7 +1297,7 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
 
 /*
  * The first parameter is pg_opclass, opened and suitably locked.  The second
- * parameter is the tuple from pg_opclass we want to modify.
+ * parameter is a copy of the tuple from pg_opclass we want to modify.
  */
 static void
 AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
index 76884e8cd82ce1e40fd27265c6202f7c9bb5154e..a84feee2a717b23f583eb1c2de67f565094b4aa4 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.33 2006/10/04 00:29:51 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.34 2006/12/23 00:43:09 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -64,8 +64,8 @@ DefineOperator(List *names, List *parameters)
        char       *oprName;
        Oid                     oprNamespace;
        AclResult       aclresult;
-       bool            canHash = false;        /* operator hashes */
        bool            canMerge = false;               /* operator merges */
+       bool            canHash = false;                /* operator hashes */
        List       *functionName = NIL;         /* function for operator */
        TypeName   *typeName1 = NULL;           /* first type name */
        TypeName   *typeName2 = NULL;           /* second type name */
@@ -75,10 +75,6 @@ DefineOperator(List *names, List *parameters)
        List       *negatorName = NIL;          /* optional negator operator name */
        List       *restrictionName = NIL;      /* optional restrict. sel. procedure */
        List       *joinName = NIL; /* optional join sel. procedure */
-       List       *leftSortName = NIL;         /* optional left sort operator */
-       List       *rightSortName = NIL;        /* optional right sort operator */
-       List       *ltCompareName = NIL;        /* optional < compare operator */
-       List       *gtCompareName = NIL;        /* optional > compare operator */
        ListCell   *pl;
 
        /* Convert list of names to a name and namespace */
@@ -127,14 +123,15 @@ DefineOperator(List *names, List *parameters)
                        canHash = defGetBoolean(defel);
                else if (pg_strcasecmp(defel->defname, "merges") == 0)
                        canMerge = defGetBoolean(defel);
+               /* These obsolete options are taken as meaning canMerge */
                else if (pg_strcasecmp(defel->defname, "sort1") == 0)
-                       leftSortName = defGetQualifiedName(defel);
+                       canMerge = true;
                else if (pg_strcasecmp(defel->defname, "sort2") == 0)
-                       rightSortName = defGetQualifiedName(defel);
+                       canMerge = true;
                else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
-                       ltCompareName = defGetQualifiedName(defel);
+                       canMerge = true;
                else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
-                       gtCompareName = defGetQualifiedName(defel);
+                       canMerge = true;
                else
                        ereport(WARNING,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
@@ -156,26 +153,6 @@ DefineOperator(List *names, List *parameters)
        if (typeName2)
                typeId2 = typenameTypeId(NULL, typeName2);
 
-       /*
-        * If any of the mergejoin support operators were given, then canMerge is
-        * implicit.  If canMerge is specified or implicit, fill in default
-        * operator names for any missing mergejoin support operators.
-        */
-       if (leftSortName || rightSortName || ltCompareName || gtCompareName)
-               canMerge = true;
-
-       if (canMerge)
-       {
-               if (!leftSortName)
-                       leftSortName = list_make1(makeString("<"));
-               if (!rightSortName)
-                       rightSortName = list_make1(makeString("<"));
-               if (!ltCompareName)
-                       ltCompareName = list_make1(makeString("<"));
-               if (!gtCompareName)
-                       gtCompareName = list_make1(makeString(">"));
-       }
-
        /*
         * now have OperatorCreate do all the work..
         */
@@ -188,11 +165,8 @@ DefineOperator(List *names, List *parameters)
                                   negatorName, /* optional negator operator name */
                                   restrictionName,             /* optional restrict. sel. procedure */
                                   joinName,    /* optional join sel. procedure name */
-                                  canHash,             /* operator hashes */
-                                  leftSortName,        /* optional left sort operator */
-                                  rightSortName,               /* optional right sort operator */
-                                  ltCompareName,               /* optional < comparison op */
-                                  gtCompareName);              /* optional < comparison op */
+                                  canMerge,    /* operator merges */
+                                  canHash);    /* operator hashes */
 }
 
 
index ea80c4e8286c8463aa9e3a466d68b542b03174eb..2a1116f75800c66d238f9caa694f8a474130527b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.206 2006/10/13 21:43:18 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.207 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4145,7 +4145,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
                 * generate a warning if not, since otherwise costly seqscans will be
                 * incurred to check FK validity.
                 */
-               if (!op_in_opclass(oprid(o), opclasses[i]))
+               if (!op_in_opfamily(oprid(o), get_opclass_family(opclasses[i])))
                        ereport(WARNING,
                                        (errmsg("foreign key constraint \"%s\" "
                                                        "will require costly sequential scans",
index 10b02b4a3ec92ded44c37d54e9294f8138a66941..1e9865c300755d6c3998eb12d15a62d0b66f67c7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.200 2006/12/21 16:05:13 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.201 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3700,21 +3700,28 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                        outlist = lappend(outlist, estate);
                                }
                                rstate->rargs = outlist;
-                               Assert(list_length(rcexpr->opclasses) == nopers);
+                               Assert(list_length(rcexpr->opfamilies) == nopers);
                                rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
                                i = 0;
-                               forboth(l, rcexpr->opnos, l2, rcexpr->opclasses)
+                               forboth(l, rcexpr->opnos, l2, rcexpr->opfamilies)
                                {
                                        Oid                     opno = lfirst_oid(l);
-                                       Oid                     opclass = lfirst_oid(l2);
+                                       Oid                     opfamily = lfirst_oid(l2);
                                        int                     strategy;
-                                       Oid                     subtype;
+                                       Oid                     lefttype;
+                                       Oid                     righttype;
                                        bool            recheck;
                                        Oid                     proc;
 
-                                       get_op_opclass_properties(opno, opclass,
-                                                                                         &strategy, &subtype, &recheck);
-                                       proc = get_opclass_proc(opclass, subtype, BTORDER_PROC);
+                                       get_op_opfamily_properties(opno, opfamily,
+                                                                                          &strategy,
+                                                                                          &lefttype,
+                                                                                          &righttype,
+                                                                                          &recheck);
+                                       proc = get_opfamily_proc(opfamily,
+                                                                                        lefttype,
+                                                                                        righttype,
+                                                                                        BTORDER_PROC);
 
                                        /*
                                         * If we enforced permissions checks on index support
index 9773f2341ec78eda88b6fceb7a09c0ea1fe6fbe0..4371fc1a280d02295db6ba5a4bb0ad6b72c0115b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.117 2006/10/04 00:29:52 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.118 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -797,9 +797,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
                                int                     flags = SK_ROW_MEMBER;
                                Datum           scanvalue;
                                Oid                     opno;
-                               Oid                     opclass;
+                               Oid                     opfamily;
                                int                     op_strategy;
-                               Oid                     op_subtype;
+                               Oid                     op_lefttype;
+                               Oid                     op_righttype;
                                bool            op_recheck;
 
                                /*
@@ -857,15 +858,21 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
                                if (index->rd_rel->relam != BTREE_AM_OID ||
                                        varattno < 1 || varattno > index->rd_index->indnatts)
                                        elog(ERROR, "bogus RowCompare index qualification");
-                               opclass = index->rd_indclass->values[varattno - 1];
+                               opfamily = index->rd_opfamily[varattno - 1];
 
-                               get_op_opclass_properties(opno, opclass,
-                                                                        &op_strategy, &op_subtype, &op_recheck);
+                               get_op_opfamily_properties(opno, opfamily,
+                                                                                  &op_strategy,
+                                                                                  &op_lefttype,
+                                                                                  &op_righttype,
+                                                                                  &op_recheck);
 
                                if (op_strategy != rc->rctype)
                                        elog(ERROR, "RowCompare index qualification contains wrong operator");
 
-                               opfuncid = get_opclass_proc(opclass, op_subtype, BTORDER_PROC);
+                               opfuncid = get_opfamily_proc(opfamily,
+                                                                                        op_lefttype,
+                                                                                        op_righttype,
+                                                                                        BTORDER_PROC);
 
                                /*
                                 * initialize the subsidiary scan key's fields appropriately
@@ -874,7 +881,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
                                                                           flags,
                                                                           varattno,            /* attribute number */
                                                                           op_strategy,         /* op's strategy */
-                                                                          op_subtype,          /* strategy subtype */
+                                                                          op_righttype,        /* strategy subtype */
                                                                           opfuncid,            /* reg proc to use */
                                                                           scanvalue);          /* constant */
                                extra_scan_keys++;
index 8a9f6fe230061804f970c1a57b89dff391f4e557..97824920d6397566e9dc89d861b59f44735d60a4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.82 2006/10/04 00:29:52 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.83 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * Comparison strategies supported by MJCompare
  *
- * XXX eventually should extend these to support descending-order sorts.
+ * XXX eventually should extend MJCompare to support descending-order sorts.
  * There are some tricky issues however about being sure we are on the same
  * page as the underlying sort or index as to which end NULLs sort to.
  */
 typedef enum
 {
-       MERGEFUNC_LT,                           /* raw "<" operator */
-       MERGEFUNC_CMP                           /* -1 / 0 / 1 three-way comparator */
+       MERGEFUNC_CMP,                          /* -1 / 0 / 1 three-way comparator */
+       MERGEFUNC_REV_CMP                       /* same, reversing the sense of the result */
 } MergeFunctionKind;
 
 /* Runtime data for each mergejoin clause */
@@ -132,20 +132,11 @@ typedef struct MergeJoinClauseData
        bool            lisnull;                /* and their isnull flags */
        bool            risnull;
 
-       /*
-        * Remember whether mergejoin operator is strict (usually it will be).
-        * NOTE: if it's not strict, we still assume it cannot return true for one
-        * null and one non-null input.
-        */
-       bool            mergestrict;
-
        /*
         * The comparison strategy in use, and the lookup info to let us call the
-        * needed comparison routines.  eqfinfo is the "=" operator itself.
-        * cmpfinfo is either the btree comparator or the "<" operator.
+        * btree comparison support function.
         */
        MergeFunctionKind cmpstrategy;
-       FmgrInfo        eqfinfo;
        FmgrInfo        cmpfinfo;
 } MergeJoinClauseData;
 
@@ -164,34 +155,51 @@ typedef struct MergeJoinClauseData
  * we will need at runtime.  Each struct essentially tells us how to compare
  * the two expressions from the original clause.
  *
- * The best, most efficient way to compare two expressions is to use a btree
- * comparison support routine, since that requires only one function call
- * per comparison.     Hence we try to find a btree opclass that matches the
- * mergejoinable operator.     If we cannot find one, we'll have to call both
- * the "=" and (often) the "<" operator for each comparison.
+ * In addition to the expressions themselves, the planner passes the btree
+ * opfamily OID and btree strategy number (BTLessStrategyNumber or
+ * BTGreaterStrategyNumber) that identify the intended merge semantics for
+ * each merge key.  The mergejoinable operator is an equality operator in
+ * this opfamily, and the two inputs are guaranteed to be ordered in either
+ * increasing or decreasing (respectively) order according to this opfamily.
+ * This allows us to obtain the needed comparison functions from the opfamily.
  */
 static MergeJoinClause
-MJExamineQuals(List *qualList, PlanState *parent)
+MJExamineQuals(List *mergeclauses, List *mergefamilies, List *mergestrategies,
+                          PlanState *parent)
 {
        MergeJoinClause clauses;
-       int                     nClauses = list_length(qualList);
+       int                     nClauses = list_length(mergeclauses);
        int                     iClause;
-       ListCell   *l;
+       ListCell   *cl;
+       ListCell   *cf;
+       ListCell   *cs;
 
        clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData));
 
        iClause = 0;
-       foreach(l, qualList)
+       cf = list_head(mergefamilies);
+       cs = list_head(mergestrategies);
+       foreach(cl, mergeclauses)
        {
-               OpExpr     *qual = (OpExpr *) lfirst(l);
+               OpExpr     *qual = (OpExpr *) lfirst(cl);
                MergeJoinClause clause = &clauses[iClause];
-               Oid                     ltop;
-               Oid                     gtop;
-               RegProcedure ltproc;
-               RegProcedure gtproc;
+               Oid                     opfamily;
+               StrategyNumber opstrategy;
+               int                     op_strategy;
+               Oid                     op_lefttype;
+               Oid                     op_righttype;
+               bool            op_recheck;
+               RegProcedure cmpproc;
                AclResult       aclresult;
-               CatCList   *catlist;
-               int                     i;
+
+               opfamily = lfirst_oid(cf);
+               cf = lnext(cf);
+               opstrategy = lfirst_int(cs);
+               cs = lnext(cs);
+
+               /* Later we'll support both ascending and descending sort... */
+               Assert(opstrategy == BTLessStrategyNumber);
+               clause->cmpstrategy = MERGEFUNC_CMP;
 
                if (!IsA(qual, OpExpr))
                        elog(ERROR, "mergejoin clause is not an OpExpr");
@@ -202,77 +210,30 @@ MJExamineQuals(List *qualList, PlanState *parent)
                clause->lexpr = ExecInitExpr((Expr *) linitial(qual->args), parent);
                clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
 
-               /*
-                * Check permission to call the mergejoinable operator. For
-                * predictability, we check this even if we end up not using it.
-                */
-               aclresult = pg_proc_aclcheck(qual->opfuncid, GetUserId(), ACL_EXECUTE);
-               if (aclresult != ACLCHECK_OK)
-                       aclcheck_error(aclresult, ACL_KIND_PROC,
-                                                  get_func_name(qual->opfuncid));
-
-               /* Set up the fmgr lookup information */
-               fmgr_info(qual->opfuncid, &(clause->eqfinfo));
-
-               /* And remember strictness */
-               clause->mergestrict = clause->eqfinfo.fn_strict;
-
-               /*
-                * Lookup the comparison operators that go with the mergejoinable
-                * top-level operator.  (This will elog if the operator isn't
-                * mergejoinable, which would be the planner's mistake.)
-                */
-               op_mergejoin_crossops(qual->opno,
-                                                         &ltop,
-                                                         &gtop,
-                                                         &ltproc,
-                                                         &gtproc);
-
-               clause->cmpstrategy = MERGEFUNC_LT;
-
-               /*
-                * Look for a btree opclass including all three operators. This is
-                * much like SelectSortFunction except we insist on matching all the
-                * operators provided, and it can be a cross-type opclass.
-                *
-                * XXX for now, insist on forward sort so that NULLs can be counted on
-                * to be high.
-                */
-               catlist = SearchSysCacheList(AMOPOPID, 1,
-                                                                        ObjectIdGetDatum(qual->opno),
-                                                                        0, 0, 0);
-
-               for (i = 0; i < catlist->n_members; i++)
-               {
-                       HeapTuple       tuple = &catlist->members[i]->tuple;
-                       Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
-                       Oid                     opcid = aform->amopclaid;
-
-                       if (aform->amopstrategy != BTEqualStrategyNumber)
-                               continue;
-                       if (!opclass_is_btree(opcid))
-                               continue;
-                       if (get_op_opclass_strategy(ltop, opcid) == BTLessStrategyNumber &&
-                        get_op_opclass_strategy(gtop, opcid) == BTGreaterStrategyNumber)
-                       {
-                               clause->cmpstrategy = MERGEFUNC_CMP;
-                               ltproc = get_opclass_proc(opcid, aform->amopsubtype,
-                                                                                 BTORDER_PROC);
-                               Assert(RegProcedureIsValid(ltproc));
-                               break;                  /* done looking */
-                       }
-               }
-
-               ReleaseSysCacheList(catlist);
-
-               /* Check permission to call "<" operator or cmp function */
-               aclresult = pg_proc_aclcheck(ltproc, GetUserId(), ACL_EXECUTE);
+               /* Extract the operator's declared left/right datatypes */
+               get_op_opfamily_properties(qual->opno, opfamily,
+                                                                  &op_strategy,
+                                                                  &op_lefttype,
+                                                                  &op_righttype,
+                                                                  &op_recheck);
+               Assert(op_strategy == BTEqualStrategyNumber);
+               Assert(!op_recheck);
+
+               /* And get the matching support procedure (comparison function) */
+               cmpproc = get_opfamily_proc(opfamily,
+                                                                       op_lefttype,
+                                                                       op_righttype,
+                                                                       BTORDER_PROC);
+               Assert(RegProcedureIsValid(cmpproc));
+
+               /* Check permission to call cmp function */
+               aclresult = pg_proc_aclcheck(cmpproc, GetUserId(), ACL_EXECUTE);
                if (aclresult != ACLCHECK_OK)
                        aclcheck_error(aclresult, ACL_KIND_PROC,
-                                                  get_func_name(ltproc));
+                                                  get_func_name(cmpproc));
 
                /* Set up the fmgr lookup information */
-               fmgr_info(ltproc, &(clause->cmpfinfo));
+               fmgr_info(cmpproc, &(clause->cmpfinfo));
 
                iClause++;
        }
@@ -286,7 +247,7 @@ MJExamineQuals(List *qualList, PlanState *parent)
  * Compute the values of the mergejoined expressions for the current
  * outer tuple.  We also detect whether it's impossible for the current
  * outer tuple to match anything --- this is true if it yields a NULL
- * input for any strict mergejoin operator.
+ * input, since we assume mergejoin operators are strict.
  *
  * We evaluate the values in OuterEContext, which can be reset each
  * time we move to a new tuple.
@@ -311,7 +272,7 @@ MJEvalOuterValues(MergeJoinState *mergestate)
 
                clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
                                                                          &clause->lisnull, NULL);
-               if (clause->lisnull && clause->mergestrict)
+               if (clause->lisnull)
                        canmatch = false;
        }
 
@@ -347,7 +308,7 @@ MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
 
                clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
                                                                          &clause->risnull, NULL);
-               if (clause->risnull && clause->mergestrict)
+               if (clause->risnull)
                        canmatch = false;
        }
 
@@ -391,32 +352,11 @@ MJCompare(MergeJoinState *mergestate)
 
                /*
                 * Deal with null inputs.  We treat NULL as sorting after non-NULL.
-                *
-                * If both inputs are NULL, and the comparison function isn't strict,
-                * then we call it and check for a true result (this allows operators
-                * that behave like IS NOT DISTINCT to be mergejoinable). If the
-                * function is strict or returns false, we temporarily pretend NULL ==
-                * NULL and contine checking remaining columns.
                 */
                if (clause->lisnull)
                {
                        if (clause->risnull)
                        {
-                               if (!clause->eqfinfo.fn_strict)
-                               {
-                                       InitFunctionCallInfoData(fcinfo, &(clause->eqfinfo), 2,
-                                                                                        NULL, NULL);
-                                       fcinfo.arg[0] = clause->ldatum;
-                                       fcinfo.arg[1] = clause->rdatum;
-                                       fcinfo.argnull[0] = true;
-                                       fcinfo.argnull[1] = true;
-                                       fresult = FunctionCallInvoke(&fcinfo);
-                                       if (!fcinfo.isnull && DatumGetBool(fresult))
-                                       {
-                                               /* treat nulls as really equal */
-                                               continue;
-                                       }
-                               }
                                nulleqnull = true;
                                continue;
                        }
@@ -431,38 +371,26 @@ MJCompare(MergeJoinState *mergestate)
                        break;
                }
 
-               if (clause->cmpstrategy == MERGEFUNC_LT)
+               InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
+                                                                NULL, NULL);
+               fcinfo.arg[0] = clause->ldatum;
+               fcinfo.arg[1] = clause->rdatum;
+               fcinfo.argnull[0] = false;
+               fcinfo.argnull[1] = false;
+               fresult = FunctionCallInvoke(&fcinfo);
+               if (fcinfo.isnull)
                {
-                       InitFunctionCallInfoData(fcinfo, &(clause->eqfinfo), 2,
-                                                                        NULL, NULL);
-                       fcinfo.arg[0] = clause->ldatum;
-                       fcinfo.arg[1] = clause->rdatum;
-                       fcinfo.argnull[0] = false;
-                       fcinfo.argnull[1] = false;
-                       fresult = FunctionCallInvoke(&fcinfo);
-                       if (fcinfo.isnull)
-                       {
-                               nulleqnull = true;
-                               continue;
-                       }
-                       else if (DatumGetBool(fresult))
-                       {
-                               /* equal */
-                               continue;
-                       }
-                       InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
-                                                                        NULL, NULL);
-                       fcinfo.arg[0] = clause->ldatum;
-                       fcinfo.arg[1] = clause->rdatum;
-                       fcinfo.argnull[0] = false;
-                       fcinfo.argnull[1] = false;
-                       fresult = FunctionCallInvoke(&fcinfo);
-                       if (fcinfo.isnull)
-                       {
-                               nulleqnull = true;
-                               continue;
-                       }
-                       else if (DatumGetBool(fresult))
+                       nulleqnull = true;
+                       continue;
+               }
+               if (DatumGetInt32(fresult) == 0)
+               {
+                       /* equal */
+                       continue;
+               }
+               if (clause->cmpstrategy == MERGEFUNC_CMP)
+               {
+                       if (DatumGetInt32(fresult) < 0)
                        {
                                /* less than */
                                result = -1;
@@ -476,26 +404,9 @@ MJCompare(MergeJoinState *mergestate)
                        }
                }
                else
-                       /* must be MERGEFUNC_CMP */
                {
-                       InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
-                                                                        NULL, NULL);
-                       fcinfo.arg[0] = clause->ldatum;
-                       fcinfo.arg[1] = clause->rdatum;
-                       fcinfo.argnull[0] = false;
-                       fcinfo.argnull[1] = false;
-                       fresult = FunctionCallInvoke(&fcinfo);
-                       if (fcinfo.isnull)
-                       {
-                               nulleqnull = true;
-                               continue;
-                       }
-                       else if (DatumGetInt32(fresult) == 0)
-                       {
-                               /* equal */
-                               continue;
-                       }
-                       else if (DatumGetInt32(fresult) < 0)
+                       /* reverse the sort order */
+                       if (DatumGetInt32(fresult) > 0)
                        {
                                /* less than */
                                result = -1;
@@ -1614,6 +1525,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
         */
        mergestate->mj_NumClauses = list_length(node->mergeclauses);
        mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
+                                                                                       node->mergefamilies,
+                                                                                       node->mergestrategies,
                                                                                        (PlanState *) mergestate);
 
        /*
index 3bb95b658d18c7afbb8e9a9e768790b71018f83d..ca841cb181aaed174ed03f1aa83970da5198d0b3 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.355 2006/12/21 16:05:13 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.356 2006/12/23 00:43:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -449,6 +449,8 @@ _copyMergeJoin(MergeJoin *from)
         * copy remainder of node
         */
        COPY_NODE_FIELD(mergeclauses);
+       COPY_NODE_FIELD(mergefamilies);
+       COPY_NODE_FIELD(mergestrategies);
 
        return newnode;
 }
@@ -1055,7 +1057,7 @@ _copyRowCompareExpr(RowCompareExpr *from)
 
        COPY_SCALAR_FIELD(rctype);
        COPY_NODE_FIELD(opnos);
-       COPY_NODE_FIELD(opclasses);
+       COPY_NODE_FIELD(opfamilies);
        COPY_NODE_FIELD(largs);
        COPY_NODE_FIELD(rargs);
 
@@ -1307,6 +1309,7 @@ _copyRestrictInfo(RestrictInfo *from)
        COPY_SCALAR_FIELD(mergejoinoperator);
        COPY_SCALAR_FIELD(left_sortop);
        COPY_SCALAR_FIELD(right_sortop);
+       COPY_SCALAR_FIELD(mergeopfamily);
 
        /*
         * Do not copy pathkeys, since they'd not be canonical in a copied query
@@ -2291,6 +2294,7 @@ _copyCreateOpClassStmt(CreateOpClassStmt *from)
        CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
 
        COPY_NODE_FIELD(opclassname);
+       COPY_NODE_FIELD(opfamilyname);
        COPY_STRING_FIELD(amname);
        COPY_NODE_FIELD(datatype);
        COPY_NODE_FIELD(items);
index ef21e67fafb7966271d02c32c35795b797608daa..a7c4ef4e2a819e5838176bf382ff7752088d5bd4 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.289 2006/12/21 16:05:13 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.290 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -428,7 +428,7 @@ _equalRowCompareExpr(RowCompareExpr *a, RowCompareExpr *b)
 {
        COMPARE_SCALAR_FIELD(rctype);
        COMPARE_NODE_FIELD(opnos);
-       COMPARE_NODE_FIELD(opclasses);
+       COMPARE_NODE_FIELD(opfamilies);
        COMPARE_NODE_FIELD(largs);
        COMPARE_NODE_FIELD(rargs);
 
@@ -1163,6 +1163,7 @@ static bool
 _equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
 {
        COMPARE_NODE_FIELD(opclassname);
+       COMPARE_NODE_FIELD(opfamilyname);
        COMPARE_STRING_FIELD(amname);
        COMPARE_NODE_FIELD(datatype);
        COMPARE_NODE_FIELD(items);
index 5ddf60dbbb1ea1e8d6bcd8ad38626865086df6bd..b18b6988cfa776163141f877c8b570eaf6ae52c5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.287 2006/12/21 16:05:13 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.288 2006/12/23 00:43:10 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -442,6 +442,8 @@ _outMergeJoin(StringInfo str, MergeJoin *node)
        _outJoinPlanInfo(str, (Join *) node);
 
        WRITE_NODE_FIELD(mergeclauses);
+       WRITE_NODE_FIELD(mergefamilies);
+       WRITE_NODE_FIELD(mergestrategies);
 }
 
 static void
@@ -866,7 +868,7 @@ _outRowCompareExpr(StringInfo str, RowCompareExpr *node)
 
        WRITE_ENUM_FIELD(rctype, RowCompareType);
        WRITE_NODE_FIELD(opnos);
-       WRITE_NODE_FIELD(opclasses);
+       WRITE_NODE_FIELD(opfamilies);
        WRITE_NODE_FIELD(largs);
        WRITE_NODE_FIELD(rargs);
 }
@@ -1167,6 +1169,8 @@ _outMergePath(StringInfo str, MergePath *node)
        _outJoinPathInfo(str, (JoinPath *) node);
 
        WRITE_NODE_FIELD(path_mergeclauses);
+       WRITE_NODE_FIELD(path_mergefamilies);
+       WRITE_NODE_FIELD(path_mergestrategies);
        WRITE_NODE_FIELD(outersortkeys);
        WRITE_NODE_FIELD(innersortkeys);
 }
@@ -1281,6 +1285,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
        WRITE_OID_FIELD(mergejoinoperator);
        WRITE_OID_FIELD(left_sortop);
        WRITE_OID_FIELD(right_sortop);
+       WRITE_OID_FIELD(mergeopfamily);
        WRITE_NODE_FIELD(left_pathkey);
        WRITE_NODE_FIELD(right_pathkey);
        WRITE_OID_FIELD(hashjoinoperator);
index 689cef3edf25f175c6ed88657663b1610362168e..37b39439eb0d4f69066b5c5525f0497d654e38cb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.197 2006/12/21 16:05:13 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.198 2006/12/23 00:43:10 tgl Exp $
  *
  * NOTES
  *       Path and Plan nodes do not have any readfuncs support, because we
@@ -672,7 +672,7 @@ _readRowCompareExpr(void)
 
        READ_ENUM_FIELD(rctype, RowCompareType);
        READ_NODE_FIELD(opnos);
-       READ_NODE_FIELD(opclasses);
+       READ_NODE_FIELD(opfamilies);
        READ_NODE_FIELD(largs);
        READ_NODE_FIELD(rargs);
 
index 71685643efa0367cf664e6fe848409a1f5459a70..fbcf7d2b5f54a1986198640626d628f93d8965ae 100644 (file)
@@ -54,7 +54,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.170 2006/12/15 18:42:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.171 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1258,6 +1258,8 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
        Path       *outer_path = path->jpath.outerjoinpath;
        Path       *inner_path = path->jpath.innerjoinpath;
        List       *mergeclauses = path->path_mergeclauses;
+       List       *mergefamilies = path->path_mergefamilies;
+       List       *mergestrategies = path->path_mergestrategies;
        List       *outersortkeys = path->outersortkeys;
        List       *innersortkeys = path->innersortkeys;
        Cost            startup_cost = 0;
@@ -1347,13 +1349,16 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
         *
         * Since this calculation is somewhat expensive, and will be the same for
         * all mergejoin paths associated with the merge clause, we cache the
-        * results in the RestrictInfo node.
+        * results in the RestrictInfo node.  XXX that won't work anymore once
+        * we support multiple possible orderings!
         */
        if (mergeclauses && path->jpath.jointype != JOIN_FULL)
        {
                firstclause = (RestrictInfo *) linitial(mergeclauses);
                if (firstclause->left_mergescansel < 0) /* not computed yet? */
                        mergejoinscansel(root, (Node *) firstclause->clause,
+                                                        linitial_oid(mergefamilies),
+                                                        linitial_int(mergestrategies),
                                                         &firstclause->left_mergescansel,
                                                         &firstclause->right_mergescansel);
 
index b15affa54d5a331ac34128e3982ea6feb1e60805..af081b82c8e6c49a9464f568f2893bc60129e3b1 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.212 2006/10/04 00:29:54 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.213 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,8 +19,8 @@
 
 #include "access/skey.h"
 #include "catalog/pg_am.h"
-#include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 /*
  * DoneMatchingIndexKeys() - MACRO
  */
-#define DoneMatchingIndexKeys(classes) (classes[0] == InvalidOid)
+#define DoneMatchingIndexKeys(families)        (families[0] == InvalidOid)
 
-#define IsBooleanOpclass(opclass) \
-       ((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
+#define IsBooleanOpfamily(opfamily) \
+       ((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
 
 
 static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
@@ -61,15 +61,15 @@ static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,
 static List *pull_indexpath_quals(Path *bitmapqual);
 static bool lists_intersect_ptr(List *list1, List *list2);
 static bool match_clause_to_indexcol(IndexOptInfo *index,
-                                                int indexcol, Oid opclass,
+                                                int indexcol, Oid opfamily,
                                                 RestrictInfo *rinfo,
                                                 Relids outer_relids,
                                                 SaOpControl saop_control);
-static bool is_indexable_operator(Oid expr_op, Oid opclass,
+static bool is_indexable_operator(Oid expr_op, Oid opfamily,
                                          bool indexkey_on_left);
 static bool match_rowcompare_to_indexcol(IndexOptInfo *index,
                                                         int indexcol,
-                                                        Oid opclass,
+                                                        Oid opfamily,
                                                         RowCompareExpr *clause,
                                                         Relids outer_relids);
 static Relids indexable_outerrelids(RelOptInfo *rel);
@@ -89,17 +89,17 @@ static bool match_index_to_query_keys(PlannerInfo *root,
                                                  List *ignorables);
 static bool match_boolean_index_clause(Node *clause, int indexcol,
                                                   IndexOptInfo *index);
-static bool match_special_index_operator(Expr *clause, Oid opclass,
+static bool match_special_index_operator(Expr *clause, Oid opfamily,
                                                         bool indexkey_on_left);
 static Expr *expand_boolean_index_clause(Node *clause, int indexcol,
                                                        IndexOptInfo *index);
-static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass);
+static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily);
 static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo,
                                                        IndexOptInfo *index,
                                                        int indexcol);
-static List *prefix_quals(Node *leftop, Oid opclass,
+static List *prefix_quals(Node *leftop, Oid opfamily,
                         Const *prefix, Pattern_Prefix_Status pstatus);
-static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass,
+static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily,
                                         Datum rightop);
 static Datum string_to_datum(const char *str, Oid datatype);
 static Const *string_to_const(const char *str, Oid datatype);
@@ -858,7 +858,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
        List       *clausegroup_list = NIL;
        bool            found_outer_clause = false;
        int                     indexcol = 0;
-       Oid                *classes = index->classlist;
+       Oid                *families = index->opfamily;
 
        *found_clause = false;          /* default result */
 
@@ -867,7 +867,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
 
        do
        {
-               Oid                     curClass = classes[0];
+               Oid                     curFamily = families[0];
                List       *clausegroup = NIL;
                ListCell   *l;
 
@@ -879,7 +879,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
                        Assert(IsA(rinfo, RestrictInfo));
                        if (match_clause_to_indexcol(index,
                                                                                 indexcol,
-                                                                                curClass,
+                                                                                curFamily,
                                                                                 rinfo,
                                                                                 outer_relids,
                                                                                 saop_control))
@@ -899,7 +899,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
                        Assert(IsA(rinfo, RestrictInfo));
                        if (match_clause_to_indexcol(index,
                                                                                 indexcol,
-                                                                                curClass,
+                                                                                curFamily,
                                                                                 rinfo,
                                                                                 outer_relids,
                                                                                 saop_control))
@@ -918,9 +918,9 @@ group_clauses_by_indexkey(IndexOptInfo *index,
                clausegroup_list = lappend(clausegroup_list, clausegroup);
 
                indexcol++;
-               classes++;
+               families++;
 
-       } while (!DoneMatchingIndexKeys(classes));
+       } while (!DoneMatchingIndexKeys(families));
 
        if (!*found_clause && !found_outer_clause)
                return NIL;                             /* no indexable clauses anywhere */
@@ -937,7 +937,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
  *
  *       (1)  must be in the form (indexkey op const) or (const op indexkey);
  *                and
- *       (2)  must contain an operator which is in the same class as the index
+ *       (2)  must contain an operator which is in the same family as the index
  *                operator for this column, or is a "special" operator as recognized
  *                by match_special_index_operator().
  *
@@ -978,7 +978,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
  *
  * 'index' is the index of interest.
  * 'indexcol' is a column number of 'index' (counting from 0).
- * 'opclass' is the corresponding operator class.
+ * 'opfamily' is the corresponding operator family.
  * 'rinfo' is the clause to be tested (as a RestrictInfo node).
  * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used.
  *
@@ -990,7 +990,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
 static bool
 match_clause_to_indexcol(IndexOptInfo *index,
                                                 int indexcol,
-                                                Oid opclass,
+                                                Oid opfamily,
                                                 RestrictInfo *rinfo,
                                                 Relids outer_relids,
                                                 SaOpControl saop_control)
@@ -1013,7 +1013,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
                return false;
 
        /* First check for boolean-index cases. */
-       if (IsBooleanOpclass(opclass))
+       if (IsBooleanOpfamily(opfamily))
        {
                if (match_boolean_index_clause((Node *) clause, indexcol, index))
                        return true;
@@ -1052,7 +1052,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
        }
        else if (clause && IsA(clause, RowCompareExpr))
        {
-               return match_rowcompare_to_indexcol(index, indexcol, opclass,
+               return match_rowcompare_to_indexcol(index, indexcol, opfamily,
                                                                                        (RowCompareExpr *) clause,
                                                                                        outer_relids);
        }
@@ -1067,15 +1067,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
                bms_is_subset(right_relids, outer_relids) &&
                !contain_volatile_functions(rightop))
        {
-               if (is_indexable_operator(expr_op, opclass, true))
+               if (is_indexable_operator(expr_op, opfamily, true))
                        return true;
 
                /*
-                * If we didn't find a member of the index's opclass, see whether it
+                * If we didn't find a member of the index's opfamily, see whether it
                 * is a "special" indexable operator.
                 */
                if (plain_op &&
-                       match_special_index_operator(clause, opclass, true))
+                       match_special_index_operator(clause, opfamily, true))
                        return true;
                return false;
        }
@@ -1085,14 +1085,14 @@ match_clause_to_indexcol(IndexOptInfo *index,
                bms_is_subset(left_relids, outer_relids) &&
                !contain_volatile_functions(leftop))
        {
-               if (is_indexable_operator(expr_op, opclass, false))
+               if (is_indexable_operator(expr_op, opfamily, false))
                        return true;
 
                /*
-                * If we didn't find a member of the index's opclass, see whether it
+                * If we didn't find a member of the index's opfamily, see whether it
                 * is a "special" indexable operator.
                 */
-               if (match_special_index_operator(clause, opclass, false))
+               if (match_special_index_operator(clause, opfamily, false))
                        return true;
                return false;
        }
@@ -1102,14 +1102,14 @@ match_clause_to_indexcol(IndexOptInfo *index,
 
 /*
  * is_indexable_operator
- *       Does the operator match the specified index opclass?
+ *       Does the operator match the specified index opfamily?
  *
  * If the indexkey is on the right, what we actually want to know
  * is whether the operator has a commutator operator that matches
- * the opclass.
+ * the opfamily.
  */
 static bool
-is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
+is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
 {
        /* Get the commuted operator if necessary */
        if (!indexkey_on_left)
@@ -1119,8 +1119,8 @@ is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
                        return false;
        }
 
-       /* OK if the (commuted) operator is a member of the index's opclass */
-       return op_in_opclass(expr_op, opclass);
+       /* OK if the (commuted) operator is a member of the index's opfamily */
+       return op_in_opfamily(expr_op, opfamily);
 }
 
 /*
@@ -1131,7 +1131,7 @@ is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
 static bool
 match_rowcompare_to_indexcol(IndexOptInfo *index,
                                                         int indexcol,
-                                                        Oid opclass,
+                                                        Oid opfamily,
                                                         RowCompareExpr *clause,
                                                         Relids outer_relids)
 {
@@ -1144,13 +1144,14 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
                return false;
 
        /*
-        * We could do the matching on the basis of insisting that the opclass
-        * shown in the RowCompareExpr be the same as the index column's opclass,
-        * but that does not work well for cross-type comparisons (the opclass
-        * could be for the other datatype).  Also it would fail to handle indexes
-        * using reverse-sort opclasses.  Instead, match if the operator listed in
-        * the RowCompareExpr is the < <= > or >= member of the index opclass
-        * (after commutation, if the indexkey is on the right).
+        * We could do the matching on the basis of insisting that the opfamily
+        * shown in the RowCompareExpr be the same as the index column's opfamily,
+        * but that could fail in the presence of reverse-sort opfamilies: it'd
+        * be a matter of chance whether RowCompareExpr had picked the forward
+        * or reverse-sort family.  So look only at the operator, and match
+        * if it is a member of the index's opfamily (after commutation, if the
+        * indexkey is on the right).  We'll worry later about whether any
+        * additional operators are matchable to the index.
         */
        leftop = (Node *) linitial(clause->largs);
        rightop = (Node *) linitial(clause->rargs);
@@ -1177,8 +1178,8 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
        else
                return false;
 
-       /* We're good if the operator is the right type of opclass member */
-       switch (get_op_opclass_strategy(expr_op, opclass))
+       /* We're good if the operator is the right type of opfamily member */
+       switch (get_op_opfamily_strategy(expr_op, opfamily))
        {
                case BTLessStrategyNumber:
                case BTLessEqualStrategyNumber:
@@ -1316,23 +1317,23 @@ matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
        {
                IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
                int                     indexcol = 0;
-               Oid                *classes = index->classlist;
+               Oid                *families = index->opfamily;
 
                do
                {
-                       Oid                     curClass = classes[0];
+                       Oid                     curFamily = families[0];
 
                        if (match_clause_to_indexcol(index,
                                                                                 indexcol,
-                                                                                curClass,
+                                                                                curFamily,
                                                                                 rinfo,
                                                                                 outer_relids,
                                                                                 SAOP_ALLOW))
                                return true;
 
                        indexcol++;
-                       classes++;
-               } while (!DoneMatchingIndexKeys(classes));
+                       families++;
+               } while (!DoneMatchingIndexKeys(families));
        }
 
        return false;
@@ -1601,11 +1602,11 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
  * Note: it would be possible to similarly ignore useless ORDER BY items;
  * that is, an index on just y could be considered to match the ordering of
  *             ... WHERE x = 42 ORDER BY x, y;
- * But proving that this is safe would require finding a btree opclass
+ * But proving that this is safe would require finding a btree opfamily
  * containing both the = operator and the < or > operator in the ORDER BY
  * item.  That's significantly more expensive than what we do here, since
  * we'd have to look at restriction clauses unrelated to the current index
- * and search for opclasses without any hint from the index.  The practical
+ * and search for opfamilies without any hint from the index.  The practical
  * use-cases seem to be mostly covered by ignoring index columns, so that's
  * all we do for now.
  *
@@ -1627,7 +1628,7 @@ match_variant_ordering(PlannerInfo *root,
 
        /*
         * Forget the whole thing if not a btree index; our check for ignorable
-        * columns assumes we are dealing with btree opclasses.  (It'd be possible
+        * columns assumes we are dealing with btree opfamilies.  (It'd be possible
         * to factor out just the try for backwards indexscan, but considering
         * that we presently have no orderable indexes except btrees anyway, it's
         * hardly worth contorting this code for that case.)
@@ -1685,7 +1686,7 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
        foreach(l, restrictclauses)
        {
                List       *sublist = (List *) lfirst(l);
-               Oid                     opclass = index->classlist[indexcol];
+               Oid                     opfamily = index->opfamily[indexcol];
                ListCell   *l2;
 
                foreach(l2, sublist)
@@ -1698,7 +1699,7 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
                        bool            ispc;
 
                        /* First check for boolean-index cases. */
-                       if (IsBooleanOpclass(opclass))
+                       if (IsBooleanOpfamily(opfamily))
                        {
                                if (match_boolean_index_clause((Node *) clause, indexcol,
                                                                                           index))
@@ -1729,18 +1730,18 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
                        {
                                Assert(match_index_to_operand(lsecond(clause->args), indexcol,
                                                                                          index));
-                               /* Must flip operator to get the opclass member */
+                               /* Must flip operator to get the opfamily member */
                                clause_op = get_commutator(clause_op);
                                varonleft = false;
                        }
                        if (!OidIsValid(clause_op))
                                continue;               /* ignore non match, per next comment */
-                       op_strategy = get_op_opclass_strategy(clause_op, opclass);
+                       op_strategy = get_op_opfamily_strategy(clause_op, opfamily);
 
                        /*
                         * You might expect to see Assert(op_strategy != 0) here, but you
                         * won't: the clause might contain a special indexable operator
-                        * rather than an ordinary opclass member.      Currently none of the
+                        * rather than an ordinary opfamily member.     Currently none of the
                         * special operators are very likely to expand to an equality
                         * operator; we do not bother to check, but just assume no match.
                         */
@@ -1968,7 +1969,7 @@ match_index_to_operand(Node *operand,
  *
  * match_special_index_operator() is just an auxiliary function for
  * match_clause_to_indexcol(); after the latter fails to recognize a
- * restriction opclause's operator as a member of an index's opclass,
+ * restriction opclause's operator as a member of an index's opfamily,
  * it asks match_special_index_operator() whether the clause should be
  * considered an indexqual anyway.
  *
@@ -1978,7 +1979,7 @@ match_index_to_operand(Node *operand,
  * expand_indexqual_conditions() converts a list of lists of RestrictInfo
  * nodes (with implicit AND semantics across list elements) into
  * a list of clauses that the executor can actually handle.  For operators
- * that are members of the index's opclass this transformation is a no-op,
+ * that are members of the index's opfamily this transformation is a no-op,
  * but clauses recognized by match_special_index_operator() or
  * match_boolean_index_clause() must be converted into one or more "regular"
  * indexqual conditions.
@@ -1989,8 +1990,8 @@ match_index_to_operand(Node *operand,
  * match_boolean_index_clause
  *       Recognize restriction clauses that can be matched to a boolean index.
  *
- * This should be called only when IsBooleanOpclass() recognizes the
- * index's operator class.  We check to see if the clause matches the
+ * This should be called only when IsBooleanOpfamily() recognizes the
+ * index's operator family.  We check to see if the clause matches the
  * index's key.
  */
 static bool
@@ -2034,11 +2035,11 @@ match_boolean_index_clause(Node *clause,
  *
  * The given clause is already known to be a binary opclause having
  * the form (indexkey OP pseudoconst) or (pseudoconst OP indexkey),
- * but the OP proved not to be one of the index's opclass operators.
+ * but the OP proved not to be one of the index's opfamily operators.
  * Return 'true' if we can do something with it anyway.
  */
 static bool
-match_special_index_operator(Expr *clause, Oid opclass,
+match_special_index_operator(Expr *clause, Oid opfamily,
                                                         bool indexkey_on_left)
 {
        bool            isIndexable = false;
@@ -2122,12 +2123,12 @@ match_special_index_operator(Expr *clause, Oid opclass,
                return false;
 
        /*
-        * Must also check that index's opclass supports the operators we will
+        * Must also check that index's opfamily supports the operators we will
         * want to apply.  (A hash index, for example, will not support ">=".)
         * Currently, only btree supports the operators we need.
         *
-        * We insist on the opclass being the specific one we expect, else we'd do
-        * the wrong thing if someone were to make a reverse-sort opclass with the
+        * We insist on the opfamily being the specific one we expect, else we'd do
+        * the wrong thing if someone were to make a reverse-sort opfamily with the
         * same operators.
         */
        switch (expr_op)
@@ -2136,12 +2137,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
                case OID_TEXT_ICLIKE_OP:
                case OID_TEXT_REGEXEQ_OP:
                case OID_TEXT_ICREGEXEQ_OP:
-                       /* text operators will be used for varchar inputs, too */
                        isIndexable =
-                               (opclass == TEXT_PATTERN_BTREE_OPS_OID) ||
-                               (opclass == TEXT_BTREE_OPS_OID && lc_collate_is_c()) ||
-                               (opclass == VARCHAR_PATTERN_BTREE_OPS_OID) ||
-                               (opclass == VARCHAR_BTREE_OPS_OID && lc_collate_is_c());
+                               (opfamily == TEXT_PATTERN_BTREE_FAM_OID) ||
+                               (opfamily == TEXT_BTREE_FAM_OID && lc_collate_is_c());
                        break;
 
                case OID_BPCHAR_LIKE_OP:
@@ -2149,8 +2147,8 @@ match_special_index_operator(Expr *clause, Oid opclass,
                case OID_BPCHAR_REGEXEQ_OP:
                case OID_BPCHAR_ICREGEXEQ_OP:
                        isIndexable =
-                               (opclass == BPCHAR_PATTERN_BTREE_OPS_OID) ||
-                               (opclass == BPCHAR_BTREE_OPS_OID && lc_collate_is_c());
+                               (opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) ||
+                               (opfamily == BPCHAR_BTREE_FAM_OID && lc_collate_is_c());
                        break;
 
                case OID_NAME_LIKE_OP:
@@ -2158,18 +2156,17 @@ match_special_index_operator(Expr *clause, Oid opclass,
                case OID_NAME_REGEXEQ_OP:
                case OID_NAME_ICREGEXEQ_OP:
                        isIndexable =
-                               (opclass == NAME_PATTERN_BTREE_OPS_OID) ||
-                               (opclass == NAME_BTREE_OPS_OID && lc_collate_is_c());
+                               (opfamily == NAME_PATTERN_BTREE_FAM_OID) ||
+                               (opfamily == NAME_BTREE_FAM_OID && lc_collate_is_c());
                        break;
 
                case OID_BYTEA_LIKE_OP:
-                       isIndexable = (opclass == BYTEA_BTREE_OPS_OID);
+                       isIndexable = (opfamily == BYTEA_BTREE_FAM_OID);
                        break;
 
                case OID_INET_SUB_OP:
                case OID_INET_SUBEQ_OP:
-                       isIndexable = (opclass == INET_BTREE_OPS_OID ||
-                                                  opclass == CIDR_BTREE_OPS_OID);
+                       isIndexable = (opfamily == NETWORK_BTREE_FAM_OID);
                        break;
        }
 
@@ -2180,7 +2177,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
  * expand_indexqual_conditions
  *       Given a list of sublists of RestrictInfo nodes, produce a flat list
  *       of index qual clauses.  Standard qual clauses (those in the index's
- *       opclass) are passed through unchanged.  Boolean clauses and "special"
+ *       opfamily) are passed through unchanged.  Boolean clauses and "special"
  *       index operators are expanded into clauses that the indexscan machinery
  *       will know what to do with.  RowCompare clauses are simplified if
  *       necessary to create a clause that is fully checkable by the index.
@@ -2196,7 +2193,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
        List       *resultquals = NIL;
        ListCell   *clausegroup_item;
        int                     indexcol = 0;
-       Oid                *classes = index->classlist;
+       Oid                *families = index->opfamily;
 
        if (clausegroups == NIL)
                return NIL;
@@ -2204,7 +2201,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
        clausegroup_item = list_head(clausegroups);
        do
        {
-               Oid                     curClass = classes[0];
+               Oid                     curFamily = families[0];
                ListCell   *l;
 
                foreach(l, (List *) lfirst(clausegroup_item))
@@ -2213,7 +2210,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
                        Expr       *clause = rinfo->clause;
 
                        /* First check for boolean cases */
-                       if (IsBooleanOpclass(curClass))
+                       if (IsBooleanOpfamily(curFamily))
                        {
                                Expr       *boolqual;
 
@@ -2240,7 +2237,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
                        {
                                resultquals = list_concat(resultquals,
                                                                                  expand_indexqual_opclause(rinfo,
-                                                                                                                                 curClass));
+                                                                                                                                 curFamily));
                        }
                        else if (IsA(clause, ScalarArrayOpExpr))
                        {
@@ -2262,8 +2259,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
                clausegroup_item = lnext(clausegroup_item);
 
                indexcol++;
-               classes++;
-       } while (clausegroup_item != NULL && !DoneMatchingIndexKeys(classes));
+               families++;
+       } while (clausegroup_item != NULL && !DoneMatchingIndexKeys(families));
 
        Assert(clausegroup_item == NULL);       /* else more groups than indexkeys */
 
@@ -2337,7 +2334,7 @@ expand_boolean_index_clause(Node *clause,
  * The input is a single RestrictInfo, the output a list of RestrictInfos
  */
 static List *
-expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
+expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
 {
        Expr       *clause = rinfo->clause;
 
@@ -2354,7 +2351,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
        switch (expr_op)
        {
                        /*
-                        * LIKE and regex operators are not members of any index opclass,
+                        * LIKE and regex operators are not members of any index opfamily,
                         * so if we find one in an indexqual list we can assume that it
                         * was accepted by match_special_index_operator().
                         */
@@ -2364,7 +2361,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
                case OID_BYTEA_LIKE_OP:
                        pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
                                                                                   &prefix, &rest);
-                       result = prefix_quals(leftop, opclass, prefix, pstatus);
+                       result = prefix_quals(leftop, opfamily, prefix, pstatus);
                        break;
 
                case OID_TEXT_ICLIKE_OP:
@@ -2373,7 +2370,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
                        /* the right-hand const is type text for all of these */
                        pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
                                                                                   &prefix, &rest);
-                       result = prefix_quals(leftop, opclass, prefix, pstatus);
+                       result = prefix_quals(leftop, opfamily, prefix, pstatus);
                        break;
 
                case OID_TEXT_REGEXEQ_OP:
@@ -2382,7 +2379,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
                        /* the right-hand const is type text for all of these */
                        pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
                                                                                   &prefix, &rest);
-                       result = prefix_quals(leftop, opclass, prefix, pstatus);
+                       result = prefix_quals(leftop, opfamily, prefix, pstatus);
                        break;
 
                case OID_TEXT_ICREGEXEQ_OP:
@@ -2391,12 +2388,12 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
                        /* the right-hand const is type text for all of these */
                        pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
                                                                                   &prefix, &rest);
-                       result = prefix_quals(leftop, opclass, prefix, pstatus);
+                       result = prefix_quals(leftop, opfamily, prefix, pstatus);
                        break;
 
                case OID_INET_SUB_OP:
                case OID_INET_SUBEQ_OP:
-                       result = network_prefix_quals(leftop, expr_op, opclass,
+                       result = network_prefix_quals(leftop, expr_op, opfamily,
                                                                                  patt->constvalue);
                        break;
 
@@ -2416,7 +2413,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
  * the specified column of the index.  We can use additional columns of the
  * row comparison as index qualifications, so long as they match the index
  * in the "same direction", ie, the indexkeys are all on the same side of the
- * clause and the operators are all the same-type members of the opclasses.
+ * clause and the operators are all the same-type members of the opfamilies.
  * If all the columns of the RowCompareExpr match in this way, we just use it
  * as-is.  Otherwise, we build a shortened RowCompareExpr (if more than one
  * column matches) or a simple OpExpr (if the first-column match is all
@@ -2433,12 +2430,14 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
        RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
        bool            var_on_left;
        int                     op_strategy;
-       Oid                     op_subtype;
+       Oid                     op_lefttype;
+       Oid                     op_righttype;
        bool            op_recheck;
        int                     matching_cols;
        Oid                     expr_op;
-       List       *opclasses;
-       List       *subtypes;
+       List       *opfamilies;
+       List       *lefttypes;
+       List       *righttypes;
        List       *new_ops;
        ListCell   *largs_cell;
        ListCell   *rargs_cell;
@@ -2453,11 +2452,15 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
        expr_op = linitial_oid(clause->opnos);
        if (!var_on_left)
                expr_op = get_commutator(expr_op);
-       get_op_opclass_properties(expr_op, index->classlist[indexcol],
-                                                         &op_strategy, &op_subtype, &op_recheck);
-       /* Build lists of the opclasses and operator subtypes in case needed */
-       opclasses = list_make1_oid(index->classlist[indexcol]);
-       subtypes = list_make1_oid(op_subtype);
+       get_op_opfamily_properties(expr_op, index->opfamily[indexcol],
+                                                          &op_strategy,
+                                                          &op_lefttype,
+                                                          &op_righttype,
+                                                          &op_recheck);
+       /* Build lists of the opfamilies and operator datatypes in case needed */
+       opfamilies = list_make1_oid(index->opfamily[indexcol]);
+       lefttypes = list_make1_oid(op_lefttype);
+       righttypes = list_make1_oid(op_righttype);
 
        /*
         * See how many of the remaining columns match some index column in the
@@ -2513,15 +2516,19 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                        break;                          /* no match found */
 
                /* Now, do we have the right operator for this column? */
-               if (get_op_opclass_strategy(expr_op, index->classlist[i])
+               if (get_op_opfamily_strategy(expr_op, index->opfamily[i])
                        != op_strategy)
                        break;
 
-               /* Add opclass and subtype to lists */
-               get_op_opclass_properties(expr_op, index->classlist[i],
-                                                                 &op_strategy, &op_subtype, &op_recheck);
-               opclasses = lappend_oid(opclasses, index->classlist[i]);
-               subtypes = lappend_oid(subtypes, op_subtype);
+               /* Add opfamily and datatypes to lists */
+               get_op_opfamily_properties(expr_op, index->opfamily[i],
+                                                                  &op_strategy,
+                                                                  &op_lefttype,
+                                                                  &op_righttype,
+                                                                  &op_recheck);
+               opfamilies = lappend_oid(opfamilies, index->opfamily[i]);
+               lefttypes = lappend_oid(lefttypes, op_lefttype);
+               righttypes = lappend_oid(righttypes, op_righttype);
 
                /* This column matches, keep scanning */
                matching_cols++;
@@ -2547,8 +2554,9 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
        }
        else
        {
-               ListCell   *opclasses_cell;
-               ListCell   *subtypes_cell;
+               ListCell   *opfamilies_cell;
+               ListCell   *lefttypes_cell;
+               ListCell   *righttypes_cell;
 
                if (op_strategy == BTLessStrategyNumber)
                        op_strategy = BTLessEqualStrategyNumber;
@@ -2557,23 +2565,30 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                else
                        elog(ERROR, "unexpected strategy number %d", op_strategy);
                new_ops = NIL;
-               forboth(opclasses_cell, opclasses, subtypes_cell, subtypes)
+               lefttypes_cell = list_head(lefttypes);
+               righttypes_cell = list_head(righttypes);
+               foreach(opfamilies_cell, opfamilies)
                {
-                       expr_op = get_opclass_member(lfirst_oid(opclasses_cell),
-                                                                                lfirst_oid(subtypes_cell),
-                                                                                op_strategy);
+                       Oid             opfam = lfirst_oid(opfamilies_cell);
+                       Oid             lefttype = lfirst_oid(lefttypes_cell);
+                       Oid             righttype = lfirst_oid(righttypes_cell);
+
+                       expr_op = get_opfamily_member(opfam, lefttype, righttype,
+                                                                                 op_strategy);
                        if (!OidIsValid(expr_op))       /* should not happen */
-                               elog(ERROR, "could not find member %d of opclass %u",
-                                        op_strategy, lfirst_oid(opclasses_cell));
+                               elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
+                                        op_strategy, lefttype, righttype, opfam);
                        if (!var_on_left)
                        {
                                expr_op = get_commutator(expr_op);
                                if (!OidIsValid(expr_op))               /* should not happen */
-                                       elog(ERROR, "could not find commutator of member %d of opclass %u",
-                                                op_strategy, lfirst_oid(opclasses_cell));
+                                       elog(ERROR, "could not find commutator of member %d(%u,%u) of opfamily %u",
+                                                op_strategy, lefttype, righttype, opfam);
                        }
                        new_ops = lappend_oid(new_ops, expr_op);
                }
+               lefttypes_cell = lnext(lefttypes_cell);
+               righttypes_cell = lnext(righttypes_cell);
        }
 
        /* If we have more than one matching col, create a subset rowcompare */
@@ -2587,8 +2602,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                        rc->rctype = (op_strategy == BTLessEqualStrategyNumber) ?
                                ROWCOMPARE_GE : ROWCOMPARE_LE;
                rc->opnos = new_ops;
-               rc->opclasses = list_truncate(list_copy(clause->opclasses),
-                                                                         matching_cols);
+               rc->opfamilies = list_truncate(list_copy(clause->opfamilies),
+                                                                          matching_cols);
                rc->largs = list_truncate((List *) copyObject(clause->largs),
                                                                  matching_cols);
                rc->rargs = list_truncate((List *) copyObject(clause->rargs),
@@ -2608,12 +2623,12 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
 
 /*
  * Given a fixed prefix that all the "leftop" values must have,
- * generate suitable indexqual condition(s).  opclass is the index
- * operator class; we use it to deduce the appropriate comparison
+ * generate suitable indexqual condition(s).  opfamily is the index
+ * operator family; we use it to deduce the appropriate comparison
  * operators and operand datatypes.
  */
 static List *
-prefix_quals(Node *leftop, Oid opclass,
+prefix_quals(Node *leftop, Oid opfamily,
                         Const *prefix_const, Pattern_Prefix_Status pstatus)
 {
        List       *result;
@@ -2624,35 +2639,30 @@ prefix_quals(Node *leftop, Oid opclass,
 
        Assert(pstatus != Pattern_Prefix_None);
 
-       switch (opclass)
+       switch (opfamily)
        {
-               case TEXT_BTREE_OPS_OID:
-               case TEXT_PATTERN_BTREE_OPS_OID:
+               case TEXT_BTREE_FAM_OID:
+               case TEXT_PATTERN_BTREE_FAM_OID:
                        datatype = TEXTOID;
                        break;
 
-               case VARCHAR_BTREE_OPS_OID:
-               case VARCHAR_PATTERN_BTREE_OPS_OID:
-                       datatype = VARCHAROID;
-                       break;
-
-               case BPCHAR_BTREE_OPS_OID:
-               case BPCHAR_PATTERN_BTREE_OPS_OID:
+               case BPCHAR_BTREE_FAM_OID:
+               case BPCHAR_PATTERN_BTREE_FAM_OID:
                        datatype = BPCHAROID;
                        break;
 
-               case NAME_BTREE_OPS_OID:
-               case NAME_PATTERN_BTREE_OPS_OID:
+               case NAME_BTREE_FAM_OID:
+               case NAME_PATTERN_BTREE_FAM_OID:
                        datatype = NAMEOID;
                        break;
 
-               case BYTEA_BTREE_OPS_OID:
+               case BYTEA_BTREE_FAM_OID:
                        datatype = BYTEAOID;
                        break;
 
                default:
                        /* shouldn't get here */
-                       elog(ERROR, "unexpected opclass: %u", opclass);
+                       elog(ERROR, "unexpected opfamily: %u", opfamily);
                        return NIL;
        }
 
@@ -2688,10 +2698,10 @@ prefix_quals(Node *leftop, Oid opclass,
         */
        if (pstatus == Pattern_Prefix_Exact)
        {
-               oproid = get_opclass_member(opclass, InvalidOid,
-                                                                       BTEqualStrategyNumber);
+               oproid = get_opfamily_member(opfamily, datatype, datatype,
+                                                                        BTEqualStrategyNumber);
                if (oproid == InvalidOid)
-                       elog(ERROR, "no = operator for opclass %u", opclass);
+                       elog(ERROR, "no = operator for opfamily %u", opfamily);
                expr = make_opclause(oproid, BOOLOID, false,
                                                         (Expr *) leftop, (Expr *) prefix_const);
                result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
@@ -2703,10 +2713,10 @@ prefix_quals(Node *leftop, Oid opclass,
         *
         * We can always say "x >= prefix".
         */
-       oproid = get_opclass_member(opclass, InvalidOid,
-                                                               BTGreaterEqualStrategyNumber);
+       oproid = get_opfamily_member(opfamily, datatype, datatype,
+                                                                BTGreaterEqualStrategyNumber);
        if (oproid == InvalidOid)
-               elog(ERROR, "no >= operator for opclass %u", opclass);
+               elog(ERROR, "no >= operator for opfamily %u", opfamily);
        expr = make_opclause(oproid, BOOLOID, false,
                                                 (Expr *) leftop, (Expr *) prefix_const);
        result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
@@ -2719,10 +2729,10 @@ prefix_quals(Node *leftop, Oid opclass,
        greaterstr = make_greater_string(prefix_const);
        if (greaterstr)
        {
-               oproid = get_opclass_member(opclass, InvalidOid,
-                                                                       BTLessStrategyNumber);
+               oproid = get_opfamily_member(opfamily, datatype, datatype,
+                                                                        BTLessStrategyNumber);
                if (oproid == InvalidOid)
-                       elog(ERROR, "no < operator for opclass %u", opclass);
+                       elog(ERROR, "no < operator for opfamily %u", opfamily);
                expr = make_opclause(oproid, BOOLOID, false,
                                                         (Expr *) leftop, (Expr *) greaterstr);
                result = lappend(result,
@@ -2733,12 +2743,12 @@ prefix_quals(Node *leftop, Oid opclass,
 }
 
 /*
- * Given a leftop and a rightop, and a inet-class sup/sub operator,
+ * Given a leftop and a rightop, and a inet-family sup/sub operator,
  * generate suitable indexqual condition(s).  expr_op is the original
- * operator, and opclass is the index opclass.
+ * operator, and opfamily is the index opfamily.
  */
 static List *
-network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
+network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
 {
        bool            is_eq;
        Oid                     datatype;
@@ -2770,17 +2780,17 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
         */
        if (is_eq)
        {
-               opr1oid = get_opclass_member(opclass, InvalidOid,
-                                                                        BTGreaterEqualStrategyNumber);
+               opr1oid = get_opfamily_member(opfamily, datatype, datatype,
+                                                                         BTGreaterEqualStrategyNumber);
                if (opr1oid == InvalidOid)
-                       elog(ERROR, "no >= operator for opclass %u", opclass);
+                       elog(ERROR, "no >= operator for opfamily %u", opfamily);
        }
        else
        {
-               opr1oid = get_opclass_member(opclass, InvalidOid,
-                                                                        BTGreaterStrategyNumber);
+               opr1oid = get_opfamily_member(opfamily, datatype, datatype,
+                                                                         BTGreaterStrategyNumber);
                if (opr1oid == InvalidOid)
-                       elog(ERROR, "no > operator for opclass %u", opclass);
+                       elog(ERROR, "no > operator for opfamily %u", opfamily);
        }
 
        opr1right = network_scan_first(rightop);
@@ -2793,10 +2803,10 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
 
        /* create clause "key <= network_scan_last( rightop )" */
 
-       opr2oid = get_opclass_member(opclass, InvalidOid,
-                                                                BTLessEqualStrategyNumber);
+       opr2oid = get_opfamily_member(opfamily, datatype, datatype,
+                                                                 BTLessEqualStrategyNumber);
        if (opr2oid == InvalidOid)
-               elog(ERROR, "no <= operator for opclass %u", opclass);
+               elog(ERROR, "no <= operator for opfamily %u", opfamily);
 
        opr2right = network_scan_last(rightop);
 
index 6882439ca3a4b656069f12f9f667a708c0e8cbb6..06022b373b5b599eade16e1031c1514716630cdc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.107 2006/10/04 00:29:54 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.108 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include <math.h>
 
+#include "access/skey.h"
 #include "optimizer/cost.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -39,6 +40,8 @@ static List *select_mergejoin_clauses(RelOptInfo *joinrel,
                                                 RelOptInfo *innerrel,
                                                 List *restrictlist,
                                                 JoinType jointype);
+static void build_mergejoin_strat_lists(List *mergeclauses,
+                                                       List **mergefamilies, List **mergestrategies);
 
 
 /*
@@ -225,6 +228,8 @@ sort_inner_and_outer(PlannerInfo *root,
                List       *front_pathkey = (List *) lfirst(l);
                List       *cur_pathkeys;
                List       *cur_mergeclauses;
+               List       *mergefamilies;
+               List       *mergestrategies;
                List       *outerkeys;
                List       *innerkeys;
                List       *merge_pathkeys;
@@ -269,6 +274,10 @@ sort_inner_and_outer(PlannerInfo *root,
                merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
                                                                                         outerkeys);
 
+               /* Build opfamily info for execution */
+               build_mergejoin_strat_lists(cur_mergeclauses,
+                                                                       &mergefamilies, &mergestrategies);
+
                /*
                 * And now we can make the path.
                 */
@@ -281,6 +290,8 @@ sort_inner_and_outer(PlannerInfo *root,
                                                                           restrictlist,
                                                                           merge_pathkeys,
                                                                           cur_mergeclauses,
+                                                                          mergefamilies,
+                                                                          mergestrategies,
                                                                           outerkeys,
                                                                           innerkeys));
        }
@@ -410,6 +421,8 @@ match_unsorted_outer(PlannerInfo *root,
                Path       *outerpath = (Path *) lfirst(l);
                List       *merge_pathkeys;
                List       *mergeclauses;
+               List       *mergefamilies;
+               List       *mergestrategies;
                List       *innersortkeys;
                List       *trialsortkeys;
                Path       *cheapest_startup_inner;
@@ -516,6 +529,10 @@ match_unsorted_outer(PlannerInfo *root,
                                                                                                           mergeclauses,
                                                                                                           innerrel);
 
+               /* Build opfamily info for execution */
+               build_mergejoin_strat_lists(mergeclauses,
+                                                                       &mergefamilies, &mergestrategies);
+
                /*
                 * Generate a mergejoin on the basis of sorting the cheapest inner.
                 * Since a sort will be needed, only cheapest total cost matters. (But
@@ -531,6 +548,8 @@ match_unsorted_outer(PlannerInfo *root,
                                                                           restrictlist,
                                                                           merge_pathkeys,
                                                                           mergeclauses,
+                                                                          mergefamilies,
+                                                                          mergestrategies,
                                                                           NIL,
                                                                           innersortkeys));
 
@@ -589,6 +608,11 @@ match_unsorted_outer(PlannerInfo *root,
                                }
                                else
                                        newclauses = mergeclauses;
+
+                               /* Build opfamily info for execution */
+                               build_mergejoin_strat_lists(newclauses,
+                                                                                       &mergefamilies, &mergestrategies);
+
                                add_path(joinrel, (Path *)
                                                 create_mergejoin_path(root,
                                                                                           joinrel,
@@ -598,6 +622,8 @@ match_unsorted_outer(PlannerInfo *root,
                                                                                           restrictlist,
                                                                                           merge_pathkeys,
                                                                                           newclauses,
+                                                                                          mergefamilies,
+                                                                                          mergestrategies,
                                                                                           NIL,
                                                                                           NIL));
                                cheapest_total_inner = innerpath;
@@ -633,6 +659,11 @@ match_unsorted_outer(PlannerInfo *root,
                                                else
                                                        newclauses = mergeclauses;
                                        }
+
+                                       /* Build opfamily info for execution */
+                                       build_mergejoin_strat_lists(newclauses,
+                                                                                               &mergefamilies, &mergestrategies);
+
                                        add_path(joinrel, (Path *)
                                                         create_mergejoin_path(root,
                                                                                                   joinrel,
@@ -642,6 +673,8 @@ match_unsorted_outer(PlannerInfo *root,
                                                                                                   restrictlist,
                                                                                                   merge_pathkeys,
                                                                                                   newclauses,
+                                                                                                  mergefamilies,
+                                                                                                  mergestrategies,
                                                                                                   NIL,
                                                                                                   NIL));
                                }
@@ -946,3 +979,35 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
 
        return result_list;
 }
+
+/*
+ * Temporary hack to build opfamily and strategy lists needed for mergejoin
+ * by the executor.  We need to rethink the planner's handling of merge
+ * planning so that it can deal with multiple possible merge orders, but
+ * that's not done yet.
+ */
+static void
+build_mergejoin_strat_lists(List *mergeclauses,
+                                                       List **mergefamilies, List **mergestrategies)
+{
+       ListCell   *l;
+
+       *mergefamilies = NIL;
+       *mergestrategies = NIL;
+
+       foreach(l, mergeclauses)
+       {
+               RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
+
+               /*
+                * We do not need to worry about whether the mergeclause will be
+                * commuted at runtime --- it's the same opfamily either way.
+                */
+               *mergefamilies = lappend_oid(*mergefamilies, restrictinfo->mergeopfamily);
+               /*
+                * For the moment, strategy must always be LessThan --- see
+                * hack version of get_op_mergejoin_info
+                */
+               *mergestrategies = lappend_int(*mergestrategies, BTLessStrategyNumber);
+       }
+}
index 14f1f1a10f4e2071a9db39ec0138657ee054f555..f924994480bc0bd76ebc52cf7583eb954a66bf40 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.217 2006/10/04 00:29:54 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.218 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,7 +73,7 @@ static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
                                                 List **indexstrategy,
                                                 List **indexsubtype);
 static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
-                                         Oid *opclass);
+                                         Oid *opfamily);
 static List *get_switched_clauses(List *clauses, Relids outerrelids);
 static List *order_qual_clauses(PlannerInfo *root, List *clauses);
 static void copy_path_costsize(Plan *dest, Path *src);
@@ -113,7 +113,7 @@ static HashJoin *make_hashjoin(List *tlist,
 static Hash *make_hash(Plan *lefttree);
 static MergeJoin *make_mergejoin(List *tlist,
                           List *joinclauses, List *otherclauses,
-                          List *mergeclauses,
+                          List *mergeclauses, List *mergefamilies, List *mergestrategies,
                           Plan *lefttree, Plan *righttree,
                           JoinType jointype);
 static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
@@ -1540,6 +1540,8 @@ create_mergejoin_plan(PlannerInfo *root,
                                                           joinclauses,
                                                           otherclauses,
                                                           mergeclauses,
+                                                          best_path->path_mergefamilies,
+                                                          best_path->path_mergestrategies,
                                                           outer_plan,
                                                           inner_plan,
                                                           best_path->jpath.jointype);
@@ -1676,9 +1678,10 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
                RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
                Expr       *clause;
                Oid                     clause_op;
-               Oid                     opclass;
+               Oid                     opfamily;
                int                     stratno;
-               Oid                     stratsubtype;
+               Oid                     stratlefttype;
+               Oid                     stratrighttype;
                bool            recheck;
 
                Assert(IsA(rinfo, RestrictInfo));
@@ -1709,11 +1712,11 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
 
                        /*
                         * Now, determine which index attribute this is, change the
-                        * indexkey operand as needed, and get the index opclass.
+                        * indexkey operand as needed, and get the index opfamily.
                         */
                        linitial(op->args) = fix_indexqual_operand(linitial(op->args),
                                                                                                           index,
-                                                                                                          &opclass);
+                                                                                                          &opfamily);
                        clause_op = op->opno;
                }
                else if (IsA(clause, RowCompareExpr))
@@ -1734,20 +1737,20 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
                         * For each column in the row comparison, determine which index
                         * attribute this is and change the indexkey operand as needed.
                         *
-                        * Save the index opclass for only the first column.  We will
-                        * return the operator and opclass info for just the first column
+                        * Save the index opfamily for only the first column.  We will
+                        * return the operator and opfamily info for just the first column
                         * of the row comparison; the executor will have to look up the
                         * rest if it needs them.
                         */
                        foreach(lc, rc->largs)
                        {
-                               Oid                     tmp_opclass;
+                               Oid                     tmp_opfamily;
 
                                lfirst(lc) = fix_indexqual_operand(lfirst(lc),
                                                                                                   index,
-                                                                                                  &tmp_opclass);
+                                                                                                  &tmp_opfamily);
                                if (lc == list_head(rc->largs))
-                                       opclass = tmp_opclass;
+                                       opfamily = tmp_opfamily;
                        }
                        clause_op = linitial_oid(rc->opnos);
                }
@@ -1759,11 +1762,11 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
 
                        /*
                         * Now, determine which index attribute this is, change the
-                        * indexkey operand as needed, and get the index opclass.
+                        * indexkey operand as needed, and get the index opfamily.
                         */
                        linitial(saop->args) = fix_indexqual_operand(linitial(saop->args),
                                                                                                                 index,
-                                                                                                                &opclass);
+                                                                                                                &opfamily);
                        clause_op = saop->opno;
                }
                else
@@ -1776,15 +1779,18 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
                *fixed_indexquals = lappend(*fixed_indexquals, clause);
 
                /*
-                * Look up the (possibly commuted) operator in the operator class to
-                * get its strategy numbers and the recheck indicator.  This also
+                * Look up the (possibly commuted) operator in the operator family to
+                * get its strategy number and the recheck indicator.   This also
                 * double-checks that we found an operator matching the index.
                 */
-               get_op_opclass_properties(clause_op, opclass,
-                                                                 &stratno, &stratsubtype, &recheck);
+               get_op_opfamily_properties(clause_op, opfamily,
+                                                                  &stratno,
+                                                                  &stratlefttype,
+                                                                  &stratrighttype,
+                                                                  &recheck);
 
                *indexstrategy = lappend_int(*indexstrategy, stratno);
-               *indexsubtype = lappend_oid(*indexsubtype, stratsubtype);
+               *indexsubtype = lappend_oid(*indexsubtype, stratrighttype);
 
                /* If it's not lossy, add to nonlossy_indexquals */
                if (!recheck)
@@ -1793,7 +1799,7 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
 }
 
 static Node *
-fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
+fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opfamily)
 {
        /*
         * We represent index keys by Var nodes having the varno of the base table
@@ -1826,8 +1832,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
                                {
                                        result = (Var *) copyObject(node);
                                        result->varattno = pos + 1;
-                                       /* return the correct opclass, too */
-                                       *opclass = index->classlist[pos];
+                                       /* return the correct opfamily, too */
+                                       *opfamily = index->opfamily[pos];
                                        return (Node *) result;
                                }
                        }
@@ -1853,8 +1859,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
                                result = makeVar(index->rel->relid, pos + 1,
                                                                 exprType(lfirst(indexpr_item)), -1,
                                                                 0);
-                               /* return the correct opclass, too */
-                               *opclass = index->classlist[pos];
+                               /* return the correct opfamily, too */
+                               *opfamily = index->opfamily[pos];
                                return (Node *) result;
                        }
                        indexpr_item = lnext(indexpr_item);
@@ -1863,7 +1869,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
 
        /* Ooops... */
        elog(ERROR, "node is not an index attribute");
-       *opclass = InvalidOid;          /* keep compiler quiet */
+       *opfamily = InvalidOid;         /* keep compiler quiet */
        return NULL;
 }
 
@@ -2327,6 +2333,8 @@ make_mergejoin(List *tlist,
                           List *joinclauses,
                           List *otherclauses,
                           List *mergeclauses,
+                          List *mergefamilies,
+                          List *mergestrategies,
                           Plan *lefttree,
                           Plan *righttree,
                           JoinType jointype)
@@ -2340,6 +2348,8 @@ make_mergejoin(List *tlist,
        plan->lefttree = lefttree;
        plan->righttree = righttree;
        node->mergeclauses = mergeclauses;
+       node->mergefamilies = mergefamilies;
+       node->mergestrategies = mergestrategies;
        node->join.jointype = jointype;
        node->join.joinqual = joinclauses;
 
index da321a637b21035c9682c33c0af632b6968aaccb..229b779af0309d8d09534312a3a0046d6fa3e0bd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.124 2006/12/07 19:33:40 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.125 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1109,10 +1109,10 @@ process_implied_equality(PlannerInfo *root,
 
        /*
         * Let's just make sure this appears to be a compatible operator.
+        *
+        * XXX needs work
         */
-       if (pgopform->oprlsortop != sortop1 ||
-               pgopform->oprrsortop != sortop2 ||
-               pgopform->oprresult != BOOLOID)
+       if (pgopform->oprresult != BOOLOID)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                                 errmsg("equality operator for types %s and %s should be merge-joinable, but isn't",
@@ -1276,6 +1276,7 @@ check_mergejoinable(RestrictInfo *restrictinfo)
        Oid                     opno,
                                leftOp,
                                rightOp;
+       Oid                     opfamily;
 
        if (restrictinfo->pseudoconstant)
                return;
@@ -1286,14 +1287,17 @@ check_mergejoinable(RestrictInfo *restrictinfo)
 
        opno = ((OpExpr *) clause)->opno;
 
-       if (op_mergejoinable(opno,
-                                                &leftOp,
-                                                &rightOp) &&
+       if (op_mergejoinable(opno) &&
                !contain_volatile_functions((Node *) clause))
        {
-               restrictinfo->mergejoinoperator = opno;
-               restrictinfo->left_sortop = leftOp;
-               restrictinfo->right_sortop = rightOp;
+               /* XXX for the moment, continue to force use of particular sortops */
+               if (get_op_mergejoin_info(opno, &leftOp, &rightOp, &opfamily))
+               {
+                       restrictinfo->mergejoinoperator = opno;
+                       restrictinfo->left_sortop = leftOp;
+                       restrictinfo->right_sortop = rightOp;
+                       restrictinfo->mergeopfamily = opfamily;
+               }
        }
 }
 
index e64340ed21c1122b1470302f246649d62d1d77f4..fcc8d51078642c0fa33da11e34d551231e480f7c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.22 2006/10/04 00:29:54 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.23 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -340,8 +340,8 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
 
                                Assert(is_opclause(rinfo->clause));
                                strategy =
-                                       get_op_opclass_strategy(((OpExpr *) rinfo->clause)->opno,
-                                                                                       index->classlist[prevcol]);
+                                       get_op_opfamily_strategy(((OpExpr *) rinfo->clause)->opno,
+                                                                                        index->opfamily[prevcol]);
                                if (strategy == BTEqualStrategyNumber)
                                        break;
                        }
@@ -390,10 +390,10 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
  *             Does an aggregate match an index column?
  *
  * It matches if its argument is equal to the index column's data and its
- * sortop is either the LessThan or GreaterThan member of the column's opclass.
+ * sortop is either a LessThan or GreaterThan member of the column's opfamily.
  *
- * We return ForwardScanDirection if match the LessThan member,
- * BackwardScanDirection if match the GreaterThan member,
+ * We return ForwardScanDirection if match a LessThan member,
+ * BackwardScanDirection if match a GreaterThan member,
  * and NoMovementScanDirection if there's no match.
  */
 static ScanDirection
@@ -405,9 +405,9 @@ match_agg_to_index_col(MinMaxAggInfo *info, IndexOptInfo *index, int indexcol)
        if (!match_index_to_operand((Node *) info->target, indexcol, index))
                return NoMovementScanDirection;
 
-       /* Look up the operator in the opclass */
-       strategy = get_op_opclass_strategy(info->aggsortop,
-                                                                          index->classlist[indexcol]);
+       /* Look up the operator in the opfamily */
+       strategy = get_op_opfamily_strategy(info->aggsortop,
+                                                                               index->opfamily[indexcol]);
        if (strategy == BTLessStrategyNumber)
                return ForwardScanDirection;
        if (strategy == BTGreaterStrategyNumber)
index 7793d071cda49010ac3a702be5309cb80c54caee..f42a28cddd5419d5eb5cb14601472e6ef32f7bfc 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.114 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.115 2006/12/23 00:43:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -689,11 +689,11 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
                return NULL;
        if (sublink->testexpr && IsA(sublink->testexpr, OpExpr))
        {
-               List       *opclasses;
+               List       *opfamilies;
                List       *opstrats;
 
                get_op_btree_interpretation(((OpExpr *) sublink->testexpr)->opno,
-                                                                       &opclasses, &opstrats);
+                                                                       &opfamilies, &opstrats);
                if (!list_member_int(opstrats, ROWCOMPARE_EQ))
                        return NULL;
        }
index 73ad926418fb0c49ffc3f810fcc6ee1806437a5b..0f720c40e932e8a5563d1cdab4cd1188f62545ba 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.224 2006/12/21 16:05:13 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.225 2006/12/23 00:43:10 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -1294,13 +1294,9 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
        clause->opnos = newops;
 
        /*
-        * Note: we don't bother to update the opclasses list, but just set it to
-        * empty.  This is OK since this routine is currently only used for index
-        * quals, and the index machinery won't use the opclass information.  The
-        * original opclass list is NOT valid if we have commuted any cross-type
-        * comparisons, so don't leave it in place.
+        * Note: we need not change the opfamilies list; we assume any btree
+        * opfamily containing an operator will also contain its commutator.
         */
-       clause->opclasses = NIL;        /* XXX */
 
        temp = clause->largs;
        clause->largs = clause->rargs;
index 01f3151bee8c651577f5bff2da0f7d667a365cb8..5042a3ff5639deb316b45401e98eeaa8bac4902d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.133 2006/10/04 00:29:55 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.134 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1152,6 +1152,10 @@ create_nestloop_path(PlannerInfo *root,
  * 'pathkeys' are the path keys of the new join path
  * 'mergeclauses' are the RestrictInfo nodes to use as merge clauses
  *             (this should be a subset of the restrict_clauses list)
+ * 'mergefamilies' are the btree opfamily OIDs identifying the merge
+ *             ordering for each merge clause
+ * 'mergestrategies' are the btree operator strategies identifying the merge
+ *             ordering for each merge clause
  * 'outersortkeys' are the sort varkeys for the outer relation
  * 'innersortkeys' are the sort varkeys for the inner relation
  */
@@ -1164,6 +1168,8 @@ create_mergejoin_path(PlannerInfo *root,
                                          List *restrict_clauses,
                                          List *pathkeys,
                                          List *mergeclauses,
+                                         List *mergefamilies,
+                                         List *mergestrategies,
                                          List *outersortkeys,
                                          List *innersortkeys)
 {
@@ -1204,6 +1210,8 @@ create_mergejoin_path(PlannerInfo *root,
        pathnode->jpath.joinrestrictinfo = restrict_clauses;
        pathnode->jpath.path.pathkeys = pathkeys;
        pathnode->path_mergeclauses = mergeclauses;
+       pathnode->path_mergefamilies = mergefamilies;
+       pathnode->path_mergestrategies = mergestrategies;
        pathnode->outersortkeys = outersortkeys;
        pathnode->innersortkeys = innersortkeys;
 
index 70a77bd3bd89c0f97e7a8cd7fd25a56199ba3590..5b80991aefecbfb524b866bb00e9ee49a22c77b6 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.128 2006/12/18 18:56:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.129 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -169,16 +169,16 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                        info->ncolumns = ncolumns = index->indnatts;
 
                        /*
-                        * Need to make classlist and ordering arrays large enough to put
+                        * Need to make opfamily and ordering arrays large enough to put
                         * a terminating 0 at the end of each one.
                         */
                        info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
-                       info->classlist = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
+                       info->opfamily = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
                        info->ordering = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
 
                        for (i = 0; i < ncolumns; i++)
                        {
-                               info->classlist[i] = indexRelation->rd_indclass->values[i];
+                               info->opfamily[i] = indexRelation->rd_opfamily[i];
                                info->indexkeys[i] = index->indkey.values[i];
                        }
 
index 4a2609a4ab6a55d0fcd50b563e6746e4e2c89190..5f81cae4e85d6ef8dbba3fab6a3b8f74c61e0c20 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.10 2006/10/04 00:29:55 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.11 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -939,7 +939,7 @@ arrayexpr_cleanup_fn(PredIterInfo info)
  * already known immutable, so the clause will certainly always fail.)
  *
  * Finally, we may be able to deduce something using knowledge about btree
- * operator classes; this is encapsulated in btree_predicate_proof().
+ * operator families; this is encapsulated in btree_predicate_proof().
  *----------
  */
 static bool
@@ -989,7 +989,7 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
  * that has "foo" as an input. See notes for implication case.
  *
  * Finally, we may be able to deduce something using knowledge about btree
- * operator classes; this is encapsulated in btree_predicate_proof().
+ * operator families; this is encapsulated in btree_predicate_proof().
  *----------
  */
 static bool
@@ -1062,8 +1062,8 @@ extract_not_arg(Node *clause)
  * The strategy numbers defined by btree indexes (see access/skey.h) are:
  *             (1) <   (2) <=   (3) =   (4) >=   (5) >
  * and in addition we use (6) to represent <>. <> is not a btree-indexable
- * operator, but we assume here that if the equality operator of a btree
- * opclass has a negator operator, the negator behaves as <> for the opclass.
+ * operator, but we assume here that if an equality operator of a btree
+ * opfamily has a negator operator, the negator behaves as <> for the opfamily.
  *
  * The interpretation of:
  *
@@ -1146,10 +1146,10 @@ static const StrategyNumber BT_refute_table[6][6] = {
  * What we look for here is binary boolean opclauses of the form
  * "foo op constant", where "foo" is the same in both clauses. The operators
  * and constants can be different but the operators must be in the same btree
- * operator class.     We use the above operator implication tables to
+ * operator family.  We use the above operator implication tables to
  * derive implications between nonidentical clauses.  (Note: "foo" is known
  * immutable, and constants are surely immutable, but we have to check that
- * the operators are too.  As of 8.0 it's possible for opclasses to contain
+ * the operators are too.  As of 8.0 it's possible for opfamilies to contain
  * operators that are merely stable, and we dare not make deductions with
  * these.)
  *----------
@@ -1171,12 +1171,12 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
                                pred_op_negator,
                                clause_op_negator,
                                test_op = InvalidOid;
-       Oid                     opclass_id;
+       Oid                     opfamily_id;
        bool            found = false;
        StrategyNumber pred_strategy,
                                clause_strategy,
                                test_strategy;
-       Oid                     clause_subtype;
+       Oid                     clause_righttype;
        Expr       *test_expr;
        ExprState  *test_exprstate;
        Datum           test_result;
@@ -1272,28 +1272,30 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
        }
 
        /*
-        * Try to find a btree opclass containing the needed operators.
+        * Try to find a btree opfamily containing the needed operators.
         *
-        * We must find a btree opclass that contains both operators, else the
+        * XXX this needs work!!!!!!!!!!!!!!!!!!!!!!!
+        *
+        * We must find a btree opfamily that contains both operators, else the
         * implication can't be determined.  Also, the pred_op has to be of
         * default subtype (implying left and right input datatypes are the same);
         * otherwise it's unsafe to put the pred_const on the left side of the
-        * test.  Also, the opclass must contain a suitable test operator matching
+        * test.  Also, the opfamily must contain a suitable test operator matching
         * the clause_const's type (which we take to mean that it has the same
         * subtype as the original clause_operator).
         *
-        * If there are multiple matching opclasses, assume we can use any one to
+        * If there are multiple matching opfamilies, assume we can use any one to
         * determine the logical relationship of the two operators and the correct
         * corresponding test operator.  This should work for any logically
-        * consistent opclasses.
+        * consistent opfamilies.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
                                                                 ObjectIdGetDatum(pred_op),
                                                                 0, 0, 0);
 
        /*
-        * If we couldn't find any opclass containing the pred_op, perhaps it is a
-        * <> operator.  See if it has a negator that is in an opclass.
+        * If we couldn't find any opfamily containing the pred_op, perhaps it is a
+        * <> operator.  See if it has a negator that is in an opfamily.
         */
        pred_op_negated = false;
        if (catlist->n_members == 0)
@@ -1312,23 +1314,22 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
        /* Also may need the clause_op's negator */
        clause_op_negator = get_negator(clause_op);
 
-       /* Now search the opclasses */
+       /* Now search the opfamilies */
        for (i = 0; i < catlist->n_members; i++)
        {
                HeapTuple       pred_tuple = &catlist->members[i]->tuple;
                Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
                HeapTuple       clause_tuple;
 
-               opclass_id = pred_form->amopclaid;
-
                /* must be btree */
-               if (!opclass_is_btree(opclass_id))
+               if (pred_form->amopmethod != BTREE_AM_OID)
                        continue;
-               /* predicate operator must be default within this opclass */
-               if (pred_form->amopsubtype != InvalidOid)
+               /* predicate operator must be default within this opfamily */
+               if (pred_form->amoplefttype != pred_form->amoprighttype)
                        continue;
 
                /* Get the predicate operator's btree strategy number */
+               opfamily_id = pred_form->amopfamily;
                pred_strategy = (StrategyNumber) pred_form->amopstrategy;
                Assert(pred_strategy >= 1 && pred_strategy <= 5);
 
@@ -1341,37 +1342,39 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
                }
 
                /*
-                * From the same opclass, find a strategy number for the clause_op, if
-                * possible
+                * From the same opfamily, find a strategy number for the clause_op,
+                * if possible
                 */
                clause_tuple = SearchSysCache(AMOPOPID,
                                                                          ObjectIdGetDatum(clause_op),
-                                                                         ObjectIdGetDatum(opclass_id),
+                                                                         ObjectIdGetDatum(opfamily_id),
                                                                          0, 0);
                if (HeapTupleIsValid(clause_tuple))
                {
                        Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
 
-                       /* Get the restriction clause operator's strategy/subtype */
+                       /* Get the restriction clause operator's strategy/datatype */
                        clause_strategy = (StrategyNumber) clause_form->amopstrategy;
                        Assert(clause_strategy >= 1 && clause_strategy <= 5);
-                       clause_subtype = clause_form->amopsubtype;
+                       Assert(clause_form->amoplefttype == pred_form->amoplefttype);
+                       clause_righttype = clause_form->amoprighttype;
                        ReleaseSysCache(clause_tuple);
                }
                else if (OidIsValid(clause_op_negator))
                {
                        clause_tuple = SearchSysCache(AMOPOPID,
                                                                                  ObjectIdGetDatum(clause_op_negator),
-                                                                                 ObjectIdGetDatum(opclass_id),
+                                                                                 ObjectIdGetDatum(opfamily_id),
                                                                                  0, 0);
                        if (HeapTupleIsValid(clause_tuple))
                        {
                                Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
 
-                               /* Get the restriction clause operator's strategy/subtype */
+                               /* Get the restriction clause operator's strategy/datatype */
                                clause_strategy = (StrategyNumber) clause_form->amopstrategy;
                                Assert(clause_strategy >= 1 && clause_strategy <= 5);
-                               clause_subtype = clause_form->amopsubtype;
+                               Assert(clause_form->amoplefttype == pred_form->amoplefttype);
+                               clause_righttype = clause_form->amoprighttype;
                                ReleaseSysCache(clause_tuple);
 
                                /* Only consider negators that are = */
@@ -1400,20 +1403,24 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
                }
 
                /*
-                * See if opclass has an operator for the test strategy and the clause
-                * datatype.
+                * See if opfamily has an operator for the test strategy and the
+                * datatypes.
                 */
                if (test_strategy == BTNE)
                {
-                       test_op = get_opclass_member(opclass_id, clause_subtype,
-                                                                                BTEqualStrategyNumber);
+                       test_op = get_opfamily_member(opfamily_id,
+                                                                                 pred_form->amoprighttype,
+                                                                                 clause_righttype,
+                                                                                 BTEqualStrategyNumber);
                        if (OidIsValid(test_op))
                                test_op = get_negator(test_op);
                }
                else
                {
-                       test_op = get_opclass_member(opclass_id, clause_subtype,
-                                                                                test_strategy);
+                       test_op = get_opfamily_member(opfamily_id,
+                                                                                 pred_form->amoprighttype,
+                                                                                 clause_righttype,
+                                                                                 test_strategy);
                }
                if (OidIsValid(test_op))
                {
@@ -1423,7 +1430,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
                         * Note that we require only the test_op to be immutable, not the
                         * original clause_op.  (pred_op is assumed to have been checked
                         * immutable by the caller.)  Essentially we are assuming that the
-                        * opclass is consistent even if it contains operators that are
+                        * opfamily is consistent even if it contains operators that are
                         * merely stable.
                         */
                        if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE)
@@ -1438,7 +1445,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
 
        if (!found)
        {
-               /* couldn't find a btree opclass to interpret the operators */
+               /* couldn't find a btree opfamily to interpret the operators */
                return false;
        }
 
index 9176ae1680cb12fcba3fa1a185cc58efb94a8ddd..adfd9e478580eeb07574d84ab352ec50a879811b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.49 2006/10/04 00:29:55 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.50 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -342,6 +342,7 @@ make_restrictinfo_internal(Expr *clause,
        restrictinfo->mergejoinoperator = InvalidOid;
        restrictinfo->left_sortop = InvalidOid;
        restrictinfo->right_sortop = InvalidOid;
+       restrictinfo->mergeopfamily = InvalidOid;
 
        restrictinfo->left_pathkey = NIL;
        restrictinfo->right_pathkey = NIL;
index 234a15b6afbdc6073957b1a7635beba30f9fc899..2a48741b3a2fef31be935b3beacca84411c3c1f3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.200 2006/12/21 16:05:14 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.201 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2014,10 +2014,10 @@ make_row_comparison_op(ParseState *pstate, List *opname,
        RowCompareType rctype;
        List       *opexprs;
        List       *opnos;
-       List       *opclasses;
+       List       *opfamilies;
        ListCell   *l,
                           *r;
-       List      **opclass_lists;
+       List      **opfamily_lists;
        List      **opstrat_lists;
        Bitmapset  *strats;
        int                     nopers;
@@ -2057,7 +2057,7 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                /*
                 * We don't use coerce_to_boolean here because we insist on the
                 * operator yielding boolean directly, not via coercion.  If it
-                * doesn't yield bool it won't be in any index opclasses...
+                * doesn't yield bool it won't be in any index opfamilies...
                 */
                if (cmp->opresulttype != BOOLOID)
                        ereport(ERROR,
@@ -2084,21 +2084,22 @@ make_row_comparison_op(ParseState *pstate, List *opname,
 
        /*
         * Now we must determine which row comparison semantics (= <> < <= > >=)
-        * apply to this set of operators.      We look for btree opclasses containing
+        * apply to this set of operators.      We look for btree opfamilies containing
         * the operators, and see which interpretations (strategy numbers) exist
         * for each operator.
         */
-       opclass_lists = (List **) palloc(nopers * sizeof(List *));
+       opfamily_lists = (List **) palloc(nopers * sizeof(List *));
        opstrat_lists = (List **) palloc(nopers * sizeof(List *));
        strats = NULL;
        i = 0;
        foreach(l, opexprs)
        {
+               Oid                     opno = ((OpExpr *) lfirst(l))->opno;
                Bitmapset  *this_strats;
                ListCell   *j;
 
-               get_op_btree_interpretation(((OpExpr *) lfirst(l))->opno,
-                                                                       &opclass_lists[i], &opstrat_lists[i]);
+               get_op_btree_interpretation(opno,
+                                                                       &opfamily_lists[i], &opstrat_lists[i]);
 
                /*
                 * convert strategy number list to a Bitmapset to make the
@@ -2116,68 +2117,23 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                i++;
        }
 
-       switch (bms_membership(strats))
+       /*
+        * If there are multiple common interpretations, we may use any one of
+        * them ... this coding arbitrarily picks the lowest btree strategy
+        * number.
+        */
+       i = bms_first_member(strats);
+       if (i < 0)
        {
-               case BMS_EMPTY_SET:
-                       /* No common interpretation, so fail */
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("could not determine interpretation of row comparison operator %s",
-                                                       strVal(llast(opname))),
-                                        errhint("Row comparison operators must be associated with btree operator classes."),
-                                        parser_errposition(pstate, location)));
-                       rctype = 0;                     /* keep compiler quiet */
-                       break;
-               case BMS_SINGLETON:
-                       /* Simple case: just one possible interpretation */
-                       rctype = bms_singleton_member(strats);
-                       break;
-               case BMS_MULTIPLE:
-               default:                                /* keep compiler quiet */
-                       {
-                               /*
-                                * Prefer the interpretation with the most default opclasses.
-                                */
-                               int                     best_defaults = 0;
-                               bool            multiple_best = false;
-                               int                     this_rctype;
-
-                               rctype = 0;             /* keep compiler quiet */
-                               while ((this_rctype = bms_first_member(strats)) >= 0)
-                               {
-                                       int                     ndefaults = 0;
-
-                                       for (i = 0; i < nopers; i++)
-                                       {
-                                               forboth(l, opclass_lists[i], r, opstrat_lists[i])
-                                               {
-                                                       Oid                     opclass = lfirst_oid(l);
-                                                       int                     opstrat = lfirst_int(r);
-
-                                                       if (opstrat == this_rctype &&
-                                                               opclass_is_default(opclass))
-                                                               ndefaults++;
-                                               }
-                                       }
-                                       if (ndefaults > best_defaults)
-                                       {
-                                               best_defaults = ndefaults;
-                                               rctype = this_rctype;
-                                               multiple_best = false;
-                                       }
-                                       else if (ndefaults == best_defaults)
-                                               multiple_best = true;
-                               }
-                               if (best_defaults == 0 || multiple_best)
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                        errmsg("could not determine interpretation of row comparison operator %s",
-                                                                       strVal(llast(opname))),
-                                                        errdetail("There are multiple equally-plausible candidates."),
-                                                        parser_errposition(pstate, location)));
-                               break;
-                       }
+               /* No common interpretation, so fail */
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("could not determine interpretation of row comparison operator %s",
+                                               strVal(llast(opname))),
+                                errhint("Row comparison operators must be associated with btree operator families."),
+                                parser_errposition(pstate, location)));
        }
+       rctype = (RowCompareType) i;
 
        /*
         * For = and <> cases, we just combine the pairwise operators with AND or
@@ -2193,34 +2149,27 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                return (Node *) makeBoolExpr(OR_EXPR, opexprs);
 
        /*
-        * Otherwise we need to determine exactly which opclass to associate with
+        * Otherwise we need to choose exactly which opfamily to associate with
         * each operator.
         */
-       opclasses = NIL;
+       opfamilies = NIL;
        for (i = 0; i < nopers; i++)
        {
-               Oid                     best_opclass = 0;
-               int                     ndefault = 0;
-               int                     nmatch = 0;
+               Oid                     opfamily = InvalidOid;
 
-               forboth(l, opclass_lists[i], r, opstrat_lists[i])
+               forboth(l, opfamily_lists[i], r, opstrat_lists[i])
                {
-                       Oid                     opclass = lfirst_oid(l);
                        int                     opstrat = lfirst_int(r);
 
                        if (opstrat == rctype)
                        {
-                               if (ndefault == 0)
-                                       best_opclass = opclass;
-                               if (opclass_is_default(opclass))
-                                       ndefault++;
-                               else
-                                       nmatch++;
+                               opfamily = lfirst_oid(l);
+                               break;
                        }
                }
-               if (ndefault == 1 || (ndefault == 0 && nmatch == 1))
-                       opclasses = lappend_oid(opclasses, best_opclass);
-               else
+               if (OidIsValid(opfamily))
+                       opfamilies = lappend_oid(opfamilies, opfamily);
+               else                                    /* should not happen */
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("could not determine interpretation of row comparison operator %s",
@@ -2250,7 +2199,7 @@ make_row_comparison_op(ParseState *pstate, List *opname,
        rcexpr = makeNode(RowCompareExpr);
        rcexpr->rctype = rctype;
        rcexpr->opnos = opnos;
-       rcexpr->opclasses = opclasses;
+       rcexpr->opfamilies = opfamilies;
        rcexpr->largs = largs;
        rcexpr->rargs = rargs;
 
index a99942010b66a8c46ca404856c23283c12e253b6..b2ff95f457b758576b38504e6a1355384b87ec95 100644 (file)
@@ -2,7 +2,7 @@
  * ruleutils.c - Functions to convert stored expressions/querytrees
  *                             back to source text
  *
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.236 2006/12/21 16:05:15 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.237 2006/12/23 00:43:11 tgl Exp $
  **********************************************************************/
 
 #include "postgres.h"
@@ -19,6 +19,7 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_trigger.h"
+#include "commands/defrem.h"
 #include "executor/spi.h"
 #include "funcapi.h"
 #include "nodes/makefuncs.h"
@@ -4717,11 +4718,6 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
        Form_pg_opclass opcrec;
        char       *opcname;
        char       *nspname;
-       bool            isvisible;
-
-       /* Domains use their base type's default opclass */
-       if (OidIsValid(actual_datatype))
-               actual_datatype = getBaseType(actual_datatype);
 
        ht_opc = SearchSysCache(CLAOID,
                                                        ObjectIdGetDatum(opclass),
@@ -4730,25 +4726,12 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
                elog(ERROR, "cache lookup failed for opclass %u", opclass);
        opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
 
-       /*
-        * Special case for ARRAY_OPS: pretend it is default for any array type
-        */
-       if (OidIsValid(actual_datatype))
-       {
-               if (opcrec->opcintype == ANYARRAYOID &&
-                       OidIsValid(get_element_type(actual_datatype)))
-                       actual_datatype = opcrec->opcintype;
-       }
-
-       /* Must force use of opclass name if not in search path */
-       isvisible = OpclassIsVisible(opclass);
-
-       if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault ||
-               !isvisible)
+       if (!OidIsValid(actual_datatype) ||
+               GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
        {
                /* Okay, we need the opclass name.      Do we need to qualify it? */
                opcname = NameStr(opcrec->opcname);
-               if (isvisible)
+               if (OpclassIsVisible(opclass))
                        appendStringInfo(buf, " %s", quote_identifier(opcname));
                else
                {
index 230ce549f3bbd400764101edd76e09931653485c..73e82cd5e0194a7a740eb7ed7c09569522a0aaf5 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.215 2006/12/15 18:42:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.216 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,7 +76,7 @@
 #include <ctype.h>
 #include <math.h>
 
-#include "catalog/pg_opclass.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
 #include "mb/pg_wchar.h"
@@ -128,7 +128,7 @@ static double convert_timevalue_to_scalar(Datum value, Oid typid);
 static bool get_variable_maximum(PlannerInfo *root, VariableStatData *vardata,
                                         Oid sortop, Datum *max);
 static Selectivity prefix_selectivity(VariableStatData *vardata,
-                                  Oid opclass, Const *prefixcon);
+                                  Oid vartype, Oid opfamily, Const *prefixcon);
 static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
 static Datum string_to_datum(const char *str, Oid datatype);
 static Const *string_to_const(const char *str, Oid datatype);
@@ -911,7 +911,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
        Datum           constval;
        Oid                     consttype;
        Oid                     vartype;
-       Oid                     opclass;
+       Oid                     opfamily;
        Pattern_Prefix_Status pstatus;
        Const      *patt = NULL;
        Const      *prefix = NULL;
@@ -960,9 +960,9 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
         * Similarly, the exposed type of the left-hand side should be one of
         * those we know.  (Do not look at vardata.atttype, which might be
         * something binary-compatible but different.)  We can use it to choose
-        * the index opclass from which we must draw the comparison operators.
+        * the index opfamily from which we must draw the comparison operators.
         *
-        * NOTE: It would be more correct to use the PATTERN opclasses than the
+        * NOTE: It would be more correct to use the PATTERN opfamilies than the
         * simple ones, but at the moment ANALYZE will not generate statistics for
         * the PATTERN operators.  But our results are so approximate anyway that
         * it probably hardly matters.
@@ -972,19 +972,16 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
        switch (vartype)
        {
                case TEXTOID:
-                       opclass = TEXT_BTREE_OPS_OID;
-                       break;
-               case VARCHAROID:
-                       opclass = VARCHAR_BTREE_OPS_OID;
+                       opfamily = TEXT_BTREE_FAM_OID;
                        break;
                case BPCHAROID:
-                       opclass = BPCHAR_BTREE_OPS_OID;
+                       opfamily = BPCHAR_BTREE_FAM_OID;
                        break;
                case NAMEOID:
-                       opclass = NAME_BTREE_OPS_OID;
+                       opfamily = NAME_BTREE_FAM_OID;
                        break;
                case BYTEAOID:
-                       opclass = BYTEA_BTREE_OPS_OID;
+                       opfamily = BYTEA_BTREE_FAM_OID;
                        break;
                default:
                        ReleaseVariableStats(vardata);
@@ -1028,12 +1025,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
                /*
                 * Pattern specifies an exact match, so pretend operator is '='
                 */
-               Oid                     eqopr = get_opclass_member(opclass, InvalidOid,
-                                                                                          BTEqualStrategyNumber);
+               Oid                     eqopr = get_opfamily_member(opfamily, vartype, vartype,
+                                                                                               BTEqualStrategyNumber);
                List       *eqargs;
 
                if (eqopr == InvalidOid)
-                       elog(ERROR, "no = operator for opclass %u", opclass);
+                       elog(ERROR, "no = operator for opfamily %u", opfamily);
                eqargs = list_make2(variable, prefix);
                result = DatumGetFloat8(DirectFunctionCall4(eqsel,
                                                                                                        PointerGetDatum(root),
@@ -1074,7 +1071,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
                        Selectivity restsel;
 
                        if (pstatus == Pattern_Prefix_Partial)
-                               prefixsel = prefix_selectivity(&vardata, opclass, prefix);
+                               prefixsel = prefix_selectivity(&vardata, vartype,
+                                                                                          opfamily, prefix);
                        else
                                prefixsel = 1.0;
                        restsel = pattern_selectivity(rest, ptype);
@@ -2114,7 +2112,8 @@ icnlikejoinsel(PG_FUNCTION_ARGS)
  * we can estimate how much of the input will actually be read.  This
  * can have a considerable impact on the cost when using indexscans.
  *
- * clause should be a clause already known to be mergejoinable.
+ * clause should be a clause already known to be mergejoinable.  opfamily and
+ * strategy specify the sort ordering being used.
  *
  * *leftscan is set to the fraction of the left-hand variable expected
  * to be scanned (0 to 1), and similarly *rightscan for the right-hand
@@ -2122,6 +2121,7 @@ icnlikejoinsel(PG_FUNCTION_ARGS)
  */
 void
 mergejoinscansel(PlannerInfo *root, Node *clause,
+                                Oid opfamily, int strategy,
                                 Selectivity *leftscan,
                                 Selectivity *rightscan)
 {
@@ -2129,15 +2129,14 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
                           *right;
        VariableStatData leftvar,
                                rightvar;
-       Oid                     lefttype,
-                               righttype;
+       int                     op_strategy;
+       Oid                     op_lefttype;
+       Oid                     op_righttype;
+       bool            op_recheck;
        Oid                     opno,
                                lsortop,
                                rsortop,
-                               ltop,
-                               gtop,
                                leop,
-                               revgtop,
                                revleop;
        Datum           leftmax,
                                rightmax;
@@ -2159,15 +2158,51 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
        examine_variable(root, left, 0, &leftvar);
        examine_variable(root, right, 0, &rightvar);
 
-       /* Get the direct input types of the operator */
-       lefttype = exprType(left);
-       righttype = exprType(right);
+       /* Extract the operator's declared left/right datatypes */
+       get_op_opfamily_properties(opno, opfamily,
+                                                          &op_strategy,
+                                                          &op_lefttype,
+                                                          &op_righttype,
+                                                          &op_recheck);
+       Assert(op_strategy == BTEqualStrategyNumber);
+       Assert(!op_recheck);
+
+       /*
+        * Look up the various operators we need.  If we don't find them all,
+        * it probably means the opfamily is broken, but we cope anyway.
+        */
+       switch (strategy)
+       {
+               case BTLessStrategyNumber:
+                       lsortop = get_opfamily_member(opfamily, op_lefttype, op_lefttype,
+                                                                                 BTLessStrategyNumber);
+                       rsortop = get_opfamily_member(opfamily, op_righttype, op_righttype,
+                                                                                 BTLessStrategyNumber);
+                       leop = get_opfamily_member(opfamily, op_lefttype, op_righttype,
+                                                                          BTLessEqualStrategyNumber);
+                       revleop = get_opfamily_member(opfamily, op_righttype, op_lefttype,
+                                                                                 BTLessEqualStrategyNumber);
+                       break;
+               case BTGreaterStrategyNumber:
+                       /* descending-order case */
+                       lsortop = get_opfamily_member(opfamily, op_lefttype, op_lefttype,
+                                                                                 BTGreaterStrategyNumber);
+                       rsortop = get_opfamily_member(opfamily, op_righttype, op_righttype,
+                                                                                 BTGreaterStrategyNumber);
+                       leop = get_opfamily_member(opfamily, op_lefttype, op_righttype,
+                                                                          BTGreaterEqualStrategyNumber);
+                       revleop = get_opfamily_member(opfamily, op_righttype, op_lefttype,
+                                                                                 BTGreaterEqualStrategyNumber);
+                       break;
+               default:
+                       goto fail;                      /* shouldn't get here */
+       }
 
-       /* Verify mergejoinability and get left and right "<" operators */
-       if (!op_mergejoinable(opno,
-                                                 &lsortop,
-                                                 &rsortop))
-               goto fail;                              /* shouldn't happen */
+       if (!OidIsValid(lsortop) ||
+               !OidIsValid(rsortop) ||
+               !OidIsValid(leop) ||
+               !OidIsValid(revleop))
+               goto fail;                              /* insufficient info in catalogs */
 
        /* Try to get maximum values of both inputs */
        if (!get_variable_maximum(root, &leftvar, lsortop, &leftmax))
@@ -2176,37 +2211,19 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
        if (!get_variable_maximum(root, &rightvar, rsortop, &rightmax))
                goto fail;                              /* no max available from stats */
 
-       /* Look up the "left < right" and "left > right" operators */
-       op_mergejoin_crossops(opno, &ltop, &gtop, NULL, NULL);
-
-       /* Look up the "left <= right" operator */
-       leop = get_negator(gtop);
-       if (!OidIsValid(leop))
-               goto fail;                              /* insufficient info in catalogs */
-
-       /* Look up the "right > left" operator */
-       revgtop = get_commutator(ltop);
-       if (!OidIsValid(revgtop))
-               goto fail;                              /* insufficient info in catalogs */
-
-       /* Look up the "right <= left" operator */
-       revleop = get_negator(revgtop);
-       if (!OidIsValid(revleop))
-               goto fail;                              /* insufficient info in catalogs */
-
        /*
         * Now, the fraction of the left variable that will be scanned is the
         * fraction that's <= the right-side maximum value.  But only believe
         * non-default estimates, else stick with our 1.0.
         */
        selec = scalarineqsel(root, leop, false, &leftvar,
-                                                 rightmax, righttype);
+                                                 rightmax, op_righttype);
        if (selec != DEFAULT_INEQ_SEL)
                *leftscan = selec;
 
        /* And similarly for the right variable. */
        selec = scalarineqsel(root, revleop, false, &rightvar,
-                                                 leftmax, lefttype);
+                                                 leftmax, op_lefttype);
        if (selec != DEFAULT_INEQ_SEL)
                *rightscan = selec;
 
@@ -3486,7 +3503,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
                 * statistics.
                 *
                 * XXX it's conceivable that there are multiple matches with different
-                * index opclasses; if so, we need to pick one that matches the
+                * index opfamilies; if so, we need to pick one that matches the
                 * operator we are estimating for.      FIXME later.
                 */
                ListCell   *ilist;
@@ -4100,7 +4117,7 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
  * population represented by the histogram --- the caller must fold this
  * together with info about MCVs and NULLs.
  *
- * We use the >= and < operators from the specified btree opclass to do the
+ * We use the >= and < operators from the specified btree opfamily to do the
  * estimation. The given variable and Const must be of the associated
  * datatype.
  *
@@ -4110,17 +4127,18 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
  * more useful to use the upper-bound code than not.
  */
 static Selectivity
-prefix_selectivity(VariableStatData *vardata, Oid opclass, Const *prefixcon)
+prefix_selectivity(VariableStatData *vardata,
+                                  Oid vartype, Oid opfamily, Const *prefixcon)
 {
        Selectivity prefixsel;
        Oid                     cmpopr;
        FmgrInfo        opproc;
        Const      *greaterstrcon;
 
-       cmpopr = get_opclass_member(opclass, InvalidOid,
-                                                               BTGreaterEqualStrategyNumber);
+       cmpopr = get_opfamily_member(opfamily, vartype, vartype,
+                                                                BTGreaterEqualStrategyNumber);
        if (cmpopr == InvalidOid)
-               elog(ERROR, "no >= operator for opclass %u", opclass);
+               elog(ERROR, "no >= operator for opfamily %u", opfamily);
        fmgr_info(get_opcode(cmpopr), &opproc);
 
        prefixsel = ineq_histogram_selectivity(vardata, &opproc, true,
@@ -4143,10 +4161,10 @@ prefix_selectivity(VariableStatData *vardata, Oid opclass, Const *prefixcon)
        {
                Selectivity topsel;
 
-               cmpopr = get_opclass_member(opclass, InvalidOid,
-                                                                       BTLessStrategyNumber);
+               cmpopr = get_opfamily_member(opfamily, vartype, vartype,
+                                                                        BTLessStrategyNumber);
                if (cmpopr == InvalidOid)
-                       elog(ERROR, "no < operator for opclass %u", opclass);
+                       elog(ERROR, "no < operator for opfamily %u", opfamily);
                fmgr_info(get_opcode(cmpopr), &opproc);
 
                topsel = ineq_histogram_selectivity(vardata, &opproc, false,
@@ -4921,7 +4939,7 @@ btcostestimate(PG_FUNCTION_ARGS)
                }
                else if (match_index_to_operand(rightop, indexcol, index))
                {
-                       /* Must flip operator to get the opclass member */
+                       /* Must flip operator to get the opfamily member */
                        clause_op = get_commutator(clause_op);
                }
                else
@@ -4937,7 +4955,7 @@ btcostestimate(PG_FUNCTION_ARGS)
                        }
                        else if (match_index_to_operand(rightop, indexcol, index))
                        {
-                               /* Must flip operator to get the opclass member */
+                               /* Must flip operator to get the opfamily member */
                                clause_op = get_commutator(clause_op);
                        }
                        else
@@ -4946,9 +4964,9 @@ btcostestimate(PG_FUNCTION_ARGS)
                                break;
                        }
                }
-               op_strategy = get_op_opclass_strategy(clause_op,
-                                                                                         index->classlist[indexcol]);
-               Assert(op_strategy != 0);               /* not a member of opclass?? */
+               op_strategy = get_op_opfamily_strategy(clause_op,
+                                                                                          index->opfamily[indexcol]);
+               Assert(op_strategy != 0);               /* not a member of opfamily?? */
                if (op_strategy == BTEqualStrategyNumber)
                        eqQualHere = true;
                /* count up number of SA scans induced by indexBoundQuals only */
index 55b9d5baf07334ada84dd0309739049d1ef8b627..1a1d19f399ab5391a6f01680b73f6e97b1302cad 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.134 2006/10/06 18:23:35 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.135 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1033,9 +1033,10 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
        if (cache->id == INDEXRELID)
        {
                /*
-                * Since the OIDs of indexes aren't hardwired, it's painful to figure
-                * out which is which.  Just force all pg_index searches to be heap
-                * scans while building the relcaches.
+                * Rather than tracking exactly which indexes have to be loaded
+                * before we can use indexscans (which changes from time to time),
+                * just force all pg_index searches to be heap scans until we've
+                * built the critical relcaches.
                 */
                if (!criticalRelcachesBuilt)
                        return false;
@@ -1051,17 +1052,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
                 */
                return false;
        }
-       else if (cache->id == OPEROID)
-       {
-               if (!criticalRelcachesBuilt)
-               {
-                       /* Looking for an OID comparison function? */
-                       Oid                     lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
-
-                       if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
-                               return false;
-               }
-       }
 
        /* Normal case, allow index scan */
        return true;
index fdc31e0d97741362b45e9752dd3c04c584a73c80..824ef4a1efe9d2e2f7fef3d013286b3c9a4f1950 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.138 2006/10/04 00:30:00 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.139 2006/12/23 00:43:11 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
 /*                             ---------- AMOP CACHES ----------                                                */
 
 /*
- * op_in_opclass
+ * op_in_opfamily
  *
- *             Return t iff operator 'opno' is in operator class 'opclass'.
+ *             Return t iff operator 'opno' is in operator family 'opfamily'.
  */
 bool
-op_in_opclass(Oid opno, Oid opclass)
+op_in_opfamily(Oid opno, Oid opfamily)
 {
        return SearchSysCacheExists(AMOPOPID,
                                                                ObjectIdGetDatum(opno),
-                                                               ObjectIdGetDatum(opclass),
+                                                               ObjectIdGetDatum(opfamily),
                                                                0, 0);
 }
 
 /*
- * get_op_opclass_strategy
+ * get_op_opfamily_strategy
  *
- *             Get the operator's strategy number within the specified opclass,
- *             or 0 if it's not a member of the opclass.
+ *             Get the operator's strategy number within the specified opfamily,
+ *             or 0 if it's not a member of the opfamily.
  */
 int
-get_op_opclass_strategy(Oid opno, Oid opclass)
+get_op_opfamily_strategy(Oid opno, Oid opfamily)
 {
        HeapTuple       tp;
        Form_pg_amop amop_tup;
@@ -65,7 +65,7 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
 
        tp = SearchSysCache(AMOPOPID,
                                                ObjectIdGetDatum(opno),
-                                               ObjectIdGetDatum(opclass),
+                                               ObjectIdGetDatum(opfamily),
                                                0, 0);
        if (!HeapTupleIsValid(tp))
                return 0;
@@ -76,54 +76,59 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
 }
 
 /*
- * get_op_opclass_properties
+ * get_op_opfamily_properties
  *
- *             Get the operator's strategy number, subtype, and recheck (lossy) flag
- *             within the specified opclass.
+ *             Get the operator's strategy number, input types, and recheck (lossy)
+ *             flag within the specified opfamily.
  *
- * Caller should already have verified that opno is a member of opclass,
+ * Caller should already have verified that opno is a member of opfamily,
  * therefore we raise an error if the tuple is not found.
  */
 void
-get_op_opclass_properties(Oid opno, Oid opclass,
-                                                 int *strategy, Oid *subtype, bool *recheck)
+get_op_opfamily_properties(Oid opno, Oid opfamily,
+                                                  int *strategy,
+                                                  Oid *lefttype,
+                                                  Oid *righttype,
+                                                  bool *recheck)
 {
        HeapTuple       tp;
        Form_pg_amop amop_tup;
 
        tp = SearchSysCache(AMOPOPID,
                                                ObjectIdGetDatum(opno),
-                                               ObjectIdGetDatum(opclass),
+                                               ObjectIdGetDatum(opfamily),
                                                0, 0);
        if (!HeapTupleIsValid(tp))
-               elog(ERROR, "operator %u is not a member of opclass %u",
-                        opno, opclass);
+               elog(ERROR, "operator %u is not a member of opfamily %u",
+                        opno, opfamily);
        amop_tup = (Form_pg_amop) GETSTRUCT(tp);
        *strategy = amop_tup->amopstrategy;
-       *subtype = amop_tup->amopsubtype;
+       *lefttype = amop_tup->amoplefttype;
+       *righttype = amop_tup->amoprighttype;
        *recheck = amop_tup->amopreqcheck;
        ReleaseSysCache(tp);
 }
 
 /*
- * get_opclass_member
+ * get_opfamily_member
  *             Get the OID of the operator that implements the specified strategy
- *             with the specified subtype for the specified opclass.
+ *             with the specified datatypes for the specified opfamily.
  *
  * Returns InvalidOid if there is no pg_amop entry for the given keys.
  */
 Oid
-get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
+get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
+                                       int16 strategy)
 {
        HeapTuple       tp;
        Form_pg_amop amop_tup;
        Oid                     result;
 
        tp = SearchSysCache(AMOPSTRATEGY,
-                                               ObjectIdGetDatum(opclass),
-                                               ObjectIdGetDatum(subtype),
-                                               Int16GetDatum(strategy),
-                                               0);
+                                               ObjectIdGetDatum(opfamily),
+                                               ObjectIdGetDatum(lefttype),
+                                               ObjectIdGetDatum(righttype),
+                                               Int16GetDatum(strategy));
        if (!HeapTupleIsValid(tp))
                return InvalidOid;
        amop_tup = (Form_pg_amop) GETSTRUCT(tp);
@@ -132,11 +137,161 @@ get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
        return result;
 }
 
+/*
+ * get_op_mergejoin_info
+ *             Given the OIDs of a (putatively) mergejoinable equality operator
+ *             and a sortop defining the sort ordering of the lefthand input of
+ *             the merge clause, determine whether this sort ordering is actually
+ *             usable for merging.  If so, return the required sort ordering op
+ *             for the righthand input, as well as the btree opfamily OID containing
+ *             these operators and the operator strategy number of the two sortops
+ *             (either BTLessStrategyNumber or BTGreaterStrategyNumber).
+ *
+ * We can mergejoin if we find the two operators in the same opfamily as
+ * equality and either less-than or greater-than respectively.  If there
+ * are multiple such opfamilies, assume we can use any one.
+ */
+#ifdef NOT_YET
+/* eventually should look like this */
+bool
+get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
+                                         Oid *right_sortop, Oid *opfamily, int *opstrategy)
+{
+       bool            result = false;
+       Oid                     lefttype;
+       Oid                     righttype;
+       CatCList   *catlist;
+       int                     i;
+
+       /* Make sure output args are initialized even on failure */
+       *right_sortop = InvalidOid;
+       *opfamily = InvalidOid;
+       *opstrategy = 0;
+
+       /* Need the righthand input datatype */
+       op_input_types(eq_op, &lefttype, &righttype);
+
+       /*
+        * Search through all the pg_amop entries containing the equality operator
+        */
+       catlist = SearchSysCacheList(AMOPOPID, 1,
+                                                                ObjectIdGetDatum(eq_op),
+                                                                0, 0, 0);
+
+       for (i = 0; i < catlist->n_members; i++)
+       {
+               HeapTuple       op_tuple = &catlist->members[i]->tuple;
+               Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
+               Oid                     opfamily_id;
+               StrategyNumber op_strategy;
+
+               /* must be btree */
+               if (op_form->amopmethod != BTREE_AM_OID)
+                       continue;
+               /* must use the operator as equality */
+               if (op_form->amopstrategy != BTEqualStrategyNumber)
+                       continue;
+
+               /* See if sort operator is also in this opclass with OK semantics */
+               opfamily_id = op_form->amopfamily;
+               op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
+               if (op_strategy == BTLessStrategyNumber ||
+                       op_strategy == BTGreaterStrategyNumber)
+               {
+                       /* Yes, so find the corresponding righthand sortop */
+                       *right_sortop = get_opfamily_member(opfamily_id,
+                                                                                               righttype,
+                                                                                               righttype,
+                                                                                               op_strategy);
+                       if (OidIsValid(*right_sortop))
+                       {
+                               /* Found a workable mergejoin semantics */
+                               *opfamily = opfamily_id;
+                               *opstrategy = op_strategy;
+                               result = true;
+                               break;
+                       }
+               }
+       }
+
+       ReleaseSysCacheList(catlist);
+
+       return result;
+}
+#else
+/* temp implementation until planner gets smarter: left_sortop is output */
+bool
+get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
+                                         Oid *right_sortop, Oid *opfamily)
+{
+       bool            result = false;
+       Oid                     lefttype;
+       Oid                     righttype;
+       CatCList   *catlist;
+       int                     i;
+
+       /* Make sure output args are initialized even on failure */
+       *left_sortop = InvalidOid;
+       *right_sortop = InvalidOid;
+       *opfamily = InvalidOid;
+
+       /* Need the input datatypes */
+       op_input_types(eq_op, &lefttype, &righttype);
+
+       /*
+        * Search through all the pg_amop entries containing the equality operator
+        */
+       catlist = SearchSysCacheList(AMOPOPID, 1,
+                                                                ObjectIdGetDatum(eq_op),
+                                                                0, 0, 0);
+
+       for (i = 0; i < catlist->n_members; i++)
+       {
+               HeapTuple       op_tuple = &catlist->members[i]->tuple;
+               Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
+               Oid                     opfamily_id;
+
+               /* must be btree */
+               if (op_form->amopmethod != BTREE_AM_OID)
+                       continue;
+               /* must use the operator as equality */
+               if (op_form->amopstrategy != BTEqualStrategyNumber)
+                       continue;
+
+               opfamily_id = op_form->amopfamily;
+
+               /* Find the matching sortops */
+               *left_sortop = get_opfamily_member(opfamily_id,
+                                                                                  lefttype,
+                                                                                  lefttype,
+                                                                                  BTLessStrategyNumber);
+               *right_sortop = get_opfamily_member(opfamily_id,
+                                                                                       righttype,
+                                                                                       righttype,
+                                                                                       BTLessStrategyNumber);
+               if (OidIsValid(*left_sortop) && OidIsValid(*right_sortop))
+               {
+                       /* Found a workable mergejoin semantics */
+                       *opfamily = opfamily_id;
+                       result = true;
+                       break;
+               }
+       }
+
+       ReleaseSysCacheList(catlist);
+
+       return result;
+}
+#endif
+
 /*
  * get_op_hash_function
  *             Get the OID of the datatype-specific hash function associated with
  *             a hashable equality operator.
  *
+ * XXX API needs to be generalized for the case of different left and right
+ * datatypes.
+ *
  * Returns InvalidOid if no hash function can be found.  (This indicates
  * that the operator should not have been marked oprcanhash.)
  */
@@ -145,12 +300,12 @@ get_op_hash_function(Oid opno)
 {
        CatCList   *catlist;
        int                     i;
-       Oid                     opclass = InvalidOid;
+       Oid                     result = InvalidOid;
 
        /*
         * Search pg_amop to see if the target operator is registered as the "="
-        * operator of any hash opclass.  If the operator is registered in
-        * multiple opclasses, assume we can use the associated hash function from
+        * operator of any hash opfamily.  If the operator is registered in
+        * multiple opfamilies, assume we can use the associated hash function from
         * any one.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
@@ -162,57 +317,43 @@ get_op_hash_function(Oid opno)
                HeapTuple       tuple = &catlist->members[i]->tuple;
                Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
 
-               if (aform->amopstrategy == HTEqualStrategyNumber &&
-                       opclass_is_hash(aform->amopclaid))
+               if (aform->amopmethod == HASH_AM_OID &&
+                       aform->amopstrategy == HTEqualStrategyNumber)
                {
-                       opclass = aform->amopclaid;
+                       /* Found a suitable opfamily, get matching hash support function */
+                       result = get_opfamily_proc(aform->amopfamily,
+                                                                          aform->amoplefttype,
+                                                                          aform->amoprighttype,
+                                                                          HASHPROC);
                        break;
                }
        }
 
        ReleaseSysCacheList(catlist);
 
-       if (OidIsValid(opclass))
-       {
-               /* Found a suitable opclass, get its default hash support function */
-               return get_opclass_proc(opclass, InvalidOid, HASHPROC);
-       }
-
-       /* Didn't find a match... */
-       return InvalidOid;
+       return result;
 }
 
 /*
  * get_op_btree_interpretation
- *             Given an operator's OID, find out which btree opclasses it belongs to,
+ *             Given an operator's OID, find out which btree opfamilies it belongs to,
  *             and what strategy number it has within each one.  The results are
  *             returned as an OID list and a parallel integer list.
  *
  * In addition to the normal btree operators, we consider a <> operator to be
- * a "member" of an opclass if its negator is the opclass' equality operator.
- * ROWCOMPARE_NE is returned as the strategy number for this case.
+ * a "member" of an opfamily if its negator is an equality operator of the
+ * opfamily.  ROWCOMPARE_NE is returned as the strategy number for this case.
  */
 void
-get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
+get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
 {
-       Oid                     lefttype,
-                               righttype;
        CatCList   *catlist;
        bool            op_negated;
        int                     i;
 
-       *opclasses = NIL;
+       *opfamilies = NIL;
        *opstrats = NIL;
 
-       /*
-        * Get the nominal left-hand input type of the operator; we will ignore
-        * opclasses that don't have that as the expected input datatype.  This is
-        * a kluge to avoid being confused by binary-compatible opclasses (such as
-        * text_ops and varchar_ops, which share the same operators).
-        */
-       op_input_types(opno, &lefttype, &righttype);
-       Assert(OidIsValid(lefttype));
-
        /*
         * Find all the pg_amop entries containing the operator.
         */
@@ -221,8 +362,8 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
                                                                 0, 0, 0);
 
        /*
-        * If we can't find any opclass containing the op, perhaps it is a <>
-        * operator.  See if it has a negator that is in an opclass.
+        * If we can't find any opfamily containing the op, perhaps it is a <>
+        * operator.  See if it has a negator that is in an opfamily.
         */
        op_negated = false;
        if (catlist->n_members == 0)
@@ -239,25 +380,20 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
                }
        }
 
-       /* Now search the opclasses */
+       /* Now search the opfamilies */
        for (i = 0; i < catlist->n_members; i++)
        {
                HeapTuple       op_tuple = &catlist->members[i]->tuple;
                Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
-               Oid                     opclass_id;
+               Oid                     opfamily_id;
                StrategyNumber op_strategy;
 
-               opclass_id = op_form->amopclaid;
-
                /* must be btree */
-               if (!opclass_is_btree(opclass_id))
-                       continue;
-
-               /* must match operator input type exactly */
-               if (get_opclass_input_type(opclass_id) != lefttype)
+               if (op_form->amopmethod != BTREE_AM_OID)
                        continue;
 
                /* Get the operator's btree strategy number */
+               opfamily_id = op_form->amopfamily;
                op_strategy = (StrategyNumber) op_form->amopstrategy;
                Assert(op_strategy >= 1 && op_strategy <= 5);
 
@@ -269,7 +405,7 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
                        op_strategy = ROWCOMPARE_NE;
                }
 
-               *opclasses = lappend_oid(*opclasses, opclass_id);
+               *opfamilies = lappend_oid(*opfamilies, opfamily_id);
                *opstrats = lappend_int(*opstrats, op_strategy);
        }
 
@@ -280,24 +416,24 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
 /*                             ---------- AMPROC CACHES ----------                                              */
 
 /*
- * get_opclass_proc
+ * get_opfamily_proc
  *             Get the OID of the specified support function
- *             for the specified opclass and subtype.
+ *             for the specified opfamily and datatypes.
  *
  * Returns InvalidOid if there is no pg_amproc entry for the given keys.
  */
 Oid
-get_opclass_proc(Oid opclass, Oid subtype, int16 procnum)
+get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
 {
        HeapTuple       tp;
        Form_pg_amproc amproc_tup;
        RegProcedure result;
 
        tp = SearchSysCache(AMPROCNUM,
-                                               ObjectIdGetDatum(opclass),
-                                               ObjectIdGetDatum(subtype),
-                                               Int16GetDatum(procnum),
-                                               0);
+                                               ObjectIdGetDatum(opfamily),
+                                               ObjectIdGetDatum(lefttype),
+                                               ObjectIdGetDatum(righttype),
+                                               Int16GetDatum(procnum));
        if (!HeapTupleIsValid(tp))
                return InvalidOid;
        amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
@@ -477,67 +613,16 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
 /*                             ---------- OPCLASS CACHE ----------                                              */
 
 /*
- * opclass_is_btree
+ * get_opclass_family
  *
- *             Returns TRUE iff the specified opclass is associated with the
- *             btree index access method.
+ *             Returns the OID of the operator family the opclass belongs to.
  */
-bool
-opclass_is_btree(Oid opclass)
-{
-       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 == BTREE_AM_OID);
-       ReleaseSysCache(tp);
-       return result;
-}
-
-/*
- * opclass_is_hash
- *
- *             Returns TRUE iff the specified opclass is associated with the
- *             hash index access method.
- */
-bool
-opclass_is_hash(Oid opclass)
-{
-       HeapTuple       tp;
-       Form_pg_opclass cla_tup;
-       bool            result;
-
-       tp = SearchSysCache(CLAOID,
-                                               ObjectIdGetDatum(opclass),
-                                               0, 0, 0);
-       if (!HeapTupleIsValid(tp))
-               elog(ERROR, "cache lookup failed for opclass %u", opclass);
-       cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
-
-       result = (cla_tup->opcamid == HASH_AM_OID);
-       ReleaseSysCache(tp);
-       return result;
-}
-
-/*
- * opclass_is_default
- *
- *             Returns TRUE iff the specified opclass is the default for its
- *             index access method and input data type.
- */
-bool
-opclass_is_default(Oid opclass)
+Oid
+get_opclass_family(Oid opclass)
 {
        HeapTuple       tp;
        Form_pg_opclass cla_tup;
-       bool            result;
+       Oid                     result;
 
        tp = SearchSysCache(CLAOID,
                                                ObjectIdGetDatum(opclass),
@@ -546,7 +631,7 @@ opclass_is_default(Oid opclass)
                elog(ERROR, "cache lookup failed for opclass %u", opclass);
        cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
 
-       result = cla_tup->opcdefault;
+       result = cla_tup->opcfamily;
        ReleaseSysCache(tp);
        return result;
 }
@@ -657,11 +742,13 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
 /*
  * op_mergejoinable
  *
- *             Returns the left and right sort operators corresponding to a
- *             mergejoinable operator, or false if the operator is not mergejoinable.
+ * Returns true if the operator is potentially mergejoinable.  (The planner
+ * will fail to find any mergejoin plans unless there are suitable btree
+ * opfamily entries for this operator and associated sortops.  The pg_operator
+ * flag is just a hint to tell the planner whether to bother looking.)
  */
 bool
-op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
+op_mergejoinable(Oid opno)
 {
        HeapTuple       tp;
        bool            result = false;
@@ -673,65 +760,17 @@ op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
 
-               if (optup->oprlsortop &&
-                       optup->oprrsortop)
-               {
-                       *leftOp = optup->oprlsortop;
-                       *rightOp = optup->oprrsortop;
-                       result = true;
-               }
+               result = optup->oprcanmerge;
                ReleaseSysCache(tp);
        }
        return result;
 }
 
-/*
- * op_mergejoin_crossops
- *
- *             Returns the cross-type comparison operators (ltype "<" rtype and
- *             ltype ">" rtype) for an operator previously determined to be
- *             mergejoinable.  Optionally, fetches the regproc ids of these
- *             operators, as well as their operator OIDs.
- */
-void
-op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
-                                         RegProcedure *ltproc, RegProcedure *gtproc)
-{
-       HeapTuple       tp;
-       Form_pg_operator optup;
-
-       /*
-        * Get the declared comparison operators of the operator.
-        */
-       tp = SearchSysCache(OPEROID,
-                                               ObjectIdGetDatum(opno),
-                                               0, 0, 0);
-       if (!HeapTupleIsValid(tp))      /* shouldn't happen */
-               elog(ERROR, "cache lookup failed for operator %u", opno);
-       optup = (Form_pg_operator) GETSTRUCT(tp);
-       *ltop = optup->oprltcmpop;
-       *gtop = optup->oprgtcmpop;
-       ReleaseSysCache(tp);
-
-       /* Check < op provided */
-       if (!OidIsValid(*ltop))
-               elog(ERROR, "mergejoin operator %u has no matching < operator",
-                        opno);
-       if (ltproc)
-               *ltproc = get_opcode(*ltop);
-
-       /* Check > op provided */
-       if (!OidIsValid(*gtop))
-               elog(ERROR, "mergejoin operator %u has no matching > operator",
-                        opno);
-       if (gtproc)
-               *gtproc = get_opcode(*gtop);
-}
-
 /*
  * op_hashjoinable
  *
- * Returns true if the operator is hashjoinable.
+ * Returns true if the operator is hashjoinable.  (There must be a suitable
+ * hash opfamily entry for this operator if it is so marked.)
  */
 bool
 op_hashjoinable(Oid opno)
index 65cd1e72907b155695271c030159445300832c4e..be5fb60dc8e7528722e5ed416629483c2a3bef7e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.250 2006/11/05 23:40:30 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.251 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,7 +69,7 @@
  */
 #define RELCACHE_INIT_FILENAME "pg_internal.init"
 
-#define RELCACHE_INIT_FILEMAGIC                0x573263        /* version ID value */
+#define RELCACHE_INIT_FILEMAGIC                0x573264        /* version ID value */
 
 /*
  *             hardcoded tuple descriptors.  see include/catalog/pg_attribute.h
@@ -159,7 +159,8 @@ do { \
 /*
  * Special cache for opclass-related information
  *
- * Note: only default-subtype operators and support procs get cached
+ * Note: only default operators and support procs get cached, ie, those with
+ * lefttype = righttype = opcintype.
  */
 typedef struct opclasscacheent
 {
@@ -167,6 +168,8 @@ typedef struct opclasscacheent
        bool            valid;                  /* set TRUE after successful fill-in */
        StrategyNumber numStrats;       /* max # of strategies (from pg_am) */
        StrategyNumber numSupport;      /* max # of support procs (from pg_am) */
+       Oid                     opcfamily;              /* OID of opclass's family */
+       Oid                     opcintype;              /* OID of opclass's declared input type */
        Oid                *operatorOids;       /* strategy operators' OIDs */
        RegProcedure *supportProcs; /* support procs */
 } OpClassCacheEnt;
@@ -201,6 +204,8 @@ static List *insert_ordered_oid(List *list, Oid datum);
 static void IndexSupportInitialize(oidvector *indclass,
                                           Oid *indexOperator,
                                           RegProcedure *indexSupport,
+                                          Oid *opFamily,
+                                          Oid *opcInType,
                                           StrategyNumber maxStrategyNumber,
                                           StrategyNumber maxSupportNumber,
                                           AttrNumber maxAttributeNumber);
@@ -921,11 +926,9 @@ RelationInitIndexAccessInfo(Relation relation)
        Form_pg_am      aform;
        Datum           indclassDatum;
        bool            isnull;
+       oidvector  *indclass;
        MemoryContext indexcxt;
        MemoryContext oldcontext;
-       Oid                *operator;
-       RegProcedure *support;
-       FmgrInfo   *supportinfo;
        int                     natts;
        uint16          amstrategies;
        uint16          amsupport;
@@ -947,18 +950,6 @@ RelationInitIndexAccessInfo(Relation relation)
        MemoryContextSwitchTo(oldcontext);
        ReleaseSysCache(tuple);
 
-       /*
-        * indclass cannot be referenced directly through the C struct, because it
-        * is after the variable-width indkey field.  Therefore we extract the
-        * datum the hard way and provide a direct link in the relcache.
-        */
-       indclassDatum = fastgetattr(relation->rd_indextuple,
-                                                               Anum_pg_index_indclass,
-                                                               GetPgIndexDescriptor(),
-                                                               &isnull);
-       Assert(!isnull);
-       relation->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum);
-
        /*
         * Make a copy of the pg_am entry for the index's access method
         */
@@ -1001,38 +992,53 @@ RelationInitIndexAccessInfo(Relation relation)
        relation->rd_aminfo = (RelationAmInfo *)
                MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
 
+       relation->rd_opfamily = (Oid *)
+               MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
+       relation->rd_opcintype = (Oid *)
+               MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
+
        if (amstrategies > 0)
-               operator = (Oid *)
+               relation->rd_operator = (Oid *)
                        MemoryContextAllocZero(indexcxt,
                                                                   natts * amstrategies * sizeof(Oid));
        else
-               operator = NULL;
+               relation->rd_operator = NULL;
 
        if (amsupport > 0)
        {
                int                     nsupport = natts * amsupport;
 
-               support = (RegProcedure *)
+               relation->rd_support = (RegProcedure *)
                        MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
-               supportinfo = (FmgrInfo *)
+               relation->rd_supportinfo = (FmgrInfo *)
                        MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
        }
        else
        {
-               support = NULL;
-               supportinfo = NULL;
+               relation->rd_support = NULL;
+               relation->rd_supportinfo = NULL;
        }
 
-       relation->rd_operator = operator;
-       relation->rd_support = support;
-       relation->rd_supportinfo = supportinfo;
+       /*
+        * indclass cannot be referenced directly through the C struct, because it
+        * comes after the variable-width indkey field.  Must extract the
+        * datum the hard way...
+        */
+       indclassDatum = fastgetattr(relation->rd_indextuple,
+                                                               Anum_pg_index_indclass,
+                                                               GetPgIndexDescriptor(),
+                                                               &isnull);
+       Assert(!isnull);
+       indclass = (oidvector *) DatumGetPointer(indclassDatum);
 
        /*
-        * Fill the operator and support procedure OID arrays.  (aminfo and
+        * Fill the operator and support procedure OID arrays, as well as the
+        * info about opfamilies and opclass input types.  (aminfo and
         * supportinfo are left as zeroes, and are filled on-the-fly when used)
         */
-       IndexSupportInitialize(relation->rd_indclass,
-                                                  operator, support,
+       IndexSupportInitialize(indclass,
+                                                  relation->rd_operator, relation->rd_support,
+                                                  relation->rd_opfamily, relation->rd_opcintype,
                                                   amstrategies, amsupport, natts);
 
        /*
@@ -1048,8 +1054,8 @@ RelationInitIndexAccessInfo(Relation relation)
  *             Initializes an index's cached opclass information,
  *             given the index's pg_index.indclass entry.
  *
- * Data is returned into *indexOperator and *indexSupport, which are arrays
- * allocated by the caller.
+ * Data is returned into *indexOperator, *indexSupport, *opFamily, and
+ * *opcInType, which are arrays allocated by the caller.
  *
  * The caller also passes maxStrategyNumber, maxSupportNumber, and
  * maxAttributeNumber, since these indicate the size of the arrays
@@ -1061,6 +1067,8 @@ static void
 IndexSupportInitialize(oidvector *indclass,
                                           Oid *indexOperator,
                                           RegProcedure *indexSupport,
+                                          Oid *opFamily,
+                                          Oid *opcInType,
                                           StrategyNumber maxStrategyNumber,
                                           StrategyNumber maxSupportNumber,
                                           AttrNumber maxAttributeNumber)
@@ -1080,6 +1088,8 @@ IndexSupportInitialize(oidvector *indclass,
                                                                         maxSupportNumber);
 
                /* copy cached data into relcache entry */
+               opFamily[attIndex] = opcentry->opcfamily;
+               opcInType[attIndex] = opcentry->opcintype;
                if (maxStrategyNumber > 0)
                        memcpy(&indexOperator[attIndex * maxStrategyNumber],
                                   opcentry->operatorOids,
@@ -1116,7 +1126,7 @@ LookupOpclassInfo(Oid operatorClassOid,
        bool            found;
        Relation        rel;
        SysScanDesc scan;
-       ScanKeyData skey[2];
+       ScanKeyData skey[3];
        HeapTuple       htup;
        bool            indexOK;
 
@@ -1176,23 +1186,55 @@ LookupOpclassInfo(Oid operatorClassOid,
                (operatorClassOid != OID_BTREE_OPS_OID &&
                 operatorClassOid != INT2_BTREE_OPS_OID);
 
+       /*
+        * We have to fetch the pg_opclass row to determine its opfamily and
+        * opcintype, which are needed to look up the operators and functions.
+        * It'd be convenient to use the syscache here, but that probably doesn't
+        * work while bootstrapping.
+        */
+       ScanKeyInit(&skey[0],
+                               ObjectIdAttributeNumber,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(operatorClassOid));
+       rel = heap_open(OperatorClassRelationId, AccessShareLock);
+       scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
+                                                         SnapshotNow, 1, skey);
+
+       if (HeapTupleIsValid(htup = systable_getnext(scan)))
+       {
+               Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
+
+               opcentry->opcfamily = opclassform->opcfamily;
+               opcentry->opcintype = opclassform->opcintype;
+       }
+       else
+               elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
+
+       systable_endscan(scan);
+       heap_close(rel, AccessShareLock);
+
+
        /*
         * Scan pg_amop to obtain operators for the opclass.  We only fetch the
-        * default ones (those with subtype zero).
+        * default ones (those with lefttype = righttype = opcintype).
         */
        if (numStrats > 0)
        {
                ScanKeyInit(&skey[0],
-                                       Anum_pg_amop_amopclaid,
+                                       Anum_pg_amop_amopfamily,
                                        BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(operatorClassOid));
+                                       ObjectIdGetDatum(opcentry->opcfamily));
                ScanKeyInit(&skey[1],
-                                       Anum_pg_amop_amopsubtype,
+                                       Anum_pg_amop_amoplefttype,
+                                       BTEqualStrategyNumber, F_OIDEQ,
+                                       ObjectIdGetDatum(opcentry->opcintype));
+               ScanKeyInit(&skey[2],
+                                       Anum_pg_amop_amoprighttype,
                                        BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(InvalidOid));
+                                       ObjectIdGetDatum(opcentry->opcintype));
                rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);
                scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,
-                                                                 SnapshotNow, 2, skey);
+                                                                 SnapshotNow, 3, skey);
 
                while (HeapTupleIsValid(htup = systable_getnext(scan)))
                {
@@ -1212,21 +1254,25 @@ LookupOpclassInfo(Oid operatorClassOid,
 
        /*
         * Scan pg_amproc to obtain support procs for the opclass.      We only fetch
-        * the default ones (those with subtype zero).
+        * the default ones (those with lefttype = righttype = opcintype).
         */
        if (numSupport > 0)
        {
                ScanKeyInit(&skey[0],
-                                       Anum_pg_amproc_amopclaid,
+                                       Anum_pg_amproc_amprocfamily,
                                        BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(operatorClassOid));
+                                       ObjectIdGetDatum(opcentry->opcfamily));
                ScanKeyInit(&skey[1],
-                                       Anum_pg_amproc_amprocsubtype,
+                                       Anum_pg_amproc_amproclefttype,
                                        BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(InvalidOid));
+                                       ObjectIdGetDatum(opcentry->opcintype));
+               ScanKeyInit(&skey[2],
+                                       Anum_pg_amproc_amprocrighttype,
+                                       BTEqualStrategyNumber, F_OIDEQ,
+                                       ObjectIdGetDatum(opcentry->opcintype));
                rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
                scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
-                                                                 SnapshotNow, 2, skey);
+                                                                 SnapshotNow, 3, skey);
 
                while (HeapTupleIsValid(htup = systable_getnext(scan)))
                {
@@ -3097,8 +3143,6 @@ load_relcache_init_file(void)
                Relation        rel;
                Form_pg_class relform;
                bool            has_not_null;
-               Datum           indclassDatum;
-               bool            isnull;
 
                /* first read the relation descriptor length */
                if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
@@ -3187,6 +3231,8 @@ load_relcache_init_file(void)
                {
                        Form_pg_am      am;
                        MemoryContext indexcxt;
+                       Oid                *opfamily;
+                       Oid                *opcintype;
                        Oid                *operator;
                        RegProcedure *support;
                        int                     nsupport;
@@ -3207,14 +3253,6 @@ load_relcache_init_file(void)
                        rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
                        rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple);
 
-                       /* fix up indclass pointer too */
-                       indclassDatum = fastgetattr(rel->rd_indextuple,
-                                                                               Anum_pg_index_indclass,
-                                                                               GetPgIndexDescriptor(),
-                                                                               &isnull);
-                       Assert(!isnull);
-                       rel->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum);
-
                        /* next, read the access method tuple form */
                        if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
                                goto read_failed;
@@ -3235,6 +3273,26 @@ load_relcache_init_file(void)
                                                                                         ALLOCSET_SMALL_MAXSIZE);
                        rel->rd_indexcxt = indexcxt;
 
+                       /* next, read the vector of opfamily OIDs */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
+
+                       opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
+                       if ((nread = fread(opfamily, 1, len, fp)) != len)
+                               goto read_failed;
+
+                       rel->rd_opfamily = opfamily;
+
+                       /* next, read the vector of opcintype OIDs */
+                       if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+                               goto read_failed;
+
+                       opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
+                       if ((nread = fread(opcintype, 1, len, fp)) != len)
+                               goto read_failed;
+
+                       rel->rd_opcintype = opcintype;
+
                        /* next, read the vector of operator OIDs */
                        if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
                                goto read_failed;
@@ -3269,10 +3327,11 @@ load_relcache_init_file(void)
 
                        Assert(rel->rd_index == NULL);
                        Assert(rel->rd_indextuple == NULL);
-                       Assert(rel->rd_indclass == NULL);
                        Assert(rel->rd_am == NULL);
                        Assert(rel->rd_indexcxt == NULL);
                        Assert(rel->rd_aminfo == NULL);
+                       Assert(rel->rd_opfamily == NULL);
+                       Assert(rel->rd_opcintype == NULL);
                        Assert(rel->rd_operator == NULL);
                        Assert(rel->rd_support == NULL);
                        Assert(rel->rd_supportinfo == NULL);
@@ -3450,6 +3509,16 @@ write_relcache_init_file(void)
                        /* next, write the access method tuple form */
                        write_item(am, sizeof(FormData_pg_am), fp);
 
+                       /* next, write the vector of opfamily OIDs */
+                       write_item(rel->rd_opfamily,
+                                          relform->relnatts * sizeof(Oid),
+                                          fp);
+
+                       /* next, write the vector of opcintype OIDs */
+                       write_item(rel->rd_opcintype,
+                                          relform->relnatts * sizeof(Oid),
+                                          fp);
+
                        /* next, write the vector of operator OIDs */
                        write_item(rel->rd_operator,
                                           relform->relnatts * (am->amstrategies * sizeof(Oid)),
index e19fba05840bb1f5dd03156420edb61c36f18fb0..f2fb0796cbb833ef46b5196ed08dcd44f956f191 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.108 2006/10/06 18:23:35 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.109 2006/12/23 00:43:11 tgl Exp $
  *
  * NOTES
  *       These routines allow the parser/planner/executor to perform
 #include "catalog/pg_cast.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_inherits.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_statistic.h"
@@ -135,7 +135,7 @@ static const struct cachedesc cacheinfo[] = {
                2,
                {
                        Anum_pg_amop_amopopr,
-                       Anum_pg_amop_amopclaid,
+                       Anum_pg_amop_amopfamily,
                        0,
                        0
                },
@@ -144,24 +144,24 @@ static const struct cachedesc cacheinfo[] = {
        {AccessMethodOperatorRelationId,        /* AMOPSTRATEGY */
                AccessMethodStrategyIndexId,
                0,
-               3,
+               4,
                {
-                       Anum_pg_amop_amopclaid,
-                       Anum_pg_amop_amopsubtype,
-                       Anum_pg_amop_amopstrategy,
-                       0
+                       Anum_pg_amop_amopfamily,
+                       Anum_pg_amop_amoplefttype,
+                       Anum_pg_amop_amoprighttype,
+                       Anum_pg_amop_amopstrategy
                },
                64
        },
        {AccessMethodProcedureRelationId,       /* AMPROCNUM */
                AccessMethodProcedureIndexId,
                0,
-               3,
+               4,
                {
-                       Anum_pg_amproc_amopclaid,
-                       Anum_pg_amproc_amprocsubtype,
-                       Anum_pg_amproc_amprocnum,
-                       0
+                       Anum_pg_amproc_amprocfamily,
+                       Anum_pg_amproc_amproclefttype,
+                       Anum_pg_amproc_amprocrighttype,
+                       Anum_pg_amproc_amprocnum
                },
                64
        },
@@ -255,7 +255,7 @@ static const struct cachedesc cacheinfo[] = {
                0,
                3,
                {
-                       Anum_pg_opclass_opcamid,
+                       Anum_pg_opclass_opcmethod,
                        Anum_pg_opclass_opcname,
                        Anum_pg_opclass_opcnamespace,
                        0
@@ -334,18 +334,6 @@ static const struct cachedesc cacheinfo[] = {
                },
                1024
        },
-       {InheritsRelationId,            /* INHRELID */
-               InheritsRelidSeqnoIndexId,
-               Anum_pg_inherits_inhrelid,
-               2,
-               {
-                       Anum_pg_inherits_inhrelid,
-                       Anum_pg_inherits_inhseqno,
-                       0,
-                       0
-               },
-               256
-       },
        {LanguageRelationId,            /* LANGNAME */
                LanguageNameIndexId,
                0,
@@ -418,6 +406,30 @@ static const struct cachedesc cacheinfo[] = {
                },
                1024
        },
+       {OperatorFamilyRelationId,      /* OPFAMILYAMNAMENSP */
+               OpfamilyAmNameNspIndexId,
+               0,
+               3,
+               {
+                       Anum_pg_opfamily_opfmethod,
+                       Anum_pg_opfamily_opfname,
+                       Anum_pg_opfamily_opfnamespace,
+                       0
+               },
+               64
+       },
+       {OperatorFamilyRelationId,      /* OPFAMILYOID */
+               OpfamilyOidIndexId,
+               0,
+               1,
+               {
+                       ObjectIdAttributeNumber,
+                       0,
+                       0,
+                       0
+               },
+               64
+       },
        {ProcedureRelationId,           /* PROCNAMEARGSNSP */
                ProcedureNameArgsNspIndexId,
                0,
index c5a0272414d55994e74bf7b4fdd85ce2e8a8efe4..192675c95ee6d9c603fd002e23fa3e6c7982d419 100644 (file)
@@ -36,7 +36,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.22 2006/10/04 00:30:01 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.23 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -165,17 +165,30 @@ lookup_type_cache(Oid type_id, int flags)
        /* If we haven't already found the opclass, try to do so */
        if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR |
                                  TYPECACHE_CMP_PROC |
-                                 TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO)) &&
-               typentry->btree_opc == InvalidOid)
+                                 TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO |
+                                 TYPECACHE_BTREE_OPFAMILY)) &&
+               typentry->btree_opf == InvalidOid)
        {
-               typentry->btree_opc = GetDefaultOpClass(type_id,
-                                                                                               BTREE_AM_OID);
+               Oid             opclass;
+
+               opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
+               if (OidIsValid(opclass))
+               {
+                       typentry->btree_opf = get_opclass_family(opclass);
+                       typentry->btree_opintype = get_opclass_input_type(opclass);
+               }
                /* Only care about hash opclass if no btree opclass... */
-               if (typentry->btree_opc == InvalidOid)
+               if (typentry->btree_opf == InvalidOid)
                {
-                       if (typentry->hash_opc == InvalidOid)
-                               typentry->hash_opc = GetDefaultOpClass(type_id,
-                                                                                                          HASH_AM_OID);
+                       if (typentry->hash_opf == InvalidOid)
+                       {
+                               opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
+                               if (OidIsValid(opclass))
+                               {
+                                       typentry->hash_opf = get_opclass_family(opclass);
+                                       typentry->hash_opintype = get_opclass_input_type(opclass);
+                               }
+                       }
                }
                else
                {
@@ -193,37 +206,42 @@ lookup_type_cache(Oid type_id, int flags)
        if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
                typentry->eq_opr == InvalidOid)
        {
-               if (typentry->btree_opc != InvalidOid)
-                       typentry->eq_opr = get_opclass_member(typentry->btree_opc,
-                                                                                                 InvalidOid,
-                                                                                                 BTEqualStrategyNumber);
+               if (typentry->btree_opf != InvalidOid)
+                       typentry->eq_opr = get_opfamily_member(typentry->btree_opf,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  BTEqualStrategyNumber);
                if (typentry->eq_opr == InvalidOid &&
-                       typentry->hash_opc != InvalidOid)
-                       typentry->eq_opr = get_opclass_member(typentry->hash_opc,
-                                                                                                 InvalidOid,
-                                                                                                 HTEqualStrategyNumber);
+                       typentry->hash_opf != InvalidOid)
+                       typentry->eq_opr = get_opfamily_member(typentry->hash_opf,
+                                                                                                  typentry->hash_opintype,
+                                                                                                  typentry->hash_opintype,
+                                                                                                  HTEqualStrategyNumber);
        }
        if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
        {
-               if (typentry->btree_opc != InvalidOid)
-                       typentry->lt_opr = get_opclass_member(typentry->btree_opc,
-                                                                                                 InvalidOid,
-                                                                                                 BTLessStrategyNumber);
+               if (typentry->btree_opf != InvalidOid)
+                       typentry->lt_opr = get_opfamily_member(typentry->btree_opf,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  BTLessStrategyNumber);
        }
        if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
        {
-               if (typentry->btree_opc != InvalidOid)
-                       typentry->gt_opr = get_opclass_member(typentry->btree_opc,
-                                                                                                 InvalidOid,
-                                                                                                 BTGreaterStrategyNumber);
+               if (typentry->btree_opf != InvalidOid)
+                       typentry->gt_opr = get_opfamily_member(typentry->btree_opf,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  BTGreaterStrategyNumber);
        }
        if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
                typentry->cmp_proc == InvalidOid)
        {
-               if (typentry->btree_opc != InvalidOid)
-                       typentry->cmp_proc = get_opclass_proc(typentry->btree_opc,
-                                                                                                 InvalidOid,
-                                                                                                 BTORDER_PROC);
+               if (typentry->btree_opf != InvalidOid)
+                       typentry->cmp_proc = get_opfamily_proc(typentry->btree_opf,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  typentry->btree_opintype,
+                                                                                                  BTORDER_PROC);
        }
 
        /*
index 652f9a2ff44b36a915faf5dcb69e227043a08b1b..dceaf5a6556314403a62a17b0e87d8e5a2dfc734 100644 (file)
@@ -91,7 +91,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.70 2006/10/04 00:30:04 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.71 2006/12/23 00:43:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2104,15 +2104,16 @@ SelectSortFunction(Oid sortOperator,
        int                     i;
        HeapTuple       tuple;
        Form_pg_operator optup;
-       Oid                     opclass = InvalidOid;
+       Oid                     opfamily = InvalidOid;
+       Oid                     opinputtype = InvalidOid;
 
        /*
-        * Search pg_amop to see if the target operator is registered as the "<"
-        * or ">" operator of any btree opclass.  It's possible that it might be
+        * Search pg_amop to see if the target operator is registered as a "<"
+        * or ">" operator of any btree opfamily.  It's possible that it might be
         * registered both ways (eg, if someone were to build a "reverse sort"
-        * opclass for some reason); prefer the "<" case if so. If the operator is
-        * registered the same way in multiple opclasses, assume we can use the
-        * associated comparator function from any one.
+        * opfamily); prefer the "<" case if so. If the operator is registered the
+        * same way in multiple opfamilies, assume we can use the associated
+        * comparator function from any one.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
                                                                 ObjectIdGetDatum(sortOperator),
@@ -2125,21 +2126,24 @@ SelectSortFunction(Oid sortOperator,
                tuple = &catlist->members[i]->tuple;
                aform = (Form_pg_amop) GETSTRUCT(tuple);
 
-               if (!opclass_is_btree(aform->amopclaid))
+               /* must be btree */
+               if (aform->amopmethod != BTREE_AM_OID)
                        continue;
-               /* must be of default subtype, too */
-               if (aform->amopsubtype != InvalidOid)
+               /* mustn't be cross-datatype, either */
+               if (aform->amoplefttype != aform->amoprighttype)
                        continue;
 
                if (aform->amopstrategy == BTLessStrategyNumber)
                {
-                       opclass = aform->amopclaid;
+                       opfamily = aform->amopfamily;
+                       opinputtype = aform->amoplefttype;
                        *kind = SORTFUNC_CMP;
                        break;                          /* done looking */
                }
                else if (aform->amopstrategy == BTGreaterStrategyNumber)
                {
-                       opclass = aform->amopclaid;
+                       opfamily = aform->amopfamily;
+                       opinputtype = aform->amoplefttype;
                        *kind = SORTFUNC_REVCMP;
                        /* keep scanning in hopes of finding a BTLess entry */
                }
@@ -2147,10 +2151,13 @@ SelectSortFunction(Oid sortOperator,
 
        ReleaseSysCacheList(catlist);
 
-       if (OidIsValid(opclass))
+       if (OidIsValid(opfamily))
        {
-               /* Found a suitable opclass, get its default comparator function */
-               *sortFunction = get_opclass_proc(opclass, InvalidOid, BTORDER_PROC);
+               /* Found a suitable opfamily, get the matching comparator function */
+               *sortFunction = get_opfamily_proc(opfamily,
+                                                                                 opinputtype,
+                                                                                 opinputtype,
+                                                                                 BTORDER_PROC);
                Assert(RegProcedureIsValid(*sortFunction));
                return;
        }
index ce5439a1dd12ab5ab9c55c1a9a3b7c4a61c9e296..cd31e135deeb0bf793ce48793db5d8bf28bed448 100644 (file)
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * Portions taken from FreeBSD.
  *
- * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.125 2006/10/04 18:58:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.126 2006/12/23 00:43:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1590,7 +1590,8 @@ setup_depend(void)
                 * dependencies seems hard.
                 *
                 * Note that we deliberately do not pin the system views, which
-                * haven't been created yet.
+                * haven't been created yet.  Also, no conversions, databases,
+                * or tablespaces are pinned.
                 *
                 * First delete any already-made entries; PINs override all else, and
                 * must be the only entries for their objects.
@@ -1619,6 +1620,12 @@ setup_depend(void)
                "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
                " FROM pg_opclass;\n",
                "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_opfamily;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_amop;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_amproc;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
                " FROM pg_rewrite;\n",
                "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
                " FROM pg_trigger;\n",
index c4df03083e116dd8889d655e422a87b06a6b1dec..ae8d54936f18f47d2a9ba7e14d6a321026864f2d 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.453 2006/10/09 23:36:59 tgl Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.454 2006/12/23 00:43:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -6219,11 +6219,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        int                     i_oprnegate;
        int                     i_oprrest;
        int                     i_oprjoin;
+       int                     i_oprcanmerge;
        int                     i_oprcanhash;
-       int                     i_oprlsortop;
-       int                     i_oprrsortop;
-       int                     i_oprltcmpop;
-       int                     i_oprgtcmpop;
        char       *oprkind;
        char       *oprcode;
        char       *oprleft;
@@ -6232,11 +6229,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        char       *oprnegate;
        char       *oprrest;
        char       *oprjoin;
+       char       *oprcanmerge;
        char       *oprcanhash;
-       char       *oprlsortop;
-       char       *oprrsortop;
-       char       *oprltcmpop;
-       char       *oprgtcmpop;
 
        /* Skip if not to be dumped */
        if (!oprinfo->dobj.dump || dataOnly)
@@ -6258,7 +6252,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        /* Make sure we are in proper schema so regoperator works correctly */
        selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
 
-       if (g_fout->remoteVersion >= 70300)
+       if (g_fout->remoteVersion >= 80300)
        {
                appendPQExpBuffer(query, "SELECT oprkind, "
                                                  "oprcode::pg_catalog.regprocedure, "
@@ -6268,11 +6262,23 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
                                                  "oprnegate::pg_catalog.regoperator, "
                                                  "oprrest::pg_catalog.regprocedure, "
                                                  "oprjoin::pg_catalog.regprocedure, "
-                                                 "oprcanhash, "
-                                                 "oprlsortop::pg_catalog.regoperator, "
-                                                 "oprrsortop::pg_catalog.regoperator, "
-                                                 "oprltcmpop::pg_catalog.regoperator, "
-                                                 "oprgtcmpop::pg_catalog.regoperator "
+                                                 "oprcanmerge, oprcanhash "
+                                                 "from pg_catalog.pg_operator "
+                                                 "where oid = '%u'::pg_catalog.oid",
+                                                 oprinfo->dobj.catId.oid);
+       }
+       else if (g_fout->remoteVersion >= 70300)
+       {
+               appendPQExpBuffer(query, "SELECT oprkind, "
+                                                 "oprcode::pg_catalog.regprocedure, "
+                                                 "oprleft::pg_catalog.regtype, "
+                                                 "oprright::pg_catalog.regtype, "
+                                                 "oprcom::pg_catalog.regoperator, "
+                                                 "oprnegate::pg_catalog.regoperator, "
+                                                 "oprrest::pg_catalog.regprocedure, "
+                                                 "oprjoin::pg_catalog.regprocedure, "
+                                                 "(oprlsortop != 0) as oprcanmerge, "
+                                                 "oprcanhash "
                                                  "from pg_catalog.pg_operator "
                                                  "where oid = '%u'::pg_catalog.oid",
                                                  oprinfo->dobj.catId.oid);
@@ -6285,8 +6291,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
                                                  "CASE WHEN oprright = 0 THEN '-' "
                                                  "ELSE format_type(oprright, NULL) END as oprright, "
                                                  "oprcom, oprnegate, oprrest, oprjoin, "
-                                                 "oprcanhash, oprlsortop, oprrsortop, "
-                                                 "0 as oprltcmpop, 0 as oprgtcmpop "
+                                                 "(oprlsortop != 0) as oprcanmerge, "
+                                                 "oprcanhash "
                                                  "from pg_operator "
                                                  "where oid = '%u'::oid",
                                                  oprinfo->dobj.catId.oid);
@@ -6299,8 +6305,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
                                                  "CASE WHEN oprright = 0 THEN '-'::name "
                                                  "ELSE (select typname from pg_type where oid = oprright) END as oprright, "
                                                  "oprcom, oprnegate, oprrest, oprjoin, "
-                                                 "oprcanhash, oprlsortop, oprrsortop, "
-                                                 "0 as oprltcmpop, 0 as oprgtcmpop "
+                                                 "(oprlsortop != 0) as oprcanmerge, "
+                                                 "oprcanhash "
                                                  "from pg_operator "
                                                  "where oid = '%u'::oid",
                                                  oprinfo->dobj.catId.oid);
@@ -6326,11 +6332,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        i_oprnegate = PQfnumber(res, "oprnegate");
        i_oprrest = PQfnumber(res, "oprrest");
        i_oprjoin = PQfnumber(res, "oprjoin");
+       i_oprcanmerge = PQfnumber(res, "oprcanmerge");
        i_oprcanhash = PQfnumber(res, "oprcanhash");
-       i_oprlsortop = PQfnumber(res, "oprlsortop");
-       i_oprrsortop = PQfnumber(res, "oprrsortop");
-       i_oprltcmpop = PQfnumber(res, "oprltcmpop");
-       i_oprgtcmpop = PQfnumber(res, "oprgtcmpop");
 
        oprkind = PQgetvalue(res, 0, i_oprkind);
        oprcode = PQgetvalue(res, 0, i_oprcode);
@@ -6340,11 +6343,8 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        oprnegate = PQgetvalue(res, 0, i_oprnegate);
        oprrest = PQgetvalue(res, 0, i_oprrest);
        oprjoin = PQgetvalue(res, 0, i_oprjoin);
+       oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
        oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
-       oprlsortop = PQgetvalue(res, 0, i_oprlsortop);
-       oprrsortop = PQgetvalue(res, 0, i_oprrsortop);
-       oprltcmpop = PQgetvalue(res, 0, i_oprltcmpop);
-       oprgtcmpop = PQgetvalue(res, 0, i_oprgtcmpop);
 
        appendPQExpBuffer(details, "    PROCEDURE = %s",
                                          convertRegProcReference(oprcode));
@@ -6390,6 +6390,9 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        if (name)
                appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
 
+       if (strcmp(oprcanmerge, "t") == 0)
+               appendPQExpBuffer(details, ",\n    MERGES");
+
        if (strcmp(oprcanhash, "t") == 0)
                appendPQExpBuffer(details, ",\n    HASHES");
 
@@ -6401,22 +6404,6 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        if (name)
                appendPQExpBuffer(details, ",\n    JOIN = %s", name);
 
-       name = convertOperatorReference(oprlsortop);
-       if (name)
-               appendPQExpBuffer(details, ",\n    SORT1 = %s", name);
-
-       name = convertOperatorReference(oprrsortop);
-       if (name)
-               appendPQExpBuffer(details, ",\n    SORT2 = %s", name);
-
-       name = convertOperatorReference(oprltcmpop);
-       if (name)
-               appendPQExpBuffer(details, ",\n    LTCMP = %s", name);
-
-       name = convertOperatorReference(oprgtcmpop);
-       if (name)
-               appendPQExpBuffer(details, ",\n    GTCMP = %s", name);
-
        /*
         * DROP must be fully qualified in case same name appears in pg_catalog
         */
@@ -6608,13 +6595,26 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
 
        /* Get additional fields from the pg_opclass row */
-       appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
-                                         "opckeytype::pg_catalog.regtype, "
-                                         "opcdefault, "
-          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
-                                         "FROM pg_catalog.pg_opclass "
-                                         "WHERE oid = '%u'::pg_catalog.oid",
-                                         opcinfo->dobj.catId.oid);
+       if (g_fout->remoteVersion >= 80300)
+       {
+               appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
+                                                 "opckeytype::pg_catalog.regtype, "
+                                                 "opcdefault, "
+                                                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
+                                                 "FROM pg_catalog.pg_opclass "
+                                                 "WHERE oid = '%u'::pg_catalog.oid",
+                                                 opcinfo->dobj.catId.oid);
+       }
+       else
+       {
+               appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
+                                                 "opckeytype::pg_catalog.regtype, "
+                                                 "opcdefault, "
+                                                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
+                                                 "FROM pg_catalog.pg_opclass "
+                                                 "WHERE oid = '%u'::pg_catalog.oid",
+                                                 opcinfo->dobj.catId.oid);
+       }
 
        res = PQexec(g_conn, query->data);
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@@ -6674,12 +6674,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
         */
        resetPQExpBuffer(query);
 
-       appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
-                                         "amopopr::pg_catalog.regoperator "
-                                         "FROM pg_catalog.pg_amop "
-                                         "WHERE amopclaid = '%u'::pg_catalog.oid "
-                                         "ORDER BY amopstrategy",
-                                         opcinfo->dobj.catId.oid);
+       if (g_fout->remoteVersion >= 80300)
+       {
+               /*
+                * Print only those opfamily members that are tied to the opclass
+                * by pg_depend entries.
+                */
+               appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+                                                 "amopopr::pg_catalog.regoperator "
+                                                 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::regclass "
+                                                 "AND refobjid = '%u'::pg_catalog.oid "
+                                                 "AND classid = 'pg_catalog.pg_amop'::regclass "
+                                                 "AND objid = ao.oid "
+                                                 "ORDER BY amopstrategy",
+                                                 opcinfo->dobj.catId.oid);
+       }
+       else
+       {
+               appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+                                                 "amopopr::pg_catalog.regoperator "
+                                                 "FROM pg_catalog.pg_amop "
+                                                 "WHERE amopclaid = '%u'::pg_catalog.oid "
+                                                 "ORDER BY amopstrategy",
+                                                 opcinfo->dobj.catId.oid);
+       }
 
        res = PQexec(g_conn, query->data);
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@@ -6714,12 +6733,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
         */
        resetPQExpBuffer(query);
 
-       appendPQExpBuffer(query, "SELECT amprocnum, "
-                                         "amproc::pg_catalog.regprocedure "
-                                         "FROM pg_catalog.pg_amproc "
-                                         "WHERE amopclaid = '%u'::pg_catalog.oid "
-                                         "ORDER BY amprocnum",
-                                         opcinfo->dobj.catId.oid);
+       if (g_fout->remoteVersion >= 80300)
+       {
+               /*
+                * Print only those opfamily members that are tied to the opclass
+                * by pg_depend entries.
+                */
+               appendPQExpBuffer(query, "SELECT amprocnum, "
+                                                 "amproc::pg_catalog.regprocedure "
+                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
+                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::regclass "
+                                                 "AND refobjid = '%u'::pg_catalog.oid "
+                                                 "AND classid = 'pg_catalog.pg_amproc'::regclass "
+                                                 "AND objid = ap.oid "
+                                                 "ORDER BY amprocnum",
+                                                 opcinfo->dobj.catId.oid);
+       }
+       else
+       {
+               appendPQExpBuffer(query, "SELECT amprocnum, "
+                                                 "amproc::pg_catalog.regprocedure "
+                                                 "FROM pg_catalog.pg_amproc "
+                                                 "WHERE amopclaid = '%u'::pg_catalog.oid "
+                                                 "ORDER BY amprocnum",
+                                                 opcinfo->dobj.catId.oid);
+       }
 
        res = PQexec(g_conn, query->data);
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
index 945c9a1b2293d74e3abd4d1f169defa212844cc1..f0a840a3ddef5d349d23362731a9968b3b167258 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.364 2006/12/21 18:32:56 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.365 2006/12/23 00:43:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200612201
+#define CATALOG_VERSION_NO     200612221
 
 #endif
index da7d7ac8e4eb1c830b77d64159cebd7f9225e774..b3ec0ccf2c68d87f2762ba5d0c0f0bdacbbdc145 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.27 2006/08/21 00:57:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.28 2006/12/23 00:43:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -131,6 +131,9 @@ typedef enum ObjectClass
        OCLASS_LANGUAGE,                        /* pg_language */
        OCLASS_OPERATOR,                        /* pg_operator */
        OCLASS_OPCLASS,                         /* pg_opclass */
+       OCLASS_OPFAMILY,                        /* pg_opfamily */
+       OCLASS_AMOP,                            /* pg_amop */
+       OCLASS_AMPROC,                          /* pg_amproc */
        OCLASS_REWRITE,                         /* pg_rewrite */
        OCLASS_TRIGGER,                         /* pg_trigger */
        OCLASS_SCHEMA,                          /* pg_namespace */
index 6587b34db720d377ecdc61c571a1731228b2407a..215119afd04dac3b8763cb906fe5e5b9c57c8767 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.95 2006/07/13 17:47:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.96 2006/12/23 00:43:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,13 +65,17 @@ DECLARE_UNIQUE_INDEX(pg_am_name_index, 2651, on pg_am using btree(amname name_op
 DECLARE_UNIQUE_INDEX(pg_am_oid_index, 2652, on pg_am using btree(oid oid_ops));
 #define AmOidIndexId  2652
 
-DECLARE_UNIQUE_INDEX(pg_amop_opc_strat_index, 2653, on pg_amop using btree(amopclaid oid_ops, amopsubtype oid_ops, amopstrategy int2_ops));
+DECLARE_UNIQUE_INDEX(pg_amop_fam_strat_index, 2653, on pg_amop using btree(amopfamily oid_ops, amoplefttype oid_ops, amoprighttype oid_ops, amopstrategy int2_ops));
 #define AccessMethodStrategyIndexId  2653
-DECLARE_UNIQUE_INDEX(pg_amop_opr_opc_index, 2654, on pg_amop using btree(amopopr oid_ops, amopclaid oid_ops));
+DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amopfamily oid_ops));
 #define AccessMethodOperatorIndexId  2654
+DECLARE_UNIQUE_INDEX(pg_amop_oid_index, 2756, on pg_amop using btree(oid oid_ops));
+#define AccessMethodOperatorOidIndexId  2756
 
-DECLARE_UNIQUE_INDEX(pg_amproc_opc_proc_index, 2655, on pg_amproc using btree(amopclaid oid_ops, amprocsubtype oid_ops, amprocnum int2_ops));
+DECLARE_UNIQUE_INDEX(pg_amproc_fam_proc_index, 2655, on pg_amproc using btree(amprocfamily oid_ops, amproclefttype oid_ops, amprocrighttype oid_ops, amprocnum int2_ops));
 #define AccessMethodProcedureIndexId  2655
+DECLARE_UNIQUE_INDEX(pg_amproc_oid_index, 2757, on pg_amproc using btree(oid oid_ops));
+#define AccessMethodProcedureOidIndexId  2757
 
 DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops));
 #define AttrDefaultIndexId     2656
@@ -164,7 +168,7 @@ DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btr
 DECLARE_UNIQUE_INDEX(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops));
 #define NamespaceOidIndexId  2685
 
-DECLARE_UNIQUE_INDEX(pg_opclass_am_name_nsp_index, 2686, on pg_opclass using btree(opcamid oid_ops, opcname name_ops, opcnamespace oid_ops));
+DECLARE_UNIQUE_INDEX(pg_opclass_am_name_nsp_index, 2686, on pg_opclass using btree(opcmethod oid_ops, opcname name_ops, opcnamespace oid_ops));
 #define OpclassAmNameNspIndexId  2686
 DECLARE_UNIQUE_INDEX(pg_opclass_oid_index, 2687, on pg_opclass using btree(oid oid_ops));
 #define OpclassOidIndexId  2687
@@ -174,6 +178,11 @@ DECLARE_UNIQUE_INDEX(pg_operator_oid_index, 2688, on pg_operator using btree(oid
 DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index, 2689, on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops));
 #define OperatorNameNspIndexId 2689
 
+DECLARE_UNIQUE_INDEX(pg_opfamily_am_name_nsp_index, 2754, on pg_opfamily using btree(opfmethod oid_ops, opfname name_ops, opfnamespace oid_ops));
+#define OpfamilyAmNameNspIndexId  2754
+DECLARE_UNIQUE_INDEX(pg_opfamily_oid_index, 2755, on pg_opfamily using btree(oid oid_ops));
+#define OpfamilyOidIndexId  2755
+
 DECLARE_UNIQUE_INDEX(pg_pltemplate_name_index, 1137, on pg_pltemplate using btree(tmplname name_ops));
 #define PLTemplateNameIndexId  1137
 
index ab354f53ac6074a89e1d2d7917e88a79944422e1..e1d9b190f2b4b72455679b63af1b4177febd9fd3 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.42 2006/05/01 23:22:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.43 2006/12/23 00:43:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,9 @@ extern bool OperatorIsVisible(Oid oprid);
 extern Oid     OpclassnameGetOpcid(Oid amid, const char *opcname);
 extern bool OpclassIsVisible(Oid opcid);
 
+extern Oid     OpfamilynameGetOpfid(Oid amid, const char *opfname);
+extern bool OpfamilyIsVisible(Oid opfid);
+
 extern Oid     ConversionGetConid(const char *conname);
 extern bool ConversionIsVisible(Oid conid);
 
index 1203434727fe19ad358d7b0d5ba7e7d5c46045c8..6907547eef5d7d65a11df149cfe36156f090bc6f 100644 (file)
@@ -4,26 +4,32 @@
  *       definition of the system "amop" relation (pg_amop)
  *       along with the relation's initial contents.
  *
- * The amop table identifies the operators associated with each index opclass.
+ * The amop table identifies the operators associated with each index operator
+ * family and operator class (classes are subsets of families).
  *
- * The primary key for this table is <amopclaid, amopsubtype, amopstrategy>.
- * amopsubtype is equal to zero for an opclass's "default" operators
- * (which normally are those that accept the opclass's opcintype on both
- * left and right sides).  Some index AMs allow nondefault operators to
- * exist for a single strategy --- for example, in the btree AM nondefault
- * operators can have right-hand input data types different from opcintype,
- * and their amopsubtype is equal to the right-hand input data type.
+ * The primary key for this table is <amopfamily, amoplefttype, amoprighttype,
+ * amopstrategy>.  amoplefttype and amoprighttype are just copies of the
+ * operator's oprleft/oprright, ie its declared input data types.  The
+ * "default" operators for a particular opclass within the family are those
+ * with amoplefttype = amoprighttype = opclass's opcintype.  An opfamily may
+ * also contain other operators, typically cross-data-type operators.  All the
+ * operators within a family are supposed to be compatible, in a way that is
+ * defined by each individual index AM.
  *
- * We also keep a unique index on <amopclaid, amopopr>, so that we can
- * use a syscache to quickly answer questions of the form "is this operator
- * in this opclass?".  This implies that the same operator cannot be listed
- * for multiple subtypes or strategy numbers of a single opclass.
+ * We also keep a unique index on <amopfamily, amopopr>, so that we can use a
+ * syscache to quickly answer questions of the form "is this operator in this
+ * opfamily, and if so what are its semantics with respect to the family?"
+ * This implies that the same operator cannot be listed for multiple strategy
+ * numbers within a single opfamily.
+ *
+ * amopmethod is a copy of the owning opfamily's opfmethod field.  This is an
+ * intentional denormalization of the catalogs to buy lookup speed.
  *
  *
  * 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_amop.h,v 1.75 2006/10/04 00:30:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.76 2006/12/23 00:43:12 tgl Exp $
  *
  * NOTES
  *      the genbki.sh script reads this file and generates .bki
  */
 #define AccessMethodOperatorRelationId 2602
 
-CATALOG(pg_amop,2602) BKI_WITHOUT_OIDS
+CATALOG(pg_amop,2602)
 {
-       Oid                     amopclaid;              /* the index opclass this entry is for */
-       Oid                     amopsubtype;    /* operator subtype, or zero if default */
+       Oid                     amopfamily;             /* the index opfamily this entry is for */
+       Oid                     amoplefttype;   /* operator's left input data type */
+       Oid                     amoprighttype;  /* operator's right input data type */
        int2            amopstrategy;   /* operator strategy number */
        bool            amopreqcheck;   /* index hit must be rechecked */
        Oid                     amopopr;                /* the operator's pg_operator OID */
+       Oid                     amopmethod;             /* the index access method this entry is for */
 } FormData_pg_amop;
 
 /* ----------------
@@ -68,12 +76,14 @@ typedef FormData_pg_amop *Form_pg_amop;
  *             compiler constants for pg_amop
  * ----------------
  */
-#define Natts_pg_amop                                  5
-#define Anum_pg_amop_amopclaid                 1
-#define Anum_pg_amop_amopsubtype               2
-#define Anum_pg_amop_amopstrategy              3
-#define Anum_pg_amop_amopreqcheck              4
-#define Anum_pg_amop_amopopr                   5
+#define Natts_pg_amop                                  7
+#define Anum_pg_amop_amopfamily                        1
+#define Anum_pg_amop_amoplefttype              2
+#define Anum_pg_amop_amoprighttype             3
+#define Anum_pg_amop_amopstrategy              4
+#define Anum_pg_amop_amopreqcheck              5
+#define Anum_pg_amop_amopopr                   6
+#define Anum_pg_amop_amopmethod                        7
 
 /* ----------------
  *             initial contents of pg_amop
@@ -81,815 +91,528 @@ typedef FormData_pg_amop *Form_pg_amop;
  */
 
 /*
- *     btree int2_ops
+ *     btree integer_ops
  */
 
-DATA(insert (  1976    0 1 f   95 ));
-DATA(insert (  1976    0 2 f  522 ));
-DATA(insert (  1976    0 3 f   94 ));
-DATA(insert (  1976    0 4 f  524 ));
-DATA(insert (  1976    0 5 f  520 ));
+/* default operators int2 */
+DATA(insert (  1976   21 21 1 f  95    403 ));
+DATA(insert (  1976   21 21 2 f  522   403 ));
+DATA(insert (  1976   21 21 3 f  94    403 ));
+DATA(insert (  1976   21 21 4 f  524   403 ));
+DATA(insert (  1976   21 21 5 f  520   403 ));
 /* crosstype operators int24 */
-DATA(insert (  1976   23 1 f  534 ));
-DATA(insert (  1976   23 2 f  540 ));
-DATA(insert (  1976   23 3 f  532 ));
-DATA(insert (  1976   23 4 f  542 ));
-DATA(insert (  1976   23 5 f  536 ));
+DATA(insert (  1976   21 23 1 f  534   403 ));
+DATA(insert (  1976   21 23 2 f  540   403 ));
+DATA(insert (  1976   21 23 3 f  532   403 ));
+DATA(insert (  1976   21 23 4 f  542   403 ));
+DATA(insert (  1976   21 23 5 f  536   403 ));
 /* crosstype operators int28 */
-DATA(insert (  1976   20 1 f  1864 ));
-DATA(insert (  1976   20 2 f  1866 ));
-DATA(insert (  1976   20 3 f  1862 ));
-DATA(insert (  1976   20 4 f  1867 ));
-DATA(insert (  1976   20 5 f  1865 ));
-
-/*
- *     btree int4_ops
- */
-
-DATA(insert (  1978    0 1 f   97 ));
-DATA(insert (  1978    0 2 f  523 ));
-DATA(insert (  1978    0 3 f   96 ));
-DATA(insert (  1978    0 4 f  525 ));
-DATA(insert (  1978    0 5 f  521 ));
+DATA(insert (  1976   21 20 1 f  1864  403 ));
+DATA(insert (  1976   21 20 2 f  1866  403 ));
+DATA(insert (  1976   21 20 3 f  1862  403 ));
+DATA(insert (  1976   21 20 4 f  1867  403 ));
+DATA(insert (  1976   21 20 5 f  1865  403 ));
+/* default operators int4 */
+DATA(insert (  1976   23 23 1 f  97    403 ));
+DATA(insert (  1976   23 23 2 f  523   403 ));
+DATA(insert (  1976   23 23 3 f  96    403 ));
+DATA(insert (  1976   23 23 4 f  525   403 ));
+DATA(insert (  1976   23 23 5 f  521   403 ));
 /* crosstype operators int42 */
-DATA(insert (  1978   21 1 f  535 ));
-DATA(insert (  1978   21 2 f  541 ));
-DATA(insert (  1978   21 3 f  533 ));
-DATA(insert (  1978   21 4 f  543 ));
-DATA(insert (  1978   21 5 f  537 ));
+DATA(insert (  1976   23 21 1 f  535   403 ));
+DATA(insert (  1976   23 21 2 f  541   403 ));
+DATA(insert (  1976   23 21 3 f  533   403 ));
+DATA(insert (  1976   23 21 4 f  543   403 ));
+DATA(insert (  1976   23 21 5 f  537   403 ));
 /* crosstype operators int48 */
-DATA(insert (  1978   20 1 f   37 ));
-DATA(insert (  1978   20 2 f   80 ));
-DATA(insert (  1978   20 3 f   15 ));
-DATA(insert (  1978   20 4 f   82 ));
-DATA(insert (  1978   20 5 f   76 ));
-
-/*
- *     btree int8_ops
- */
-
-DATA(insert (  1980    0 1 f  412 ));
-DATA(insert (  1980    0 2 f  414 ));
-DATA(insert (  1980    0 3 f  410 ));
-DATA(insert (  1980    0 4 f  415 ));
-DATA(insert (  1980    0 5 f  413 ));
+DATA(insert (  1976   23 20 1 f  37    403 ));
+DATA(insert (  1976   23 20 2 f  80    403 ));
+DATA(insert (  1976   23 20 3 f  15    403 ));
+DATA(insert (  1976   23 20 4 f  82    403 ));
+DATA(insert (  1976   23 20 5 f  76    403 ));
+/* default operators int8 */
+DATA(insert (  1976   20 20 1 f  412   403 ));
+DATA(insert (  1976   20 20 2 f  414   403 ));
+DATA(insert (  1976   20 20 3 f  410   403 ));
+DATA(insert (  1976   20 20 4 f  415   403 ));
+DATA(insert (  1976   20 20 5 f  413   403 ));
 /* crosstype operators int82 */
-DATA(insert (  1980   21 1 f  1870 ));
-DATA(insert (  1980   21 2 f  1872 ));
-DATA(insert (  1980   21 3 f  1868 ));
-DATA(insert (  1980   21 4 f  1873 ));
-DATA(insert (  1980   21 5 f  1871 ));
+DATA(insert (  1976   20 21 1 f  1870  403 ));
+DATA(insert (  1976   20 21 2 f  1872  403 ));
+DATA(insert (  1976   20 21 3 f  1868  403 ));
+DATA(insert (  1976   20 21 4 f  1873  403 ));
+DATA(insert (  1976   20 21 5 f  1871  403 ));
 /* crosstype operators int84 */
-DATA(insert (  1980   23 1 f  418 ));
-DATA(insert (  1980   23 2 f  420 ));
-DATA(insert (  1980   23 3 f  416 ));
-DATA(insert (  1980   23 4 f  430 ));
-DATA(insert (  1980   23 5 f  419 ));
+DATA(insert (  1976   20 23 1 f  418   403 ));
+DATA(insert (  1976   20 23 2 f  420   403 ));
+DATA(insert (  1976   20 23 3 f  416   403 ));
+DATA(insert (  1976   20 23 4 f  430   403 ));
+DATA(insert (  1976   20 23 5 f  419   403 ));
 
 /*
  *     btree oid_ops
  */
 
-DATA(insert (  1989    0 1 f  609 ));
-DATA(insert (  1989    0 2 f  611 ));
-DATA(insert (  1989    0 3 f  607 ));
-DATA(insert (  1989    0 4 f  612 ));
-DATA(insert (  1989    0 5 f  610 ));
+DATA(insert (  1989   26 26 1 f  609   403 ));
+DATA(insert (  1989   26 26 2 f  611   403 ));
+DATA(insert (  1989   26 26 3 f  607   403 ));
+DATA(insert (  1989   26 26 4 f  612   403 ));
+DATA(insert (  1989   26 26 5 f  610   403 ));
 
 /*
  * btree tid_ops
  */
 
-DATA(insert (  2789    0 1 f 2799 ));
-DATA(insert (  2789    0 2 f 2801 ));
-DATA(insert (  2789    0 3 f 387  ));
-DATA(insert (  2789    0 4 f 2802 ));
-DATA(insert (  2789    0 5 f 2800 ));
+DATA(insert (  2789   27 27 1 f 2799   403 ));
+DATA(insert (  2789   27 27 2 f 2801   403 ));
+DATA(insert (  2789   27 27 3 f 387    403 ));
+DATA(insert (  2789   27 27 4 f 2802   403 ));
+DATA(insert (  2789   27 27 5 f 2800   403 ));
 
 /*
  *     btree oidvector_ops
  */
 
-DATA(insert (  1991    0 1 f  645 ));
-DATA(insert (  1991    0 2 f  647 ));
-DATA(insert (  1991    0 3 f  649 ));
-DATA(insert (  1991    0 4 f  648 ));
-DATA(insert (  1991    0 5 f  646 ));
+DATA(insert (  1991   30 30 1 f  645   403 ));
+DATA(insert (  1991   30 30 2 f  647   403 ));
+DATA(insert (  1991   30 30 3 f  649   403 ));
+DATA(insert (  1991   30 30 4 f  648   403 ));
+DATA(insert (  1991   30 30 5 f  646   403 ));
 
 /*
- *     btree float4_ops
+ *     btree float_ops
  */
 
-DATA(insert (  1970    0 1 f  622 ));
-DATA(insert (  1970    0 2 f  624 ));
-DATA(insert (  1970    0 3 f  620 ));
-DATA(insert (  1970    0 4 f  625 ));
-DATA(insert (  1970    0 5 f  623 ));
+/* default operators float4 */
+DATA(insert (  1970   700 700 1 f  622 403 ));
+DATA(insert (  1970   700 700 2 f  624 403 ));
+DATA(insert (  1970   700 700 3 f  620 403 ));
+DATA(insert (  1970   700 700 4 f  625 403 ));
+DATA(insert (  1970   700 700 5 f  623 403 ));
 /* crosstype operators float48 */
-DATA(insert (  1970  701 1 f  1122 ));
-DATA(insert (  1970  701 2 f  1124 ));
-DATA(insert (  1970  701 3 f  1120 ));
-DATA(insert (  1970  701 4 f  1125 ));
-DATA(insert (  1970  701 5 f  1123 ));
-
-/*
- *     btree float8_ops
- */
-
-DATA(insert (  1972    0 1 f  672 ));
-DATA(insert (  1972    0 2 f  673 ));
-DATA(insert (  1972    0 3 f  670 ));
-DATA(insert (  1972    0 4 f  675 ));
-DATA(insert (  1972    0 5 f  674 ));
+DATA(insert (  1970   700 701 1 f  1122 403 ));
+DATA(insert (  1970   700 701 2 f  1124 403 ));
+DATA(insert (  1970   700 701 3 f  1120 403 ));
+DATA(insert (  1970   700 701 4 f  1125 403 ));
+DATA(insert (  1970   700 701 5 f  1123 403 ));
+/* default operators float8 */
+DATA(insert (  1970   701 701 1 f  672 403 ));
+DATA(insert (  1970   701 701 2 f  673 403 ));
+DATA(insert (  1970   701 701 3 f  670 403 ));
+DATA(insert (  1970   701 701 4 f  675 403 ));
+DATA(insert (  1970   701 701 5 f  674 403 ));
 /* crosstype operators float84 */
-DATA(insert (  1972  700 1 f  1132 ));
-DATA(insert (  1972  700 2 f  1134 ));
-DATA(insert (  1972  700 3 f  1130 ));
-DATA(insert (  1972  700 4 f  1135 ));
-DATA(insert (  1972  700 5 f  1133 ));
+DATA(insert (  1970   701 700 1 f  1132 403 ));
+DATA(insert (  1970   701 700 2 f  1134 403 ));
+DATA(insert (  1970   701 700 3 f  1130 403 ));
+DATA(insert (  1970   701 700 4 f  1135 403 ));
+DATA(insert (  1970   701 700 5 f  1133 403 ));
 
 /*
  *     btree char_ops
  */
 
-DATA(insert (   429    0 1 f  631 ));
-DATA(insert (   429    0 2 f  632 ));
-DATA(insert (   429    0 3 f   92 ));
-DATA(insert (   429    0 4 f  634 ));
-DATA(insert (   429    0 5 f  633 ));
+DATA(insert (  429   18 18 1 f  631    403 ));
+DATA(insert (  429   18 18 2 f  632    403 ));
+DATA(insert (  429   18 18 3 f 92      403 ));
+DATA(insert (  429   18 18 4 f  634    403 ));
+DATA(insert (  429   18 18 5 f  633    403 ));
 
 /*
  *     btree name_ops
  */
 
-DATA(insert (  1986    0 1 f  660 ));
-DATA(insert (  1986    0 2 f  661 ));
-DATA(insert (  1986    0 3 f   93 ));
-DATA(insert (  1986    0 4 f  663 ));
-DATA(insert (  1986    0 5 f  662 ));
+DATA(insert (  1986   19 19 1 f  660   403 ));
+DATA(insert (  1986   19 19 2 f  661   403 ));
+DATA(insert (  1986   19 19 3 f        93      403 ));
+DATA(insert (  1986   19 19 4 f  663   403 ));
+DATA(insert (  1986   19 19 5 f  662   403 ));
 
 /*
  *     btree text_ops
  */
 
-DATA(insert (  1994    0 1 f  664 ));
-DATA(insert (  1994    0 2 f  665 ));
-DATA(insert (  1994    0 3 f   98 ));
-DATA(insert (  1994    0 4 f  667 ));
-DATA(insert (  1994    0 5 f  666 ));
+DATA(insert (  1994   25 25 1 f  664   403 ));
+DATA(insert (  1994   25 25 2 f  665   403 ));
+DATA(insert (  1994   25 25 3 f        98      403 ));
+DATA(insert (  1994   25 25 4 f  667   403 ));
+DATA(insert (  1994   25 25 5 f  666   403 ));
 
 /*
  *     btree bpchar_ops
  */
 
-DATA(insert (   426    0 1 f 1058 ));
-DATA(insert (   426    0 2 f 1059 ));
-DATA(insert (   426    0 3 f 1054 ));
-DATA(insert (   426    0 4 f 1061 ));
-DATA(insert (   426    0 5 f 1060 ));
-
-/*
- *     btree varchar_ops (same operators as text_ops)
- */
-
-DATA(insert (  2003    0 1 f 664 ));
-DATA(insert (  2003    0 2 f 665 ));
-DATA(insert (  2003    0 3 f  98 ));
-DATA(insert (  2003    0 4 f 667 ));
-DATA(insert (  2003    0 5 f 666 ));
+DATA(insert (  426   1042 1042 1 f 1058        403 ));
+DATA(insert (  426   1042 1042 2 f 1059        403 ));
+DATA(insert (  426   1042 1042 3 f 1054        403 ));
+DATA(insert (  426   1042 1042 4 f 1061        403 ));
+DATA(insert (  426   1042 1042 5 f 1060        403 ));
 
 /*
  *     btree bytea_ops
  */
 
-DATA(insert (   428    0 1 f 1957 ));
-DATA(insert (   428    0 2 f 1958 ));
-DATA(insert (   428    0 3 f 1955 ));
-DATA(insert (   428    0 4 f 1960 ));
-DATA(insert (   428    0 5 f 1959 ));
+DATA(insert (  428   17 17 1 f 1957    403 ));
+DATA(insert (  428   17 17 2 f 1958    403 ));
+DATA(insert (  428   17 17 3 f 1955    403 ));
+DATA(insert (  428   17 17 4 f 1960    403 ));
+DATA(insert (  428   17 17 5 f 1959    403 ));
 
 /*
  *     btree abstime_ops
  */
 
-DATA(insert (   421    0 1 f  562 ));
-DATA(insert (   421    0 2 f  564 ));
-DATA(insert (   421    0 3 f  560 ));
-DATA(insert (   421    0 4 f  565 ));
-DATA(insert (   421    0 5 f  563 ));
+DATA(insert (  421   702 702 1 f  562  403 ));
+DATA(insert (  421   702 702 2 f  564  403 ));
+DATA(insert (  421   702 702 3 f  560  403 ));
+DATA(insert (  421   702 702 4 f  565  403 ));
+DATA(insert (  421   702 702 5 f  563  403 ));
 
 /*
- *     btree date_ops
+ *     btree datetime_ops
  */
 
-DATA(insert (   434    0 1 f 1095 ));
-DATA(insert (   434    0 2 f 1096 ));
-DATA(insert (   434    0 3 f 1093 ));
-DATA(insert (   434    0 4 f 1098 ));
-DATA(insert (   434    0 5 f 1097 ));
+/* default operators date */
+DATA(insert (  434   1082 1082 1 f 1095        403 ));
+DATA(insert (  434   1082 1082 2 f 1096        403 ));
+DATA(insert (  434   1082 1082 3 f 1093        403 ));
+DATA(insert (  434   1082 1082 4 f 1098        403 ));
+DATA(insert (  434   1082 1082 5 f 1097        403 ));
 /* crosstype operators vs timestamp */
-DATA(insert (   434 1114 1 f 2345 ));
-DATA(insert (   434 1114 2 f 2346 ));
-DATA(insert (   434 1114 3 f 2347 ));
-DATA(insert (   434 1114 4 f 2348 ));
-DATA(insert (   434 1114 5 f 2349 ));
+DATA(insert (  434   1082 1114 1 f 2345        403 ));
+DATA(insert (  434   1082 1114 2 f 2346        403 ));
+DATA(insert (  434   1082 1114 3 f 2347        403 ));
+DATA(insert (  434   1082 1114 4 f 2348        403 ));
+DATA(insert (  434   1082 1114 5 f 2349        403 ));
 /* crosstype operators vs timestamptz */
-DATA(insert (   434 1184 1 f 2358 ));
-DATA(insert (   434 1184 2 f 2359 ));
-DATA(insert (   434 1184 3 f 2360 ));
-DATA(insert (   434 1184 4 f 2361 ));
-DATA(insert (   434 1184 5 f 2362 ));
+DATA(insert (  434   1082 1184 1 f 2358        403 ));
+DATA(insert (  434   1082 1184 2 f 2359        403 ));
+DATA(insert (  434   1082 1184 3 f 2360        403 ));
+DATA(insert (  434   1082 1184 4 f 2361        403 ));
+DATA(insert (  434   1082 1184 5 f 2362        403 ));
+/* default operators timestamp */
+DATA(insert (  434   1114 1114 1 f 2062        403 ));
+DATA(insert (  434   1114 1114 2 f 2063        403 ));
+DATA(insert (  434   1114 1114 3 f 2060        403 ));
+DATA(insert (  434   1114 1114 4 f 2065        403 ));
+DATA(insert (  434   1114 1114 5 f 2064        403 ));
+/* crosstype operators vs date */
+DATA(insert (  434   1114 1082 1 f 2371        403 ));
+DATA(insert (  434   1114 1082 2 f 2372        403 ));
+DATA(insert (  434   1114 1082 3 f 2373        403 ));
+DATA(insert (  434   1114 1082 4 f 2374        403 ));
+DATA(insert (  434   1114 1082 5 f 2375        403 ));
+/* crosstype operators vs timestamptz */
+DATA(insert (  434   1114 1184 1 f 2534        403 ));
+DATA(insert (  434   1114 1184 2 f 2535        403 ));
+DATA(insert (  434   1114 1184 3 f 2536        403 ));
+DATA(insert (  434   1114 1184 4 f 2537        403 ));
+DATA(insert (  434   1114 1184 5 f 2538        403 ));
+/* default operators timestamptz */
+DATA(insert (  434   1184 1184 1 f 1322        403 ));
+DATA(insert (  434   1184 1184 2 f 1323        403 ));
+DATA(insert (  434   1184 1184 3 f 1320        403 ));
+DATA(insert (  434   1184 1184 4 f 1325        403 ));
+DATA(insert (  434   1184 1184 5 f 1324        403 ));
+/* crosstype operators vs date */
+DATA(insert (  434   1184 1082 1 f 2384        403 ));
+DATA(insert (  434   1184 1082 2 f 2385        403 ));
+DATA(insert (  434   1184 1082 3 f 2386        403 ));
+DATA(insert (  434   1184 1082 4 f 2387        403 ));
+DATA(insert (  434   1184 1082 5 f 2388        403 ));
+/* crosstype operators vs timestamp */
+DATA(insert (  434   1184 1114 1 f 2540        403 ));
+DATA(insert (  434   1184 1114 2 f 2541        403 ));
+DATA(insert (  434   1184 1114 3 f 2542        403 ));
+DATA(insert (  434   1184 1114 4 f 2543        403 ));
+DATA(insert (  434   1184 1114 5 f 2544        403 ));
 
 /*
  *     btree time_ops
  */
 
-DATA(insert (  1996    0 1 f 1110 ));
-DATA(insert (  1996    0 2 f 1111 ));
-DATA(insert (  1996    0 3 f 1108 ));
-DATA(insert (  1996    0 4 f 1113 ));
-DATA(insert (  1996    0 5 f 1112 ));
+DATA(insert (  1996   1083 1083 1 f 1110       403 ));
+DATA(insert (  1996   1083 1083 2 f 1111       403 ));
+DATA(insert (  1996   1083 1083 3 f 1108       403 ));
+DATA(insert (  1996   1083 1083 4 f 1113       403 ));
+DATA(insert (  1996   1083 1083 5 f 1112       403 ));
 
 /*
  *     btree timetz_ops
  */
 
-DATA(insert (  2000    0 1 f 1552 ));
-DATA(insert (  2000    0 2 f 1553 ));
-DATA(insert (  2000    0 3 f 1550 ));
-DATA(insert (  2000    0 4 f 1555 ));
-DATA(insert (  2000    0 5 f 1554 ));
-
-/*
- *     btree timestamp_ops
- */
-
-DATA(insert (  2039    0 1 f 2062 ));
-DATA(insert (  2039    0 2 f 2063 ));
-DATA(insert (  2039    0 3 f 2060 ));
-DATA(insert (  2039    0 4 f 2065 ));
-DATA(insert (  2039    0 5 f 2064 ));
-/* crosstype operators vs date */
-DATA(insert (  2039 1082 1 f 2371 ));
-DATA(insert (  2039 1082 2 f 2372 ));
-DATA(insert (  2039 1082 3 f 2373 ));
-DATA(insert (  2039 1082 4 f 2374 ));
-DATA(insert (  2039 1082 5 f 2375 ));
-/* crosstype operators vs timestamptz */
-DATA(insert (  2039 1184 1 f 2534 ));
-DATA(insert (  2039 1184 2 f 2535 ));
-DATA(insert (  2039 1184 3 f 2536 ));
-DATA(insert (  2039 1184 4 f 2537 ));
-DATA(insert (  2039 1184 5 f 2538 ));
-
-/*
- *     btree timestamptz_ops
- */
-
-DATA(insert (  1998    0 1 f 1322 ));
-DATA(insert (  1998    0 2 f 1323 ));
-DATA(insert (  1998    0 3 f 1320 ));
-DATA(insert (  1998    0 4 f 1325 ));
-DATA(insert (  1998    0 5 f 1324 ));
-/* crosstype operators vs date */
-DATA(insert (  1998 1082 1 f 2384 ));
-DATA(insert (  1998 1082 2 f 2385 ));
-DATA(insert (  1998 1082 3 f 2386 ));
-DATA(insert (  1998 1082 4 f 2387 ));
-DATA(insert (  1998 1082 5 f 2388 ));
-/* crosstype operators vs timestamp */
-DATA(insert (  1998 1114 1 f 2540 ));
-DATA(insert (  1998 1114 2 f 2541 ));
-DATA(insert (  1998 1114 3 f 2542 ));
-DATA(insert (  1998 1114 4 f 2543 ));
-DATA(insert (  1998 1114 5 f 2544 ));
+DATA(insert (  2000   1266 1266 1 f 1552       403 ));
+DATA(insert (  2000   1266 1266 2 f 1553       403 ));
+DATA(insert (  2000   1266 1266 3 f 1550       403 ));
+DATA(insert (  2000   1266 1266 4 f 1555       403 ));
+DATA(insert (  2000   1266 1266 5 f 1554       403 ));
 
 /*
  *     btree interval_ops
  */
 
-DATA(insert (  1982    0 1 f 1332 ));
-DATA(insert (  1982    0 2 f 1333 ));
-DATA(insert (  1982    0 3 f 1330 ));
-DATA(insert (  1982    0 4 f 1335 ));
-DATA(insert (  1982    0 5 f 1334 ));
+DATA(insert (  1982   1186 1186 1 f 1332       403 ));
+DATA(insert (  1982   1186 1186 2 f 1333       403 ));
+DATA(insert (  1982   1186 1186 3 f 1330       403 ));
+DATA(insert (  1982   1186 1186 4 f 1335       403 ));
+DATA(insert (  1982   1186 1186 5 f 1334       403 ));
 
 /*
  *     btree macaddr
  */
 
-DATA(insert (  1984    0 1 f 1222 ));
-DATA(insert (  1984    0 2 f 1223 ));
-DATA(insert (  1984    0 3 f 1220 ));
-DATA(insert (  1984    0 4 f 1225 ));
-DATA(insert (  1984    0 5 f 1224 ));
+DATA(insert (  1984   829 829 1 f 1222 403 ));
+DATA(insert (  1984   829 829 2 f 1223 403 ));
+DATA(insert (  1984   829 829 3 f 1220 403 ));
+DATA(insert (  1984   829 829 4 f 1225 403 ));
+DATA(insert (  1984   829 829 5 f 1224 403 ));
 
 /*
- *     btree inet
+ *     btree network
  */
 
-DATA(insert (  1974    0 1 f 1203 ));
-DATA(insert (  1974    0 2 f 1204 ));
-DATA(insert (  1974    0 3 f 1201 ));
-DATA(insert (  1974    0 4 f 1206 ));
-DATA(insert (  1974    0 5 f 1205 ));
-
-/*
- *     btree cidr
- */
-
-DATA(insert (   432    0 1 f 1203 ));
-DATA(insert (   432    0 2 f 1204 ));
-DATA(insert (   432    0 3 f 1201 ));
-DATA(insert (   432    0 4 f 1206 ));
-DATA(insert (   432    0 5 f 1205 ));
+DATA(insert (  1974   869 869 1 f 1203 403 ));
+DATA(insert (  1974   869 869 2 f 1204 403 ));
+DATA(insert (  1974   869 869 3 f 1201 403 ));
+DATA(insert (  1974   869 869 4 f 1206 403 ));
+DATA(insert (  1974   869 869 5 f 1205 403 ));
 
 /*
  *     btree numeric
  */
 
-DATA(insert (  1988    0 1 f 1754 ));
-DATA(insert (  1988    0 2 f 1755 ));
-DATA(insert (  1988    0 3 f 1752 ));
-DATA(insert (  1988    0 4 f 1757 ));
-DATA(insert (  1988    0 5 f 1756 ));
+DATA(insert (  1988   1700 1700 1 f 1754       403 ));
+DATA(insert (  1988   1700 1700 2 f 1755       403 ));
+DATA(insert (  1988   1700 1700 3 f 1752       403 ));
+DATA(insert (  1988   1700 1700 4 f 1757       403 ));
+DATA(insert (  1988   1700 1700 5 f 1756       403 ));
 
 /*
  *     btree bool
  */
 
-DATA(insert (   424    0 1 f   58 ));
-DATA(insert (   424    0 2 f 1694 ));
-DATA(insert (   424    0 3 f   91 ));
-DATA(insert (   424    0 4 f 1695 ));
-DATA(insert (   424    0 5 f   59 ));
+DATA(insert (  424   16 16 1 f 58      403 ));
+DATA(insert (  424   16 16 2 f 1694    403 ));
+DATA(insert (  424   16 16 3 f 91      403 ));
+DATA(insert (  424   16 16 4 f 1695    403 ));
+DATA(insert (  424   16 16 5 f 59      403 ));
 
 /*
  *     btree bit
  */
 
-DATA(insert (   423    0 1 f 1786 ));
-DATA(insert (   423    0 2 f 1788 ));
-DATA(insert (   423    0 3 f 1784 ));
-DATA(insert (   423    0 4 f 1789 ));
-DATA(insert (   423    0 5 f 1787 ));
+DATA(insert (  423   1560 1560 1 f 1786        403 ));
+DATA(insert (  423   1560 1560 2 f 1788        403 ));
+DATA(insert (  423   1560 1560 3 f 1784        403 ));
+DATA(insert (  423   1560 1560 4 f 1789        403 ));
+DATA(insert (  423   1560 1560 5 f 1787        403 ));
 
 /*
  *     btree varbit
  */
 
-DATA(insert (  2002    0 1 f 1806 ));
-DATA(insert (  2002    0 2 f 1808 ));
-DATA(insert (  2002    0 3 f 1804 ));
-DATA(insert (  2002    0 4 f 1809 ));
-DATA(insert (  2002    0 5 f 1807 ));
+DATA(insert (  2002   1562 1562 1 f 1806       403 ));
+DATA(insert (  2002   1562 1562 2 f 1808       403 ));
+DATA(insert (  2002   1562 1562 3 f 1804       403 ));
+DATA(insert (  2002   1562 1562 4 f 1809       403 ));
+DATA(insert (  2002   1562 1562 5 f 1807       403 ));
 
 /*
  *     btree text pattern
  */
 
-DATA(insert (  2095    0 1 f 2314 ));
-DATA(insert (  2095    0 2 f 2315 ));
-DATA(insert (  2095    0 3 f 2316 ));
-DATA(insert (  2095    0 4 f 2317 ));
-DATA(insert (  2095    0 5 f 2318 ));
-
-/*
- *     btree varchar pattern (same operators as text)
- */
-
-DATA(insert (  2096    0 1 f 2314 ));
-DATA(insert (  2096    0 2 f 2315 ));
-DATA(insert (  2096    0 3 f 2316 ));
-DATA(insert (  2096    0 4 f 2317 ));
-DATA(insert (  2096    0 5 f 2318 ));
+DATA(insert (  2095   25 25 1 f 2314   403 ));
+DATA(insert (  2095   25 25 2 f 2315   403 ));
+DATA(insert (  2095   25 25 3 f 2316   403 ));
+DATA(insert (  2095   25 25 4 f 2317   403 ));
+DATA(insert (  2095   25 25 5 f 2318   403 ));
 
 /*
  *     btree bpchar pattern
  */
 
-DATA(insert (  2097    0 1 f 2326 ));
-DATA(insert (  2097    0 2 f 2327 ));
-DATA(insert (  2097    0 3 f 2328 ));
-DATA(insert (  2097    0 4 f 2329 ));
-DATA(insert (  2097    0 5 f 2330 ));
+DATA(insert (  2097   1042 1042 1 f 2326       403 ));
+DATA(insert (  2097   1042 1042 2 f 2327       403 ));
+DATA(insert (  2097   1042 1042 3 f 2328       403 ));
+DATA(insert (  2097   1042 1042 4 f 2329       403 ));
+DATA(insert (  2097   1042 1042 5 f 2330       403 ));
 
 /*
  *     btree name pattern
  */
 
-DATA(insert (  2098    0 1 f 2332 ));
-DATA(insert (  2098    0 2 f 2333 ));
-DATA(insert (  2098    0 3 f 2334 ));
-DATA(insert (  2098    0 4 f 2335 ));
-DATA(insert (  2098    0 5 f 2336 ));
+DATA(insert (  2098   19 19 1 f 2332   403 ));
+DATA(insert (  2098   19 19 2 f 2333   403 ));
+DATA(insert (  2098   19 19 3 f 2334   403 ));
+DATA(insert (  2098   19 19 4 f 2335   403 ));
+DATA(insert (  2098   19 19 5 f 2336   403 ));
 
 /*
  *     btree money_ops
  */
 
-DATA(insert (  2099    0 1 f  902 ));
-DATA(insert (  2099    0 2 f  904 ));
-DATA(insert (  2099    0 3 f  900 ));
-DATA(insert (  2099    0 4 f  905 ));
-DATA(insert (  2099    0 5 f  903 ));
+DATA(insert (  2099   790 790 1 f  902 403 ));
+DATA(insert (  2099   790 790 2 f  904 403 ));
+DATA(insert (  2099   790 790 3 f  900 403 ));
+DATA(insert (  2099   790 790 4 f  905 403 ));
+DATA(insert (  2099   790 790 5 f  903 403 ));
 
 /*
  *     btree reltime_ops
  */
 
-DATA(insert (  2233    0 1 f  568 ));
-DATA(insert (  2233    0 2 f  570 ));
-DATA(insert (  2233    0 3 f  566 ));
-DATA(insert (  2233    0 4 f  571 ));
-DATA(insert (  2233    0 5 f  569 ));
+DATA(insert (  2233   703 703 1 f  568 403 ));
+DATA(insert (  2233   703 703 2 f  570 403 ));
+DATA(insert (  2233   703 703 3 f  566 403 ));
+DATA(insert (  2233   703 703 4 f  571 403 ));
+DATA(insert (  2233   703 703 5 f  569 403 ));
 
 /*
  *     btree tinterval_ops
  */
 
-DATA(insert (  2234    0 1 f  813 ));
-DATA(insert (  2234    0 2 f  815 ));
-DATA(insert (  2234    0 3 f  811 ));
-DATA(insert (  2234    0 4 f  816 ));
-DATA(insert (  2234    0 5 f  814 ));
+DATA(insert (  2234   704 704 1 f  813 403 ));
+DATA(insert (  2234   704 704 2 f  815 403 ));
+DATA(insert (  2234   704 704 3 f  811 403 ));
+DATA(insert (  2234   704 704 4 f  816 403 ));
+DATA(insert (  2234   704 704 5 f  814 403 ));
 
 /*
  *     btree array_ops
  */
 
-DATA(insert (   397    0 1 f 1072 ));
-DATA(insert (   397    0 2 f 1074 ));
-DATA(insert (   397    0 3 f 1070 ));
-DATA(insert (   397    0 4 f 1075 ));
-DATA(insert (   397    0 5 f 1073 ));
+DATA(insert (  397   2277 2277 1 f 1072        403 ));
+DATA(insert (  397   2277 2277 2 f 1074        403 ));
+DATA(insert (  397   2277 2277 3 f 1070        403 ));
+DATA(insert (  397   2277 2277 4 f 1075        403 ));
+DATA(insert (  397   2277 2277 5 f 1073        403 ));
 
 /*
  *     hash index _ops
  */
 
 /* bpchar_ops */
-DATA(insert (   427    0 1 f 1054 ));
+DATA(insert (  427   1042 1042 1 f 1054        405 ));
 /* char_ops */
-DATA(insert (   431    0 1 f   92 ));
-/* cidr_ops */
-DATA(insert (   433    0 1 f 1201 ));
+DATA(insert (  431   18 18 1 f 92      405 ));
 /* date_ops */
-DATA(insert (   435    0 1 f 1093 ));
-/* float4_ops */
-DATA(insert (  1971    0 1 f  620 ));
-/* float8_ops */
-DATA(insert (  1973    0 1 f  670 ));
-/* inet_ops */
-DATA(insert (  1975    0 1 f 1201 ));
-/* int2_ops */
-DATA(insert (  1977    0 1 f   94 ));
-/* int4_ops */
-DATA(insert (  1979    0 1 f   96 ));
-/* int8_ops */
-DATA(insert (  1981    0 1 f  410 ));
+DATA(insert (  435   1082 1082 1 f 1093        405 ));
+/* float_ops */
+DATA(insert (  1971   700 700 1 f  620 405 ));
+DATA(insert (  1971   701 701 1 f  670 405 ));
+/* network_ops */
+DATA(insert (  1975   869 869 1 f 1201 405 ));
+/* integer_ops */
+DATA(insert (  1977   21 21 1 f        94      405 ));
+DATA(insert (  1977   23 23 1 f        96      405 ));
+DATA(insert (  1977   20 20 1 f        410     405 ));
 /* interval_ops */
-DATA(insert (  1983    0 1 f 1330 ));
+DATA(insert (  1983   1186 1186 1 f 1330       405 ));
 /* macaddr_ops */
-DATA(insert (  1985    0 1 f 1220 ));
+DATA(insert (  1985   829 829 1 f 1220 405 ));
 /* name_ops */
-DATA(insert (  1987    0 1 f   93 ));
+DATA(insert (  1987   19 19 1 f        93      405 ));
 /* oid_ops */
-DATA(insert (  1990    0 1 f  607 ));
+DATA(insert (  1990   26 26 1 f  607   405 ));
 /* oidvector_ops */
-DATA(insert (  1992    0 1 f  649 ));
+DATA(insert (  1992   30 30 1 f  649   405 ));
 /* text_ops */
-DATA(insert (  1995    0 1 f   98 ));
+DATA(insert (  1995   25 25 1 f        98      405 ));
 /* time_ops */
-DATA(insert (  1997    0 1 f 1108 ));
+DATA(insert (  1997   1083 1083 1 f 1108       405 ));
 /* timestamptz_ops */
-DATA(insert (  1999    0 1 f 1320 ));
+DATA(insert (  1999   1184 1184 1 f 1320       405 ));
 /* timetz_ops */
-DATA(insert (  2001    0 1 f 1550 ));
-/* varchar_ops */
-DATA(insert (  2004    0 1 f   98 ));
+DATA(insert (  2001   1266 1266 1 f 1550       405 ));
 /* timestamp_ops */
-DATA(insert (  2040    0 1 f 2060 ));
+DATA(insert (  2040   1114 1114 1 f 2060       405 ));
 /* bool_ops */
-DATA(insert (  2222    0 1 f   91 ));
+DATA(insert (  2222   16 16 1 f        91      405 ));
 /* bytea_ops */
-DATA(insert (  2223    0 1 f 1955 ));
+DATA(insert (  2223   17 17 1 f 1955   405 ));
 /* int2vector_ops */
-DATA(insert (  2224    0 1 f  386 ));
+DATA(insert (  2224   22 22 1 f  386   405 ));
 /* xid_ops */
-DATA(insert (  2225    0 1 f  352 ));
+DATA(insert (  2225   28 28 1 f  352   405 ));
 /* cid_ops */
-DATA(insert (  2226    0 1 f  385 ));
+DATA(insert (  2226   29 29 1 f  385   405 ));
 /* abstime_ops */
-DATA(insert (  2227    0 1 f  560 ));
+DATA(insert (  2227   702 702 1 f  560 405 ));
 /* reltime_ops */
-DATA(insert (  2228    0 1 f  566 ));
+DATA(insert (  2228   703 703 1 f  566 405 ));
 /* text_pattern_ops */
-DATA(insert (  2229    0 1 f 2316 ));
-/* varchar_pattern_ops */
-DATA(insert (  2230    0 1 f 2316 ));
+DATA(insert (  2229   25 25 1 f 2316   405 ));
 /* bpchar_pattern_ops */
-DATA(insert (  2231    0 1 f 2328 ));
+DATA(insert (  2231   1042 1042 1 f 2328       405 ));
 /* name_pattern_ops */
-DATA(insert (  2232    0 1 f 2334 ));
+DATA(insert (  2232   19 19 1 f 2334   405 ));
 /* aclitem_ops */
-DATA(insert (  2235    0 1 f  974 ));
+DATA(insert (  2235   1033 1033 1 f  974       405 ));
 
 /*
  *     gist box_ops
  */
 
-DATA(insert (  2593    0 1  f  493 ));
-DATA(insert (  2593    0 2  f  494 ));
-DATA(insert (  2593    0 3  f  500 ));
-DATA(insert (  2593    0 4  f  495 ));
-DATA(insert (  2593    0 5  f  496 ));
-DATA(insert (  2593    0 6  f  499 ));
-DATA(insert (  2593    0 7  f  498 ));
-DATA(insert (  2593    0 8  f  497 ));
-DATA(insert (  2593    0 9  f  2571 ));
-DATA(insert (  2593    0 10 f  2570 ));
-DATA(insert (  2593    0 11 f  2573 ));
-DATA(insert (  2593    0 12 f  2572 ));
-DATA(insert (  2593    0 13 f  2863 ));
-DATA(insert (  2593    0 14 f  2862 ));
+DATA(insert (  2593   603 603 1  f     493     783 ));
+DATA(insert (  2593   603 603 2  f     494     783 ));
+DATA(insert (  2593   603 603 3  f     500     783 ));
+DATA(insert (  2593   603 603 4  f     495     783 ));
+DATA(insert (  2593   603 603 5  f     496     783 ));
+DATA(insert (  2593   603 603 6  f     499     783 ));
+DATA(insert (  2593   603 603 7  f     498     783 ));
+DATA(insert (  2593   603 603 8  f     497     783 ));
+DATA(insert (  2593   603 603 9  f     2571    783 ));
+DATA(insert (  2593   603 603 10 f     2570    783 ));
+DATA(insert (  2593   603 603 11 f     2573    783 ));
+DATA(insert (  2593   603 603 12 f     2572    783 ));
+DATA(insert (  2593   603 603 13 f     2863    783 ));
+DATA(insert (  2593   603 603 14 f     2862    783 ));
 
 /*
  *     gist poly_ops (supports polygons)
  */
 
-DATA(insert (  2594    0 1  t  485 ));
-DATA(insert (  2594    0 2  t  486 ));
-DATA(insert (  2594    0 3  t  492 ));
-DATA(insert (  2594    0 4  t  487 ));
-DATA(insert (  2594    0 5  t  488 ));
-DATA(insert (  2594    0 6  t  491 ));
-DATA(insert (  2594    0 7  t  490 ));
-DATA(insert (  2594    0 8  t  489 ));
-DATA(insert (  2594    0 9  t  2575 ));
-DATA(insert (  2594    0 10 t  2574 ));
-DATA(insert (  2594    0 11 t  2577 ));
-DATA(insert (  2594    0 12 t  2576 ));
-DATA(insert (  2594    0 13 t  2861 ));
-DATA(insert (  2594    0 14 t  2860 ));
+DATA(insert (  2594   604 604 1  t     485     783 ));
+DATA(insert (  2594   604 604 2  t     486     783 ));
+DATA(insert (  2594   604 604 3  t     492     783 ));
+DATA(insert (  2594   604 604 4  t     487     783 ));
+DATA(insert (  2594   604 604 5  t     488     783 ));
+DATA(insert (  2594   604 604 6  t     491     783 ));
+DATA(insert (  2594   604 604 7  t     490     783 ));
+DATA(insert (  2594   604 604 8  t     489     783 ));
+DATA(insert (  2594   604 604 9  t     2575    783 ));
+DATA(insert (  2594   604 604 10 t     2574    783 ));
+DATA(insert (  2594   604 604 11 t     2577    783 ));
+DATA(insert (  2594   604 604 12 t     2576    783 ));
+DATA(insert (  2594   604 604 13 t     2861    783 ));
+DATA(insert (  2594   604 604 14 t     2860    783 ));
 
 /*
  *     gist circle_ops
  */
 
-DATA(insert (  2595    0 1  t  1506 ));
-DATA(insert (  2595    0 2  t  1507 ));
-DATA(insert (  2595    0 3  t  1513 ));
-DATA(insert (  2595    0 4  t  1508 ));
-DATA(insert (  2595    0 5  t  1509 ));
-DATA(insert (  2595    0 6  t  1512 ));
-DATA(insert (  2595    0 7  t  1511 ));
-DATA(insert (  2595    0 8  t  1510 ));
-DATA(insert (  2595    0 9  t  2589 ));
-DATA(insert (  2595    0 10 t  1515 ));
-DATA(insert (  2595    0 11 t  1514 ));
-DATA(insert (  2595    0 12 t  2590 ));
-DATA(insert (  2595    0 13 t  2865 ));
-DATA(insert (  2595    0 14 t  2864 ));
-
-/*
- * gin _int4_ops
- */
-DATA(insert (  2745    0 1  f  2750 ));
-DATA(insert (  2745    0 2  f  2751 ));
-DATA(insert (  2745    0 3  t  2752 ));
-DATA(insert (  2745    0 4  t  1070 ));
-
-/*
- * gin _text_ops
- */
-DATA(insert (  2746    0 1  f  2750 ));
-DATA(insert (  2746    0 2  f  2751 ));
-DATA(insert (  2746    0 3  t  2752 ));
-DATA(insert (  2746    0 4  t  1070 ));
-
-/*
- * gin _abstime_ops
- */
-DATA(insert (  2753    0 1  f  2750 ));
-DATA(insert (  2753    0 2  f  2751 ));
-DATA(insert (  2753    0 3  t  2752 ));
-DATA(insert (  2753    0 4  t  1070 ));
-
-/*
- * gin _bit_ops
- */
-DATA(insert (  2754    0 1  f  2750 ));
-DATA(insert (  2754    0 2  f  2751 ));
-DATA(insert (  2754    0 3  t  2752 ));
-DATA(insert (  2754    0 4  t  1070 ));
-
-/*
- * gin _bool_ops
- */
-DATA(insert (  2755    0 1  f  2750 ));
-DATA(insert (  2755    0 2  f  2751 ));
-DATA(insert (  2755    0 3  t  2752 ));
-DATA(insert (  2755    0 4  t  1070 ));
-
-/*
- * gin _bpchar_ops
- */
-DATA(insert (  2756    0 1  f  2750 ));
-DATA(insert (  2756    0 2  f  2751 ));
-DATA(insert (  2756    0 3  t  2752 ));
-DATA(insert (  2756    0 4  t  1070 ));
-
-/*
- * gin _bytea_ops
- */
-DATA(insert (  2757    0 1  f  2750 ));
-DATA(insert (  2757    0 2  f  2751 ));
-DATA(insert (  2757    0 3  t  2752 ));
-DATA(insert (  2757    0 4  t  1070 ));
-
-/*
- * gin _char_ops
- */
-DATA(insert (  2758    0 1  f  2750 ));
-DATA(insert (  2758    0 2  f  2751 ));
-DATA(insert (  2758    0 3  t  2752 ));
-DATA(insert (  2758    0 4  t  1070 ));
-
-/*
- * gin _cidr_ops
- */
-DATA(insert (  2759    0 1  f  2750 ));
-DATA(insert (  2759    0 2  f  2751 ));
-DATA(insert (  2759    0 3  t  2752 ));
-DATA(insert (  2759    0 4  t  1070 ));
-
-/*
- * gin _date_ops
- */
-DATA(insert (  2760    0 1  f  2750 ));
-DATA(insert (  2760    0 2  f  2751 ));
-DATA(insert (  2760    0 3  t  2752 ));
-DATA(insert (  2760    0 4  t  1070 ));
-
-/*
- * gin _float4_ops
- */
-DATA(insert (  2761    0 1  f  2750 ));
-DATA(insert (  2761    0 2  f  2751 ));
-DATA(insert (  2761    0 3  t  2752 ));
-DATA(insert (  2761    0 4  t  1070 ));
-
-/*
- * gin _float8_ops
- */
-DATA(insert (  2762    0 1  f  2750 ));
-DATA(insert (  2762    0 2  f  2751 ));
-DATA(insert (  2762    0 3  t  2752 ));
-DATA(insert (  2762    0 4  t  1070 ));
-
-/*
- * gin _inet_ops
- */
-DATA(insert (  2763    0 1  f  2750 ));
-DATA(insert (  2763    0 2  f  2751 ));
-DATA(insert (  2763    0 3  t  2752 ));
-DATA(insert (  2763    0 4  t  1070 ));
-
-/*
- * gin _int2_ops
- */
-DATA(insert (  2764    0 1  f  2750 ));
-DATA(insert (  2764    0 2  f  2751 ));
-DATA(insert (  2764    0 3  t  2752 ));
-DATA(insert (  2764    0 4  t  1070 ));
-
-/*
- * gin _int8_ops
- */
-DATA(insert (  2765    0 1  f  2750 ));
-DATA(insert (  2765    0 2  f  2751 ));
-DATA(insert (  2765    0 3  t  2752 ));
-DATA(insert (  2765    0 4  t  1070 ));
-
-/*
- * gin _interval_ops
- */
-DATA(insert (  2766    0 1  f  2750 ));
-DATA(insert (  2766    0 2  f  2751 ));
-DATA(insert (  2766    0 3  t  2752 ));
-DATA(insert (  2766    0 4  t  1070 ));
-
-/*
- * gin _macaddr_ops
- */
-DATA(insert (  2767    0 1  f  2750 ));
-DATA(insert (  2767    0 2  f  2751 ));
-DATA(insert (  2767    0 3  t  2752 ));
-DATA(insert (  2767    0 4  t  1070 ));
-
-/*
- * gin _name_ops
- */
-DATA(insert (  2768    0 1  f  2750 ));
-DATA(insert (  2768    0 2  f  2751 ));
-DATA(insert (  2768    0 3  t  2752 ));
-DATA(insert (  2768    0 4  t  1070 ));
-
-/*
- * gin _numeric_ops
- */
-DATA(insert (  2769    0 1  f  2750 ));
-DATA(insert (  2769    0 2  f  2751 ));
-DATA(insert (  2769    0 3  t  2752 ));
-DATA(insert (  2769    0 4  t  1070 ));
-
-/*
- * gin _oid_ops
- */
-DATA(insert (  2770    0 1  f  2750 ));
-DATA(insert (  2770    0 2  f  2751 ));
-DATA(insert (  2770    0 3  t  2752 ));
-DATA(insert (  2770    0 4  t  1070 ));
-
-/*
- * gin _oidvector_ops
- */
-DATA(insert (  2771    0 1  f  2750 ));
-DATA(insert (  2771    0 2  f  2751 ));
-DATA(insert (  2771    0 3  t  2752 ));
-DATA(insert (  2771    0 4  t  1070 ));
-
-/*
- * gin _time_ops
- */
-DATA(insert (  2772    0 1  f  2750 ));
-DATA(insert (  2772    0 2  f  2751 ));
-DATA(insert (  2772    0 3  t  2752 ));
-DATA(insert (  2772    0 4  t  1070 ));
-
-/*
- * gin _timestamptz_ops
- */
-DATA(insert (  2773    0 1  f  2750 ));
-DATA(insert (  2773    0 2  f  2751 ));
-DATA(insert (  2773    0 3  t  2752 ));
-DATA(insert (  2773    0 4  t  1070 ));
-
-/*
- * gin _timetz_ops
- */
-DATA(insert (  2774    0 1  f  2750 ));
-DATA(insert (  2774    0 2  f  2751 ));
-DATA(insert (  2774    0 3  t  2752 ));
-DATA(insert (  2774    0 4  t  1070 ));
-
-/*
- * gin _varbit_ops
- */
-DATA(insert (  2775    0 1  f  2750 ));
-DATA(insert (  2775    0 2  f  2751 ));
-DATA(insert (  2775    0 3  t  2752 ));
-DATA(insert (  2775    0 4  t  1070 ));
-
-/*
- * gin _varchar_ops
- */
-DATA(insert (  2776    0 1  f  2750 ));
-DATA(insert (  2776    0 2  f  2751 ));
-DATA(insert (  2776    0 3  t  2752 ));
-DATA(insert (  2776    0 4  t  1070 ));
-
-/*
- * gin _timestamp_ops
- */
-DATA(insert (  2777    0 1  f  2750 ));
-DATA(insert (  2777    0 2  f  2751 ));
-DATA(insert (  2777    0 3  t  2752 ));
-DATA(insert (  2777    0 4  t  1070 ));
-
-/*
- * gin _money_ops
- */
-DATA(insert (  2778    0 1  f  2750 ));
-DATA(insert (  2778    0 2  f  2751 ));
-DATA(insert (  2778    0 3  t  2752 ));
-DATA(insert (  2778    0 4  t  1070 ));
-
-/*
- * gin _reltime_ops
- */
-DATA(insert (  2779    0 1  f  2750 ));
-DATA(insert (  2779    0 2  f  2751 ));
-DATA(insert (  2779    0 3  t  2752 ));
-DATA(insert (  2779    0 4  t  1070 ));
-
-/*
- * gin _tinterval_ops
- */
-DATA(insert (  2780    0 1  f  2750 ));
-DATA(insert (  2780    0 2  f  2751 ));
-DATA(insert (  2780    0 3  t  2752 ));
-DATA(insert (  2780    0 4  t  1070 ));
+DATA(insert (  2595   718 718 1  t     1506    783 ));
+DATA(insert (  2595   718 718 2  t     1507    783 ));
+DATA(insert (  2595   718 718 3  t     1513    783 ));
+DATA(insert (  2595   718 718 4  t     1508    783 ));
+DATA(insert (  2595   718 718 5  t     1509    783 ));
+DATA(insert (  2595   718 718 6  t     1512    783 ));
+DATA(insert (  2595   718 718 7  t     1511    783 ));
+DATA(insert (  2595   718 718 8  t     1510    783 ));
+DATA(insert (  2595   718 718 9  t     2589    783 ));
+DATA(insert (  2595   718 718 10 t     1515    783 ));
+DATA(insert (  2595   718 718 11 t     1514    783 ));
+DATA(insert (  2595   718 718 12 t     2590    783 ));
+DATA(insert (  2595   718 718 13 t     2865    783 ));
+DATA(insert (  2595   718 718 14 t     2864    783 ));
+
+/*
+ * gin array_ops (these anyarray operators are used with all the opclasses
+ * of the family)
+ */
+DATA(insert (  2745   2277 2277 1  f   2750    2742 ));
+DATA(insert (  2745   2277 2277 2  f   2751    2742 ));
+DATA(insert (  2745   2277 2277 3  t   2752    2742 ));
+DATA(insert (  2745   2277 2277 4  t   1070    2742 ));
 
 #endif   /* PG_AMOP_H */
index 291931b707bc10371c3a501080ec75289cc114f7..1f81ff78309098282ef442c0cc8c6e2fb54a3c65 100644 (file)
@@ -5,21 +5,24 @@
  *       along with the relation's initial contents.
  *
  * The amproc table identifies support procedures associated with index
- * opclasses.  These procedures can't be listed in pg_amop since they are
- * not the implementation of any indexable operator for the opclass.
+ * operator families and classes.  These procedures can't be listed in pg_amop
+ * since they are not the implementation of any indexable operator.
  *
- * The primary key for this table is <amopclaid, amprocsubtype, amprocnum>.
- * amprocsubtype is equal to zero for an opclass's "default" procedures.
- * Usually a nondefault amprocsubtype indicates a support procedure to be
- * used with operators having the same nondefault amopsubtype. The exact
- * behavior depends on the index AM, however, and some don't pay attention
- * to subtype at all.
+ * The primary key for this table is <amprocfamily, amproclefttype,
+ * amprocrighttype, amprocnum>.  The "default" support functions for a
+ * particular opclass within the family are those with amproclefttype =
+ * amprocrighttype = opclass's opcintype.  These are the ones loaded into the
+ * relcache for an index and typically used for internal index operations.
+ * Other support functions are typically used to handle cross-type indexable
+ * operators with oprleft/oprright matching the entry's amproclefttype and
+ * amprocrighttype. The exact behavior depends on the index AM, however, and
+ * some don't pay attention to non-default functions at all.
  *
  *
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.60 2006/10/04 00:30:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.61 2006/12/23 00:43:12 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
  */
 #define AccessMethodProcedureRelationId  2603
 
-CATALOG(pg_amproc,2603) BKI_WITHOUT_OIDS
+CATALOG(pg_amproc,2603)
 {
-       Oid                     amopclaid;              /* the index opclass this entry is for */
-       Oid                     amprocsubtype;  /* procedure subtype, or zero if default */
-       int2            amprocnum;              /* support procedure index */
-       regproc         amproc;                 /* OID of the proc */
+       Oid                     amprocfamily;           /* the index opfamily this entry is for */
+       Oid                     amproclefttype;         /* procedure's left input data type */
+       Oid                     amprocrighttype;        /* procedure's right input data type */
+       int2            amprocnum;                      /* support procedure index */
+       regproc         amproc;                         /* OID of the proc */
 } FormData_pg_amproc;
 
 /* ----------------
@@ -63,11 +67,12 @@ typedef FormData_pg_amproc *Form_pg_amproc;
  *             compiler constants for pg_amproc
  * ----------------
  */
-#define Natts_pg_amproc                                        4
-#define Anum_pg_amproc_amopclaid               1
-#define Anum_pg_amproc_amprocsubtype   2
-#define Anum_pg_amproc_amprocnum               3
-#define Anum_pg_amproc_amproc                  4
+#define Natts_pg_amproc                                        5
+#define Anum_pg_amproc_amprocfamily            1
+#define Anum_pg_amproc_amproclefttype  2
+#define Anum_pg_amproc_amprocrighttype 3
+#define Anum_pg_amproc_amprocnum               4
+#define Anum_pg_amproc_amproc                  5
 
 /* ----------------
  *             initial contents of pg_amproc
@@ -75,237 +80,223 @@ typedef FormData_pg_amproc *Form_pg_amproc;
  */
 
 /* btree */
-DATA(insert (   397    0 1 382 ));
-DATA(insert (   421    0 1 357 ));
-DATA(insert (   423    0 1 1596 ));
-DATA(insert (   424    0 1 1693 ));
-DATA(insert (   426    0 1 1078 ));
-DATA(insert (   428    0 1 1954 ));
-DATA(insert (   429    0 1 358 ));
-DATA(insert (   432    0 1 926 ));
-DATA(insert (   434    0 1 1092 ));
-DATA(insert (   434 1114 1 2344 ));
-DATA(insert (   434 1184 1 2357 ));
-DATA(insert (  1970    0 1 354 ));
-DATA(insert (  1970  701 1 2194 ));
-DATA(insert (  1972    0 1 355 ));
-DATA(insert (  1972  700 1 2195 ));
-DATA(insert (  1974    0 1 926 ));
-DATA(insert (  1976    0 1 350 ));
-DATA(insert (  1976   23 1 2190 ));
-DATA(insert (  1976   20 1 2192 ));
-DATA(insert (  1978    0 1 351 ));
-DATA(insert (  1978   20 1 2188 ));
-DATA(insert (  1978   21 1 2191 ));
-DATA(insert (  1980    0 1 842 ));
-DATA(insert (  1980   23 1 2189 ));
-DATA(insert (  1980   21 1 2193 ));
-DATA(insert (  1982    0 1 1315 ));
-DATA(insert (  1984    0 1 836 ));
-DATA(insert (  1986    0 1 359 ));
-DATA(insert (  1988    0 1 1769 ));
-DATA(insert (  1989    0 1 356 ));
-DATA(insert (  1991    0 1 404 ));
-DATA(insert (  1994    0 1 360 ));
-DATA(insert (  1996    0 1 1107 ));
-DATA(insert (  1998    0 1 1314 ));
-DATA(insert (  1998 1082 1 2383 ));
-DATA(insert (  1998 1114 1 2533 ));
-DATA(insert (  2000    0 1 1358 ));
-DATA(insert (  2002    0 1 1672 ));
-DATA(insert (  2003    0 1 360 ));
-DATA(insert (  2039    0 1 2045 ));
-DATA(insert (  2039 1082 1 2370 ));
-DATA(insert (  2039 1184 1 2526 ));
-DATA(insert (  2095    0 1 2166 ));
-DATA(insert (  2096    0 1 2166 ));
-DATA(insert (  2097    0 1 2180 ));
-DATA(insert (  2098    0 1 2187 ));
-DATA(insert (  2099    0 1  377 ));
-DATA(insert (  2233    0 1  380 ));
-DATA(insert (  2234    0 1  381 ));
-DATA(insert (  2789    0 1 2794 ));
+DATA(insert (  397   2277 2277 1 382 ));
+DATA(insert (  421   702 702 1 357 ));
+DATA(insert (  423   1560 1560 1 1596 ));
+DATA(insert (  424   16 16 1 1693 ));
+DATA(insert (  426   1042 1042 1 1078 ));
+DATA(insert (  428   17 17 1 1954 ));
+DATA(insert (  429   18 18 1 358 ));
+DATA(insert (  434   1082 1082 1 1092 ));
+DATA(insert (  434   1082 1114 1 2344 ));
+DATA(insert (  434   1082 1184 1 2357 ));
+DATA(insert (  434   1114 1114 1 2045 ));
+DATA(insert (  434   1114 1082 1 2370 ));
+DATA(insert (  434   1114 1184 1 2526 ));
+DATA(insert (  434   1184 1184 1 1314 ));
+DATA(insert (  434   1184 1082 1 2383 ));
+DATA(insert (  434   1184 1114 1 2533 ));
+DATA(insert (  1970   700 700 1 354 ));
+DATA(insert (  1970   700 701 1 2194 ));
+DATA(insert (  1970   701 701 1 355 ));
+DATA(insert (  1970   701 700 1 2195 ));
+DATA(insert (  1974   869 869 1 926 ));
+DATA(insert (  1976   21 21 1 350 ));
+DATA(insert (  1976   21 23 1 2190 ));
+DATA(insert (  1976   21 20 1 2192 ));
+DATA(insert (  1976   23 23 1 351 ));
+DATA(insert (  1976   23 20 1 2188 ));
+DATA(insert (  1976   23 21 1 2191 ));
+DATA(insert (  1976   20 20 1 842 ));
+DATA(insert (  1976   20 23 1 2189 ));
+DATA(insert (  1976   20 21 1 2193 ));
+DATA(insert (  1982   1186 1186 1 1315 ));
+DATA(insert (  1984   829 829 1 836 ));
+DATA(insert (  1986   19 19 1 359 ));
+DATA(insert (  1988   1700 1700 1 1769 ));
+DATA(insert (  1989   26 26 1 356 ));
+DATA(insert (  1991   30 30 1 404 ));
+DATA(insert (  1994   25 25 1 360 ));
+DATA(insert (  1996   1083 1083 1 1107 ));
+DATA(insert (  2000   1266 1266 1 1358 ));
+DATA(insert (  2002   1562 1562 1 1672 ));
+DATA(insert (  2095   25 25 1 2166 ));
+DATA(insert (  2097   1042 1042 1 2180 ));
+DATA(insert (  2098   19 19 1 2187 ));
+DATA(insert (  2099   790 790 1  377 ));
+DATA(insert (  2233   703 703 1  380 ));
+DATA(insert (  2234   704 704 1  381 ));
+DATA(insert (  2789   27 27 1 2794 ));
 
 
 /* hash */
-DATA(insert (   427    0 1 1080 ));
-DATA(insert (   431    0 1 454 ));
-DATA(insert (   433    0 1 422 ));
-DATA(insert (   435    0 1 450 ));
-DATA(insert (  1971    0 1 451 ));
-DATA(insert (  1973    0 1 452 ));
-DATA(insert (  1975    0 1 422 ));
-DATA(insert (  1977    0 1 449 ));
-DATA(insert (  1979    0 1 450 ));
-DATA(insert (  1981    0 1 949 ));
-DATA(insert (  1983    0 1 1697 ));
-DATA(insert (  1985    0 1 399 ));
-DATA(insert (  1987    0 1 455 ));
-DATA(insert (  1990    0 1 453 ));
-DATA(insert (  1992    0 1 457 ));
-DATA(insert (  1995    0 1 400 ));
-DATA(insert (  1997    0 1 452 ));
-DATA(insert (  1999    0 1 452 ));
-DATA(insert (  2001    0 1 1696 ));
-DATA(insert (  2004    0 1 400 ));
-DATA(insert (  2040    0 1 452 ));
-DATA(insert (  2222    0 1 454 ));
-DATA(insert (  2223    0 1 456 ));
-DATA(insert (  2224    0 1 398 ));
-DATA(insert (  2225    0 1 450 ));
-DATA(insert (  2226    0 1 450 ));
-DATA(insert (  2227    0 1 450 ));
-DATA(insert (  2228    0 1 450 ));
-DATA(insert (  2229    0 1 456 ));
-DATA(insert (  2230    0 1 456 ));
-DATA(insert (  2231    0 1 456 ));
-DATA(insert (  2232    0 1 455 ));
-DATA(insert (  2235    0 1 329 ));
+DATA(insert (  427   1042 1042 1 1080 ));
+DATA(insert (  431   18 18 1 454 ));
+DATA(insert (  435   1082 1082 1 450 ));
+DATA(insert (  1971   700 700 1 451 ));
+DATA(insert (  1971   701 701 1 452 ));
+DATA(insert (  1975   869 869 1 422 ));
+DATA(insert (  1977   21 21 1 449 ));
+DATA(insert (  1977   23 23 1 450 ));
+DATA(insert (  1977   20 20 1 949 ));
+DATA(insert (  1983   1186 1186 1 1697 ));
+DATA(insert (  1985   829 829 1 399 ));
+DATA(insert (  1987   19 19 1 455 ));
+DATA(insert (  1990   26 26 1 453 ));
+DATA(insert (  1992   30 30 1 457 ));
+DATA(insert (  1995   25 25 1 400 ));
+DATA(insert (  1997   1083 1083 1 452 ));
+DATA(insert (  1999   1184 1184 1 452 ));
+DATA(insert (  2001   1266 1266 1 1696 ));
+DATA(insert (  2040   1114 1114 1 452 ));
+DATA(insert (  2222   16 16 1 454 ));
+DATA(insert (  2223   17 17 1 456 ));
+DATA(insert (  2224   22 22 1 398 ));
+DATA(insert (  2225   28 28 1 450 ));
+DATA(insert (  2226   29 29 1 450 ));
+DATA(insert (  2227   702 702 1 450 ));
+DATA(insert (  2228   703 703 1 450 ));
+DATA(insert (  2229   25 25 1 456 ));
+DATA(insert (  2231   1042 1042 1 456 ));
+DATA(insert (  2232   19 19 1 455 ));
+DATA(insert (  2235   1033 1033 1 329 ));
 
 
 /* gist */
-DATA(insert (  2593    0 1 2578 ));
-DATA(insert (  2593    0 2 2583 ));
-DATA(insert (  2593    0 3 2579 ));
-DATA(insert (  2593    0 4 2580 ));
-DATA(insert (  2593    0 5 2581 ));
-DATA(insert (  2593    0 6 2582 ));
-DATA(insert (  2593    0 7 2584 ));
-DATA(insert (  2594    0 1 2585 ));
-DATA(insert (  2594    0 2 2583 ));
-DATA(insert (  2594    0 3 2586 ));
-DATA(insert (  2594    0 4 2580 ));
-DATA(insert (  2594    0 5 2581 ));
-DATA(insert (  2594    0 6 2582 ));
-DATA(insert (  2594    0 7 2584 ));
-DATA(insert (  2595    0 1 2591 ));
-DATA(insert (  2595    0 2 2583 ));
-DATA(insert (  2595    0 3 2592 ));
-DATA(insert (  2595    0 4 2580 ));
-DATA(insert (  2595    0 5 2581 ));
-DATA(insert (  2595    0 6 2582 ));
-DATA(insert (  2595    0 7 2584 ));
+DATA(insert (  2593   603 603 1 2578 ));
+DATA(insert (  2593   603 603 2 2583 ));
+DATA(insert (  2593   603 603 3 2579 ));
+DATA(insert (  2593   603 603 4 2580 ));
+DATA(insert (  2593   603 603 5 2581 ));
+DATA(insert (  2593   603 603 6 2582 ));
+DATA(insert (  2593   603 603 7 2584 ));
+DATA(insert (  2594   604 604 1 2585 ));
+DATA(insert (  2594   604 604 2 2583 ));
+DATA(insert (  2594   604 604 3 2586 ));
+DATA(insert (  2594   604 604 4 2580 ));
+DATA(insert (  2594   604 604 5 2581 ));
+DATA(insert (  2594   604 604 6 2582 ));
+DATA(insert (  2594   604 604 7 2584 ));
+DATA(insert (  2595   718 718 1 2591 ));
+DATA(insert (  2595   718 718 2 2583 ));
+DATA(insert (  2595   718 718 3 2592 ));
+DATA(insert (  2595   718 718 4 2580 ));
+DATA(insert (  2595   718 718 5 2581 ));
+DATA(insert (  2595   718 718 6 2582 ));
+DATA(insert (  2595   718 718 7 2584 ));
 
 /* gin */
-DATA(insert (  2745    0 1  351 ));
-DATA(insert (  2745    0 2 2743 ));
-DATA(insert (  2745    0 3 2743 ));
-DATA(insert (  2745    0 4 2744 ));
-DATA(insert (  2746    0 1  360 ));
-DATA(insert (  2746    0 2 2743 ));
-DATA(insert (  2746    0 3 2743 ));
-DATA(insert (  2746    0 4 2744 ));
-DATA(insert (  2753    0 1 357 ));
-DATA(insert (  2753    0 2 2743 ));
-DATA(insert (  2753    0 3 2743 ));
-DATA(insert (  2753    0 4 2744 ));
-DATA(insert (  2754    0 1 1596 ));
-DATA(insert (  2754    0 2 2743 ));
-DATA(insert (  2754    0 3 2743 ));
-DATA(insert (  2754    0 4 2744 ));
-DATA(insert (  2755    0 1 1693 ));
-DATA(insert (  2755    0 2 2743 ));
-DATA(insert (  2755    0 3 2743 ));
-DATA(insert (  2755    0 4 2744 ));
-DATA(insert (  2756    0 1 1078 ));
-DATA(insert (  2756    0 2 2743 ));
-DATA(insert (  2756    0 3 2743 ));
-DATA(insert (  2756    0 4 2744 ));
-DATA(insert (  2757    0 1 1954 ));
-DATA(insert (  2757    0 2 2743 ));
-DATA(insert (  2757    0 3 2743 ));
-DATA(insert (  2757    0 4 2744 ));
-DATA(insert (  2758    0 1 358 ));
-DATA(insert (  2758    0 2 2743 ));
-DATA(insert (  2758    0 3 2743 ));
-DATA(insert (  2758    0 4 2744 ));
-DATA(insert (  2759    0 1 926 ));
-DATA(insert (  2759    0 2 2743 ));
-DATA(insert (  2759    0 3 2743 ));
-DATA(insert (  2759    0 4 2744 ));
-DATA(insert (  2760    0 1 1092 ));
-DATA(insert (  2760    0 2 2743 ));
-DATA(insert (  2760    0 3 2743 ));
-DATA(insert (  2760    0 4 2744 ));
-DATA(insert (  2761    0 1 354 ));
-DATA(insert (  2761    0 2 2743 ));
-DATA(insert (  2761    0 3 2743 ));
-DATA(insert (  2761    0 4 2744 ));
-DATA(insert (  2762    0 1 355 ));
-DATA(insert (  2762    0 2 2743 ));
-DATA(insert (  2762    0 3 2743 ));
-DATA(insert (  2762    0 4 2744 ));
-DATA(insert (  2763    0 1 926 ));
-DATA(insert (  2763    0 2 2743 ));
-DATA(insert (  2763    0 3 2743 ));
-DATA(insert (  2763    0 4 2744 ));
-DATA(insert (  2764    0 1 350 ));
-DATA(insert (  2764    0 2 2743 ));
-DATA(insert (  2764    0 3 2743 ));
-DATA(insert (  2764    0 4 2744 ));
-DATA(insert (  2765    0 1 842 ));
-DATA(insert (  2765    0 2 2743 ));
-DATA(insert (  2765    0 3 2743 ));
-DATA(insert (  2765    0 4 2744 ));
-DATA(insert (  2766    0 1 1315 ));
-DATA(insert (  2766    0 2 2743 ));
-DATA(insert (  2766    0 3 2743 ));
-DATA(insert (  2766    0 4 2744 ));
-DATA(insert (  2767    0 1 836 ));
-DATA(insert (  2767    0 2 2743 ));
-DATA(insert (  2767    0 3 2743 ));
-DATA(insert (  2767    0 4 2744 ));
-DATA(insert (  2768    0 1 359 ));
-DATA(insert (  2768    0 2 2743 ));
-DATA(insert (  2768    0 3 2743 ));
-DATA(insert (  2768    0 4 2744 ));
-DATA(insert (  2769    0 1 1769 ));
-DATA(insert (  2769    0 2 2743 ));
-DATA(insert (  2769    0 3 2743 ));
-DATA(insert (  2769    0 4 2744 ));
-DATA(insert (  2770    0 1 356 ));
-DATA(insert (  2770    0 2 2743 ));
-DATA(insert (  2770    0 3 2743 ));
-DATA(insert (  2770    0 4 2744 ));
-DATA(insert (  2771    0 1 404 ));
-DATA(insert (  2771    0 2 2743 ));
-DATA(insert (  2771    0 3 2743 ));
-DATA(insert (  2771    0 4 2744 ));
-DATA(insert (  2772    0 1 1107 ));
-DATA(insert (  2772    0 2 2743 ));
-DATA(insert (  2772    0 3 2743 ));
-DATA(insert (  2772    0 4 2744 ));
-DATA(insert (  2773    0 1 1314 ));
-DATA(insert (  2773    0 2 2743 ));
-DATA(insert (  2773    0 3 2743 ));
-DATA(insert (  2773    0 4 2744 ));
-DATA(insert (  2774    0 1 1358 ));
-DATA(insert (  2774    0 2 2743 ));
-DATA(insert (  2774    0 3 2743 ));
-DATA(insert (  2774    0 4 2744 ));
-DATA(insert (  2775    0 1 1672 ));
-DATA(insert (  2775    0 2 2743 ));
-DATA(insert (  2775    0 3 2743 ));
-DATA(insert (  2775    0 4 2744 ));
-DATA(insert (  2776    0 1 360 ));
-DATA(insert (  2776    0 2 2743 ));
-DATA(insert (  2776    0 3 2743 ));
-DATA(insert (  2776    0 4 2744 ));
-DATA(insert (  2777    0 1 2045 ));
-DATA(insert (  2777    0 2 2743 ));
-DATA(insert (  2777    0 3 2743 ));
-DATA(insert (  2777    0 4 2744 ));
-DATA(insert (  2778    0 1 377 ));
-DATA(insert (  2778    0 2 2743 ));
-DATA(insert (  2778    0 3 2743 ));
-DATA(insert (  2778    0 4 2744 ));
-DATA(insert (  2779    0 1 380 ));
-DATA(insert (  2779    0 2 2743 ));
-DATA(insert (  2779    0 3 2743 ));
-DATA(insert (  2779    0 4 2744 ));
-DATA(insert (  2780    0 1 381 ));
-DATA(insert (  2780    0 2 2743 ));
-DATA(insert (  2780    0 3 2743 ));
-DATA(insert (  2780    0 4 2744 ));
+DATA(insert (  2745   1007 1007 1  351 ));
+DATA(insert (  2745   1007 1007 2 2743 ));
+DATA(insert (  2745   1007 1007 3 2743 ));
+DATA(insert (  2745   1007 1007 4 2744 ));
+DATA(insert (  2745   1009 1009 1  360 ));
+DATA(insert (  2745   1009 1009 2 2743 ));
+DATA(insert (  2745   1009 1009 3 2743 ));
+DATA(insert (  2745   1009 1009 4 2744 ));
+DATA(insert (  2745   1023 1023 1 357 ));
+DATA(insert (  2745   1023 1023 2 2743 ));
+DATA(insert (  2745   1023 1023 3 2743 ));
+DATA(insert (  2745   1023 1023 4 2744 ));
+DATA(insert (  2745   1561 1561 1 1596 ));
+DATA(insert (  2745   1561 1561 2 2743 ));
+DATA(insert (  2745   1561 1561 3 2743 ));
+DATA(insert (  2745   1561 1561 4 2744 ));
+DATA(insert (  2745   1000 1000 1 1693 ));
+DATA(insert (  2745   1000 1000 2 2743 ));
+DATA(insert (  2745   1000 1000 3 2743 ));
+DATA(insert (  2745   1000 1000 4 2744 ));
+DATA(insert (  2745   1014 1014 1 1078 ));
+DATA(insert (  2745   1014 1014 2 2743 ));
+DATA(insert (  2745   1014 1014 3 2743 ));
+DATA(insert (  2745   1014 1014 4 2744 ));
+DATA(insert (  2745   1001 1001 1 1954 ));
+DATA(insert (  2745   1001 1001 2 2743 ));
+DATA(insert (  2745   1001 1001 3 2743 ));
+DATA(insert (  2745   1001 1001 4 2744 ));
+DATA(insert (  2745   1002 1002 1 358 ));
+DATA(insert (  2745   1002 1002 2 2743 ));
+DATA(insert (  2745   1002 1002 3 2743 ));
+DATA(insert (  2745   1002 1002 4 2744 ));
+DATA(insert (  2745   1182 1182 1 1092 ));
+DATA(insert (  2745   1182 1182 2 2743 ));
+DATA(insert (  2745   1182 1182 3 2743 ));
+DATA(insert (  2745   1182 1182 4 2744 ));
+DATA(insert (  2745   1021 1021 1 354 ));
+DATA(insert (  2745   1021 1021 2 2743 ));
+DATA(insert (  2745   1021 1021 3 2743 ));
+DATA(insert (  2745   1021 1021 4 2744 ));
+DATA(insert (  2745   1022 1022 1 355 ));
+DATA(insert (  2745   1022 1022 2 2743 ));
+DATA(insert (  2745   1022 1022 3 2743 ));
+DATA(insert (  2745   1022 1022 4 2744 ));
+DATA(insert (  2745   1041 1041 1 926 ));
+DATA(insert (  2745   1041 1041 2 2743 ));
+DATA(insert (  2745   1041 1041 3 2743 ));
+DATA(insert (  2745   1041 1041 4 2744 ));
+DATA(insert (  2745   1005 1005 1 350 ));
+DATA(insert (  2745   1005 1005 2 2743 ));
+DATA(insert (  2745   1005 1005 3 2743 ));
+DATA(insert (  2745   1005 1005 4 2744 ));
+DATA(insert (  2745   1016 1016 1 842 ));
+DATA(insert (  2745   1016 1016 2 2743 ));
+DATA(insert (  2745   1016 1016 3 2743 ));
+DATA(insert (  2745   1016 1016 4 2744 ));
+DATA(insert (  2745   1187 1187 1 1315 ));
+DATA(insert (  2745   1187 1187 2 2743 ));
+DATA(insert (  2745   1187 1187 3 2743 ));
+DATA(insert (  2745   1187 1187 4 2744 ));
+DATA(insert (  2745   1040 1040 1 836 ));
+DATA(insert (  2745   1040 1040 2 2743 ));
+DATA(insert (  2745   1040 1040 3 2743 ));
+DATA(insert (  2745   1040 1040 4 2744 ));
+DATA(insert (  2745   1003 1003 1 359 ));
+DATA(insert (  2745   1003 1003 2 2743 ));
+DATA(insert (  2745   1003 1003 3 2743 ));
+DATA(insert (  2745   1003 1003 4 2744 ));
+DATA(insert (  2745   1231 1231 1 1769 ));
+DATA(insert (  2745   1231 1231 2 2743 ));
+DATA(insert (  2745   1231 1231 3 2743 ));
+DATA(insert (  2745   1231 1231 4 2744 ));
+DATA(insert (  2745   1028 1028 1 356 ));
+DATA(insert (  2745   1028 1028 2 2743 ));
+DATA(insert (  2745   1028 1028 3 2743 ));
+DATA(insert (  2745   1028 1028 4 2744 ));
+DATA(insert (  2745   1013 1013 1 404 ));
+DATA(insert (  2745   1013 1013 2 2743 ));
+DATA(insert (  2745   1013 1013 3 2743 ));
+DATA(insert (  2745   1013 1013 4 2744 ));
+DATA(insert (  2745   1183 1183 1 1107 ));
+DATA(insert (  2745   1183 1183 2 2743 ));
+DATA(insert (  2745   1183 1183 3 2743 ));
+DATA(insert (  2745   1183 1183 4 2744 ));
+DATA(insert (  2745   1185 1185 1 1314 ));
+DATA(insert (  2745   1185 1185 2 2743 ));
+DATA(insert (  2745   1185 1185 3 2743 ));
+DATA(insert (  2745   1185 1185 4 2744 ));
+DATA(insert (  2745   1270 1270 1 1358 ));
+DATA(insert (  2745   1270 1270 2 2743 ));
+DATA(insert (  2745   1270 1270 3 2743 ));
+DATA(insert (  2745   1270 1270 4 2744 ));
+DATA(insert (  2745   1563 1563 1 1672 ));
+DATA(insert (  2745   1563 1563 2 2743 ));
+DATA(insert (  2745   1563 1563 3 2743 ));
+DATA(insert (  2745   1563 1563 4 2744 ));
+DATA(insert (  2745   1115 1115 1 2045 ));
+DATA(insert (  2745   1115 1115 2 2743 ));
+DATA(insert (  2745   1115 1115 3 2743 ));
+DATA(insert (  2745   1115 1115 4 2744 ));
+DATA(insert (  2745   791 791 1 377 ));
+DATA(insert (  2745   791 791 2 2743 ));
+DATA(insert (  2745   791 791 3 2743 ));
+DATA(insert (  2745   791 791 4 2744 ));
+DATA(insert (  2745   1024 1024 1 380 ));
+DATA(insert (  2745   1024 1024 2 2743 ));
+DATA(insert (  2745   1024 1024 3 2743 ));
+DATA(insert (  2745   1024 1024 4 2744 ));
+DATA(insert (  2745   1025 1025 1 381 ));
+DATA(insert (  2745   1025 1025 2 2743 ));
+DATA(insert (  2745   1025 1025 3 2743 ));
+DATA(insert (  2745   1025 1025 4 2744 ));
 
 #endif   /* PG_AMPROC_H */
index cee9f752bf087f23530f8844078593465c5c4350..8aa9ea3d68af50984e8797e761b3fc81e92e7860 100644 (file)
@@ -4,16 +4,17 @@
  *       definition of the system "opclass" relation (pg_opclass)
  *       along with the relation's initial contents.
  *
- * New definition for Postgres 7.2: the primary key for this table is
- * <opcamid, opcname> --- that is, there is a row for each valid combination
- * of opclass name and index access method type.  This row specifies the
- * expected input data type for the opclass (the type of the heap column,
- * or the expression output type in the case of an index expression).  Note
- * that types binary-coercible to the specified type will be accepted too.
+ * The primary key for this table is <opcmethod, opcname, opcnamespace> ---
+ * that is, there is a row for each valid combination of opclass name and
+ * index access method type.  This row specifies the expected input data type
+ * for the opclass (the type of the heap column, or the expression output type
+ * in the case of an index expression).  Note that types binary-coercible to
+ * the specified type will be accepted too.
  *
- * For a given <opcamid, opcintype> pair, there can be at most one row that
+ * For a given <opcmethod, opcintype> pair, there can be at most one row that
  * has opcdefault = true; this row is the default opclass for such data in
- * such an index.
+ * such an index.  (This is not currently enforced by an index, because we
+ * don't support partial indexes on system catalogs.)
  *
  * Normally opckeytype = InvalidOid (zero), indicating that the data stored
  * in the index is the same as the data in the indexed column. If opckeytype
@@ -27,7 +28,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.71 2006/07/21 20:51:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.72 2006/12/23 00:43:12 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
 
 CATALOG(pg_opclass,2616)
 {
-       Oid                     opcamid;                /* index access method opclass is for */
+       Oid                     opcmethod;              /* index access method opclass is for */
        NameData        opcname;                /* name of this opclass */
        Oid                     opcnamespace;   /* namespace of this opclass */
        Oid                     opcowner;               /* opclass owner */
+       Oid                     opcfamily;              /* containing operator family */
        Oid                     opcintype;              /* type of data indexed by opclass */
        bool            opcdefault;             /* T if opclass is default for opcintype */
        Oid                     opckeytype;             /* type of data in index, or InvalidOid */
@@ -74,138 +76,129 @@ typedef FormData_pg_opclass *Form_pg_opclass;
  *             compiler constants for pg_opclass
  * ----------------
  */
-#define Natts_pg_opclass                               7
-#define Anum_pg_opclass_opcamid                        1
+#define Natts_pg_opclass                               8
+#define Anum_pg_opclass_opcmethod              1
 #define Anum_pg_opclass_opcname                        2
 #define Anum_pg_opclass_opcnamespace   3
 #define Anum_pg_opclass_opcowner               4
-#define Anum_pg_opclass_opcintype              5
-#define Anum_pg_opclass_opcdefault             6
-#define Anum_pg_opclass_opckeytype             7
+#define Anum_pg_opclass_opcfamily              5
+#define Anum_pg_opclass_opcintype              6
+#define Anum_pg_opclass_opcdefault             7
+#define Anum_pg_opclass_opckeytype             8
 
 /* ----------------
  *             initial contents of pg_opclass
+ *
+ * Note: we hard-wire an OID only for a few entries that have to be explicitly
+ * referenced in the C code for bootstrapping purposes.  The rest get OIDs
+ * assigned on-the-fly during initdb.
  * ----------------
  */
 
-DATA(insert OID =  421 (       403             abstime_ops             PGNSP PGUID  702 t 0 ));
-DATA(insert OID =  397 (       403             array_ops               PGNSP PGUID 2277 t 0 ));
-#define ARRAY_BTREE_OPS_OID 397
-DATA(insert OID =  423 (       403             bit_ops                 PGNSP PGUID 1560 t 0 ));
-DATA(insert OID =  424 (       403             bool_ops                PGNSP PGUID   16 t 0 ));
-#define BOOL_BTREE_OPS_OID 424
-DATA(insert OID =  426 (       403             bpchar_ops              PGNSP PGUID 1042 t 0 ));
-#define BPCHAR_BTREE_OPS_OID 426
-DATA(insert OID =  427 (       405             bpchar_ops              PGNSP PGUID 1042 t 0 ));
-DATA(insert OID =  428 (       403             bytea_ops               PGNSP PGUID   17 t 0 ));
-#define BYTEA_BTREE_OPS_OID 428
-DATA(insert OID =  429 (       403             char_ops                PGNSP PGUID   18 t 0 ));
-DATA(insert OID =  431 (       405             char_ops                PGNSP PGUID   18 t 0 ));
-DATA(insert OID =  432 (       403             cidr_ops                PGNSP PGUID  650 t 0 ));
-#define CIDR_BTREE_OPS_OID 432
-DATA(insert OID =  433 (       405             cidr_ops                PGNSP PGUID  650 t 0 ));
-DATA(insert OID =  434 (       403             date_ops                PGNSP PGUID 1082 t 0 ));
-DATA(insert OID =  435 (       405             date_ops                PGNSP PGUID 1082 t 0 ));
-DATA(insert OID = 1970 (       403             float4_ops              PGNSP PGUID  700 t 0 ));
-DATA(insert OID = 1971 (       405             float4_ops              PGNSP PGUID  700 t 0 ));
-DATA(insert OID = 1972 (       403             float8_ops              PGNSP PGUID  701 t 0 ));
-DATA(insert OID = 1973 (       405             float8_ops              PGNSP PGUID  701 t 0 ));
-DATA(insert OID = 1974 (       403             inet_ops                PGNSP PGUID  869 t 0 ));
-#define INET_BTREE_OPS_OID 1974
-DATA(insert OID = 1975 (       405             inet_ops                PGNSP PGUID  869 t 0 ));
-DATA(insert OID = 1976 (       403             int2_ops                PGNSP PGUID   21 t 0 ));
-#define INT2_BTREE_OPS_OID 1976
-DATA(insert OID = 1977 (       405             int2_ops                PGNSP PGUID   21 t 0 ));
-DATA(insert OID = 1978 (       403             int4_ops                PGNSP PGUID   23 t 0 ));
+DATA(insert (  403             abstime_ops                     PGNSP PGUID  421  702 t 0 ));
+DATA(insert (  403             array_ops                       PGNSP PGUID  397 2277 t 0 ));
+DATA(insert (  403             bit_ops                         PGNSP PGUID  423 1560 t 0 ));
+DATA(insert (  403             bool_ops                        PGNSP PGUID  424   16 t 0 ));
+DATA(insert (  403             bpchar_ops                      PGNSP PGUID  426 1042 t 0 ));
+DATA(insert (  405             bpchar_ops                      PGNSP PGUID  427 1042 t 0 ));
+DATA(insert (  403             bytea_ops                       PGNSP PGUID  428   17 t 0 ));
+DATA(insert (  403             char_ops                        PGNSP PGUID  429   18 t 0 ));
+DATA(insert (  405             char_ops                        PGNSP PGUID  431   18 t 0 ));
+DATA(insert (  403             cidr_ops                        PGNSP PGUID 1974  869 f 0 ));
+DATA(insert (  405             cidr_ops                        PGNSP PGUID 1975  869 f 0 ));
+DATA(insert (  403             date_ops                        PGNSP PGUID  434 1082 t 0 ));
+DATA(insert (  405             date_ops                        PGNSP PGUID  435 1082 t 0 ));
+DATA(insert (  403             float4_ops                      PGNSP PGUID 1970  700 t 0 ));
+DATA(insert (  405             float4_ops                      PGNSP PGUID 1971  700 t 0 ));
+DATA(insert (  403             float8_ops                      PGNSP PGUID 1970  701 t 0 ));
+DATA(insert (  405             float8_ops                      PGNSP PGUID 1971  701 t 0 ));
+DATA(insert (  403             inet_ops                        PGNSP PGUID 1974  869 t 0 ));
+DATA(insert (  405             inet_ops                        PGNSP PGUID 1975  869 t 0 ));
+DATA(insert OID = 1979 ( 403   int2_ops        PGNSP PGUID 1976   21 t 0 ));
+#define INT2_BTREE_OPS_OID 1979
+DATA(insert (  405             int2_ops                        PGNSP PGUID 1977   21 t 0 ));
+DATA(insert OID = 1978 ( 403   int4_ops        PGNSP PGUID 1976   23 t 0 ));
 #define INT4_BTREE_OPS_OID 1978
-DATA(insert OID = 1979 (       405             int4_ops                PGNSP PGUID   23 t 0 ));
-DATA(insert OID = 1980 (       403             int8_ops                PGNSP PGUID   20 t 0 ));
-DATA(insert OID = 1981 (       405             int8_ops                PGNSP PGUID   20 t 0 ));
-DATA(insert OID = 1982 (       403             interval_ops    PGNSP PGUID 1186 t 0 ));
-DATA(insert OID = 1983 (       405             interval_ops    PGNSP PGUID 1186 t 0 ));
-DATA(insert OID = 1984 (       403             macaddr_ops             PGNSP PGUID  829 t 0 ));
-DATA(insert OID = 1985 (       405             macaddr_ops             PGNSP PGUID  829 t 0 ));
-DATA(insert OID = 1986 (       403             name_ops                PGNSP PGUID   19 t 0 ));
-#define NAME_BTREE_OPS_OID 1986
-DATA(insert OID = 1987 (       405             name_ops                PGNSP PGUID   19 t 0 ));
-DATA(insert OID = 1988 (       403             numeric_ops             PGNSP PGUID 1700 t 0 ));
-DATA(insert OID = 1989 (       403             oid_ops                 PGNSP PGUID   26 t 0 ));
-#define OID_BTREE_OPS_OID 1989
-DATA(insert OID = 1990 (       405             oid_ops                 PGNSP PGUID   26 t 0 ));
-DATA(insert OID = 1991 (       403             oidvector_ops   PGNSP PGUID   30 t 0 ));
-DATA(insert OID = 1992 (       405             oidvector_ops   PGNSP PGUID   30 t 0 ));
-DATA(insert OID = 1994 (       403             text_ops                PGNSP PGUID   25 t 0 ));
-#define TEXT_BTREE_OPS_OID 1994
-DATA(insert OID = 1995 (       405             text_ops                PGNSP PGUID   25 t 0 ));
-DATA(insert OID = 1996 (       403             time_ops                PGNSP PGUID 1083 t 0 ));
-DATA(insert OID = 1997 (       405             time_ops                PGNSP PGUID 1083 t 0 ));
-DATA(insert OID = 1998 (       403             timestamptz_ops PGNSP PGUID 1184 t 0 ));
-DATA(insert OID = 1999 (       405             timestamptz_ops PGNSP PGUID 1184 t 0 ));
-DATA(insert OID = 2000 (       403             timetz_ops              PGNSP PGUID 1266 t 0 ));
-DATA(insert OID = 2001 (       405             timetz_ops              PGNSP PGUID 1266 t 0 ));
-DATA(insert OID = 2002 (       403             varbit_ops              PGNSP PGUID 1562 t 0 ));
-DATA(insert OID = 2003 (       403             varchar_ops             PGNSP PGUID 1043 t 0 ));
-#define VARCHAR_BTREE_OPS_OID 2003
-DATA(insert OID = 2004 (       405             varchar_ops             PGNSP PGUID 1043 t 0 ));
-DATA(insert OID = 2039 (       403             timestamp_ops   PGNSP PGUID 1114 t 0 ));
-DATA(insert OID = 2040 (       405             timestamp_ops   PGNSP PGUID 1114 t 0 ));
-DATA(insert OID = 2095 (       403             text_pattern_ops        PGNSP PGUID   25 f 0 ));
-#define TEXT_PATTERN_BTREE_OPS_OID 2095
-DATA(insert OID = 2096 (       403             varchar_pattern_ops PGNSP PGUID 1043 f 0 ));
-#define VARCHAR_PATTERN_BTREE_OPS_OID 2096
-DATA(insert OID = 2097 (       403             bpchar_pattern_ops      PGNSP PGUID 1042 f 0 ));
-#define BPCHAR_PATTERN_BTREE_OPS_OID 2097
-DATA(insert OID = 2098 (       403             name_pattern_ops        PGNSP PGUID   19 f 0 ));
-#define NAME_PATTERN_BTREE_OPS_OID 2098
-DATA(insert OID = 2099 (       403             money_ops               PGNSP PGUID  790 t 0 ));
-DATA(insert OID = 2222 (       405             bool_ops                PGNSP PGUID   16 t 0 ));
-#define BOOL_HASH_OPS_OID 2222
-DATA(insert OID = 2223 (       405             bytea_ops               PGNSP PGUID   17 t 0 ));
-DATA(insert OID = 2224 (       405             int2vector_ops  PGNSP PGUID   22 t 0 ));
-DATA(insert OID = 2789 (       403             tid_ops                 PGNSP PGUID   27 t 0 ));
-DATA(insert OID = 2225 (       405             xid_ops                 PGNSP PGUID   28 t 0 ));
-DATA(insert OID = 2226 (       405             cid_ops                 PGNSP PGUID   29 t 0 ));
-DATA(insert OID = 2227 (       405             abstime_ops             PGNSP PGUID  702 t 0 ));
-DATA(insert OID = 2228 (       405             reltime_ops             PGNSP PGUID  703 t 0 ));
-DATA(insert OID = 2229 (       405             text_pattern_ops        PGNSP PGUID   25 f 0 ));
-DATA(insert OID = 2230 (       405             varchar_pattern_ops PGNSP PGUID 1043 f 0 ));
-DATA(insert OID = 2231 (       405             bpchar_pattern_ops      PGNSP PGUID 1042 f 0 ));
-DATA(insert OID = 2232 (       405             name_pattern_ops        PGNSP PGUID   19 f 0 ));
-DATA(insert OID = 2233 (       403             reltime_ops             PGNSP PGUID  703 t 0 ));
-DATA(insert OID = 2234 (       403             tinterval_ops   PGNSP PGUID  704 t 0 ));
-DATA(insert OID = 2235 (       405             aclitem_ops             PGNSP PGUID 1033 t 0 ));
-DATA(insert OID = 2593 (       783             box_ops                 PGNSP PGUID  603 t 0 ));
-DATA(insert OID = 2594 (       783             poly_ops                PGNSP PGUID  604 t 603 ));
-DATA(insert OID = 2595 (       783             circle_ops              PGNSP PGUID  718 t 603 ));
-DATA(insert OID = 2745 (       2742    _int4_ops               PGNSP PGUID  1007 t 23 ));
-DATA(insert OID = 2746 (       2742    _text_ops               PGNSP PGUID  1009 t 25 ));
-DATA(insert OID = 2753 (       2742    _abstime_ops    PGNSP PGUID  1023 t 702 ));
-DATA(insert OID = 2754 (       2742    _bit_ops                PGNSP PGUID  1561 t 1560 ));
-DATA(insert OID = 2755 (       2742    _bool_ops               PGNSP PGUID  1000 t 16 ));
-DATA(insert OID = 2756 (       2742    _bpchar_ops             PGNSP PGUID  1014 t 1042 ));
-DATA(insert OID = 2757 (       2742    _bytea_ops              PGNSP PGUID  1001 t 17 ));
-DATA(insert OID = 2758 (       2742    _char_ops               PGNSP PGUID  1002 t 18 ));
-DATA(insert OID = 2759 (       2742    _cidr_ops               PGNSP PGUID  651 t 650 ));
-DATA(insert OID = 2760 (       2742    _date_ops               PGNSP PGUID  1182 t 1082 ));
-DATA(insert OID = 2761 (       2742    _float4_ops             PGNSP PGUID  1021 t 700 ));
-DATA(insert OID = 2762 (       2742    _float8_ops             PGNSP PGUID  1022 t 701 ));
-DATA(insert OID = 2763 (       2742    _inet_ops               PGNSP PGUID  1041 t 869 ));
-DATA(insert OID = 2764 (       2742    _int2_ops               PGNSP PGUID  1005 t 21 ));
-DATA(insert OID = 2765 (       2742    _int8_ops               PGNSP PGUID  1016 t 20 ));
-DATA(insert OID = 2766 (       2742    _interval_ops   PGNSP PGUID  1187 t 1186 ));
-DATA(insert OID = 2767 (       2742    _macaddr_ops    PGNSP PGUID  1040 t 829 ));
-DATA(insert OID = 2768 (       2742    _name_ops               PGNSP PGUID  1003 t 19 ));
-DATA(insert OID = 2769 (       2742    _numeric_ops    PGNSP PGUID  1231 t 1700 ));
-DATA(insert OID = 2770 (       2742    _oid_ops                PGNSP PGUID  1028 t 26 ));
-DATA(insert OID = 2771 (       2742    _oidvector_ops  PGNSP PGUID  1013 t 30 ));
-DATA(insert OID = 2772 (       2742    _time_ops               PGNSP PGUID  1183 t 1083 ));
-DATA(insert OID = 2773 (       2742    _timestamptz_ops        PGNSP PGUID  1185 t 1184 ));
-DATA(insert OID = 2774 (       2742    _timetz_ops             PGNSP PGUID  1270 t 1266 ));
-DATA(insert OID = 2775 (       2742    _varbit_ops             PGNSP PGUID  1563 t 1562 ));
-DATA(insert OID = 2776 (       2742    _varchar_ops    PGNSP PGUID  1015 t 1043 ));
-DATA(insert OID = 2777 (       2742    _timestamp_ops  PGNSP PGUID  1115 t 1114 ));
-DATA(insert OID = 2778 (       2742    _money_ops              PGNSP PGUID  791 t 790 ));
-DATA(insert OID = 2779 (       2742    _reltime_ops    PGNSP PGUID  1024 t 703 ));
-DATA(insert OID = 2780 (       2742    _tinterval_ops  PGNSP PGUID  1025 t 704 ));
+DATA(insert (  405             int4_ops                        PGNSP PGUID 1977   23 t 0 ));
+DATA(insert (  403             int8_ops                        PGNSP PGUID 1976   20 t 0 ));
+DATA(insert (  405             int8_ops                        PGNSP PGUID 1977   20 t 0 ));
+DATA(insert (  403             interval_ops            PGNSP PGUID 1982 1186 t 0 ));
+DATA(insert (  405             interval_ops            PGNSP PGUID 1983 1186 t 0 ));
+DATA(insert (  403             macaddr_ops                     PGNSP PGUID 1984  829 t 0 ));
+DATA(insert (  405             macaddr_ops                     PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (  403             name_ops                        PGNSP PGUID 1986   19 t 0 ));
+DATA(insert (  405             name_ops                        PGNSP PGUID 1987   19 t 0 ));
+DATA(insert (  403             numeric_ops                     PGNSP PGUID 1988 1700 t 0 ));
+DATA(insert OID = 1981 ( 403   oid_ops         PGNSP PGUID 1989   26 t 0 ));
+#define OID_BTREE_OPS_OID 1981
+DATA(insert (  405             oid_ops                         PGNSP PGUID 1990   26 t 0 ));
+DATA(insert (  403             oidvector_ops           PGNSP PGUID 1991   30 t 0 ));
+DATA(insert (  405             oidvector_ops           PGNSP PGUID 1992   30 t 0 ));
+DATA(insert (  403             text_ops                        PGNSP PGUID 1994   25 t 0 ));
+DATA(insert (  405             text_ops                        PGNSP PGUID 1995   25 t 0 ));
+DATA(insert (  403             time_ops                        PGNSP PGUID 1996 1083 t 0 ));
+DATA(insert (  405             time_ops                        PGNSP PGUID 1997 1083 t 0 ));
+DATA(insert (  403             timestamptz_ops         PGNSP PGUID  434 1184 t 0 ));
+DATA(insert (  405             timestamptz_ops         PGNSP PGUID 1999 1184 t 0 ));
+DATA(insert (  403             timetz_ops                      PGNSP PGUID 2000 1266 t 0 ));
+DATA(insert (  405             timetz_ops                      PGNSP PGUID 2001 1266 t 0 ));
+DATA(insert (  403             varbit_ops                      PGNSP PGUID 2002 1562 t 0 ));
+DATA(insert (  403             varchar_ops                     PGNSP PGUID 1994   25 f 0 ));
+DATA(insert (  405             varchar_ops                     PGNSP PGUID 1995   25 f 0 ));
+DATA(insert (  403             timestamp_ops           PGNSP PGUID  434 1114 t 0 ));
+DATA(insert (  405             timestamp_ops           PGNSP PGUID 2040 1114 t 0 ));
+DATA(insert (  403             text_pattern_ops        PGNSP PGUID 2095   25 f 0 ));
+DATA(insert (  403             varchar_pattern_ops PGNSP PGUID 2095   25 f 0 ));
+DATA(insert (  403             bpchar_pattern_ops      PGNSP PGUID 2097 1042 f 0 ));
+DATA(insert (  403             name_pattern_ops        PGNSP PGUID 2098   19 f 0 ));
+DATA(insert (  403             money_ops                       PGNSP PGUID 2099  790 t 0 ));
+DATA(insert (  405             bool_ops                        PGNSP PGUID 2222   16 t 0 ));
+DATA(insert (  405             bytea_ops                       PGNSP PGUID 2223   17 t 0 ));
+DATA(insert (  405             int2vector_ops          PGNSP PGUID 2224   22 t 0 ));
+DATA(insert (  403             tid_ops                         PGNSP PGUID 2789   27 t 0 ));
+DATA(insert (  405             xid_ops                         PGNSP PGUID 2225   28 t 0 ));
+DATA(insert (  405             cid_ops                         PGNSP PGUID 2226   29 t 0 ));
+DATA(insert (  405             abstime_ops                     PGNSP PGUID 2227  702 t 0 ));
+DATA(insert (  405             reltime_ops                     PGNSP PGUID 2228  703 t 0 ));
+DATA(insert (  405             text_pattern_ops        PGNSP PGUID 2229   25 f 0 ));
+DATA(insert (  405             varchar_pattern_ops PGNSP PGUID 2229   25 f 0 ));
+DATA(insert (  405             bpchar_pattern_ops      PGNSP PGUID 2231 1042 f 0 ));
+DATA(insert (  405             name_pattern_ops        PGNSP PGUID 2232   19 f 0 ));
+DATA(insert (  403             reltime_ops                     PGNSP PGUID 2233  703 t 0 ));
+DATA(insert (  403             tinterval_ops           PGNSP PGUID 2234  704 t 0 ));
+DATA(insert (  405             aclitem_ops                     PGNSP PGUID 2235 1033 t 0 ));
+DATA(insert (  783             box_ops                         PGNSP PGUID 2593  603 t 0 ));
+DATA(insert (  783             poly_ops                        PGNSP PGUID 2594  604 t 603 ));
+DATA(insert (  783             circle_ops                      PGNSP PGUID 2595  718 t 603 ));
+DATA(insert (  2742    _int4_ops                       PGNSP PGUID 2745  1007 t 23 ));
+DATA(insert (  2742    _text_ops                       PGNSP PGUID 2745  1009 t 25 ));
+DATA(insert (  2742    _abstime_ops            PGNSP PGUID 2745  1023 t 702 ));
+DATA(insert (  2742    _bit_ops                        PGNSP PGUID 2745  1561 t 1560 ));
+DATA(insert (  2742    _bool_ops                       PGNSP PGUID 2745  1000 t 16 ));
+DATA(insert (  2742    _bpchar_ops                     PGNSP PGUID 2745  1014 t 1042 ));
+DATA(insert (  2742    _bytea_ops                      PGNSP PGUID 2745  1001 t 17 ));
+DATA(insert (  2742    _char_ops                       PGNSP PGUID 2745  1002 t 18 ));
+DATA(insert (  2742    _cidr_ops                       PGNSP PGUID 2745  651 t 650 ));
+DATA(insert (  2742    _date_ops                       PGNSP PGUID 2745  1182 t 1082 ));
+DATA(insert (  2742    _float4_ops                     PGNSP PGUID 2745  1021 t 700 ));
+DATA(insert (  2742    _float8_ops                     PGNSP PGUID 2745  1022 t 701 ));
+DATA(insert (  2742    _inet_ops                       PGNSP PGUID 2745  1041 t 869 ));
+DATA(insert (  2742    _int2_ops                       PGNSP PGUID 2745  1005 t 21 ));
+DATA(insert (  2742    _int8_ops                       PGNSP PGUID 2745  1016 t 20 ));
+DATA(insert (  2742    _interval_ops           PGNSP PGUID 2745  1187 t 1186 ));
+DATA(insert (  2742    _macaddr_ops            PGNSP PGUID 2745  1040 t 829 ));
+DATA(insert (  2742    _name_ops                       PGNSP PGUID 2745  1003 t 19 ));
+DATA(insert (  2742    _numeric_ops            PGNSP PGUID 2745  1231 t 1700 ));
+DATA(insert (  2742    _oid_ops                        PGNSP PGUID 2745  1028 t 26 ));
+DATA(insert (  2742    _oidvector_ops          PGNSP PGUID 2745  1013 t 30 ));
+DATA(insert (  2742    _time_ops                       PGNSP PGUID 2745  1183 t 1083 ));
+DATA(insert (  2742    _timestamptz_ops        PGNSP PGUID 2745  1185 t 1184 ));
+DATA(insert (  2742    _timetz_ops                     PGNSP PGUID 2745  1270 t 1266 ));
+DATA(insert (  2742    _varbit_ops                     PGNSP PGUID 2745  1563 t 1562 ));
+DATA(insert (  2742    _varchar_ops            PGNSP PGUID 2745  1015 t 1043 ));
+DATA(insert (  2742    _timestamp_ops          PGNSP PGUID 2745  1115 t 1114 ));
+DATA(insert (  2742    _money_ops                      PGNSP PGUID 2745  791 t 790 ));
+DATA(insert (  2742    _reltime_ops            PGNSP PGUID 2745  1024 t 703 ));
+DATA(insert (  2742    _tinterval_ops          PGNSP PGUID 2745  1025 t 704 ));
 
 #endif   /* PG_OPCLASS_H */
index b64b3c5136ff2af4483d37a23bc429447240aaf4..b2acdc425b193968150127e462c410d33eecd523 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.146 2006/10/04 00:30:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.147 2006/12/23 00:43:12 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -44,16 +44,13 @@ CATALOG(pg_operator,2617)
        Oid                     oprnamespace;   /* OID of namespace containing this oper */
        Oid                     oprowner;               /* operator owner */
        char            oprkind;                /* 'l', 'r', or 'b' */
+       bool            oprcanmerge;    /* can be used in merge join? */
        bool            oprcanhash;             /* can be used in hash join? */
        Oid                     oprleft;                /* left arg type, or 0 if 'l' oprkind */
        Oid                     oprright;               /* right arg type, or 0 if 'r' oprkind */
        Oid                     oprresult;              /* result datatype */
        Oid                     oprcom;                 /* OID of commutator oper, or 0 if none */
        Oid                     oprnegate;              /* OID of negator oper, or 0 if none */
-       Oid                     oprlsortop;             /* OID of left sortop, if mergejoinable */
-       Oid                     oprrsortop;             /* OID of right sortop, if mergejoinable */
-       Oid                     oprltcmpop;             /* OID of "l<r" oper, if mergejoinable */
-       Oid                     oprgtcmpop;             /* OID of "l>r" oper, if mergejoinable */
        regproc         oprcode;                /* OID of underlying function */
        regproc         oprrest;                /* OID of restriction estimator, or 0 */
        regproc         oprjoin;                /* OID of join estimator, or 0 */
@@ -71,837 +68,832 @@ typedef FormData_pg_operator *Form_pg_operator;
  * ----------------
  */
 
-#define Natts_pg_operator                              17
+#define Natts_pg_operator                              14
 #define Anum_pg_operator_oprname               1
 #define Anum_pg_operator_oprnamespace  2
 #define Anum_pg_operator_oprowner              3
 #define Anum_pg_operator_oprkind               4
-#define Anum_pg_operator_oprcanhash            5
-#define Anum_pg_operator_oprleft               6
-#define Anum_pg_operator_oprright              7
-#define Anum_pg_operator_oprresult             8
-#define Anum_pg_operator_oprcom                        9
-#define Anum_pg_operator_oprnegate             10
-#define Anum_pg_operator_oprlsortop            11
-#define Anum_pg_operator_oprrsortop            12
-#define Anum_pg_operator_oprltcmpop            13
-#define Anum_pg_operator_oprgtcmpop            14
-#define Anum_pg_operator_oprcode               15
-#define Anum_pg_operator_oprrest               16
-#define Anum_pg_operator_oprjoin               17
+#define Anum_pg_operator_oprcanmerge   5
+#define Anum_pg_operator_oprcanhash            6
+#define Anum_pg_operator_oprleft               7
+#define Anum_pg_operator_oprright              8
+#define Anum_pg_operator_oprresult             9
+#define Anum_pg_operator_oprcom                        10
+#define Anum_pg_operator_oprnegate             11
+#define Anum_pg_operator_oprcode               12
+#define Anum_pg_operator_oprrest               13
+#define Anum_pg_operator_oprjoin               14
 
 /* ----------------
  *             initial contents of pg_operator
  * ----------------
  */
 
-DATA(insert OID =  15 ( "="               PGNSP PGUID b f      23      20      16 416  36      97 412  37      76 int48eq eqsel eqjoinsel ));
-DATA(insert OID =  36 ( "<>"      PGNSP PGUID b f      23      20      16 417  15       0       0       0       0 int48ne neqsel neqjoinsel ));
-DATA(insert OID =  37 ( "<"               PGNSP PGUID b f      23      20      16 419  82       0       0       0       0 int48lt scalarltsel scalarltjoinsel ));
-DATA(insert OID =  76 ( ">"               PGNSP PGUID b f      23      20      16 418  80       0       0       0       0 int48gt scalargtsel scalargtjoinsel ));
-DATA(insert OID =  80 ( "<="      PGNSP PGUID b f      23      20      16 430  76       0       0       0       0 int48le scalarltsel scalarltjoinsel ));
-DATA(insert OID =  82 ( ">="      PGNSP PGUID b f      23      20      16 420  37       0       0       0       0 int48ge scalargtsel scalargtjoinsel ));
-
-DATA(insert OID =  58 ( "<"               PGNSP PGUID b f      16      16      16      59       1695   0       0       0       0 boollt scalarltsel scalarltjoinsel ));
-DATA(insert OID =  59 ( ">"               PGNSP PGUID b f      16      16      16      58       1694   0       0       0       0 boolgt scalargtsel scalargtjoinsel ));
-DATA(insert OID =  85 ( "<>"      PGNSP PGUID b f      16      16      16      85      91       0       0       0       0 boolne neqsel neqjoinsel ));
-DATA(insert OID =  91 ( "="               PGNSP PGUID b t      16      16      16      91      85      58      58      58      59 booleq eqsel eqjoinsel ));
+DATA(insert OID =  15 ( "="               PGNSP PGUID b t f    23      20      16 416  36 int48eq eqsel eqjoinsel ));
+DATA(insert OID =  36 ( "<>"      PGNSP PGUID b f f    23      20      16 417  15 int48ne neqsel neqjoinsel ));
+DATA(insert OID =  37 ( "<"               PGNSP PGUID b f f    23      20      16 419  82 int48lt scalarltsel scalarltjoinsel ));
+DATA(insert OID =  76 ( ">"               PGNSP PGUID b f f    23      20      16 418  80 int48gt scalargtsel scalargtjoinsel ));
+DATA(insert OID =  80 ( "<="      PGNSP PGUID b f f    23      20      16 430  76 int48le scalarltsel scalarltjoinsel ));
+DATA(insert OID =  82 ( ">="      PGNSP PGUID b f f    23      20      16 420  37 int48ge scalargtsel scalargtjoinsel ));
+
+DATA(insert OID =  58 ( "<"               PGNSP PGUID b f f    16      16      16      59      1695 boollt scalarltsel scalarltjoinsel ));
+DATA(insert OID =  59 ( ">"               PGNSP PGUID b f f    16      16      16      58      1694 boolgt scalargtsel scalargtjoinsel ));
+DATA(insert OID =  85 ( "<>"      PGNSP PGUID b f f    16      16      16      85      91 boolne neqsel neqjoinsel ));
+DATA(insert OID =  91 ( "="               PGNSP PGUID b t t    16      16      16      91      85 booleq eqsel eqjoinsel ));
 #define BooleanEqualOperator   91
-DATA(insert OID = 1694 (  "<="    PGNSP PGUID b f      16      16      16 1695 59      0  0   0   0 boolle scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1695 (  ">="    PGNSP PGUID b f      16      16      16 1694 58      0  0   0   0 boolge scalargtsel scalargtjoinsel ));
-
-DATA(insert OID =  92 ( "="               PGNSP PGUID b t      18      18      16      92 630 631 631 631 633 chareq eqsel eqjoinsel ));
-DATA(insert OID =  93 ( "="               PGNSP PGUID b t      19      19      16      93 643 660 660 660 662 nameeq eqsel eqjoinsel ));
-DATA(insert OID =  94 ( "="               PGNSP PGUID b t      21      21      16      94 519  95      95      95 520 int2eq eqsel eqjoinsel ));
-DATA(insert OID =  95 ( "<"               PGNSP PGUID b f      21      21      16 520 524       0       0       0       0 int2lt scalarltsel scalarltjoinsel ));
-DATA(insert OID =  96 ( "="               PGNSP PGUID b t      23      23      16      96 518  97      97      97 521 int4eq eqsel eqjoinsel ));
-DATA(insert OID =  97 ( "<"               PGNSP PGUID b f      23      23      16 521 525       0       0       0       0 int4lt scalarltsel scalarltjoinsel ));
-DATA(insert OID =  98 ( "="               PGNSP PGUID b t      25      25      16      98 531 664 664 664 666 texteq eqsel eqjoinsel ));
-
-DATA(insert OID = 349 (  "||"     PGNSP PGUID b f 2277 2283 2277       0 0 0 0 0 0 array_append   -       -     ));
-DATA(insert OID = 374 (  "||"     PGNSP PGUID b f 2283 2277 2277       0 0 0 0 0 0 array_prepend  -       -     ));
-DATA(insert OID = 375 (  "||"     PGNSP PGUID b f 2277 2277 2277       0 0 0 0 0 0 array_cat      -       -     ));
-
-DATA(insert OID = 352 (  "="      PGNSP PGUID b t      28      28      16 352   0       0       0       0       0 xideq eqsel eqjoinsel ));
-DATA(insert OID = 353 (  "="      PGNSP PGUID b f      28      23      16       0       0       0       0       0       0 xideqint4 eqsel eqjoinsel ));
-DATA(insert OID = 388 (  "!"      PGNSP PGUID r f      20       0      1700   0   0   0   0  0   0 numeric_fac - - ));
-DATA(insert OID = 389 (  "!!"     PGNSP PGUID l f       0      20      1700   0   0   0   0  0   0 numeric_fac - - ));
-DATA(insert OID = 385 (  "="      PGNSP PGUID b t      29      29      16 385   0       0       0       0       0 cideq eqsel eqjoinsel ));
-DATA(insert OID = 386 (  "="      PGNSP PGUID b t      22      22      16 386   0       0       0       0       0 int2vectoreq eqsel eqjoinsel ));
-
-DATA(insert OID = 387 (  "="      PGNSP PGUID b f      27      27      16 387 402 2799 2799 2799 2800 tideq eqsel eqjoinsel ));
+DATA(insert OID = 1694 (  "<="    PGNSP PGUID b f f    16      16      16 1695 59 boolle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1695 (  ">="    PGNSP PGUID b f f    16      16      16 1694 58 boolge scalargtsel scalargtjoinsel ));
+
+DATA(insert OID =  92 ( "="               PGNSP PGUID b t t    18      18      16      92 630 chareq eqsel eqjoinsel ));
+DATA(insert OID =  93 ( "="               PGNSP PGUID b t t    19      19      16      93 643 nameeq eqsel eqjoinsel ));
+DATA(insert OID =  94 ( "="               PGNSP PGUID b t t    21      21      16      94 519 int2eq eqsel eqjoinsel ));
+DATA(insert OID =  95 ( "<"               PGNSP PGUID b f f    21      21      16 520 524 int2lt scalarltsel scalarltjoinsel ));
+DATA(insert OID =  96 ( "="               PGNSP PGUID b t t    23      23      16      96 518 int4eq eqsel eqjoinsel ));
+DATA(insert OID =  97 ( "<"               PGNSP PGUID b f f    23      23      16 521 525 int4lt scalarltsel scalarltjoinsel ));
+DATA(insert OID =  98 ( "="               PGNSP PGUID b t t    25      25      16      98 531 texteq eqsel eqjoinsel ));
+
+DATA(insert OID = 349 (  "||"     PGNSP PGUID b f f 2277 2283 2277     0 0 array_append   -       -     ));
+DATA(insert OID = 374 (  "||"     PGNSP PGUID b f f 2283 2277 2277     0 0 array_prepend  -       -     ));
+DATA(insert OID = 375 (  "||"     PGNSP PGUID b f f 2277 2277 2277     0 0 array_cat      -       -     ));
+
+DATA(insert OID = 352 (  "="      PGNSP PGUID b f t    28      28      16 352   0 xideq eqsel eqjoinsel ));
+DATA(insert OID = 353 (  "="      PGNSP PGUID b f f    28      23      16       0       0 xideqint4 eqsel eqjoinsel ));
+DATA(insert OID = 388 (  "!"      PGNSP PGUID r f f    20       0      1700  0  0 numeric_fac - - ));
+DATA(insert OID = 389 (  "!!"     PGNSP PGUID l f f     0      20      1700  0  0 numeric_fac - - ));
+DATA(insert OID = 385 (  "="      PGNSP PGUID b f t    29      29      16 385   0 cideq eqsel eqjoinsel ));
+DATA(insert OID = 386 (  "="      PGNSP PGUID b f t    22      22      16 386   0 int2vectoreq eqsel eqjoinsel ));
+
+DATA(insert OID = 387 (  "="      PGNSP PGUID b t f    27      27      16 387 402 tideq eqsel eqjoinsel ));
 #define TIDEqualOperator   387
-DATA(insert OID = 402 (  "<>"     PGNSP PGUID b f      27      27      16 402 387 0 0 0 0 tidne neqsel neqjoinsel ));
-DATA(insert OID = 2799 (  "<"     PGNSP PGUID b f      27      27      16 2800 2802 0 0 0 0 tidlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 402 (  "<>"     PGNSP PGUID b f f    27      27      16 402 387 tidne neqsel neqjoinsel ));
+DATA(insert OID = 2799 (  "<"     PGNSP PGUID b f f    27      27      16 2800 2802 tidlt scalarltsel scalarltjoinsel ));
 #define TIDLessOperator    2799
-DATA(insert OID = 2800 (  ">"     PGNSP PGUID b f      27      27      16 2799 2801 0 0 0 0 tidgt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 2801 (  "<="    PGNSP PGUID b f      27      27      16 2802 2800 0 0 0 0 tidle scalarltsel scalarltjoinsel ));
-DATA(insert OID = 2802 (  ">="    PGNSP PGUID b f      27      27      16 2801 2799 0 0 0 0 tidge scalargtsel scalargtjoinsel ));
-
-DATA(insert OID = 410 ( "="               PGNSP PGUID b t      20      20      16 410 411 412 412 412 413 int8eq eqsel eqjoinsel ));
-DATA(insert OID = 411 ( "<>"      PGNSP PGUID b f      20      20      16 411 410 0 0 0 0 int8ne neqsel neqjoinsel ));
-DATA(insert OID = 412 ( "<"               PGNSP PGUID b f      20      20      16 413 415 0 0 0 0 int8lt scalarltsel scalarltjoinsel ));
-DATA(insert OID = 413 ( ">"               PGNSP PGUID b f      20      20      16 412 414 0 0 0 0 int8gt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 414 ( "<="      PGNSP PGUID b f      20      20      16 415 413 0 0 0 0 int8le scalarltsel scalarltjoinsel ));
-DATA(insert OID = 415 ( ">="      PGNSP PGUID b f      20      20      16 414 412 0 0 0 0 int8ge scalargtsel scalargtjoinsel ));
-
-DATA(insert OID = 416 ( "="               PGNSP PGUID b f      20      23      16      15 417 412 97 418 419 int84eq eqsel eqjoinsel ));
-DATA(insert OID = 417 ( "<>"      PGNSP PGUID b f      20      23      16      36 416 0 0 0 0 int84ne neqsel neqjoinsel ));
-DATA(insert OID = 418 ( "<"               PGNSP PGUID b f      20      23      16      76 430 0 0 0 0 int84lt scalarltsel scalarltjoinsel ));
-DATA(insert OID = 419 ( ">"               PGNSP PGUID b f      20      23      16      37 420 0 0 0 0 int84gt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 420 ( "<="      PGNSP PGUID b f      20      23      16      82 419 0 0 0 0 int84le scalarltsel scalarltjoinsel ));
-DATA(insert OID = 430 ( ">="      PGNSP PGUID b f      20      23      16      80 418 0 0 0 0 int84ge scalargtsel scalargtjoinsel ));
-DATA(insert OID = 439 (  "%"      PGNSP PGUID b f      20      20      20       0       0 0 0 0 0 int8mod - - ));
-DATA(insert OID = 473 (  "@"      PGNSP PGUID l f       0      20      20       0       0 0 0 0 0 int8abs - - ));
-
-DATA(insert OID = 484 (  "-"      PGNSP PGUID l f       0      20      20       0       0       0       0       0       0 int8um - - ));
-DATA(insert OID = 485 (  "<<"     PGNSP PGUID b f 604 604      16       0       0       0       0       0       0 poly_left positionsel positionjoinsel ));
-DATA(insert OID = 486 (  "&<"     PGNSP PGUID b f 604 604      16       0       0       0       0       0       0 poly_overleft positionsel positionjoinsel ));
-DATA(insert OID = 487 (  "&>"     PGNSP PGUID b f 604 604      16       0       0       0       0       0       0 poly_overright positionsel positionjoinsel ));
-DATA(insert OID = 488 (  ">>"     PGNSP PGUID b f 604 604      16       0       0       0       0       0       0 poly_right positionsel positionjoinsel ));
-DATA(insert OID = 489 (  "<@"     PGNSP PGUID b f 604 604      16 490   0       0       0       0       0 poly_contained contsel contjoinsel ));
-DATA(insert OID = 490 (  "@>"     PGNSP PGUID b f 604 604      16 489   0       0       0       0       0 poly_contain contsel contjoinsel ));
-DATA(insert OID = 491 (  "~="     PGNSP PGUID b f 604 604      16 491   0       0       0       0       0 poly_same eqsel eqjoinsel ));
-DATA(insert OID = 492 (  "&&"     PGNSP PGUID b f 604 604      16 492   0       0       0       0       0 poly_overlap areasel areajoinsel ));
-DATA(insert OID = 493 (  "<<"     PGNSP PGUID b f 603 603      16       0       0       0       0       0       0 box_left positionsel positionjoinsel ));
-DATA(insert OID = 494 (  "&<"     PGNSP PGUID b f 603 603      16       0       0       0       0       0       0 box_overleft positionsel positionjoinsel ));
-DATA(insert OID = 495 (  "&>"     PGNSP PGUID b f 603 603      16       0       0       0       0       0       0 box_overright positionsel positionjoinsel ));
-DATA(insert OID = 496 (  ">>"     PGNSP PGUID b f 603 603      16       0       0       0       0       0       0 box_right positionsel positionjoinsel ));
-DATA(insert OID = 497 (  "<@"     PGNSP PGUID b f 603 603      16 498   0       0       0       0       0 box_contained contsel contjoinsel ));
-DATA(insert OID = 498 (  "@>"     PGNSP PGUID b f 603 603      16 497   0       0       0       0       0 box_contain contsel contjoinsel ));
-DATA(insert OID = 499 (  "~="     PGNSP PGUID b f 603 603      16 499   0       0       0       0       0 box_same eqsel eqjoinsel ));
-DATA(insert OID = 500 (  "&&"     PGNSP PGUID b f 603 603      16 500   0       0       0       0       0 box_overlap areasel areajoinsel ));
-DATA(insert OID = 501 (  ">="     PGNSP PGUID b f 603 603      16 505 504       0       0       0       0 box_ge areasel areajoinsel ));
-DATA(insert OID = 502 (  ">"      PGNSP PGUID b f 603 603      16 504 505       0       0       0       0 box_gt areasel areajoinsel ));
-DATA(insert OID = 503 (  "="      PGNSP PGUID b f 603 603      16 503   0 504 504 504 502 box_eq eqsel eqjoinsel ));
-DATA(insert OID = 504 (  "<"      PGNSP PGUID b f 603 603      16 502 501       0       0       0       0 box_lt areasel areajoinsel ));
-DATA(insert OID = 505 (  "<="     PGNSP PGUID b f 603 603      16 501 502       0       0       0       0 box_le areasel areajoinsel ));
-DATA(insert OID = 506 (  ">^"     PGNSP PGUID b f 600 600      16       0       0       0       0       0       0 point_above positionsel positionjoinsel ));
-DATA(insert OID = 507 (  "<<"     PGNSP PGUID b f 600 600      16       0       0       0       0       0       0 point_left positionsel positionjoinsel ));
-DATA(insert OID = 508 (  ">>"     PGNSP PGUID b f 600 600      16       0       0       0       0       0       0 point_right positionsel positionjoinsel ));
-DATA(insert OID = 509 (  "<^"     PGNSP PGUID b f 600 600      16       0       0       0       0       0       0 point_below positionsel positionjoinsel ));
-DATA(insert OID = 510 (  "~="     PGNSP PGUID b f 600 600      16 510 713       0       0       0       0 point_eq eqsel eqjoinsel ));
-DATA(insert OID = 511 (  "<@"     PGNSP PGUID b f 600 603      16       0       0       0       0       0       0 on_pb - - ));
-DATA(insert OID = 512 (  "<@"     PGNSP PGUID b f 600 602      16 755   0       0       0       0       0 on_ppath - - ));
-DATA(insert OID = 513 (  "@@"     PGNSP PGUID l f       0 603 600       0       0       0       0       0       0 box_center - - ));
-DATA(insert OID = 514 (  "*"      PGNSP PGUID b f      23      23      23 514   0       0       0       0       0 int4mul - - ));
-DATA(insert OID = 517 (  "<->"    PGNSP PGUID b f 600 600 701 517       0       0       0       0       0 point_distance - - ));
-DATA(insert OID = 518 (  "<>"     PGNSP PGUID b f      23      23      16 518  96      0  0   0   0 int4ne neqsel neqjoinsel ));
-DATA(insert OID = 519 (  "<>"     PGNSP PGUID b f      21      21      16 519  94      0  0   0   0 int2ne neqsel neqjoinsel&