Commit 18c30002 authored by Tom Lane's avatar Tom Lane

Teach grammar and parser about aggregate(DISTINCT ...). No implementation

yet, but at least we can give a better error message:
regression=> select count(distinct f1) from int4_tbl;
ERROR:  aggregate(DISTINCT ...) is not implemented yet
instead of 'parser: parse error at or near distinct'.
parent ecba5d30
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: outfuncs.c,v 1.98 1999/11/23 20:06:53 momjian Exp $ * $Id: outfuncs.c,v 1.99 1999/12/10 07:37:31 tgl Exp $
* *
* NOTES * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -114,8 +114,12 @@ _outSelectStmt(StringInfo str, SelectStmt *node) ...@@ -114,8 +114,12 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
static void static void
_outFuncCall(StringInfo str, FuncCall *node) _outFuncCall(StringInfo str, FuncCall *node)
{ {
appendStringInfo(str, "FUNCTION %s :args ", stringStringInfo(node->funcname)); appendStringInfo(str, "FUNCTION %s :args ",
stringStringInfo(node->funcname));
_outNode(str, node->args); _outNode(str, node->args);
appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
node->agg_star ? "true" : "false",
node->agg_distinct ? "true" : "false");
} }
static void static void
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: analyze.c,v 1.125 1999/12/06 18:02:42 wieck Exp $ * $Id: analyze.c,v 1.126 1999/12/10 07:37:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -624,6 +624,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt) ...@@ -624,6 +624,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
funccallnode = makeNode(FuncCall); funccallnode = makeNode(FuncCall);
funccallnode->funcname = "nextval"; funccallnode->funcname = "nextval";
funccallnode->args = lcons(snamenode, NIL); funccallnode->args = lcons(snamenode, NIL);
funccallnode->agg_star = false;
funccallnode->agg_distinct = false;
constraint = makeNode(Constraint); constraint = makeNode(Constraint);
constraint->contype = CONSTR_DEFAULT; constraint->contype = CONSTR_DEFAULT;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.120 1999/12/10 05:17:13 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.121 1999/12/10 07:37:35 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -246,7 +246,7 @@ static Node *doNegate(Node *n); ...@@ -246,7 +246,7 @@ static Node *doNegate(Node *n);
%type <str> TypeId %type <str> TypeId
%type <node> TableConstraint %type <node> TableConstraint
%type <list> ColPrimaryKey, ColQualifier %type <list> ColPrimaryKey, ColConstraintList
%type <node> ColConstraint, ColConstraintElem %type <node> ColConstraint, ColConstraintElem
%type <ival> key_actions, key_action, key_reference %type <ival> key_actions, key_action, key_reference
%type <str> key_match %type <str> key_match
...@@ -912,7 +912,7 @@ OptTableElement: columnDef { $$ = $1; } ...@@ -912,7 +912,7 @@ OptTableElement: columnDef { $$ = $1; }
| TableConstraint { $$ = $1; } | TableConstraint { $$ = $1; }
; ;
columnDef: ColId Typename ColQualifier columnDef: ColId Typename ColConstraintList
{ {
ColumnDef *n = makeNode(ColumnDef); ColumnDef *n = makeNode(ColumnDef);
n->colname = $1; n->colname = $1;
...@@ -939,14 +939,15 @@ columnDef: ColId Typename ColQualifier ...@@ -939,14 +939,15 @@ columnDef: ColId Typename ColQualifier
} }
; ;
ColQualifier: ColQualifier ColConstraint ColConstraintList: ColConstraintList ColConstraint
{ {
if ($2 != NULL) if ($2 != NULL)
$$ = lappend($1, $2); $$ = lappend($1, $2);
else else
$$ = $1; $$ = $1;
} }
| /*EMPTY*/ { $$ = NULL; } | /*EMPTY*/
{ $$ = NIL; }
; ;
ColPrimaryKey: PRIMARY KEY ColPrimaryKey: PRIMARY KEY
...@@ -3792,6 +3793,8 @@ a_expr: com_expr ...@@ -3792,6 +3793,8 @@ a_expr: com_expr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = $3->name; n->funcname = $3->name;
n->args = lcons($1,NIL); n->args = lcons($1,NIL);
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
} }
...@@ -4037,6 +4040,8 @@ b_expr: com_expr ...@@ -4037,6 +4040,8 @@ b_expr: com_expr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = $3->name; n->funcname = $3->name;
n->args = lcons($1,NIL); n->args = lcons($1,NIL);
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
} }
...@@ -4129,6 +4134,8 @@ com_expr: attr ...@@ -4129,6 +4134,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = $5->name; n->funcname = $5->name;
n->args = lcons($3,NIL); n->args = lcons($3,NIL);
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
} }
...@@ -4139,6 +4146,8 @@ com_expr: attr ...@@ -4139,6 +4146,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = $1; n->funcname = $1;
n->args = NIL; n->args = NIL;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| func_name '(' expr_list ')' | func_name '(' expr_list ')'
...@@ -4146,6 +4155,17 @@ com_expr: attr ...@@ -4146,6 +4155,17 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = $1; n->funcname = $1;
n->args = $3; n->args = $3;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n;
}
| func_name '(' DISTINCT expr_list ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = $1;
n->args = $4;
n->agg_star = false;
n->agg_distinct = true;
$$ = (Node *)n; $$ = (Node *)n;
} }
| func_name '(' '*' ')' | func_name '(' '*' ')'
...@@ -4158,12 +4178,9 @@ com_expr: attr ...@@ -4158,12 +4178,9 @@ com_expr: attr
* and there are no other aggregates in SQL92 that accept * and there are no other aggregates in SQL92 that accept
* '*' as parameter. * '*' as parameter.
* *
* XXX really, the '*' ought to be transformed to some * The FuncCall node is also marked agg_star = true,
* special construct that wouldn't be acceptable as the * so that later processing can detect what the argument
* input of a non-aggregate function, in case the given * really was.
* func_name matches a plain function. This would also
* support a possible extension to let user-defined
* aggregates do something special with '*' as input.
*/ */
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
A_Const *star = makeNode(A_Const); A_Const *star = makeNode(A_Const);
...@@ -4172,6 +4189,8 @@ com_expr: attr ...@@ -4172,6 +4189,8 @@ com_expr: attr
star->val.val.ival = 1; star->val.val.ival = 1;
n->funcname = $1; n->funcname = $1;
n->args = lcons(star, NIL); n->args = lcons(star, NIL);
n->agg_star = true;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CURRENT_DATE | CURRENT_DATE
...@@ -4203,6 +4222,8 @@ com_expr: attr ...@@ -4203,6 +4222,8 @@ com_expr: attr
n->funcname = xlateSqlType("date"); n->funcname = xlateSqlType("date");
n->args = lcons(s, NIL); n->args = lcons(s, NIL);
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -4226,6 +4247,8 @@ com_expr: attr ...@@ -4226,6 +4247,8 @@ com_expr: attr
n->funcname = xlateSqlType("time"); n->funcname = xlateSqlType("time");
n->args = lcons(s, NIL); n->args = lcons(s, NIL);
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -4249,6 +4272,8 @@ com_expr: attr ...@@ -4249,6 +4272,8 @@ com_expr: attr
n->funcname = xlateSqlType("time"); n->funcname = xlateSqlType("time");
n->args = lcons(s, NIL); n->args = lcons(s, NIL);
n->agg_star = false;
n->agg_distinct = false;
if ($3 != 0) if ($3 != 0)
elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3); elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
...@@ -4275,6 +4300,8 @@ com_expr: attr ...@@ -4275,6 +4300,8 @@ com_expr: attr
n->funcname = xlateSqlType("timestamp"); n->funcname = xlateSqlType("timestamp");
n->args = lcons(s, NIL); n->args = lcons(s, NIL);
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -4298,6 +4325,8 @@ com_expr: attr ...@@ -4298,6 +4325,8 @@ com_expr: attr
n->funcname = xlateSqlType("timestamp"); n->funcname = xlateSqlType("timestamp");
n->args = lcons(s, NIL); n->args = lcons(s, NIL);
n->agg_star = false;
n->agg_distinct = false;
if ($3 != 0) if ($3 != 0)
elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3); elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
...@@ -4309,6 +4338,8 @@ com_expr: attr ...@@ -4309,6 +4338,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "getpgusername"; n->funcname = "getpgusername";
n->args = NIL; n->args = NIL;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| USER | USER
...@@ -4316,6 +4347,8 @@ com_expr: attr ...@@ -4316,6 +4347,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "getpgusername"; n->funcname = "getpgusername";
n->args = NIL; n->args = NIL;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| EXTRACT '(' extract_list ')' | EXTRACT '(' extract_list ')'
...@@ -4323,6 +4356,8 @@ com_expr: attr ...@@ -4323,6 +4356,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "date_part"; n->funcname = "date_part";
n->args = $3; n->args = $3;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| POSITION '(' position_list ')' | POSITION '(' position_list ')'
...@@ -4330,6 +4365,8 @@ com_expr: attr ...@@ -4330,6 +4365,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "strpos"; n->funcname = "strpos";
n->args = $3; n->args = $3;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| SUBSTRING '(' substr_list ')' | SUBSTRING '(' substr_list ')'
...@@ -4337,6 +4374,8 @@ com_expr: attr ...@@ -4337,6 +4374,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "substr"; n->funcname = "substr";
n->args = $3; n->args = $3;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */ /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
...@@ -4345,6 +4384,8 @@ com_expr: attr ...@@ -4345,6 +4384,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "btrim"; n->funcname = "btrim";
n->args = $4; n->args = $4;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| TRIM '(' LEADING trim_list ')' | TRIM '(' LEADING trim_list ')'
...@@ -4352,6 +4393,8 @@ com_expr: attr ...@@ -4352,6 +4393,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "ltrim"; n->funcname = "ltrim";
n->args = $4; n->args = $4;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| TRIM '(' TRAILING trim_list ')' | TRIM '(' TRAILING trim_list ')'
...@@ -4359,6 +4402,8 @@ com_expr: attr ...@@ -4359,6 +4402,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "rtrim"; n->funcname = "rtrim";
n->args = $4; n->args = $4;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| TRIM '(' trim_list ')' | TRIM '(' trim_list ')'
...@@ -4366,6 +4411,8 @@ com_expr: attr ...@@ -4366,6 +4411,8 @@ com_expr: attr
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = "btrim"; n->funcname = "btrim";
n->args = $3; n->args = $3;
n->agg_star = false;
n->agg_distinct = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| '(' SubSelect ')' | '(' SubSelect ')'
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.30 1999/12/09 05:58:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.31 1999/12/10 07:37:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -203,7 +203,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry) ...@@ -203,7 +203,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
Aggref * Aggref *
ParseAgg(ParseState *pstate, char *aggname, Oid basetype, ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
List *target, int precedence) List *args, bool agg_star, bool agg_distinct,
int precedence)
{ {
HeapTuple theAggTuple; HeapTuple theAggTuple;
Form_pg_aggregate aggform; Form_pg_aggregate aggform;
...@@ -242,7 +243,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, ...@@ -242,7 +243,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
if (OidIsValid(xfn1)) if (OidIsValid(xfn1))
{ {
basetype = aggform->aggbasetype; basetype = aggform->aggbasetype;
vartype = exprType(lfirst(target)); vartype = exprType(lfirst(args));
if ((basetype != vartype) if ((basetype != vartype)
&& (!IS_BINARY_COMPATIBLE(basetype, vartype))) && (!IS_BINARY_COMPATIBLE(basetype, vartype)))
{ {
...@@ -261,9 +262,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, ...@@ -261,9 +262,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
aggref->aggname = pstrdup(aggname); aggref->aggname = pstrdup(aggname);
aggref->basetype = aggform->aggbasetype; aggref->basetype = aggform->aggbasetype;
aggref->aggtype = fintype; aggref->aggtype = fintype;
aggref->target = lfirst(target); aggref->target = lfirst(args);
aggref->usenulls = usenulls; aggref->usenulls = usenulls;
/*
* We should store agg_star and agg_distinct into the Aggref node,
* and let downstream processing deal with them. Currently, agg_star
* is ignored and agg_distinct is not implemented...
*/
if (agg_distinct)
elog(ERROR, "aggregate(DISTINCT ...) is not implemented yet");
pstate->p_hasAggs = true; pstate->p_hasAggs = true;
return aggref; return aggref;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.25 1999/11/22 17:56:20 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.26 1999/12/10 07:37:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -99,6 +99,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, ...@@ -99,6 +99,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
n->funcname = typeTypeName(targetType); n->funcname = typeTypeName(targetType);
n->args = lcons(node, NIL); n->args = lcons(node, NIL);
n->agg_star = false;
n->agg_distinct = false;
result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST); result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.59 1999/11/15 02:00:10 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.60 1999/12/10 07:37:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -106,8 +106,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -106,8 +106,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
Node *lexpr = transformExpr(pstate, a->lexpr, precedence); Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
result = ParseFuncOrColumn(pstate, result = ParseFuncOrColumn(pstate,
"nullvalue", lcons(lexpr, NIL), "nullvalue",
&pstate->p_last_resno, lcons(lexpr, NIL),
false, false,
&pstate->p_last_resno,
precedence); precedence);
} }
break; break;
...@@ -116,8 +118,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -116,8 +118,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
Node *lexpr = transformExpr(pstate, a->lexpr, precedence); Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
result = ParseFuncOrColumn(pstate, result = ParseFuncOrColumn(pstate,
"nonnullvalue", lcons(lexpr, NIL), "nonnullvalue",
&pstate->p_last_resno, lcons(lexpr, NIL),
false, false,
&pstate->p_last_resno,
precedence); precedence);
} }
break; break;
...@@ -192,6 +196,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -192,6 +196,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
result = ParseFuncOrColumn(pstate, result = ParseFuncOrColumn(pstate,
fn->funcname, fn->funcname,
fn->args, fn->args,
fn->agg_star,
fn->agg_distinct,
&pstate->p_last_resno, &pstate->p_last_resno,
precedence); precedence);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.63 1999/12/07 04:09:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.64 1999/12/10 07:37:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -87,6 +87,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre ...@@ -87,6 +87,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)), retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
lcons(param, NIL), lcons(param, NIL),
false, false,
curr_resno, curr_resno,
precedence); precedence);
} }
...@@ -98,6 +99,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre ...@@ -98,6 +99,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
ident->isRel = TRUE; ident->isRel = TRUE;
retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)), retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
lcons(ident, NIL), lcons(ident, NIL),
false, false,
curr_resno, curr_resno,
precedence); precedence);
} }
...@@ -107,6 +109,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre ...@@ -107,6 +109,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
{ {
retval = ParseFuncOrColumn(pstate, strVal(lfirst(mutator_iter)), retval = ParseFuncOrColumn(pstate, strVal(lfirst(mutator_iter)),
lcons(retval, NIL), lcons(retval, NIL),
false, false,
curr_resno, curr_resno,
precedence); precedence);
} }
...@@ -219,6 +222,7 @@ agg_select_candidate(Oid typeid, CandidateList candidates) ...@@ -219,6 +222,7 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
*/ */
Node * Node *
ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
bool agg_star, bool agg_distinct,
int *curr_resno, int precedence) int *curr_resno, int precedence)
{ {
Oid rettype = InvalidOid; Oid rettype = InvalidOid;
...@@ -230,12 +234,13 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -230,12 +234,13 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
char *refname = NULL; char *refname = NULL;
Relation rd; Relation rd;
Oid relid; Oid relid;
int nargs; int nargs = length(fargs);
Func *funcnode; Func *funcnode;
Oid oid_array[MAXFARGS]; Oid oid_array[MAXFARGS];
Oid *true_oid_array; Oid *true_oid_array;
Node *retval; Node *retval;
bool retset; bool retset;
bool must_be_agg = agg_star || agg_distinct;
bool attisset = false; bool attisset = false;
Oid toid = InvalidOid; Oid toid = InvalidOid;
Expr *expr; Expr *expr;
...@@ -252,11 +257,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -252,11 +257,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
* that argument is a relation, param, or PQ function returning a * that argument is a relation, param, or PQ function returning a
* complex * type, then the function could be a projection. * complex * type, then the function could be a projection.
*/ */
/* We only have one parameter */ /* We only have one parameter, and it's not got aggregate decoration */
if (length(fargs) == 1) if (nargs == 1 && !must_be_agg)
{ {
/* Is is a plain Relation name from the parser? */ /* Is it a plain Relation name from the parser? */
if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel) if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
{ {
RangeTblEntry *rte; RangeTblEntry *rte;
Ident *ident = (Ident *) first_arg; Ident *ident = (Ident *) first_arg;
...@@ -292,15 +297,10 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -292,15 +297,10 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
refname, refname,
funcname); funcname);
} }
else /* else drop through - attr is a set */
{
/* drop through - attr is a set */
;
}
} }
else if (ISCOMPLEX(exprType(first_arg))) else if (ISCOMPLEX(exprType(first_arg)))
{ {
/* /*
* Attempt to handle projection of a complex argument. If * Attempt to handle projection of a complex argument. If
* ParseComplexProjection can't handle the projection, we have * ParseComplexProjection can't handle the projection, we have
...@@ -325,8 +325,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -325,8 +325,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
argrelid = typeidTypeRelid(toid); argrelid = typeidTypeRelid(toid);
/* /*
* A projection contains either an attribute name or the * A projection contains either an attribute name or "*".
* "*".
*/ */
if ((get_attnum(argrelid, funcname) == InvalidAttrNumber) if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
&& strcmp(funcname, "*")) && strcmp(funcname, "*"))
...@@ -336,76 +335,99 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -336,76 +335,99 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
if (retval) if (retval)
return retval; return retval;
} }
else }
{
/* if (nargs == 1 || must_be_agg)
* Parsing aggregates. {
*/ /*
Type tp; * See if it's an aggregate.
Oid basetype; */
int ncandidates; Oid basetype;
CandidateList candidates; int ncandidates;
CandidateList candidates;
/* /* We don't presently cope with, eg, foo(DISTINCT x,y) */
* the aggregate COUNT is a special case, ignore its base if (nargs != 1)
* type. Treat it as zero elog(ERROR, "Aggregate functions may only have one parameter");
*/
if (strcmp(funcname, "count") == 0)
basetype = 0;
else
basetype = exprType(lfirst(fargs));
/* try for exact match first... */ /*
if (SearchSysCacheTuple(AGGNAME, * the aggregate COUNT is a special case, ignore its base
PointerGetDatum(funcname), * type. Treat it as zero. XXX mighty ugly --- FIXME
ObjectIdGetDatum(basetype), */
0, 0)) if (strcmp(funcname, "count") == 0)
return (Node *) ParseAgg(pstate, funcname, basetype, basetype = 0;
fargs, precedence); else
basetype = exprType(lfirst(fargs));
/* /* try for exact match first... */
* No exact match yet, so see if there is another entry in the if (SearchSysCacheTuple(AGGNAME,
* aggregate table which is compatible. - thomas 1998-12-05 PointerGetDatum(funcname),
*/ ObjectIdGetDatum(basetype),
ncandidates = agg_get_candidates(funcname, basetype, &candidates); 0, 0))
if (ncandidates > 0) return (Node *) ParseAgg(pstate, funcname, basetype,
{ fargs, agg_star, agg_distinct,
Oid type; precedence);
type = agg_select_candidate(basetype, candidates); /*
if (OidIsValid(type)) * No exact match yet, so see if there is another entry in the
{ * aggregate table which is compatible. - thomas 1998-12-05
lfirst(fargs) = coerce_type(pstate, lfirst(fargs), */
basetype, type, -1); ncandidates = agg_get_candidates(funcname, basetype, &candidates);
basetype = type; if (ncandidates > 0)
{
Oid type;
return (Node *) ParseAgg(pstate, funcname, basetype, type = agg_select_candidate(basetype, candidates);
fargs, precedence); if (OidIsValid(type))
} {
else lfirst(fargs) = coerce_type(pstate, lfirst(fargs),
{ basetype, type, -1);
elog(ERROR, "Unable to select an aggregate function %s(%s)", basetype = type;
funcname, typeidTypeName(basetype)); return (Node *) ParseAgg(pstate, funcname, basetype,
} fargs, agg_star, agg_distinct,
precedence);
}
else
{
/* Multiple possible matches --- give up */
elog(ERROR, "Unable to select an aggregate function %s(%s)",
funcname, typeidTypeName(basetype));
} }
}
if (must_be_agg)
{
/* /*
* See if this is a single argument function with the function * No matching agg, but we had '*' or DISTINCT, so a plain
* name also a type name and the input argument and type name * function could not have been meant.
* binary compatible... This means that you are trying for a
* type conversion which does not need to take place, so we'll
* just pass through the argument itself. (make this clearer
* with some extra brackets - thomas 1998-12-05)
*/ */
if ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPENAME, elog(ERROR, "There is no aggregate function %s(%s)",
PointerGetDatum(funcname), funcname, typeidTypeName(basetype));
0, 0, 0)))
&& IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))
return ((Node *) lfirst(fargs));
} }
} }
/*
* See if this is a single argument function with the function
* name also a type name and the input argument and type name
* binary compatible... This means that you are trying for a
* type conversion which does not need to take place, so we'll
* just pass through the argument itself. (make this clearer
* with some extra brackets - thomas 1998-12-05)
*/
if (nargs == 1)
{
Type tp;
tp = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(funcname),
0, 0, 0);
if (HeapTupleIsValid(tp) &&
IS_BINARY_COMPATIBLE(typeTypeId(tp), exprType(lfirst(fargs))))
{
/* XXX FIXME: probably need to change expression's marked type? */
return (Node *) lfirst(fargs);
}
}
/* /*
* If we dropped through to here it's really a function (or a set, * If we dropped through to here it's really a function (or a set,
...@@ -461,14 +483,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -461,14 +483,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
{ /* set functions don't have parameters */ { /* set functions don't have parameters */
/* /*
* any functiona args which are typed "unknown", but aren't * any function args which are typed "unknown", but aren't
* constants, we don't know what to do with, because we can't * constants, we don't know what to do with, because we can't
* cast them - jolly * cast them - jolly
*/ */
if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const)) if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const))
elog(ERROR, "There is no function '%s'" elog(ERROR, "There is no function '%s'"
" with argument #%d of type UNKNOWN", " with argument #%d of type UNKNOWN",
funcname, nargs); funcname, nargs+1);
else else
toid = exprType(pair); toid = exprType(pair);
} }
...@@ -572,7 +594,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -572,7 +594,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
text *seqname; text *seqname;
int32 aclcheck_result = -1; int32 aclcheck_result = -1;
Assert(length(fargs) == ((funcid == F_SETVAL) ? 2 : 1)); Assert(nargs == ((funcid == F_SETVAL) ? 2 : 1));
seq = (Const *) lfirst(fargs); seq = (Const *) lfirst(fargs);
if (!IsA((Node *) seq, Const)) if (!IsA((Node *) seq, Const))
elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname); elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.49 1999/11/22 17:56:21 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.50 1999/12/10 07:37:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -337,16 +337,16 @@ SizeTargetExpr(ParseState *pstate, ...@@ -337,16 +337,16 @@ SizeTargetExpr(ParseState *pstate,
if (HeapTupleIsValid(ftup)) if (HeapTupleIsValid(ftup))
{ {
FuncCall *func; A_Const *cons = makeNode(A_Const);
A_Const *cons; FuncCall *func = makeNode(FuncCall);
func = makeNode(FuncCall);
func->funcname = funcname;
cons = makeNode(A_Const);
cons->val.type = T_Integer; cons->val.type = T_Integer;
cons->val.val.ival = attrtypmod; cons->val.val.ival = attrtypmod;
func->funcname = funcname;
func->args = lappend(lcons(expr, NIL), cons); func->args = lappend(lcons(expr, NIL), cons);
func->agg_star = false;
func->agg_distinct = false;
expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST); expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parsenodes.h,v 1.89 1999/12/10 03:56:09 momjian Exp $ * $Id: parsenodes.h,v 1.90 1999/12/10 07:37:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -758,6 +758,10 @@ typedef struct SelectStmt ...@@ -758,6 +758,10 @@ typedef struct SelectStmt
/**************************************************************************** /****************************************************************************
* Supporting data structures for Parse Trees * Supporting data structures for Parse Trees
*
* Most of these node types appear in raw parsetrees output by the grammar,
* and get transformed to something else by the analyzer. A few of them
* are used as-is in transformed querytrees.
****************************************************************************/ ****************************************************************************/
/* /*
...@@ -889,13 +893,20 @@ typedef struct Ident ...@@ -889,13 +893,20 @@ typedef struct Ident
} Ident; } Ident;
/* /*
* FuncCall - a function/aggregate invocation * FuncCall - a function or aggregate invocation
*
* agg_star indicates we saw a 'foo(*)' construct, while agg_distinct
* indicates we saw 'foo(DISTINCT ...)'. In either case, the construct
* *must* be an aggregate call. Otherwise, it might be either an
* aggregate or some other kind of function.
*/ */
typedef struct FuncCall typedef struct FuncCall
{ {
NodeTag type; NodeTag type;
char *funcname; /* name of function */ char *funcname; /* name of function */
List *args; /* the arguments (list of exprs) */ List *args; /* the arguments (list of exprs) */
bool agg_star; /* argument was really '*' */
bool agg_distinct; /* arguments were labeled DISTINCT */
} FuncCall; } FuncCall;
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_agg.h,v 1.12 1999/07/15 23:04:01 momjian Exp $ * $Id: parse_agg.h,v 1.13 1999/12/10 07:37:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
extern void AddAggToParseState(ParseState *pstate, Aggref *aggref); extern void AddAggToParseState(ParseState *pstate, Aggref *aggref);
extern void parseCheckAggregates(ParseState *pstate, Query *qry); extern void parseCheckAggregates(ParseState *pstate, Query *qry);
extern Aggref *ParseAgg(ParseState *pstate, char *aggname, Oid basetype, extern Aggref *ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
List *target, int precedence); List *args, bool agg_star, bool agg_distinct,
int precedence);
extern void agg_error(char *caller, char *aggname, Oid basetypeID); extern void agg_error(char *caller, char *aggname, Oid basetypeID);
#endif /* PARSE_AGG_H */ #endif /* PARSE_AGG_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_func.h,v 1.19 1999/08/21 03:49:17 tgl Exp $ * $Id: parse_func.h,v 1.20 1999/12/10 07:37:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -42,8 +42,10 @@ typedef struct _CandidateList ...@@ -42,8 +42,10 @@ typedef struct _CandidateList
extern Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, extern Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr,
int *curr_resno, int precedence); int *curr_resno, int precedence);
extern Node *ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, extern Node *ParseFuncOrColumn(ParseState *pstate,
int *curr_resno, int precedence); char *funcname, List *fargs,
bool agg_star, bool agg_distinct,
int *curr_resno, int precedence);
extern List *setup_base_tlist(Oid typeid); extern List *setup_base_tlist(Oid typeid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment