Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions  Download package

nodeValuesscan.c
/*-------------------------------------------------------------------------
 *
 * nodeValuesscan.c
 *      Support routines for scanning Values lists
 *      ("VALUES (...), (...), ..." in rangetable).
 *
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.9 2009/01/01 17:23:42 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */
/*
 * INTERFACE ROUTINES
 *          ExecValuesScan                scans a values list.
 *          ExecValuesNext                retrieve next tuple in sequential order.
 *          ExecInitValuesScan            creates and initializes a valuesscan node.
 *          ExecEndValuesScan       releases any storage allocated.
 *          ExecValuesReScan        rescans the values list
 */
#include "postgres.h"

#include "executor/executor.h"
#include "executor/nodeValuesscan.h"
#include "utils/memutils.h"


static TupleTableSlot *ValuesNext(ValuesScanState *node);


/* ----------------------------------------------------------------
 *                                  Scan Support
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
 *          ValuesNext
 *
 *          This is a workhorse for ExecValuesScan
 * ----------------------------------------------------------------
 */
static TupleTableSlot *
ValuesNext(ValuesScanState *node)
{
      TupleTableSlot *slot;
      EState         *estate;
      ExprContext *econtext;
      ScanDirection direction;
      List     *exprlist;

      /*
       * get information from the estate and scan state
       */
      estate = node->ss.ps.state;
      direction = estate->es_direction;
      slot = node->ss.ss_ScanTupleSlot;
      econtext = node->rowcontext;

      /*
       * Get the next tuple. Return NULL if no more tuples.
       */
      if (ScanDirectionIsForward(direction))
      {
            if (node->curr_idx < node->array_len)
                  node->curr_idx++;
            if (node->curr_idx < node->array_len)
                  exprlist = node->exprlists[node->curr_idx];
            else
                  exprlist = NIL;
      }
      else
      {
            if (node->curr_idx >= 0)
                  node->curr_idx--;
            if (node->curr_idx >= 0)
                  exprlist = node->exprlists[node->curr_idx];
            else
                  exprlist = NIL;
      }

      /*
       * Always clear the result slot; this is appropriate if we are at the end
       * of the data, and if we're not, we still need it as the first step of
       * the store-virtual-tuple protocol.  It seems wise to clear the slot
       * before we reset the context it might have pointers into.
       */
      ExecClearTuple(slot);

      if (exprlist)
      {
            MemoryContext oldContext;
            List     *exprstatelist;
            Datum    *values;
            bool     *isnull;
            ListCell   *lc;
            int               resind;

            /*
             * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
             * not just ResetExprContext because we want any registered shutdown
             * callbacks to be called.
             */
            ReScanExprContext(econtext);

            /*
             * Build the expression eval state in the econtext's per-tuple memory.
             * This is a tad unusual, but we want to delete the eval state again
             * when we move to the next row, to avoid growth of memory
             * requirements over a long values list.
             */
            oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);

            /*
             * Pass NULL, not my plan node, because we don't want anything in this
             * transient state linking into permanent state.  The only possibility
             * is a SubPlan, and there shouldn't be any (any subselects in the
             * VALUES list should be InitPlans).
             */
            exprstatelist = (List *) ExecInitExpr((Expr *) exprlist, NULL);

            /* parser should have checked all sublists are the same length */
            Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);

            /*
             * Compute the expressions and build a virtual result tuple. We
             * already did ExecClearTuple(slot).
             */
            values = slot->tts_values;
            isnull = slot->tts_isnull;

            resind = 0;
            foreach(lc, exprstatelist)
            {
                  ExprState  *estate = (ExprState *) lfirst(lc);

                  values[resind] = ExecEvalExpr(estate,
                                                              econtext,
                                                              &isnull[resind],
                                                              NULL);
                  resind++;
            }

            MemoryContextSwitchTo(oldContext);

            /*
             * And return the virtual tuple.
             */
            ExecStoreVirtualTuple(slot);
      }

      return slot;
}


/* ----------------------------------------------------------------
 *          ExecValuesScan(node)
 *
 *          Scans the values lists sequentially and returns the next qualifying
 *          tuple.
 *          It calls the ExecScan() routine and passes it the access method
 *          which retrieves tuples sequentially.
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecValuesScan(ValuesScanState *node)
{
      /*
       * use ValuesNext as access method
       */
      return ExecScan(&node->ss, (ExecScanAccessMtd) ValuesNext);
}

