From: Tom Lane Date: Tue, 12 Apr 2005 04:26:34 +0000 (+0000) Subject: Add aggsortop column to pg_aggregate, so that MIN/MAX optimization can X-Git-Tag: REL9_0_0~10431 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=2e7a68896bfa84b28cd57e23e141aa9c899275c7;p=pg-rex%2Fsyncrep.git 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. --- diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 11d774410d..5a171e9496 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -251,10 +251,16 @@ Final function (zero if none) + aggsortop + oid + pg_operator.oid + Associated sort operator (zero if none) + + aggtranstype oid pg_type.oid - The type of the aggregate function's internal transition (state) data + Data type of the aggregate function's internal transition (state) data agginitval @@ -263,7 +269,7 @@ 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. diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml index 4ae1d1dd8c..24e233f589 100644 --- a/doc/src/sgml/ref/create_aggregate.sgml +++ b/doc/src/sgml/ref/create_aggregate.sgml @@ -1,5 +1,5 @@ @@ -26,6 +26,7 @@ CREATE AGGREGATE name ( STYPE = state_data_type [ , FINALFUNC = ffunc ] [ , INITCOND = initial_condition ] + [ , SORTOP = sort_operator ] ) @@ -125,6 +126,29 @@ CREATE AGGREGATE name ( avg returns null when it sees there were zero input rows. + + + Aggregates that behave like MIN or 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 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 + +SELECT agg(col) FROM tab; + + must be equivalent to + +SELECT col FROM tab ORDER BY col USING sortop LIMIT 1; + + 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 < operator is the proper sort + operator for MIN, and > is the proper sort + operator for 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. + @@ -211,6 +235,19 @@ CREATE AGGREGATE name ( + + + sort_operator + + + The associated sort operator for a MIN- or + 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. + + + diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 4428bc7ecb..c833f948a8 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -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); + } } /* diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 7d4cbe3642..32bf25389a 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -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 */ } diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 299931c615..b80f2c6900 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -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 } diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index eeb218bf57..17d775d23b 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -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 diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 92ab99d01a..323c3d9182 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -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 diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 4243ce19b2..cb3868ea15 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 854e9e888f..6e339c7687 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -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); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index cb90a5e04c..d9bf85973c 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -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_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 4caa5b4cba..96e33786ee 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -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); diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index feb912b87f..445f41ffb9 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -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 diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 8740b0e938..e2e59d675e 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -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 diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql index 9df84436bf..910d55f9f9 100644 --- a/src/test/regress/sql/oidjoins.sql +++ b/src/test/regress/sql/oidjoins.sql @@ -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 diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 84e9b9f738..3b74c1bbd7 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -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