Skip to content

Commit 2e7a688

Browse files
committed
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.
1 parent 3803f24 commit 2e7a688

File tree

15 files changed

+356
-123
lines changed

15 files changed

+356
-123
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!--
22
Documentation of the system catalogs, directed toward PostgreSQL developers
3-
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.99 2005/03/29 19:44:22 tgl Exp $
3+
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.100 2005/04/12 04:26:13 tgl Exp $
44
-->
55

66
<chapter id="catalogs">
@@ -250,11 +250,17 @@
250250
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
251251
<entry>Final function (zero if none)</entry>
252252
</row>
253+
<row>
254+
<entry><structfield>aggsortop</structfield></entry>
255+
<entry><type>oid</type></entry>
256+
<entry><literal><link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.oid</literal></entry>
257+
<entry>Associated sort operator (zero if none)</entry>
258+
</row>
253259
<row>
254260
<entry><structfield>aggtranstype</structfield></entry>
255261
<entry><type>oid</type></entry>
256262
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
257-
<entry>The type of the aggregate function's internal transition (state) data</entry>
263+
<entry>Data type of the aggregate function's internal transition (state) data</entry>
258264
</row>
259265
<row>
260266
<entry><structfield>agginitval</structfield></entry>
@@ -263,7 +269,7 @@
263269
<entry>
264270
The initial value of the transition state. This is a text
265271
field containing the initial value in its external string
266-
representation. If the value is null, the transition state
272+
representation. If this field is null, the transition state
267273
value starts out null.
268274
</entry>
269275
</row>

doc/src/sgml/ref/create_aggregate.sgml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.31 2005/01/04 00:39:53 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.32 2005/04/12 04:26:15 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -26,6 +26,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
2626
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
2727
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
2828
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
29+
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
2930
)
3031
</synopsis>
3132
</refsynopsisdiv>
@@ -125,6 +126,29 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
125126
<function>avg</function> returns null when it sees there were zero
126127
input rows.
127128
</para>
129+
130+
<para>
131+
Aggregates that behave like <function>MIN</> or <function>MAX</> can
132+
sometimes be optimized by looking into an index instead of scanning every
133+
input row. If this aggregate can be so optimized, indicate it by
134+
specifying a <firstterm>sort operator</>. The basic requirement is that
135+
the aggregate must yield the first element in the sort ordering induced by
136+
the operator; in other words
137+
<programlisting>
138+
SELECT agg(col) FROM tab;
139+
</programlisting>
140+
must be equivalent to
141+
<programlisting>
142+
SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
143+
</programlisting>
144+
Further assumptions are that the aggregate ignores null inputs, and that
145+
it delivers a null result if and only if there were no non-null inputs.
146+
Ordinarily, a datatype's <literal>&lt;</> operator is the proper sort
147+
operator for <function>MIN</>, and <literal>&gt;</> is the proper sort
148+
operator for <function>MAX</>. Note that the optimization will never
149+
actually take effect unless the specified operator is the LessThan or
150+
GreaterThan strategy member of a btree index opclass.
151+
</para>
128152
</refsect1>
129153

130154
<refsect1>
@@ -211,6 +235,19 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
211235
</para>
212236
</listitem>
213237
</varlistentry>
238+
239+
<varlistentry>
240+
<term><replaceable class="PARAMETER">sort_operator</replaceable></term>
241+
<listitem>
242+
<para>
243+
The associated sort operator for a <function>MIN</>- or
244+
<function>MAX</>-like aggregate.
245+
This is just an operator name (possibly schema-qualified).
246+
The operator is assumed to have the same input datatypes as
247+
the aggregate.
248+
</para>
249+
</listitem>
250+
</varlistentry>
214251
</variablelist>
215252

216253
<para>

src/backend/catalog/pg_aggregate.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.72 2005/03/31 22:46:06 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.73 2005/04/12 04:26:17 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -26,6 +26,7 @@
2626
#include "optimizer/cost.h"
2727
#include "parser/parse_coerce.h"
2828
#include "parser/parse_func.h"
29+
#include "parser/parse_oper.h"
2930
#include "utils/acl.h"
3031
#include "utils/builtins.h"
3132
#include "utils/lsyscache.h"
@@ -42,9 +43,10 @@ static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
4243
void
4344
AggregateCreate(const char *aggName,
4445
Oid aggNamespace,
46+
Oid aggBaseType,
4547
List *aggtransfnName,
4648
List *aggfinalfnName,
47-
Oid aggBaseType,
49+
List *aggsortopName,
4850
Oid aggTransType,
4951
const char *agginitval)
5052
{
@@ -55,6 +57,7 @@ AggregateCreate(const char *aggName,
5557
Form_pg_proc proc;
5658
Oid transfn;
5759
Oid finalfn = InvalidOid; /* can be omitted */
60+
Oid sortop = InvalidOid; /* can be omitted */
5861
Oid rettype;
5962
Oid finaltype;
6063
Oid fnArgs[2]; /* we only deal with 1- and 2-arg fns */
@@ -167,6 +170,12 @@ AggregateCreate(const char *aggName,
167170
errdetail("An aggregate returning \"anyarray\" or \"anyelement\" "
168171
"must have one of them as its base type.")));
169172

173+
/* handle sortop, if supplied */
174+
if (aggsortopName)
175+
sortop = LookupOperName(aggsortopName,
176+
aggBaseType, aggBaseType,
177+
false);
178+
170179
/*
171180
* Everything looks okay. Try to create the pg_proc entry for the
172181
* aggregate. (This could fail if there's already a conflicting
@@ -207,6 +216,7 @@ AggregateCreate(const char *aggName,
207216
values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
208217
values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
209218
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
219+
values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
210220
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
211221
if (agginitval)
212222
values[Anum_pg_aggregate_agginitval - 1] =
@@ -248,6 +258,15 @@ AggregateCreate(const char *aggName,
248258
referenced.objectSubId = 0;
249259
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
250260
}
261+
262+
/* Depends on sort operator, if any */
263+
if (OidIsValid(sortop))
264+
{
265+
referenced.classId = get_system_catalog_relid(OperatorRelationName);
266+
referenced.objectId = sortop;
267+
referenced.objectSubId = 0;
268+
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
269+
}
251270
}
252271

253272
/*

src/backend/commands/aggregatecmds.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.23 2005/03/29 00:16:57 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.24 2005/04/12 04:26:20 tgl Exp $
1313
*
1414
* DESCRIPTION
1515
* The "DefineFoo" routines take the parse tree and pick out the
@@ -51,6 +51,7 @@ DefineAggregate(List *names, List *parameters)
5151
AclResult aclresult;
5252
List *transfuncName = NIL;
5353
List *finalfuncName = NIL;
54+
List *sortoperatorName = NIL;
5455
TypeName *baseType = NULL;
5556
TypeName *transType = NULL;
5657
char *initval = NULL;
@@ -81,6 +82,8 @@ DefineAggregate(List *names, List *parameters)
8182
transfuncName = defGetQualifiedName(defel);
8283
else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
8384
finalfuncName = defGetQualifiedName(defel);
85+
else if (pg_strcasecmp(defel->defname, "sortop") == 0)
86+
sortoperatorName = defGetQualifiedName(defel);
8487
else if (pg_strcasecmp(defel->defname, "basetype") == 0)
8588
baseType = defGetTypeName(defel);
8689
else if (pg_strcasecmp(defel->defname, "stype") == 0)
@@ -143,9 +146,10 @@ DefineAggregate(List *names, List *parameters)
143146
*/
144147
AggregateCreate(aggName, /* aggregate name */
145148
aggNamespace, /* namespace */
149+
baseTypeId, /* type of data being aggregated */
146150
transfuncName, /* step function name */
147151
finalfuncName, /* final function name */
148-
baseTypeId, /* type of data being aggregated */
152+
sortoperatorName, /* sort operator name */
149153
transTypeId, /* transition data type */
150154
initval); /* initial condition */
151155
}

src/backend/optimizer/plan/planagg.c

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.1 2005/04/11 23:06:55 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.2 2005/04/12 04:26:24 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -542,7 +542,6 @@ replace_aggs_with_params_mutator(Node *node, List **context)
542542
static Oid
543543
fetch_agg_sort_op(Oid aggfnoid)
544544
{
545-
#ifdef NOT_YET
546545
HeapTuple aggTuple;
547546
Form_pg_aggregate aggform;
548547
Oid aggsortop;
@@ -558,18 +557,4 @@ fetch_agg_sort_op(Oid aggfnoid)
558557
ReleaseSysCache(aggTuple);
559558

560559
return aggsortop;
561-
#else
562-
/*
563-
* XXX stub implementation for testing: hardwire a few cases.
564-
*/
565-
if (aggfnoid == 2132) /* min(int4) -> int4lt */
566-
return 97;
567-
if (aggfnoid == 2116) /* max(int4) -> int4gt */
568-
return 521;
569-
if (aggfnoid == 2145) /* min(text) -> text_lt */
570-
return 664;
571-
if (aggfnoid == 2129) /* max(text) -> text_gt */
572-
return 666;
573-
return InvalidOid;
574-
#endif
575560
}

src/backend/utils/adt/varchar.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.108 2004/12/31 22:01:22 pgsql Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.109 2005/04/12 04:26:26 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -687,6 +687,40 @@ bpcharcmp(PG_FUNCTION_ARGS)
687687
PG_RETURN_INT32(cmp);
688688
}
689689

690+
Datum
691+
bpchar_larger(PG_FUNCTION_ARGS)
692+
{
693+
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
694+
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
695+
int len1,
696+
len2;
697+
int cmp;
698+
699+
len1 = bcTruelen(arg1);
700+
len2 = bcTruelen(arg2);
701+
702+
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
703+
704+
PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
705+
}
706+
707+
Datum
708+
bpchar_smaller(PG_FUNCTION_ARGS)
709+
{
710+
BpChar *arg1 = PG_GETARG_BPCHAR_P(0);
711+
BpChar *arg2 = PG_GETARG_BPCHAR_P(1);
712+
int len1,
713+
len2;
714+
int cmp;
715+
716+
len1 = bcTruelen(arg1);
717+
len2 = bcTruelen(arg2);
718+
719+
cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2);
720+
721+
PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
722+
}
723+
690724

691725
/*
692726
* bpchar needs a specialized hash function because we want to ignore

src/bin/pg_dump/pg_dump.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* by PostgreSQL
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.405 2005/04/01 18:35:41 tgl Exp $
15+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.406 2005/04/12 04:26:27 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -6325,13 +6325,15 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
63256325
int ntups;
63266326
int i_aggtransfn;
63276327
int i_aggfinalfn;
6328+
int i_aggsortop;
63286329
int i_aggtranstype;
63296330
int i_agginitval;
63306331
int i_anybasetype;
63316332
int i_fmtbasetype;
63326333
int i_convertok;
63336334
const char *aggtransfn;
63346335
const char *aggfinalfn;
6336+
const char *aggsortop;
63356337
const char *aggtranstype;
63366338
const char *agginitval;
63376339
bool convertok;
@@ -6349,10 +6351,25 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
63496351
selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
63506352

63516353
/* Get aggregate-specific details */
6352-
if (g_fout->remoteVersion >= 70300)
6354+
if (g_fout->remoteVersion >= 80100)
6355+
{
6356+
appendPQExpBuffer(query, "SELECT aggtransfn, "
6357+
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
6358+
"aggsortop::pg_catalog.regoperator, "
6359+
"agginitval, "
6360+
"proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
6361+
"proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
6362+
"'t'::boolean as convertok "
6363+
"from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
6364+
"where a.aggfnoid = p.oid "
6365+
"and p.oid = '%u'::pg_catalog.oid",
6366+
agginfo->aggfn.dobj.catId.oid);
6367+
}
6368+
else if (g_fout->remoteVersion >= 70300)
63536369
{
63546370
appendPQExpBuffer(query, "SELECT aggtransfn, "
63556371
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
6372+
"0 as aggsortop, "
63566373
"agginitval, "
63576374
"proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
63586375
"proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
@@ -6366,6 +6383,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
63666383
{
63676384
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
63686385
"format_type(aggtranstype, NULL) as aggtranstype, "
6386+
"0 as aggsortop, "
63696387
"agginitval, "
63706388
"aggbasetype = 0 as anybasetype, "
63716389
"CASE WHEN aggbasetype = 0 THEN '-' "
@@ -6380,6 +6398,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
63806398
appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
63816399
"aggfinalfn, "
63826400
"(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
6401+
"0 as aggsortop, "
63836402
"agginitval1 as agginitval, "
63846403
"aggbasetype = 0 as anybasetype, "
63856404
"(select typname from pg_type where oid = aggbasetype) as fmtbasetype, "
@@ -6403,6 +6422,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
64036422

64046423
i_aggtransfn = PQfnumber(res, "aggtransfn");
64056424
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
6425+
i_aggsortop = PQfnumber(res, "aggsortop");
64066426
i_aggtranstype = PQfnumber(res, "aggtranstype");
64076427
i_agginitval = PQfnumber(res, "agginitval");
64086428
i_anybasetype = PQfnumber(res, "anybasetype");
@@ -6411,6 +6431,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
64116431

64126432
aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
64136433
aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
6434+
aggsortop = PQgetvalue(res, 0, i_aggsortop);
64146435
aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
64156436
agginitval = PQgetvalue(res, 0, i_agginitval);
64166437
/* we save anybasetype for format_aggregate_signature */
@@ -6471,6 +6492,13 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
64716492
aggfinalfn);
64726493
}
64736494

6495+
aggsortop = convertOperatorReference(aggsortop);
6496+
if (aggsortop)
6497+
{
6498+
appendPQExpBuffer(details, ",\n SORTOP = %s",
6499+
aggsortop);
6500+
}
6501+
64746502
/*
64756503
* DROP must be fully qualified in case same name appears in
64766504
* pg_catalog

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy