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'.
This commit is contained in:
parent
ecba5d308c
commit
18c3000286
@ -5,7 +5,7 @@
|
||||
*
|
||||
* 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
|
||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||
@ -114,8 +114,12 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
|
||||
static void
|
||||
_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);
|
||||
appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
|
||||
node->agg_star ? "true" : "false",
|
||||
node->agg_distinct ? "true" : "false");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* 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)
|
||||
funccallnode = makeNode(FuncCall);
|
||||
funccallnode->funcname = "nextval";
|
||||
funccallnode->args = lcons(snamenode, NIL);
|
||||
funccallnode->agg_star = false;
|
||||
funccallnode->agg_distinct = false;
|
||||
|
||||
constraint = makeNode(Constraint);
|
||||
constraint->contype = CONSTR_DEFAULT;
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -246,7 +246,7 @@ static Node *doNegate(Node *n);
|
||||
%type <str> TypeId
|
||||
|
||||
%type <node> TableConstraint
|
||||
%type <list> ColPrimaryKey, ColQualifier
|
||||
%type <list> ColPrimaryKey, ColConstraintList
|
||||
%type <node> ColConstraint, ColConstraintElem
|
||||
%type <ival> key_actions, key_action, key_reference
|
||||
%type <str> key_match
|
||||
@ -912,7 +912,7 @@ OptTableElement: columnDef { $$ = $1; }
|
||||
| TableConstraint { $$ = $1; }
|
||||
;
|
||||
|
||||
columnDef: ColId Typename ColQualifier
|
||||
columnDef: ColId Typename ColConstraintList
|
||||
{
|
||||
ColumnDef *n = makeNode(ColumnDef);
|
||||
n->colname = $1;
|
||||
@ -939,14 +939,15 @@ columnDef: ColId Typename ColQualifier
|
||||
}
|
||||
;
|
||||
|
||||
ColQualifier: ColQualifier ColConstraint
|
||||
ColConstraintList: ColConstraintList ColConstraint
|
||||
{
|
||||
if ($2 != NULL)
|
||||
$$ = lappend($1, $2);
|
||||
else
|
||||
$$ = $1;
|
||||
}
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
| /*EMPTY*/
|
||||
{ $$ = NIL; }
|
||||
;
|
||||
|
||||
ColPrimaryKey: PRIMARY KEY
|
||||
@ -3792,6 +3793,8 @@ a_expr: com_expr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $3->name;
|
||||
n->args = lcons($1,NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
}
|
||||
@ -4037,6 +4040,8 @@ b_expr: com_expr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $3->name;
|
||||
n->args = lcons($1,NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
}
|
||||
@ -4129,6 +4134,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $5->name;
|
||||
n->args = lcons($3,NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
}
|
||||
@ -4139,6 +4146,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = NIL;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| func_name '(' expr_list ')'
|
||||
@ -4146,6 +4155,17 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
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;
|
||||
}
|
||||
| func_name '(' '*' ')'
|
||||
@ -4158,12 +4178,9 @@ com_expr: attr
|
||||
* and there are no other aggregates in SQL92 that accept
|
||||
* '*' as parameter.
|
||||
*
|
||||
* XXX really, the '*' ought to be transformed to some
|
||||
* special construct that wouldn't be acceptable as the
|
||||
* input of a non-aggregate function, in case the given
|
||||
* func_name matches a plain function. This would also
|
||||
* support a possible extension to let user-defined
|
||||
* aggregates do something special with '*' as input.
|
||||
* The FuncCall node is also marked agg_star = true,
|
||||
* so that later processing can detect what the argument
|
||||
* really was.
|
||||
*/
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
A_Const *star = makeNode(A_Const);
|
||||
@ -4172,6 +4189,8 @@ com_expr: attr
|
||||
star->val.val.ival = 1;
|
||||
n->funcname = $1;
|
||||
n->args = lcons(star, NIL);
|
||||
n->agg_star = true;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CURRENT_DATE
|
||||
@ -4203,6 +4222,8 @@ com_expr: attr
|
||||
|
||||
n->funcname = xlateSqlType("date");
|
||||
n->args = lcons(s, NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@ -4226,6 +4247,8 @@ com_expr: attr
|
||||
|
||||
n->funcname = xlateSqlType("time");
|
||||
n->args = lcons(s, NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@ -4249,6 +4272,8 @@ com_expr: attr
|
||||
|
||||
n->funcname = xlateSqlType("time");
|
||||
n->args = lcons(s, NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
|
||||
if ($3 != 0)
|
||||
elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
|
||||
@ -4275,6 +4300,8 @@ com_expr: attr
|
||||
|
||||
n->funcname = xlateSqlType("timestamp");
|
||||
n->args = lcons(s, NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@ -4298,6 +4325,8 @@ com_expr: attr
|
||||
|
||||
n->funcname = xlateSqlType("timestamp");
|
||||
n->args = lcons(s, NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
|
||||
if ($3 != 0)
|
||||
elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
|
||||
@ -4309,6 +4338,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "getpgusername";
|
||||
n->args = NIL;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| USER
|
||||
@ -4316,6 +4347,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "getpgusername";
|
||||
n->args = NIL;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| EXTRACT '(' extract_list ')'
|
||||
@ -4323,6 +4356,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "date_part";
|
||||
n->args = $3;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| POSITION '(' position_list ')'
|
||||
@ -4330,6 +4365,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "strpos";
|
||||
n->args = $3;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| SUBSTRING '(' substr_list ')'
|
||||
@ -4337,6 +4374,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "substr";
|
||||
n->args = $3;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
|
||||
@ -4345,6 +4384,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "btrim";
|
||||
n->args = $4;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| TRIM '(' LEADING trim_list ')'
|
||||
@ -4352,6 +4393,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "ltrim";
|
||||
n->args = $4;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| TRIM '(' TRAILING trim_list ')'
|
||||
@ -4359,6 +4402,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "rtrim";
|
||||
n->args = $4;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| TRIM '(' trim_list ')'
|
||||
@ -4366,6 +4411,8 @@ com_expr: attr
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = "btrim";
|
||||
n->args = $3;
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' SubSelect ')'
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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)
|
||||
|
||||
Aggref *
|
||||
ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
|
||||
List *target, int precedence)
|
||||
List *args, bool agg_star, bool agg_distinct,
|
||||
int precedence)
|
||||
{
|
||||
HeapTuple theAggTuple;
|
||||
Form_pg_aggregate aggform;
|
||||
@ -242,7 +243,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
|
||||
if (OidIsValid(xfn1))
|
||||
{
|
||||
basetype = aggform->aggbasetype;
|
||||
vartype = exprType(lfirst(target));
|
||||
vartype = exprType(lfirst(args));
|
||||
if ((basetype != vartype)
|
||||
&& (!IS_BINARY_COMPATIBLE(basetype, vartype)))
|
||||
{
|
||||
@ -261,9 +262,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
|
||||
aggref->aggname = pstrdup(aggname);
|
||||
aggref->basetype = aggform->aggbasetype;
|
||||
aggref->aggtype = fintype;
|
||||
aggref->target = lfirst(target);
|
||||
aggref->target = lfirst(args);
|
||||
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;
|
||||
|
||||
return aggref;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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,
|
||||
|
||||
n->funcname = typeTypeName(targetType);
|
||||
n->args = lcons(node, NIL);
|
||||
n->agg_star = false;
|
||||
n->agg_distinct = false;
|
||||
|
||||
result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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)
|
||||
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||
|
||||
result = ParseFuncOrColumn(pstate,
|
||||
"nullvalue", lcons(lexpr, NIL),
|
||||
&pstate->p_last_resno,
|
||||
"nullvalue",
|
||||
lcons(lexpr, NIL),
|
||||
false, false,
|
||||
&pstate->p_last_resno,
|
||||
precedence);
|
||||
}
|
||||
break;
|
||||
@ -116,8 +118,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||
|
||||
result = ParseFuncOrColumn(pstate,
|
||||
"nonnullvalue", lcons(lexpr, NIL),
|
||||
&pstate->p_last_resno,
|
||||
"nonnullvalue",
|
||||
lcons(lexpr, NIL),
|
||||
false, false,
|
||||
&pstate->p_last_resno,
|
||||
precedence);
|
||||
}
|
||||
break;
|
||||
@ -192,6 +196,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
result = ParseFuncOrColumn(pstate,
|
||||
fn->funcname,
|
||||
fn->args,
|
||||
fn->agg_star,
|
||||
fn->agg_distinct,
|
||||
&pstate->p_last_resno,
|
||||
precedence);
|
||||
break;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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
|
||||
|
||||
retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
|
||||
lcons(param, NIL),
|
||||
false, false,
|
||||
curr_resno,
|
||||
precedence);
|
||||
}
|
||||
@ -98,6 +99,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
|
||||
ident->isRel = TRUE;
|
||||
retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
|
||||
lcons(ident, NIL),
|
||||
false, false,
|
||||
curr_resno,
|
||||
precedence);
|
||||
}
|
||||
@ -107,6 +109,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
|
||||
{
|
||||
retval = ParseFuncOrColumn(pstate, strVal(lfirst(mutator_iter)),
|
||||
lcons(retval, NIL),
|
||||
false, false,
|
||||
curr_resno,
|
||||
precedence);
|
||||
}
|
||||
@ -219,6 +222,7 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
|
||||
*/
|
||||
Node *
|
||||
ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
bool agg_star, bool agg_distinct,
|
||||
int *curr_resno, int precedence)
|
||||
{
|
||||
Oid rettype = InvalidOid;
|
||||
@ -230,12 +234,13 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
char *refname = NULL;
|
||||
Relation rd;
|
||||
Oid relid;
|
||||
int nargs;
|
||||
int nargs = length(fargs);
|
||||
Func *funcnode;
|
||||
Oid oid_array[MAXFARGS];
|
||||
Oid *true_oid_array;
|
||||
Node *retval;
|
||||
bool retset;
|
||||
bool must_be_agg = agg_star || agg_distinct;
|
||||
bool attisset = false;
|
||||
Oid toid = InvalidOid;
|
||||
Expr *expr;
|
||||
@ -252,11 +257,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
* that argument is a relation, param, or PQ function returning a
|
||||
* complex * type, then the function could be a projection.
|
||||
*/
|
||||
/* We only have one parameter */
|
||||
if (length(fargs) == 1)
|
||||
/* We only have one parameter, and it's not got aggregate decoration */
|
||||
if (nargs == 1 && !must_be_agg)
|
||||
{
|
||||
/* Is is a plain Relation name from the parser? */
|
||||
if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)
|
||||
/* Is it a plain Relation name from the parser? */
|
||||
if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
Ident *ident = (Ident *) first_arg;
|
||||
@ -292,15 +297,10 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
refname,
|
||||
funcname);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drop through - attr is a set */
|
||||
;
|
||||
}
|
||||
/* else drop through - attr is a set */
|
||||
}
|
||||
else if (ISCOMPLEX(exprType(first_arg)))
|
||||
{
|
||||
|
||||
/*
|
||||
* Attempt to handle projection of a complex argument. If
|
||||
* ParseComplexProjection can't handle the projection, we have
|
||||
@ -325,8 +325,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
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)
|
||||
&& strcmp(funcname, "*"))
|
||||
@ -336,76 +335,99 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (nargs == 1 || must_be_agg)
|
||||
{
|
||||
/*
|
||||
* See if it's an aggregate.
|
||||
*/
|
||||
Oid basetype;
|
||||
int ncandidates;
|
||||
CandidateList candidates;
|
||||
|
||||
/* We don't presently cope with, eg, foo(DISTINCT x,y) */
|
||||
if (nargs != 1)
|
||||
elog(ERROR, "Aggregate functions may only have one parameter");
|
||||
|
||||
/*
|
||||
* the aggregate COUNT is a special case, ignore its base
|
||||
* type. Treat it as zero. XXX mighty ugly --- FIXME
|
||||
*/
|
||||
if (strcmp(funcname, "count") == 0)
|
||||
basetype = 0;
|
||||
else
|
||||
basetype = exprType(lfirst(fargs));
|
||||
|
||||
/* try for exact match first... */
|
||||
if (SearchSysCacheTuple(AGGNAME,
|
||||
PointerGetDatum(funcname),
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0))
|
||||
return (Node *) ParseAgg(pstate, funcname, basetype,
|
||||
fargs, agg_star, agg_distinct,
|
||||
precedence);
|
||||
|
||||
/*
|
||||
* No exact match yet, so see if there is another entry in the
|
||||
* aggregate table which is compatible. - thomas 1998-12-05
|
||||
*/
|
||||
ncandidates = agg_get_candidates(funcname, basetype, &candidates);
|
||||
if (ncandidates > 0)
|
||||
{
|
||||
Oid type;
|
||||
|
||||
/*
|
||||
* Parsing aggregates.
|
||||
*/
|
||||
Type tp;
|
||||
Oid basetype;
|
||||
int ncandidates;
|
||||
CandidateList candidates;
|
||||
|
||||
/*
|
||||
* the aggregate COUNT is a special case, ignore its base
|
||||
* type. Treat it as zero
|
||||
*/
|
||||
if (strcmp(funcname, "count") == 0)
|
||||
basetype = 0;
|
||||
else
|
||||
basetype = exprType(lfirst(fargs));
|
||||
|
||||
/* try for exact match first... */
|
||||
if (SearchSysCacheTuple(AGGNAME,
|
||||
PointerGetDatum(funcname),
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0))
|
||||
return (Node *) ParseAgg(pstate, funcname, basetype,
|
||||
fargs, precedence);
|
||||
|
||||
/*
|
||||
* No exact match yet, so see if there is another entry in the
|
||||
* aggregate table which is compatible. - thomas 1998-12-05
|
||||
*/
|
||||
ncandidates = agg_get_candidates(funcname, basetype, &candidates);
|
||||
if (ncandidates > 0)
|
||||
type = agg_select_candidate(basetype, candidates);
|
||||
if (OidIsValid(type))
|
||||
{
|
||||
Oid type;
|
||||
|
||||
type = agg_select_candidate(basetype, candidates);
|
||||
if (OidIsValid(type))
|
||||
{
|
||||
lfirst(fargs) = coerce_type(pstate, lfirst(fargs),
|
||||
basetype, type, -1);
|
||||
basetype = type;
|
||||
|
||||
return (Node *) ParseAgg(pstate, funcname, basetype,
|
||||
fargs, precedence);
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "Unable to select an aggregate function %s(%s)",
|
||||
funcname, typeidTypeName(basetype));
|
||||
}
|
||||
lfirst(fargs) = coerce_type(pstate, lfirst(fargs),
|
||||
basetype, type, -1);
|
||||
basetype = type;
|
||||
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
|
||||
* 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)
|
||||
* No matching agg, but we had '*' or DISTINCT, so a plain
|
||||
* function could not have been meant.
|
||||
*/
|
||||
if ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPENAME,
|
||||
PointerGetDatum(funcname),
|
||||
0, 0, 0)))
|
||||
&& IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))
|
||||
return ((Node *) lfirst(fargs));
|
||||
elog(ERROR, "There is no aggregate function %s(%s)",
|
||||
funcname, typeidTypeName(basetype));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
@ -461,14 +483,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
{ /* 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
|
||||
* cast them - jolly
|
||||
*/
|
||||
if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const))
|
||||
elog(ERROR, "There is no function '%s'"
|
||||
" with argument #%d of type UNKNOWN",
|
||||
funcname, nargs);
|
||||
funcname, nargs+1);
|
||||
else
|
||||
toid = exprType(pair);
|
||||
}
|
||||
@ -572,7 +594,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
text *seqname;
|
||||
int32 aclcheck_result = -1;
|
||||
|
||||
Assert(length(fargs) == ((funcid == F_SETVAL) ? 2 : 1));
|
||||
Assert(nargs == ((funcid == F_SETVAL) ? 2 : 1));
|
||||
seq = (Const *) lfirst(fargs);
|
||||
if (!IsA((Node *) seq, Const))
|
||||
elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* 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,
|
||||
|
||||
if (HeapTupleIsValid(ftup))
|
||||
{
|
||||
FuncCall *func;
|
||||
A_Const *cons;
|
||||
A_Const *cons = makeNode(A_Const);
|
||||
FuncCall *func = makeNode(FuncCall);
|
||||
|
||||
func = makeNode(FuncCall);
|
||||
func->funcname = funcname;
|
||||
|
||||
cons = makeNode(A_Const);
|
||||
cons->val.type = T_Integer;
|
||||
cons->val.val.ival = attrtypmod;
|
||||
|
||||
func->funcname = funcname;
|
||||
func->args = lappend(lcons(expr, NIL), cons);
|
||||
func->agg_star = false;
|
||||
func->agg_distinct = false;
|
||||
|
||||
expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* 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
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
} 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
|
||||
{
|
||||
NodeTag type;
|
||||
char *funcname; /* name of function */
|
||||
List *args; /* the arguments (list of exprs) */
|
||||
bool agg_star; /* argument was really '*' */
|
||||
bool agg_distinct; /* arguments were labeled DISTINCT */
|
||||
} FuncCall;
|
||||
|
||||
/*
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* 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 @@
|
||||
extern void AddAggToParseState(ParseState *pstate, Aggref *aggref);
|
||||
extern void parseCheckAggregates(ParseState *pstate, Query *qry);
|
||||
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);
|
||||
|
||||
#endif /* PARSE_AGG_H */
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* 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
|
||||
|
||||
extern Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr,
|
||||
int *curr_resno, int precedence);
|
||||
extern Node *ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
int *curr_resno, int precedence);
|
||||
extern Node *ParseFuncOrColumn(ParseState *pstate,
|
||||
char *funcname, List *fargs,
|
||||
bool agg_star, bool agg_distinct,
|
||||
int *curr_resno, int precedence);
|
||||
|
||||
extern List *setup_base_tlist(Oid typeid);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user