make_const --- don't repeat cache searches that aren't needed.
*
* 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 $
*
*-------------------------------------------------------------------------
*/
Query *qry = makeNode(Query);
Node *fromQual;
List *icolumns;
+ List *attrnos;
+ List *attnos;
+ int numuseratts;
List *tl;
TupleDesc rd_att;
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);
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?
*/
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))),
* 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);
}
}
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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
} /* 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;
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);
}
/*
}
/*
- * 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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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 */
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
resnode->restype = attrtype;
resnode->restypmod = attrtypmod;
resnode->resname = colname;
- resnode->resno = (AttrNumber) resdomno;
+ resnode->resno = (AttrNumber) attrno;
}
/*
- * 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)
{
/*
id->indirection = NIL;
id->isRel = false;
cols = lappend(cols, id);
+ *attrnos = lappendi(*attrnos, i+1);
}
}
else
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);
}
}
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */