1 /*-------------------------------------------------------------------------
5 * Routines for aggregate-manipulation commands
7 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/commands/aggregatecmds.c
15 * The "DefineFoo" routines take the parse tree and pick out the
16 * appropriate arguments/flags, passing the results to the
17 * corresponding "FooDefine" routines (in src/catalog) that do
18 * the actual catalog-munging. These routines also verify permission
19 * of the user to execute the command.
21 *-------------------------------------------------------------------------
25 #include "access/heapam.h"
26 #include "access/htup_details.h"
27 #include "catalog/dependency.h"
28 #include "catalog/indexing.h"
29 #include "catalog/pg_aggregate.h"
30 #include "catalog/pg_proc.h"
31 #include "catalog/pg_type.h"
32 #include "commands/defrem.h"
33 #include "miscadmin.h"
34 #include "parser/parse_func.h"
35 #include "parser/parse_type.h"
36 #include "utils/acl.h"
37 #include "utils/builtins.h"
38 #include "utils/lsyscache.h"
39 #include "utils/syscache.h"
45 * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
46 * is specified by a BASETYPE element in the parameters. Otherwise,
47 * "args" defines the input type(s).
50 DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
55 List *transfuncName = NIL;
56 List *finalfuncName = NIL;
57 List *sortoperatorName = NIL;
58 TypeName *baseType = NULL;
59 TypeName *transType = NULL;
66 /* Convert list of names to a name and namespace */
67 aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
69 /* Check we have creation rights in target namespace */
70 aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
71 if (aclresult != ACLCHECK_OK)
72 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
73 get_namespace_name(aggNamespace));
75 foreach(pl, parameters)
77 DefElem *defel = (DefElem *) lfirst(pl);
80 * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
81 * for sfunc, stype, initcond.
83 if (pg_strcasecmp(defel->defname, "sfunc") == 0)
84 transfuncName = defGetQualifiedName(defel);
85 else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
86 transfuncName = defGetQualifiedName(defel);
87 else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
88 finalfuncName = defGetQualifiedName(defel);
89 else if (pg_strcasecmp(defel->defname, "sortop") == 0)
90 sortoperatorName = defGetQualifiedName(defel);
91 else if (pg_strcasecmp(defel->defname, "basetype") == 0)
92 baseType = defGetTypeName(defel);
93 else if (pg_strcasecmp(defel->defname, "stype") == 0)
94 transType = defGetTypeName(defel);
95 else if (pg_strcasecmp(defel->defname, "stype1") == 0)
96 transType = defGetTypeName(defel);
97 else if (pg_strcasecmp(defel->defname, "initcond") == 0)
98 initval = defGetString(defel);
99 else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
100 initval = defGetString(defel);
103 (errcode(ERRCODE_SYNTAX_ERROR),
104 errmsg("aggregate attribute \"%s\" not recognized",
109 * make sure we have our required definitions
111 if (transType == NULL)
113 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
114 errmsg("aggregate stype must be specified")));
115 if (transfuncName == NIL)
117 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
118 errmsg("aggregate sfunc must be specified")));
121 * look up the aggregate's input datatype(s).
126 * Old style: use basetype parameter. This supports aggregates of
127 * zero or one input, with input type ANY meaning zero inputs.
129 * Historically we allowed the command to look like basetype = 'ANY'
130 * so we must do a case-insensitive comparison for the name ANY. Ugh.
132 if (baseType == NULL)
134 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
135 errmsg("aggregate input type must be specified")));
137 if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
145 aggArgTypes = (Oid *) palloc(sizeof(Oid));
146 aggArgTypes[0] = typenameTypeId(NULL, baseType);
152 * New style: args is a list of TypeNames (possibly zero of 'em).
157 if (baseType != NULL)
159 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
160 errmsg("basetype is redundant with aggregate input type specification")));
162 numArgs = list_length(args);
163 aggArgTypes = (Oid *) palloc(sizeof(Oid) * numArgs);
166 TypeName *curTypeName = (TypeName *) lfirst(lc);
168 aggArgTypes[i++] = typenameTypeId(NULL, curTypeName);
173 * look up the aggregate's transtype.
175 * transtype can't be a pseudo-type, since we need to be able to store
176 * values of the transtype. However, we can allow polymorphic transtype
177 * in some cases (AggregateCreate will check). Also, we allow "internal"
178 * for functions that want to pass pointers to private data structures;
179 * but allow that only to superusers, since you could crash the system (or
180 * worse) by connecting up incompatible internal-using functions in an
183 transTypeId = typenameTypeId(NULL, transType);
184 if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
185 !IsPolymorphicType(transTypeId))
187 if (transTypeId == INTERNALOID && superuser())
191 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
192 errmsg("aggregate transition data type cannot be %s",
193 format_type_be(transTypeId))));
197 * Most of the argument-checking is done inside of AggregateCreate
199 AggregateCreate(aggName, /* aggregate name */
200 aggNamespace, /* namespace */
201 aggArgTypes, /* input data type(s) */
203 transfuncName, /* step function name */
204 finalfuncName, /* final function name */
205 sortoperatorName, /* sort operator name */
206 transTypeId, /* transition data type */
207 initval); /* initial condition */
213 * Rename an aggregate.
216 RenameAggregate(List *name, List *args, const char *newname)
221 Form_pg_proc procForm;
225 rel = heap_open(ProcedureRelationId, RowExclusiveLock);
227 /* Look up function and make sure it's an aggregate */
228 procOid = LookupAggNameTypeNames(name, args, false);
230 tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
231 if (!HeapTupleIsValid(tup)) /* should not happen */
232 elog(ERROR, "cache lookup failed for function %u", procOid);
233 procForm = (Form_pg_proc) GETSTRUCT(tup);
235 namespaceOid = procForm->pronamespace;
237 /* make sure the new name doesn't exist */
238 if (SearchSysCacheExists3(PROCNAMEARGSNSP,
239 CStringGetDatum(newname),
240 PointerGetDatum(&procForm->proargtypes),
241 ObjectIdGetDatum(namespaceOid)))
243 (errcode(ERRCODE_DUPLICATE_FUNCTION),
244 errmsg("function %s already exists in schema \"%s\"",
245 funcname_signature_string(newname,
248 procForm->proargtypes.values),
249 get_namespace_name(namespaceOid))));
252 if (!pg_proc_ownercheck(procOid, GetUserId()))
253 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
254 NameListToString(name));
256 /* must have CREATE privilege on namespace */
257 aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
258 if (aclresult != ACLCHECK_OK)
259 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
260 get_namespace_name(namespaceOid));
263 namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname);
264 simple_heap_update(rel, &tup->t_self, tup);
265 CatalogUpdateIndexes(rel, tup);
267 heap_close(rel, NoLock);