From 46651ce6fe013220ed397add242004d764fc0153 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:15:05 +0200 Subject: Adding upstream version 14.5. Signed-off-by: Daniel Baumann --- src/backend/executor/execJunk.c | 304 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 src/backend/executor/execJunk.c (limited to 'src/backend/executor/execJunk.c') diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c new file mode 100644 index 0000000..9741897 --- /dev/null +++ b/src/backend/executor/execJunk.c @@ -0,0 +1,304 @@ +/*------------------------------------------------------------------------- + * + * execJunk.c + * Junk attribute support stuff.... + * + * Portions Copyright (c) 1996-2021, 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 (TupleDescAttr(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); +} -- cgit v1.2.3