blob: b2db4b7b0a725ee122a681165b985a7779bc9df1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*-------------------------------------------------------------------------
*
* nodeSubqueryscan.c
* 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) 2006-2008, Greenplum inc
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.32.2.2 2006/12/26 21:37:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* 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.
* ExecSubqueryReScan rescans the relation
*
*/
#include "postgres.h"
#include "cdb/cdbvars.h"
#include "executor/execdebug.h"
#include "executor/nodeSubqueryscan.h"
#include "optimizer/var.h" /* CDB: contain_var_reference() */
#include "parser/parsetree.h"
static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
/* ----------------------------------------------------------------
* Scan Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* SubqueryNext
*
* This is a workhorse for ExecSubqueryScan
* ----------------------------------------------------------------
*/
static TupleTableSlot *
SubqueryNext(SubqueryScanState *node)
{
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
/*
* get information from the estate and scan state
*/
estate = node->ss.ps.state;
direction = estate->es_direction;
/*
* We need not support EvalPlanQual here, since we are not scanning a real
* relation.
*/
/*
* Get the next tuple from the sub-query.
*/
node->sss_SubEState->es_direction = direction;
slot = ExecProcNode(node->subplan);
/*
* We just overwrite our ScanTupleSlot with the subplan's result slot,
* rather than expending the cycles for ExecCopySlot().
*/
node->ss.ss_ScanTupleSlot = slot;
/*
* CDB: Label each row with a synthetic ctid if needed for subquery dedup.
*/
if (node->cdb_want_ctid &&
!TupIsNull(slot))
{
slot_set_ctid_from_fake(slot, &node->cdb_fake_ctid);
}
if (!TupIsNull(slot))
{
Gpmon_M_Incr_Rows_Out(GpmonPktFromSubqueryScanState(node));
CheckSendPlanStateGpmonPkt(&node->ss.ps);
}
return slot;
}
/* ----------------------------------------------------------------
* ExecSubqueryScan(node)
*
* Scans the subquery sequentially and returns the next qualifying
* tuple.
* It calls the ExecScan() routine and passes it the access method
* which retrieve tuples sequentially.
*
*/
TupleTableSlot *
ExecSubqueryScan(SubqueryScanState *node)
{
/*
* use SubqueryNext as access method
*/
return ExecScan(&node->ss, (ExecScanAccessMtd) SubqueryNext);
}
/* ----------------------------------------------------------------
* ExecInitSubqueryScan
* ----------------------------------------------------------------
*/
SubqueryScanState *
ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
{
SubqueryScanState *subquerystate;
EState *sp_estate;
/* check for unsupported flags */
Assert(!(eflags & EXEC_FLAG_MARK));
/*
* SubqueryScan should not have any "normal" children. Also, if planner
* left anything in subrtable, it's fishy.
*/
Assert(outerPlan(node) == NULL);
Assert(innerPlan(node) == NULL);
Assert(node->subrtable == NIL);
/*
* Since subquery nodes create its own executor state,
* and pass it down to its child nodes, we always
* initialize the subquery node. However, some
* fields are not initialized if not necessary, see
* below.
*/
/*
* create state structure
*/
subquerystate = makeNode(SubqueryScanState);
subquerystate->ss.ps.plan = (Plan *) node;
subquerystate->ss.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &subquerystate->ss.ps);
/*
* initialize child expressions
*/
subquerystate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) subquerystate);
subquerystate->ss.ps.qual = (List *)
ExecInitExpr((Expr *) node->scan.plan.qual,
(PlanState *) subquerystate);
/* Check if targetlist or qual contains a var node referencing the ctid column */
subquerystate->cdb_want_ctid = contain_ctid_var_reference(&node->scan);
ItemPointerSetInvalid(&subquerystate->cdb_fake_ctid);
#define SUBQUERYSCAN_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
ExecInitScanTupleSlot(estate, &subquerystate->ss);
/*
* initialize subquery
*
* This should agree with ExecInitSubPlan
*
* The subquery needs its own EState because it has its own rangetable. It
* shares our Param ID space and es_query_cxt, however. XXX if rangetable
* access were done differently, the subquery could share our EState,
* which would eliminate some thrashing about in this module...
*/
sp_estate = CreateSubExecutorState(estate);
subquerystate->sss_SubEState = sp_estate;
sp_estate->es_range_table = estate->es_range_table;
sp_estate->es_param_list_info = estate->es_param_list_info;
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
sp_estate->es_instrument = estate->es_instrument;
sp_estate->es_plannedstmt = estate->es_plannedstmt;
/*
* "Loan" the global slice table and map to the subplan EState. The
* global state is already set up by the code that called us.
*/
sp_estate->es_sliceTable = estate->es_sliceTable;
sp_estate->currentSliceIdInPlan = estate->currentSliceIdInPlan;
sp_estate->currentExecutingSliceId = estate->currentExecutingSliceId;
sp_estate->rootSliceId = estate->currentExecutingSliceId;
/*
* also load shared nodes list
*/
sp_estate->es_sharenode = estate->es_sharenode;
/*
* also loan the motion later state and interconnect state
*/
sp_estate->motionlayer_context = estate->motionlayer_context;
sp_estate->interconnect_context = estate->interconnect_context;
/*
* Start up the subplan (this is a very cut-down form of InitPlan())
*/
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate, eflags);
/* return borrowed share node list */
estate->es_sharenode = sp_estate->es_sharenode;
/*
* Initialize scan tuple type (needed by ExecAssignScanProjectionInfo).
* Because the subplan is in its own memory context, we need to copy its
* result tuple type not just link to it; else the tupdesc will disappear
* too soon during shutdown.
*/
ExecAssignScanType(&subquerystate->ss,
CreateTupleDescCopy(ExecGetResultType(subquerystate->subplan)));
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
ExecAssignScanProjectionInfo(&subquerystate->ss);
initGpmonPktForSubqueryScan((Plan *)node, &subquerystate->ss.ps.gpmon_pkt, estate);
return subquerystate;
}
int
ExecCountSlotsSubqueryScan(SubqueryScan *node)
{
/*
* The subplan has its own tuple table and must not be counted here!
*/
return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
SUBQUERYSCAN_NSLOTS;
}
/* ----------------------------------------------------------------
* 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
*/
if (node->ss.ss_ScanTupleSlot != NULL)
{
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
node->ss.ss_ScanTupleSlot = NULL; /* not ours to clear */
}
/* gpmon */
EndPlanStateGpmonPkt(&node->ss.ps);
/*
* close down subquery
*/
ExecEndPlan(node->subplan, node->sss_SubEState);
FreeExecutorState(node->sss_SubEState);
}
/* ----------------------------------------------------------------
* ExecSubqueryReScan
*
* Rescans the relation.
* ----------------------------------------------------------------
*/
void
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
{
EState *estate;
estate = node->ss.ps.state;
ItemPointerSet(&node->cdb_fake_ctid, 0, 0);
/*
* 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, NULL);
node->ss.ss_ScanTupleSlot = NULL;
/*node->ss.ps.ps_TupFromTlist = false;*/
Gpmon_M_Incr(GpmonPktFromSubqueryScanState(node), GPMON_SUBQUERYSCAN_RESCAN);
CheckSendPlanStateGpmonPkt(&node->ss.ps);
}
void
initGpmonPktForSubqueryScan(Plan *planNode, gpmon_packet_t *gpmon_pkt, EState *estate)
{
RangeTblEntry *rte;
Assert(planNode != NULL && gpmon_pkt != NULL && IsA(planNode, SubqueryScan));
rte = rt_fetch(((SubqueryScan *)planNode)->scan.scanrelid, estate->es_range_table);
if (rte && rte->rtekind != RTE_VOID)
{
InitPlanNodeGpmonPkt(planNode, gpmon_pkt, estate, PMNT_SubqueryScan,
(int64)planNode->plan_rows,
rte->eref->aliasname);
}
}