summaryrefslogtreecommitdiff
path: root/src/backend/executor/execJunk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execJunk.c')
-rw-r--r--src/backend/executor/execJunk.c195
1 files changed, 112 insertions, 83 deletions
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
index c797c343d35..bfa4ad9d7fd 100644
--- a/src/backend/executor/execJunk.c
+++ b/src/backend/executor/execJunk.c
@@ -1,6 +1,6 @@
/*-------------------------------------------------------------------------
*
- * junk.c
+ * execJunk.c
* Junk attribute support stuff....
*
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.43 2004/08/29 05:06:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.44 2004/10/07 18:38:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -50,97 +50,128 @@
*-------------------------------------------------------------------------
*/
-/*-------------------------------------------------------------------------
+/*
* ExecInitJunkFilter
*
* Initialize the Junk filter.
*
- * The initial targetlist and associated tuple descriptor are passed in.
+ * The source targetlist is passed in. The output tuple descriptor is
+ * built from the non-junk tlist entries, plus the passed specification
+ * of whether to include room for an OID or not.
* An optional resultSlot can be passed as well.
- *-------------------------------------------------------------------------
*/
JunkFilter *
-ExecInitJunkFilter(List *targetList, TupleDesc tupType,
- TupleTableSlot *slot)
+ExecInitJunkFilter(List *targetList, bool hasoid, TupleTableSlot *slot)
{
JunkFilter *junkfilter;
- List *cleanTargetList;
- int len,
- cleanLength;
TupleDesc cleanTupType;
+ int cleanLength;
+ AttrNumber *cleanMap;
ListCell *t;
- TargetEntry *tle;
- Resdom *resdom,
- *cleanResdom;
- bool resjunk;
AttrNumber cleanResno;
- AttrNumber *cleanMap;
- Expr *expr;
/*
- * First find the "clean" target list, i.e. all the entries in the
- * original target list which have a false 'resjunk' NOTE: make copy
- * of the Resdom nodes, because we have to change the 'resno's...
+ * Compute the tuple descriptor for the cleaned tuple.
*/
- cleanTargetList = NIL;
- cleanResno = 1;
+ cleanTupType = ExecCleanTypeFromTL(targetList, hasoid);
- foreach(t, targetList)
+ /*
+ * Now calculate the mapping between the original tuple's attributes and
+ * the "clean" tuple's attributes.
+ *
+ * The "map" is an array of "cleanLength" attribute numbers, i.e. one
+ * entry for every attribute of the "clean" tuple. The value of this
+ * entry is the attribute number of the corresponding attribute of the
+ * "original" tuple. (Zero indicates a NULL output attribute, but we
+ * do not use that feature in this routine.)
+ */
+ cleanLength = cleanTupType->natts;
+ if (cleanLength > 0)
{
- TargetEntry *rtarget = lfirst(t);
-
- resdom = rtarget->resdom;
- expr = rtarget->expr;
- resjunk = resdom->resjunk;
- if (!resjunk)
+ cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
+ cleanResno = 1;
+ foreach(t, targetList)
{
- /*
- * make a copy of the resdom node, changing its resno.
- */
- cleanResdom = (Resdom *) copyObject(resdom);
- cleanResdom->resno = cleanResno;
- cleanResno++;
-
- /*
- * create a new target list entry
- */
- tle = makeTargetEntry(cleanResdom, expr);
- cleanTargetList = lappend(cleanTargetList, tle);
+ TargetEntry *tle = lfirst(t);
+ Resdom *resdom = tle->resdom;
+
+ if (!resdom->resjunk)
+ {
+ cleanMap[cleanResno - 1] = resdom->resno;
+ cleanResno++;
+ }
}
}
+ else
+ cleanMap = NULL;
/*
- * Now calculate the tuple type for the cleaned tuple (we were already
- * given the type for the original targetlist).
+ * Finally create and initialize the JunkFilter struct.
*/
- cleanTupType = ExecTypeFromTL(cleanTargetList, tupType->tdhasoid);
+ junkfilter = makeNode(JunkFilter);
- len = ExecTargetListLength(targetList);
- cleanLength = ExecTargetListLength(cleanTargetList);
+ junkfilter->jf_targetList = targetList;
+ junkfilter->jf_cleanTupType = cleanTupType;
+ junkfilter->jf_cleanMap = cleanMap;
+ junkfilter->jf_resultSlot = slot;
+
+ if (slot)
+ ExecSetSlotDescriptor(slot, cleanTupType, false);
+
+ return junkfilter;
+}
+
+/*
+ * ExecInitJunkFilterConversion
+ *
+ * Initialize a JunkFilter for rowtype conversions.
+ *
+ * Here, we are given the target "clean" tuple descriptor rather than
+ * inferring it from the targetlist. The target descriptor can contain
+ * deleted columns. It is assumed that the caller has checked that the
+ * non-deleted columns match up with the non-junk columns of the targetlist.
+ */
+JunkFilter *
+ExecInitJunkFilterConversion(List *targetList,
+ TupleDesc cleanTupType,
+ TupleTableSlot *slot)
+{
+ JunkFilter *junkfilter;
+ int cleanLength;
+ AttrNumber *cleanMap;
+ ListCell *t;
+ int i;
/*
- * Now calculate the "map" between the original tuple's attributes and
+ * Calculate the mapping between the original tuple's attributes and
* the "clean" tuple's attributes.
*
* The "map" is an array of "cleanLength" attribute numbers, i.e. one
* entry for every attribute of the "clean" tuple. The value of this
* entry is the attribute number of the corresponding attribute of the
- * "original" tuple.
+ * "original" tuple. We store zero for any deleted attributes, marking
+ * that a NULL is needed in the output tuple.
*/
+ cleanLength = cleanTupType->natts;
if (cleanLength > 0)
{
- cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
- cleanResno = 1;
- foreach(t, targetList)
+ cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
+ t = list_head(targetList);
+ for (i = 0; i < cleanLength; i++)
{
- TargetEntry *tle = lfirst(t);
-
- resdom = tle->resdom;
- resjunk = resdom->resjunk;
- if (!resjunk)
+ if (cleanTupType->attrs[i]->attisdropped)
+ continue; /* map entry is already zero */
+ for (;;)
{
- cleanMap[cleanResno - 1] = resdom->resno;
- cleanResno++;
+ TargetEntry *tle = lfirst(t);
+ Resdom *resdom = tle->resdom;
+
+ t = lnext(t);
+ if (!resdom->resjunk)
+ {
+ cleanMap[i] = resdom->resno;
+ break;
+ }
}
}
}
@@ -153,10 +184,6 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType,
junkfilter = makeNode(JunkFilter);
junkfilter->jf_targetList = targetList;
- junkfilter->jf_length = len;
- junkfilter->jf_tupType = tupType;
- junkfilter->jf_cleanTargetList = cleanTargetList;
- junkfilter->jf_cleanLength = cleanLength;
junkfilter->jf_cleanTupType = cleanTupType;
junkfilter->jf_cleanMap = cleanMap;
junkfilter->jf_resultSlot = slot;
@@ -167,14 +194,13 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType,
return junkfilter;
}
-/*-------------------------------------------------------------------------
+/*
* ExecGetJunkAttribute
*
* Given a tuple (slot), the junk filter and a junk attribute's name,
* extract & return the value and isNull flag of this attribute.
*
* It returns false iff no junk attribute with such name was found.
- *-------------------------------------------------------------------------
*/
bool
ExecGetJunkAttribute(JunkFilter *junkfilter,
@@ -220,14 +246,14 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
* Now extract the attribute value from the tuple.
*/
tuple = slot->val;
- tupType = junkfilter->jf_tupType;
+ tupType = slot->ttc_tupleDescriptor;
*value = heap_getattr(tuple, resno, tupType, isNull);
return true;
}
-/*-------------------------------------------------------------------------
+/*
* ExecRemoveJunk
*
* Construct and return a tuple with all the junk attributes removed.
@@ -235,35 +261,37 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
* Note: for historical reasons, this does not store the constructed
* tuple into the junkfilter's resultSlot. The caller should do that
* if it wants to.
- *-------------------------------------------------------------------------
*/
HeapTuple
ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
{
+#define PREALLOC_SIZE 64
HeapTuple tuple;
HeapTuple cleanTuple;
AttrNumber *cleanMap;
TupleDesc cleanTupType;
TupleDesc tupType;
int cleanLength;
+ int oldLength;
int i;
Datum *values;
char *nulls;
Datum *old_values;
char *old_nulls;
- Datum values_array[64];
- Datum old_values_array[64];
- char nulls_array[64];
- char old_nulls_array[64];
+ Datum values_array[PREALLOC_SIZE];
+ Datum old_values_array[PREALLOC_SIZE];
+ char nulls_array[PREALLOC_SIZE];
+ char old_nulls_array[PREALLOC_SIZE];
/*
* get info from the slot and the junk filter
*/
tuple = slot->val;
+ tupType = slot->ttc_tupleDescriptor;
+ oldLength = tupType->natts + 1; /* +1 for NULL */
- tupType = junkfilter->jf_tupType;
cleanTupType = junkfilter->jf_cleanTupType;
- cleanLength = junkfilter->jf_cleanLength;
+ cleanLength = cleanTupType->natts;
cleanMap = junkfilter->jf_cleanMap;
/*
@@ -273,12 +301,8 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
* Note: we use memory on the stack to optimize things when we are
* dealing with a small number of attributes. for large tuples we just
* use palloc.
- *
- * Note: we could use just one set of arrays if we were willing to assume
- * that the resno mapping is monotonic... I think it is, but won't
- * take the risk of breaking things right now.
*/
- if (cleanLength > 64)
+ if (cleanLength > PREALLOC_SIZE)
{
values = (Datum *) palloc(cleanLength * sizeof(Datum));
nulls = (char *) palloc(cleanLength * sizeof(char));
@@ -288,10 +312,10 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
values = values_array;
nulls = nulls_array;
}
- if (tupType->natts > 64)
+ if (oldLength > PREALLOC_SIZE)
{
- old_values = (Datum *) palloc(tupType->natts * sizeof(Datum));
- old_nulls = (char *) palloc(tupType->natts * sizeof(char));
+ old_values = (Datum *) palloc(oldLength * sizeof(Datum));
+ old_nulls = (char *) palloc(oldLength * sizeof(char));
}
else
{
@@ -300,16 +324,21 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
}
/*
- * Extract all the values of the old tuple.
+ * Extract all the values of the old tuple, offsetting the arrays
+ * so that old_values[0] is NULL and old_values[1] is the first
+ * source attribute; this exactly matches the numbering convention
+ * in cleanMap.
*/
- heap_deformtuple(tuple, tupType, old_values, old_nulls);
+ heap_deformtuple(tuple, tupType, old_values + 1, old_nulls + 1);
+ old_values[0] = (Datum) 0;
+ old_nulls[0] = 'n';
/*
* Transpose into proper fields of the new tuple.
*/
for (i = 0; i < cleanLength; i++)
{
- int j = cleanMap[i] - 1;
+ int j = cleanMap[i];
values[i] = old_values[j];
nulls[i] = old_nulls[j];