From db7a90f1d9cd8dfa148fb3524ec0c1e902511c9e Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Tue, 17 Dec 1996 01:53:43 +0000 Subject: [PATCH] Make GROUP BY work with aliases, ORDER BY with column numbers --- src/backend/parser/analyze.c | 98 +++++++++++++++++++++------------- src/backend/parser/gram.y | 60 ++++++++++++++------- src/include/nodes/nodes.h | 4 +- src/include/nodes/parsenodes.h | 13 ++--- 4 files changed, 110 insertions(+), 65 deletions(-) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index e4b9fad1b5..29eb7d3cf9 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -7,7 +7,7 @@ * * * 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, char *colname, Node *expr, List *arrayRef); 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, List *orderlist, List *targetlist, char* uniqueFlag); @@ -422,13 +423,14 @@ transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt) /* fix order clause */ qry->sortClause = transformSortClause(pstate, - stmt->orderClause, + stmt->sortClause, qry->targetList, qry->uniqueFlag); /* fix group by clause */ qry->groupClause = transformGroupClause(pstate, - stmt->groupClause); + stmt->groupClause, + qry->targetList); qry->rtable = pstate->p_rtable; if (pstate->p_numAgg > 0) @@ -505,12 +507,13 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt) /* fix order clause */ qry->sortClause = transformSortClause(pstate, - stmt->orderClause, + stmt->sortClause, qry->targetList, qry->uniqueFlag); /* fix group by clause */ qry->groupClause = transformGroupClause(pstate, - stmt->groupClause); + stmt->groupClause, + qry->targetList); qry->rtable = pstate->p_rtable; @@ -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 * and range * */ -static Resdom * -find_tl_elt(ParseState *pstate, char *refname, char *colname, List *tlist) +static TargetEntry * +find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist) { List *i; - int real_rtable_pos = 0; - - if(refname) - real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable, refname); + int real_rtable_pos = 0, target_pos = 0; + TargetEntry *target_result = NULL; + + if(sortgroupby->range) + real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable, + sortgroupby->range); foreach(i, tlist) { TargetEntry *target = (TargetEntry *)lfirst(i); @@ -1447,17 +1452,30 @@ find_tl_elt(ParseState *pstate, char *refname, char *colname, List *tlist) char *resname = resnode->resname; int test_rtable_pos = var->varno; - if (!strcmp(resname, colname)) { - if(refname) { - if(real_rtable_pos == test_rtable_pos) { - return (resnode); - } - } else { - return (resnode); + if (!sortgroupby->name) { + if (sortgroupby->resno == ++target_pos) { + target_result = target; + break; + } + } + 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 @@ -1478,22 +1496,27 @@ any_ordering_op(int restype) * */ static List * -transformGroupClause(ParseState *pstate, List *grouplist) +transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) { List *glist = NIL, *gl = NIL; while (grouplist != NIL) { GroupClause *grpcl = makeNode(GroupClause); - Var *groupAttr = (Var*)transformExpr(pstate, (Node*)lfirst(grouplist)); + TargetEntry *restarget; - if (nodeTag(groupAttr) != T_Var) { - elog(WARN, "parser: can only specify attribute in group by"); - } - grpcl->grpAttr = groupAttr; - grpcl->grpOpoid = any_ordering_op(groupAttr->vartype); - if (glist == NIL) { + restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist); + + if (restarget == NULL) + elog(WARN,"The field being grouped by must appear in the target list"); + if (nodeTag(restarget->expr) != T_Var) { + 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); - } else { + else { lnext(gl) = lcons(grpcl, NIL); gl = lnext(gl); } @@ -1517,15 +1540,16 @@ transformSortClause(ParseState *pstate, List *s = NIL, *i; while(orderlist != NIL) { - SortBy *sortby = lfirst(orderlist); + SortGroupBy *sortby = lfirst(orderlist); SortClause *sortcl = makeNode(SortClause); + TargetEntry *restarget; Resdom *resdom; - - resdom = find_tl_elt(pstate, sortby->range, sortby->name, targetlist); - if (resdom == NULL) - elog(WARN,"The field being sorted by must appear in the target list"); - - sortcl->resdom = resdom; + + restarget = find_targetlist_entry(pstate, sortby, targetlist); + if (restarget == NULL) + elog(WARN,"The field being ordered by must appear in the target list"); + + sortcl->resdom = resdom = restarget->resdom; sortcl->opoid = oprid(oper(sortby->useOp, resdom->restype, resdom->restype)); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 2dc6c6145b..2e4e1f7a83 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.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 * AUTHOR DATE MAJOR EVENT @@ -82,7 +82,7 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); TypeName *typnam; DefElem *defelt; ParamString *param; - SortBy *sortby; + SortGroupBy *sortgroupby; IndexElem *ielem; RangeVar *range; RelExpr *relexp; @@ -146,10 +146,11 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr); %type def_elem %type def_arg, columnElem, where_clause, a_expr, AexprConst, in_expr_nodes, not_in_expr_nodes, - having_clause, groupby + having_clause %type NumConst %type event_object, attr -%type sortby +%type groupby +%type sortby %type index_elem, func_index %type from_val %type relation_expr @@ -1359,7 +1360,7 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR n->fromClause = $9; n->whereClause = $10; n->groupClause = $11; - n->orderClause = $12; + n->sortClause = $12; $$ = (Node *)n; } ; @@ -1385,7 +1386,7 @@ RetrieveStmt: SELECT opt_unique res_target_list2 n->whereClause = $6; n->groupClause = $7; n->havingClause = $8; - n->orderClause = $9; + n->sortClause = $9; $$ = (Node *)n; } ; @@ -1413,22 +1414,28 @@ sortby_list: sortby sortby: Id OptUseOp { - $$ = makeNode(SortBy); + $$ = makeNode(SortGroupBy); + $$->resno = 0; $$->range = NULL; $$->name = $1; $$->useOp = $2; } | Id '.' Id OptUseOp { - $$ = makeNode(SortBy); + $$ = makeNode(SortGroupBy); + $$->resno = 0; $$->range = $1; $$->name = $3; $$->useOp = $4; } - | /*EMPTY*/ - { - yyerror("parse error: use 'order by attribute_name'"); - } + | Iconst OptUseOp + { + $$ = makeNode(SortGroupBy); + $$->resno = $1; + $$->range = NULL; + $$->name = NULL; + $$->useOp = $2; + } ; OptUseOp: USING Op { $$ = $2; } @@ -1509,16 +1516,29 @@ groupby_list: groupby { $$ = lcons($1, NIL); } | groupby_list ',' groupby { $$ = lappend($1, $3); } ; -groupby: Id - { - Ident *n = makeNode(Ident); - n->name = $1; - n->indirection = NULL; - $$ = (Node*)n; +groupby: Id + { + $$ = makeNode(SortGroupBy); + $$->resno = 0; + $$->range = NULL; + $$->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; } ; diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 992933c59f..c1203ac78b 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -6,7 +6,7 @@ * * 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 { T_ParamString, T_TimeRange, T_RelExpr, - T_SortBy, + T_SortGroupBy, T_RangeVar, T_TypeName, T_IndexElem, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 01c037b54f..9c6500135c 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -6,7 +6,7 @@ * * 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 { List *fromClause; /* the from clause */ Node *whereClause; /* qualifications */ List *groupClause; /* group by clause */ - List *orderClause; /* sort clause (a list of SortBy's) */ + List *sortClause; /* sort clause (a list of SortGroupBy's) */ } CursorStmt; /* ---------------------- @@ -480,7 +480,7 @@ typedef struct RetrieveStmt { Node *whereClause; /* qualifications */ List *groupClause; /* group by clause */ Node *havingClause; /* having conditional-expression */ - List *orderClause; /* sort clause (a list of SortBy's) */ + List *sortClause; /* sort clause (a list of SortGroupBy's) */ } RetrieveStmt; @@ -627,14 +627,15 @@ typedef struct RelExpr { } RelExpr; /* - * Sortby - for order by clause + * SortGroupBy - for order by clause */ -typedef struct SortBy { +typedef struct SortGroupBy { NodeTag type; + int resno; /* target number */ char *range; char *name; /* name of column to sort on */ char *useOp; /* operator to use */ -} SortBy; +} SortGroupBy; /* * RangeVar - range variable, used in from clauses -- 2.40.0