From 9f3d63936b0e155f71a020dc0255c323b9e67c2a Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Thu, 21 May 1998 03:53:51 +0000 Subject: [PATCH] From: David Hartwig Here is a patch to remove the requirement that ORDER/GROUP BY clause identifiers be included in the target list. --- src/backend/executor/execMain.c | 10 +++-- src/backend/parser/parse_clause.c | 40 +++++++++++++---- src/backend/parser/parse_target.c | 72 ++++++++++++++++++++----------- src/include/parser/parse_target.h | 4 +- 4 files changed, 88 insertions(+), 38 deletions(-) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 35107c8af2..1437c2e8c9 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * 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 * 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 || - operation == CMD_INSERT) + operation == CMD_INSERT || operation == CMD_SELECT) { - JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList); - estate->es_junkFilter = j; + + tupType = j->jf_cleanTupType; /* Added by daveh@insightdist.com 5/20/98 */ } else estate->es_junkFilter = NULL; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 30be833535..06c7cdee5f 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -7,7 +7,7 @@ * * * 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; } @@ -203,10 +234,6 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist) Resdom *resdom; 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; resdom = restarget->resdom; grpcl->grpOpoid = oprid(oper("<", @@ -262,9 +289,6 @@ transformSortClause(ParseState *pstate, 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->opoid = oprid(oper(sortby->useOp, resdom->restype, diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index e3d5654ec4..e76fa1829e 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.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 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 - * turns a list of ResTarget's into a list of TargetEntry's @@ -71,36 +116,13 @@ transformTargetList(ParseState *pstate, List *targetlist) { case T_Ident: { - Node *expr; - Oid type_id; - int16 type_mod; char *identname; char *resname; identname = ((Ident *) res->val)->name; 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; - tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++, - (Oid) type_id, - type_mod, - resname, - (Index) 0, - (Oid) 0, - 0); - - tent->expr = expr; + transformTargetId(pstate, (Ident*)res->val, tent, resname, FALSE); break; } case T_ParamNo: diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index 98dd31f68c..cb75d61615 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -6,7 +6,7 @@ * * 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 *makeTargetNames(ParseState *pstate, List *cols); +extern void transformTargetId(ParseState *pstate, Ident *ident, + TargetEntry *tent, char *resname, int16 resjunk); #endif /* PARSE_TARGET_H */ -- 2.40.0