Eliminate local inefficiencies in updateTargetListEntry, make_var, and
authorTom Lane
Mon, 1 Nov 1999 05:06:21 +0000 (05:06 +0000)
committerTom Lane
Mon, 1 Nov 1999 05:06:21 +0000 (05:06 +0000)
make_const --- don't repeat cache searches that aren't needed.

src/backend/parser/analyze.c
src/backend/parser/parse_node.c
src/backend/parser/parse_target.c
src/include/parser/parse_target.h

index 08c209b2a5dd0a0876ebfa80c78d7ee1a988ea8c..2bd3a00b73e9656a52bc33124aaa4c056a60b670 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: analyze.c,v 1.121 1999/10/07 04:23:11 tgl Exp $
+ * $Id: analyze.c,v 1.122 1999/11/01 05:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -253,6 +253,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
    Query      *qry = makeNode(Query);
    Node       *fromQual;
    List       *icolumns;
+   List       *attrnos;
+   List       *attnos;
+   int         numuseratts;
    List       *tl;
    TupleDesc   rd_att;
 
@@ -333,9 +336,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        pstate->p_last_resno = pstate->p_target_relation->rd_rel->relnatts + 1;
 
    /* Validate stmt->cols list, or build default list if no list given */
-   icolumns = makeTargetNames(pstate, stmt->cols);
+   icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
 
    /* Prepare non-junk columns for assignment to target table */
+   numuseratts = 0;
+   attnos = attrnos;
    foreach(tl, qry->targetList)
    {
        TargetEntry *tle = (TargetEntry *) lfirst(tl);
@@ -352,16 +357,30 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
            resnode->resno = (AttrNumber) pstate->p_last_resno++;
            continue;
        }
-       if (icolumns == NIL)
+       if (icolumns == NIL || attnos == NIL)
            elog(ERROR, "INSERT has more expressions than target columns");
        id = (Ident *) lfirst(icolumns);
-       updateTargetListEntry(pstate, tle, id->name, id->indirection);
+       updateTargetListEntry(pstate, tle, id->name, lfirsti(attnos),
+                             id->indirection);
+       numuseratts++;
        icolumns = lnext(icolumns);
+       attnos = lnext(attnos);
    }
 
+   /*
+    * It is possible that the targetlist has fewer entries than were in
+    * the columns list.  We do not consider this an error (perhaps we
+    * should, if the columns list was explictly given?).  We must truncate
+    * the attrnos list to only include the attrs actually provided,
+    * else we will fail to apply defaults for them below.
+    */
+   if (icolumns != NIL)
+       attrnos = ltruncate(numuseratts, attrnos);
+
    /*
     * Add targetlist items to assign DEFAULT values to any columns that
     * have defaults and were not assigned to by the user.
+    *
     * XXX wouldn't it make more sense to do this further downstream,
     * after the rule rewriter?
     */
@@ -372,29 +391,20 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        AttrDefault *defval = rd_att->constr->defval;
        int         ndef = rd_att->constr->num_defval;
 
