Make GROUP BY work with aliases, ORDER BY with column numbers
This commit is contained in:
parent
ec105b6026
commit
db7a90f1d9
@ -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));
|
||||
|
@ -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 <defelt> def_elem
|
||||
%type <node> def_arg, columnElem, where_clause,
|
||||
a_expr, AexprConst, in_expr_nodes, not_in_expr_nodes,
|
||||
having_clause, groupby
|
||||
having_clause
|
||||
%type <value> NumConst
|
||||
%type <attr> event_object, attr
|
||||
%type <sortby> sortby
|
||||
%type <sortgroupby> groupby
|
||||
%type <sortgroupby> sortby
|
||||
%type <ielem> index_elem, func_index
|
||||
%type <range> from_val
|
||||
%type <relexp> 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;
|
||||
}
|
||||
| attr
|
||||
groupby: Id
|
||||
{
|
||||
$$ = (Node*)$1;
|
||||
$$ = makeNode(SortGroupBy);
|
||||
$$->resno = 0;
|
||||
$$->range = NULL;
|
||||
$$->name = $1;
|
||||
$$->useOp = NULL;
|
||||
}
|
||||
| Id '.' Id
|
||||
{
|
||||
$$ = 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 @@
|
||||
*
|
||||
* 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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user