Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

nodeRecursiveunion.h File Reference

#include "nodes/execnodes.h"
Include dependency graph for nodeRecursiveunion.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

RecursiveUnionStateExecInitRecursiveUnion (RecursiveUnion *node, EState *estate, int eflags)
TupleTableSlotExecRecursiveUnion (RecursiveUnionState *node)
void ExecEndRecursiveUnion (RecursiveUnionState *node)
void ExecReScanRecursiveUnion (RecursiveUnionState *node)

Function Documentation

void ExecEndRecursiveUnion ( RecursiveUnionState node  ) 
RecursiveUnionState* ExecInitRecursiveUnion ( RecursiveUnion node,
EState estate,
int  eflags 
)

Definition at line 165 of file nodeRecursiveunion.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, build_hash_table(), CurrentMemoryContext, RecursiveUnion::dupOperators, RecursiveUnionState::eqfunctions, EState::es_param_exec_vals, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignResultTypeFromTL(), ExecInitNode(), ExecInitResultTupleSlot(), ParamExecData::execPlan, execTuplesHashPrepare(), RecursiveUnionState::hashfunctions, RecursiveUnionState::hashtable, innerPlan, innerPlanState, RecursiveUnionState::intermediate_empty, RecursiveUnionState::intermediate_table, ParamExecData::isnull, makeNode, NIL, NULL, RecursiveUnion::numCols, outerPlan, outerPlanState, RecursiveUnion::plan, PlanState::plan, PointerGetDatum, RecursiveUnionState::ps, PlanState::ps_ProjInfo, Plan::qual, RecursiveUnionState::recursing, PlanState::state, RecursiveUnionState::tableContext, RecursiveUnionState::tempContext, tuplestore_begin_heap(), ParamExecData::value, work_mem, RecursiveUnionState::working_table, and RecursiveUnion::wtParam.

Referenced by ExecInitNode().

{
    RecursiveUnionState *rustate;
    ParamExecData *prmdata;

    /* check for unsupported flags */
    Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));

    /*
     * create state structure
     */
    rustate = makeNode(RecursiveUnionState);
    rustate->ps.plan = (Plan *) node;
    rustate->ps.state = estate;

    rustate->eqfunctions = NULL;
    rustate->hashfunctions = NULL;
    rustate->hashtable = NULL;
    rustate->tempContext = NULL;
    rustate->tableContext = NULL;

    /* initialize processing state */
    rustate->recursing = false;
    rustate->intermediate_empty = true;
    rustate->working_table = tuplestore_begin_heap(false, false, work_mem);
    rustate->intermediate_table = tuplestore_begin_heap(false, false, work_mem);

    /*
     * If hashing, we need a per-tuple memory context for comparisons, and a
     * longer-lived context to store the hash table.  The table can't just be
     * kept in the per-query context because we want to be able to throw it
     * away when rescanning.
     */
    if (node->numCols > 0)
    {
        rustate->tempContext =
            AllocSetContextCreate(CurrentMemoryContext,
                                  "RecursiveUnion",
                                  ALLOCSET_DEFAULT_MINSIZE,
                                  ALLOCSET_DEFAULT_INITSIZE,
                                  ALLOCSET_DEFAULT_MAXSIZE);
        rustate->tableContext =
            AllocSetContextCreate(CurrentMemoryContext,
                                  "RecursiveUnion hash table",
                                  ALLOCSET_DEFAULT_MINSIZE,
                                  ALLOCSET_DEFAULT_INITSIZE,
                                  ALLOCSET_DEFAULT_MAXSIZE);
    }

    /*
     * Make the state structure available to descendant WorkTableScan nodes
     * via the Param slot reserved for it.
     */
    prmdata = &(estate->es_param_exec_vals[node->wtParam]);
    Assert(prmdata->execPlan == NULL);
    prmdata->value = PointerGetDatum(rustate);
    prmdata->isnull = false;

    /*
     * Miscellaneous initialization
     *
     * RecursiveUnion plans don't have expression contexts because they never
     * call ExecQual or ExecProject.
     */
    Assert(node->plan.qual == NIL);

    /*
     * RecursiveUnion nodes still have Result slots, which hold pointers to
     * tuples, so we have to initialize them.
     */
    ExecInitResultTupleSlot(estate, &rustate->ps);

    /*
     * Initialize result tuple type and projection info.  (Note: we have to
     * set up the result type before initializing child nodes, because
     * nodeWorktablescan.c expects it to be valid.)
     */
    ExecAssignResultTypeFromTL(&rustate->ps);
    rustate->ps.ps_ProjInfo = NULL;

    /*
     * initialize child nodes
     */
    outerPlanState(rustate) = ExecInitNode(outerPlan(node), estate, eflags);
    innerPlanState(rustate) = ExecInitNode(innerPlan(node), estate, eflags);

    /*
     * If hashing, precompute fmgr lookup data for inner loop, and create the
     * hash table.
     */
    if (node->numCols > 0)
    {
        execTuplesHashPrepare(node->numCols,
                              node->dupOperators,
                              &rustate->eqfunctions,
                              &rustate->hashfunctions);
        build_hash_table(rustate);
    }

    return rustate;
}

