Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite3b1b6c

Browse files
committed
Aggregates can be polymorphic, using polymorphic implementation functions.
It also works to create a non-polymorphic aggregate from polymorphicfunctions, should you want to do that. Regression test added, docs stilllacking. By Joe Conway, with some kibitzing from Tom Lane.
1 parent02b5d8e commite3b1b6c

File tree

15 files changed

+1300
-83
lines changed

15 files changed

+1300
-83
lines changed

‎src/backend/catalog/pg_aggregate.c

Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.58 2003/06/25 21:30:25 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.59 2003/07/01 19:10:52 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -29,6 +29,10 @@
2929
#include"utils/syscache.h"
3030

3131

32+
staticOidlookup_agg_function(List*fnName,intnargs,Oid*input_types,
33+
Oid*rettype);
34+
35+
3236
/*
3337
* AggregateCreate
3438
*/
@@ -48,9 +52,10 @@ AggregateCreate(const char *aggName,
4852
Form_pg_procproc;
4953
Oidtransfn;
5054
Oidfinalfn=InvalidOid;/* can be omitted */
55+
Oidrettype;
5156
Oidfinaltype;
5257
OidfnArgs[FUNC_MAX_ARGS];
53-
intnargs;
58+
intnargs_transfn;
5459
OidprocOid;
5560
TupleDesctupDesc;
5661
inti;
@@ -64,28 +69,49 @@ AggregateCreate(const char *aggName,
6469
if (!aggtransfnName)
6570
elog(ERROR,"aggregate must have a transition function");
6671

72+
/*
73+
* If transtype is polymorphic, basetype must be polymorphic also;
74+
* else we will have no way to deduce the actual transtype.
75+
*/
76+
if ((aggTransType==ANYARRAYOID||aggTransType==ANYELEMENTOID)&&
77+
!(aggBaseType==ANYARRAYOID||aggBaseType==ANYELEMENTOID))
78+
elog(ERROR,"an aggregate using ANYARRAY or ANYELEMENT as trans type "
79+
"must also have one of them as its base type");
80+
6781
/* handle transfn */
6882
MemSet(fnArgs,0,FUNC_MAX_ARGS*sizeof(Oid));
6983
fnArgs[0]=aggTransType;
7084
if (aggBaseType==ANYOID)
71-
nargs=1;
85+
nargs_transfn=1;
7286
else
7387
{
7488
fnArgs[1]=aggBaseType;
75-
nargs=2;
89+
nargs_transfn=2;
7690
}
77-
transfn=LookupFuncName(aggtransfnName,nargs,fnArgs);
78-
if (!OidIsValid(transfn))
79-
func_error("AggregateCreate",aggtransfnName,nargs,fnArgs,NULL);
91+
transfn=lookup_agg_function(aggtransfnName,nargs_transfn,fnArgs,
92+
&rettype);
93+
94+
/*
95+
* Return type of transfn (possibly after refinement by
96+
* enforce_generic_type_consistency, if transtype isn't polymorphic)
97+
* must exactly match declared transtype.
98+
*
99+
* In the non-polymorphic-transtype case, it might be okay to allow
100+
* a rettype that's binary-coercible to transtype, but I'm not quite
101+
* convinced that it's either safe or useful. When transtype is
102+
* polymorphic we *must* demand exact equality.
103+
*/
104+
if (rettype!=aggTransType)
105+
elog(ERROR,"return type of transition function %s is not %s",
106+
NameListToString(aggtransfnName),format_type_be(aggTransType));
107+
80108
tup=SearchSysCache(PROCOID,
81109
ObjectIdGetDatum(transfn),
82110
0,0,0);
83111
if (!HeapTupleIsValid(tup))
84-
func_error("AggregateCreate",aggtransfnName,nargs,fnArgs,NULL);
112+
func_error("AggregateCreate",aggtransfnName,
113+
nargs_transfn,fnArgs,NULL);
85114
proc= (Form_pg_proc)GETSTRUCT(tup);
86-
if (proc->prorettype!=aggTransType)
87-
elog(ERROR,"return type of transition function %s is not %s",
88-
NameListToString(aggtransfnName),format_type_be(aggTransType));
89115

90116
/*
91117
* If the transfn is strict and the initval is NULL, make sure input
@@ -105,17 +131,8 @@ AggregateCreate(const char *aggName,
105131
{
106132
MemSet(fnArgs,0,FUNC_MAX_ARGS*sizeof(Oid));
107133
fnArgs[0]=aggTransType;
108-
finalfn=LookupFuncName(aggfinalfnName,1,fnArgs);
109-
if (!OidIsValid(finalfn))
110-
func_error("AggregateCreate",aggfinalfnName,1,fnArgs,NULL);
111-
tup=SearchSysCache(PROCOID,
112-
ObjectIdGetDatum(finalfn),
113-
0,0,0);
114-
if (!HeapTupleIsValid(tup))
115-
func_error("AggregateCreate",aggfinalfnName,1,fnArgs,NULL);
116-
proc= (Form_pg_proc)GETSTRUCT(tup);
117-
finaltype=proc->prorettype;
118-
ReleaseSysCache(tup);
134+
finalfn=lookup_agg_function(aggfinalfnName,1,fnArgs,
135+
&finaltype);
119136
}
120137
else
121138
{
@@ -126,6 +143,19 @@ AggregateCreate(const char *aggName,
126143
}
127144
Assert(OidIsValid(finaltype));
128145

146+
/*
147+
* If finaltype (i.e. aggregate return type) is polymorphic,
148+
* basetype must be polymorphic also, else parser will fail to deduce
149+
* result type. (Note: given the previous test on transtype and basetype,
150+
* this cannot happen, unless someone has snuck a finalfn definition
151+
* into the catalogs that itself violates the rule against polymorphic
152+
* result with no polymorphic input.)
153+
*/
154+
if ((finaltype==ANYARRAYOID||finaltype==ANYELEMENTOID)&&
155+
!(aggBaseType==ANYARRAYOID||aggBaseType==ANYELEMENTOID))
156+
elog(ERROR,"an aggregate returning ANYARRAY or ANYELEMENT "
157+
"must also have one of them as its base type");
158+
129159
/*
130160
* Everything looks okay. Try to create the pg_proc entry for the
131161
* aggregate. (This could fail if there's already a conflicting
@@ -207,3 +237,71 @@ AggregateCreate(const char *aggName,
207237
recordDependencyOn(&myself,&referenced,DEPENDENCY_NORMAL);
208238
}
209239
}
240+
241+
/*
242+
* lookup_agg_function -- common code for finding both transfn and finalfn
243+
*/
244+
staticOid
245+
lookup_agg_function(List*fnName,
246+
intnargs,
247+
Oid*input_types,
248+
Oid*rettype)
249+
{
250+
OidfnOid;
251+
boolretset;
252+
Oid*true_oid_array;
253+
FuncDetailCodefdresult;
254+
255+
/*
256+
* func_get_detail looks up the function in the catalogs, does
257+
* disambiguation for polymorphic functions, handles inheritance, and
258+
* returns the funcid and type and set or singleton status of the
259+
* function's return value. it also returns the true argument types
260+
* to the function.
261+
*/
262+
fdresult=func_get_detail(fnName,NIL,nargs,input_types,
263+
&fnOid,rettype,&retset,
264+
&true_oid_array);
265+
266+
/* only valid case is a normal function not returning a set */
267+
if (fdresult!=FUNCDETAIL_NORMAL||
268+
!OidIsValid(fnOid)||
269+
retset)
270+
func_error("AggregateCreate",fnName,nargs,input_types,NULL);
271+
272+
/*
273+
* If the given type(s) are all polymorphic, there's nothing we
274+
* can check. Otherwise, enforce consistency, and possibly refine
275+
* the result type.
276+
*/
277+
if ((input_types[0]==ANYARRAYOID||input_types[0]==ANYELEMENTOID)&&
278+
(nargs==1||
279+
(input_types[1]==ANYARRAYOID||input_types[1]==ANYELEMENTOID)))
280+
{
281+
/* nothing to check here */
282+
}
283+
else
284+
{
285+
*rettype=enforce_generic_type_consistency(input_types,
286+
true_oid_array,
287+
nargs,
288+
*rettype);
289+
}
290+
291+
/*
292+
* func_get_detail will find functions requiring run-time argument type
293+
* coercion, but nodeAgg.c isn't prepared to deal with that
294+
*/
295+
if (true_oid_array[0]!=ANYARRAYOID&&
296+
true_oid_array[0]!=ANYELEMENTOID&&
297+
!IsBinaryCoercible(input_types[0],true_oid_array[0]))
298+
func_error("AggregateCreate",fnName,nargs,input_types,NULL);
299+
300+
if (nargs==2&&
301+
true_oid_array[1]!=ANYARRAYOID&&
302+
true_oid_array[1]!=ANYELEMENTOID&&
303+
!IsBinaryCoercible(input_types[1],true_oid_array[1]))
304+
func_error("AggregateCreate",fnName,nargs,input_types,NULL);
305+
306+
returnfnOid;
307+
}

‎src/backend/commands/aggregatecmds.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.8 2003/06/27 14:45:27 petere Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.9 2003/07/01 19:10:52 tgl Exp $
1313
*
1414
* DESCRIPTION
1515
* The "DefineFoo" routines take the parse tree and pick out the
@@ -120,7 +120,9 @@ DefineAggregate(List *names, List *parameters)
120120
baseTypeId=typenameTypeId(baseType);
121121

122122
transTypeId=typenameTypeId(transType);
123-
if (get_typtype(transTypeId)=='p')
123+
if (get_typtype(transTypeId)=='p'&&
124+
transTypeId!=ANYARRAYOID&&
125+
transTypeId!=ANYELEMENTOID)
124126
elog(ERROR,"Aggregate transition datatype cannot be %s",
125127
format_type_be(transTypeId));
126128

‎src/backend/executor/nodeAgg.c

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* Portions Copyright (c) 1994, Regents of the University of California
4646
*
4747
* IDENTIFICATION
48-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.109 2003/06/25 21:30:28 momjian Exp $
48+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.110 2003/07/01 19:10:52 tgl Exp $
4949
*
5050
*-------------------------------------------------------------------------
5151
*/
@@ -59,6 +59,7 @@
5959
#include"executor/nodeAgg.h"
6060
#include"miscadmin.h"
6161
#include"optimizer/clauses.h"
62+
#include"parser/parse_agg.h"
6263
#include"parser/parse_coerce.h"
6364
#include"parser/parse_expr.h"
6465
#include"parser/parse_oper.h"
@@ -1182,11 +1183,15 @@ ExecInitAgg(Agg *node, EState *estate)
11821183
AggrefExprState*aggrefstate= (AggrefExprState*)lfirst(alist);
11831184
Aggref*aggref= (Aggref*)aggrefstate->xprstate.expr;
11841185
AggStatePerAggperaggstate;
1186+
OidinputType;
11851187
HeapTupleaggTuple;
11861188
Form_pg_aggregateaggform;
1189+
Oidaggtranstype;
11871190
AclResultaclresult;
11881191
Oidtransfn_oid,
11891192
finalfn_oid;
1193+
Expr*transfnexpr,
1194+
*finalfnexpr;
11901195
DatumtextInitVal;
11911196
inti;
11921197

@@ -1217,6 +1222,13 @@ ExecInitAgg(Agg *node, EState *estate)
12171222
peraggstate->aggrefstate=aggrefstate;
12181223
peraggstate->aggref=aggref;
12191224

1225+
/*
1226+
* Get actual datatype of the input. We need this because it may
1227+
* be different from the agg's declared input type, when the agg
1228+
* accepts ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
1229+
*/
1230+
inputType=exprType((Node*)aggref->target);
1231+
12201232
aggTuple=SearchSysCache(AGGFNOID,
12211233
ObjectIdGetDatum(aggref->aggfnoid),
12221234
0,0,0);
@@ -1231,10 +1243,47 @@ ExecInitAgg(Agg *node, EState *estate)
12311243
if (aclresult!=ACLCHECK_OK)
12321244
aclcheck_error(aclresult,get_func_name(aggref->aggfnoid));
12331245

1246+
peraggstate->transfn_oid=transfn_oid=aggform->aggtransfn;
1247+
peraggstate->finalfn_oid=finalfn_oid=aggform->aggfinalfn;
1248+
1249+
/* resolve actual type of transition state, if polymorphic */
1250+
aggtranstype=aggform->aggtranstype;
1251+
if (aggtranstype==ANYARRAYOID||aggtranstype==ANYELEMENTOID)
1252+
{
1253+
/* have to fetch the agg's declared input type... */
1254+
Oidagg_arg_types[FUNC_MAX_ARGS];
1255+
intagg_nargs;
1256+
1257+
(void)get_func_signature(aggref->aggfnoid,
1258+
agg_arg_types,&agg_nargs);
1259+
Assert(agg_nargs==1);
1260+
aggtranstype=resolve_generic_type(aggtranstype,
1261+
inputType,
1262+
agg_arg_types[0]);
1263+
}
1264+
1265+
/* build expression trees using actual argument & result types */
1266+
build_aggregate_fnexprs(inputType,
1267+
aggtranstype,
1268+
aggref->aggtype,
1269+
transfn_oid,
1270+
finalfn_oid,
1271+
&transfnexpr,
1272+
&finalfnexpr);
1273+
1274+
fmgr_info(transfn_oid,&peraggstate->transfn);
1275+
peraggstate->transfn.fn_expr= (Node*)transfnexpr;
1276+
1277+
if (OidIsValid(finalfn_oid))
1278+
{
1279+
fmgr_info(finalfn_oid,&peraggstate->finalfn);
1280+
peraggstate->finalfn.fn_expr= (Node*)finalfnexpr;
1281+
}
1282+
12341283
get_typlenbyval(aggref->aggtype,
12351284
&peraggstate->resulttypeLen,
12361285
&peraggstate->resulttypeByVal);
1237-
get_typlenbyval(aggform->aggtranstype,
1286+
get_typlenbyval(aggtranstype,
12381287
&peraggstate->transtypeLen,
12391288
&peraggstate->transtypeByVal);
12401289

@@ -1250,14 +1299,7 @@ ExecInitAgg(Agg *node, EState *estate)
12501299
peraggstate->initValue= (Datum)0;
12511300
else
12521301
peraggstate->initValue=GetAggInitVal(textInitVal,
1253-
aggform->aggtranstype);
1254-
1255-
peraggstate->transfn_oid=transfn_oid=aggform->aggtransfn;
1256-
peraggstate->finalfn_oid=finalfn_oid=aggform->aggfinalfn;
1257-
1258-
fmgr_info(transfn_oid,&peraggstate->transfn);
1259-
if (OidIsValid(finalfn_oid))
1260-
fmgr_info(finalfn_oid,&peraggstate->finalfn);
1302+
aggtranstype);
12611303

12621304
/*
12631305
* If the transfn is strict and the initval is NULL, make sure
@@ -1268,26 +1310,13 @@ ExecInitAgg(Agg *node, EState *estate)
12681310
*/
12691311
if (peraggstate->transfn.fn_strict&&peraggstate->initValueIsNull)
12701312
{
1271-
/*
1272-
* Note: use the type from the input expression here, not from
1273-
* pg_proc.proargtypes, because the latter might be 0.
1274-
* (Consider COUNT(*).)
1275-
*/
1276-
OidinputType=exprType((Node*)aggref->target);
1277-
1278-
if (!IsBinaryCoercible(inputType,aggform->aggtranstype))
1313+
if (!IsBinaryCoercible(inputType,aggtranstype))
12791314
elog(ERROR,"Aggregate %u needs to have compatible input type and transition type",
12801315
aggref->aggfnoid);
12811316
}
12821317

12831318
if (aggref->aggdistinct)
12841319
{
1285-
/*
1286-
* Note: use the type from the input expression here, not from
1287-
* pg_proc.proargtypes, because the latter might be a pseudotype.
1288-
* (Consider COUNT(*).)
1289-
*/
1290-
OidinputType=exprType((Node*)aggref->target);
12911320
Oideq_function;
12921321

12931322
/* We don't implement DISTINCT aggs in the HASHED case */

‎src/backend/nodes/makefuncs.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.39 2003/05/06 00:20:32 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.40 2003/07/01 19:10:52 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -251,3 +251,24 @@ makeTypeName(char *typnam)
251251
n->typmod=-1;
252252
returnn;
253253
}
254+
255+
/*
256+
* makeFuncExpr -
257+
*build an expression tree representing a function call.
258+
*
259+
* The argument expressions must have been transformed already.
260+
*/
261+
FuncExpr*
262+
makeFuncExpr(Oidfuncid,Oidrettype,List*args,CoercionFormfformat)
263+
{
264+
FuncExpr*funcexpr;
265+
266+
funcexpr=makeNode(FuncExpr);
267+
funcexpr->funcid=funcid;
268+
funcexpr->funcresulttype=rettype;
269+
funcexpr->funcretset= false;/* only allowed case here */
270+
funcexpr->funcformat=fformat;
271+
funcexpr->args=args;
272+
273+
returnfuncexpr;
274+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp