diff options
Diffstat (limited to 'src/backend/executor/execJunk.c')
-rw-r--r-- | src/backend/executor/execJunk.c | 389 |
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); +} + |