Commit 302f1a86 authored by Tom Lane's avatar Tom Lane

Rewriter and planner should use only resno, not resname, to identify

target columns in INSERT and UPDATE targetlists.  Don't rely on resname
to be accurate in ruleutils, either.  This fixes bug reported by
Donald Fraser, in which renaming a column referenced in a rule did not
work very well.
parent 730b3a15
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.98 2003/08/04 02:39:56 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.99 2003/08/11 23:04:49 tgl Exp $
* *
* NOTES * NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be * some of the executor utility code such as "ExecTypeFromTL" should be
...@@ -357,7 +357,7 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) ...@@ -357,7 +357,7 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
void void
TupleDescInitEntry(TupleDesc desc, TupleDescInitEntry(TupleDesc desc,
AttrNumber attributeNumber, AttrNumber attributeNumber,
char *attributeName, const char *attributeName,
Oid oidtypeid, Oid oidtypeid,
int32 typmod, int32 typmod,
int attdim, int attdim,
...@@ -373,13 +373,6 @@ TupleDescInitEntry(TupleDesc desc, ...@@ -373,13 +373,6 @@ TupleDescInitEntry(TupleDesc desc,
AssertArg(PointerIsValid(desc)); AssertArg(PointerIsValid(desc));
AssertArg(attributeNumber >= 1); AssertArg(attributeNumber >= 1);
AssertArg(attributeNumber <= desc->natts); AssertArg(attributeNumber <= desc->natts);
/*
* attributeName's are sometimes NULL, from resdom's. I don't know
* why that is, though -- Jolly
*/
/* AssertArg(NameIsValid(attributeName));*/
AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1])); AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
/* /*
...@@ -394,6 +387,11 @@ TupleDescInitEntry(TupleDesc desc, ...@@ -394,6 +387,11 @@ TupleDescInitEntry(TupleDesc desc,
*/ */
att->attrelid = 0; /* dummy value */ att->attrelid = 0; /* dummy value */
/*
* Note: attributeName can be NULL, because the planner doesn't always
* fill in valid resname values in targetlists, particularly for resjunk
* attributes.
*/
if (attributeName != NULL) if (attributeName != NULL)
namestrcpy(&(att->attname), attributeName); namestrcpy(&(att->attname), attributeName);
else else
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.30 2003/08/04 02:39:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.31 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1439,8 +1439,8 @@ getObjectDescription(const ObjectAddress *object) ...@@ -1439,8 +1439,8 @@ getObjectDescription(const ObjectAddress *object)
getRelationDescription(&buffer, object->objectId); getRelationDescription(&buffer, object->objectId);
if (object->objectSubId != 0) if (object->objectSubId != 0)
appendStringInfo(&buffer, " column %s", appendStringInfo(&buffer, " column %s",
get_attname(object->objectId, get_relid_attribute_name(object->objectId,
object->objectSubId)); object->objectSubId));
break; break;
case OCLASS_PROC: case OCLASS_PROC:
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.63 2003/08/04 02:39:59 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.64 2003/08/11 23:04:49 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -448,7 +448,8 @@ print_tl(List *tlist, List *rtable) ...@@ -448,7 +448,8 @@ print_tl(List *tlist, List *rtable)
{ {
TargetEntry *tle = lfirst(tl); TargetEntry *tle = lfirst(tl);
printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname); printf("\t%d %s\t", tle->resdom->resno,
tle->resdom->resname ? tle->resdom->resname : "<null>");
if (tle->resdom->ressortgroupref != 0) if (tle->resdom->ressortgroupref != 0)
printf("(%u):\t", tle->resdom->ressortgroupref); printf("(%u):\t", tle->resdom->ressortgroupref);
else else
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.64 2003/08/04 02:40:01 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.65 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -150,8 +150,6 @@ expand_targetlist(List *tlist, int command_type, ...@@ -150,8 +150,6 @@ expand_targetlist(List *tlist, int command_type,
if (!resdom->resjunk && resdom->resno == attrno) if (!resdom->resjunk && resdom->resno == attrno)
{ {
Assert(strcmp(resdom->resname,
NameStr(att_tup->attname)) == 0);
new_tle = old_tle; new_tle = old_tle;
tlist = lnext(tlist); tlist = lnext(tlist);
} }
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.103 2003/08/04 02:40:01 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.104 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -64,7 +64,7 @@ static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK); ...@@ -64,7 +64,7 @@ static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
static Node *adjust_inherited_attrs_mutator(Node *node, static Node *adjust_inherited_attrs_mutator(Node *node,
adjust_inherited_attrs_context *context); adjust_inherited_attrs_context *context);
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid); static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
static List *adjust_inherited_tlist(List *tlist, Oid new_relid); static List *adjust_inherited_tlist(List *tlist, Oid old_relid, Oid new_relid);
/* /*
...@@ -787,6 +787,7 @@ adjust_inherited_attrs(Node *node, ...@@ -787,6 +787,7 @@ adjust_inherited_attrs(Node *node,
if (newnode->commandType == CMD_UPDATE) if (newnode->commandType == CMD_UPDATE)
newnode->targetList = newnode->targetList =
adjust_inherited_tlist(newnode->targetList, adjust_inherited_tlist(newnode->targetList,
old_relid,
new_relid); new_relid);
} }
return (Node *) newnode; return (Node *) newnode;
...@@ -812,9 +813,10 @@ adjust_inherited_attrs_mutator(Node *node, ...@@ -812,9 +813,10 @@ adjust_inherited_attrs_mutator(Node *node,
var->varnoold = context->new_rt_index; var->varnoold = context->new_rt_index;
if (var->varattno > 0) if (var->varattno > 0)
{ {
char *attname = get_attname(context->old_relid, char *attname;
var->varattno);
attname = get_relid_attribute_name(context->old_relid,
var->varattno);
var->varattno = get_attnum(context->new_relid, attname); var->varattno = get_attnum(context->new_relid, attname);
if (var->varattno == InvalidAttrNumber) if (var->varattno == InvalidAttrNumber)
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist", elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist",
...@@ -976,7 +978,7 @@ adjust_relid_set(Relids relids, Index oldrelid, Index newrelid) ...@@ -976,7 +978,7 @@ adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
* Note that this is not needed for INSERT because INSERT isn't inheritable. * Note that this is not needed for INSERT because INSERT isn't inheritable.
*/ */
static List * static List *
adjust_inherited_tlist(List *tlist, Oid new_relid) adjust_inherited_tlist(List *tlist, Oid old_relid, Oid new_relid)
{ {
bool changed_it = false; bool changed_it = false;
List *tl; List *tl;
...@@ -989,21 +991,26 @@ adjust_inherited_tlist(List *tlist, Oid new_relid) ...@@ -989,21 +991,26 @@ adjust_inherited_tlist(List *tlist, Oid new_relid)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(tl); TargetEntry *tle = (TargetEntry *) lfirst(tl);
Resdom *resdom = tle->resdom; Resdom *resdom = tle->resdom;
char *attname;
if (resdom->resjunk) if (resdom->resjunk)
continue; /* ignore junk items */ continue; /* ignore junk items */
attrno = get_attnum(new_relid, resdom->resname); attname = get_relid_attribute_name(old_relid, resdom->resno);
attrno = get_attnum(new_relid, attname);
if (attrno == InvalidAttrNumber) if (attrno == InvalidAttrNumber)
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist", elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist",
resdom->resname, get_rel_name(new_relid)); attname, get_rel_name(new_relid));
if (resdom->resno != attrno) if (resdom->resno != attrno)
{ {
resdom = (Resdom *) copyObject((Node *) resdom); resdom = (Resdom *) copyObject((Node *) resdom);
resdom->resno = attrno; resdom->resno = attrno;
resdom->resname = attname;
tle->resdom = resdom; tle->resdom = resdom;
changed_it = true; changed_it = true;
} }
else
pfree(attname);
} }
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.286 2003/08/08 21:41:55 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.287 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2124,10 +2124,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -2124,10 +2124,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
{ {
Oid colType = lfirsto(dtlist); Oid colType = lfirsto(dtlist);
Resdom *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom; Resdom *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
char *colName = pstrdup(leftResdom->resname); char *colName;
Resdom *resdom; Resdom *resdom;
Expr *expr; Expr *expr;
Assert(!leftResdom->resjunk);
colName = pstrdup(leftResdom->resname);
resdom = makeResdom((AttrNumber) pstate->p_next_resno++, resdom = makeResdom((AttrNumber) pstate->p_next_resno++,
colType, colType,
-1, -1,
...@@ -2501,11 +2503,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) ...@@ -2501,11 +2503,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
{ {
/* /*
* Resjunk nodes need no additional processing, but be sure * Resjunk nodes need no additional processing, but be sure
* they have names and resnos that do not match any target * they have resnos that do not match any target columns;
* columns; else rewriter or planner might get confused. * else rewriter or planner might get confused. They don't
* need a resname either.
*/ */
resnode->resname = "?resjunk?";
resnode->resno = (AttrNumber) pstate->p_next_resno++; resnode->resno = (AttrNumber) pstate->p_next_resno++;
resnode->resname = NULL;
continue; continue;
} }
if (origTargetList == NIL) if (origTargetList == NIL)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.88 2003/08/11 20:46:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.89 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1516,8 +1516,6 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte) ...@@ -1516,8 +1516,6 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte)
char * char *
get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum) get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
{ {
char *attname;
if (attnum == InvalidAttrNumber) if (attnum == InvalidAttrNumber)
return "*"; return "*";
...@@ -1535,13 +1533,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum) ...@@ -1535,13 +1533,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
* built (which can easily happen for rules). * built (which can easily happen for rules).
*/ */
if (rte->rtekind == RTE_RELATION) if (rte->rtekind == RTE_RELATION)
{ return get_relid_attribute_name(rte->relid, attnum);
attname = get_attname(rte->relid, attnum);
if (attname == NULL)
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, rte->relid);
return attname;
}
/* /*
* Otherwise use the column name from eref. There should always be * Otherwise use the column name from eref. There should always be
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.111 2003/08/11 20:46:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.112 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -71,7 +71,7 @@ transformTargetEntry(ParseState *pstate, ...@@ -71,7 +71,7 @@ transformTargetEntry(ParseState *pstate,
type_id = exprType(expr); type_id = exprType(expr);
type_mod = exprTypmod(expr); type_mod = exprTypmod(expr);
if (colname == NULL) if (colname == NULL && !resjunk)
{ {
/* /*
* Generate a suitable column name for a column without any * Generate a suitable column name for a column without any
...@@ -428,14 +428,19 @@ updateTargetListEntry(ParseState *pstate, ...@@ -428,14 +428,19 @@ updateTargetListEntry(ParseState *pstate,
/* /*
* The result of the target expression should now match the * The result of the target expression should now match the
* destination column's type. Also, reset the resname and resno to * destination column's type.
* identify the destination column --- rewriter and planner depend on
* that!
*/ */
resnode->restype = attrtype; resnode->restype = attrtype;
resnode->restypmod = attrtypmod; resnode->restypmod = attrtypmod;
resnode->resname = colname; /*
* Set the resno to identify the target column --- the rewriter and
* planner depend on this. We also set the resname to identify the
* target column, but this is only for debugging purposes; it should
* not be relied on. (In particular, it might be out of date in a
* stored rule.)
*/
resnode->resno = (AttrNumber) attrno; resnode->resno = (AttrNumber) attrno;
resnode->resname = colname;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.128 2003/08/08 21:41:56 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.129 2003/08/11 23:04:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,7 +48,8 @@ static Query *rewriteRuleAction(Query *parsetree, ...@@ -48,7 +48,8 @@ static Query *rewriteRuleAction(Query *parsetree,
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index); static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static void rewriteTargetList(Query *parsetree, Relation target_relation); static void rewriteTargetList(Query *parsetree, Relation target_relation);
static TargetEntry *process_matched_tle(TargetEntry *src_tle, static TargetEntry *process_matched_tle(TargetEntry *src_tle,
TargetEntry *prior_tle); TargetEntry *prior_tle,
const char *attrName);
static void markQueryForUpdate(Query *qry, bool skipOldNew); static void markQueryForUpdate(Query *qry, bool skipOldNew);
static List *matchLocks(CmdType event, RuleLock *rulelocks, static List *matchLocks(CmdType event, RuleLock *rulelocks,
int varno, Query *parsetree); int varno, Query *parsetree);
...@@ -312,8 +313,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation) ...@@ -312,8 +313,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
continue; continue;
/* /*
* Look for targetlist entries matching this attr. We match by * Look for targetlist entries matching this attr.
* resno, but the resname should match too.
* *
* Junk attributes are not candidates to be matched. * Junk attributes are not candidates to be matched.
*/ */
...@@ -324,9 +324,8 @@ rewriteTargetList(Query *parsetree, Relation target_relation) ...@@ -324,9 +324,8 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
if (!resdom->resjunk && resdom->resno == attrno) if (!resdom->resjunk && resdom->resno == attrno)
{ {
Assert(strcmp(resdom->resname, new_tle = process_matched_tle(old_tle, new_tle,
NameStr(att_tup->attname)) == 0); NameStr(att_tup->attname));
new_tle = process_matched_tle(old_tle, new_tle);
/* keep scanning to detect multiple assignments to attr */ /* keep scanning to detect multiple assignments to attr */
} }
} }
...@@ -424,11 +423,12 @@ rewriteTargetList(Query *parsetree, Relation target_relation) ...@@ -424,11 +423,12 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
* Convert a matched TLE from the original tlist into a correct new TLE. * Convert a matched TLE from the original tlist into a correct new TLE.
* *
* This routine detects and handles multiple assignments to the same target * This routine detects and handles multiple assignments to the same target
* attribute. * attribute. (The attribute name is needed only for error messages.)
*/ */
static TargetEntry * static TargetEntry *
process_matched_tle(TargetEntry *src_tle, process_matched_tle(TargetEntry *src_tle,
TargetEntry *prior_tle) TargetEntry *prior_tle,
const char *attrName)
{ {
Resdom *resdom = src_tle->resdom; Resdom *resdom = src_tle->resdom;
Node *priorbottom; Node *priorbottom;
...@@ -456,7 +456,7 @@ process_matched_tle(TargetEntry *src_tle, ...@@ -456,7 +456,7 @@ process_matched_tle(TargetEntry *src_tle,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple assignments to same attribute \"%s\"", errmsg("multiple assignments to same attribute \"%s\"",
resdom->resname))); attrName)));
/* /*
* Prior TLE could be a nest of ArrayRefs if we do this more than * Prior TLE could be a nest of ArrayRefs if we do this more than
...@@ -470,7 +470,7 @@ process_matched_tle(TargetEntry *src_tle, ...@@ -470,7 +470,7 @@ process_matched_tle(TargetEntry *src_tle,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple assignments to same attribute \"%s\"", errmsg("multiple assignments to same attribute \"%s\"",
resdom->resname))); attrName)));
/* /*
* Looks OK to nest 'em. * Looks OK to nest 'em.
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.150 2003/08/08 21:42:09 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.151 2003/08/11 23:04:49 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -207,7 +207,6 @@ static char *generate_relation_name(Oid relid); ...@@ -207,7 +207,6 @@ static char *generate_relation_name(Oid relid);
static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes); static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
static void print_operator_name(StringInfo buf, List *opname); static void print_operator_name(StringInfo buf, List *opname);
static char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ") #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
...@@ -1140,7 +1139,7 @@ decompile_column_index_array(Datum column_index_array, Oid relId, ...@@ -1140,7 +1139,7 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
{ {
char *colName; char *colName;
colName = get_attname(relId, DatumGetInt16(keys[j])); colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
if (j == 0) if (j == 0)
appendStringInfo(buf, "%s", appendStringInfo(buf, "%s",
...@@ -1901,7 +1900,6 @@ get_basic_select_query(Query *query, deparse_context *context, ...@@ -1901,7 +1900,6 @@ get_basic_select_query(Query *query, deparse_context *context,
foreach(l, query->targetList) foreach(l, query->targetList)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(l); TargetEntry *tle = (TargetEntry *) lfirst(l);
bool tell_as = false;
char *colname; char *colname;
if (tle->resdom->resjunk) if (tle->resdom->resjunk)
...@@ -1924,24 +1922,30 @@ get_basic_select_query(Query *query, deparse_context *context, ...@@ -1924,24 +1922,30 @@ get_basic_select_query(Query *query, deparse_context *context,
else else
colname = tle->resdom->resname; colname = tle->resdom->resname;
/* Check if we must say AS ... */ if (colname) /* resname could be NULL */
if (!IsA(tle->expr, Var))
tell_as = (strcmp(colname, "?column?") != 0);
else
{ {
Var *var = (Var *) (tle->expr); /* Check if we must say AS ... */
char *schemaname; bool tell_as;
char *refname;
char *attname;
get_names_for_var(var, context, &schemaname, &refname, &attname); if (!IsA(tle->expr, Var))
tell_as = (attname == NULL || tell_as = (strcmp(colname, "?column?") != 0);
strcmp(attname, colname) != 0); else
} {
Var *var = (Var *) (tle->expr);
char *schemaname;
char *refname;
char *attname;
/* and do if so */ get_names_for_var(var, context,
if (tell_as) &schemaname, &refname, &attname);
appendStringInfo(buf, " AS %s", quote_identifier(colname)); tell_as = (attname == NULL ||
strcmp(attname, colname) != 0);
}
/* and do if so */
if (tell_as)
appendStringInfo(buf, " AS %s", quote_identifier(colname));
}
} }
/* Add the FROM clause if needed */ /* Add the FROM clause if needed */
...@@ -2151,7 +2155,9 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -2151,7 +2155,9 @@ get_insert_query_def(Query *query, deparse_context *context)
appendStringInfo(buf, sep); appendStringInfo(buf, sep);
sep = ", "; sep = ", ";
appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname)); appendStringInfo(buf, "%s",
quote_identifier(get_relid_attribute_name(rte->relid,
tle->resdom->resno)));
} }
appendStringInfo(buf, ") "); appendStringInfo(buf, ") ");
...@@ -2225,7 +2231,8 @@ get_update_query_def(Query *query, deparse_context *context) ...@@ -2225,7 +2231,8 @@ get_update_query_def(Query *query, deparse_context *context)
*/ */
if (!tleIsArrayAssign(tle)) if (!tleIsArrayAssign(tle))
appendStringInfo(buf, "%s = ", appendStringInfo(buf, "%s = ",
quote_identifier(tle->resdom->resname)); quote_identifier(get_relid_attribute_name(rte->relid,
tle->resdom->resno)));
get_rule_expr((Node *) tle->expr, context, false); get_rule_expr((Node *) tle->expr, context, false);
} }
...@@ -4351,22 +4358,3 @@ print_operator_name(StringInfo buf, List *opname) ...@@ -4351,22 +4358,3 @@ print_operator_name(StringInfo buf, List *opname)
appendStringInfo(buf, "%s)", strVal(lfirst(opname))); appendStringInfo(buf, "%s)", strVal(lfirst(opname)));
} }
} }
/*
* get_relid_attribute_name
* Get an attribute name by its relations Oid and its attnum
*
* Same as underlying syscache routine get_attname(), except that error
* is handled by elog() instead of returning NULL.
*/
static char *
get_relid_attribute_name(Oid relid, AttrNumber attnum)
{
char *attname;
attname = get_attname(relid, attnum);
if (attname == NULL)
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
return attname;
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.105 2003/08/04 02:40:06 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.106 2003/08/11 23:04:49 tgl Exp $
* *
* NOTES * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -180,11 +180,10 @@ get_op_hash_function(Oid opno) ...@@ -180,11 +180,10 @@ get_op_hash_function(Oid opno)
/* /*
* get_attname * get_attname
*
* Given the relation id and the attribute number, * Given the relation id and the attribute number,
* return the "attname" field from the attribute relation. * return the "attname" field from the attribute relation.
* *
* Note: returns a palloc'd copy of the string, or NULL if no such operator. * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
*/ */
char * char *
get_attname(Oid relid, AttrNumber attnum) get_attname(Oid relid, AttrNumber attnum)
...@@ -208,6 +207,24 @@ get_attname(Oid relid, AttrNumber attnum) ...@@ -208,6 +207,24 @@ get_attname(Oid relid, AttrNumber attnum)
return NULL; return NULL;
} }
/*
* get_relid_attribute_name
*
* Same as above routine get_attname(), except that error
* is handled by elog() instead of returning NULL.
*/
char *
get_relid_attribute_name(Oid relid, AttrNumber attnum)
{
char *attname;
attname = get_attname(relid, attnum);
if (attname == NULL)
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
return attname;
}
/* /*
* get_attnum * get_attnum
* *
...@@ -1443,7 +1460,7 @@ get_typtype(Oid typid) ...@@ -1443,7 +1460,7 @@ get_typtype(Oid typid)
* get_typname * get_typname
* Returns the name of a given type. * Returns the name of a given type.
* *
* Returns a palloc'd copy of the string, or NULL if no such relation. * Returns a palloc'd copy of the string, or NULL if no such type.
* *
* NOTE: since type name is not unique, be wary of code that uses this * NOTE: since type name is not unique, be wary of code that uses this
* for anything except preparing error messages. * for anything except preparing error messages.
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.148 2003/08/04 23:59:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.149 2003/08/11 23:04:49 tgl Exp $
* *
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */
...@@ -3293,7 +3293,7 @@ GetPGVariableResultDesc(const char *name) ...@@ -3293,7 +3293,7 @@ GetPGVariableResultDesc(const char *name)
/* need a tuple descriptor representing a single TEXT column */ /* need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false); tupdesc = CreateTemplateTupleDesc(1, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) varname, TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
TEXTOID, -1, 0, false); TEXTOID, -1, 0, false);
} }
return tupdesc; return tupdesc;
...@@ -3333,7 +3333,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest) ...@@ -3333,7 +3333,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest)
/* need a tuple descriptor representing a single TEXT column */ /* need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false); tupdesc = CreateTemplateTupleDesc(1, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) varname, TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
TEXTOID, -1, 0, false); TEXTOID, -1, 0, false);
/* prepare for projection of tuples */ /* prepare for projection of tuples */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: tupdesc.h,v 1.40 2003/08/04 02:40:10 momjian Exp $ * $Id: tupdesc.h,v 1.41 2003/08/11 23:04:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -70,7 +70,7 @@ extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); ...@@ -70,7 +70,7 @@ extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
extern void TupleDescInitEntry(TupleDesc desc, extern void TupleDescInitEntry(TupleDesc desc,
AttrNumber attributeNumber, AttrNumber attributeNumber,
char *attributeName, const char *attributeName,
Oid oidtypeid, Oid oidtypeid,
int32 typmod, int32 typmod,
int attdim, int attdim,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: primnodes.h,v 1.90 2003/08/08 21:42:48 momjian Exp $ * $Id: primnodes.h,v 1.91 2003/08/11 23:04:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,13 +31,29 @@ ...@@ -31,13 +31,29 @@
* *
* Notes: * Notes:
* *
* resno will normally be equal to the item's position in a targetlist, * In a SELECT's targetlist, resno should always be equal to the item's
* but the code generally tries to avoid relying on that (eg, we avoid * ordinal position (counting from 1). However, in an INSERT or UPDATE
* using "nth()" rather than a search to find an item by resno). * targetlist, resno represents the attribute number of the destination
* * column for the item; so there may be missing or out-of-order resnos.
* resname will be null if no name can easily be assigned to the column. * In an UPDATE, it is even legal to have duplicated resnos; consider
* But it should never be null for user-visible columns (i.e., non-junk * UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ...
* columns in a toplevel targetlist). * The two meanings come together in the executor, because the planner
* transforms INSERT/UPDATE tlists into a normalized form with exactly
* one entry for each column of the destination table. Before that's
* happened, however, it is risky to assume that resno == position.
* Generally get_tle_by_resno() should be used rather than nth() to fetch
* tlist entries by resno.
*
* resname is required to represent the correct column name in non-resjunk
* entries of top-level SELECT targetlists, since it will be used as the
* column title sent to the frontend. In most other contexts it is only
* a debugging aid, and may be wrong or even NULL. (In particular, it may
* be wrong in a tlist from a stored rule, if the referenced column has been
* renamed by ALTER TABLE since the rule was made. Also, the planner tends
* to store NULL rather than look up a valid name for tlist entries in
* non-toplevel plan nodes.) In resjunk entries, resname should be either
* a specific system-generated name (such as "ctid") or NULL; anything else
* risks confusing ExecGetJunkAttribute!
* *
* ressortgroupref is used in the representation of ORDER BY and * ressortgroupref is used in the representation of ORDER BY and
* GROUP BY items. Targetlist entries with ressortgroupref=0 are not * GROUP BY items. Targetlist entries with ressortgroupref=0 are not
...@@ -53,13 +69,16 @@ ...@@ -53,13 +69,16 @@
* a simple reference, these fields are zeroes. * a simple reference, these fields are zeroes.
* *
* If resjunk is true then the column is a working column (such as a sort key) * If resjunk is true then the column is a working column (such as a sort key)
* that should be removed from the final output of the query. * that should be removed from the final output of the query. Resjunk columns
* must have resnos that cannot duplicate any regular column's resno. Also
* note that there are places that assume resjunk columns come after non-junk
* columns.
*-------------------- *--------------------
*/ */
typedef struct Resdom typedef struct Resdom
{ {
NodeTag type; NodeTag type;
AttrNumber resno; /* attribute number (1..N) */ AttrNumber resno; /* attribute number (see notes above) */
Oid restype; /* type of the value */ Oid restype; /* type of the value */
int32 restypmod; /* type-specific modifier of the value */ int32 restypmod; /* type-specific modifier of the value */
char *resname; /* name of the column (could be NULL) */ char *resname; /* name of the column (could be NULL) */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: lsyscache.h,v 1.79 2003/08/08 21:42:55 momjian Exp $ * $Id: lsyscache.h,v 1.80 2003/08/11 23:04:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,6 +29,7 @@ extern bool op_requires_recheck(Oid opno, Oid opclass); ...@@ -29,6 +29,7 @@ extern bool op_requires_recheck(Oid opno, Oid opclass);
extern Oid get_opclass_member(Oid opclass, int16 strategy); extern Oid get_opclass_member(Oid opclass, int16 strategy);
extern Oid get_op_hash_function(Oid opno); extern Oid get_op_hash_function(Oid opno);
extern char *get_attname(Oid relid, AttrNumber attnum); extern char *get_attname(Oid relid, AttrNumber attnum);
extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
extern AttrNumber get_attnum(Oid relid, const char *attname); extern AttrNumber get_attnum(Oid relid, const char *attname);
extern Oid get_atttype(Oid relid, AttrNumber attnum); extern Oid get_atttype(Oid relid, AttrNumber attnum);
extern int32 get_atttypmod(Oid relid, AttrNumber attnum); extern int32 get_atttypmod(Oid relid, AttrNumber attnum);
......
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