Commit 2e7a6889 authored by Tom Lane's avatar Tom Lane

Add aggsortop column to pg_aggregate, so that MIN/MAX optimization can

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.
parent 3803f243
<!--
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">
......@@ -250,11 +250,17 @@
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<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>
......@@ -263,7 +269,7 @@
<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>
......
<!--
$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>
......
......@@ -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);
}
}
/*
......
......@@ -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 */
}
......
......@@ -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
}
......@@ -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
......
......@@ -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
......
......@@ -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
......@@ -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
......@@ -35,9 +35,10 @@
*
* 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);
......
......@@ -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_ ));
......
......@@ -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);
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment