1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_aggregate relation
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.53 2002/08/05 03:29:16 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "catalog/catname.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/namespace.h"
22 #include "catalog/pg_aggregate.h"
23 #include "catalog/pg_language.h"
24 #include "catalog/pg_proc.h"
25 #include "optimizer/cost.h"
26 #include "parser/parse_coerce.h"
27 #include "parser/parse_func.h"
28 #include "utils/builtins.h"
29 #include "utils/syscache.h"
36 AggregateCreate(const char *aggName,
42 const char *agginitval)
46 char nulls[Natts_pg_aggregate];
47 Datum values[Natts_pg_aggregate];
50 Oid finalfn = InvalidOid; /* can be omitted */
52 Oid fnArgs[FUNC_MAX_ARGS];
62 elog(ERROR, "no aggregate name supplied");
65 elog(ERROR, "aggregate must have a transition function");
68 MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
69 fnArgs[0] = aggTransType;
70 if (OidIsValid(aggBaseType))
72 fnArgs[1] = aggBaseType;
77 transfn = LookupFuncName(aggtransfnName, nargs, fnArgs);
78 if (!OidIsValid(transfn))
79 func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
80 tup = SearchSysCache(PROCOID,
81 ObjectIdGetDatum(transfn),
83 if (!HeapTupleIsValid(tup))
84 func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
85 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));
91 * If the transfn is strict and the initval is NULL, make sure input
92 * type and transtype are the same (or at least binary-compatible),
93 * so that it's OK to use the first input value as the initial
96 if (proc->proisstrict && agginitval == NULL)
98 if (!IsBinaryCompatible(aggBaseType, aggTransType))
99 elog(ERROR, "must not omit initval when transfn is strict and transtype is not compatible with input type");
101 ReleaseSysCache(tup);
103 /* handle finalfn, if supplied */
106 MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
107 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),
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);
123 * If no finalfn, aggregate result type is type of the state value
125 finaltype = aggTransType;
127 Assert(OidIsValid(finaltype));
130 * Everything looks okay. Try to create the pg_proc entry for the
131 * aggregate. (This could fail if there's already a conflicting entry.)
133 MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
134 fnArgs[0] = aggBaseType;
136 procOid = ProcedureCreate(aggName,
138 false, /* no replacement */
139 false, /* doesn't return a set */
140 finaltype, /* returnType */
141 INTERNALlanguageId, /* languageObjectId */
143 "aggregate_dummy", /* placeholder proc */
146 false, /* security invoker (currently not definable for agg) */
147 false, /* isStrict (not needed for agg) */
148 PROVOLATILE_IMMUTABLE, /* volatility (not needed for agg) */
149 1, /* parameterCount */
150 fnArgs); /* parameterTypes */
153 * Okay to create the pg_aggregate entry.
156 /* initialize nulls and values */
157 for (i = 0; i < Natts_pg_aggregate; i++)
160 values[i] = (Datum) NULL;
162 values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
163 values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
164 values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
165 values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
167 values[Anum_pg_aggregate_agginitval - 1] =
168 DirectFunctionCall1(textin, CStringGetDatum(agginitval));
170 nulls[Anum_pg_aggregate_agginitval - 1] = 'n';
172 aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
173 tupDesc = aggdesc->rd_att;
175 tup = heap_formtuple(tupDesc, values, nulls);
176 simple_heap_insert(aggdesc, tup);
178 CatalogUpdateIndexes(aggdesc, tup);
180 heap_close(aggdesc, RowExclusiveLock);
183 * Create dependencies for the aggregate (above and beyond those
184 * already made by ProcedureCreate). Note: we don't need an explicit
185 * dependency on aggTransType since we depend on it indirectly through
188 myself.classId = RelOid_pg_proc;
189 myself.objectId = procOid;
190 myself.objectSubId = 0;
192 /* Depends on transition function */
193 referenced.classId = RelOid_pg_proc;
194 referenced.objectId = transfn;
195 referenced.objectSubId = 0;
196 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
198 /* Depends on final function, if any */
199 if (OidIsValid(finalfn))
201 referenced.classId = RelOid_pg_proc;
202 referenced.objectId = finalfn;
203 referenced.objectSubId = 0;
204 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);