-       while (ndef-- > 0)
+       while (--ndef >= 0)
        {
-           Form_pg_attribute thisatt = att[defval[ndef].adnum - 1];
-           TargetEntry *te;
+           AttrNumber      attrno = defval[ndef].adnum;
+           Form_pg_attribute thisatt = att[attrno - 1];
+           TargetEntry    *te;
 
-           foreach(tl, qry->targetList)
-           {
-               TargetEntry *tle = (TargetEntry *) lfirst(tl);
-               Resdom     *resnode = tle->resdom;
-
-               if (resnode->resjunk)
-                   continue;   /* ignore resjunk nodes */
-               if (namestrcmp(&(thisatt->attname), resnode->resname) == 0)
-                   break;
-           }
-           if (tl != NIL)      /* found TLE for this attr */
-               continue;
+           if (intMember((int) attrno, attrnos))
+               continue;       /* there was a user-specified value */
            /*
             * No user-supplied value, so add a targetentry with DEFAULT expr
             * and correct data for the target column.
             */
            te = makeTargetEntry(
-               makeResdom(defval[ndef].adnum,
+               makeResdom(attrno,
                           thisatt->atttypid,
                           thisatt->atttypmod,
                           pstrdup(nameout(&(thisatt->attname))),
@@ -405,7 +415,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
             * Make sure the value is coerced to the target column type
             * (might not be right type if it's not a constant!)
             */
-           updateTargetListEntry(pstate, te, te->resdom->resname, NIL);
+           updateTargetListEntry(pstate, te, te->resdom->resname, attrno,
+                                 NIL);
        }
    }
 
@@ -1128,8 +1139,10 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
        if (origTargetList == NIL)
            elog(ERROR, "UPDATE target count mismatch --- internal error");
        origTarget = (ResTarget *) lfirst(origTargetList);
-       updateTargetListEntry(pstate, tle,
-                             origTarget->name, origTarget->indirection);
+       updateTargetListEntry(pstate, tle, origTarget->name,
+                             attnameAttNum(pstate->p_target_relation,
+                                           origTarget->name),
+                             origTarget->indirection);
        origTargetList = lnext(origTargetList);
    }
    if (origTargetList != NIL)
index 35fa858dc0888931da341c97d3d33af95bac520e..d4593a1357b3c1d30b939d4d393e902e8656ccb1 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.31 1999/08/23 23:48:39 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.32 1999/11/01 05:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -176,11 +176,16 @@ make_op(char *opname, Node *ltree, Node *rtree)
 }  /* make_op() */
 
 
+/*
+ * make_var
+ *     Build a Var node for an attribute identified by name
+ */
 Var *
 make_var(ParseState *pstate, Oid relid, char *refname,
         char *attrname)
 {
-   Var        *varnode;
+   HeapTuple   tp;
+   Form_pg_attribute att_tup;
    int         vnum,
                attid;
    Oid         vartypeid;
@@ -189,16 +194,19 @@ make_var(ParseState *pstate, Oid relid, char *refname,
 
    vnum = refnameRangeTablePosn(pstate, refname, &sublevels_up);
 
-   attid = get_attnum(relid, attrname);
-   if (attid == InvalidAttrNumber)
+   tp = SearchSysCacheTuple(ATTNAME,
+                            ObjectIdGetDatum(relid),
+                            PointerGetDatum(attrname),
+                            0, 0);
+   if (!HeapTupleIsValid(tp))
        elog(ERROR, "Relation %s does not have attribute %s",
             refname, attrname);
-   vartypeid = get_atttype(relid, attid);
-   type_mod = get_atttypmod(relid, attid);
-
-   varnode = makeVar(vnum, attid, vartypeid, type_mod, sublevels_up);
+   att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+   attid = att_tup->attnum;
+   vartypeid = att_tup->atttypid;
+   type_mod = att_tup->atttypmod;
 
-   return varnode;
+   return makeVar(vnum, attid, vartypeid, type_mod, sublevels_up);
 }
 
 /*
@@ -380,67 +388,73 @@ transformArraySubscripts(ParseState *pstate,
 }
 
 /*
- * make_const -
+ * make_const
  *
- * - takes a lispvalue, (as returned to the yacc routine by the lexer)
- *  extracts the type, and makes the appropriate type constant
- *  by invoking the (c-callable) lisp routine c-make-const
- *  via the lisp_call() mechanism
- *
- * eventually, produces a "const" lisp-struct as per nodedefs.cl
+ * Convert a Value node (as returned by the grammar) to a Const node
+ * of the "natural" type for the constant.  For strings we produce
+ * a constant of type UNKNOWN ---- representation is the same as text,
+ * but this indicates to later type resolution that we're not sure that
+ * it should be considered text.
  */
 Const *
 make_const(Value *value)
 {
-   Type        tp;
    Datum       val;
+   Oid         typeid;
+   int         typelen;
+   bool        typebyval;
    Const      *con;
 
    switch (nodeTag(value))
    {
        case T_Integer:
-           tp = typeidType(INT4OID);
            val = Int32GetDatum(intVal(value));
+
+           typeid = INT4OID;
+           typelen = sizeof(int32);
+           typebyval = true;
            break;
 
        case T_Float:
            {
                float64     dummy;
 
-               tp = typeidType(FLOAT8OID);
-
                dummy = (float64) palloc(sizeof(float64data));
                *dummy = floatVal(value);
 
                val = Float64GetDatum(dummy);
+
+               typeid = FLOAT8OID;
+               typelen = sizeof(float64data);
+               typebyval = false;
            }
            break;
 
        case T_String:
-           tp = typeidType(UNKNOWNOID);        /* unknown for now, will
-                                                * be type coerced */
            val = PointerGetDatum(textin(strVal(value)));
+
+           typeid = UNKNOWNOID; /* will be coerced later */
+           typelen = -1;       /* variable len */
+           typebyval = false;
            break;
 
        case T_Null:
        default:
-           {
-               if (nodeTag(value) != T_Null)
-                   elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value));
+           if (nodeTag(value) != T_Null)
+               elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value));
 
-               /* null const */
-               con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
-               return con;
-           }
+           /* return a null const */
+           con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
+           return con;
    }
 
