mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
From: David Hartwig <daveh@insightdist.com>
Here is a patch to remove the requirement that ORDER/GROUP BY clause identifiers be included in the target list.
This commit is contained in:
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.45 1998/02/27 08:43:52 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.46 1998/05/21 03:53:50 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -521,14 +521,16 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||||||
* NOTE: in the future we might want to initialize the junk
|
* NOTE: in the future we might want to initialize the junk
|
||||||
* filter for all queries.
|
* filter for all queries.
|
||||||
* ----------------
|
* ----------------
|
||||||
|
* SELECT added by daveh@insightdist.com 5/20/98 to allow
|
||||||
|
* ORDER/GROUP BY have an identifier missing from the target.
|
||||||
*/
|
*/
|
||||||
if (operation == CMD_UPDATE || operation == CMD_DELETE ||
|
if (operation == CMD_UPDATE || operation == CMD_DELETE ||
|
||||||
operation == CMD_INSERT)
|
operation == CMD_INSERT || operation == CMD_SELECT)
|
||||||
{
|
{
|
||||||
|
|
||||||
JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList);
|
JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList);
|
||||||
|
|
||||||
estate->es_junkFilter = j;
|
estate->es_junkFilter = j;
|
||||||
|
|
||||||
|
tupType = j->jf_cleanTupType; /* Added by daveh@insightdist.com 5/20/98 */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
estate->es_junkFilter = NULL;
|
estate->es_junkFilter = NULL;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.15 1998/03/31 04:43:53 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.16 1998/05/21 03:53:50 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -182,6 +182,37 @@ find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BEGIN add missing target entry hack.
|
||||||
|
*
|
||||||
|
* Prior to this hack, this function returned NIL if no target_result.
|
||||||
|
* Thus, ORDER/GROUP BY required the attributes be in the target list.
|
||||||
|
* Now it constructs a new target entry which is appended to the end of
|
||||||
|
* the target list. This target is set to be resjunk = TRUE so that
|
||||||
|
* it will not be projected into the final tuple.
|
||||||
|
* daveh@insightdist.com 5/20/98
|
||||||
|
*/
|
||||||
|
if ( ! target_result) {
|
||||||
|
List *p_target = tlist;
|
||||||
|
Ident *missingTargetId = (Ident *)makeNode(Ident);
|
||||||
|
TargetEntry *tent = makeNode(TargetEntry);
|
||||||
|
|
||||||
|
/* Fill in the constructed Ident node */
|
||||||
|
missingTargetId->type = T_Ident;
|
||||||
|
missingTargetId->name = palloc(strlen(sortgroupby->name) + 1);
|
||||||
|
strcpy(missingTargetId->name, sortgroupby->name);
|
||||||
|
|
||||||
|
transformTargetId(pstate, missingTargetId, tent, missingTargetId->name, TRUE);
|
||||||
|
|
||||||
|
/* Add to the end of the target list */
|
||||||
|
while (lnext(p_target) != NIL) {
|
||||||
|
p_target = lnext(p_target);
|
||||||
|
}
|
||||||
|
lnext(p_target) = lcons(tent, NIL);
|
||||||
|
target_result = tent;
|
||||||
|
}
|
||||||
|
/* END add missing target entry hack. */
|
||||||
|
|
||||||
return target_result;
|
return target_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,10 +234,6 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
|
|||||||
Resdom *resdom;
|
Resdom *resdom;
|
||||||
|
|
||||||
restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
|
restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
|
||||||
|
|
||||||
if (restarget == NULL)
|
|
||||||
elog(ERROR, "The field being grouped by must appear in the target list");
|
|
||||||
|
|
||||||
grpcl->entry = restarget;
|
grpcl->entry = restarget;
|
||||||
resdom = restarget->resdom;
|
resdom = restarget->resdom;
|
||||||
grpcl->grpOpoid = oprid(oper("<",
|
grpcl->grpOpoid = oprid(oper("<",
|
||||||
@ -262,9 +289,6 @@ transformSortClause(ParseState *pstate,
|
|||||||
|
|
||||||
|
|
||||||
restarget = find_targetlist_entry(pstate, sortby, targetlist);
|
restarget = find_targetlist_entry(pstate, sortby, targetlist);
|
||||||
if (restarget == NULL)
|
|
||||||
elog(ERROR, "The field being ordered by must appear in the target list");
|
|
||||||
|
|
||||||
sortcl->resdom = resdom = restarget->resdom;
|
sortcl->resdom = resdom = restarget->resdom;
|
||||||
sortcl->opoid = oprid(oper(sortby->useOp,
|
sortcl->opoid = oprid(oper(sortby->useOp,
|
||||||
resdom->restype,
|
resdom->restype,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.12 1998/05/09 23:29:54 thomas Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.13 1998/05/21 03:53:51 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -52,6 +52,51 @@ coerce_target_expr(ParseState *pstate,
|
|||||||
Oid type_id,
|
Oid type_id,
|
||||||
Oid attrtype);
|
Oid attrtype);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transformTargetId - transforms an Ident Node to a Target Entry
|
||||||
|
* Created this a function to allow the ORDER/GROUP BY clause be able
|
||||||
|
* to construct a TargetEntry from an Ident.
|
||||||
|
*
|
||||||
|
* resjunk = TRUE will hide the target entry in the final result tuple.
|
||||||
|
* daveh@insightdist.com 5/20/98
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
transformTargetId(ParseState *pstate,
|
||||||
|
Ident *ident,
|
||||||
|
TargetEntry *tent,
|
||||||
|
char *resname,
|
||||||
|
int16 resjunk)
|
||||||
|
{
|
||||||
|
Node *expr;
|
||||||
|
Oid type_id;
|
||||||
|
int16 type_mod;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* here we want to look for column names only, not
|
||||||
|
* relation names (even though they can be stored in
|
||||||
|
* Ident nodes, too)
|
||||||
|
*/
|
||||||
|
expr = transformIdent(pstate, (Node *) ident, EXPR_COLUMN_FIRST);
|
||||||
|
type_id = exprType(expr);
|
||||||
|
if (nodeTag(expr) == T_Var)
|
||||||
|
type_mod = ((Var *) expr)->vartypmod;
|
||||||
|
else
|
||||||
|
type_mod = -1;
|
||||||
|
tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
|
||||||
|
(Oid) type_id,
|
||||||
|
type_mod,
|
||||||
|
resname,
|
||||||
|
(Index) 0,
|
||||||
|
(Oid) 0,
|
||||||
|
resjunk);
|
||||||
|
|
||||||
|
tent->expr = expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transformTargetList -
|
* transformTargetList -
|
||||||
* turns a list of ResTarget's into a list of TargetEntry's
|
* turns a list of ResTarget's into a list of TargetEntry's
|
||||||
@ -71,36 +116,13 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
{
|
{
|
||||||
case T_Ident:
|
case T_Ident:
|
||||||
{
|
{
|
||||||
Node *expr;
|
|
||||||
Oid type_id;
|
|
||||||
int16 type_mod;
|
|
||||||
char *identname;
|
char *identname;
|
||||||
char *resname;
|
char *resname;
|
||||||
|
|
||||||
identname = ((Ident *) res->val)->name;
|
identname = ((Ident *) res->val)->name;
|
||||||
handleTargetColname(pstate, &res->name, NULL, identname);
|
handleTargetColname(pstate, &res->name, NULL, identname);
|
||||||
|
|
||||||
/*
|
|
||||||
* here we want to look for column names only, not
|
|
||||||
* relation names (even though they can be stored in
|
|
||||||
* Ident nodes, too)
|
|
||||||
*/
|
|
||||||
expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
|
|
||||||
type_id = exprType(expr);
|
|
||||||
if (nodeTag(expr) == T_Var)
|
|
||||||
type_mod = ((Var *) expr)->vartypmod;
|
|
||||||
else
|
|
||||||
type_mod = -1;
|
|
||||||
resname = (res->name) ? res->name : identname;
|
resname = (res->name) ? res->name : identname;
|
||||||
tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
|
transformTargetId(pstate, (Ident*)res->val, tent, resname, FALSE);
|
||||||
(Oid) type_id,
|
|
||||||
type_mod,
|
|
||||||
resname,
|
|
||||||
(Index) 0,
|
|
||||||
(Oid) 0,
|
|
||||||
0);
|
|
||||||
|
|
||||||
tent->expr = expr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_ParamNo:
|
case T_ParamNo:
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parse_target.h,v 1.4 1998/02/26 04:42:49 momjian Exp $
|
* $Id: parse_target.h,v 1.5 1998/05/21 03:53:51 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -24,5 +24,7 @@
|
|||||||
|
|
||||||
extern List *transformTargetList(ParseState *pstate, List *targetlist);
|
extern List *transformTargetList(ParseState *pstate, List *targetlist);
|
||||||
extern List *makeTargetNames(ParseState *pstate, List *cols);
|
extern List *makeTargetNames(ParseState *pstate, List *cols);
|
||||||
|
extern void transformTargetId(ParseState *pstate, Ident *ident,
|
||||||
|
TargetEntry *tent, char *resname, int16 resjunk);
|
||||||
|
|
||||||
#endif /* PARSE_TARGET_H */
|
#endif /* PARSE_TARGET_H */
|
||||||
|
Reference in New Issue
Block a user