Commit d40dbb73 authored by Tom Lane's avatar Tom Lane

Eliminate local inefficiencies in updateTargetListEntry, make_var, and

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