aboutsummaryrefslogtreecommitdiff
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.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
new file mode 100644
index 00000000000..7ee1543299a
--- /dev/null
+++ b/src/backend/executor/execJunk.c
@@ -0,0 +1,389 @@
+/*-------------------------------------------------------------------------
+ *
+ * junk.c--
+ * Junk attribute support stuff....
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.1.1.1 1996/07/09 06:21:24 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "utils/palloc.h"
+#include "executor/executor.h"
+#include "nodes/relation.h"
+#include "optimizer/tlist.h" /* for MakeTLE */
+
+/*-------------------------------------------------------------------------
+ * 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 in 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.
+ *
+ * The general idea is the following: A target list consists of a list of
+ * Resdom nodes & expression pairs. Each Resdom node has an attribute
+ * called 'resjunk'. If the value of this attribute is 1 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
+ * EState.
+ *
+ * We then execute the plan ignoring the "resjunk" attributes.
+ *
+ * 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 'ExecRemoveJunk' to remove all the junk attributes
+ * from a tuple. This new "clean" tuple is then printed, replaced, deleted
+ * or inserted.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*-------------------------------------------------------------------------
+ * ExecInitJunkFilter
+ *
+ * Initialize the Junk filter.
+ *-------------------------------------------------------------------------
+ */
+JunkFilter *
+ExecInitJunkFilter(List *targetList)
+{
+ JunkFilter *junkfilter;
+ List *cleanTargetList;
+ int len, cleanLength;
+ TupleDesc tupType, cleanTupType;
+ List *t;
+ TargetEntry *tle;
+ Resdom *resdom, *cleanResdom;
+ int resjunk;
+ AttrNumber cleanResno;
+ AttrNumber *cleanMap;
+ Size size;
+ Node *expr;
+
+ /* ---------------------
+ * First find the "clean" target list, i.e. all the entries
+ * in the original target list which have a zero 'resjunk'
+ * NOTE: make copy of the Resdom nodes, because we have
+ * to change the 'resno's...
+ * ---------------------
+ */
+ cleanTargetList = NIL;
+ cleanResno = 1;
+
+ foreach (t, targetList) {
+ TargetEntry *rtarget = lfirst(t);
+ if (rtarget->resdom != NULL) {
+ resdom = rtarget->resdom;
+ expr = rtarget->expr;
+ resjunk = resdom->resjunk;
+ if (resjunk == 0) {
+ /*
+ * 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 = makeNode(TargetEntry);
+ tle->resdom = cleanResdom;
+ tle->expr = expr;
+ cleanTargetList = lappend(cleanTargetList, tle);
+ }
+ }
+ else {
+#ifdef SETS_FIXED
+ List *fjListP;
+ Fjoin *cleanFjoin;
+ List *cleanFjList;
+ List *fjList = lfirst(t);
+ Fjoin *fjNode = (Fjoin *)tl_node(fjList);
+
+ cleanFjoin = (Fjoin)copyObject((Node) fjNode);
+ cleanFjList = lcons(cleanFjoin, NIL);
+
+ resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
+ expr = lsecond(get_fj_innerNode(fjNode));
+ cleanResdom = (Resdom) copyObject((Node) resdom);
+ set_resno(cleanResdom, cleanResno);
+ cleanResno++;
+ tle = (List) MakeTLE(cleanResdom, (Expr) expr);
+ set_fj_innerNode(cleanFjoin, tle);
+
+ foreach(fjListP, lnext(fjList)) {
+ TargetEntry *tle = lfirst(fjListP);
+
+ resdom = tle->resdom;
+ expr = tle->expr;
+ cleanResdom = (Resdom*) copyObject((Node) resdom);
+ cleanResno++;
+ cleanResdom->Resno = cleanResno;
+ /*
+ * create a new target list entry
+ */
+ tle = (List) MakeTLE(cleanResdom, (Expr) expr);
+ cleanFjList = lappend(cleanFjList, tle);
+ }
+ lappend(cleanTargetList, cleanFjList);
+#endif
+ }
+ }
+
+ /* ---------------------
+ * Now calculate the tuple types for the original and the clean tuple
+ *
+ * XXX ExecTypeFromTL should be used sparingly. Don't we already
+ * have the tupType corresponding to the targetlist we are passed?
+ * -cim 5/31/91
+ * ---------------------
+ */
+ tupType = (TupleDesc) ExecTypeFromTL(targetList);
+ cleanTupType = (TupleDesc) ExecTypeFromTL(cleanTargetList);
+
+ len = ExecTargetListLength(targetList);
+ cleanLength = ExecTargetListLength(cleanTargetList);
+
+ /* ---------------------
+ * Now calculate the "map" between the original tuples 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.
+ * ---------------------
+ */
+ if (cleanLength > 0) {
+ size = cleanLength * sizeof(AttrNumber);
+ cleanMap = (AttrNumber*) palloc(size);
+ cleanResno = 1;
+ foreach (t, targetList) {
+ TargetEntry *tle = lfirst(t);
+ if (tle->resdom != NULL) {
+ resdom = tle->resdom;
+ expr = tle->expr;
+ resjunk = resdom->resjunk;
+ if (resjunk == 0) {
+ cleanMap[cleanResno-1] = resdom->resno;
+ cleanResno ++;
+ }
+ } else {
+#ifdef SETS_FIXED
+ List fjListP;
+ List fjList = lfirst(t);
+ Fjoin fjNode = (Fjoin)lfirst(fjList);
+
+ /* what the hell is this????? */
+ resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
+#endif
+
+ cleanMap[cleanResno-1] = tle->resdom->resno;
+ cleanResno++;
+
+#ifdef SETS_FIXED
+ foreach(fjListP, lnext(fjList)) {
+ TargetEntry *tle = lfirst(fjListP);
+
+ resdom = tle->resdom;
+ cleanMap[cleanResno-1] = resdom->resno;
+ cleanResno++;
+ }
+#endif
+ }
+ }
+ } else {
+ cleanMap = NULL;
+ }
+
+ /* ---------------------
+ * Finally create and initialize the JunkFilter.
+ * ---------------------
+ */
+ 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;
+
+ return(junkfilter);
+
+}
+
+/*-------------------------------------------------------------------------
+ * ExecGetJunkAttribute
+ *
+ * Given a tuple (slot), the junk filter and a junk attribute's name,
+ * extract & return the value of this attribute.
+ *
+ * It returns false iff no junk attribute with such name was found.
+ *
+ * NOTE: isNull might be NULL !
+ *-------------------------------------------------------------------------
+ */
+bool
+ExecGetJunkAttribute(JunkFilter *junkfilter,
+ TupleTableSlot *slot,
+ char *attrName,
+ Datum *value,
+ bool *isNull)
+{
+ List *targetList;
+ List *t;
+ Resdom *resdom;
+ AttrNumber resno;
+ char *resname;
+ int resjunk;
+ TupleDesc tupType;
+ HeapTuple tuple;
+
+ /* ---------------------
+ * first look in the junkfilter's target list for
+ * an attribute with the given name
+ * ---------------------
+ */
+ resno = InvalidAttrNumber;
+ targetList = junkfilter->jf_targetList;
+
+ foreach (t, targetList) {
+ TargetEntry *tle = lfirst(t);
+ resdom = tle->resdom;
+ resname = resdom->resname;
+ resjunk = resdom->resjunk;
+ if (resjunk != 0 && (strcmp(resname, attrName) == 0)) {
+ /* We found it ! */
+ resno = resdom->resno;
+ break;
+ }
+ }
+
+ if (resno == InvalidAttrNumber) {
+ /* Ooops! We couldn't find this attribute... */
+ return(false);
+ }
+
+ /* ---------------------
+ * Now extract the attribute value from the tuple.
+ * ---------------------
+ */
+ tuple = slot->val;
+ tupType = (TupleDesc) junkfilter->jf_tupType;
+
+ *value = (Datum)
+ heap_getattr(tuple, InvalidBuffer, resno, tupType, isNull);
+
+ return true;
+}
+
+/*-------------------------------------------------------------------------
+ * ExecRemoveJunk
+ *
+ * Construct and return a tuple with all the junk attributes removed.
+ *-------------------------------------------------------------------------
+ */
+HeapTuple
+ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
+{
+ HeapTuple tuple;
+ HeapTuple cleanTuple;
+ AttrNumber *cleanMap;
+ TupleDesc cleanTupType;
+ TupleDesc tupType;
+ int cleanLength;
+ bool isNull;
+ int i;
+ Size size;
+ Datum *values;
+ char *nulls;
+ Datum values_array[64];
+ char nulls_array[64];
+
+ /* ----------------
+ * get info from the slot and the junk filter
+ * ----------------
+ */
+ tuple = slot->val;
+
+ tupType = (TupleDesc) junkfilter->jf_tupType;
+ cleanTupType = (TupleDesc) junkfilter->jf_cleanTupType;
+ cleanLength = junkfilter->jf_cleanLength;
+ cleanMap = junkfilter->jf_cleanMap;
+
+ /* ---------------------
+ * Handle the trivial case first.
+ * ---------------------
+ */
+ if (cleanLength == 0)
+ return (HeapTuple) NULL;
+
+ /* ---------------------
+ * Create the arrays that will hold the attribute values
+ * and the null information for the new "clean" tuple.
+ *
+ * Note: we use memory on the stack to optimize things when
+ * we are dealing with a small number of tuples.
+ * for large tuples we just use palloc.
+ * ---------------------
+ */
+ if (cleanLength > 64) {
+ size = cleanLength * sizeof(Datum);
+ values = (Datum *) palloc(size);
+
+ size = cleanLength * sizeof(char);
+ nulls = (char *) palloc(size);
+ } else {
+ values = values_array;
+ nulls = nulls_array;
+ }
+
+ /* ---------------------
+ * Exctract one by one all the values of the "clean" tuple.
+ * ---------------------
+ */
+ for (i=0; i<cleanLength; i++) {
+ Datum d = (Datum)
+ heap_getattr(tuple, InvalidBuffer, cleanMap[i], tupType, &isNull);
+
+ values[i] = d;
+
+ if (isNull)
+ nulls[i] = 'n';
+ else
+ nulls[i] = ' ';
+ }
+
+ /* ---------------------
+ * Now form the new tuple.
+ * ---------------------
+ */
+ cleanTuple = heap_formtuple(cleanTupType,
+ values,
+ nulls);
+
+ /* ---------------------
+ * We are done. Free any space allocated for 'values' and 'nulls'
+ * and return the new tuple.
+ * ---------------------
+ */
+ if (cleanLength > 64) {
+ pfree(values);
+ pfree(nulls);
+ }
+
+ return(cleanTuple);
+}
+