/*-------------------------------------------------------------------------
*
* execJunk . c
* Junk attribute support stuff . . . .
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
*
* IDENTIFICATION
* src / backend / executor / execJunk . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "executor/executor.h"
/*-------------------------------------------------------------------------
* XXX this stuff should be rewritten to take advantage
* of ExecProject ( ) and the ProjectionInfo node .
* - cim 6 / 3 / 91
*
* An attribute of a tuple living inside the executor , can be
* either a normal attribute or a " junk " attribute . " junk " attributes
* 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 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 a filter .
*
* 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
* ExecFindJunkAttribute / ExecGetJunkAttribute to retrieve the values of the
* junk attributes we are interested in , and ExecFilterJunk to remove all the
* junk attributes from a tuple . This new " clean " tuple is then printed ,
* inserted , or updated .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/*
* ExecInitJunkFilter
*
* Initialize the Junk filter .
*
* The source targetlist is passed in . The output tuple descriptor is
* built from the non - junk tlist entries .
* An optional resultSlot can be passed as well ; otherwise , we create one .
*/
JunkFilter *
ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
{
JunkFilter *junkfilter;
TupleDesc cleanTupType;
int cleanLength;
AttrNumber *cleanMap;
/*
* Compute the tuple descriptor for the cleaned tuple .
*/
cleanTupType = ExecCleanTypeFromTL(targetList);
/*
* Use the given slot , or make a new slot if we weren ' t given one .
*/
if (slot)
ExecSetSlotDescriptor(slot, cleanTupType);
else
slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
/*
* 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 )
{
AttrNumber cleanResno;
ListCell *t;
cleanMap = (AttrNumber *) palloc(cleanLength * sizeof (AttrNumber));
cleanResno = 0 ;
foreach(t, targetList)
{
TargetEntry *tle = lfirst(t);
if (!tle->resjunk)
{
cleanMap[cleanResno] = tle->resno;
cleanResno++;
}
}
Assert(cleanResno == cleanLength);
}
else
cleanMap = NULL;
/*
* Finally create and initialize the JunkFilter struct .
*/
junkfilter = makeNode(JunkFilter);
junkfilter->jf_targetList = targetList;
junkfilter->jf_cleanTupType = cleanTupType;
junkfilter->jf_cleanMap = cleanMap;
junkfilter->jf_resultSlot = slot;
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;
/*
* Use the given slot , or make a new slot if we weren ' t given one .
*/
if (slot)
ExecSetSlotDescriptor(slot, cleanTupType);
else
slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
/*
* 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 . 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 *) palloc0(cleanLength * sizeof (AttrNumber));
t = list_head(targetList);
for (i = 0 ; i < cleanLength; i++)
{
if (TupleDescCompactAttr(cleanTupType, i)->attisdropped)
continue ; /* map entry is already zero */
for (;;)
{
TargetEntry *tle = lfirst(t);
t = lnext(targetList, t);
if (!tle->resjunk)
{
cleanMap[i] = tle->resno;
break ;
}
}
}
}
else
cleanMap = NULL;
/*
* Finally create and initialize the JunkFilter struct .
*/
junkfilter = makeNode(JunkFilter);
junkfilter->jf_targetList = targetList;
junkfilter->jf_cleanTupType = cleanTupType;
junkfilter->jf_cleanMap = cleanMap;
junkfilter->jf_resultSlot = slot;
return junkfilter;
}
/*
* ExecFindJunkAttribute
*
* Locate the specified junk attribute in the junk filter ' s targetlist ,
* and return its resno . Returns InvalidAttrNumber if not found .
*/
AttrNumber
ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
{
return ExecFindJunkAttributeInTlist(junkfilter->jf_targetList, attrName);
}
/*
* ExecFindJunkAttributeInTlist
*
* Find a junk attribute given a subplan ' s targetlist ( not necessarily
* part of a JunkFilter ) .
*/
AttrNumber
ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
{
ListCell *t;
foreach(t, targetlist)
{
TargetEntry *tle = lfirst(t);
if (tle->resjunk && tle->resname &&
(strcmp(tle->resname, attrName) == 0 ))
{
/* We found it ! */
return tle->resno;
}
}
return InvalidAttrNumber;
}
/*
* ExecFilterJunk
*
* Construct and return a slot with all the junk attributes removed .
*/
TupleTableSlot *
ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
{
TupleTableSlot *resultSlot;
AttrNumber *cleanMap;
TupleDesc cleanTupType;
int cleanLength;
int i;
Datum *values;
bool *isnull;
Datum *old_values;
bool *old_isnull;
/*
* Extract all the values of the old tuple .
*/
slot_getallattrs(slot);
old_values = slot->tts_values;
old_isnull = slot->tts_isnull;
/*
* get info from the junk filter
*/
cleanTupType = junkfilter->jf_cleanTupType;
cleanLength = cleanTupType->natts;
cleanMap = junkfilter->jf_cleanMap;
resultSlot = junkfilter->jf_resultSlot;
/*
* Prepare to build a virtual result tuple .
*/
ExecClearTuple(resultSlot);
values = resultSlot->tts_values;
isnull = resultSlot->tts_isnull;
/*
* Transpose data into proper fields of the new tuple .
*/
for (i = 0 ; i < cleanLength; i++)
{
int j = cleanMap[i];
if (j == 0 )
{
values[i] = (Datum) 0 ;
isnull[i] = true ;
}
else
{
values[i] = old_values[j - 1 ];
isnull[i] = old_isnull[j - 1 ];
}
}
/*
* And return the virtual tuple .
*/
return ExecStoreVirtualTuple(resultSlot);
}
Messung V0.5 in Prozent C=94 H=94 G=93
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland