Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / catalog / pg_aggregate.c
blob7399123942dde8f0bbd6f006cdf40a0d4e205657
1 /*-------------------------------------------------------------------------
3 * pg_aggregate.c
4 * routines to support manipulation of the pg_aggregate relation
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "access/heapam.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_aggregate.h"
21 #include "catalog/pg_language.h"
22 #include "catalog/pg_operator.h"
23 #include "catalog/pg_proc.h"
24 #include "catalog/pg_proc_fn.h"
25 #include "catalog/pg_type.h"
26 #include "miscadmin.h"
27 #include "parser/parse_coerce.h"
28 #include "parser/parse_func.h"
29 #include "parser/parse_oper.h"
30 #include "utils/acl.h"
31 #include "utils/builtins.h"
32 #include "utils/lsyscache.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
37 static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
38 Oid *rettype);
42 * AggregateCreate
44 void
45 AggregateCreate(const char *aggName,
46 Oid aggNamespace,
47 Oid *aggArgTypes,
48 int numArgs,
49 List *aggtransfnName,
50 List *aggfinalfnName,
51 List *aggsortopName,
52 Oid aggTransType,
53 const char *agginitval)
55 Relation aggdesc;
56 HeapTuple tup;
57 bool nulls[Natts_pg_aggregate];
58 Datum values[Natts_pg_aggregate];
59 Form_pg_proc proc;
60 Oid transfn;
61 Oid finalfn = InvalidOid; /* can be omitted */
62 Oid sortop = InvalidOid; /* can be omitted */
63 bool hasPolyArg;
64 Oid rettype;
65 Oid finaltype;
66 Oid *fnArgs;
67 int nargs_transfn;
68 Oid procOid;
69 TupleDesc tupDesc;
70 int i;
71 ObjectAddress myself,
72 referenced;
74 /* sanity checks (caller should have caught these) */
75 if (!aggName)
76 elog(ERROR, "no aggregate name supplied");
78 if (!aggtransfnName)
79 elog(ERROR, "aggregate must have a transition function");
81 /* check for polymorphic arguments */
82 hasPolyArg = false;
83 for (i = 0; i < numArgs; i++)
85 if (IsPolymorphicType(aggArgTypes[i]))
87 hasPolyArg = true;
88 break;
93 * If transtype is polymorphic, must have polymorphic argument also; else
94 * we will have no way to deduce the actual transtype.
96 if (IsPolymorphicType(aggTransType) && !hasPolyArg)
97 ereport(ERROR,
98 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
99 errmsg("cannot determine transition data type"),
100 errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
102 /* find the transfn */
103 nargs_transfn = numArgs + 1;
104 fnArgs = (Oid *) palloc(nargs_transfn * sizeof(Oid));
105 fnArgs[0] = aggTransType;
106 memcpy(fnArgs + 1, aggArgTypes, numArgs * sizeof(Oid));
107 transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
108 &rettype);
111 * Return type of transfn (possibly after refinement by
112 * enforce_generic_type_consistency, if transtype isn't polymorphic) must
113 * exactly match declared transtype.
115 * In the non-polymorphic-transtype case, it might be okay to allow a
116 * rettype that's binary-coercible to transtype, but I'm not quite
117 * convinced that it's either safe or useful. When transtype is
118 * polymorphic we *must* demand exact equality.
120 if (rettype != aggTransType)
121 ereport(ERROR,
122 (errcode(ERRCODE_DATATYPE_MISMATCH),
123 errmsg("return type of transition function %s is not %s",
124 NameListToString(aggtransfnName),
125 format_type_be(aggTransType))));
127 tup = SearchSysCache(PROCOID,
128 ObjectIdGetDatum(transfn),
129 0, 0, 0);
130 if (!HeapTupleIsValid(tup))
131 elog(ERROR, "cache lookup failed for function %u", transfn);
132 proc = (Form_pg_proc) GETSTRUCT(tup);
135 * If the transfn is strict and the initval is NULL, make sure first input
136 * type and transtype are the same (or at least binary-compatible), so
137 * that it's OK to use the first input value as the initial transValue.
139 if (proc->proisstrict && agginitval == NULL)
141 if (numArgs < 1 ||
142 !IsBinaryCoercible(aggArgTypes[0], aggTransType))
143 ereport(ERROR,
144 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
145 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
147 ReleaseSysCache(tup);
149 /* handle finalfn, if supplied */
150 if (aggfinalfnName)
152 fnArgs[0] = aggTransType;
153 finalfn = lookup_agg_function(aggfinalfnName, 1, fnArgs,
154 &finaltype);
156 else
159 * If no finalfn, aggregate result type is type of the state value
161 finaltype = aggTransType;
163 Assert(OidIsValid(finaltype));
166 * If finaltype (i.e. aggregate return type) is polymorphic, inputs must
167 * be polymorphic also, else parser will fail to deduce result type.
168 * (Note: given the previous test on transtype and inputs, this cannot
169 * happen, unless someone has snuck a finalfn definition into the catalogs
170 * that itself violates the rule against polymorphic result with no
171 * polymorphic input.)
173 if (IsPolymorphicType(finaltype) && !hasPolyArg)
174 ereport(ERROR,
175 (errcode(ERRCODE_DATATYPE_MISMATCH),
176 errmsg("cannot determine result data type"),
177 errdetail("An aggregate returning a polymorphic type "
178 "must have at least one polymorphic argument.")));
180 /* handle sortop, if supplied */
181 if (aggsortopName)
183 if (numArgs != 1)
184 ereport(ERROR,
185 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
186 errmsg("sort operator can only be specified for single-argument aggregates")));
187 sortop = LookupOperName(NULL, aggsortopName,
188 aggArgTypes[0], aggArgTypes[0],
189 false, -1);
193 * Everything looks okay. Try to create the pg_proc entry for the
194 * aggregate. (This could fail if there's already a conflicting entry.)
197 procOid = ProcedureCreate(aggName,
198 aggNamespace,
199 false, /* no replacement */
200 false, /* doesn't return a set */
201 finaltype, /* returnType */
202 INTERNALlanguageId, /* languageObjectId */
203 InvalidOid, /* no validator */
204 "aggregate_dummy", /* placeholder proc */
205 NULL, /* probin */
206 true, /* isAgg */
207 false, /* security invoker (currently not
208 * definable for agg) */
209 false, /* isStrict (not needed for agg) */
210 PROVOLATILE_IMMUTABLE, /* volatility (not
211 * needed for agg) */
212 buildoidvector(aggArgTypes,
213 numArgs), /* paramTypes */
214 PointerGetDatum(NULL), /* allParamTypes */
215 PointerGetDatum(NULL), /* parameterModes */
216 PointerGetDatum(NULL), /* parameterNames */
217 PointerGetDatum(NULL), /* proconfig */
218 1, /* procost */
219 0); /* prorows */
222 * Okay to create the pg_aggregate entry.
225 /* initialize nulls and values */
226 for (i = 0; i < Natts_pg_aggregate; i++)
228 nulls[i] = false;
229 values[i] = (Datum) NULL;
231 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
232 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
233 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
234 values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
235 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
236 if (agginitval)
237 values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
238 else
239 nulls[Anum_pg_aggregate_agginitval - 1] = true;
241 aggdesc = heap_open(AggregateRelationId, RowExclusiveLock);
242 tupDesc = aggdesc->rd_att;
244 tup = heap_form_tuple(tupDesc, values, nulls);
245 simple_heap_insert(aggdesc, tup);
247 CatalogUpdateIndexes(aggdesc, tup);
249 heap_close(aggdesc, RowExclusiveLock);
252 * Create dependencies for the aggregate (above and beyond those already
253 * made by ProcedureCreate). Note: we don't need an explicit dependency
254 * on aggTransType since we depend on it indirectly through transfn.
256 myself.classId = ProcedureRelationId;
257 myself.objectId = procOid;
258 myself.objectSubId = 0;
260 /* Depends on transition function */
261 referenced.classId = ProcedureRelationId;
262 referenced.objectId = transfn;
263 referenced.objectSubId = 0;
264 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
266 /* Depends on final function, if any */
267 if (OidIsValid(finalfn))
269 referenced.classId = ProcedureRelationId;
270 referenced.objectId = finalfn;
271 referenced.objectSubId = 0;
272 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
275 /* Depends on sort operator, if any */
276 if (OidIsValid(sortop))
278 referenced.classId = OperatorRelationId;
279 referenced.objectId = sortop;
280 referenced.objectSubId = 0;
281 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
286 * lookup_agg_function -- common code for finding both transfn and finalfn
288 static Oid
289 lookup_agg_function(List *fnName,
290 int nargs,
291 Oid *input_types,
292 Oid *rettype)
294 Oid fnOid;
295 bool retset;
296 int nvargs;
297 Oid *true_oid_array;
298 FuncDetailCode fdresult;
299 AclResult aclresult;
300 int i;
303 * func_get_detail looks up the function in the catalogs, does
304 * disambiguation for polymorphic functions, handles inheritance, and
305 * returns the funcid and type and set or singleton status of the
306 * function's return value. it also returns the true argument types to
307 * the function.
309 fdresult = func_get_detail(fnName, NIL, nargs, input_types, false,
310 &fnOid, rettype, &retset, &nvargs,
311 &true_oid_array);
313 /* only valid case is a normal function not returning a set */
314 if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
315 ereport(ERROR,
316 (errcode(ERRCODE_UNDEFINED_FUNCTION),
317 errmsg("function %s does not exist",
318 func_signature_string(fnName, nargs, input_types))));
319 if (retset)
320 ereport(ERROR,
321 (errcode(ERRCODE_DATATYPE_MISMATCH),
322 errmsg("function %s returns a set",
323 func_signature_string(fnName, nargs, input_types))));
326 * If there are any polymorphic types involved, enforce consistency, and
327 * possibly refine the result type. It's OK if the result is still
328 * polymorphic at this point, though.
330 *rettype = enforce_generic_type_consistency(input_types,
331 true_oid_array,
332 nargs,
333 *rettype,
334 true);
337 * func_get_detail will find functions requiring run-time argument type
338 * coercion, but nodeAgg.c isn't prepared to deal with that
340 for (i = 0; i < nargs; i++)
342 if (!IsPolymorphicType(true_oid_array[i]) &&
343 !IsBinaryCoercible(input_types[i], true_oid_array[i]))
344 ereport(ERROR,
345 (errcode(ERRCODE_DATATYPE_MISMATCH),
346 errmsg("function %s requires run-time type coercion",
347 func_signature_string(fnName, nargs, true_oid_array))));
350 /* Check aggregate creator has permission to call the function */
351 aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
352 if (aclresult != ACLCHECK_OK)
353 aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(fnOid));
355 return fnOid;