<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.33 2005/11/04 23:14:02 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.34 2006/04/15 17:45:18 tgl Exp $
PostgreSQL documentation
-->
<refsynopsisdiv>
<synopsis>
+CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_data_type</replaceable> ) (
+ SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
+ STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
+ [ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
+ [ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
+ [ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
+)
+
+or the old syntax
+
CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
- BASETYPE = <replaceable class="PARAMETER">input_data_type</replaceable>,
+ BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
<para>
An aggregate function may provide an initial condition,
that is, an initial value for the internal state value.
- This is specified and stored in the database as a column of type
+ This is specified and stored in the database as a value of type
<type>text</type>, but it must be a valid external representation
of a constant of the state value data type. If it is not supplied
then the state value starts out null.
Ordinarily, a data type's <literal><</> operator is the proper sort
operator for <function>MIN</>, and <literal>></> is the proper sort
operator for <function>MAX</>. Note that the optimization will never
- actually take effect unless the specified operator is the <quote>less than</quote> or
- <quote>greater than</quote> strategy member of a B-tree index operator class.
+ actually take effect unless the specified operator is the <quote>less
+ than</quote> or <quote>greater than</quote> strategy member of a B-tree
+ index operator class.
</para>
</refsect1>
<listitem>
<para>
The input data type on which this aggregate function operates.
- This can be specified as <literal>"ANY"</> for an aggregate that
+ This can be specified as <literal>*</> for an aggregate that
does not examine its input values (an example is
<function>count(*)</function>).
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable class="PARAMETER">base_type</replaceable></term>
+ <listitem>
+ <para>
+ In the old syntax for <command>CREATE AGGREGATE</>, the input data type
+ is specified by a <literal>basetype</> parameter rather than being
+ written next to the aggregate name. Note that this syntax allows
+ only one input parameter. To define an aggregate that does not examine
+ its input values, specify the <literal>basetype</> as
+ <literal>"ANY"</> (not <literal>*</>).
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><replaceable class="PARAMETER">sfunc</replaceable></term>
<listitem>
-<!-- $PostgreSQL: pgsql/doc/src/sgml/xaggr.sgml,v 1.30 2006/03/10 19:10:49 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/xaggr.sgml,v 1.31 2006/04/15 17:45:33 tgl Exp $ -->
<sect1 id="xaggr">
<title>User-Defined Aggregates</title>
The aggregate definition would be:
<screen>
-CREATE AGGREGATE complex_sum (
+CREATE AGGREGATE sum (complex)
+(
sfunc = complex_add,
- basetype = complex,
stype = complex,
initcond = '(0,0)'
);
-SELECT complex_sum(a) FROM test_complex;
+SELECT sum(a) FROM test_complex;
- complex_sum
--------------
+ sum
+-----------
(34,53.9)
</screen>
- (In practice, we'd just name the aggregate <function>sum</function> and rely on
- <productname>PostgreSQL</productname> to figure out which kind
- of sum to apply to a column of type <type>complex</type>.)
+ (Notice that we are relying on function overloading: there is more than
+ one aggregate named <function>sum</>, but
+ <productname>PostgreSQL</productname> can figure out which kind
+ of sum applies to a column of type <type>complex</type>.)
</para>
<para>
looks like:
<programlisting>
-CREATE AGGREGATE avg (
+CREATE AGGREGATE avg (float8)
+(
sfunc = float8_accum,
- basetype = float8,
stype = float8[],
finalfunc = float8_avg,
initcond = '{0,0}'
See <xref linkend="extend-types-polymorphic">
for an explanation of polymorphic functions.
Going a step further, the aggregate function itself may be specified
- with a polymorphic base type and state type, allowing a single
+ with a polymorphic input type and state type, allowing a single
aggregate definition to serve for multiple input data types.
Here is an example of a polymorphic aggregate:
<programlisting>
-CREATE AGGREGATE array_accum (
+CREATE AGGREGATE array_accum (anyelement)
+(
sfunc = array_append,
- basetype = anyelement,
stype = anyarray,
initcond = '{}'
);
<programlisting>
if (fcinfo->context && IsA(fcinfo->context, AggState))
</programlisting>
- One reason for checking this is that when it is true, the left input
+ One reason for checking this is that when it is true, the first input
must be a temporary transition value and can therefore safely be modified
in-place rather than allocating a new copy. (This is the <emphasis>only</>
case where it is safe for a function to modify a pass-by-reference input.)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.33 2006/03/14 22:48:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.34 2006/04/15 17:45:33 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
/*
* DefineAggregate
+ *
+ * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
+ * is specified by a BASETYPE element in the parameters. Otherwise,
+ * "args" defines the input type(s).
*/
void
-DefineAggregate(List *names, List *parameters)
+DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
{
char *aggName;
Oid aggNamespace;
ListCell *pl;
/* Convert list of names to a name and namespace */
- aggNamespace = QualifiedNameGetCreationNamespace(names, &aggName);
+ aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
/*
* make sure we have our required definitions
*/
- if (baseType == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("aggregate basetype must be specified")));
if (transType == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate sfunc must be specified")));
/*
- * look up the aggregate's base type (input datatype) and transtype.
- *
- * We have historically allowed the command to look like basetype = 'ANY'
- * so we must do a case-insensitive comparison for the name ANY. Ugh.
+ * look up the aggregate's input datatype.
+ */
+ if (oldstyle)
+ {
+ /*
+ * Old style: use basetype parameter. This supports only one input.
+ *
+ * Historically we allowed the command to look like basetype = 'ANY'
+ * so we must do a case-insensitive comparison for the name ANY. Ugh.
+ */
+ if (baseType == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("aggregate input type must be specified")));
+
+ if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
+ baseTypeId = ANYOID;
+ else
+ baseTypeId = typenameTypeId(NULL, baseType);
+ }
+ else
+ {
+ /*
+ * New style: args is a list of TypeNames. For the moment, though,
+ * we allow at most one.
+ */
+ if (baseType != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("basetype is redundant with aggregate input type specification")));
+
+ if (args == NIL)
+ {
+ /* special case for agg(*) */
+ baseTypeId = ANYOID;
+ }
+ else if (list_length(args) != 1)
+ {
+ /* temporarily reject > 1 arg */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("aggregates can have only one input")));
+ baseTypeId = InvalidOid; /* keep compiler quiet */
+ }
+ else
+ {
+ baseTypeId = typenameTypeId(NULL, (TypeName *) linitial(args));
+ }
+ }
+
+ /*
+ * look up the aggregate's transtype.
*
- * basetype can be a pseudo-type, but transtype can't, since we need to be
+ * transtype can't be a pseudo-type, since we need to be
* able to store values of the transtype. However, we can allow
* polymorphic transtype in some cases (AggregateCreate will check).
*/
- if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
- baseTypeId = ANYOID;
- else
- baseTypeId = typenameTypeId(NULL, baseType);
-
transTypeId = typenameTypeId(NULL, transType);
if (get_typtype(transTypeId) == 'p' &&
transTypeId != ANYARRAYOID &&
* Deletes an aggregate.
*/
void
-RemoveAggregate(RemoveAggrStmt *stmt)
+RemoveAggregate(RemoveFuncStmt *stmt)
{
- List *aggName = stmt->aggname;
- TypeName *aggType = stmt->aggtype;
- Oid basetypeID;
+ List *aggName = stmt->name;
+ List *aggArgs = stmt->args;
Oid procOid;
HeapTuple tup;
ObjectAddress object;
- /*
- * if a basetype is passed in, then attempt to find an aggregate for that
- * specific type.
- *
- * else attempt to find an aggregate with a basetype of ANYOID. This means
- * that the aggregate is to apply to all basetypes (eg, COUNT).
- */
- if (aggType)
- basetypeID = typenameTypeId(NULL, aggType);
- else
- basetypeID = ANYOID;
-
- procOid = find_aggregate_func(aggName, basetypeID, false);
+ /* Look up function and make sure it's an aggregate */
+ procOid = LookupAggNameTypeNames(aggName, aggArgs, false);
/*
* Find the function tuple, do permissions and validity checks
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(aggName));
- /* find_aggregate_func already checked it is an aggregate */
-
ReleaseSysCache(tup);
/*
void
-RenameAggregate(List *name, TypeName *basetype, const char *newname)
+RenameAggregate(List *name, List *args, const char *newname)
{
- Oid basetypeOid;
Oid procOid;
Oid namespaceOid;
HeapTuple tup;
Relation rel;
AclResult aclresult;
- /*
- * if a basetype is passed in, then attempt to find an aggregate for that
- * specific type; else attempt to find an aggregate with a basetype of
- * ANYOID. This means that the aggregate applies to all basetypes (eg,
- * COUNT).
- */
- if (basetype)
- basetypeOid = typenameTypeId(NULL, basetype);
- else
- basetypeOid = ANYOID;
-
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
- procOid = find_aggregate_func(name, basetypeOid, false);
+ /* Look up function and make sure it's an aggregate */
+ procOid = LookupAggNameTypeNames(name, args, false);
tup = SearchSysCacheCopy(PROCOID,
ObjectIdGetDatum(procOid),
PointerGetDatum(&procForm->proargtypes),
ObjectIdGetDatum(namespaceOid),
0))
- {
- if (basetypeOid == ANYOID)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_FUNCTION),
- errmsg("function %s(*) already exists in schema \"%s\"",
- newname,
- get_namespace_name(namespaceOid))));
- else
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_FUNCTION),
- errmsg("function %s already exists in schema \"%s\"",
- funcname_signature_string(newname,
- procForm->pronargs,
- procForm->proargtypes.values),
- get_namespace_name(namespaceOid))));
- }
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_FUNCTION),
+ errmsg("function %s already exists in schema \"%s\"",
+ funcname_signature_string(newname,
+ procForm->pronargs,
+ procForm->proargtypes.values),
+ get_namespace_name(namespaceOid))));
/* must be owner */
if (!pg_proc_ownercheck(procOid, GetUserId()))
* Change aggregate owner
*/
void
-AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId)
+AlterAggregateOwner(List *name, List *args, Oid newOwnerId)
{
- Oid basetypeOid;
Oid procOid;
HeapTuple tup;
Form_pg_proc procForm;
Relation rel;
AclResult aclresult;
- /*
- * if a basetype is passed in, then attempt to find an aggregate for that
- * specific type; else attempt to find an aggregate with a basetype of
- * ANYOID. This means that the aggregate applies to all basetypes (eg,
- * COUNT).
- */
- if (basetype)
- basetypeOid = typenameTypeId(NULL, basetype);
- else
- basetypeOid = ANYOID;
-
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
- procOid = find_aggregate_func(name, basetypeOid, false);
+ /* Look up function and make sure it's an aggregate */
+ procOid = LookupAggNameTypeNames(name, args, false);
tup = SearchSysCacheCopy(PROCOID,
ObjectIdGetDatum(procOid),
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.18 2006/03/05 15:58:23 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.19 2006/04/15 17:45:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
switch (stmt->renameType)
{
case OBJECT_AGGREGATE:
- RenameAggregate(stmt->object,
- (TypeName *) linitial(stmt->objarg),
- stmt->newname);
+ RenameAggregate(stmt->object, stmt->objarg, stmt->newname);
break;
case OBJECT_CONVERSION:
switch (stmt->objectType)
{
case OBJECT_AGGREGATE:
+ AlterFunctionNamespace(stmt->object, stmt->objarg, true,
+ stmt->newschema);
+ break;
+
case OBJECT_FUNCTION:
- AlterFunctionNamespace(stmt->object, stmt->objarg,
+ AlterFunctionNamespace(stmt->object, stmt->objarg, false,
stmt->newschema);
break;
switch (stmt->objectType)
{
case OBJECT_AGGREGATE:
- AlterAggregateOwner(stmt->object,
- (TypeName *) linitial(stmt->objarg),
- newowner);
+ AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
break;
case OBJECT_CONVERSION:
break;
case OBJECT_OPERATOR:
+ Assert(list_length(stmt->objarg) == 2);
AlterOperatorOwner(stmt->object,
(TypeName *) linitial(stmt->objarg),
(TypeName *) lsecond(stmt->objarg),
* Copyright (c) 1996-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.88 2006/03/14 22:48:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.89 2006/04/15 17:45:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* This routine is used to allow a user to provide comments on an
* aggregate function. The aggregate function is determined by both
- * its name and its argument type, which, with the comments are
- * the three parameters handed to this routine.
+ * its name and its argument type(s).
*/
static void
CommentAggregate(List *aggregate, List *arguments, char *comment)
{
- TypeName *aggtype = (TypeName *) linitial(arguments);
- Oid baseoid,
- oid;
-
- /* First, attempt to determine the base aggregate oid */
- if (aggtype)
- baseoid = typenameTypeId(NULL, aggtype);
- else
- baseoid = ANYOID;
-
- /* Now, attempt to find the actual tuple in pg_proc */
+ Oid oid;
- oid = find_aggregate_func(aggregate, baseoid, false);
+ /* Look up function and make sure it's an aggregate */
+ oid = LookupAggNameTypeNames(aggregate, arguments, false);
/* Next, validate the user's attempt to comment */
-
if (!pg_proc_ownercheck(oid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(aggregate));
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.73 2006/03/14 22:48:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.74 2006/04/15 17:45:34 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
void
RemoveFunction(RemoveFuncStmt *stmt)
{
- List *functionName = stmt->funcname;
+ List *functionName = stmt->name;
List *argTypes = stmt->args; /* list of TypeName nodes */
Oid funcOid;
HeapTuple tup;
}
/*
- * Execute ALTER FUNCTION SET SCHEMA
+ * Execute ALTER FUNCTION/AGGREGATE SET SCHEMA
+ *
+ * These commands are identical except for the lookup procedure, so share code.
*/
void
-AlterFunctionNamespace(List *name, List *argtypes, const char *newschema)
+AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
+ const char *newschema)
{
Oid procOid;
Oid oldNspOid;
procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
/* get function OID */
- procOid = LookupFuncNameTypeNames(name, argtypes, false);
+ if (isagg)
+ procOid = LookupAggNameTypeNames(name, argtypes, false);
+ else
+ procOid = LookupFuncNameTypeNames(name, argtypes, false);
/* check permissions on function */
if (!pg_proc_ownercheck(procOid, GetUserId()))
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.29 2006/03/14 22:48:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.30 2006/04/15 17:45:34 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
* Deletes an operator.
*/
void
-RemoveOperator(RemoveOperStmt *stmt)
+RemoveOperator(RemoveFuncStmt *stmt)
{
- List *operatorName = stmt->opname;
+ List *operatorName = stmt->name;
TypeName *typeName1 = (TypeName *) linitial(stmt->args);
TypeName *typeName2 = (TypeName *) lsecond(stmt->args);
Oid operOid;
HeapTuple tup;
ObjectAddress object;
+ Assert(list_length(stmt->args) == 2);
operOid = LookupOperNameTypeNames(NULL, operatorName,
typeName1, typeName2,
false, -1);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.332 2006/03/23 00:19:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.333 2006/04/15 17:45:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
DefineStmt *newnode = makeNode(DefineStmt);
COPY_SCALAR_FIELD(kind);
+ COPY_SCALAR_FIELD(oldstyle);
COPY_NODE_FIELD(defnames);
+ COPY_NODE_FIELD(args);
COPY_NODE_FIELD(definition);
return newnode;
return newnode;
}
-static RemoveAggrStmt *
-_copyRemoveAggrStmt(RemoveAggrStmt *from)
-{
- RemoveAggrStmt *newnode = makeNode(RemoveAggrStmt);
-
- COPY_NODE_FIELD(aggname);
- COPY_NODE_FIELD(aggtype);
- COPY_SCALAR_FIELD(behavior);
-
- return newnode;
-}
-
static RemoveFuncStmt *
_copyRemoveFuncStmt(RemoveFuncStmt *from)
{
RemoveFuncStmt *newnode = makeNode(RemoveFuncStmt);
- COPY_NODE_FIELD(funcname);
- COPY_NODE_FIELD(args);
- COPY_SCALAR_FIELD(behavior);
-
- return newnode;
-}
-
-static RemoveOperStmt *
-_copyRemoveOperStmt(RemoveOperStmt *from)
-{
- RemoveOperStmt *newnode = makeNode(RemoveOperStmt);
-
- COPY_NODE_FIELD(opname);
+ COPY_SCALAR_FIELD(kind);
+ COPY_NODE_FIELD(name);
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(behavior);
case T_AlterFunctionStmt:
retval = _copyAlterFunctionStmt(from);
break;
- case T_RemoveAggrStmt:
- retval = _copyRemoveAggrStmt(from);
- break;
case T_RemoveFuncStmt:
retval = _copyRemoveFuncStmt(from);
break;
- case T_RemoveOperStmt:
- retval = _copyRemoveOperStmt(from);
- break;
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.268 2006/03/23 00:19:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.269 2006/04/15 17:45:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
_equalDefineStmt(DefineStmt *a, DefineStmt *b)
{
COMPARE_SCALAR_FIELD(kind);
+ COMPARE_SCALAR_FIELD(oldstyle);
COMPARE_NODE_FIELD(defnames);
+ COMPARE_NODE_FIELD(args);
COMPARE_NODE_FIELD(definition);
return true;
return true;
}
-static bool
-_equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b)
-{
- COMPARE_NODE_FIELD(aggname);
- COMPARE_NODE_FIELD(aggtype);
- COMPARE_SCALAR_FIELD(behavior);
-
- return true;
-}
-
static bool
_equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
{
- COMPARE_NODE_FIELD(funcname);
- COMPARE_NODE_FIELD(args);
- COMPARE_SCALAR_FIELD(behavior);
-
- return true;
-}
-
-static bool
-_equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
-{
- COMPARE_NODE_FIELD(opname);
+ COMPARE_SCALAR_FIELD(kind);
+ COMPARE_NODE_FIELD(name);
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(behavior);
case T_AlterFunctionStmt:
retval = _equalAlterFunctionStmt(a, b);
break;
- case T_RemoveAggrStmt:
- retval = _equalRemoveAggrStmt(a, b);
- break;
case T_RemoveFuncStmt:
retval = _equalRemoveFuncStmt(a, b);
break;
- case T_RemoveOperStmt:
- retval = _equalRemoveOperStmt(a, b);
- break;
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.537 2006/03/23 00:19:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.538 2006/04/15 17:45:34 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
- opt_distinct opt_definition func_args
- func_args_list func_as createfunc_opt_list alterfunc_opt_list
+ opt_distinct opt_definition func_args func_args_list
+ func_as createfunc_opt_list alterfunc_opt_list
+ aggr_args aggr_args_list old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti
opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
%type <defelt> createfunc_opt_item common_func_opt_item
%type <fun_param> func_arg
%type <fun_param_mode> arg_class
-%type <typnam> func_return func_type aggr_argtype
+%type <typnam> func_return func_type
%type <boolean> TriggerForType OptTemp
%type <oncommit> OnCommitOption
%type <node> TableElement ConstraintElem TableFuncElement
%type <node> columnDef
-%type <defelt> def_elem
+%type <defelt> def_elem old_aggr_elem
%type <node> def_arg columnElem where_clause
a_expr b_expr c_expr func_expr AexprConst indirection_el
columnref in_expr having_clause func_table array_expr
*****************************************************************************/
DefineStmt:
- CREATE AGGREGATE func_name definition
+ CREATE AGGREGATE func_name aggr_args definition
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_AGGREGATE;
+ n->oldstyle = false;
n->defnames = $3;
+ n->args = $4;
+ n->definition = $5;
+ $$ = (Node *)n;
+ }
+ | CREATE AGGREGATE func_name old_aggr_definition
+ {
+ /* old-style (pre-8.2) syntax for CREATE AGGREGATE */
+ DefineStmt *n = makeNode(DefineStmt);
+ n->kind = OBJECT_AGGREGATE;
+ n->oldstyle = true;
+ n->defnames = $3;
+ n->args = NIL;
n->definition = $4;
$$ = (Node *)n;
}
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_OPERATOR;
+ n->oldstyle = false;
n->defnames = $3;
+ n->args = NIL;
n->definition = $4;
$$ = (Node *)n;
}
{
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_TYPE;
+ n->oldstyle = false;
n->defnames = $3;
+ n->args = NIL;
n->definition = $4;
$$ = (Node *)n;
}
/* Shell type (identified by lack of definition) */
DefineStmt *n = makeNode(DefineStmt);
n->kind = OBJECT_TYPE;
+ n->oldstyle = false;
n->defnames = $3;
+ n->args = NIL;
n->definition = NIL;
$$ = (Node *)n;
}
| Sconst { $$ = (Node *)makeString($1); }
;
+aggr_args: '(' aggr_args_list ')' { $$ = $2; }
+ | '(' '*' ')' { $$ = NIL; }
+ ;
+
+aggr_args_list:
+ Typename { $$ = list_make1($1); }
+ | aggr_args_list ',' Typename { $$ = lappend($1, $3); }
+ ;
+
+old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; }
+ ;
+
+old_aggr_list: old_aggr_elem { $$ = list_make1($1); }
+ | old_aggr_list ',' old_aggr_elem { $$ = lappend($1, $3); }
+ ;
+
+old_aggr_elem: IDENT '=' def_arg
+ {
+ $$ = makeDefElem($1, (Node *)$3);
+ }
+ ;
+
/*****************************************************************************
*
* COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
* CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
* CAST | COLUMN | SCHEMA | TABLESPACE | ROLE ] <objname> |
- * AGGREGATE <aggname> (<aggtype>) |
+ * AGGREGATE <aggname> (arg1, ...) |
* FUNCTION <funcname> (arg1, arg2, ...) |
* OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
* TRIGGER <triggername> ON <relname> |
n->comment = $6;
$$ = (Node *) n;
}
- | COMMENT ON AGGREGATE func_name '(' aggr_argtype ')'
- IS comment_text
+ | COMMENT ON AGGREGATE func_name aggr_args IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
n->objtype = OBJECT_AGGREGATE;
n->objname = $4;
- n->objargs = list_make1($6);
- n->comment = $9;
+ n->objargs = $5;
+ n->comment = $7;
$$ = (Node *) n;
}
| COMMENT ON FUNCTION func_name func_args IS comment_text
* QUERY:
*
* DROP FUNCTION funcname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
- * DROP AGGREGATE aggname (aggtype) [ RESTRICT | CASCADE ]
+ * DROP AGGREGATE aggname (arg1, ...) [ RESTRICT | CASCADE ]
* DROP OPERATOR opname (leftoperand_typ, rightoperand_typ) [ RESTRICT | CASCADE ]
*
*****************************************************************************/
DROP FUNCTION func_name func_args opt_drop_behavior
{
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
- n->funcname = $3;
+ n->kind = OBJECT_FUNCTION;
+ n->name = $3;
n->args = extractArgTypes($4);
n->behavior = $5;
$$ = (Node *)n;
;
RemoveAggrStmt:
- DROP AGGREGATE func_name '(' aggr_argtype ')' opt_drop_behavior
+ DROP AGGREGATE func_name aggr_args opt_drop_behavior
{
- RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
- n->aggname = $3;
- n->aggtype = $5;
- n->behavior = $7;
- $$ = (Node *)n;
+ RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
+ n->kind = OBJECT_AGGREGATE;
+ n->name = $3;
+ n->args = $4;
+ n->behavior = $5;
+ $$ = (Node *)n;
}
;
-aggr_argtype:
- Typename { $$ = $1; }
- | '*' { $$ = NULL; }
- ;
-
RemoveOperStmt:
DROP OPERATOR any_operator '(' oper_argtypes ')' opt_drop_behavior
{
- RemoveOperStmt *n = makeNode(RemoveOperStmt);
- n->opname = $3;
+ RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
+ n->kind = OBJECT_OPERATOR;
+ n->name = $3;
n->args = $5;
n->behavior = $7;
$$ = (Node *)n;
*
*****************************************************************************/
-RenameStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' RENAME TO name
+RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_AGGREGATE;
n->object = $3;
- n->objarg = list_make1($5);
- n->newname = $9;
+ n->objarg = $4;
+ n->newname = $7;
$$ = (Node *)n;
}
| ALTER CONVERSION_P any_name RENAME TO name
*****************************************************************************/
AlterObjectSchemaStmt:
- ALTER AGGREGATE func_name '(' aggr_argtype ')' SET SCHEMA name
+ ALTER AGGREGATE func_name aggr_args SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_AGGREGATE;
n->object = $3;
- n->objarg = list_make1($5);
- n->newschema = $9;
+ n->objarg = $4;
+ n->newschema = $7;
$$ = (Node *)n;
}
| ALTER DOMAIN_P any_name SET SCHEMA name
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
n->object = $3;
- n->objarg = list_make1($5);
- n->newowner = $9;
+ n->objarg = $4;
+ n->newowner = $7;
$$ = (Node *)n;
}
| ALTER CONVERSION_P any_name OWNER TO RoleId
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.185 2006/03/14 22:48:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.186 2006/04/15 17:45:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
nargs, argtypes);
}
-/*
- * find_aggregate_func
- * Convenience routine to check that a function exists and is an
- * aggregate.
- *
- * Note: basetype is ANYOID if we are looking for an aggregate on
- * all types.
- */
-Oid
-find_aggregate_func(List *aggname, Oid basetype, bool noError)
-{
- Oid oid;
- HeapTuple ftup;
- Form_pg_proc pform;
-
- oid = LookupFuncName(aggname, 1, &basetype, true);
-
- if (!OidIsValid(oid))
- {
- if (noError)
- return InvalidOid;
- if (basetype == ANYOID)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_FUNCTION),
- errmsg("aggregate %s(*) does not exist",
- NameListToString(aggname))));
- else
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_FUNCTION),
- errmsg("aggregate %s(%s) does not exist",
- NameListToString(aggname),
- format_type_be(basetype))));
- }
-
- /* Make sure it's an aggregate */
- ftup = SearchSysCache(PROCOID,
- ObjectIdGetDatum(oid),
- 0, 0, 0);
- if (!HeapTupleIsValid(ftup)) /* should not happen */
- elog(ERROR, "cache lookup failed for function %u", oid);
- pform = (Form_pg_proc) GETSTRUCT(ftup);
-
- if (!pform->proisagg)
- {
- ReleaseSysCache(ftup);
- if (noError)
- return InvalidOid;
- /* we do not use the (*) notation for functions... */
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("function %s(%s) is not an aggregate",
- NameListToString(aggname), format_type_be(basetype))));
- }
-
- ReleaseSysCache(ftup);
-
- return oid;
-}
-
/*
* LookupFuncName
* Given a possibly-qualified function name and a set of argument types,
return LookupFuncName(funcname, argcount, argoids, noError);
}
+
+/*
+ * LookupAggNameTypeNames
+ * Find an aggregate function given a name and list of TypeName nodes.
+ *
+ * This is almost like LookupFuncNameTypeNames, but the error messages refer
+ * to aggregates rather than plain functions, and we verify that the found
+ * function really is an aggregate, and we recognize the convention used by
+ * the grammar that agg(*) translates to a NIL list, which we have to treat
+ * as one ANY argument. (XXX this ought to be changed)
+ */
+Oid
+LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
+{
+ Oid argoids[FUNC_MAX_ARGS];
+ int argcount;
+ int i;
+ ListCell *args_item;
+ Oid oid;
+ HeapTuple ftup;
+ Form_pg_proc pform;
+
+ argcount = list_length(argtypes);
+ if (argcount > FUNC_MAX_ARGS)
+ ereport(ERROR,
+ (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
+ errmsg("functions cannot have more than %d arguments",
+ FUNC_MAX_ARGS)));
+
+ if (argcount == 0)
+ {
+ /* special case for agg(*) */
+ argoids[0] = ANYOID;
+ argcount = 1;
+ }
+ else
+ {
+ args_item = list_head(argtypes);
+ for (i = 0; i < argcount; i++)
+ {
+ TypeName *t = (TypeName *) lfirst(args_item);
+
+ argoids[i] = LookupTypeName(NULL, t);
+
+ if (!OidIsValid(argoids[i]))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type \"%s\" does not exist",
+ TypeNameToString(t))));
+
+ args_item = lnext(args_item);
+ }
+ }
+
+ oid = LookupFuncName(aggname, argcount, argoids, true);
+
+ if (!OidIsValid(oid))
+ {
+ if (noError)
+ return InvalidOid;
+ if (argcount == 1 && argoids[0] == ANYOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("aggregate %s(*) does not exist",
+ NameListToString(aggname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("aggregate %s does not exist",
+ func_signature_string(aggname,
+ argcount, argoids))));
+ }
+
+ /* Make sure it's an aggregate */
+ ftup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(ftup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for function %u", oid);
+ pform = (Form_pg_proc) GETSTRUCT(ftup);
+
+ if (!pform->proisagg)
+ {
+ ReleaseSysCache(ftup);
+ if (noError)
+ return InvalidOid;
+ /* we do not use the (*) notation for functions... */
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s is not an aggregate",
+ func_signature_string(aggname,
+ argcount, argoids))));
+ }
+
+ ReleaseSysCache(ftup);
+
+ return oid;
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.255 2006/03/05 15:58:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.256 2006/04/15 17:45:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
case T_CreateTrigStmt:
case T_CompositeTypeStmt:
case T_ViewStmt:
- case T_RemoveAggrStmt:
case T_DropCastStmt:
case T_DropStmt:
case T_DropdbStmt:
case T_RemoveFuncStmt:
case T_DropRoleStmt:
case T_DropPLangStmt:
- case T_RemoveOperStmt:
case T_RemoveOpClassStmt:
case T_DropPropertyStmt:
case T_GrantStmt:
break;
/*
- * **************** object creation / destruction ******************
+ * **************** object creation / destruction *****************
*/
case T_DefineStmt:
{
switch (stmt->kind)
{
case OBJECT_AGGREGATE:
- DefineAggregate(stmt->defnames, stmt->definition);
+ DefineAggregate(stmt->defnames, stmt->args,
+ stmt->oldstyle, stmt->definition);
break;
case OBJECT_OPERATOR:
+ Assert(stmt->args == NIL);
DefineOperator(stmt->defnames, stmt->definition);
break;
case OBJECT_TYPE:
+ Assert(stmt->args == NIL);
DefineType(stmt->defnames, stmt->definition);
break;
default:
AlterSequence((AlterSeqStmt *) parsetree);
break;
- case T_RemoveAggrStmt:
- RemoveAggregate((RemoveAggrStmt *) parsetree);
- break;
-
case T_RemoveFuncStmt:
- RemoveFunction((RemoveFuncStmt *) parsetree);
- break;
+ {
+ RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
- case T_RemoveOperStmt:
- RemoveOperator((RemoveOperStmt *) parsetree);
+ switch (stmt->kind)
+ {
+ case OBJECT_FUNCTION:
+ RemoveFunction(stmt);
+ break;
+ case OBJECT_AGGREGATE:
+ RemoveAggregate(stmt);
+ break;
+ case OBJECT_OPERATOR:
+ RemoveOperator(stmt);
+ break;
+ default:
+ elog(ERROR, "unrecognized object type: %d",
+ (int) stmt->kind);
+ break;
+ }
+ }
break;
case T_CreatedbStmt:
tag = "ALTER SEQUENCE";
break;
- case T_RemoveAggrStmt:
- tag = "DROP AGGREGATE";
- break;
-
case T_RemoveFuncStmt:
- tag = "DROP FUNCTION";
- break;
-
- case T_RemoveOperStmt:
- tag = "DROP OPERATOR";
+ switch (((RemoveFuncStmt *) parsetree)->kind)
+ {
+ case OBJECT_FUNCTION:
+ tag = "DROP FUNCTION";
+ break;
+ case OBJECT_AGGREGATE:
+ tag = "DROP AGGREGATE";
+ break;
+ case OBJECT_OPERATOR:
+ tag = "DROP OPERATOR";
+ break;
+ default:
+ tag = "???";
+ }
break;
case T_CreatedbStmt:
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.71 2006/03/05 15:58:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.72 2006/04/15 17:45:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void CreateCast(CreateCastStmt *stmt);
extern void DropCast(DropCastStmt *stmt);
extern void DropCastById(Oid castOid);
-extern void AlterFunctionNamespace(List *name, List *argtypes,
+extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
const char *newschema);
/* commands/operatorcmds.c */
extern void DefineOperator(List *names, List *parameters);
-extern void RemoveOperator(RemoveOperStmt *stmt);
+extern void RemoveOperator(RemoveFuncStmt *stmt);
extern void RemoveOperatorById(Oid operOid);
extern void AlterOperatorOwner(List *name, TypeName *typeName1,
TypeName *typename2, Oid newOwnerId);
extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
/* commands/aggregatecmds.c */
-extern void DefineAggregate(List *names, List *parameters);
-extern void RemoveAggregate(RemoveAggrStmt *stmt);
-extern void RenameAggregate(List *name, TypeName *basetype, const char *newname);
-extern void AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId);
+extern void DefineAggregate(List *name, List *args, bool oldstyle,
+ List *parameters);
+extern void RemoveAggregate(RemoveFuncStmt *stmt);
+extern void RenameAggregate(List *name, List *args, const char *newname);
+extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
/* commands/opclasscmds.c */
extern void DefineOpClass(CreateOpClassStmt *stmt);
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.184 2006/03/07 01:00:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.185 2006/04/15 17:45:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
T_IndexStmt,
T_CreateFunctionStmt,
T_AlterFunctionStmt,
- T_RemoveAggrStmt,
T_RemoveFuncStmt,
- T_RemoveOperStmt,
T_RenameStmt,
T_RuleStmt,
T_NotifyStmt,
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.306 2006/03/23 00:19:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.307 2006/04/15 17:45:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
NodeTag type;
ObjectType kind; /* aggregate, operator, type */
+ bool oldstyle; /* hack to signal old CREATE AGG syntax */
List *defnames; /* qualified name (list of Value strings) */
+ List *args; /* a list of TypeName (if needed) */
List *definition; /* a list of DefElem */
} DefineStmt;
} AlterFunctionStmt;
/* ----------------------
- * Drop Aggregate Statement
- * ----------------------
- */
-typedef struct RemoveAggrStmt
-{
- NodeTag type;
- List *aggname; /* aggregate to drop */
- TypeName *aggtype; /* TypeName for input datatype, or NULL */
- DropBehavior behavior; /* RESTRICT or CASCADE behavior */
-} RemoveAggrStmt;
-
-/* ----------------------
- * Drop Function Statement
+ * Drop {Function|Aggregate|Operator} Statement
* ----------------------
*/
typedef struct RemoveFuncStmt
{
NodeTag type;
- List *funcname; /* function to drop */
+ ObjectType kind; /* function, aggregate, operator */
+ List *name; /* qualified name of object to drop */
List *args; /* types of the arguments */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
} RemoveFuncStmt;
-/* ----------------------
- * Drop Operator Statement
- * ----------------------
- */
-typedef struct RemoveOperStmt
-{
- NodeTag type;
- List *opname; /* operator to drop */
- List *args; /* types of the arguments */
- DropBehavior behavior; /* RESTRICT or CASCADE behavior */
-} RemoveOperStmt;
-
/* ----------------------
* Drop Operator Class Statement
* ----------------------
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.55 2006/03/14 22:48:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.56 2006/04/15 17:45:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern const char *func_signature_string(List *funcname,
int nargs, const Oid *argtypes);
-extern Oid find_aggregate_func(List *aggname, Oid basetype, bool noError);
-
extern Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes,
bool noError);
extern Oid LookupFuncNameTypeNames(List *funcname, List *argtypes,
bool noError);
+extern Oid LookupAggNameTypeNames(List *aggname, List *argtypes,
+ bool noError);
#endif /* PARSE_FUNC_H */
create aggregate newcnt1 (sfunc = int4inc,
stype = int4,
initcond = '0');
-ERROR: aggregate basetype must be specified
+ERROR: aggregate input type must be specified
--
-- DROP INDEX