OSDN Git Service

Add aggsortop column to pg_aggregate, so that MIN/MAX optimization can
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Apr 2005 04:26:34 +0000 (04:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 12 Apr 2005 04:26:34 +0000 (04:26 +0000)
be supported for all datatypes.  Add CREATE AGGREGATE and pg_dump support
too.  Add specialized min/max aggregates for bpchar, instead of depending
on text's min/max, because otherwise the possible use of bpchar indexes
cannot be recognized.
initdb forced because of catalog changes.

15 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/create_aggregate.sgml
src/backend/catalog/pg_aggregate.c
src/backend/commands/aggregatecmds.c
src/backend/optimizer/plan/planagg.c
src/backend/utils/adt/varchar.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h
src/include/catalog/pg_aggregate.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/oidjoins.out
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/oidjoins.sql
src/test/regress/sql/opr_sanity.sql

index 11d7744..5a171e9 100644 (file)
@@ -1,6 +1,6 @@
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.99 2005/03/29 19:44:22 tgl Exp $
+ $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.100 2005/04/12 04:26:13 tgl Exp $
  -->
 
 <chapter id="catalogs">
       <entry>Final function (zero if none)</entry>
      </row>
      <row>
+      <entry><structfield>aggsortop</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
+      <entry>Associated sort operator (zero if none)</entry>
+     </row>
+     <row>
       <entry><structfield>aggtranstype</structfield></entry>
       <entry><type>oid</type></entry>
       <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
-      <entry>The type of the aggregate function's internal transition (state) data</entry>
+      <entry>Data type of the aggregate function's internal transition (state) data</entry>
      </row>
      <row>
       <entry><structfield>agginitval</structfield></entry>
       <entry>
        The initial value of the transition state.  This is a text
        field containing the initial value in its external string
-       representation.  If the value is null, the transition state
+       representation.  If this field is null, the transition state
        value starts out null.
       </entry>
      </row>
index 4ae1d1d..24e233f 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.31 2005/01/04 00:39:53 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.32 2005/04/12 04:26:15 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -26,6 +26,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
     STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
     [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
     [ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
+    [ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
 )
 </synopsis>
  </refsynopsisdiv>
@@ -125,6 +126,29 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
    <function>avg</function> returns null when it sees there were zero
    input rows.
   </para>
+  
+  <para>
+   Aggregates that behave like <function>MIN</> or <function>MAX</> can
+   sometimes be optimized by looking into an index instead of scanning every
+   input row.  If this aggregate can be so optimized, indicate it by
+   specifying a <firstterm>sort operator</>.  The basic requirement is that
+   the aggregate must yield the first element in the sort ordering induced by
+   the operator; in other words
+<programlisting>
+SELECT agg(col) FROM tab;
+</programlisting>
+   must be equivalent to
+<programlisting>
+SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
+</programlisting>
+   Further assumptions are that the aggregate ignores null inputs, and that
+   it delivers a null result if and only if there were no non-null inputs.
+   Ordinarily, a datatype's <literal>&lt;</> operator is the proper sort
+   operator for <function>MIN</>, and <literal>&gt;</> is the proper sort
+   operator for <function>MAX</>.  Note that the optimization will never
+   actually take effect unless the specified operator is the LessThan or
+   GreaterThan strategy member of a btree index opclass.
+  </para>
  </refsect1>
 
  <refsect1>
@@ -211,6 +235,19 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="PARAMETER">sort_operator</replaceable></term>
+    <listitem>
+     <para>
+      The associated sort operator for a <function>MIN</>- or
+      <function>MAX</>-like aggregate.
+      This is just an operator name (possibly schema-qualified).
+      The operator is assumed to have the same input datatypes as
+      the aggregate.
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
 
   <para>
index 4428bc7..c833f94 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.72 2005/03/31 22:46:06 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.73 2005/04/12 04:26:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@
 #include "optimizer/cost.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
+#include "parser/parse_oper.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -42,9 +43,10 @@ static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
 void
 AggregateCreate(const char *aggName,
                                Oid aggNamespace,
+                               Oid aggBaseType,
                                List *aggtransfnName,
                                List *aggfinalfnName,
-                               Oid aggBaseType,
+                               List *aggsortopName,
                                Oid aggTransType,
                                const char *agginitval)
 {
@@ -55,6 +57,7 @@ AggregateCreate(const char *aggName,
        Form_pg_proc proc;
        Oid                     transfn;
        Oid                     finalfn = InvalidOid;   /* can be omitted */
+       Oid                     sortop = InvalidOid;    /* can be omitted */
        Oid                     rettype;
        Oid                     finaltype;
        Oid                     fnArgs[2];              /* we only deal with 1- and 2-arg fns */
@@ -167,6 +170,12 @@ AggregateCreate(const char *aggName,
                errdetail("An aggregate returning \"anyarray\" or \"anyelement\" "
                                  "must have one of them as its base type.")));
 
+       /* handle sortop, if supplied */
+       if (aggsortopName)
+               sortop = LookupOperName(aggsortopName,
+                                                               aggBaseType, aggBaseType,
+                                                               false);
+
        /*
         * Everything looks okay.  Try to create the pg_proc entry for the
         * aggregate.  (This could fail if there's already a conflicting
@@ -207,6 +216,7 @@ AggregateCreate(const char *aggName,
        values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
        values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
        values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
+       values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
        values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
        if (agginitval)
                values[Anum_pg_aggregate_agginitval - 1] =
@@ -248,6 +258,15 @@ AggregateCreate(const char *aggName,
                referenced.objectSubId = 0;
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
+
+       /* Depends on sort operator, if any */
+       if (OidIsValid(sortop))
+       {
+               referenced.classId = get_system_catalog_relid(OperatorRelationName);
+               referenced.objectId = sortop;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
 }
 
 /*
index 7d4cbe3..32bf253 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.23 2005/03/29 00:16:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.24 2005/04/12 04:26:20 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -51,6 +51,7 @@ DefineAggregate(List *names, List *parameters)
        AclResult       aclresult;
        List       *transfuncName = NIL;
        List       *finalfuncName = NIL;
+       List       *sortoperatorName = NIL;
        TypeName   *baseType = NULL;
        TypeName   *transType = NULL;
        char       *initval = NULL;
@@ -81,6 +82,8 @@ DefineAggregate(List *names, List *parameters)
                        transfuncName = defGetQualifiedName(defel);
                else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
                        finalfuncName = defGetQualifiedName(defel);
+               else if (pg_strcasecmp(defel->defname, "sortop") == 0)
+                       sortoperatorName = defGetQualifiedName(defel);
                else if (pg_strcasecmp(defel->defname, "basetype") == 0)
                        baseType = defGetTypeName(defel);
                else if (pg_strcasecmp(defel->defname, "stype") == 0)
@@ -143,9 +146,10 @@ DefineAggregate(List *names, List *parameters)
         */
        AggregateCreate(aggName,        /* aggregate name */
                                        aggNamespace,           /* namespace */
+                                       baseTypeId, /* type of data being aggregated */
                                        transfuncName,          /* step function name */
                                        finalfuncName,          /* final function name */
-                                       baseTypeId, /* type of data being aggregated */
+                                       sortoperatorName,       /* sort operator name */
                                        transTypeId,    /* transition data type */
                                        initval);       /* initial condition */
 }
index 299931c..b80f2c6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.1 2005/04/11 23:06:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.2 2005/04/12 04:26:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -542,7 +542,6 @@ replace_aggs_with_params_mutator(Node *node,  List **context)
 static Oid
 fetch_agg_sort_op(Oid aggfnoid)
 {
-#ifdef NOT_YET
        HeapTuple       aggTuple;
        Form_pg_aggregate aggform;
        Oid                     aggsortop;
@@ -558,18 +557,4 @@ fetch_agg_sort_op(Oid aggfnoid)
        ReleaseSysCache(aggTuple);
 
        return aggsortop;
-#else
-       /*
-        * XXX stub implementation for testing: hardwire a few cases.
-        */
-       if (aggfnoid == 2132)           /* min(int4) -> int4lt */
-               return 97;
-       if (aggfnoid == 2116)           /* max(int4) -> int4gt */
-               return 521;
-       if (aggfnoid == 2145)           /* min(text) -> text_lt */
-               return 664;
-       if (aggfnoid == 2129)           /* max(text) -> text_gt */
-               return 666;
-       return InvalidOid;
-#endif
 }
index eeb218b..17d775d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.108 2004/12/31 22:01:22 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.109 2005/04/12 04:26:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -687,6 +687,40 @@ bpcharcmp(PG_FUNCTION_ARGS)
        PG_RETURN_INT32(cmp);
 }
 
+Datum
+bpchar_larger(PG_FUNCTION_ARGS)
+{
+       BpChar     *arg1 = PG_GETARG_BPCHAR_P(0);
+       BpChar     *arg2 = PG_GETARG_BPCHAR_P(1);
+       int                     len1,
+                               len2;
+       int                     cmp;
+
+       len1 = bcTruelen(arg1);
+       len2 = bcTruelen(arg2);
+
+       cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
+
+       PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
+}
+
+Datum
+bpchar_smaller(PG_FUNCTION_ARGS)
+{
+       BpChar     *arg1 = PG_GETARG_BPCHAR_P(0);
+       BpChar     *arg2 = PG_GETARG_BPCHAR_P(1);
+       int                     len1,
+                               len2;
+       int                     cmp;
+
+       len1 = bcTruelen(arg1);
+       len2 = bcTruelen(arg2);
+
+       cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
+
+       PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
+}
+
 
 /*
  * bpchar needs a specialized hash function because we want to ignore
index 92ab99d..323c3d9 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.405 2005/04/01 18:35:41 tgl Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.406 2005/04/12 04:26:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -6325,6 +6325,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
        int                     ntups;
        int                     i_aggtransfn;
        int                     i_aggfinalfn;
+       int                     i_aggsortop;
        int                     i_aggtranstype;
        int                     i_agginitval;
        int                     i_anybasetype;
@@ -6332,6 +6333,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
        int                     i_convertok;
        const char *aggtransfn;
        const char *aggfinalfn;
+       const char *aggsortop;
        const char *aggtranstype;
        const char *agginitval;
        bool            convertok;
@@ -6349,10 +6351,25 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
        selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
 
        /* Get aggregate-specific details */
-       if (g_fout->remoteVersion >= 70300)
+       if (g_fout->remoteVersion >= 80100)
+       {
+               appendPQExpBuffer(query, "SELECT aggtransfn, "
+                                                 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+                                                 "aggsortop::pg_catalog.regoperator, "
+                                                 "agginitval, "
+                                                 "proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
+                                       "proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
+                                                 "'t'::boolean as convertok "
+                                 "from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
+                                                 "where a.aggfnoid = p.oid "
+                                                 "and p.oid = '%u'::pg_catalog.oid",
+                                                 agginfo->aggfn.dobj.catId.oid);
+       }
+       else if (g_fout->remoteVersion >= 70300)
        {
                appendPQExpBuffer(query, "SELECT aggtransfn, "
                                                  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+                                                 "0 as aggsortop, "
                                                  "agginitval, "
                                                  "proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
                                        "proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
@@ -6366,6 +6383,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
        {
                appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
                                          "format_type(aggtranstype, NULL) as aggtranstype, "
+                                                 "0 as aggsortop, "
                                                  "agginitval, "
                                                  "aggbasetype = 0 as anybasetype, "
                                                  "CASE WHEN aggbasetype = 0 THEN '-' "
@@ -6380,6 +6398,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
                appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
                                                  "aggfinalfn, "
                                                  "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
+                                                 "0 as aggsortop, "
                                                  "agginitval1 as agginitval, "
                                                  "aggbasetype = 0 as anybasetype, "
                                                  "(select typname from pg_type where oid = aggbasetype) as fmtbasetype, "
@@ -6403,6 +6422,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 
        i_aggtransfn = PQfnumber(res, "aggtransfn");
        i_aggfinalfn = PQfnumber(res, "aggfinalfn");
+       i_aggsortop = PQfnumber(res, "aggsortop");
        i_aggtranstype = PQfnumber(res, "aggtranstype");
        i_agginitval = PQfnumber(res, "agginitval");
        i_anybasetype = PQfnumber(res, "anybasetype");
@@ -6411,6 +6431,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 
        aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
        aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
+       aggsortop = PQgetvalue(res, 0, i_aggsortop);
        aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
        agginitval = PQgetvalue(res, 0, i_agginitval);
        /* we save anybasetype for format_aggregate_signature */
@@ -6471,6 +6492,13 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
                                                  aggfinalfn);
        }
 
+       aggsortop = convertOperatorReference(aggsortop);
+       if (aggsortop)
+       {
+               appendPQExpBuffer(details, ",\n    SORTOP = %s",
+                                                 aggsortop);
+       }
+
        /*
         * DROP must be fully qualified in case same name appears in
         * pg_catalog
index 4243ce1..cb3868e 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.263 2005/04/06 16:34:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.264 2005/04/12 04:26:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200504061
+#define CATALOG_VERSION_NO     200504111
 
 #endif
index 854e9e8..6e339c7 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.49 2005/02/28 03:45:22 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.50 2005/04/12 04:26:28 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
  *
  *     aggfnoid                        pg_proc OID of the aggregate itself
  *     aggtransfn                      transition function
- *     aggfinalfn                      final function
+ *     aggfinalfn                      final function (0 if none)
+ *     aggsortop                       associated sort operator (0 if none)
  *     aggtranstype            type of aggregate's transition (state) data
- *     agginitval                      initial value for transition state
+ *     agginitval                      initial value for transition state (can be NULL)
  * ----------------------------------------------------------------
  */
 CATALOG(pg_aggregate) BKI_WITHOUT_OIDS
@@ -45,6 +46,7 @@ CATALOG(pg_aggregate) BKI_WITHOUT_OIDS
        regproc         aggfnoid;
        regproc         aggtransfn;
        regproc         aggfinalfn;
+       Oid                     aggsortop;
        Oid                     aggtranstype;
        text            agginitval;             /* VARIABLE LENGTH FIELD */
 } FormData_pg_aggregate;
@@ -61,12 +63,13 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
  * ----------------
  */
 
-#define Natts_pg_aggregate                             5
+#define Natts_pg_aggregate                             6
 #define Anum_pg_aggregate_aggfnoid             1
 #define Anum_pg_aggregate_aggtransfn   2
 #define Anum_pg_aggregate_aggfinalfn   3
-#define Anum_pg_aggregate_aggtranstype 4
-#define Anum_pg_aggregate_agginitval   5
+#define Anum_pg_aggregate_aggsortop            4
+#define Anum_pg_aggregate_aggtranstype 5
+#define Anum_pg_aggregate_agginitval   6
 
 
 /* ----------------
@@ -75,107 +78,110 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
  */
 
 /* avg */
-DATA(insert ( 2100     int8_accum              numeric_avg             1231    "{0,0,0}" ));
-DATA(insert ( 2101     int4_avg_accum  int8_avg                1016    "{0,0}" ));
-DATA(insert ( 2102     int2_avg_accum  int8_avg                1016    "{0,0}" ));
-DATA(insert ( 2103     numeric_accum   numeric_avg             1231    "{0,0,0}" ));
-DATA(insert ( 2104     float4_accum    float8_avg              1022    "{0,0,0}" ));
-DATA(insert ( 2105     float8_accum    float8_avg              1022    "{0,0,0}" ));
-DATA(insert ( 2106     interval_accum  interval_avg    1187    "{0 second,0 second}" ));
+DATA(insert ( 2100     int8_accum              numeric_avg             0       1231    "{0,0,0}" ));
+DATA(insert ( 2101     int4_avg_accum  int8_avg                0       1016    "{0,0}" ));
+DATA(insert ( 2102     int2_avg_accum  int8_avg                0       1016    "{0,0}" ));
+DATA(insert ( 2103     numeric_accum   numeric_avg             0       1231    "{0,0,0}" ));
+DATA(insert ( 2104     float4_accum    float8_avg              0       1022    "{0,0,0}" ));
+DATA(insert ( 2105     float8_accum    float8_avg              0       1022    "{0,0,0}" ));
+DATA(insert ( 2106     interval_accum  interval_avg    0       1187    "{0 second,0 second}" ));
 
 /* sum */
-DATA(insert ( 2107     int8_sum                -                               1700    _null_ ));
-DATA(insert ( 2108     int4_sum                -                               20              _null_ ));
-DATA(insert ( 2109     int2_sum                -                               20              _null_ ));
-DATA(insert ( 2110     float4pl                -                               700             _null_ ));
-DATA(insert ( 2111     float8pl                -                               701             _null_ ));
-DATA(insert ( 2112     cash_pl                 -                               790             _null_ ));
-DATA(insert ( 2113     interval_pl             -                               1186    _null_ ));
-DATA(insert ( 2114     numeric_add             -                               1700    _null_ ));
+DATA(insert ( 2107     int8_sum                -                               0       1700    _null_ ));
+DATA(insert ( 2108     int4_sum                -                               0       20              _null_ ));
+DATA(insert ( 2109     int2_sum                -                               0       20              _null_ ));
+DATA(insert ( 2110     float4pl                -                               0       700             _null_ ));
+DATA(insert ( 2111     float8pl                -                               0       701             _null_ ));
+DATA(insert ( 2112     cash_pl                 -                               0       790             _null_ ));
+DATA(insert ( 2113     interval_pl             -                               0       1186    _null_ ));
+DATA(insert ( 2114     numeric_add             -                               0       1700    _null_ ));
 
 /* max */
-DATA(insert ( 2115     int8larger              -                               20              _null_ ));
-DATA(insert ( 2116     int4larger              -                               23              _null_ ));
-DATA(insert ( 2117     int2larger              -                               21              _null_ ));
-DATA(insert ( 2118     oidlarger               -                               26              _null_ ));
-DATA(insert ( 2119     float4larger    -                               700             _null_ ));
-DATA(insert ( 2120     float8larger    -                               701             _null_ ));
-DATA(insert ( 2121     int4larger              -                               702             _null_ ));
-DATA(insert ( 2122     date_larger             -                               1082    _null_ ));
-DATA(insert ( 2123     time_larger             -                               1083    _null_ ));
-DATA(insert ( 2124     timetz_larger   -                               1266    _null_ ));
-DATA(insert ( 2125     cashlarger              -                               790             _null_ ));
-DATA(insert ( 2126     timestamp_larger        -                       1114    _null_ ));
-DATA(insert ( 2127     timestamptz_larger      -                       1184    _null_ ));
-DATA(insert ( 2128     interval_larger -                               1186    _null_ ));
-DATA(insert ( 2129     text_larger             -                               25              _null_ ));
-DATA(insert ( 2130     numeric_larger  -                               1700    _null_ ));
-DATA(insert ( 2050     array_larger    -                               2277    _null_ ));
+DATA(insert ( 2115     int8larger              -                               413             20              _null_ ));
+DATA(insert ( 2116     int4larger              -                               521             23              _null_ ));
+DATA(insert ( 2117     int2larger              -                               520             21              _null_ ));
+DATA(insert ( 2118     oidlarger               -                               610             26              _null_ ));
+DATA(insert ( 2119     float4larger    -                               623             700             _null_ ));
+DATA(insert ( 2120     float8larger    -                               674             701             _null_ ));
+DATA(insert ( 2121     int4larger              -                               563             702             _null_ ));
+DATA(insert ( 2122     date_larger             -                               1097    1082    _null_ ));
+DATA(insert ( 2123     time_larger             -                               1112    1083    _null_ ));
+DATA(insert ( 2124     timetz_larger   -                               1554    1266    _null_ ));
+DATA(insert ( 2125     cashlarger              -                               903             790             _null_ ));
+DATA(insert ( 2126     timestamp_larger        -                       2064    1114    _null_ ));
+DATA(insert ( 2127     timestamptz_larger      -                       1324    1184    _null_ ));
+DATA(insert ( 2128     interval_larger -                               1334    1186    _null_ ));
+DATA(insert ( 2129     text_larger             -                               666             25              _null_ ));
+DATA(insert ( 2130     numeric_larger  -                               1756    1700    _null_ ));
+DATA(insert ( 2050     array_larger    -                               1073    2277    _null_ ));
+DATA(insert ( 2244     bpchar_larger   -                               1060    1042    _null_ ));
 
 /* min */
-DATA(insert ( 2131     int8smaller             -                               20              _null_ ));
-DATA(insert ( 2132     int4smaller             -                               23              _null_ ));
-DATA(insert ( 2133     int2smaller             -                               21              _null_ ));
-DATA(insert ( 2134     oidsmaller              -                               26              _null_ ));
-DATA(insert ( 2135     float4smaller   -                               700             _null_ ));
-DATA(insert ( 2136     float8smaller   -                               701             _null_ ));
-DATA(insert ( 2137     int4smaller             -                               702             _null_ ));
-DATA(insert ( 2138     date_smaller    -                               1082    _null_ ));
-DATA(insert ( 2139     time_smaller    -                               1083    _null_ ));
-DATA(insert ( 2140     timetz_smaller  -                               1266    _null_ ));
-DATA(insert ( 2141     cashsmaller             -                               790             _null_ ));
-DATA(insert ( 2142     timestamp_smaller       -                       1114    _null_ ));
-DATA(insert ( 2143     timestamptz_smaller -                   1184    _null_ ));
-DATA(insert ( 2144     interval_smaller        -                       1186    _null_ ));
-DATA(insert ( 2145     text_smaller    -                               25              _null_ ));
-DATA(insert ( 2146     numeric_smaller -                               1700    _null_ ));
-DATA(insert ( 2051     array_smaller   -                               2277    _null_ ));
+DATA(insert ( 2131     int8smaller             -                               412             20              _null_ ));
+DATA(insert ( 2132     int4smaller             -                               97              23              _null_ ));
+DATA(insert ( 2133     int2smaller             -                               95              21              _null_ ));
+DATA(insert ( 2134     oidsmaller              -                               609             26              _null_ ));
+DATA(insert ( 2135     float4smaller   -                               622             700             _null_ ));
+DATA(insert ( 2136     float8smaller   -                               672             701             _null_ ));
+DATA(insert ( 2137     int4smaller             -                               562             702             _null_ ));
+DATA(insert ( 2138     date_smaller    -                               1095    1082    _null_ ));
+DATA(insert ( 2139     time_smaller    -                               1110    1083    _null_ ));
+DATA(insert ( 2140     timetz_smaller  -                               1552    1266    _null_ ));
+DATA(insert ( 2141     cashsmaller             -                               902             790             _null_ ));
+DATA(insert ( 2142     timestamp_smaller       -                       2062    1114    _null_ ));
+DATA(insert ( 2143     timestamptz_smaller -                   1322    1184    _null_ ));
+DATA(insert ( 2144     interval_smaller        -                       1332    1186    _null_ ));
+DATA(insert ( 2145     text_smaller    -                               664             25              _null_ ));
+DATA(insert ( 2146     numeric_smaller -                               1754    1700    _null_ ));
+DATA(insert ( 2051     array_smaller   -                               1072    2277    _null_ ));
+DATA(insert ( 2245     bpchar_smaller  -                               1058    1042    _null_ ));
 
 /*
  * Using int8inc for count() is cheating a little, since it really only
  * takes 1 parameter not 2, but nodeAgg.c won't complain ...
  */
-DATA(insert ( 2147     int8inc         -                                        20             0 ));
+DATA(insert ( 2147     int8inc         -                                       0       20              0 ));
 
 /* variance */
-DATA(insert ( 2148     int8_accum      numeric_variance        1231    "{0,0,0}" ));
-DATA(insert ( 2149     int4_accum      numeric_variance        1231    "{0,0,0}" ));
-DATA(insert ( 2150     int2_accum      numeric_variance        1231    "{0,0,0}" ));
-DATA(insert ( 2151     float4_accum    float8_variance 1022    "{0,0,0}" ));
-DATA(insert ( 2152     float8_accum    float8_variance 1022    "{0,0,0}" ));
-DATA(insert ( 2153     numeric_accum   numeric_variance        1231    "{0,0,0}" ));
+DATA(insert ( 2148     int8_accum      numeric_variance        0       1231    "{0,0,0}" ));
+DATA(insert ( 2149     int4_accum      numeric_variance        0       1231    "{0,0,0}" ));
+DATA(insert ( 2150     int2_accum      numeric_variance        0       1231    "{0,0,0}" ));
+DATA(insert ( 2151     float4_accum    float8_variance 0       1022    "{0,0,0}" ));
+DATA(insert ( 2152     float8_accum    float8_variance 0       1022    "{0,0,0}" ));
+DATA(insert ( 2153     numeric_accum  numeric_variance 0       1231    "{0,0,0}" ));
 
 /* stddev */
-DATA(insert ( 2154     int8_accum      numeric_stddev          1231    "{0,0,0}" ));
-DATA(insert ( 2155     int4_accum      numeric_stddev          1231    "{0,0,0}" ));
-DATA(insert ( 2156     int2_accum      numeric_stddev          1231    "{0,0,0}" ));
-DATA(insert ( 2157     float4_accum    float8_stddev   1022    "{0,0,0}" ));
-DATA(insert ( 2158     float8_accum    float8_stddev   1022    "{0,0,0}" ));
-DATA(insert ( 2159     numeric_accum   numeric_stddev  1231    "{0,0,0}" ));
+DATA(insert ( 2154     int8_accum      numeric_stddev          0       1231    "{0,0,0}" ));
+DATA(insert ( 2155     int4_accum      numeric_stddev          0       1231    "{0,0,0}" ));
+DATA(insert ( 2156     int2_accum      numeric_stddev          0       1231    "{0,0,0}" ));
+DATA(insert ( 2157     float4_accum    float8_stddev   0       1022    "{0,0,0}" ));
+DATA(insert ( 2158     float8_accum    float8_stddev   0       1022    "{0,0,0}" ));
+DATA(insert ( 2159     numeric_accum   numeric_stddev  0       1231    "{0,0,0}" ));
 
 /* boolean-and and boolean-or */
-DATA(insert ( 2517     booland_statefunc       -                               16      _null_ ));
-DATA(insert ( 2518     boolor_statefunc        -                               16      _null_ ));
-DATA(insert ( 2519     booland_statefunc       -                               16      _null_ ));
+DATA(insert ( 2517     booland_statefunc       -                       0       16              _null_ ));
+DATA(insert ( 2518     boolor_statefunc        -                       0       16              _null_ ));
+DATA(insert ( 2519     booland_statefunc       -                       0       16              _null_ ));
 
 /* bitwise integer */
-DATA(insert ( 2236 int2and               -                                     21               _null_ ));
-DATA(insert ( 2237 int2or                -                                     21               _null_ ));
-DATA(insert ( 2238 int4and               -                                     23               _null_ ));
-DATA(insert ( 2239 int4or                -                                     23               _null_ ));
-DATA(insert ( 2240 int8and               -                                     20               _null_ ));
-DATA(insert ( 2241 int8or                -                                     20               _null_ ));
-DATA(insert ( 2242 bitand                -                               1560           _null_ ));
-DATA(insert ( 2243 bitor                 -                               1560           _null_ ));
+DATA(insert ( 2236 int2and               -                                     0       21              _null_ ));
+DATA(insert ( 2237 int2or                -                                     0       21              _null_ ));
+DATA(insert ( 2238 int4and               -                                     0       23              _null_ ));
+DATA(insert ( 2239 int4or                -                                     0       23              _null_ ));
+DATA(insert ( 2240 int8and               -                                     0       20              _null_ ));
+DATA(insert ( 2241 int8or                -                                     0       20              _null_ ));
+DATA(insert ( 2242 bitand                -                                     0       1560    _null_ ));
+DATA(insert ( 2243 bitor                 -                                     0       1560    _null_ ));
 
 /*
  * prototypes for functions in pg_aggregate.c
  */
 extern void AggregateCreate(const char *aggName,
                                Oid aggNamespace,
+                               Oid aggBaseType,
                                List *aggtransfnName,
                                List *aggfinalfnName,
-                               Oid aggBaseType,
+                               List *aggsortopName,
                                Oid aggTransType,
                                const char *agginitval);
 
index cb90a5e..d9bf859 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.357 2005/03/31 22:46:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.358 2005/04/12 04:26:28 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -1372,6 +1372,10 @@ DATA(insert OID = 1052 (  bpcharge                  PGNSP PGUID 12 f f t f i 2 16 "1042 1042"
 DESCR("greater-than-or-equal");
 DATA(insert OID = 1053 (  bpcharne                PGNSP PGUID 12 f f t f i 2 16 "1042 1042" _null_ _null_ _null_ bpcharne - _null_ ));
 DESCR("not equal");
+DATA(insert OID = 1063 (  bpchar_larger           PGNSP PGUID 12 f f t f i 2 1042 "1042 1042" _null_ _null_ _null_ bpchar_larger - _null_ ));
+DESCR("larger of two");
+DATA(insert OID = 1064 (  bpchar_smaller   PGNSP PGUID 12 f f t f i 2 1042 "1042 1042" _null_ _null_ _null_ bpchar_smaller - _null_ ));
+DESCR("smaller of two");
 DATA(insert OID = 1078 (  bpcharcmp               PGNSP PGUID 12 f f t f i 2 23 "1042 1042" _null_ _null_ _null_ bpcharcmp - _null_ ));
 DESCR("less-equal-greater");
 DATA(insert OID = 1080 (  hashbpchar      PGNSP PGUID 12 f f t f i 1 23 "1042" _null_ _null_ _null_    hashbpchar - _null_ ));
@@ -3048,6 +3052,7 @@ DATA(insert OID = 2128 (  max                             PGNSP PGUID 12 t f f f i 1 1186 "1186" _null_ _
 DATA(insert OID = 2129 (  max                          PGNSP PGUID 12 t f f f i 1 25 "25" _null_ _null_ _null_ aggregate_dummy - _null_ ));
 DATA(insert OID = 2130 (  max                          PGNSP PGUID 12 t f f f i 1 1700 "1700" _null_ _null_ _null_     aggregate_dummy - _null_ ));
 DATA(insert OID = 2050 (  max                          PGNSP PGUID 12 t f f f i 1 2277 "2277" _null_ _null_ _null_     aggregate_dummy - _null_ ));
+DATA(insert OID = 2244 (  max                          PGNSP PGUID 12 t f f f i 1 1042 "1042" _null_ _null_ _null_     aggregate_dummy - _null_ ));
 
 DATA(insert OID = 2131 (  min                          PGNSP PGUID 12 t f f f i 1 20 "20" _null_ _null_ _null_ aggregate_dummy - _null_ ));
 DATA(insert OID = 2132 (  min                          PGNSP PGUID 12 t f f f i 1 23 "23" _null_ _null_ _null_ aggregate_dummy - _null_ ));
@@ -3066,6 +3071,7 @@ DATA(insert OID = 2144 (  min                             PGNSP PGUID 12 t f f f i 1 1186 "1186" _null_ _
 DATA(insert OID = 2145 (  min                          PGNSP PGUID 12 t f f f i 1 25 "25" _null_ _null_ _null_ aggregate_dummy - _null_ ));
 DATA(insert OID = 2146 (  min                          PGNSP PGUID 12 t f f f i 1 1700 "1700" _null_ _null_ _null_     aggregate_dummy - _null_ ));
 DATA(insert OID = 2051 (  min                          PGNSP PGUID 12 t f f f i 1 2277 "2277" _null_ _null_ _null_     aggregate_dummy - _null_ ));
+DATA(insert OID = 2245 (  min                          PGNSP PGUID 12 t f f f i 1 1042 "1042" _null_ _null_ _null_     aggregate_dummy - _null_ ));
 
 DATA(insert OID = 2147 (  count                                PGNSP PGUID 12 t f f f i 1 20 "2276" _null_ _null_ _null_  aggregate_dummy - _null_ ));
 
index 4caa5b4..96e3378 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.254 2005/03/29 00:17:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.255 2005/04/12 04:26:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -522,6 +522,8 @@ extern Datum bpcharle(PG_FUNCTION_ARGS);
 extern Datum bpchargt(PG_FUNCTION_ARGS);
 extern Datum bpcharge(PG_FUNCTION_ARGS);
 extern Datum bpcharcmp(PG_FUNCTION_ARGS);
+extern Datum bpchar_larger(PG_FUNCTION_ARGS);
+extern Datum bpchar_smaller(PG_FUNCTION_ARGS);
 extern Datum bpcharlen(PG_FUNCTION_ARGS);
 extern Datum bpcharoctetlen(PG_FUNCTION_ARGS);
 extern Datum hashbpchar(PG_FUNCTION_ARGS);
index feb912b..445f41f 100644 (file)
@@ -25,6 +25,14 @@ WHERE        aggfinalfn != 0 AND
 ------+------------
 (0 rows)
 
+SELECT ctid, aggsortop 
+FROM   pg_catalog.pg_aggregate fk 
+WHERE  aggsortop != 0 AND 
+       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop);
+ ctid | aggsortop 
+------+-----------
+(0 rows)
+
 SELECT ctid, aggtranstype 
 FROM   pg_catalog.pg_aggregate fk 
 WHERE  aggtranstype != 0 AND 
@@ -33,14 +41,6 @@ WHERE        aggtranstype != 0 AND
 ------+--------------
 (0 rows)
 
-SELECT ctid, amgettuple 
-FROM   pg_catalog.pg_am fk 
-WHERE  amgettuple != 0 AND 
-       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
- ctid | amgettuple 
-------+------------
-(0 rows)
-
 SELECT ctid, aminsert 
 FROM   pg_catalog.pg_am fk 
 WHERE  aminsert != 0 AND 
@@ -57,6 +57,22 @@ WHERE        ambeginscan != 0 AND
 ------+-------------
 (0 rows)
 
+SELECT ctid, amgettuple 
+FROM   pg_catalog.pg_am fk 
+WHERE  amgettuple != 0 AND 
+       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
+ ctid | amgettuple 
+------+------------
+(0 rows)
+
+SELECT ctid, amgetmulti 
+FROM   pg_catalog.pg_am fk 
+WHERE  amgetmulti != 0 AND 
+       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetmulti);
+ ctid | amgetmulti 
+------+------------
+(0 rows)
+
 SELECT ctid, amrescan 
 FROM   pg_catalog.pg_am fk 
 WHERE  amrescan != 0 AND 
index 8740b0e..e2e59d6 100644 (file)
@@ -677,6 +677,53 @@ WHERE a.aggfnoid = p.oid AND
 ----------+---------+-----+---------
 (0 rows)
 
+-- Cross-check aggsortop (if present) against pg_operator.
+-- We expect to find only "<" for "min" and ">" for "max".
+SELECT DISTINCT proname, oprname
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid
+ORDER BY 1;
+ proname | oprname 
+---------+---------
+ max     | >
+ min     | <
+(2 rows)
+
+-- Check datatypes match
+SELECT a.aggfnoid::oid, o.oid
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
+    (oprkind != 'b' OR oprresult != 'boolean'::regtype
+     OR oprleft != p.proargtypes[0] OR oprright != p.proargtypes[0]);
+ aggfnoid | oid 
+----------+-----
+(0 rows)
+
+-- Check operator is a suitable btree opclass member
+SELECT a.aggfnoid::oid, o.oid
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
+    NOT EXISTS(SELECT 1 FROM pg_amop ao, pg_opclass oc
+               WHERE amopclaid = oc.oid AND amopsubtype = 0
+                     AND amopopr = o.oid AND opcamid = 403
+                     AND opcintype = o.oprleft AND opcdefault);
+ aggfnoid | oid 
+----------+-----
+(0 rows)
+
+-- Check correspondence of btree strategies and names
+SELECT DISTINCT proname, oprname, amopstrategy
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p,
+     pg_amop as ao, pg_opclass oc
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
+    amopclaid = oc.oid AND amopopr = o.oid AND opcamid = 403
+ORDER BY 1;
+ proname | oprname | amopstrategy 
+---------+---------+--------------
+ max     | >       |            5
+ min     | <       |            1
+(2 rows)
+
 -- **************** pg_opclass ****************
 -- Look for illegal values in pg_opclass fields
 SELECT p1.oid
index 9df8443..910d55f 100644 (file)
@@ -13,14 +13,14 @@ SELECT      ctid, aggfinalfn
 FROM   pg_catalog.pg_aggregate fk 
 WHERE  aggfinalfn != 0 AND 
        NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aggfinalfn);
+SELECT ctid, aggsortop 
+FROM   pg_catalog.pg_aggregate fk 
+WHERE  aggsortop != 0 AND 
+       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_operator pk WHERE pk.oid = fk.aggsortop);
 SELECT ctid, aggtranstype 
 FROM   pg_catalog.pg_aggregate fk 
 WHERE  aggtranstype != 0 AND 
        NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggtranstype);
-SELECT ctid, amgettuple 
-FROM   pg_catalog.pg_am fk 
-WHERE  amgettuple != 0 AND 
-       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
 SELECT ctid, aminsert 
 FROM   pg_catalog.pg_am fk 
 WHERE  aminsert != 0 AND 
@@ -29,6 +29,14 @@ SELECT       ctid, ambeginscan
 FROM   pg_catalog.pg_am fk 
 WHERE  ambeginscan != 0 AND 
        NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
+SELECT ctid, amgettuple 
+FROM   pg_catalog.pg_am fk 
+WHERE  amgettuple != 0 AND 
+       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
+SELECT ctid, amgetmulti 
+FROM   pg_catalog.pg_am fk 
+WHERE  amgetmulti != 0 AND 
+       NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetmulti);
 SELECT ctid, amrescan 
 FROM   pg_catalog.pg_am fk 
 WHERE  amrescan != 0 AND 
index 84e9b9f..3b74c1b 100644 (file)
@@ -561,6 +561,41 @@ WHERE a.aggfnoid = p.oid AND
     a.agginitval IS NULL AND
     NOT binary_coercible(p.proargtypes[0], a.aggtranstype);
 
+-- Cross-check aggsortop (if present) against pg_operator.
+-- We expect to find only "<" for "min" and ">" for "max".
+
+SELECT DISTINCT proname, oprname
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid
+ORDER BY 1;
+
+-- Check datatypes match
+
+SELECT a.aggfnoid::oid, o.oid
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
+    (oprkind != 'b' OR oprresult != 'boolean'::regtype
+     OR oprleft != p.proargtypes[0] OR oprright != p.proargtypes[0]);
+
+-- Check operator is a suitable btree opclass member
+
+SELECT a.aggfnoid::oid, o.oid
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
+    NOT EXISTS(SELECT 1 FROM pg_amop ao, pg_opclass oc
+               WHERE amopclaid = oc.oid AND amopsubtype = 0
+                     AND amopopr = o.oid AND opcamid = 403
+                     AND opcintype = o.oprleft AND opcdefault);
+
+-- Check correspondence of btree strategies and names
+
+SELECT DISTINCT proname, oprname, amopstrategy
+FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p,
+     pg_amop as ao, pg_opclass oc
+WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
+    amopclaid = oc.oid AND amopopr = o.oid AND opcamid = 403
+ORDER BY 1;
+
 -- **************** pg_opclass ****************
 
 -- Look for illegal values in pg_opclass fields