]> granicus.if.org Git - postgresql/commitdiff
Rewriter and planner should use only resno, not resname, to identify
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 11 Aug 2003 23:04:50 +0000 (23:04 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 11 Aug 2003 23:04:50 +0000 (23:04 +0000)
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.

15 files changed:
src/backend/access/common/tupdesc.c
src/backend/catalog/dependency.c
src/backend/nodes/print.c
src/backend/optimizer/prep/preptlist.c
src/backend/optimizer/prep/prepunion.c
src/backend/parser/analyze.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/rewrite/rewriteHandler.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/misc/guc.c
src/include/access/tupdesc.h
src/include/nodes/primnodes.h
src/include/utils/lsyscache.h

index b76e03ed43f63181605d1f3598051d7400b4f3b9..9a40c08ca92964714c776639d0da02ba8fc4a4d5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -357,7 +357,7 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
 void
 TupleDescInitEntry(TupleDesc desc,
                                   AttrNumber attributeNumber,
-                                  char *attributeName,
+                                  const char *attributeName,
                                   Oid oidtypeid,
                                   int32 typmod,
                                   int attdim,
@@ -373,13 +373,6 @@ TupleDescInitEntry(TupleDesc desc,
        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]));
 
        /*
@@ -394,6 +387,11 @@ TupleDescInitEntry(TupleDesc desc,
         */
        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
index 870a2320c2f9d3703c59a3279982e001933d973a..8155f4fff3f0a1cdfe14e26d3f459b6314eb9983 100644 (file)
@@ -8,7 +8,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1439,8 +1439,8 @@ getObjectDescription(const ObjectAddress *object)
                        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:
index c3d702316d29837a5893d0e836739fd09fe6bf56..c3417d8efa2019111c4fc7cd21fd96dbf3be66a8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -448,7 +448,8 @@ print_tl(List *tlist, List *rtable)
        {
                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
index 5796870e767fc6c201aa9b1e9b676e4c66063f7a..f2368d0677981c13f13ccc9001ba07342840e857 100644 (file)
@@ -15,7 +15,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -150,8 +150,6 @@ expand_targetlist(List *tlist, int command_type,
 
                        if (!resdom->resjunk && resdom->resno == attrno)
                        {
-                               Assert(strcmp(resdom->resname,
-                                                         NameStr(att_tup->attname)) == 0);
                                new_tle = old_tle;
                                tlist = lnext(tlist);
                        }
index d023fd97a8fc45b43faf870945b7dbbc21d3fab1..281b15571d5ae6277b7508fd06f4f10270ee4c45 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * 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);
 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);
 
 
 /*
@@ -787,6 +787,7 @@ adjust_inherited_attrs(Node *node,
                        if (newnode->commandType == CMD_UPDATE)
                                newnode->targetList =
                                        adjust_inherited_tlist(newnode->targetList,
+                                                                                  old_relid,
                                                                                   new_relid);
                }
                return (Node *) newnode;
@@ -812,9 +813,10 @@ adjust_inherited_attrs_mutator(Node *node,
                        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",
@@ -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.
  */
 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;
@@ -989,21 +991,26 @@ adjust_inherited_tlist(List *tlist, Oid new_relid)
        {
                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);
        }
 
        /*
index ea9a1d80a8e41cdc97a6f51f095790959fa4c574..832c98a1c1c4d48acb4808daf7651b5144876120 100644 (file)
@@ -6,7 +6,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -2124,10 +2124,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        {
                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,
@@ -2501,11 +2503,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
                {
                        /*
                         * 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)
index b8c2d8c8e366b8ff0bd200ceca7e57fcd34a3822..ba1eea0475bc0bb8508d703c2feded13d409d427 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
 char *
 get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
 {
-       char       *attname;
-
        if (attnum == InvalidAttrNumber)
                return "*";
 
@@ -1535,13 +1533,7 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
         * 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
index a525e8795f0e6f87f7a586f51be3116f6f3770e5..5d5ee56eb14d4c6e21b7ad4be012a8128a474e64 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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,
        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
@@ -428,14 +428,19 @@ updateTargetListEntry(ParseState *pstate,
 
        /*
         * 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;
 }
 
 
index e8f3c185d16d8ccb8ac9e886e25f37cf79ed0240..d0ca89ee6ab407955202b8d8a2b9e5449054e408 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,7 +48,8 @@ static Query *rewriteRuleAction(Query *parsetree,
 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);
@@ -312,8 +313,7 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
                        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.
                 */
