mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Support the syntax
CREATE AGGREGATE aggname (input_type) (parameter_list) along with the old syntax where the input type was named in the parameter list. This fits more naturally with the way that the aggregate is identified in DROP AGGREGATE and other utility commands; furthermore it has a natural extension to handle multiple-input aggregates, where the basetype-parameter method would get ugly. In fact, this commit fixes the grammar and all the utility commands to support multiple-input aggregates; but DefineAggregate rejects it because the executor isn't fixed yet. I didn't do anything about treating agg(*) as a zero-input aggregate instead of artificially making it a one-input aggregate, but that should be considered in combination with supporting multi-input aggregates.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
@@ -224,8 +224,9 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%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
|
||||
@@ -246,7 +247,7 @@ static void doNegateFloat(Value *v);
|
||||
%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
|
||||
@@ -285,7 +286,7 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%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
|
||||
@@ -2671,11 +2672,24 @@ DropAssertStmt:
|
||||
*****************************************************************************/
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -2683,7 +2697,9 @@ DefineStmt:
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->kind = OBJECT_OPERATOR;
|
||||
n->oldstyle = false;
|
||||
n->defnames = $3;
|
||||
n->args = NIL;
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@@ -2691,7 +2707,9 @@ DefineStmt:
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->kind = OBJECT_TYPE;
|
||||
n->oldstyle = false;
|
||||
n->defnames = $3;
|
||||
n->args = NIL;
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@@ -2700,7 +2718,9 @@ DefineStmt:
|
||||
/* 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;
|
||||
}
|
||||
@@ -2764,6 +2784,28 @@ def_arg: func_type { $$ = (Node *)$1; }
|
||||
| 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);
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
@@ -2960,7 +3002,7 @@ TruncateStmt:
|
||||
* 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> |
|
||||
@@ -2980,14 +3022,13 @@ CommentStmt:
|
||||
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
|
||||
@@ -3844,7 +3885,7 @@ opt_restrict:
|
||||
* 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 ]
|
||||
*
|
||||
*****************************************************************************/
|
||||
@@ -3853,7 +3894,8 @@ RemoveFuncStmt:
|
||||
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;
|
||||
@@ -3861,26 +3903,23 @@ RemoveFuncStmt:
|
||||
;
|
||||
|
||||
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;
|
||||
@@ -4013,13 +4052,13 @@ opt_force: FORCE { $$ = TRUE; }
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
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
|
||||
@@ -4153,13 +4192,13 @@ opt_column: COLUMN { $$ = COLUMN; }
|
||||
*****************************************************************************/
|
||||
|
||||
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
|
||||
@@ -4211,13 +4250,13 @@ AlterObjectSchemaStmt:
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
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
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* 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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1115,65 +1115,6 @@ func_signature_string(List *funcname, int nargs, const Oid *argtypes)
|
||||
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,
|
||||
@@ -1246,3 +1187,101 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user