summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>1998-01-04 04:31:43 +0000
committerBruce Momjian <bruce@momjian.us>1998-01-04 04:31:43 +0000
commit4b05912f0b6aa69507bc32ac6ddaf8aeecdeb396 (patch)
tree2ff63f8cd09f1d5c628cefb16827c406ef40f014 /src/backend/parser
parentc629d3b9d65fdce320aba26d092bfe96274c6092 (diff)
downloadpostgresql-4b05912f0b6aa69507bc32ac6ddaf8aeecdeb396.tar.gz
Fix for count(*), aggs with views and multiple tables and sum(3).
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y11
-rw-r--r--src/backend/parser/parse_agg.c84
-rw-r--r--src/backend/parser/parse_func.c14
-rw-r--r--src/backend/parser/parse_relation.c30
-rw-r--r--src/backend/parser/parse_target.c7
5 files changed, 91 insertions, 55 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c64c8d41d2..963d5adf0d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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 '(' '*' ')'
{
+ /* cheap hack for aggregate (eg. count) */
FuncCall *n = makeNode(FuncCall);
- Ident *star = makeNode(Ident);
+ A_Const *star = makeNode(A_Const);
- /* cheap hack for aggregate (eg. count) */
- star->name = "oid";
+ star->val.type = T_String;
+ star->val.val.str = "";
n->funcname = $1;
n->args = lcons(star, NIL);
$$ = (Node *)n;
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index e776f69500..a244d0398c 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -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;
}
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 4d1017b54a..43c78e299d 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -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)),
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 2b880213d7..e2c53ed152 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -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
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 04739fe550..a7049b0b3f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -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);