From d40dbb7387a50b1319d84cb596a854f1688302db Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 1 Nov 1999 05:06:21 +0000 Subject: [PATCH] Eliminate local inefficiencies in updateTargetListEntry, make_var, and make_const --- don't repeat cache searches that aren't needed. --- src/backend/parser/analyze.c | 59 ++++++++++++++--------- src/backend/parser/parse_node.c | 80 ++++++++++++++++++------------- src/backend/parser/parse_target.c | 35 +++++++------- src/include/parser/parse_target.h | 8 ++-- 4 files changed, 106 insertions(+), 76 deletions(-) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 08c209b2a5..2bd3a00b73 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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) diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 35fa858dc0..d4593a1357 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -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; } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 48973f67d9..a009bc5a77 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -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); } } diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index c2babecb76..08cf389d72 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -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 */ -- 2.40.0