mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Eliminate local inefficiencies in updateTargetListEntry, make_var, and
make_const --- don't repeat cache searches that aren't needed.
This commit is contained in:
parent
249f6b40ab
commit
d40dbb7387
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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;
|
||||||
|
Form_pg_attribute thisatt = att[attrno - 1];
|
||||||
TargetEntry *te;
|
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)
|
|||||||
* 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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
} /* 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,
|
|||||||
|
|
||||||
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;
|
||||||
|
type_mod = att_tup->atttypmod;
|
||||||
|
|
||||||
varnode = makeVar(vnum, attid, vartypeid, type_mod, sublevels_up);
|
return makeVar(vnum, attid, vartypeid, type_mod, sublevels_up);
|
||||||
|
|
||||||
return varnode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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,
|
|||||||
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user