提交 53b47679 编写于 作者: T Thomas G. Lockhart

Define routines and catalog entries for string min()/max() functions.

Extend new type coersion techniques to aggregates.
Clean up a few elog() messages.
上级 9470ab03
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.14 1998/09/09 03:48:17 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.15 1998/12/08 06:18:56 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_node.h" #include "parser/parse_node.h"
#include "parser/parse_target.h" #include "parser/parse_target.h"
#include "parser/parse_coerce.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -149,7 +150,7 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause) ...@@ -149,7 +150,7 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
if (tle->resdom->resno == grpcl->entry->resdom->resno) if (tle->resdom->resno == grpcl->entry->resdom->resno)
{ {
if (contain_agg_clause((Node *) expr)) if (contain_agg_clause((Node *) expr))
elog(ERROR, "parser: aggregates not allowed in GROUP BY clause"); elog(ERROR, "Aggregates not allowed in GROUP BY clause");
return TRUE; return TRUE;
} }
} }
...@@ -189,7 +190,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry) ...@@ -189,7 +190,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
* non-group column in target list may fail.) * non-group column in target list may fail.)
*/ */
if (contain_agg_clause(qry->qual)) if (contain_agg_clause(qry->qual))
elog(ERROR, "parser: aggregates not allowed in WHERE clause"); elog(ERROR, "Aggregates not allowed in WHERE clause");
/* /*
* the target list can only contain aggregates, group columns and * the target list can only contain aggregates, group columns and
...@@ -201,7 +202,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry) ...@@ -201,7 +202,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
if (!tleIsAggOrGroupCol(tle, qry->groupClause)) if (!tleIsAggOrGroupCol(tle, qry->groupClause))
elog(ERROR, elog(ERROR,
"parser: illegal use of aggregates or non-group column in target list"); "Illegal use of aggregates or non-group column in target list");
} }
/* /*
...@@ -211,7 +212,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry) ...@@ -211,7 +212,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause)) if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
elog(ERROR, elog(ERROR,
"parser: illegal use of aggregates or non-group column in HAVING clause"); "Illegal use of aggregates or non-group column in HAVING clause");
return; return;
} }
...@@ -233,7 +234,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, ...@@ -233,7 +234,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
ObjectIdGetDatum(basetype), ObjectIdGetDatum(basetype),
0, 0); 0, 0);
if (!HeapTupleIsValid(theAggTuple)) if (!HeapTupleIsValid(theAggTuple))
elog(ERROR, "aggregate %s does not exist", aggname); elog(ERROR, "Aggregate %s does not exist", aggname);
/* /*
* We do a major hack for count(*) here. * We do a major hack for count(*) here.
...@@ -309,16 +310,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, ...@@ -309,16 +310,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
else else
vartype = ((Expr *) lfirst(target))->typeOid; vartype = ((Expr *) lfirst(target))->typeOid;
if (basetype != vartype) if ((basetype != vartype)
&& (! IS_BINARY_COMPATIBLE(basetype, vartype)))
{ {
Type tp1, Type tp1,
tp2; tp2;
tp1 = typeidType(basetype); tp1 = typeidType(basetype);
tp2 = typeidType(vartype); tp2 = typeidType(vartype);
elog(NOTICE, "Aggregate type mismatch:"); elog(ERROR, "Aggregate type mismatch"
elog(ERROR, "%s works on %s, not %s", aggname, "\n\t%s() works on %s, not on %s",
typeTypeName(tp1), typeTypeName(tp2)); aggname, typeTypeName(tp1), typeTypeName(tp2));
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.31 1998/11/27 19:52:13 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.32 1998/12/08 06:18:56 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "catalog/pg_inherits.h" #include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "catalog/pg_aggregate.h"
#include "fmgr.h" #include "fmgr.h"
#include "lib/dllist.h" #include "lib/dllist.h"
#include "miscadmin.h" #include "miscadmin.h"
...@@ -76,6 +77,8 @@ static List *setup_tlist(char *attname, Oid relid); ...@@ -76,6 +77,8 @@ static List *setup_tlist(char *attname, Oid relid);
static List *setup_base_tlist(Oid typeid); static List *setup_base_tlist(Oid typeid);
static Oid *func_select_candidate(int nargs, Oid *input_typeids, static Oid *func_select_candidate(int nargs, Oid *input_typeids,
CandidateList candidates); CandidateList candidates);
static int agg_get_candidates(char *aggname, Oid typeId, CandidateList *candidates);
static Oid agg_select_candidate(Oid typeid, CandidateList candidates);
#define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false) #define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)
...@@ -130,6 +133,108 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre ...@@ -130,6 +133,108 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
return retval; return retval;
} }
static int
agg_get_candidates(char *aggname,
Oid typeId,
CandidateList *candidates)
{
CandidateList current_candidate;
Relation pg_aggregate_desc;
HeapScanDesc pg_aggregate_scan;
HeapTuple tup;
Form_pg_aggregate agg;
int ncandidates = 0;
static ScanKeyData aggKey[1] = {
{0, Anum_pg_aggregate_aggname, F_NAMEEQ}};
*candidates = NULL;
fmgr_info(F_NAMEEQ, (FmgrInfo *) &aggKey[0].sk_func);
aggKey[0].sk_argument = NameGetDatum(aggname);
pg_aggregate_desc = heap_openr(AggregateRelationName);
pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,
0,
SnapshotSelf, /* ??? */
1,
aggKey);
while (HeapTupleIsValid(tup = heap_getnext(pg_aggregate_scan, 0)))
{
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(sizeof(Oid));
agg = (Form_pg_aggregate) GETSTRUCT(tup);
current_candidate->args[0] = agg->aggbasetype;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
}
heap_endscan(pg_aggregate_scan);
heap_close(pg_aggregate_desc);
return ncandidates;
} /* agg_get_candidates() */
/* agg_select_candidate()
* Try to choose only one candidate aggregate function from a list of possibles.
*/
static Oid
agg_select_candidate(Oid typeid, CandidateList candidates)
{
CandidateList current_candidate;
CandidateList last_candidate;
Oid current_typeid;
int ncandidates;
CATEGORY category,
current_category;
/*
* Look for candidates which allow coersion and have a preferred type.
* Keep all candidates if none match.
*/
category = TypeCategory(typeid);
ncandidates = 0;
last_candidate = NULL;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
{
current_typeid = current_candidate->args[0];
current_category = TypeCategory(current_typeid);
if ((current_category == category)
&& IsPreferredType(current_category, current_typeid)
&& can_coerce_type(1, &typeid, &current_typeid))
{
/* only one so far? then keep it... */
if (last_candidate == NULL)
{
candidates = current_candidate;
last_candidate = current_candidate;
ncandidates = 1;
}
/* otherwise, keep this one too... */
else
{
last_candidate->next = current_candidate;
last_candidate = current_candidate;
ncandidates++;
}
}
/* otherwise, don't bother keeping this one around... */
else
{
last_candidate->next = NULL;
}
}
return ((ncandidates == 1) ? candidates->args[0] : 0);
} /* agg_select_candidate() */
/* /*
* parse function * parse function
*/ */
...@@ -250,8 +355,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -250,8 +355,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
/* /*
* Parsing aggregates. * Parsing aggregates.
*/ */
Type tp; Type tp;
Oid basetype; Oid basetype;
int ncandidates;
CandidateList candidates;
/* /*
* the aggregate COUNT is a special case, ignore its base * the aggregate COUNT is a special case, ignore its base
...@@ -261,6 +369,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -261,6 +369,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
basetype = 0; basetype = 0;
else else
basetype = exprType(lfirst(fargs)); basetype = exprType(lfirst(fargs));
/* try for exact match first... */
if (SearchSysCacheTuple(AGGNAME, if (SearchSysCacheTuple(AGGNAME,
PointerGetDatum(funcname), PointerGetDatum(funcname),
ObjectIdGetDatum(basetype), ObjectIdGetDatum(basetype),
...@@ -268,16 +378,47 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -268,16 +378,47 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
return (Node *) ParseAgg(pstate, funcname, basetype, return (Node *) ParseAgg(pstate, funcname, basetype,
fargs, precedence); 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)
{
Oid type;
type = agg_select_candidate(basetype, candidates);
if (OidIsValid(type))
{
lfirst(fargs) = coerce_type(pstate, lfirst(fargs), basetype, type);
basetype = type;
return (Node *) ParseAgg(pstate, funcname, basetype,
fargs, precedence);
}
else
{
elog(ERROR,"Unable to select an aggregate function for type %s",
typeidTypeName(basetype));
}
}
/* /*
* See if this is a single argument function with the function * See if this is a single argument function with the function
* name also a type name and the input argument and type name * name also a type name and the input argument and type name
* binary compatible... * 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(TYPNAME, if ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPNAME,
PointerGetDatum(funcname), PointerGetDatum(funcname),
0, 0, 0))) 0, 0, 0)))
&& IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype)) && IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))
{
return ((Node *) lfirst(fargs)); return ((Node *) lfirst(fargs));
}
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.21 1998/11/27 19:52:14 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.22 1998/12/08 06:18:57 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -210,6 +210,7 @@ oper_select_candidate(int nargs, ...@@ -210,6 +210,7 @@ oper_select_candidate(int nargs,
nmatch++; nmatch++;
} }
/* take this one as the best choice so far? */
if ((nmatch > nbestMatch) || (last_candidate == NULL)) if ((nmatch > nbestMatch) || (last_candidate == NULL))
{ {
nbestMatch = nmatch; nbestMatch = nmatch;
...@@ -217,12 +218,14 @@ oper_select_candidate(int nargs, ...@@ -217,12 +218,14 @@ oper_select_candidate(int nargs,
last_candidate = current_candidate; last_candidate = current_candidate;
ncandidates = 1; ncandidates = 1;
} }
/* no worse than the last choice, so keep this one too? */
else if (nmatch == nbestMatch) else if (nmatch == nbestMatch)
{ {
last_candidate->next = current_candidate; last_candidate->next = current_candidate;
last_candidate = current_candidate; last_candidate = current_candidate;
ncandidates++; ncandidates++;
} }
/* otherwise, don't bother keeping this one... */
else else
{ {
last_candidate->next = NULL; last_candidate->next = NULL;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.44 1998/10/08 18:30:12 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.45 1998/12/08 06:19:15 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -577,6 +577,38 @@ text_ge(text *arg1, text *arg2) ...@@ -577,6 +577,38 @@ text_ge(text *arg1, text *arg2)
return (bool) !text_lt(arg1, arg2); return (bool) !text_lt(arg1, arg2);
} }
text *
text_larger(text *arg1, text *arg2)
{
text *result;
text *temp;
temp = ((text_cmp(arg1, arg2) <= 0)? arg2: arg1);
/* Make a copy */
result = (text *) palloc(VARSIZE(temp));
memmove((char *) result, (char *) temp, VARSIZE(temp));
return (result);
}
text *
text_smaller(text *arg1, text *arg2)
{
text *result;
text *temp;
temp = ((text_cmp(arg1, arg2) > 0)? arg2: arg1);
/* Make a copy */
result = (text *) palloc(VARSIZE(temp));
memmove((char *) result, (char *) temp, VARSIZE(temp));
return (result);
}
/*------------------------------------------------------------- /*-------------------------------------------------------------
* byteaGetSize * byteaGetSize
* *
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册