OSDN Git Service

Create the system catalog infrastructure needed for KNNGIST.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 24 Nov 2010 19:20:39 +0000 (14:20 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 24 Nov 2010 19:22:17 +0000 (14:22 -0500)
This commit adds columns amoppurpose and amopsortfamily to pg_amop, and
column amcanorderbyop to pg_am.  For the moment all the entries in
amcanorderbyop are "false", since the underlying support isn't there yet.

Also, extend the CREATE OPERATOR CLASS/ALTER OPERATOR FAMILY commands with
[ FOR SEARCH | FOR ORDER BY sort_operator_family ] clauses to allow the new
columns of pg_amop to be populated, and create pg_dump support for dumping
that information.

I also added some documentation, although it's perhaps a bit premature
given that the feature doesn't do anything useful yet.

Teodor Sigaev, Robert Haas, Tom Lane

21 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/alter_opfamily.sgml
doc/src/sgml/ref/create_opclass.sgml
doc/src/sgml/xindex.sgml
src/backend/commands/opclasscmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/predtest.c
src/backend/parser/gram.y
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/syscache.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h
src/include/catalog/indexing.h
src/include/catalog/pg_am.h
src/include/catalog/pg_amop.h
src/include/nodes/parsenodes.h
src/include/nodes/relation.h
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/opr_sanity.sql

index 9a8729b..54a6dcc 100644 (file)
       <entry><structfield>amcanorder</structfield></entry>
       <entry><type>bool</type></entry>
       <entry></entry>
-      <entry>Does the access method support ordered scans?</entry>
+      <entry>Does the access method support ordered scans sorted by the
+       indexed column's value?</entry>
+     </row>
+
+     <row>
+      <entry><structfield>amcanorderbyop</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>Does the access method support ordered scans sorted by the result
+       of an operator on the indexed column?</entry>
      </row>
 
      <row>
   <para>
    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
+   row for each operator that is a member of an operator family.  A family
+   member can be either a <firstterm>search</> operator or an
+   <firstterm>ordering</> operator.  An operator
    can appear in more than one family, but cannot appear in more than one
-   position within a family.
+   search position nor more than one ordering position within a family.
+   (It is allowed, though unlikely, for an operator to be used for both
+   search and ordering purposes.)
   </para>
 
   <table>
      </row>
 
      <row>
+      <entry><structfield>amoppurpose</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>Operator purpose, either <literal>s</> for search or
+       <literal>o</> for ordering</entry>
+     </row>
+
+     <row>
       <entry><structfield>amopopr</structfield></entry>
       <entry><type>oid</type></entry>
       <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
       <entry>Index access method operator family is for</entry>
      </row>
 
+     <row>
+      <entry><structfield>amopsortfamily</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-opfamily"><structname>pg_opfamily</structname></link>.oid</literal></entry>
+      <entry>The btree operator family this entry sorts according to, if an
+       ordering operator; zero if a search operator</entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
 
   <para>
+   A <quote>search</> operator entry indicates that an index of this operator
+   family can be searched to find all rows satisfying
+   <literal>WHERE</>
+   <replaceable>indexed_column</>
+   <replaceable>operator</>
+   <replaceable>constant</>.
+   Obviously, such an operator must return boolean, and its left-hand input
+   type must match the index's column data type.
+  </para>
+
+  <para>
+   An <quote>ordering</> operator entry indicates that an index of this
+   operator family can be scanned to return rows in the order represented by
+   <literal>ORDER BY</>
+   <replaceable>indexed_column</>
+   <replaceable>operator</>
+   <replaceable>constant</>.
+   Such an operator could return any sortable data type, though again
+   its left-hand input type must match the index's column data type.
+   The exact semantics of the <literal>ORDER BY</> are specified by the
+   <structfield>amopsortfamily</structfield> column, which must reference
+   a btree operator family for the operator's result type.
+  </para>
+
+  <note>
+   <para>
+    At present, it's assumed that the sort order for an ordering operator
+    is the default for the referenced opfamily, i.e., <literal>ASC NULLS
+    LAST</>.  This might someday be relaxed by adding additional columns
+    to specify sort options explicitly.
+   </para>
+  </note>
+
+  <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
index 1018af8..3c8ca21 100644 (file)
@@ -22,7 +22,7 @@ PostgreSQL documentation
  <refsynopsisdiv>
 <synopsis>
 ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> ADD
-  {  OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> )
+  {  OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) [ FOR SEARCH | FOR ORDER BY <replaceable class="parameter">sort_family_name</replaceable> ]
    | FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">function_name</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
   } [, ... ]
 ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> DROP
@@ -155,6 +155,22 @@ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
    </varlistentry>
 
    <varlistentry>
+    <term><replaceable class="parameter">sort_family_name</replaceable></term>
+    <listitem>
+     <para>
+      The name (optionally schema-qualified) of an existing btree operator
+      family that describes the sort ordering associated with an ordering
+      operator.
+     </para>
+
+     <para>
+      If neither <literal>FOR SEARCH</> nor <literal>FOR ORDER BY</> is
+      specified, <literal>FOR SEARCH</> is the default.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">support_number</replaceable></term>
     <listitem>
      <para>
index f12f13d..eff5854 100644 (file)
@@ -23,7 +23,7 @@ PostgreSQL documentation
 <synopsis>
 CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable>
   USING <replaceable class="parameter">index_method</replaceable> [ FAMILY <replaceable class="parameter">family_name</replaceable> ] AS
-  {  OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ]
+  {  OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ] [ FOR SEARCH | FOR ORDER BY <replaceable class="parameter">sort_family_name</replaceable> ]
    | FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">function_name</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
    | STORAGE <replaceable class="parameter">storage_type</replaceable>
   } [, ... ]
@@ -181,6 +181,22 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
    </varlistentry>
 
    <varlistentry>
+    <term><replaceable class="parameter">sort_family_name</replaceable></term>
+    <listitem>
+     <para>
+      The name (optionally schema-qualified) of an existing btree operator
+      family that describes the sort ordering associated with an ordering
+      operator.
+     </para>
+
+     <para>
+      If neither <literal>FOR SEARCH</> nor <literal>FOR ORDER BY</> is
+      specified, <literal>FOR SEARCH</> is the default.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">support_number</replaceable></term>
     <listitem>
      <para>
index 8f9fd21..6d059bd 100644 (file)
    </table>
 
   <para>
-   Notice that all strategy operators return Boolean values.  In
-   practice, all operators defined as index method strategies must
+   Notice that all the operators listed above return Boolean values.  In
+   practice, all operators defined as index method search operators must
    return type <type>boolean</type>, since they must appear at the top
    level of a <literal>WHERE</> clause to be used with an index.
+   (Some index access methods also support <firstterm>ordering operators</>,
+   which typically don't return Boolean values; that feature is discussed
+   in <xref linkend="xindex-ordering-ops">.)
   </para>
  </sect2>
 
    </table>
 
   <para>
-   Unlike strategy operators, support functions return whichever data
+   Unlike search operators, support functions return whichever data
    type the particular index method expects; for example in the case
    of the comparison function for B-trees, a signed integer.  The number
    and types of the arguments to each support function are likewise
@@ -921,6 +924,62 @@ ALTER OPERATOR FAMILY integer_ops USING btree ADD
   </para>
  </sect2>
 
+ <sect2 id="xindex-ordering-ops">
+  <title>Ordering Operators</title>
+
+  <para>
+   Some index access methods (currently, only GiST) support the concept of
+   <firstterm>ordering operators</>.  What we have been discussing so far
+   are <firstterm>search operators</>.  A search operator is one for which
+   the index can be searched to find all rows satisfying
+   <literal>WHERE</>
+   <replaceable>indexed_column</>
+   <replaceable>operator</>
+   <replaceable>constant</>.
+   Note that nothing is promised about the order in which the matching rows
+   will be returned.  In contrast, an ordering operator does not restrict the
+   set of rows that can be returned, but instead determines their order.
+   An ordering operator is one for which the index can be scanned to return
+   rows in the order represented by
+   <literal>ORDER BY</>
+   <replaceable>indexed_column</>
+   <replaceable>operator</>
+   <replaceable>constant</>.
+   The reason for defining ordering operators that way is that it supports
+   nearest-neighbor searches, if the operator is one that measures distance.
+   For example, a query like
+<programlisting><![CDATA[
+SELECT * FROM places ORDER BY location <-> point '(101,456)' LIMIT 10;
+]]>
+</programlisting>
+   finds the ten places closest to a given target point.  A GiST index
+   on the location column can do this efficiently because
+   <literal>&lt;-&gt;</> is an ordering operator.
+  </para>
+
+  <para>
+   While search operators have to return Boolean results, ordering operators
+   usually return some other type, such as float or numeric for distances.
+   This type is normally not the same as the data type being indexed.
+   To avoid hard-wiring assumptions about the behavior of different data
+   types, the definition of an ordering operator is required to name
+   a B-tree operator family that specifies the sort ordering of the result
+   data type.  As was stated in the previous section, B-tree operator families
+   define <productname>PostgreSQL</productname>'s notion of ordering, so
+   this is a natural representation.  Since the point <literal>&lt;-&gt;</>
+   operator returns <type>float8</>, it could be specified in an operator
+   class creation command like this:
+<programlisting><![CDATA[
+OPERATOR 15    <-> (point, point) FOR ORDER BY float_ops
+]]>
+</programlisting>
+   where <literal>float_ops</> is the built-in operator family that includes
+   operations on <type>float8</>.  This declaration states that the index
+   is able to return rows in order of increasing values of the
+   <literal>&lt;-&gt;</> operator.
+  </para>
+ </sect2>
+
  <sect2 id="xindex-opclass-features">
   <title>Special Features of Operator Classes</title>
 
index 8c49336..132c4ee 100644 (file)
@@ -54,6 +54,7 @@ typedef struct
        int                     number;                 /* strategy or support proc number */
        Oid                     lefttype;               /* lefttype */
        Oid                     righttype;              /* righttype */
+       Oid                     sortfamily;             /* ordering operator's sort opfamily, or 0 */
 } OpFamilyMember;
 
 
@@ -457,6 +458,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
                CreateOpClassItem *item = lfirst(l);
                Oid                     operOid;
                Oid                     funcOid;
+               Oid                     sortfamilyOid;
                OpFamilyMember *member;
 
                Assert(IsA(item, CreateOpClassItem));
@@ -486,6 +488,13 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                                                                         false, -1);
                                }
 
+                               if (item->order_family)
+                                       sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
+                                                                                                        item->order_family,
+                                                                                                        false);
+                               else
+                                       sortfamilyOid = InvalidOid;
+
 #ifdef NOT_USED
                                /* XXX this is unnecessary given the superuser check above */
                                /* Caller must own operator and its underlying function */
@@ -502,6 +511,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                                member->object = operOid;
                                member->number = item->number;
+                               member->sortfamily = sortfamilyOid;
                                assignOperTypes(member, amoid, typeoid);
                                addFamilyMember(&operators, member, false);
                                break;
@@ -825,6 +835,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
                CreateOpClassItem *item = lfirst(l);
                Oid                     operOid;
                Oid                     funcOid;
+               Oid                     sortfamilyOid;
                OpFamilyMember *member;
 
                Assert(IsA(item, CreateOpClassItem));
@@ -854,6 +865,13 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
                                        operOid = InvalidOid;           /* keep compiler quiet */
                                }
 
+                               if (item->order_family)
+                                       sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
+                                                                                                        item->order_family,
+                                                                                                        false);
+                               else
+                                       sortfamilyOid = InvalidOid;
+
 #ifdef NOT_USED
                                /* XXX this is unnecessary given the superuser check above */
                                /* Caller must own operator and its underlying function */
@@ -870,6 +888,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
                                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                                member->object = operOid;
                                member->number = item->number;
+                               member->sortfamily = sortfamilyOid;
                                assignOperTypes(member, amoid, InvalidOid);
                                addFamilyMember(&operators, member, false);
                                break;
@@ -1043,16 +1062,51 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
        opform = (Form_pg_operator) GETSTRUCT(optup);
 
        /*
-        * Opfamily operators must be binary ops returning boolean.
+        * Opfamily operators must be binary.
         */
        if (opform->oprkind != 'b')
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                 errmsg("index operators must be binary")));
-       if (opform->oprresult != BOOLOID)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("index operators must return boolean")));
+
+       if (OidIsValid(member->sortfamily))
+       {
+               /*
+                * Ordering op, check index supports that.  (We could perhaps also
+                * check that the operator returns a type supported by the sortfamily,
+                * but that seems more trouble than it's worth here.  If it does not,
+                * the operator will never be matchable to any ORDER BY clause, but
+                * no worse consequences can ensue.  Also, trying to check that would
+                * create an ordering hazard during dump/reload: it's possible that
+                * the family has been created but not yet populated with the required
+                * operators.)
+                */
+               HeapTuple       amtup;
+               Form_pg_am      pg_am;
+
+               amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+               if (amtup == NULL)
+                       elog(ERROR, "cache lookup failed for access method %u", amoid);
+               pg_am = (Form_pg_am) GETSTRUCT(amtup);
+
+               if (!pg_am->amcanorderbyop)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("access method \"%s\" does not support ordering operators",
+                                                       NameStr(pg_am->amname))));
+
+               ReleaseSysCache(amtup);
+       }
+       else
+       {
+               /*
+                * Search operators must return boolean.
+                */
+               if (opform->oprresult != BOOLOID)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                        errmsg("index search operators must return boolean")));
+       }
 
        /*
         * If lefttype/righttype isn't specified, use the operator's input types
@@ -1206,6 +1260,7 @@ storeOperators(List *opfamilyname, Oid amoid,
        foreach(l, operators)
        {
                OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
+               char    oppurpose;
 
                /*
                 * If adding to an existing family, check for conflict with an
@@ -1225,6 +1280,8 @@ storeOperators(List *opfamilyname, Oid amoid,
                                                        format_type_be(op->righttype),
                                                        NameListToString(opfamilyname))));
 
+               oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
+
                /* Create the pg_amop entry */
                memset(values, 0, sizeof(values));
                memset(nulls, false, sizeof(nulls));
@@ -1233,8 +1290,10 @@ storeOperators(List *opfamilyname, Oid amoid,
                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_amoppurpose - 1] = CharGetDatum(oppurpose);
                values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
                values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
+               values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
 
                tup = heap_form_tuple(rel->rd_att, values, nulls);
 
@@ -1275,6 +1334,15 @@ storeOperators(List *opfamilyname, Oid amoid,
                        referenced.objectSubId = 0;
                        recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
                }
+
+               /* A search operator also needs a dep on the referenced opfamily */
+               if (OidIsValid(op->sortfamily))
+               {
+                       referenced.classId = OperatorFamilyRelationId;
+                       referenced.objectId = op->sortfamily;
+                       referenced.objectSubId = 0;
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               }
        }
 
        heap_close(rel, RowExclusiveLock);
index bbfbab2..0e0b4dc 100644 (file)
@@ -2991,6 +2991,7 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
        COPY_NODE_FIELD(name);
        COPY_NODE_FIELD(args);
        COPY_SCALAR_FIELD(number);
+       COPY_NODE_FIELD(order_family);
        COPY_NODE_FIELD(class_args);
        COPY_NODE_FIELD(storedtype);
 
index be4b835..2d2b8c7 100644 (file)
@@ -1464,6 +1464,7 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
        COMPARE_NODE_FIELD(name);
        COMPARE_NODE_FIELD(args);
        COMPARE_SCALAR_FIELD(number);
+       COMPARE_NODE_FIELD(order_family);
        COMPARE_NODE_FIELD(class_args);
        COMPARE_NODE_FIELD(storedtype);
 
index 73132dd..908b4f7 100644 (file)
@@ -212,6 +212,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 
                        info->relam = indexRelation->rd_rel->relam;
                        info->amcostestimate = indexRelation->rd_am->amcostestimate;
+                       info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
                        info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
                        info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
                        info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
index 5ab4a31..d7ccba0 100644 (file)
@@ -1661,8 +1661,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
                 * From the same opfamily, find a strategy number for the clause_op,
                 * if possible
                 */
-               clause_tuple = SearchSysCache2(AMOPOPID,
+               clause_tuple = SearchSysCache3(AMOPOPID,
                                                                           ObjectIdGetDatum(clause_op),
+                                                                          CharGetDatum(AMOP_SEARCH),
                                                                           ObjectIdGetDatum(opfamily_id));
                if (HeapTupleIsValid(clause_tuple))
                {
@@ -1677,8 +1678,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
                }
                else if (OidIsValid(clause_op_negator))
                {
-                       clause_tuple = SearchSysCache2(AMOPOPID,
-                                                                                ObjectIdGetDatum(clause_op_negator),
+                       clause_tuple = SearchSysCache3(AMOPOPID,
+                                                                                  ObjectIdGetDatum(clause_op_negator),
+                                                                                  CharGetDatum(AMOP_SEARCH),
                                                                                   ObjectIdGetDatum(opfamily_id));
                        if (HeapTupleIsValid(clause_tuple))
                        {
index f0c2cd0..1c17be8 100644 (file)
@@ -295,7 +295,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
                                ctext_expr_list ctext_row def_list indirection opt_indirection
                                reloption_list group_clause TriggerFuncArgs select_limit
                                opt_select_limit opclass_item_list opclass_drop_list
-                               opt_opfamily transaction_mode_list_or_empty
+                               opclass_purpose opt_opfamily transaction_mode_list_or_empty
                                OptTableFuncElementList TableFuncElementList opt_type_modifiers
                                prep_type_clause
                                execute_param_clause using_clause returning_clause
@@ -3935,22 +3935,25 @@ opclass_item_list:
                ;
 
 opclass_item:
-                       OPERATOR Iconst any_operator opt_recheck
+                       OPERATOR Iconst any_operator opclass_purpose opt_recheck
                                {
                                        CreateOpClassItem *n = makeNode(CreateOpClassItem);
                                        n->itemtype = OPCLASS_ITEM_OPERATOR;
                                        n->name = $3;
                                        n->args = NIL;
                                        n->number = $2;
+                                       n->order_family = $4;
                                        $$ = (Node *) n;
                                }
-                       | OPERATOR Iconst any_operator oper_argtypes opt_recheck
+                       | OPERATOR Iconst any_operator oper_argtypes opclass_purpose
+                         opt_recheck
                                {
                                        CreateOpClassItem *n = makeNode(CreateOpClassItem);
                                        n->itemtype = OPCLASS_ITEM_OPERATOR;
                                        n->name = $3;
                                        n->args = $4;
                                        n->number = $2;
+                                       n->order_family = $5;
                                        $$ = (Node *) n;
                                }
                        | FUNCTION Iconst func_name func_args
@@ -3989,6 +3992,11 @@ opt_opfamily:    FAMILY any_name                         { $$ = $2; }
                        | /*EMPTY*/                                             { $$ = NIL; }
                ;
 
+opclass_purpose: FOR SEARCH                                    { $$ = NIL; }
+                       | FOR ORDER BY any_name                 { $$ = $4; }
+                       | /*EMPTY*/                                             { $$ = NIL; }
+               ;
+
 opt_recheck:   RECHECK
                                {
                                        /*
index df765e9..9beae0d 100644 (file)
@@ -46,12 +46,15 @@ get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
  * op_in_opfamily
  *
  *             Return t iff operator 'opno' is in operator family 'opfamily'.
+ *
+ * This function only considers search operators, not ordering operators.
  */
 bool
 op_in_opfamily(Oid opno, Oid opfamily)
 {
-       return SearchSysCacheExists2(AMOPOPID,
+       return SearchSysCacheExists3(AMOPOPID,
                                                                 ObjectIdGetDatum(opno),
+                                                                CharGetDatum(AMOP_SEARCH),
                                                                 ObjectIdGetDatum(opfamily));
 }
 
@@ -60,6 +63,8 @@ op_in_opfamily(Oid opno, Oid opfamily)
  *
  *             Get the operator's strategy number within the specified opfamily,
  *             or 0 if it's not a member of the opfamily.
+ *
+ * This function only considers search operators, not ordering operators.
  */
 int
 get_op_opfamily_strategy(Oid opno, Oid opfamily)
@@ -68,8 +73,9 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
        Form_pg_amop amop_tup;
        int                     result;
 
-       tp = SearchSysCache2(AMOPOPID,
+       tp = SearchSysCache3(AMOPOPID,
                                                 ObjectIdGetDatum(opno),
+                                                CharGetDatum(AMOP_SEARCH),
                                                 ObjectIdGetDatum(opfamily));
        if (!HeapTupleIsValid(tp))
                return 0;
@@ -85,6 +91,8 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
  *             Get the operator's strategy number and declared input data types
  *             within the specified opfamily.
  *
+ * This function only considers search operators, not ordering operators.
+ *
  * Caller should already have verified that opno is a member of opfamily,
  * therefore we raise an error if the tuple is not found.
  */
@@ -97,8 +105,9 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
        HeapTuple       tp;
        Form_pg_amop amop_tup;
 
-       tp = SearchSysCache2(AMOPOPID,
+       tp = SearchSysCache3(AMOPOPID,
                                                 ObjectIdGetDatum(opno),
+                                                CharGetDatum(AMOP_SEARCH),
                                                 ObjectIdGetDatum(opfamily));
        if (!HeapTupleIsValid(tp))
                elog(ERROR, "operator %u is not a member of opfamily %u",
index 94bef7d..08a1443 100644 (file)
@@ -135,11 +135,11 @@ static const struct cachedesc cacheinfo[] = {
        },
        {AccessMethodOperatorRelationId,        /* AMOPOPID */
                AccessMethodOperatorIndexId,
-               2,
+               3,
                {
                        Anum_pg_amop_amopopr,
+                       Anum_pg_amop_amoppurpose,
                        Anum_pg_amop_amopfamily,
-                       0,
                        0
                },
                64
index 3bca417..66274b4 100644 (file)
@@ -8815,22 +8815,28 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        int                     i_opckeytype;
        int                     i_opcdefault;
        int                     i_opcfamily;
+       int                     i_opcfamilyname;
        int                     i_opcfamilynsp;
        int                     i_amname;
        int                     i_amopstrategy;
        int                     i_amopreqcheck;
        int                     i_amopopr;
+       int                     i_sortfamily;
+       int                     i_sortfamilynsp;
        int                     i_amprocnum;
        int                     i_amproc;
        char       *opcintype;
        char       *opckeytype;
        char       *opcdefault;
        char       *opcfamily;
+       char       *opcfamilyname;
        char       *opcfamilynsp;
        char       *amname;
        char       *amopstrategy;
        char       *amopreqcheck;
        char       *amopopr;
+       char       *sortfamily;
+       char       *sortfamilynsp;
        char       *amprocnum;
        char       *amproc;
        bool            needComma;
@@ -8860,8 +8866,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        {
                appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
                                                  "opckeytype::pg_catalog.regtype, "
-                                                 "opcdefault, "
-                                                 "opfname AS opcfamily, "
+                                                 "opcdefault, opcfamily, "
+                                                 "opfname AS opcfamilyname, "
                                                  "nspname AS opcfamilynsp, "
                                                  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
                                                  "FROM pg_catalog.pg_opclass c "
@@ -8874,8 +8880,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        {
                appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
                                                  "opckeytype::pg_catalog.regtype, "
-                                                 "opcdefault, "
-                                                 "NULL AS opcfamily, "
+                                                 "opcdefault, NULL AS opcfamily, "
+                                                 "NULL AS opcfamilyname, "
                                                  "NULL AS opcfamilynsp, "
                "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
                                                  "FROM pg_catalog.pg_opclass "
@@ -8901,13 +8907,16 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        i_opckeytype = PQfnumber(res, "opckeytype");
        i_opcdefault = PQfnumber(res, "opcdefault");
        i_opcfamily = PQfnumber(res, "opcfamily");
+       i_opcfamilyname = PQfnumber(res, "opcfamilyname");
        i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
        i_amname = PQfnumber(res, "amname");
 
        opcintype = PQgetvalue(res, 0, i_opcintype);
        opckeytype = PQgetvalue(res, 0, i_opckeytype);
        opcdefault = PQgetvalue(res, 0, i_opcdefault);
-       opcfamily = PQgetvalue(res, 0, i_opcfamily);
+       /* opcfamily will still be needed after we PQclear res */
+       opcfamily = strdup(PQgetvalue(res, 0, i_opcfamily));
+       opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
        opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
        /* amname will still be needed after we PQclear res */
        amname = strdup(PQgetvalue(res, 0, i_amname));
@@ -8930,14 +8939,14 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        appendPQExpBuffer(q, "FOR TYPE %s USING %s",
                                          opcintype,
                                          fmtId(amname));
-       if (strlen(opcfamily) > 0 &&
-               (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
+       if (strlen(opcfamilyname) > 0 &&
+               (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
                 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
        {
                appendPQExpBuffer(q, " FAMILY ");
                if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
                        appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
-               appendPQExpBuffer(q, "%s", fmtId(opcfamily));
+               appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
        }
        appendPQExpBuffer(q, " AS\n    ");
 
@@ -8954,23 +8963,41 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 
        /*
         * Now fetch and print the OPERATOR entries (pg_amop rows).
+        *
+        * Print only those opfamily members that are tied to the opclass by
+        * pg_depend entries.
+        *
+        * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
+        * an older server's opclass in which it is used.  This is to avoid
+        * hard-to-detect breakage if a newer pg_dump is used to dump from an
+        * older server and then reload into that old version.  This can go
+        * away once 8.3 is so old as to not be of interest to anyone.
         */
        resetPQExpBuffer(query);
 
-       if (g_fout->remoteVersion >= 80400)
+       if (g_fout->remoteVersion >= 90100)
+       {
+               appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "opfname AS sortfamily, "
+                                                 "nspname AS sortfamilynsp "
+                                                 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
+                                                 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
+                                                 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
+                                                 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
+                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+                                                 "AND refobjid = '%u'::pg_catalog.oid "
+                                                 "AND amopfamily = '%s'::pg_catalog.oid "
+                                                 "ORDER BY amopstrategy",
+                                                 opcinfo->dobj.catId.oid,
+                                                 opcfamily);
+       }
+       else if (g_fout->remoteVersion >= 80400)
        {
-               /*
-                * Print only those opfamily members that are tied to the opclass by
-                * pg_depend entries.
-                *
-                * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
-                * an older server's opclass in which it is used.  This is to avoid
-                * hard-to-detect breakage if a newer pg_dump is used to dump from an
-                * older server and then reload into that old version.  This can go
-                * away once 8.3 is so old as to not be of interest to anyone.
-                */
                appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
-                                                 "amopopr::pg_catalog.regoperator "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "NULL AS sortfamily, "
+                                                 "NULL AS sortfamilynsp "
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
                                                  "AND refobjid = '%u'::pg_catalog.oid "
@@ -8981,12 +9008,10 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        }
        else 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 "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "NULL AS sortfamily, "
+                                                 "NULL AS sortfamilynsp "
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
                                                  "AND refobjid = '%u'::pg_catalog.oid "
@@ -8997,8 +9022,14 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        }
        else
        {
+               /*
+                * Here, we print all entries since there are no opfamilies and
+                * hence no loose operators to worry about.
+                */
                appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
-                                                 "amopopr::pg_catalog.regoperator "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "NULL AS sortfamily, "
+                                                 "NULL AS sortfamilynsp "
                                                  "FROM pg_catalog.pg_amop "
                                                  "WHERE amopclaid = '%u'::pg_catalog.oid "
                                                  "ORDER BY amopstrategy",
@@ -9013,18 +9044,31 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        i_amopstrategy = PQfnumber(res, "amopstrategy");
        i_amopreqcheck = PQfnumber(res, "amopreqcheck");
        i_amopopr = PQfnumber(res, "amopopr");
+       i_sortfamily = PQfnumber(res, "sortfamily");
+       i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
 
        for (i = 0; i < ntups; i++)
        {
                amopstrategy = PQgetvalue(res, i, i_amopstrategy);
                amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
                amopopr = PQgetvalue(res, i, i_amopopr);
+               sortfamily = PQgetvalue(res, i, i_sortfamily);
+               sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
 
                if (needComma)
                        appendPQExpBuffer(q, " ,\n    ");
 
                appendPQExpBuffer(q, "OPERATOR %s %s",
                                                  amopstrategy, amopopr);
+
+               if (strlen(sortfamily) > 0)
+               {
+                       appendPQExpBuffer(q, " FOR ORDER BY ");
+                       if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
+                               appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
+                       appendPQExpBuffer(q, "%s", fmtId(sortfamily));
+               }
+
                if (strcmp(amopreqcheck, "t") == 0)
                        appendPQExpBuffer(q, " RECHECK");
 
@@ -9035,15 +9079,14 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 
        /*
         * Now fetch and print the FUNCTION entries (pg_amproc rows).
+        *
+        * Print only those opfamily members that are tied to the opclass by
+        * pg_depend entries.
         */
        resetPQExpBuffer(query);
 
        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 "
@@ -9119,6 +9162,9 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 /*
  * dumpOpfamily
  *       write out a single operator family definition
+ *
+ * Note: this also dumps any "loose" operator members that aren't bound to a
+ * specific opclass within the opfamily.
  */
 static void
 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
@@ -9134,6 +9180,8 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
        int                     i_amopstrategy;
        int                     i_amopreqcheck;
        int                     i_amopopr;
+       int                     i_sortfamily;
+       int                     i_sortfamilynsp;
        int                     i_amprocnum;
        int                     i_amproc;
        int                     i_amproclefttype;
@@ -9142,6 +9190,8 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
        char       *amopstrategy;
        char       *amopreqcheck;
        char       *amopopr;
+       char       *sortfamily;
+       char       *sortfamilynsp;
        char       *amprocnum;
        char       *amproc;
        char       *amproclefttype;
@@ -9172,18 +9222,36 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
        /*
         * Fetch only those opfamily members that are tied directly to the
         * opfamily by pg_depend entries.
+        *
+        * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
+        * an older server's opclass in which it is used.  This is to avoid
+        * hard-to-detect breakage if a newer pg_dump is used to dump from an
+        * older server and then reload into that old version.  This can go
+        * away once 8.3 is so old as to not be of interest to anyone.
         */
-       if (g_fout->remoteVersion >= 80400)
+       if (g_fout->remoteVersion >= 90100)
        {
-               /*
-                * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
-                * an older server's opclass in which it is used.  This is to avoid
-                * hard-to-detect breakage if a newer pg_dump is used to dump from an
-                * older server and then reload into that old version.  This can go
-                * away once 8.3 is so old as to not be of interest to anyone.
-                */
                appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
-                                                 "amopopr::pg_catalog.regoperator "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "opfname AS sortfamily, "
+                                                 "nspname AS sortfamilynsp "
+                                                 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
+                                                 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
+                                                 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
+                                                 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
+                                                 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+                                                 "AND refobjid = '%u'::pg_catalog.oid "
+                                                 "AND amopfamily = '%u'::pg_catalog.oid "
+                                                 "ORDER BY amopstrategy",
+                                                 opfinfo->dobj.catId.oid,
+                                                 opfinfo->dobj.catId.oid);
+       }
+       else if (g_fout->remoteVersion >= 80400)
+       {
+               appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "NULL AS sortfamily, "
+                                                 "NULL AS sortfamilynsp "
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
                  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
                                                  "AND refobjid = '%u'::pg_catalog.oid "
@@ -9195,7 +9263,9 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
        else
        {
                appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
-                                                 "amopopr::pg_catalog.regoperator "
+                                                 "amopopr::pg_catalog.regoperator, "
+                                                 "NULL AS sortfamily, "
+                                                 "NULL AS sortfamilynsp "
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
                  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
                                                  "AND refobjid = '%u'::pg_catalog.oid "
@@ -9323,18 +9393,31 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
                i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
                i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
                i_amopopr = PQfnumber(res_ops, "amopopr");
+               i_sortfamily = PQfnumber(res_ops, "sortfamily");
+               i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
 
                for (i = 0; i < ntups; i++)
                {
                        amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
                        amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
                        amopopr = PQgetvalue(res_ops, i, i_amopopr);
+                       sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
+                       sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
 
                        if (needComma)
                                appendPQExpBuffer(q, " ,\n    ");
 
                        appendPQExpBuffer(q, "OPERATOR %s %s",
                                                          amopstrategy, amopopr);
+
+                       if (strlen(sortfamily) > 0)
+                       {
+                               appendPQExpBuffer(q, " FOR ORDER BY ");
+                               if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
+                                       appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
+                               appendPQExpBuffer(q, "%s", fmtId(sortfamily));
+                       }
+
                        if (strcmp(amopreqcheck, "t") == 0)
                                appendPQExpBuffer(q, " RECHECK");
 
index 69f76aa..8698a43 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201011211
+#define CATALOG_VERSION_NO     201011241
 
 #endif
index a3839e1..1542c8d 100644 (file)
@@ -67,7 +67,7 @@ DECLARE_UNIQUE_INDEX(pg_am_oid_index, 2652, on pg_am using btree(oid oid_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_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amopfamily oid_ops));
+DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, on pg_amop using btree(amopopr oid_ops, amoppurpose char_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
index c9b8e2d..5a18dee 100644 (file)
@@ -40,7 +40,8 @@ CATALOG(pg_am,2601)
                                                                 * assignments. */
        int2            amsupport;              /* total number of support functions that this
                                                                 * AM uses */
-       bool            amcanorder;             /* does AM support ordered scan results? */
+       bool            amcanorder;             /* does AM support order by column value? */
+       bool            amcanorderbyop; /* does AM support order by operator result? */
        bool            amcanbackward;  /* does AM support backward scan? */
        bool            amcanunique;    /* does AM support UNIQUE indexes? */
        bool            amcanmulticol;  /* does AM support multi-column indexes? */
@@ -76,49 +77,50 @@ typedef FormData_pg_am *Form_pg_am;
  *             compiler constants for pg_am
  * ----------------
  */
-#define Natts_pg_am                                            26
+#define Natts_pg_am                                            27
 #define Anum_pg_am_amname                              1
 #define Anum_pg_am_amstrategies                        2
 #define Anum_pg_am_amsupport                   3
 #define Anum_pg_am_amcanorder                  4
-#define Anum_pg_am_amcanbackward               5
-#define Anum_pg_am_amcanunique                 6
-#define Anum_pg_am_amcanmulticol               7
-#define Anum_pg_am_amoptionalkey               8
-#define Anum_pg_am_amindexnulls                        9
-#define Anum_pg_am_amsearchnulls               10
-#define Anum_pg_am_amstorage                   11
-#define Anum_pg_am_amclusterable               12
-#define Anum_pg_am_amkeytype                   13
-#define Anum_pg_am_aminsert                            14
-#define Anum_pg_am_ambeginscan                 15
-#define Anum_pg_am_amgettuple                  16
-#define Anum_pg_am_amgetbitmap                 17
-#define Anum_pg_am_amrescan                            18
-#define Anum_pg_am_amendscan                   19
-#define Anum_pg_am_ammarkpos                   20
-#define Anum_pg_am_amrestrpos                  21
-#define Anum_pg_am_ambuild                             22
-#define Anum_pg_am_ambulkdelete                        23
-#define Anum_pg_am_amvacuumcleanup             24
-#define Anum_pg_am_amcostestimate              25
-#define Anum_pg_am_amoptions                   26
+#define Anum_pg_am_amcanorderbyop              5
+#define Anum_pg_am_amcanbackward               6
+#define Anum_pg_am_amcanunique                 7
+#define Anum_pg_am_amcanmulticol               8
+#define Anum_pg_am_amoptionalkey               9
+#define Anum_pg_am_amindexnulls                        10
+#define Anum_pg_am_amsearchnulls               11
+#define Anum_pg_am_amstorage                   12
+#define Anum_pg_am_amclusterable               13
+#define Anum_pg_am_amkeytype                   14
+#define Anum_pg_am_aminsert                            15
+#define Anum_pg_am_ambeginscan                 16
+#define Anum_pg_am_amgettuple                  17
+#define Anum_pg_am_amgetbitmap                 18
+#define Anum_pg_am_amrescan                            19
+#define Anum_pg_am_amendscan                   20
+#define Anum_pg_am_ammarkpos                   21
+#define Anum_pg_am_amrestrpos                  22
+#define Anum_pg_am_ambuild                             23
+#define Anum_pg_am_ambulkdelete                        24
+#define Anum_pg_am_amvacuumcleanup             25
+#define Anum_pg_am_amcostestimate              26
+#define Anum_pg_am_amoptions                   27
 
 /* ----------------
  *             initial contents of pg_am
  * ----------------
  */
 
-DATA(insert OID = 403 (  btree 5 1 t t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
+DATA(insert OID = 403 (  btree 5 1 t t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
 DESCR("b-tree index access method");
 #define BTREE_AM_OID 403
-DATA(insert OID = 405 (  hash  1 1 f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
+DATA(insert OID = 405 (  hash  1 1 f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
 DESCR("hash index access method");
 #define HASH_AM_OID 405
-DATA(insert OID = 783 (  gist  0 7 f f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
+DATA(insert OID = 783 (  gist  0 7 f f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
 DESCR("GiST index access method");
 #define GIST_AM_OID 783
-DATA(insert OID = 2742 (  gin  0 5 f f f t t f f t f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
+DATA(insert OID = 2742 (  gin  0 5 f f f t t f f t f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
 DESCR("GIN index access method");
 #define GIN_AM_OID 2742
 
index a9e70a2..951f9cd 100644 (file)
@@ -5,7 +5,9 @@
  *       along with the relation's initial contents.
  *
  * The amop table identifies the operators associated with each index operator
- * family and operator class (classes are subsets of families).
+ * family and operator class (classes are subsets of families).  An associated
+ * operator can be either a search operator or an ordering operator, as
+ * identified by amoppurpose.
  *
  * The primary key for this table is <amopfamily, amoplefttype, amoprighttype,
  * amopstrategy>.  amoplefttype and amoprighttype are just copies of 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 <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.
+ * We also keep a unique index on <amopopr, amoppurpose, amopfamily>, 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, with the exception that
+ * it's possible to list it for both search and ordering purposes (with
+ * different strategy numbers for the two purposes).
  *
  * amopmethod is a copy of the owning opfamily's opfmethod field.  This is an
  * intentional denormalization of the catalogs to buy lookup speed.
@@ -55,10 +59,16 @@ CATALOG(pg_amop,2602)
        Oid                     amoplefttype;   /* operator's left input data type */
        Oid                     amoprighttype;  /* operator's right input data type */
        int2            amopstrategy;   /* operator strategy number */
+       char            amoppurpose;    /* is operator for 's'earch or 'o'rdering? */
        Oid                     amopopr;                /* the operator's pg_operator OID */
        Oid                     amopmethod;             /* the index access method this entry is for */
+       Oid                     amopsortfamily; /* ordering opfamily OID, or 0 if search op */
 } FormData_pg_amop;
 
+/* allowed values of amoppurpose: */
+#define AMOP_SEARCH            's'             /* operator is for search */
+#define AMOP_ORDER             'o'             /* operator is for ordering */
+
 /* ----------------
  *             Form_pg_amop corresponds to a pointer to a tuple with
  *             the format of pg_amop relation.
@@ -70,13 +80,15 @@ typedef FormData_pg_amop *Form_pg_amop;
  *             compiler constants for pg_amop
  * ----------------
  */
-#define Natts_pg_amop                                  6
+#define Natts_pg_amop                                  8
 #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_amopopr                   5
-#define Anum_pg_amop_amopmethod                        6
+#define Anum_pg_amop_amoppurpose               5
+#define Anum_pg_amop_amopopr                   6
+#define Anum_pg_amop_amopmethod                        7
+#define Anum_pg_amop_amopsortfamily            8
 
 /* ----------------
  *             initial contents of pg_amop
@@ -88,612 +100,612 @@ typedef FormData_pg_amop *Form_pg_amop;
  */
 
 /* default operators int2 */
-DATA(insert (  1976   21 21 1  95      403 ));
-DATA(insert (  1976   21 21 2  522 403 ));
-DATA(insert (  1976   21 21 3  94      403 ));
-DATA(insert (  1976   21 21 4  524 403 ));
-DATA(insert (  1976   21 21 5  520 403 ));
+DATA(insert (  1976   21 21 1 s        95      403 0 ));
+DATA(insert (  1976   21 21 2 s        522 403 0 ));
+DATA(insert (  1976   21 21 3 s        94      403 0 ));
+DATA(insert (  1976   21 21 4 s        524 403 0 ));
+DATA(insert (  1976   21 21 5 s        520 403 0 ));
 /* crosstype operators int24 */
-DATA(insert (  1976   21 23 1  534 403 ));
-DATA(insert (  1976   21 23 2  540 403 ));
-DATA(insert (  1976   21 23 3  532 403 ));
-DATA(insert (  1976   21 23 4  542 403 ));
-DATA(insert (  1976   21 23 5  536 403 ));
+DATA(insert (  1976   21 23 1 s        534 403 0 ));
+DATA(insert (  1976   21 23 2 s        540 403 0 ));
+DATA(insert (  1976   21 23 3 s        532 403 0 ));
+DATA(insert (  1976   21 23 4 s        542 403 0 ));
+DATA(insert (  1976   21 23 5 s        536 403 0 ));
 /* crosstype operators int28 */
-DATA(insert (  1976   21 20 1  1864    403 ));
-DATA(insert (  1976   21 20 2  1866    403 ));
-DATA(insert (  1976   21 20 3  1862    403 ));
-DATA(insert (  1976   21 20 4  1867    403 ));
-DATA(insert (  1976   21 20 5  1865    403 ));
+DATA(insert (  1976   21 20 1 s        1864    403 0 ));
+DATA(insert (  1976   21 20 2 s        1866    403 0 ));
+DATA(insert (  1976   21 20 3 s        1862    403 0 ));
+DATA(insert (  1976   21 20 4 s        1867    403 0 ));
+DATA(insert (  1976   21 20 5 s        1865    403 0 ));
 /* default operators int4 */
-DATA(insert (  1976   23 23 1  97      403 ));
-DATA(insert (  1976   23 23 2  523 403 ));
-DATA(insert (  1976   23 23 3  96      403 ));
-DATA(insert (  1976   23 23 4  525 403 ));
-DATA(insert (  1976   23 23 5  521 403 ));
+DATA(insert (  1976   23 23 1 s        97      403 0 ));
+DATA(insert (  1976   23 23 2 s        523 403 0 ));
+DATA(insert (  1976   23 23 3 s        96      403 0 ));
+DATA(insert (  1976   23 23 4 s        525 403 0 ));
+DATA(insert (  1976   23 23 5 s        521 403 0 ));
 /* crosstype operators int42 */
-DATA(insert (  1976   23 21 1  535 403 ));
-DATA(insert (  1976   23 21 2  541 403 ));
-DATA(insert (  1976   23 21 3  533 403 ));
-DATA(insert (  1976   23 21 4  543 403 ));
-DATA(insert (  1976   23 21 5  537 403 ));
+DATA(insert (  1976   23 21 1 s        535 403 0 ));
+DATA(insert (  1976   23 21 2 s        541 403 0 ));
+DATA(insert (  1976   23 21 3 s        533 403 0 ));
+DATA(insert (  1976   23 21 4 s        543 403 0 ));
+DATA(insert (  1976   23 21 5 s        537 403 0 ));
 /* crosstype operators int48 */
-DATA(insert (  1976   23 20 1  37      403 ));
-DATA(insert (  1976   23 20 2  80      403 ));
-DATA(insert (  1976   23 20 3  15      403 ));
-DATA(insert (  1976   23 20 4  82      403 ));
-DATA(insert (  1976   23 20 5  76      403 ));
+DATA(insert (  1976   23 20 1 s        37      403 0 ));
+DATA(insert (  1976   23 20 2 s        80      403 0 ));
+DATA(insert (  1976   23 20 3 s        15      403 0 ));
+DATA(insert (  1976   23 20 4 s        82      403 0 ));
+DATA(insert (  1976   23 20 5 s        76      403 0 ));
 /* default operators int8 */
-DATA(insert (  1976   20 20 1  412 403 ));
-DATA(insert (  1976   20 20 2  414 403 ));
-DATA(insert (  1976   20 20 3  410 403 ));
-DATA(insert (  1976   20 20 4  415 403 ));
-DATA(insert (  1976   20 20 5  413 403 ));
+DATA(insert (  1976   20 20 1 s        412 403 0 ));
+DATA(insert (  1976   20 20 2 s        414 403 0 ));
+DATA(insert (  1976   20 20 3 s        410 403 0 ));
+DATA(insert (  1976   20 20 4 s        415 403 0 ));
+DATA(insert (  1976   20 20 5 s        413 403 0 ));
 /* crosstype operators int82 */
-DATA(insert (  1976   20 21 1  1870    403 ));
-DATA(insert (  1976   20 21 2  1872    403 ));
-DATA(insert (  1976   20 21 3  1868    403 ));
-DATA(insert (  1976   20 21 4  1873    403 ));
-DATA(insert (  1976   20 21 5  1871    403 ));
+DATA(insert (  1976   20 21 1 s        1870    403 0 ));
+DATA(insert (  1976   20 21 2 s        1872    403 0 ));
+DATA(insert (  1976   20 21 3 s        1868    403 0 ));
+DATA(insert (  1976   20 21 4 s        1873    403 0 ));
+DATA(insert (  1976   20 21 5 s        1871    403 0 ));
 /* crosstype operators int84 */
-DATA(insert (  1976   20 23 1  418 403 ));
-DATA(insert (  1976   20 23 2  420 403 ));
-DATA(insert (  1976   20 23 3  416 403 ));
-DATA(insert (  1976   20 23 4  430 403 ));
-DATA(insert (  1976   20 23 5  419 403 ));
+DATA(insert (  1976   20 23 1 s        418 403 0 ));
+DATA(insert (  1976   20 23 2 s        420 403 0 ));
+DATA(insert (  1976   20 23 3 s        416 403 0 ));
+DATA(insert (  1976   20 23 4 s        430 403 0 ));
+DATA(insert (  1976   20 23 5 s        419 403 0 ));
 
 /*
  *     btree oid_ops
  */
 
-DATA(insert (  1989   26 26 1  609 403 ));
-DATA(insert (  1989   26 26 2  611 403 ));
-DATA(insert (  1989   26 26 3  607 403 ));
-DATA(insert (  1989   26 26 4  612 403 ));
-DATA(insert (  1989   26 26 5  610 403 ));
+DATA(insert (  1989   26 26 1 s        609 403 0 ));
+DATA(insert (  1989   26 26 2 s        611 403 0 ));
+DATA(insert (  1989   26 26 3 s        607 403 0 ));
+DATA(insert (  1989   26 26 4 s        612 403 0 ));
+DATA(insert (  1989   26 26 5 s        610 403 0 ));
 
 /*
  * btree tid_ops
  */
 
-DATA(insert (  2789   27 27 1 2799 403 ));
-DATA(insert (  2789   27 27 2 2801 403 ));
-DATA(insert (  2789   27 27 3 387      403 ));
-DATA(insert (  2789   27 27 4 2802 403 ));
-DATA(insert (  2789   27 27 5 2800 403 ));
+DATA(insert (  2789   27 27 1 s 2799 403 0 ));
+DATA(insert (  2789   27 27 2 s 2801 403 0 ));
+DATA(insert (  2789   27 27 3 s 387  403 0 ));
+DATA(insert (  2789   27 27 4 s 2802 403 0 ));
+DATA(insert (  2789   27 27 5 s 2800 403 0 ));
 
 /*
  *     btree oidvector_ops
  */
 
-DATA(insert (  1991   30 30 1  645 403 ));
-DATA(insert (  1991   30 30 2  647 403 ));
-DATA(insert (  1991   30 30 3  649 403 ));
-DATA(insert (  1991   30 30 4  648 403 ));
-DATA(insert (  1991   30 30 5  646 403 ));
+DATA(insert (  1991   30 30 1 s        645 403 0 ));
+DATA(insert (  1991   30 30 2 s        647 403 0 ));
+DATA(insert (  1991   30 30 3 s        649 403 0 ));
+DATA(insert (  1991   30 30 4 s        648 403 0 ));
+DATA(insert (  1991   30 30 5 s        646 403 0 ));
 
 /*
  *     btree float_ops
  */
 
 /* default operators float4 */
-DATA(insert (  1970   700 700 1        622 403 ));
-DATA(insert (  1970   700 700 2        624 403 ));
-DATA(insert (  1970   700 700 3        620 403 ));
-DATA(insert (  1970   700 700 4        625 403 ));
-DATA(insert (  1970   700 700 5        623 403 ));
+DATA(insert (  1970   700 700 1 s      622 403 0 ));
+DATA(insert (  1970   700 700 2 s      624 403 0 ));
+DATA(insert (  1970   700 700 3 s      620 403 0 ));
+DATA(insert (  1970   700 700 4 s      625 403 0 ));
+DATA(insert (  1970   700 700 5 s      623 403 0 ));
 /* crosstype operators float48 */
-DATA(insert (  1970   700 701 1        1122 403 ));
-DATA(insert (  1970   700 701 2        1124 403 ));
-DATA(insert (  1970   700 701 3        1120 403 ));
-DATA(insert (  1970   700 701 4        1125 403 ));
-DATA(insert (  1970   700 701 5        1123 403 ));
+DATA(insert (  1970   700 701 1 s      1122 403 0 ));
+DATA(insert (  1970   700 701 2 s      1124 403 0 ));
+DATA(insert (  1970   700 701 3 s      1120 403 0 ));
+DATA(insert (  1970   700 701 4 s      1125 403 0 ));
+DATA(insert (  1970   700 701 5 s      1123 403 0 ));
 /* default operators float8 */
-DATA(insert (  1970   701 701 1        672 403 ));
-DATA(insert (  1970   701 701 2        673 403 ));
-DATA(insert (  1970   701 701 3        670 403 ));
-DATA(insert (  1970   701 701 4        675 403 ));
-DATA(insert (  1970   701 701 5        674 403 ));
+DATA(insert (  1970   701 701 1 s      672 403 0 ));
+DATA(insert (  1970   701 701 2 s      673 403 0 ));
+DATA(insert (  1970   701 701 3 s      670 403 0 ));
+DATA(insert (  1970   701 701 4 s      675 403 0 ));
+DATA(insert (  1970   701 701 5 s      674 403 0 ));
 /* crosstype operators float84 */
-DATA(insert (  1970   701 700 1        1132 403 ));
-DATA(insert (  1970   701 700 2        1134 403 ));
-DATA(insert (  1970   701 700 3        1130 403 ));
-DATA(insert (  1970   701 700 4        1135 403 ));
-DATA(insert (  1970   701 700 5        1133 403 ));
+DATA(insert (  1970   701 700 1 s      1132 403 0 ));
+DATA(insert (  1970   701 700 2 s      1134 403 0 ));
+DATA(insert (  1970   701 700 3 s      1130 403 0 ));
+DATA(insert (  1970   701 700 4 s      1135 403 0 ));
+DATA(insert (  1970   701 700 5 s      1133 403 0 ));
 
 /*
  *     btree char_ops
  */
 
-DATA(insert (  429   18 18 1  631      403 ));
-DATA(insert (  429   18 18 2  632      403 ));
-DATA(insert (  429   18 18 3 92        403 ));
-DATA(insert (  429   18 18 4  634      403 ));
-DATA(insert (  429   18 18 5  633      403 ));
+DATA(insert (  429   18 18 1 s  631    403 0 ));
+DATA(insert (  429   18 18 2 s  632    403 0 ));
+DATA(insert (  429   18 18 3 s   92    403 0 ));
+DATA(insert (  429   18 18 4 s  634    403 0 ));
+DATA(insert (  429   18 18 5 s  633    403 0 ));
 
 /*
  *     btree name_ops
  */
 
-DATA(insert (  1986   19 19 1  660 403 ));
-DATA(insert (  1986   19 19 2  661 403 ));
-DATA(insert (  1986   19 19 3  93      403 ));
-DATA(insert (  1986   19 19 4  663 403 ));
-DATA(insert (  1986   19 19 5  662 403 ));
+DATA(insert (  1986   19 19 1 s        660 403 0 ));
+DATA(insert (  1986   19 19 2 s        661 403 0 ));
+DATA(insert (  1986   19 19 3 s        93      403 0 ));
+DATA(insert (  1986   19 19 4 s        663 403 0 ));
+DATA(insert (  1986   19 19 5 s        662 403 0 ));
 
 /*
  *     btree text_ops
  */
 
-DATA(insert (  1994   25 25 1  664 403 ));
-DATA(insert (  1994   25 25 2  665 403 ));
-DATA(insert (  1994   25 25 3  98      403 ));
-DATA(insert (  1994   25 25 4  667 403 ));
-DATA(insert (  1994   25 25 5  666 403 ));
+DATA(insert (  1994   25 25 1 s        664 403 0 ));
+DATA(insert (  1994   25 25 2 s        665 403 0 ));
+DATA(insert (  1994   25 25 3 s        98      403 0 ));
+DATA(insert (  1994   25 25 4 s        667 403 0 ));
+DATA(insert (  1994   25 25 5 s        666 403 0 ));
 
 /*
  *     btree bpchar_ops
  */
 
-DATA(insert (  426   1042 1042 1 1058  403 ));
-DATA(insert (  426   1042 1042 2 1059  403 ));
-DATA(insert (  426   1042 1042 3 1054  403 ));
-DATA(insert (  426   1042 1042 4 1061  403 ));
-DATA(insert (  426   1042 1042 5 1060  403 ));
+DATA(insert (  426   1042 1042 1 s 1058        403 0 ));
+DATA(insert (  426   1042 1042 2 s 1059        403 0 ));
+DATA(insert (  426   1042 1042 3 s 1054        403 0 ));
+DATA(insert (  426   1042 1042 4 s 1061        403 0 ));
+DATA(insert (  426   1042 1042 5 s 1060        403 0 ));
 
 /*
  *     btree bytea_ops
  */
 
-DATA(insert (  428   17 17 1 1957      403 ));
-DATA(insert (  428   17 17 2 1958      403 ));
-DATA(insert (  428   17 17 3 1955      403 ));
-DATA(insert (  428   17 17 4 1960      403 ));
-DATA(insert (  428   17 17 5 1959      403 ));
+DATA(insert (  428   17 17 1 s 1957    403 0 ));
+DATA(insert (  428   17 17 2 s 1958    403 0 ));
+DATA(insert (  428   17 17 3 s 1955    403 0 ));
+DATA(insert (  428   17 17 4 s 1960    403 0 ));
+DATA(insert (  428   17 17 5 s 1959    403 0 ));
 
 /*
  *     btree abstime_ops
  */
 
-DATA(insert (  421   702 702 1  562    403 ));
-DATA(insert (  421   702 702 2  564    403 ));
-DATA(insert (  421   702 702 3  560    403 ));
-DATA(insert (  421   702 702 4  565    403 ));
-DATA(insert (  421   702 702 5  563    403 ));
+DATA(insert (  421   702 702 1 s  562  403 0 ));
+DATA(insert (  421   702 702 2 s  564  403 0 ));
+DATA(insert (  421   702 702 3 s  560  403 0 ));
+DATA(insert (  421   702 702 4 s  565  403 0 ));
+DATA(insert (  421   702 702 5 s  563  403 0 ));
 
 /*
  *     btree datetime_ops
  */
 
 /* default operators date */
-DATA(insert (  434   1082 1082 1 1095  403 ));
-DATA(insert (  434   1082 1082 2 1096  403 ));
-DATA(insert (  434   1082 1082 3 1093  403 ));
-DATA(insert (  434   1082 1082 4 1098  403 ));
-DATA(insert (  434   1082 1082 5 1097  403 ));
+DATA(insert (  434   1082 1082 1 s 1095        403 0 ));
+DATA(insert (  434   1082 1082 2 s 1096        403 0 ));
+DATA(insert (  434   1082 1082 3 s 1093        403 0 ));
+DATA(insert (  434   1082 1082 4 s 1098        403 0 ));
+DATA(insert (  434   1082 1082 5 s 1097        403 0 ));
 /* crosstype operators vs timestamp */
-DATA(insert (  434   1082 1114 1 2345  403 ));
-DATA(insert (  434   1082 1114 2 2346  403 ));
-DATA(insert (  434   1082 1114 3 2347  403 ));
-DATA(insert (  434   1082 1114 4 2348  403 ));
-DATA(insert (  434   1082 1114 5 2349  403 ));
+DATA(insert (  434   1082 1114 1 s 2345        403 0 ));
+DATA(insert (  434   1082 1114 2 s 2346        403 0 ));
+DATA(insert (  434   1082 1114 3 s 2347        403 0 ));
+DATA(insert (  434   1082 1114 4 s 2348        403 0 ));
+DATA(insert (  434   1082 1114 5 s 2349        403 0 ));
 /* crosstype operators vs timestamptz */
-DATA(insert (  434   1082 1184 1 2358  403 ));
-DATA(insert (  434   1082 1184 2 2359  403 ));
-DATA(insert (  434   1082 1184 3 2360  403 ));
-DATA(insert (  434   1082 1184 4 2361  403 ));
-DATA(insert (  434   1082 1184 5 2362  403 ));
+DATA(insert (  434   1082 1184 1 s 2358        403 0 ));
+DATA(insert (  434   1082 1184 2 s 2359        403 0 ));
+DATA(insert (  434   1082 1184 3 s 2360        403 0 ));
+DATA(insert (  434   1082 1184 4 s 2361        403 0 ));
+DATA(insert (  434   1082 1184 5 s 2362        403 0 ));
 /* default operators timestamp */
-DATA(insert (  434   1114 1114 1 2062  403 ));
-DATA(insert (  434   1114 1114 2 2063  403 ));
-DATA(insert (  434   1114 1114 3 2060  403 ));
-DATA(insert (  434   1114 1114 4 2065  403 ));
-DATA(insert (  434   1114 1114 5 2064  403 ));
+DATA(insert (  434   1114 1114 1 s 2062        403 0 ));
+DATA(insert (  434   1114 1114 2 s 2063        403 0 ));
+DATA(insert (  434   1114 1114 3 s 2060        403 0 ));
+DATA(insert (  434   1114 1114 4 s 2065        403 0 ));
+DATA(insert (  434   1114 1114 5 s 2064        403 0 ));
 /* crosstype operators vs date */
-DATA(insert (  434   1114 1082 1 2371  403 ));
-DATA(insert (  434   1114 1082 2 2372  403 ));
-DATA(insert (  434   1114 1082 3 2373  403 ));
-DATA(insert (  434   1114 1082 4 2374  403 ));
-DATA(insert (  434   1114 1082 5 2375  403 ));
+DATA(insert (  434   1114 1082 1 s 2371        403 0 ));
+DATA(insert (  434   1114 1082 2 s 2372        403 0 ));
+DATA(insert (  434   1114 1082 3 s 2373        403 0 ));
+DATA(insert (  434   1114 1082 4 s 2374        403 0 ));
+DATA(insert (  434   1114 1082 5 s 2375        403 0 ));
 /* crosstype operators vs timestamptz */
-DATA(insert (  434   1114 1184 1 2534  403 ));
-DATA(insert (  434   1114 1184 2 2535  403 ));
-DATA(insert (  434   1114 1184 3 2536  403 ));
-DATA(insert (  434   1114 1184 4 2537  403 ));
-DATA(insert (  434   1114 1184 5 2538  403 ));
+DATA(insert (  434   1114 1184 1 s 2534        403 0 ));
+DATA(insert (  434   1114 1184 2 s 2535        403 0 ));
+DATA(insert (  434   1114 1184 3 s 2536        403 0 ));
+DATA(insert (  434   1114 1184 4 s 2537        403 0 ));
+DATA(insert (  434   1114 1184 5 s 2538        403 0 ));
 /* default operators timestamptz */
-DATA(insert (  434   1184 1184 1 1322  403 ));
-DATA(insert (  434   1184 1184 2 1323  403 ));
-DATA(insert (  434   1184 1184 3 1320  403 ));
-DATA(insert (  434   1184 1184 4 1325  403 ));
-DATA(insert (  434   1184 1184 5 1324  403 ));
+DATA(insert (  434   1184 1184 1 s 1322        403 0 ));
+DATA(insert (  434   1184 1184 2 s 1323        403 0 ));
+DATA(insert (  434   1184 1184 3 s 1320        403 0 ));
+DATA(insert (  434   1184 1184 4 s 1325        403 0 ));
+DATA(insert (  434   1184 1184 5 s 1324        403 0 ));
 /* crosstype operators vs date */
-DATA(insert (  434   1184 1082 1 2384  403 ));
-DATA(insert (  434   1184 1082 2 2385  403 ));
-DATA(insert (  434   1184 1082 3 2386  403 ));
-DATA(insert (  434   1184 1082 4 2387  403 ));
-DATA(insert (  434   1184 1082 5 2388  403 ));
+DATA(insert (  434   1184 1082 1 s 2384        403 0 ));
+DATA(insert (  434   1184 1082 2 s 2385        403 0 ));
+DATA(insert (  434   1184 1082 3 s 2386        403 0 ));
+DATA(insert (  434   1184 1082 4 s 2387        403 0 ));
+DATA(insert (  434   1184 1082 5 s 2388        403 0 ));
 /* crosstype operators vs timestamp */
-DATA(insert (  434   1184 1114 1 2540  403 ));
-DATA(insert (  434   1184 1114 2 2541  403 ));
-DATA(insert (  434   1184 1114 3 2542  403 ));
-DATA(insert (  434   1184 1114 4 2543  403 ));
-DATA(insert (  434   1184 1114 5 2544  403 ));
+DATA(insert (  434   1184 1114 1 s 2540        403 0 ));
+DATA(insert (  434   1184 1114 2 s 2541        403 0 ));
+DATA(insert (  434   1184 1114 3 s 2542        403 0 ));
+DATA(insert (  434   1184 1114 4 s 2543        403 0 ));
+DATA(insert (  434   1184 1114 5 s 2544        403 0 ));
 
 /*
  *     btree time_ops
  */
 
-DATA(insert (  1996   1083 1083 1 1110 403 ));
-DATA(insert (  1996   1083 1083 2 1111 403 ));
-DATA(insert (  1996   1083 1083 3 1108 403 ));
-DATA(insert (  1996   1083 1083 4 1113 403 ));
-DATA(insert (  1996   1083 1083 5 1112 403 ));
+DATA(insert (  1996   1083 1083 1 s 1110 403 0 ));
+DATA(insert (  1996   1083 1083 2 s 1111 403 0 ));
+DATA(insert (  1996   1083 1083 3 s 1108 403 0 ));
+DATA(insert (  1996   1083 1083 4 s 1113 403 0 ));
+DATA(insert (  1996   1083 1083 5 s 1112 403 0 ));
 
 /*
  *     btree timetz_ops
  */
 
-DATA(insert (  2000   1266 1266 1 1552 403 ));
-DATA(insert (  2000   1266 1266 2 1553 403 ));
-DATA(insert (  2000   1266 1266 3 1550 403 ));
-DATA(insert (  2000   1266 1266 4 1555 403 ));
-DATA(insert (  2000   1266 1266 5 1554 403 ));
+DATA(insert (  2000   1266 1266 1 s 1552 403 0 ));
+DATA(insert (  2000   1266 1266 2 s 1553 403 0 ));
+DATA(insert (  2000   1266 1266 3 s 1550 403 0 ));
+DATA(insert (  2000   1266 1266 4 s 1555 403 0 ));
+DATA(insert (  2000   1266 1266 5 s 1554 403 0 ));
 
 /*
  *     btree interval_ops
  */
 
-DATA(insert (  1982   1186 1186 1 1332 403 ));
-DATA(insert (  1982   1186 1186 2 1333 403 ));
-DATA(insert (  1982   1186 1186 3 1330 403 ));
-DATA(insert (  1982   1186 1186 4 1335 403 ));
-DATA(insert (  1982   1186 1186 5 1334 403 ));
+DATA(insert (  1982   1186 1186 1 s 1332 403 0 ));
+DATA(insert (  1982   1186 1186 2 s 1333 403 0 ));
+DATA(insert (  1982   1186 1186 3 s 1330 403 0 ));
+DATA(insert (  1982   1186 1186 4 s 1335 403 0 ));
+DATA(insert (  1982   1186 1186 5 s 1334 403 0 ));
 
 /*
  *     btree macaddr
  */
 
-DATA(insert (  1984   829 829 1 1222 403 ));
-DATA(insert (  1984   829 829 2 1223 403 ));
-DATA(insert (  1984   829 829 3 1220 403 ));
-DATA(insert (  1984   829 829 4 1225 403 ));
-DATA(insert (  1984   829 829 5 1224 403 ));
+DATA(insert (  1984   829 829 1 s 1222 403 0 ));
+DATA(insert (  1984   829 829 2 s 1223 403 0 ));
+DATA(insert (  1984   829 829 3 s 1220 403 0 ));
+DATA(insert (  1984   829 829 4 s 1225 403 0 ));
+DATA(insert (  1984   829 829 5 s 1224 403 0 ));
 
 /*
  *     btree network
  */
 
-DATA(insert (  1974   869 869 1 1203 403 ));
-DATA(insert (  1974   869 869 2 1204 403 ));
-DATA(insert (  1974   869 869 3 1201 403 ));
-DATA(insert (  1974   869 869 4 1206 403 ));
-DATA(insert (  1974   869 869 5 1205 403 ));
+DATA(insert (  1974   869 869 1 s 1203 403 0 ));
+DATA(insert (  1974   869 869 2 s 1204 403 0 ));
+DATA(insert (  1974   869 869 3 s 1201 403 0 ));
+DATA(insert (  1974   869 869 4 s 1206 403 0 ));
+DATA(insert (  1974   869 869 5 s 1205 403 0 ));
 
 /*
  *     btree numeric
  */
 
-DATA(insert (  1988   1700 1700 1 1754 403 ));
-DATA(insert (  1988   1700 1700 2 1755 403 ));
-DATA(insert (  1988   1700 1700 3 1752 403 ));
-DATA(insert (  1988   1700 1700 4 1757 403 ));
-DATA(insert (  1988   1700 1700 5 1756 403 ));
+DATA(insert (  1988   1700 1700 1 s 1754 403 0 ));
+DATA(insert (  1988   1700 1700 2 s 1755 403 0 ));
+DATA(insert (  1988   1700 1700 3 s 1752 403 0 ));
+DATA(insert (  1988   1700 1700 4 s 1757 403 0 ));
+DATA(insert (  1988   1700 1700 5 s 1756 403 0 ));
 
 /*
  *     btree bool
  */
 
-DATA(insert (  424   16 16 1 58        403 ));
-DATA(insert (  424   16 16 2 1694      403 ));
-DATA(insert (  424   16 16 3 91        403 ));
-DATA(insert (  424   16 16 4 1695      403 ));
-DATA(insert (  424   16 16 5 59        403 ));
+DATA(insert (  424   16 16 1 s 58              403 0 ));
+DATA(insert (  424   16 16 2 s 1694    403 0 ));
+DATA(insert (  424   16 16 3 s 91              403 0 ));
+DATA(insert (  424   16 16 4 s 1695    403 0 ));
+DATA(insert (  424   16 16 5 s 59              403 0 ));
 
 /*
  *     btree bit
  */
 
-DATA(insert (  423   1560 1560 1 1786  403 ));
-DATA(insert (  423   1560 1560 2 1788  403 ));
-DATA(insert (  423   1560 1560 3 1784  403 ));
-DATA(insert (  423   1560 1560 4 1789  403 ));
-DATA(insert (  423   1560 1560 5 1787  403 ));
+DATA(insert (  423   1560 1560 1 s 1786        403 0 ));
+DATA(insert (  423   1560 1560 2 s 1788        403 0 ));
+DATA(insert (  423   1560 1560 3 s 1784        403 0 ));
+DATA(insert (  423   1560 1560 4 s 1789        403 0 ));
+DATA(insert (  423   1560 1560 5 s 1787        403 0 ));
 
 /*
  *     btree varbit
  */
 
-DATA(insert (  2002   1562 1562 1 1806 403 ));
-DATA(insert (  2002   1562 1562 2 1808 403 ));
-DATA(insert (  2002   1562 1562 3 1804 403 ));
-DATA(insert (  2002   1562 1562 4 1809 403 ));
-DATA(insert (  2002   1562 1562 5 1807 403 ));
+DATA(insert (  2002   1562 1562 1 s 1806 403 0 ));
+DATA(insert (  2002   1562 1562 2 s 1808 403 0 ));
+DATA(insert (  2002   1562 1562 3 s 1804 403 0 ));
+DATA(insert (  2002   1562 1562 4 s 1809 403 0 ));
+DATA(insert (  2002   1562 1562 5 s 1807 403 0 ));
 
 /*
  *     btree text pattern
  */
 
-DATA(insert (  2095   25 25 1 2314 403 ));
-DATA(insert (  2095   25 25 2 2315 403 ));
-DATA(insert (  2095   25 25 3 98       403 ));
-DATA(insert (  2095   25 25 4 2317 403 ));
-DATA(insert (  2095   25 25 5 2318 403 ));
+DATA(insert (  2095   25 25 1 s 2314 403 0 ));
+DATA(insert (  2095   25 25 2 s 2315 403 0 ));
+DATA(insert (  2095   25 25 3 s 98   403 0 ));
+DATA(insert (  2095   25 25 4 s 2317 403 0 ));
+DATA(insert (  2095   25 25 5 s 2318 403 0 ));
 
 /*
  *     btree bpchar pattern
  */
 
-DATA(insert (  2097   1042 1042 1 2326 403 ));
-DATA(insert (  2097   1042 1042 2 2327 403 ));
-DATA(insert (  2097   1042 1042 3 1054 403 ));
-DATA(insert (  2097   1042 1042 4 2329 403 ));
-DATA(insert (  2097   1042 1042 5 2330 403 ));
+DATA(insert (  2097   1042 1042 1 s 2326 403 0 ));
+DATA(insert (  2097   1042 1042 2 s 2327 403 0 ));
+DATA(insert (  2097   1042 1042 3 s 1054 403 0 ));
+DATA(insert (  2097   1042 1042 4 s 2329 403 0 ));
+DATA(insert (  2097   1042 1042 5 s 2330 403 0 ));
 
 /*
  *     btree money_ops
  */
 
-DATA(insert (  2099   790 790 1        902 403 ));
-DATA(insert (  2099   790 790 2        904 403 ));
-DATA(insert (  2099   790 790 3        900 403 ));
-DATA(insert (  2099   790 790 4        905 403 ));
-DATA(insert (  2099   790 790 5        903 403 ));
+DATA(insert (  2099   790 790 1 s      902 403 0 ));
+DATA(insert (  2099   790 790 2 s      904 403 0 ));
+DATA(insert (  2099   790 790 3 s      900 403 0 ));
+DATA(insert (  2099   790 790 4 s      905 403 0 ));
+DATA(insert (  2099   790 790 5 s      903 403 0 ));
 
 /*
  *     btree reltime_ops
  */
 
-DATA(insert (  2233   703 703 1        568 403 ));
-DATA(insert (  2233   703 703 2        570 403 ));
-DATA(insert (  2233   703 703 3        566 403 ));
-DATA(insert (  2233   703 703 4        571 403 ));
-DATA(insert (  2233   703 703 5        569 403 ));
+DATA(insert (  2233   703 703 1 s      568 403 0 ));
+DATA(insert (  2233   703 703 2 s      570 403 0 ));
+DATA(insert (  2233   703 703 3 s      566 403 0 ));
+DATA(insert (  2233   703 703 4 s      571 403 0 ));
+DATA(insert (  2233   703 703 5 s      569 403 0 ));
 
 /*
  *     btree tinterval_ops
  */
 
-DATA(insert (  2234   704 704 1        813 403 ));
-DATA(insert (  2234   704 704 2        815 403 ));
-DATA(insert (  2234   704 704 3        811 403 ));
-DATA(insert (  2234   704 704 4        816 403 ));
-DATA(insert (  2234   704 704 5        814 403 ));
+DATA(insert (  2234   704 704 1 s      813 403 0 ));
+DATA(insert (  2234   704 704 2 s      815 403 0 ));
+DATA(insert (  2234   704 704 3 s      811 403 0 ));
+DATA(insert (  2234   704 704 4 s      816 403 0 ));
+DATA(insert (  2234   704 704 5 s      814 403 0 ));
 
 /*
  *     btree array_ops
  */
 
-DATA(insert (  397   2277 2277 1 1072  403 ));
-DATA(insert (  397   2277 2277 2 1074  403 ));
-DATA(insert (  397   2277 2277 3 1070  403 ));
-DATA(insert (  397   2277 2277 4 1075  403 ));
-DATA(insert (  397   2277 2277 5 1073  403 ));
+DATA(insert (  397   2277 2277 1 s 1072        403 0 ));
+DATA(insert (  397   2277 2277 2 s 1074        403 0 ));
+DATA(insert (  397   2277 2277 3 s 1070        403 0 ));
+DATA(insert (  397   2277 2277 4 s 1075        403 0 ));
+DATA(insert (  397   2277 2277 5 s 1073        403 0 ));
 
 /*
  *     btree record_ops
  */
 
-DATA(insert (  2994  2249 2249 1 2990  403 ));
-DATA(insert (  2994  2249 2249 2 2992  403 ));
-DATA(insert (  2994  2249 2249 3 2988  403 ));
-DATA(insert (  2994  2249 2249 4 2993  403 ));
-DATA(insert (  2994  2249 2249 5 2991  403 ));
+DATA(insert (  2994  2249 2249 1 s 2990        403 0 ));
+DATA(insert (  2994  2249 2249 2 s 2992        403 0 ));
+DATA(insert (  2994  2249 2249 3 s 2988        403 0 ));
+DATA(insert (  2994  2249 2249 4 s 2993        403 0 ));
+DATA(insert (  2994  2249 2249 5 s 2991        403 0 ));
 
 /*
  * btree uuid_ops
  */
 
-DATA(insert (  2968  2950 2950 1 2974  403 ));
-DATA(insert (  2968  2950 2950 2 2976  403 ));
-DATA(insert (  2968  2950 2950 3 2972  403 ));
-DATA(insert (  2968  2950 2950 4 2977  403 ));
-DATA(insert (  2968  2950 2950 5 2975  403 ));
+DATA(insert (  2968  2950 2950 1 s 2974        403 0 ));
+DATA(insert (  2968  2950 2950 2 s 2976        403 0 ));
+DATA(insert (  2968  2950 2950 3 s 2972        403 0 ));
+DATA(insert (  2968  2950 2950 4 s 2977        403 0 ));
+DATA(insert (  2968  2950 2950 5 s 2975        403 0 ));
 
 /*
  *     hash index _ops
  */
 
 /* bpchar_ops */
-DATA(insert (  427   1042 1042 1 1054  405 ));
+DATA(insert (  427   1042 1042 1 s 1054        405 0 ));
 /* char_ops */
-DATA(insert (  431   18 18 1 92        405 ));
+DATA(insert (  431   18 18 1 s 92      405 0 ));
 /* date_ops */
-DATA(insert (  435   1082 1082 1 1093  405 ));
+DATA(insert (  435   1082 1082 1 s 1093        405 0 ));
 /* float_ops */
-DATA(insert (  1971   700 700 1        620 405 ));
-DATA(insert (  1971   701 701 1        670 405 ));
-DATA(insert (  1971   700 701 1 1120 405 ));
-DATA(insert (  1971   701 700 1 1130 405 ));
+DATA(insert (  1971   700 700 1 s      620 405 0 ));
+DATA(insert (  1971   701 701 1 s      670 405 0 ));
+DATA(insert (  1971   700 701 1 s 1120 405 0 ));
+DATA(insert (  1971   701 700 1 s 1130 405 0 ));
 /* network_ops */
-DATA(insert (  1975   869 869 1 1201 405 ));
+DATA(insert (  1975   869 869 1 s 1201 405 0 ));
 /* integer_ops */
-DATA(insert (  1977   21 21 1  94      405 ));
-DATA(insert (  1977   23 23 1  96      405 ));
-DATA(insert (  1977   20 20 1  410 405 ));
-DATA(insert (  1977   21 23 1  532 405 ));
-DATA(insert (  1977   21 20 1   1862 405 ));
-DATA(insert (  1977   23 21 1  533 405 ));
-DATA(insert (  1977   23 20 1  15      405 ));
-DATA(insert (  1977   20 21 1   1868 405 ));
-DATA(insert (  1977   20 23 1  416 405 ));
+DATA(insert (  1977   21 21 1 s        94       405 0 ));
+DATA(insert (  1977   23 23 1 s        96       405 0 ));
+DATA(insert (  1977   20 20 1 s        410  405 0 ));
+DATA(insert (  1977   21 23 1 s        532  405 0 ));
+DATA(insert (  1977   21 20 1 s        1862 405 0 ));
+DATA(insert (  1977   23 21 1 s        533  405 0 ));
+DATA(insert (  1977   23 20 1 s        15       405 0 ));
+DATA(insert (  1977   20 21 1 s        1868 405 0 ));
+DATA(insert (  1977   20 23 1 s        416  405 0 ));
 /* interval_ops */
-DATA(insert (  1983   1186 1186 1 1330 405 ));
+DATA(insert (  1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
-DATA(insert (  1985   829 829 1 1220 405 ));
+DATA(insert (  1985   829 829 1 s 1220 405 0 ));
 /* name_ops */
-DATA(insert (  1987   19 19 1  93      405 ));
+DATA(insert (  1987   19 19 1 s        93      405 0 ));
 /* oid_ops */
-DATA(insert (  1990   26 26 1  607 405 ));
+DATA(insert (  1990   26 26 1 s        607 405 0 ));
 /* oidvector_ops */
-DATA(insert (  1992   30 30 1  649 405 ));
+DATA(insert (  1992   30 30 1 s        649 405 0 ));
 /* text_ops */
-DATA(insert (  1995   25 25 1  98      405 ));
+DATA(insert (  1995   25 25 1 s        98      405 0 ));
 /* time_ops */
-DATA(insert (  1997   1083 1083 1 1108 405 ));
+DATA(insert (  1997   1083 1083 1 s 1108 405 0 ));
 /* timestamptz_ops */
-DATA(insert (  1999   1184 1184 1 1320 405 ));
+DATA(insert (  1999   1184 1184 1 s 1320 405 0 ));
 /* timetz_ops */
-DATA(insert (  2001   1266 1266 1 1550 405 ));
+DATA(insert (  2001   1266 1266 1 s 1550 405 0 ));
 /* timestamp_ops */
-DATA(insert (  2040   1114 1114 1 2060 405 ));
+DATA(insert (  2040   1114 1114 1 s 2060 405 0 ));
 /* bool_ops */
-DATA(insert (  2222   16 16 1  91      405 ));
+DATA(insert (  2222   16 16 1 s   91 405 0 ));
 /* bytea_ops */
-DATA(insert (  2223   17 17 1 1955 405 ));
+DATA(insert (  2223   17 17 1 s 1955 405 0 ));
 /* int2vector_ops */
-DATA(insert (  2224   22 22 1  386 405 ));
+DATA(insert (  2224   22 22 1 s        386 405 0 ));
 /* xid_ops */
-DATA(insert (  2225   28 28 1  352 405 ));
+DATA(insert (  2225   28 28 1 s        352 405 0 ));
 /* cid_ops */
-DATA(insert (  2226   29 29 1  385 405 ));
+DATA(insert (  2226   29 29 1 s        385 405 0 ));
 /* abstime_ops */
-DATA(insert (  2227   702 702 1        560 405 ));
+DATA(insert (  2227   702 702 1 s      560 405 0 ));
 /* reltime_ops */
-DATA(insert (  2228   703 703 1        566 405 ));
+DATA(insert (  2228   703 703 1 s      566 405 0 ));
 /* text_pattern_ops */
-DATA(insert (  2229   25 25 1 98       405 ));
+DATA(insert (  2229   25 25 1 s        98      405 0 ));
 /* bpchar_pattern_ops */
-DATA(insert (  2231   1042 1042 1 1054 405 ));
+DATA(insert (  2231   1042 1042 1 s 1054 405 0 ));
 /* aclitem_ops */
-DATA(insert (  2235   1033 1033 1      974 405 ));
+DATA(insert (  2235   1033 1033 1 s  974 405 0 ));
 /* uuid_ops */
-DATA(insert (  2969   2950 2950 1 2972 405 ));
+DATA(insert (  2969   2950 2950 1 s 2972 405 0 ));
 /* numeric_ops */
-DATA(insert (  1998   1700 1700 1 1752 405 ));
+DATA(insert (  1998   1700 1700 1 s 1752 405 0 ));
 /* array_ops */
-DATA(insert (  627    2277 2277 1 1070 405 ));
+DATA(insert (  627    2277 2277 1 s 1070 405 0 ));
 
 
 /*
  *     gist box_ops
  */
 
-DATA(insert (  2593   603 603 1  493 783 ));
-DATA(insert (  2593   603 603 2  494 783 ));
-DATA(insert (  2593   603 603 3  500 783 ));
-DATA(insert (  2593   603 603 4  495 783 ));
-DATA(insert (  2593   603 603 5  496 783 ));
-DATA(insert (  2593   603 603 6  499 783 ));
-DATA(insert (  2593   603 603 7  498 783 ));
-DATA(insert (  2593   603 603 8  497 783 ));
-DATA(insert (  2593   603 603 9  2571  783 ));
-DATA(insert (  2593   603 603 10 2570  783 ));
-DATA(insert (  2593   603 603 11 2573  783 ));
-DATA(insert (  2593   603 603 12 2572  783 ));
-DATA(insert (  2593   603 603 13 2863  783 ));
-DATA(insert (  2593   603 603 14 2862  783 ));
+DATA(insert (  2593   603 603 1 s  493 783 0 ));
+DATA(insert (  2593   603 603 2 s  494 783 0 ));
+DATA(insert (  2593   603 603 3 s  500 783 0 ));
+DATA(insert (  2593   603 603 4 s  495 783 0 ));
+DATA(insert (  2593   603 603 5 s  496 783 0 ));
+DATA(insert (  2593   603 603 6 s  499 783 0 ));
+DATA(insert (  2593   603 603 7 s  498 783 0 ));
+DATA(insert (  2593   603 603 8 s  497 783 0 ));
+DATA(insert (  2593   603 603 9 s  2571 783 0 ));
+DATA(insert (  2593   603 603 10 s 2570 783 0 ));
+DATA(insert (  2593   603 603 11 s 2573 783 0 ));
+DATA(insert (  2593   603 603 12 s 2572 783 0 ));
+DATA(insert (  2593   603 603 13 s 2863 783 0 ));
+DATA(insert (  2593   603 603 14 s 2862 783 0 ));
 
 /*
  * gist point_ops
  */
-DATA(insert (  1029   600 600 11 506 783 ));
-DATA(insert (  1029   600 600 1  507 783 ));
-DATA(insert (  1029   600 600 5  508 783 ));
-DATA(insert (  1029   600 600 10 509 783 ));
-DATA(insert (  1029   600 600 6  510 783 ));
-DATA(insert (  1029   603 600 27  433 783 ));
-DATA(insert (  1029   600 603 28  511 783 ));
-DATA(insert (  1029   604 600 47 757 783 ));
-DATA(insert (  1029   600 604 48 756 783 ));
-DATA(insert (  1029   718 600 67 759 783 ));
-DATA(insert (  1029   600 718 68 758 783 ));
+DATA(insert (  1029   600 600 11 s 506 783 0 ));
+DATA(insert (  1029   600 600 1 s  507 783 0 ));
+DATA(insert (  1029   600 600 5 s  508 783 0 ));
+DATA(insert (  1029   600 600 10 s 509 783 0 ));
+DATA(insert (  1029   600 600 6 s  510 783 0 ));
+DATA(insert (  1029   603 600 27 s 433 783 0 ));
+DATA(insert (  1029   600 603 28 s 511 783 0 ));
+DATA(insert (  1029   604 600 47 s 757 783 0 ));
+DATA(insert (  1029   600 604 48 s 756 783 0 ));
+DATA(insert (  1029   718 600 67 s 759 783 0 ));
+DATA(insert (  1029   600 718 68 s 758 783 0 ));
 
 
 /*
  *     gist poly_ops (supports polygons)
  */
 
-DATA(insert (  2594   604 604 1  485 783 ));
-DATA(insert (  2594   604 604 2  486 783 ));
-DATA(insert (  2594   604 604 3  492 783 ));
-DATA(insert (  2594   604 604 4  487 783 ));
-DATA(insert (  2594   604 604 5  488 783 ));
-DATA(insert (  2594   604 604 6  491 783 ));
-DATA(insert (  2594   604 604 7  490 783 ));
-DATA(insert (  2594   604 604 8  489 783 ));
-DATA(insert (  2594   604 604 9  2575  783 ));
-DATA(insert (  2594   604 604 10 2574  783 ));
-DATA(insert (  2594   604 604 11 2577  783 ));
-DATA(insert (  2594   604 604 12 2576  783 ));
-DATA(insert (  2594   604 604 13 2861  783 ));
-DATA(insert (  2594   604 604 14 2860  783 ));
+DATA(insert (  2594   604 604 1 s  485 783 0 ));
+DATA(insert (  2594   604 604 2 s  486 783 0 ));
+DATA(insert (  2594   604 604 3 s  492 783 0 ));
+DATA(insert (  2594   604 604 4 s  487 783 0 ));
+DATA(insert (  2594   604 604 5 s  488 783 0 ));
+DATA(insert (  2594   604 604 6 s  491 783 0 ));
+DATA(insert (  2594   604 604 7 s  490 783 0 ));
+DATA(insert (  2594   604 604 8 s  489 783 0 ));
+DATA(insert (  2594   604 604 9 s  2575 783 0 ));
+DATA(insert (  2594   604 604 10 s 2574 783 0 ));
+DATA(insert (  2594   604 604 11 s 2577 783 0 ));
+DATA(insert (  2594   604 604 12 s 2576 783 0 ));
+DATA(insert (  2594   604 604 13 s 2861 783 0 ));
+DATA(insert (  2594   604 604 14 s 2860 783 0 ));
 
 /*
  *     gist circle_ops
  */
 
-DATA(insert (  2595   718 718 1  1506  783 ));
-DATA(insert (  2595   718 718 2  1507  783 ));
-DATA(insert (  2595   718 718 3  1513  783 ));
-DATA(insert (  2595   718 718 4  1508  783 ));
-DATA(insert (  2595   718 718 5  1509  783 ));
-DATA(insert (  2595   718 718 6  1512  783 ));
-DATA(insert (  2595   718 718 7  1511  783 ));
-DATA(insert (  2595   718 718 8  1510  783 ));
-DATA(insert (  2595   718 718 9  2589  783 ));
-DATA(insert (  2595   718 718 10 1515  783 ));
-DATA(insert (  2595   718 718 11 1514  783 ));
-DATA(insert (  2595   718 718 12 2590  783 ));
-DATA(insert (  2595   718 718 13 2865  783 ));
-DATA(insert (  2595   718 718 14 2864  783 ));
+DATA(insert (  2595   718 718 1 s  1506 783 0 ));
+DATA(insert (  2595   718 718 2 s  1507 783 0 ));
+DATA(insert (  2595   718 718 3 s  1513 783 0 ));
+DATA(insert (  2595   718 718 4 s  1508 783 0 ));
+DATA(insert (  2595   718 718 5 s  1509 783 0 ));
+DATA(insert (  2595   718 718 6 s  1512 783 0 ));
+DATA(insert (  2595   718 718 7 s  1511 783 0 ));
+DATA(insert (  2595   718 718 8 s  1510 783 0 ));
+DATA(insert (  2595   718 718 9 s  2589 783 0 ));
+DATA(insert (  2595   718 718 10 s 1515 783 0 ));
+DATA(insert (  2595   718 718 11 s 1514 783 0 ));
+DATA(insert (  2595   718 718 12 s 2590 783 0 ));
+DATA(insert (  2595   718 718 13 s 2865 783 0 ));
+DATA(insert (  2595   718 718 14 s 2864 783 0 ));
 
 /*
  * gin array_ops (these anyarray operators are used with all the opclasses
  * of the family)
  */
-DATA(insert (  2745   2277 2277 1      2750    2742 ));
-DATA(insert (  2745   2277 2277 2      2751    2742 ));
-DATA(insert (  2745   2277 2277 3      2752    2742 ));
-DATA(insert (  2745   2277 2277 4      1070    2742 ));
+DATA(insert (  2745   2277 2277 1 s 2750 2742 0 ));
+DATA(insert (  2745   2277 2277 2 s 2751 2742 0 ));
+DATA(insert (  2745   2277 2277 3 s 2752 2742 0 ));
+DATA(insert (  2745   2277 2277 4 s 1070 2742 0 ));
 
 /*
  * btree enum_ops
  */
-DATA(insert (  3522   3500 3500 1      3518    403 ));
-DATA(insert (  3522   3500 3500 2      3520    403 ));
-DATA(insert (  3522   3500 3500 3      3516    403 ));
-DATA(insert (  3522   3500 3500 4      3521    403 ));
-DATA(insert (  3522   3500 3500 5      3519    403 ));
+DATA(insert (  3522   3500 3500 1 s 3518 403 0 ));
+DATA(insert (  3522   3500 3500 2 s 3520 403 0 ));
+DATA(insert (  3522   3500 3500 3 s 3516 403 0 ));
+DATA(insert (  3522   3500 3500 4 s 3521 403 0 ));
+DATA(insert (  3522   3500 3500 5 s 3519 403 0 ));
 
 /*
  * hash enum_ops
  */
-DATA(insert (  3523   3500 3500 1      3516    405 ));
+DATA(insert (  3523   3500 3500 1 s 3516 405 0 ));
 
 /*
  * btree tsvector_ops
  */
-DATA(insert (  3626   3614 3614 1       3627 403 ));
-DATA(insert (  3626   3614 3614 2       3628 403 ));
-DATA(insert (  3626   3614 3614 3       3629 403 ));
-DATA(insert (  3626   3614 3614 4       3631 403 ));
-DATA(insert (  3626   3614 3614 5       3632 403 ));
+DATA(insert (  3626   3614 3614 1 s    3627 403 0 ));
+DATA(insert (  3626   3614 3614 2 s    3628 403 0 ));
+DATA(insert (  3626   3614 3614 3 s    3629 403 0 ));
+DATA(insert (  3626   3614 3614 4 s    3631 403 0 ));
+DATA(insert (  3626   3614 3614 5 s    3632 403 0 ));
 
 /*
  * GiST tsvector_ops
  */
-DATA(insert (  3655   3614 3615 1      3636 783 ));
+DATA(insert (  3655   3614 3615 1 s    3636 783 0 ));
 
 /*
  * GIN tsvector_ops
  */
-DATA(insert (  3659   3614 3615 1      3636 2742 ));
-DATA(insert (  3659   3614 3615 2      3660 2742 ));
+DATA(insert (  3659   3614 3615 1 s    3636 2742 0 ));
+DATA(insert (  3659   3614 3615 2 s    3660 2742 0 ));
 
 /*
  * btree tsquery_ops
  */
-DATA(insert (  3683   3615 3615 1       3674 403 ));
-DATA(insert (  3683   3615 3615 2       3675 403 ));
-DATA(insert (  3683   3615 3615 3       3676 403 ));
-DATA(insert (  3683   3615 3615 4       3678 403 ));
-DATA(insert (  3683   3615 3615 5       3679 403 ));
+DATA(insert (  3683   3615 3615 1 s    3674 403 0 ));
+DATA(insert (  3683   3615 3615 2 s    3675 403 0 ));
+DATA(insert (  3683   3615 3615 3 s    3676 403 0 ));
+DATA(insert (  3683   3615 3615 4 s    3678 403 0 ));
+DATA(insert (  3683   3615 3615 5 s    3679 403 0 ));
 
 /*
  * GiST tsquery_ops
  */
-DATA(insert (  3702   3615 3615 7      3693 783 ));
-DATA(insert (  3702   3615 3615 8      3694 783 ));
+DATA(insert (  3702   3615 3615 7 s    3693 783 0 ));
+DATA(insert (  3702   3615 3615 8 s    3694 783 0 ));
 
 #endif   /* PG_AMOP_H */
index d6cfafe..8b34b76 100644 (file)
@@ -1776,6 +1776,7 @@ typedef struct CreateOpClassItem
        List       *name;                       /* operator or function name */
        List       *args;                       /* argument types */
        int                     number;                 /* strategy num or support proc num */
+       List       *order_family;       /* only used for ordering operators */
        List       *class_args;         /* only used for functions */
        /* fields used for a storagetype item: */
        TypeName   *storedtype;         /* datatype stored in index */
index 677134d..785acc9 100644 (file)
@@ -469,6 +469,7 @@ typedef struct IndexOptInfo
 
        bool            predOK;                 /* true if predicate matches query */
        bool            unique;                 /* true if a unique index */
+       bool            amcanorderbyop; /* does AM support order by operator result? */
        bool            amoptionalkey;  /* can query omit key for the first column? */
        bool            amsearchnulls;  /* can AM search for NULL/NOT NULL entries? */
        bool            amhasgettuple;  /* does AM have amgettuple interface? */
index 4703d49..2176ea4 100644 (file)
@@ -849,6 +849,14 @@ WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
 ------------+--------------
 (0 rows)
 
+SELECT p1.amopfamily, p1.amopstrategy
+FROM pg_amop as p1
+WHERE NOT ((p1.amoppurpose = 's' AND p1.amopsortfamily = 0) OR
+           (p1.amoppurpose = 'o' AND p1.amopsortfamily <> 0));
+ amopfamily | amopstrategy 
+------------+--------------
+(0 rows)
+
 -- amoplefttype/amoprighttype must match the operator
 SELECT p1.oid, p2.oid
 FROM pg_amop AS p1, pg_operator AS p2
@@ -866,6 +874,25 @@ WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
 -----+-----
 (0 rows)
 
+-- amopsortfamily, if present, must reference a btree family
+SELECT p1.amopfamily, p1.amopstrategy
+FROM pg_amop AS p1
+WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
+    (SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
+     AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
+ amopfamily | amopstrategy 
+------------+--------------
+(0 rows)
+
+-- check for ordering operators not supported by parent AM
+SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
+FROM pg_amop AS p1, pg_am AS p2
+WHERE p1.amopmethod = p2.oid AND
+    p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
+ amopfamily | amopopr | oid | amname 
+------------+---------+-----+--------
+(0 rows)
+
 -- Cross-check amopstrategy index against parent AM
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
 FROM pg_amop AS p1, pg_am AS p2
@@ -885,17 +912,45 @@ WHERE p2.amopmethod = p1.oid AND
     p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
                         WHERE p3.amopfamily = p2.amopfamily AND
                               p3.amoplefttype = p2.amoplefttype AND
-                              p3.amoprighttype = p2.amoprighttype);
+                              p3.amoprighttype = p2.amoprighttype AND
+                              p3.amoppurpose = 's');
  amname | amoplefttype | amoprighttype 
 --------+--------------+---------------
 (0 rows)
 
+-- Currently, none of the AMs with fixed strategy sets support ordering ops.
+SELECT p1.amname, p2.amopfamily, p2.amopstrategy
+FROM pg_am AS p1, pg_amop AS p2
+WHERE p2.amopmethod = p1.oid AND
+    p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
+ amname | amopfamily | amopstrategy 
+--------+------------+--------------
+(0 rows)
+
 -- Check that amopopr points at a reasonable-looking operator, ie a binary
--- operator yielding boolean.
+-- operator.  If it's a search operator it had better yield boolean,
+-- otherwise an input type of its sort opfamily.
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
 FROM pg_amop AS p1, pg_operator AS p2
 WHERE p1.amopopr = p2.oid AND
-    (p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
+    p2.oprkind != 'b';
+ amopfamily | amopopr | oid | oprname 
+------------+---------+-----+---------
+(0 rows)
+
+SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
+FROM pg_amop AS p1, pg_operator AS p2
+WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
+    p2.oprresult != 'bool'::regtype;
+ amopfamily | amopopr | oid | oprname 
+------------+---------+-----+---------
+(0 rows)
+
+SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
+FROM pg_amop AS p1, pg_operator AS p2
+WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 'o' AND NOT EXISTS
+    (SELECT 1 FROM pg_opclass op
+     WHERE opcfamily = p1.amopsortfamily AND opcintype = p2.oprresult);
  amopfamily | amopopr | oid | oprname 
 ------------+---------+-----+---------
 (0 rows)
@@ -950,12 +1005,12 @@ ORDER BY 1, 2, 3;
        2742 |            4 | =
 (39 rows)
 
--- Check that all operators linked to by opclass entries have selectivity
--- estimators.  This is not absolutely required, but it seems a reasonable
--- thing to insist on for all standard datatypes.
+-- Check that all opclass search operators have selectivity estimators.
+-- This is not absolutely required, but it seems a reasonable thing
+-- to insist on for all standard datatypes.
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
 FROM pg_amop AS p1, pg_operator AS p2
-WHERE p1.amopopr = p2.oid AND
+WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
     (p2.oprrest = 0 OR p2.oprjoin = 0);
  amopfamily | amopopr | oid | oprname 
 ------------+---------+-----+---------
index 0d084a1..1a023a0 100644 (file)
@@ -685,6 +685,11 @@ FROM pg_amop as p1
 WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0
     OR p1.amopopr = 0 OR p1.amopmethod = 0 OR p1.amopstrategy < 1;
 
+SELECT p1.amopfamily, p1.amopstrategy
+FROM pg_amop as p1
+WHERE NOT ((p1.amoppurpose = 's' AND p1.amopsortfamily = 0) OR
+           (p1.amoppurpose = 'o' AND p1.amopsortfamily <> 0));
+
 -- amoplefttype/amoprighttype must match the operator
 
 SELECT p1.oid, p2.oid
@@ -698,6 +703,21 @@ SELECT p1.oid, p2.oid
 FROM pg_amop AS p1, pg_opfamily AS p2
 WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod;
 
+-- amopsortfamily, if present, must reference a btree family
+
+SELECT p1.amopfamily, p1.amopstrategy
+FROM pg_amop AS p1
+WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
+    (SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
+     AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
+
+-- check for ordering operators not supported by parent AM
+
+SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
+FROM pg_amop AS p1, pg_am AS p2
+WHERE p1.amopmethod = p2.oid AND
+    p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
+
 -- Cross-check amopstrategy index against parent AM
 
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
@@ -716,15 +736,35 @@ WHERE p2.amopmethod = p1.oid AND
     p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
                         WHERE p3.amopfamily = p2.amopfamily AND
                               p3.amoplefttype = p2.amoplefttype AND
-                              p3.amoprighttype = p2.amoprighttype);
+                              p3.amoprighttype = p2.amoprighttype AND
+                              p3.amoppurpose = 's');
+
+-- Currently, none of the AMs with fixed strategy sets support ordering ops.
+
+SELECT p1.amname, p2.amopfamily, p2.amopstrategy
+FROM pg_am AS p1, pg_amop AS p2
+WHERE p2.amopmethod = p1.oid AND
+    p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
 
 -- Check that amopopr points at a reasonable-looking operator, ie a binary
--- operator yielding boolean.
+-- operator.  If it's a search operator it had better yield boolean,
+-- otherwise an input type of its sort opfamily.
 
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
 FROM pg_amop AS p1, pg_operator AS p2
 WHERE p1.amopopr = p2.oid AND
-    (p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype);
+    p2.oprkind != 'b';
+
+SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
+FROM pg_amop AS p1, pg_operator AS p2
+WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
+    p2.oprresult != 'bool'::regtype;
+
+SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
+FROM pg_amop AS p1, pg_operator AS p2
+WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 'o' AND NOT EXISTS
+    (SELECT 1 FROM pg_opclass op
+     WHERE opcfamily = p1.amopsortfamily AND opcintype = p2.oprresult);
 
 -- Make a list of all the distinct operator names being used in particular
 -- strategy slots.  This is a bit hokey, since the list might need to change
@@ -735,13 +775,13 @@ SELECT DISTINCT amopmethod, amopstrategy, oprname
 FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid
 ORDER BY 1, 2, 3;
 
--- Check that all operators linked to by opclass entries have selectivity
--- estimators.  This is not absolutely required, but it seems a reasonable
--- thing to insist on for all standard datatypes.
+-- Check that all opclass search operators have selectivity estimators.
+-- This is not absolutely required, but it seems a reasonable thing
+-- to insist on for all standard datatypes.
 
 SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname
 FROM pg_amop AS p1, pg_operator AS p2
-WHERE p1.amopopr = p2.oid AND
+WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
     (p2.oprrest = 0 OR p2.oprjoin = 0);
 
 -- Check that each opclass in an opfamily has associated operators, that is