Commit db7a90f1 authored by Bruce Momjian's avatar Bruce Momjian

Make GROUP BY work with aliases, ORDER BY with column numbers

parent ec105b60
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.18 1996/11/30 18:06:20 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.19 1996/12/17 01:53:26 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -63,7 +63,8 @@ static TargetEntry *make_targetlist_expr(ParseState *pstate, ...@@ -63,7 +63,8 @@ static TargetEntry *make_targetlist_expr(ParseState *pstate,
char *colname, Node *expr, char *colname, Node *expr,
List *arrayRef); List *arrayRef);
static Node *transformWhereClause(ParseState *pstate, Node *a_expr); static Node *transformWhereClause(ParseState *pstate, Node *a_expr);
static List *transformGroupClause(ParseState *pstate, List *grouplist); static List *transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist);
static List *transformSortClause(ParseState *pstate, static List *transformSortClause(ParseState *pstate,
List *orderlist, List *targetlist, List *orderlist, List *targetlist,
char* uniqueFlag); char* uniqueFlag);
...@@ -422,13 +423,14 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt) ...@@ -422,13 +423,14 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
/* fix order clause */ /* fix order clause */
qry->sortClause = transformSortClause(pstate, qry->sortClause = transformSortClause(pstate,
stmt->orderClause, stmt->sortClause,
qry->targetList, qry->targetList,
qry->uniqueFlag); qry->uniqueFlag);
/* fix group by clause */ /* fix group by clause */
qry->groupClause = transformGroupClause(pstate, qry->groupClause = transformGroupClause(pstate,
stmt->groupClause); stmt->groupClause,
qry->targetList);
qry->rtable = pstate->p_rtable; qry->rtable = pstate->p_rtable;
if (pstate->p_numAgg > 0) if (pstate->p_numAgg > 0)
...@@ -505,12 +507,13 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt) ...@@ -505,12 +507,13 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
/* fix order clause */ /* fix order clause */
qry->sortClause = transformSortClause(pstate, qry->sortClause = transformSortClause(pstate,
stmt->orderClause, stmt->sortClause,
qry->targetList, qry->targetList,
qry->uniqueFlag); qry->uniqueFlag);
/* fix group by clause */ /* fix group by clause */
qry->groupClause = transformGroupClause(pstate, qry->groupClause = transformGroupClause(pstate,
stmt->groupClause); stmt->groupClause,
qry->targetList);
qry->rtable = pstate->p_rtable; qry->rtable = pstate->p_rtable;
...@@ -1426,19 +1429,21 @@ transformWhereClause(ParseState *pstate, Node *a_expr) ...@@ -1426,19 +1429,21 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
*****************************************************************************/ *****************************************************************************/
/* /*
* find_tl_elt - * find_targetlist_entry -
* returns the Resdom in the target list matching the specified varname * returns the Resdom in the target list matching the specified varname
* and range * and range
* *
*/ */
static Resdom * static TargetEntry *
find_tl_elt(ParseState *pstate, char *refname, char *colname, List *tlist) find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
{ {
List *i; List *i;
int real_rtable_pos = 0; int real_rtable_pos = 0, target_pos = 0;
TargetEntry *target_result = NULL;
if(refname)
real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable, refname); if(sortgroupby->range)
real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
sortgroupby->range);
foreach(i, tlist) { foreach(i, tlist) {
TargetEntry *target = (TargetEntry *)lfirst(i); TargetEntry *target = (TargetEntry *)lfirst(i);
...@@ -1447,17 +1452,30 @@ find_tl_elt(ParseState *pstate, char *refname, char *colname, List *tlist) ...@@ -1447,17 +1452,30 @@ find_tl_elt(ParseState *pstate, char *refname, char *colname, List *tlist)
char *resname = resnode->resname; char *resname = resnode->resname;
int test_rtable_pos = var->varno; int test_rtable_pos = var->varno;
if (!strcmp(resname, colname)) { if (!sortgroupby->name) {
if(refname) { if (sortgroupby->resno == ++target_pos) {
if(real_rtable_pos == test_rtable_pos) { target_result = target;
return (resnode); break;
} }
} else { }
return (resnode); else {
if (!strcmp(resname, sortgroupby->name)) {
if(sortgroupby->range) {
if(real_rtable_pos == test_rtable_pos) {
if (target_result != NULL)
elog(WARN, "Order/Group By %s is ambiguous", sortgroupby->name);
else target_result = target;
}
}
else {
if (target_result != NULL)
elog(WARN, "Order/Group By %s is ambiguous", sortgroupby->name);
else target_result = target;
}
} }
} }
} }
return ((Resdom *)NULL); return target_result;
} }
static Oid static Oid
...@@ -1478,22 +1496,27 @@ any_ordering_op(int restype) ...@@ -1478,22 +1496,27 @@ any_ordering_op(int restype)
* *
*/ */
static List * static List *
transformGroupClause(ParseState *pstate, List *grouplist) transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
{ {
List *glist = NIL, *gl = NIL; List *glist = NIL, *gl = NIL;
while (grouplist != NIL) { while (grouplist != NIL) {
GroupClause *grpcl = makeNode(GroupClause); GroupClause *grpcl = makeNode(GroupClause);
Var *groupAttr = (Var*)transformExpr(pstate, (Node*)lfirst(grouplist)); TargetEntry *restarget;
if (nodeTag(groupAttr) != T_Var) { restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
elog(WARN, "parser: can only specify attribute in group by");
} if (restarget == NULL)
grpcl->grpAttr = groupAttr; elog(WARN,"The field being grouped by must appear in the target list");
grpcl->grpOpoid = any_ordering_op(groupAttr->vartype); if (nodeTag(restarget->expr) != T_Var) {
if (glist == NIL) { elog(WARN, "parser: can only specify attribute in group by");
}
grpcl->grpAttr = (Var *)restarget->expr;
grpcl->grpOpoid = any_ordering_op(grpcl->grpAttr->vartype);
if (glist == NIL)
gl = glist = lcons(grpcl, NIL); gl = glist = lcons(grpcl, NIL);
} else { else {
lnext(gl) = lcons(grpcl, NIL); lnext(gl) = lcons(grpcl, NIL);
gl = lnext(gl); gl = lnext(gl);
} }
...@@ -1517,15 +1540,16 @@ transformSortClause(ParseState *pstate, ...@@ -1517,15 +1540,16 @@ transformSortClause(ParseState *pstate,
List *s = NIL, *i; List *s = NIL, *i;
while(orderlist != NIL) { while(orderlist != NIL) {
SortBy *sortby = lfirst(orderlist); SortGroupBy *sortby = lfirst(orderlist);
SortClause *sortcl = makeNode(SortClause); SortClause *sortcl = makeNode(SortClause);
TargetEntry *restarget;
Resdom *resdom; Resdom *resdom;
resdom = find_tl_elt(pstate, sortby->range, sortby->name, targetlist); restarget = find_targetlist_entry(pstate, sortby, targetlist);
if (resdom == NULL) if (restarget == NULL)
elog(WARN,"The field being sorted by must appear in the target list"); elog(WARN,"The field being ordered by must appear in the target list");
sortcl->resdom = resdom; sortcl->resdom = resdom = restarget->resdom;
sortcl->opoid = oprid(oper(sortby->useOp, sortcl->opoid = oprid(oper(sortby->useOp,
resdom->restype, resdom->restype,
resdom->restype)); resdom->restype));
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.21 1996/12/11 22:55:53 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.22 1996/12/17 01:53:29 momjian Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -82,7 +82,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); ...@@ -82,7 +82,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
TypeName *typnam; TypeName *typnam;
DefElem *defelt; DefElem *defelt;
ParamString *param; ParamString *param;
SortBy *sortby; SortGroupBy *sortgroupby;
IndexElem *ielem; IndexElem *ielem;
RangeVar *range; RangeVar *range;
RelExpr *relexp; RelExpr *relexp;
...@@ -146,10 +146,11 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); ...@@ -146,10 +146,11 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
%type <defelt> def_elem %type <defelt> def_elem
%type <node> def_arg, columnElem, where_clause, %type <node> def_arg, columnElem, where_clause,
a_expr, AexprConst, in_expr_nodes, not_in_expr_nodes, a_expr, AexprConst, in_expr_nodes, not_in_expr_nodes,
having_clause, groupby having_clause
%type <value> NumConst %type <value> NumConst
%type <attr> event_object, attr %type <attr> event_object, attr
%type <sortby> sortby %type <sortgroupby> groupby
%type <sortgroupby> sortby
%type <ielem> index_elem, func_index %type <ielem> index_elem, func_index
%type <range> from_val %type <range> from_val
%type <relexp> relation_expr %type <relexp> relation_expr
...@@ -1359,7 +1360,7 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR ...@@ -1359,7 +1360,7 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR
n->fromClause = $9; n->fromClause = $9;
n->whereClause = $10; n->whereClause = $10;
n->groupClause = $11; n->groupClause = $11;
n->orderClause = $12; n->sortClause = $12;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -1385,7 +1386,7 @@ RetrieveStmt: SELECT opt_unique res_target_list2 ...@@ -1385,7 +1386,7 @@ RetrieveStmt: SELECT opt_unique res_target_list2
n->whereClause = $6; n->whereClause = $6;
n->groupClause = $7; n->groupClause = $7;
n->havingClause = $8; n->havingClause = $8;
n->orderClause = $9; n->sortClause = $9;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -1413,22 +1414,28 @@ sortby_list: sortby ...@@ -1413,22 +1414,28 @@ sortby_list: sortby
sortby: Id OptUseOp sortby: Id OptUseOp
{ {
$$ = makeNode(SortBy); $$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = NULL; $$->range = NULL;
$$->name = $1; $$->name = $1;
$$->useOp = $2; $$->useOp = $2;
} }
| Id '.' Id OptUseOp | Id '.' Id OptUseOp
{ {
$$ = makeNode(SortBy); $$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = $1; $$->range = $1;
$$->name = $3; $$->name = $3;
$$->useOp = $4; $$->useOp = $4;
} }
| /*EMPTY*/ | Iconst OptUseOp
{ {
yyerror("parse error: use 'order by attribute_name'"); $$ = makeNode(SortGroupBy);
} $$->resno = $1;
$$->range = NULL;
$$->name = NULL;
$$->useOp = $2;
}
; ;
OptUseOp: USING Op { $$ = $2; } OptUseOp: USING Op { $$ = $2; }
...@@ -1509,16 +1516,29 @@ groupby_list: groupby { $$ = lcons($1, NIL); } ...@@ -1509,16 +1516,29 @@ groupby_list: groupby { $$ = lcons($1, NIL); }
| groupby_list ',' groupby { $$ = lappend($1, $3); } | groupby_list ',' groupby { $$ = lappend($1, $3); }
; ;
groupby: Id groupby: Id
{ {
Ident *n = makeNode(Ident); $$ = makeNode(SortGroupBy);
n->name = $1; $$->resno = 0;
n->indirection = NULL; $$->range = NULL;
$$ = (Node*)n; $$->name = $1;
$$->useOp = NULL;
} }
| attr | Id '.' Id
{ {
$$ = (Node*)$1; $$ = makeNode(SortGroupBy);
$$->resno = 0;
$$->range = $1;
$$->name = $3;
$$->useOp = NULL;
}
| Iconst
{
$$ = makeNode(SortGroupBy);
$$->resno = $1;
$$->range = NULL;
$$->name = NULL;
$$->useOp = NULL;
} }
; ;
......
...@@ -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: nodes.h,v 1.3 1996/11/03 12:12:52 scrappy Exp $ * $Id: nodes.h,v 1.4 1996/12/17 01:53:40 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -190,7 +190,7 @@ typedef enum NodeTag { ...@@ -190,7 +190,7 @@ typedef enum NodeTag {
T_ParamString, T_ParamString,
T_TimeRange, T_TimeRange,
T_RelExpr, T_RelExpr,
T_SortBy, T_SortGroupBy,
T_RangeVar, T_RangeVar,
T_TypeName, T_TypeName,
T_IndexElem, T_IndexElem,
......
...@@ -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.7 1996/11/13 20:56:15 scrappy Exp $ * $Id: parsenodes.h,v 1.8 1996/12/17 01:53:43 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -463,7 +463,7 @@ typedef struct CursorStmt { ...@@ -463,7 +463,7 @@ typedef struct CursorStmt {
List *fromClause; /* the from clause */ List *fromClause; /* the from clause */
Node *whereClause; /* qualifications */ Node *whereClause; /* qualifications */
List *groupClause; /* group by clause */ List *groupClause; /* group by clause */
List *orderClause; /* sort clause (a list of SortBy's) */ List *sortClause; /* sort clause (a list of SortGroupBy's) */
} CursorStmt; } CursorStmt;
/* ---------------------- /* ----------------------
...@@ -480,7 +480,7 @@ typedef struct RetrieveStmt { ...@@ -480,7 +480,7 @@ typedef struct RetrieveStmt {
Node *whereClause; /* qualifications */ Node *whereClause; /* qualifications */
List *groupClause; /* group by clause */ List *groupClause; /* group by clause */
Node *havingClause; /* having conditional-expression */ Node *havingClause; /* having conditional-expression */
List *orderClause; /* sort clause (a list of SortBy's) */ List *sortClause; /* sort clause (a list of SortGroupBy's) */
} RetrieveStmt; } RetrieveStmt;
...@@ -627,14 +627,15 @@ typedef struct RelExpr { ...@@ -627,14 +627,15 @@ typedef struct RelExpr {
} RelExpr; } RelExpr;
/* /*
* Sortby - for order by clause * SortGroupBy - for order by clause
*/ */
typedef struct SortBy { typedef struct SortGroupBy {
NodeTag type; NodeTag type;
int resno; /* target number */
char *range; char *range;
char *name; /* name of column to sort on */ char *name; /* name of column to sort on */
char *useOp; /* operator to use */ char *useOp; /* operator to use */
} SortBy; } SortGroupBy;
/* /*
* RangeVar - range variable, used in from clauses * RangeVar - range variable, used in from clauses
......
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