/* ----------------------------------------------------------------
 *          ExecInitValuesScan
 * ----------------------------------------------------------------
 */
ValuesScanState *
ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
{
      ValuesScanState *scanstate;
      TupleDesc   tupdesc;
      ListCell   *vtl;
      int               i;
      PlanState  *planstate;

      /*
       * ValuesScan should not have any children.
       */
      Assert(outerPlan(node) == NULL);
      Assert(innerPlan(node) == NULL);

      /*
       * create new ScanState for node
       */
      scanstate = makeNode(ValuesScanState);
      scanstate->ss.ps.plan = (Plan *) node;
      scanstate->ss.ps.state = estate;

      /*
       * Miscellaneous initialization
       */
      planstate = &scanstate->ss.ps;

      /*
       * Create expression contexts.      We need two, one for per-sublist
       * processing and one for execScan.c to use for quals and projections. We
       * cheat a little by using ExecAssignExprContext() to build both.
       */
      ExecAssignExprContext(estate, planstate);
      scanstate->rowcontext = planstate->ps_ExprContext;
      ExecAssignExprContext(estate, planstate);

#define VALUESSCAN_NSLOTS 2

      /*
       * tuple table initialization
       */
      ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
      ExecInitScanTupleSlot(estate, &scanstate->ss);

      /*
       * initialize child expressions
       */
      scanstate->ss.ps.targetlist = (List *)
            ExecInitExpr((Expr *) node->scan.plan.targetlist,
                               (PlanState *) scanstate);
      scanstate->ss.ps.qual = (List *)
            ExecInitExpr((Expr *) node->scan.plan.qual,
                               (PlanState *) scanstate);

      /*
       * get info about values list
       */
      tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));

      ExecAssignScanType(&scanstate->ss, tupdesc);

      /*
       * Other node-specific setup
       */
      scanstate->marked_idx = -1;
      scanstate->curr_idx = -1;
      scanstate->array_len = list_length(node->values_lists);

      /* convert list of sublists into array of sublists for easy addressing */
      scanstate->exprlists = (List **)
            palloc(scanstate->array_len * sizeof(List *));
      i = 0;
      foreach(vtl, node->values_lists)
      {
            scanstate->exprlists[i++] = (List *) lfirst(vtl);
      }

      scanstate->ss.ps.ps_TupFromTlist = false;

      /*
       * Initialize result tuple type and projection info.
       */
      ExecAssignResultTypeFromTL(&scanstate->ss.ps);
      ExecAssignScanProjectionInfo(&scanstate->ss);

      return scanstate;
}

int
ExecCountSlotsValuesScan(ValuesScan *node)
{
      return ExecCountSlotsNode(outerPlan(node)) +
            ExecCountSlotsNode(innerPlan(node)) +
            VALUESSCAN_NSLOTS;
}

/* ----------------------------------------------------------------
 *          ExecEndValuesScan
 *
 *          frees any storage allocated through C routines.
 * ----------------------------------------------------------------
 */
void
ExecEndValuesScan(ValuesScanState *node)
{
      /*
       * Free both exprcontexts
       */
      ExecFreeExprContext(&node->ss.ps);
      node->ss.ps.ps_ExprContext = node->rowcontext;
      ExecFreeExprContext(&node->ss.ps);

      /*
       * clean out the tuple table
       */
      ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
      ExecClearTuple(node->ss.ss_ScanTupleSlot);
}

/* ----------------------------------------------------------------
 *          ExecValuesMarkPos
 *
 *          Marks scan position.
 * ----------------------------------------------------------------
 */
void
ExecValuesMarkPos(ValuesScanState *node)
{
      node->marked_idx = node->curr_idx;
}

/* ----------------------------------------------------------------
 *          ExecValuesRestrPos
 *
 *          Restores scan position.
 * ----------------------------------------------------------------
 */
void
ExecValuesRestrPos(ValuesScanState *node)
{
      node->curr_idx = node->marked_idx;
}

/* ----------------------------------------------------------------
 *          ExecValuesReScan
 *
 *          Rescans the relation.
 * ----------------------------------------------------------------
 */
void
ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
{
      ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
      node->ss.ps.ps_TupFromTlist = false;

      node->curr_idx = -1;
}

Generated by  Doxygen 1.6.0   Back to index