980e7515创建于 2023年3月13日历史提交
/* -------------------------------------------------------------------------
 *
 * nodeSubqueryscan.cpp
 *	  Support routines for scanning subqueries (subselects in rangetable).
 *
 * This is just enough different from sublinks (nodeSubplan.c) to mean that
 * we need two sets of code.  Ought to look at trying to unify the cases.
 *
 * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/gausskernel/runtime/executor/nodeSubqueryscan.cpp
 *
 * -------------------------------------------------------------------------
 *
 * INTERFACE ROUTINES
 *		ExecSubqueryScan			scans a subquery.
 *		ExecSubqueryNext			retrieve next tuple in sequential order.
 *		ExecInitSubqueryScan		creates and initializes a subqueryscan node.
 *		ExecEndSubqueryScan			releases any storage allocated.
 *		ExecReScanSubqueryScan		rescans the relation
 *
 */
#include "postgres.h"
#include "knl/knl_variable.h"

#include "executor/exec/execdebug.h"
#include "executor/node/nodeSubqueryscan.h"

static TupleTableSlot* ExecSubqueryScan(PlanState* state);
static TupleTableSlot* SubqueryNext(SubqueryScanState* node);

/* ----------------------------------------------------------------
 *						Scan Support
 * ----------------------------------------------------------------
 */
/* ----------------------------------------------------------------
 *		SubqueryNext
 *
 *		This is a workhorse for ExecSubqueryScan
 * ----------------------------------------------------------------
 */
static TupleTableSlot* SubqueryNext(SubqueryScanState* node)
{
    TupleTableSlot* slot = NULL;

    /*
     * Get the next tuple from the sub-query.
     */
    slot = ExecProcNode(node->subplan);

    /*
     * We just return the subplan's result slot, rather than expending extra
     * cycles for ExecCopySlot().  (Our own ScanTupleSlot is used only for
     * EvalPlanQual rechecks.)
     */
    return slot;
}

/*
 * SubqueryRecheck -- access method routine to recheck a tuple in EvalPlanQual
 */
static bool SubqueryRecheck(SubqueryScanState* node, TupleTableSlot* slot)
{
    /* nothing to check */
    return true;
}

/* ----------------------------------------------------------------
 *		ExecSubqueryScan(node)
 *
 *		Scans the subquery sequentially and returns the next qualifying
 *		tuple.
 *		We call the ExecScan() routine and pass it the appropriate
 *		access method functions.
 * ----------------------------------------------------------------
 */
static TupleTableSlot* ExecSubqueryScan(PlanState* state)
{
    SubqueryScanState* node = castNode(SubqueryScanState, state);
    return ExecScan(&node->ss, (ExecScanAccessMtd)SubqueryNext, (ExecScanRecheckMtd)SubqueryRecheck);
}

/* ----------------------------------------------------------------
 *		ExecInitSubqueryScan
 * ----------------------------------------------------------------
 */
SubqueryScanState* ExecInitSubqueryScan(SubqueryScan* node, EState* estate, int eflags)
{
    /* check for unsupported flags */
    Assert(!(eflags & EXEC_FLAG_MARK));

    /* SubqueryScan should not have any "normal" children */
    Assert(outerPlan(node) == NULL);
    Assert(innerPlan(node) == NULL);

    /*
     * create state structure
     */
    SubqueryScanState* sub_query_state = makeNode(SubqueryScanState);
    sub_query_state->ss.ps.plan = (Plan*)node;
    sub_query_state->ss.ps.state = estate;
    sub_query_state->ss.ps.ExecProcNode = ExecSubqueryScan;

    /*
     * Miscellaneous initialization
     *
     * create expression context for node
     */
    ExecAssignExprContext(estate, &sub_query_state->ss.ps);

    /*
     * initialize child expressions
     */
    if (estate->es_is_flt_frame) {
        sub_query_state->ss.ps.qual = (List*)ExecInitQualByFlatten(node->scan.plan.qual, (PlanState*)sub_query_state);
    } else {
        sub_query_state->ss.ps.targetlist = (List*)ExecInitExprByRecursion((Expr*)node->scan.plan.targetlist, (PlanState*)sub_query_state);
        sub_query_state->ss.ps.qual = (List*)ExecInitExprByRecursion((Expr*)node->scan.plan.qual, (PlanState*)sub_query_state);
    }

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

    /*
     * initialize subquery
     */
    sub_query_state->subplan = ExecInitNode(node->subplan, estate, eflags);

    sub_query_state->ss.ps.ps_vec_TupFromTlist = false;

    /*
     * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
     */
    ExecAssignScanType(&sub_query_state->ss, ExecGetResultType(sub_query_state->subplan));

    /*
     * Initialize result tuple type and projection info.
     */
    ExecAssignResultTypeFromTL(
            &sub_query_state->ss.ps,
            sub_query_state->ss.ss_ScanTupleSlot->tts_tupleDescriptor->td_tam_ops);

    ExecAssignScanProjectionInfo(&sub_query_state->ss);

    Assert(sub_query_state->ss.ps.ps_ResultTupleSlot->tts_tupleDescriptor->td_tam_ops);

    return sub_query_state;
}

/* ----------------------------------------------------------------
 *		ExecEndSubqueryScan
 *
 *		frees any storage allocated through C routines.
 * ----------------------------------------------------------------
 */
void ExecEndSubqueryScan(SubqueryScanState* node)
{
    /*
     * Free the exprcontext
     */
    ExecFreeExprContext(&node->ss.ps);

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

    /*
     * close down subquery
     */
    ExecEndNode(node->subplan);
}

/* ----------------------------------------------------------------
 *		ExecReScanSubqueryScan
 *
 *		Rescans the relation.
 * ----------------------------------------------------------------
 */
void ExecReScanSubqueryScan(SubqueryScanState* node)
{
    ExecScanReScan(&node->ss);
    /*
     * ExecReScan doesn't know about my subplan, so I have to do
     * changed-parameter signaling myself.	This is just as well, because the
     * subplan has its own memory context in which its chgParam state lives.
     */
    if (node->ss.ps.chgParam != NULL) {
        UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam);
    }

    /*
     * if chgParam of subnode is not null then plan will be re-scanned by
     * first ExecProcNode.
     */
    if (node->subplan->chgParam == NULL) {
        ExecReScan(node->subplan);
    }
}