TupleTableSlot* ExecRecursiveUnion ( RecursiveUnionState node  ) 

Definition at line 76 of file nodeRecursiveunion.c.

References bms_add_member(), PlanState::chgParam, ExecProcNode(), RecursiveUnionState::hashtable, innerPlan, innerPlanState, RecursiveUnionState::intermediate_empty, RecursiveUnionState::intermediate_table, LookupTupleHashEntry(), MemoryContextReset(), RecursiveUnion::numCols, outerPlan, outerPlanState, PlanState::plan, RecursiveUnionState::ps, RecursiveUnionState::recursing, RecursiveUnionState::tempContext, TupIsNull, tuplestore_begin_heap(), tuplestore_end(), tuplestore_puttupleslot(), work_mem, RecursiveUnionState::working_table, and RecursiveUnion::wtParam.

Referenced by ExecProcNode().

{
    PlanState  *outerPlan = outerPlanState(node);
    PlanState  *innerPlan = innerPlanState(node);
    RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;
    TupleTableSlot *slot;
    bool        isnew;

    /* 1. Evaluate non-recursive term */
    if (!node->recursing)
    {
        for (;;)
        {
            slot = ExecProcNode(outerPlan);
            if (TupIsNull(slot))
                break;
            if (plan->numCols > 0)
            {
                /* Find or build hashtable entry for this tuple's group */
                LookupTupleHashEntry(node->hashtable, slot, &isnew);
                /* Must reset temp context after each hashtable lookup */
                MemoryContextReset(node->tempContext);
                /* Ignore tuple if already seen */
                if (!isnew)
                    continue;
            }
            /* Each non-duplicate tuple goes to the working table ... */
            tuplestore_puttupleslot(node->working_table, slot);
            /* ... and to the caller */
            return slot;
        }
        node->recursing = true;
    }

    /* 2. Execute recursive term */
    for (;;)
    {
        slot = ExecProcNode(innerPlan);
        if (TupIsNull(slot))
        {
            /* Done if there's nothing in the intermediate table */
            if (node->intermediate_empty)
                break;

            /* done with old working table ... */
            tuplestore_end(node->working_table);

            /* intermediate table becomes working table */
            node->working_table = node->intermediate_table;

            /* create new empty intermediate table */
            node->intermediate_table = tuplestore_begin_heap(false, false,
                                                             work_mem);
            node->intermediate_empty = true;

            /* reset the recursive term */
            innerPlan->chgParam = bms_add_member(innerPlan->chgParam,
                                                 plan->wtParam);

            /* and continue fetching from recursive term */
            continue;
        }

        if (plan->numCols > 0)
        {
            /* Find or build hashtable entry for this tuple's group */
            LookupTupleHashEntry(node->hashtable, slot, &isnew);
            /* Must reset temp context after each hashtable lookup */
            MemoryContextReset(node->tempContext);
            /* Ignore tuple if already seen */
            if (!isnew)
                continue;
        }

        /* Else, tuple is good; stash it in intermediate table ... */
        node->intermediate_empty = false;
        tuplestore_puttupleslot(node->intermediate_table, slot);
        /* ... and return it */
        return slot;
    }

    return NULL;
}

void ExecReScanRecursiveUnion ( RecursiveUnionState node  ) 

Definition at line 305 of file nodeRecursiveunion.c.

References bms_add_member(), build_hash_table(), PlanState::chgParam, ExecReScan(), innerPlan, innerPlanState, RecursiveUnionState::intermediate_empty, RecursiveUnionState::intermediate_table, MemoryContextResetAndDeleteChildren(), NULL, RecursiveUnion::numCols, outerPlan, outerPlanState, PlanState::plan, RecursiveUnionState::ps, RecursiveUnionState::recursing, RecursiveUnionState::tableContext, tuplestore_clear(), RecursiveUnionState::working_table, and RecursiveUnion::wtParam.

Referenced by ExecReScan().

{
    PlanState  *outerPlan = outerPlanState(node);
    PlanState  *innerPlan = innerPlanState(node);
    RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;

    /*
     * Set recursive term's chgParam to tell it that we'll modify the working
     * table and therefore it has to rescan.
     */
    innerPlan->chgParam = bms_add_member(innerPlan->chgParam, plan->wtParam);

    /*
     * if chgParam of subnode is not null then plan will be re-scanned by
     * first ExecProcNode.  Because of above, we only have to do this to the
     * non-recursive term.
     */
    if (outerPlan->chgParam == NULL)
        ExecReScan(outerPlan);

    /* Release any hashtable storage */
    if (node->tableContext)
        MemoryContextResetAndDeleteChildren(node->tableContext);

    /* And rebuild empty hashtable if needed */
    if (plan->numCols > 0)
        build_hash_table(node);

    /* reset processing state */
    node->recursing = false;
    node->intermediate_empty = true;
    tuplestore_clear(node->working_table);
    tuplestore_clear(node->intermediate_table);
}