*
*
* 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
* some of the executor utility code such as "ExecTypeFromTL" should be
void
TupleDescInitEntry(TupleDesc desc,
AttrNumber attributeNumber,
- char *attributeName,
+ const char *attributeName,
Oid oidtypeid,
int32 typmod,
int attdim,
AssertArg(PointerIsValid(desc));
AssertArg(attributeNumber >= 1);
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]));
/*
*/
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)
namestrcpy(&(att->attname), attributeName);
else
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
getRelationDescription(&buffer, object->objectId);
if (object->objectSubId != 0)
appendStringInfo(&buffer, " column %s",
- get_attname(object->objectId,
- object->objectSubId));
+ get_relid_attribute_name(object->objectId,
+ object->objectSubId));
break;
case OCLASS_PROC:
*
*
* 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
* AUTHOR DATE MAJOR EVENT
{
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)
printf("(%u):\t", tle->resdom->ressortgroupref);
else
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
if (!resdom->resjunk && resdom->resno == attrno)
{
- Assert(strcmp(resdom->resname,
- NameStr(att_tup->attname)) == 0);
new_tle = old_tle;
tlist = lnext(tlist);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
static Node *adjust_inherited_attrs_mutator(Node *node,
adjust_inherited_attrs_context *context);
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);
/*
if (newnode->commandType == CMD_UPDATE)
newnode->targetList =
adjust_inherited_tlist(newnode->targetList,
+ old_relid,
new_relid);
}
return (Node *) newnode;
var->varnoold = context->new_rt_index;
if (var->varattno > 0)
{
- char *attname = get_attname(context->old_relid,
- var->varattno);
+ char *attname;
+ attname = get_relid_attribute_name(context->old_relid,
+ var->varattno);
var->varattno = get_attnum(context->new_relid, attname);
if (var->varattno == InvalidAttrNumber)
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not exist",
* Note that this is not needed for INSERT because INSERT isn't inheritable.
*/
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;
List *tl;
{
TargetEntry *tle = (TargetEntry *) lfirst(tl);
Resdom *resdom = tle->resdom;
+ char *attname;
if (resdom->resjunk)
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)
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)
{
resdom = (Resdom *) copyObject((Node *) resdom);
resdom->resno = attrno;
+ resdom->resname = attname;
tle->resdom = resdom;
changed_it = true;
}
+ else
+ pfree(attname);
}
/*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
{
Oid colType = lfirsto(dtlist);
Resdom *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
- char *colName = pstrdup(leftResdom->resname);
+ char *colName;
Resdom *resdom;
Expr *expr;
+ Assert(!leftResdom->resjunk);
+ colName = pstrdup(leftResdom->resname);
resdom = makeResdom((AttrNumber) pstate->p_next_resno++,
colType,
-1,
{
/*
* Resjunk nodes need no additional processing, but be sure
- * they have names and resnos that do not match any target
- * columns; else rewriter or planner might get confused.
+ * they have resnos that do not match any target columns;
+ * 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->resname = NULL;
continue;
}
if (origTargetList == NIL)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
char *
get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
{
- char *attname;
-
if (attnum == InvalidAttrNumber)
return "*";
* built (which can easily happen for rules).
*/
if (rte->rtekind == RTE_RELATION)
- {
- 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;
- }
+ return get_relid_attribute_name(rte->relid, attnum);
/*
* Otherwise use the column name from eref. There should always be
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
type_id = exprType(expr);
type_mod = exprTypmod(expr);
- if (colname == NULL)
+ if (colname == NULL && !resjunk)
{
/*
* Generate a suitable column name for a column without any
/*
* The result of the target expression should now match the
- * destination column's type. Also, reset the resname and resno to
- * identify the destination column --- rewriter and planner depend on
- * that!
+ * destination column's type.
*/
resnode->restype = attrtype;
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->resname = colname;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static void rewriteTargetList(Query *parsetree, Relation target_relation);
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 List *matchLocks(CmdType event, RuleLock *rulelocks,
int varno, Query *parsetree);
continue;
/*
- * Look for targetlist entries matching this attr. We match by
- * resno, but the resname should match too.
+ * Look for targetlist entries matching this attr.
*
* Junk attributes are not candidates to be matched.
*/
if (!resdom->resjunk && resdom->resno == attrno)
{
- Assert(strcmp(resdom->resname,
- NameStr(att_tup->attname)) == 0);
- new_tle = process_matched_tle(old_tle, new_tle);
+ new_tle = process_matched_tle(old_tle, new_tle,
+ NameStr(att_tup->attname));
/* keep scanning to detect multiple assignments to attr */
}
}
* Convert a matched TLE from the original tlist into a correct new TLE.
*
* This routine detects and handles multiple assignments to the same target
- * attribute.
+ * attribute. (The attribute name is needed only for error messages.)
*/
static TargetEntry *
process_matched_tle(TargetEntry *src_tle,
- TargetEntry *prior_tle)
+ TargetEntry *prior_tle,
+ const char *attrName)
{
Resdom *resdom = src_tle->resdom;
Node *priorbottom;
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple assignments to same attribute \"%s\"",
- resdom->resname)));
+ attrName)));
/*
* Prior TLE could be a nest of ArrayRefs if we do this more than
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple assignments to same attribute \"%s\"",
- resdom->resname)));
+ attrName)));
/*
* Looks OK to nest 'em.
* back to source text
*
* 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.
*
static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
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 ")
{
char *colName;
- colName = get_attname(relId, DatumGetInt16(keys[j]));
+ colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
if (j == 0)
appendStringInfo(buf, "%s",
foreach(l, query->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
- bool tell_as = false;
char *colname;
if (tle->resdom->resjunk)
else
colname = tle->resdom->resname;
- /* Check if we must say AS ... */
- if (!IsA(tle->expr, Var))
- tell_as = (strcmp(colname, "?column?") != 0);
- else
+ if (colname) /* resname could be NULL */
{
- Var *var = (Var *) (tle->expr);
- char *schemaname;
- char *refname;
- char *attname;
+ /* Check if we must say AS ... */
+ bool tell_as;
- get_names_for_var(var, context, &schemaname, &refname, &attname);
- tell_as = (attname == NULL ||
- strcmp(attname, colname) != 0);
- }
+ if (!IsA(tle->expr, Var))
+ tell_as = (strcmp(colname, "?column?") != 0);
+ else
+ {
+ Var *var = (Var *) (tle->expr);
+ char *schemaname;
+ char *refname;
+ char *attname;
- /* and do if so */
- if (tell_as)
- appendStringInfo(buf, " AS %s", quote_identifier(colname));
+ get_names_for_var(var, context,
+ &schemaname, &refname, &attname);
+ 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 */
appendStringInfo(buf, 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, ") ");
*/
if (!tleIsArrayAssign(tle))
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);
}
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;
-}
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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
* Eventually, the index information should go through here, too.
/*
* get_attname
- *
* Given the relation id and the attribute number,
* 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 *
get_attname(Oid relid, AttrNumber attnum)
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_typname
* 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
* for anything except preparing error messages.
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* 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 $
*
*--------------------------------------------------------------------
*/
/* need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) varname,
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
TEXTOID, -1, 0, false);
}
return tupdesc;
/* need a tuple descriptor representing a single TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) varname,
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
TEXTOID, -1, 0, false);
/* prepare for projection of tuples */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
extern void TupleDescInitEntry(TupleDesc desc,
AttrNumber attributeNumber,
- char *attributeName,
+ const char *attributeName,
Oid oidtypeid,
int32 typmod,
int attdim,
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
*
* Notes:
*
- * resno will normally be equal to the item's position in a targetlist,
- * but the code generally tries to avoid relying on that (eg, we avoid
- * using "nth()" rather than a search to find an item by resno).
- *
- * resname will be null if no name can easily be assigned to the column.
- * But it should never be null for user-visible columns (i.e., non-junk
- * columns in a toplevel targetlist).
+ * In a SELECT's targetlist, resno should always be equal to the item's
+ * ordinal position (counting from 1). However, in an INSERT or UPDATE
+ * targetlist, resno represents the attribute number of the destination
+ * column for the item; so there may be missing or out-of-order resnos.
+ * In an UPDATE, it is even legal to have duplicated resnos; consider
+ * UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ...
+ * 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
* GROUP BY items. Targetlist entries with ressortgroupref=0 are not
* a simple reference, these fields are zeroes.
*
* 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
{
NodeTag type;
- AttrNumber resno; /* attribute number (1..N) */
+ AttrNumber resno; /* attribute number (see notes above) */
Oid restype; /* type of the value */
int32 restypmod; /* type-specific modifier of the value */
char *resname; /* name of the column (could be NULL) */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
extern Oid get_opclass_member(Oid opclass, int16 strategy);
extern Oid get_op_hash_function(Oid opno);
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 Oid get_atttype(Oid relid, AttrNumber attnum);
extern int32 get_atttypmod(Oid relid, AttrNumber attnum);