-   con = makeConst(typeTypeId(tp),
-                   typeLen(tp),
+   con = makeConst(typeid,
+                   typelen,
                    val,
                    false,
-                   typeByVal(tp),
+                   typebyval,
                    false,      /* not a set */
-                   false);
+                   false);     /* not coerced */
 
    return con;
 }
index 48973f67d9b928a7532ab2688d4dd45076e661b4..a009bc5a77cc554ee847de2f78a9f3a9f4c9465e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.46 1999/07/19 00:26:20 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.47 1999/11/01 05:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -162,12 +162,14 @@ transformTargetList(ParseState *pstate, List *targetlist)
  * pstate      parse state
  * tle         target list entry to be modified
  * colname     target column name (ie, name of attribute to be assigned to)
+ * attrno      target attribute number
  * indirection subscripts for target column, if any
  */
 void
 updateTargetListEntry(ParseState *pstate,
                      TargetEntry *tle,
                      char *colname,
+                     int attrno,
                      List *indirection)
 {
    Oid         type_id = exprType(tle->expr); /* type of value provided */
@@ -175,14 +177,12 @@ updateTargetListEntry(ParseState *pstate,
    int32       attrtypmod;
    Resdom     *resnode = tle->resdom;
    Relation    rd = pstate->p_target_relation;
-   int         resdomno;
 
    Assert(rd != NULL);
-   resdomno = attnameAttNum(rd, colname);
-   if (resdomno <= 0)
+   if (attrno <= 0)
        elog(ERROR, "Cannot assign to system attribute '%s'", colname);
-   attrtype = attnumTypeId(rd, resdomno);
-   attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;
+   attrtype = attnumTypeId(rd, attrno);
+   attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
 
    /*
     * If there are subscripts on the target column, prepare an
@@ -260,7 +260,7 @@ updateTargetListEntry(ParseState *pstate,
    resnode->restype = attrtype;
    resnode->restypmod = attrtypmod;
    resnode->resname = colname;
-   resnode->resno = (AttrNumber) resdomno;
+   resnode->resno = (AttrNumber) attrno;
 }
 
 
@@ -356,14 +356,17 @@ SizeTargetExpr(ParseState *pstate,
 
 
 /*
- * makeTargetNames -
+ * checkInsertTargets -
  *   generate a list of column names if not supplied or
  *   test supplied column names to make sure they are in target table.
+ *   Also return an integer list of the columns' attribute numbers.
  *   (used exclusively for inserts)
  */
 List *
-makeTargetNames(ParseState *pstate, List *cols)
+checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 {
+   *attrnos = NIL;
+
    if (cols == NIL)
    {
        /*
@@ -382,6 +385,7 @@ makeTargetNames(ParseState *pstate, List *cols)
            id->indirection = NIL;
            id->isRel = false;
            cols = lappend(cols, id);
+           *attrnos = lappendi(*attrnos, i+1);
        }
    }
    else
@@ -394,17 +398,14 @@ makeTargetNames(ParseState *pstate, List *cols)
        foreach(tl, cols)
        {
            char       *name = ((Ident *) lfirst(tl))->name;
-           List       *nxt;
+           int         attrno;
 
            /* Lookup column name, elog on failure */
-           attnameAttNum(pstate->p_target_relation, name);
+           attrno = attnameAttNum(pstate->p_target_relation, name);
            /* Check for duplicates */
-           foreach(nxt, lnext(tl))
-           {
-               if (strcmp(name, ((Ident *) lfirst(nxt))->name) == 0)
-                   elog(ERROR, "Attribute '%s' specified more than once",
-                        name);
-           }
+           if (intMember(attrno, *attrnos))
+               elog(ERROR, "Attribute '%s' specified more than once", name);
+           *attrnos = lappendi(*attrnos, attrno);
        }
    }
 
index c2babecb769d9e1b9b257fbc58420c157132db00..08cf389d72e61671edcb3a2c4a78e8489f22b42d 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_target.h,v 1.15 1999/07/19 00:26:18 tgl Exp $
+ * $Id: parse_target.h,v 1.16 1999/11/01 05:06:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,9 +20,11 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
                                         Node *node, Node *expr,
                                         char *colname, bool resjunk);
 extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
-                                 char *colname, List *indirection);
+                                 char *colname, int attrno,
+                                 List *indirection);
 extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr,
                              Oid type_id, Oid attrtype);
-extern List *makeTargetNames(ParseState *pstate, List *cols);
+extern List *checkInsertTargets(ParseState *pstate, List *cols,
+                               List **attrnos);
 
 #endif  /* PARSE_TARGET_H */