mirror of
https://github.com/postgres/postgres.git
synced 2025-07-20 05:03:10 +03:00
Fix for count(*), aggs with views and multiple tables and sum(3).
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.82 1998/01/01 05:44:53 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.83 1998/01/04 04:31:08 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -2381,8 +2381,6 @@ OptUseOp: USING Op { $$ = $2; }
|
||||
*
|
||||
* ...however, recursive addattr and rename supported. make special
|
||||
* cases for these.
|
||||
*
|
||||
* XXX i believe '*' should be the default behavior, but...
|
||||
*/
|
||||
opt_inh_star: '*' { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
@ -2978,11 +2976,12 @@ a_expr: attr opt_indirection
|
||||
}
|
||||
| name '(' '*' ')'
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
Ident *star = makeNode(Ident);
|
||||
|
||||
/* cheap hack for aggregate (eg. count) */
|
||||
star->name = "oid";
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
A_Const *star = makeNode(A_Const);
|
||||
|
||||
star->val.type = T_String;
|
||||
star->val.val.str = "";
|
||||
n->funcname = $1;
|
||||
n->args = lcons(star, NIL);
|
||||
$$ = (Node *)n;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.4 1997/12/22 05:42:19 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.5 1998/01/04 04:31:14 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -18,14 +18,17 @@
|
||||
#include "postgres.h"
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "nodes/primnodes.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_node.h"
|
||||
#include "parser/parse_target.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
static bool contain_agg_clause(Node *clause);
|
||||
static bool exprIsAggOrGroupCol(Node *expr, List *groupClause);
|
||||
@ -276,7 +279,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
|
||||
|
||||
|
||||
Aggreg *
|
||||
ParseAgg(char *aggname, Oid basetype, Node *target)
|
||||
ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
|
||||
List *target, int precedence)
|
||||
{
|
||||
Oid fintype;
|
||||
Oid vartype;
|
||||
@ -284,7 +288,8 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
|
||||
Form_pg_aggregate aggform;
|
||||
Aggreg *aggreg;
|
||||
HeapTuple theAggTuple;
|
||||
|
||||
bool usenulls = false;
|
||||
|
||||
theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0);
|
||||
@ -293,21 +298,78 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
|
||||
elog(WARN, "aggregate %s does not exist", aggname);
|
||||
}
|
||||
|
||||
/*
|
||||
* We do a major hack for count(*) here.
|
||||
*
|
||||
* Count(*) poses several problems. First, we need a field that is
|
||||
* guaranteed to be in the range table, and unique. Using a constant
|
||||
* causes the optimizer to properly remove the aggragate from any
|
||||
* elements of the query.
|
||||
* Using just 'oid', which can not be null, in the parser fails on:
|
||||
*
|
||||
* select count(*) from tab1, tab2 -- oid is not unique
|
||||
* select count(*) from viewtable -- views don't have real oids
|
||||
*
|
||||
* So, for an aggregate with parameter '*', we use the first valid
|
||||
* range table entry, and pick the first column from the table.
|
||||
* We set a flag to count nulls, because we could have nulls in
|
||||
* that column.
|
||||
*/
|
||||
|
||||
if (nodeTag(lfirst(target)) == T_Const)
|
||||
{
|
||||
Const *con = (Const *)lfirst(target);
|
||||
|
||||
if (con->consttype == UNKNOWNOID && VARSIZE(con->constvalue) == VARHDRSZ)
|
||||
{
|
||||
Attr *attr = makeNode(Attr);
|
||||
List *rtable, *rlist;
|
||||
RangeTblEntry *first_valid_rte;
|
||||
|
||||
Assert(lnext(target) == NULL);
|
||||
|
||||
if (pstate->p_is_rule)
|
||||
rtable = lnext(lnext(pstate->p_rtable));
|
||||
else
|
||||
rtable = pstate->p_rtable;
|
||||
|
||||
first_valid_rte = NULL;
|
||||
foreach(rlist, rtable)
|
||||
{
|
||||
RangeTblEntry *rte = lfirst(rlist);
|
||||
|
||||
/* only entries on outer(non-function?) scope */
|
||||
if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
|
||||
continue;
|
||||
|
||||
first_valid_rte =rte;
|
||||
break;
|
||||
}
|
||||
if (first_valid_rte == NULL)
|
||||
elog(WARN, "Can't find column to do aggregate(*) on.");
|
||||
|
||||
attr->relname = first_valid_rte->refname;
|
||||
attr->attrs = lcons(makeString(
|
||||
get_attname(first_valid_rte->relid,1)),NIL);
|
||||
|
||||
lfirst(target) = transformExpr(pstate, (Node *) attr, precedence);
|
||||
usenulls = true;
|
||||
}
|
||||
}
|
||||
|
||||
aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
|
||||
fintype = aggform->aggfinaltype;
|
||||
xfn1 = aggform->aggtransfn1;
|
||||
|
||||
if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
|
||||
elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
|
||||
|
||||
|
||||
/* only aggregates with transfn1 need a base type */
|
||||
if (OidIsValid(xfn1))
|
||||
{
|
||||
basetype = aggform->aggbasetype;
|
||||
if (nodeTag(target) == T_Var)
|
||||
vartype = ((Var *) target)->vartype;
|
||||
if (nodeTag(lfirst(target)) == T_Var)
|
||||
vartype = ((Var *) lfirst(target))->vartype;
|
||||
else
|
||||
vartype = ((Expr *) target)->typeOid;
|
||||
vartype = ((Expr *) lfirst(target))->typeOid;
|
||||
|
||||
if (basetype != vartype)
|
||||
{
|
||||
@ -327,7 +389,9 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
|
||||
aggreg->basetype = aggform->aggbasetype;
|
||||
aggreg->aggtype = fintype;
|
||||
|
||||
aggreg->target = target;
|
||||
aggreg->target = lfirst(target);
|
||||
if (usenulls)
|
||||
aggreg->usenulls = true;
|
||||
|
||||
return aggreg;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.3 1997/11/26 03:42:42 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.4 1998/01/04 04:31:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -87,7 +87,8 @@ typedef struct _SuperQE
|
||||
*/
|
||||
|
||||
Node *
|
||||
ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
|
||||
ParseFunc(ParseState *pstate, char *funcname, List *fargs,
|
||||
int *curr_resno, int precedence)
|
||||
{
|
||||
Oid rettype = (Oid) 0;
|
||||
Oid argrelid = (Oid) 0;
|
||||
@ -194,9 +195,7 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
|
||||
*/
|
||||
if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
|
||||
&& strcmp(funcname, "*"))
|
||||
{
|
||||
elog(WARN, "Functions on sets are not yet supported");
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
@ -223,7 +222,8 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0))
|
||||
{
|
||||
Aggreg *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
|
||||
Aggreg *aggreg = ParseAgg(pstate, funcname, basetype,
|
||||
fargs, precedence);
|
||||
|
||||
AddAggToParseState(pstate, aggreg);
|
||||
return (Node *) aggreg;
|
||||
@ -368,7 +368,7 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
|
||||
else
|
||||
{
|
||||
funcnode->func_tlist = setup_tlist(funcname, argrelid);
|
||||
rettype = attnameTypeId(argrelid, funcname);
|
||||
rettype = get_atttype(argrelid, get_attnum(argrelid, funcname));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1031,7 +1031,7 @@ setup_tlist(char *attname, Oid relid)
|
||||
if (attno < 0)
|
||||
elog(WARN, "cannot reference attribute '%s' of tuple params/return values for functions", attname);
|
||||
|
||||
typeid = attnameTypeId(relid, attname);
|
||||
typeid = get_atttype(relid, attno);
|
||||
resnode = makeResdom(1,
|
||||
typeid,
|
||||
typeLen(typeidType(typeid)),
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.3 1997/11/26 03:42:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.4 1998/01/04 04:31:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -346,34 +346,6 @@ attnumAttNelems(Relation rd, int attid)
|
||||
return (rd->rd_att->attrs[attid - 1]->attnelems);
|
||||
}
|
||||
|
||||
Oid
|
||||
attnameTypeId(Oid relid, char *attrname)
|
||||
{
|
||||
int attid;
|
||||
Oid vartype;
|
||||
Relation rd;
|
||||
|
||||
rd = heap_open(relid);
|
||||
if (!RelationIsValid(rd))
|
||||
{
|
||||
rd = heap_openr(typeidTypeName(relid));
|
||||
if (!RelationIsValid(rd))
|
||||
elog(WARN, "cannot compute type of att %s for relid %d",
|
||||
attrname, relid);
|
||||
}
|
||||
|
||||
attid = attnameAttNum(rd, attrname); /* could elog(WARN) and never return */
|
||||
|
||||
vartype = attnumTypeId(rd, attid);
|
||||
|
||||
/*
|
||||
* close relation we're done with it now
|
||||
*/
|
||||
heap_close(rd);
|
||||
|
||||
return (vartype);
|
||||
}
|
||||
|
||||
/* given attribute id, return type of that attribute */
|
||||
/* XXX Special case for pseudo-attributes is a hack */
|
||||
Oid
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.3 1997/11/26 03:42:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.4 1998/01/04 04:31:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -255,7 +255,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
* Target item is fully specified: ie.
|
||||
* relation.attribute
|
||||
*/
|
||||
result = handleNestedDots(pstate, att, &pstate->p_last_resno);
|
||||
result = handleNestedDots(pstate, att, &pstate->p_last_resno,EXPR_COLUMN_FIRST);
|
||||
handleTargetColname(pstate, &res->name, att->relname, attrname);
|
||||
if (att->indirection != NIL)
|
||||
{
|
||||
@ -467,7 +467,8 @@ make_targetlist_expr(ParseState *pstate,
|
||||
att->relname = pstrdup(RelationGetRelationName(rd)->data);
|
||||
att->attrs = lcons(makeString(colname), NIL);
|
||||
target_expr = (Expr *) handleNestedDots(pstate, att,
|
||||
&pstate->p_last_resno);
|
||||
&pstate->p_last_resno,
|
||||
EXPR_COLUMN_FIRST);
|
||||
while (ar != NIL)
|
||||
{
|
||||
A_Indices *ind = lfirst(ar);
|
||||
|
Reference in New Issue
Block a user