Rewriter and planner should use only resno, not resname, to identify
authorTom Lane
Mon, 11 Aug 2003 23:04:50 +0000 (23:04 +0000)
committerTom Lane
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 : "");
        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 .
  *
  * 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);