Skip to content
Snippets Groups Projects
Select Git revision
  • benchmark-tools
  • postgres-lambda
  • master default
  • REL9_4_25
  • REL9_5_20
  • REL9_6_16
  • REL_10_11
  • REL_11_6
  • REL_12_1
  • REL_12_0
  • REL_12_RC1
  • REL_12_BETA4
  • REL9_4_24
  • REL9_5_19
  • REL9_6_15
  • REL_10_10
  • REL_11_5
  • REL_12_BETA3
  • REL9_4_23
  • REL9_5_18
  • REL9_6_14
  • REL_10_9
  • REL_11_4
23 results

execJunk.c

Blame
  • execJunk.c 11.00 KiB
    /*-------------------------------------------------------------------------
     *
     * 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.5 1997/08/26 23:31:37 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 "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);
    }