@@ -324,9 +324,8 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
 
                        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 */
                        }
                }
@@ -424,11 +423,12 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
  * 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;
@@ -456,7 +456,7 @@ process_matched_tle(TargetEntry *src_tle,
                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
@@ -470,7 +470,7 @@ process_matched_tle(TargetEntry *src_tle,
                ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("multiple assignments to same attribute \"%s\"",
-                                               resdom->resname)));
+                                               attrName)));
 
        /*
         * Looks OK to nest 'em.
index 49cc73f24e4f768731e878007ff13caa2beda405..83989292d6ae21ad8bd1268eb1caa20e45a96288 100644 (file)
@@ -3,7 +3,7 @@
  *                             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.
  *
@@ -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_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 ")
 
@@ -1140,7 +1139,7 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
        {
                char       *colName;
 
-               colName = get_attname(relId, DatumGetInt16(keys[j]));
+               colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
 
                if (j == 0)
                        appendStringInfo(buf, "%s",
@@ -1901,7 +1900,6 @@ get_basic_select_query(Query *query, deparse_context *context,
        foreach(l, query->targetList)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
-               bool            tell_as = false;
                char       *colname;
 
                if (tle->resdom->resjunk)
@@ -1924,24 +1922,30 @@ get_basic_select_query(Query *query, deparse_context *context,
                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 */
@@ -2151,7 +2155,9 @@ get_insert_query_def(Query *query, deparse_context *context)
 
                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, ") ");
 
@@ -2225,7 +2231,8 @@ get_update_query_def(Query *query, deparse_context *context)
                 */
                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);
        }
 
@@ -4351,22 +4358,3 @@ print_operator_name(StringInfo buf, List *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;
-}
index 0dfa0eb7c794e11d3396dc1a285b50331ffcc8c5..0faa097f349f65ed36a45d2e56814ab057552325 100644 (file)
@@ -7,7 +7,7 @@
  * 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.
@@ -180,11 +180,10 @@ get_op_hash_function(Oid opno)
 
 /*
  * 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)
@@ -208,6 +207,24 @@ 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
  *
@@ -1443,7 +1460,7 @@ get_typtype(Oid typid)
  * 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.
index ddaee15de57a8a200448f444611d57fa4da1108c..2ff904510ca760565ce2d4c00885f07f9a2bf181 100644 (file)
@@ -10,7 +10,7 @@
  * 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 $
  *
  *--------------------------------------------------------------------
  */
@@ -3293,7 +3293,7 @@ GetPGVariableResultDesc(const char *name)
 
                /* 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;
@@ -3333,7 +3333,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest)
 
        /* 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 */
index c955689663bf2c032ab2dd9ed8d95f8851fa0332..4ecb951a902a1cd8f323c06f1446ba35fb91f585 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -70,7 +70,7 @@ extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
 
 extern void TupleDescInitEntry(TupleDesc desc,
                                   AttrNumber attributeNumber,
-                                  char *attributeName,
+                                  const char *attributeName,
                                   Oid oidtypeid,
                                   int32 typmod,
                                   int attdim,
index 49d5f4946764ca2ed289c1dcb5521d6c6ae59ced..f6e4436d95078e059be3185636f5fca5aa7bef9a 100644 (file)
@@ -10,7 +10,7 @@
  * 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) */
index c94e78eb491640bd5b4e689e486605335bd3656a..4c9c073adea28b1af537d04fce18c7ca907d6f75 100644 (file)
@@ -6,7 +6,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -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_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);