*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.54 2006/07/14 14:52:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.55 2006/12/04 02:06:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* never make it out of the executor, i.e. they are never printed,
* returned or stored on disk. Their only purpose in life is to
* store some information useful only to the executor, mainly the values
- * of some system attributes like "ctid" or rule locks.
+ * of system attributes like "ctid", or sort key columns that are not to
+ * be output.
*
* The general idea is the following: A target list consists of a list of
* TargetEntry nodes containing expressions. Each TargetEntry has a field
* called 'resjunk'. If the value of this field is true then the
* corresponding attribute is a "junk" attribute.
*
- * When we initialize a plan we call 'ExecInitJunkFilter' to create
- * and store the appropriate information in the 'es_junkFilter' attribute of
+ * When we initialize a plan we call ExecInitJunkFilter to create
+ * and store the appropriate information in the es_junkFilter attribute of
* EState.
*
- * We then execute the plan ignoring the "resjunk" attributes.
+ * We then execute the plan, treating the resjunk attributes like any others.
*
* Finally, when at the top level we get back a tuple, we can call
- * ExecGetJunkAttribute to retrieve the value of the junk attributes we
- * are interested in, and ExecFilterJunk or ExecRemoveJunk to remove all
- * the junk attributes from a tuple. This new "clean" tuple is then printed,
- * replaced, deleted or inserted.
+ * ExecFindJunkAttribute/ExecGetJunkAttribute to retrieve the values of the
+ * junk attributes we are interested in, and ExecFilterJunk or ExecRemoveJunk
+ * to remove all the junk attributes from a tuple. This new "clean" tuple is
+ * then printed, replaced, deleted or inserted.
*
*-------------------------------------------------------------------------
*/
}
/*
- * ExecGetJunkAttribute
- *
- * Given a tuple (slot), the junk filter and a junk attribute's name,
- * extract & return the value and isNull flag of this attribute.
+ * ExecFindJunkAttribute
*
- * It returns false iff no junk attribute with such name was found.
+ * Locate the specified junk attribute in the junk filter's targetlist,
+ * and return its resno. Returns InvalidAttrNumber if not found.
*/
-bool
-ExecGetJunkAttribute(JunkFilter *junkfilter,
- TupleTableSlot *slot,
- char *attrName,
- Datum *value,
- bool *isNull)
+AttrNumber
+ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
{
ListCell *t;
- /*
- * Look in the junkfilter's target list for an attribute with the given
- * name
- */
foreach(t, junkfilter->jf_targetList)
{
TargetEntry *tle = lfirst(t);
(strcmp(tle->resname, attrName) == 0))
{
/* We found it ! */
- *value = slot_getattr(slot, tle->resno, isNull);
- return true;
+ return tle->resno;
}
}
- /* Ooops! We couldn't find this attribute... */
- return false;
+ return InvalidAttrNumber;
+}
+
+/*
+ * ExecGetJunkAttribute
+ *
+ * Given a junk filter's input tuple (slot) and a junk attribute's number
+ * previously found by ExecFindJunkAttribute, extract & return the value and
+ * isNull flag of the attribute.
+ */
+Datum
+ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno,
+ bool *isNull)
+{
+ Assert(attno > 0);
+
+ return slot_getattr(slot, attno, isNull);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.280 2006/10/04 00:29:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.281 2006/12/04 02:06:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
/*
- * Have to lock relations selected FOR UPDATE/FOR SHARE
+ * Have to lock relations selected FOR UPDATE/FOR SHARE before we
+ * initialize the plan tree, else we'd be doing a lock upgrade.
+ * While we are at it, build the ExecRowMark list.
*/
estate->es_rowMarks = NIL;
foreach(l, parseTree->rowMarks)
erm->rti = rc->rti;
erm->forUpdate = rc->forUpdate;
erm->noWait = rc->noWait;
- snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rc->rti);
+ /* We'll set up ctidAttno below */
+ erm->ctidAttNo = InvalidAttrNumber;
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
}
j = ExecInitJunkFilter(subplan->plan->targetlist,
resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
ExecAllocTableSlot(estate->es_tupleTable));
+ /*
+ * Since it must be UPDATE/DELETE, there had better be
+ * a "ctid" junk attribute in the tlist ... but ctid could
+ * be at a different resno for each result relation.
+ * We look up the ctid resnos now and save them in the
+ * junkfilters.
+ */
+ j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
+ if (!AttributeNumberIsValid(j->jf_junkAttNo))
+ elog(ERROR, "could not find junk ctid column");
resultRelInfo->ri_junkFilter = j;
resultRelInfo++;
}
if (estate->es_result_relation_info)
estate->es_result_relation_info->ri_junkFilter = j;
- /* For SELECT, want to return the cleaned tuple type */
if (operation == CMD_SELECT)
+ {
+ /* For SELECT, want to return the cleaned tuple type */
tupType = j->jf_cleanTupType;
+ /* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
+ foreach(l, estate->es_rowMarks)
+ {
+ ExecRowMark *erm = (ExecRowMark *) lfirst(l);
+ char resname[32];
+
+ snprintf(resname, sizeof(resname), "ctid%u", erm->rti);
+ erm->ctidAttNo = ExecFindJunkAttribute(j, resname);
+ if (!AttributeNumberIsValid(erm->ctidAttNo))
+ elog(ERROR, "could not find junk \"%s\" column",
+ resname);
+ }
+ }
+ else if (operation == CMD_UPDATE || operation == CMD_DELETE)
+ {
+ /* For UPDATE/DELETE, find the ctid junk attr now */
+ j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
+ if (!AttributeNumberIsValid(j->jf_junkAttNo))
+ elog(ERROR, "could not find junk ctid column");
+ }
}
}
else
*/
if (operation == CMD_UPDATE || operation == CMD_DELETE)
{
- if (!ExecGetJunkAttribute(junkfilter,
- slot,
- "ctid",
- &datum,
- &isNull))
- elog(ERROR, "could not find junk ctid column");
-
+ datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
+ &isNull);
/* shouldn't ever get a null result... */
if (isNull)
elog(ERROR, "ctid is NULL");
LockTupleMode lockmode;
HTSU_Result test;
- if (!ExecGetJunkAttribute(junkfilter,
- slot,
- erm->resname,
- &datum,
- &isNull))
- elog(ERROR, "could not find junk \"%s\" column",
- erm->resname);
-
+ datum = ExecGetJunkAttribute(slot,
+ erm->ctidAttNo,
+ &isNull);
/* shouldn't ever get a null result... */
if (isNull)
- elog(ERROR, "\"%s\" is NULL", erm->resname);
+ elog(ERROR, "ctid is NULL");
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.130 2006/10/04 00:30:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.131 2006/12/04 02:06:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern JunkFilter *ExecInitJunkFilterConversion(List *targetList,
TupleDesc cleanTupType,
TupleTableSlot *slot);
-extern bool ExecGetJunkAttribute(JunkFilter *junkfilter, TupleTableSlot *slot,
- char *attrName, Datum *value, bool *isNull);
+extern AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter,
+ const char *attrName);
+extern Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno,
+ bool *isNull);
extern TupleTableSlot *ExecFilterJunk(JunkFilter *junkfilter,
TupleTableSlot *slot);
extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.161 2006/09/28 20:51:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.162 2006/12/04 02:06:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* the tuple to be updated. This is needed to do the update, but we
* don't want the ctid to be part of the stored new tuple! So, we
* apply a "junk filter" to remove the junk attributes and form the
- * real output tuple.
+ * real output tuple. The junkfilter code also provides routines to
+ * extract the values of the junk attribute(s) from the input tuple.
*
* targetList: the original target list (including junk attributes).
* cleanTupType: the tuple descriptor for the "clean" tuple (with
* attribute numbers of the "original" tuple and the
* attribute numbers of the "clean" tuple.
* resultSlot: tuple slot used to hold cleaned tuple.
+ * junkAttNo: not used by junkfilter code. Can be used by caller
+ * to remember the attno of a specific junk attribute
+ * (execMain.c stores the "ctid" attno here).
* ----------------
*/
typedef struct JunkFilter
TupleDesc jf_cleanTupType;
AttrNumber *jf_cleanMap;
TupleTableSlot *jf_resultSlot;
+ AttrNumber jf_junkAttNo;
} JunkFilter;
/* ----------------
Index rti; /* its range table index */
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
bool noWait; /* NOWAIT option */
- char resname[32]; /* name for its ctid junk attribute */
+ AttrNumber ctidAttNo; /* resno of its ctid junk attribute */
} ExecRowMark;