execJunk.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
- /*-------------------------------------------------------------------------
- *
- * junk.c
- * Junk attribute support stuff....
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.17 1999/05/17 17:03:10 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
- #include <string.h>
- #include "postgres.h"
- #include "utils/palloc.h"
- #include "access/heapam.h"
- #include "executor/executor.h"
- #include "nodes/relation.h"
- #include "nodes/makefuncs.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 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 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
- * 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;
- bool 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 false '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)
- {
- /*
- * 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);
- }
- }
- 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) makeTargetEntry(cleanResdom, (Node *) 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) makeTargetEntry(cleanResdom, (Node *) 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)
- {
- 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;
- bool 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 && (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 = heap_getattr(tuple, 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++)
- {
- values[i] = heap_getattr(tuple, cleanMap[i], tupType, &isNull);
- 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;
- }