blob: b33f547338003e2f5e5aaf1728def316105d203d [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.
*/
/*-------------------------------------------------------------------------
*
* nodeRepeat.c
* Repeatly output each result tuple in the subplan with some defined number
* of counts.
*
* DESCRIPTION
*
* Repeat nodes are used when input tuples need to be outputted several
* times. Different input tuple can be repeated different times.
*
* For example, it is useful in grouping extension queries where the query
* contain duplicate grouping sets.
*
* IDENTIFICATION:
* $Id$
*
* $File$
* $Change$
* $Author$
* $DateTime$
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "cdb/cdbvars.h"
#include "executor/executor.h"
#include "executor/nodeRepeat.h"
#include "parser/parsetree.h"
static void init_RepeatState(RepeatState *repeatstate);
/*
* Repeatly output each tuple received from the outer plan with some
* defined number of times. The number of times to output a tuple is
* determined by the value of a given column in the received tuple.
*
* Note that the Repeat node also have the functionality to evaluate
* the GroupingFunc.
*/
TupleTableSlot *
ExecRepeat(RepeatState *repeatstate)
{
TupleTableSlot *outerslot;
ExprContext *econtext = repeatstate->ps.ps_ExprContext;
Repeat *node = (Repeat *)repeatstate->ps.plan;
if (repeatstate->repeat_done)
return NULL;
/*
* If the previous tuple still needs to be outputted,
* output it here.
*/
if (repeatstate->slot != NULL)
{
if (repeatstate->repeat_count > 0)
{
/* Output the previous tuple */
econtext->ecxt_outertuple = repeatstate->slot;
econtext->ecxt_scantuple = repeatstate->slot;
do
{
econtext->group_id = repeatstate->repeat_count - 1;
econtext->grouping = node->grouping;
repeatstate->repeat_count--;
/* Check the qual until we find one output tuple. */
if (ExecQual(repeatstate->ps.qual, econtext, false))
{
Gpmon_M_Incr_Rows_Out(GpmonPktFromRepeatState(repeatstate));
CheckSendPlanStateGpmonPkt(&repeatstate->ps);
return ExecProject(repeatstate->ps.ps_ProjInfo, NULL);
}
} while (repeatstate->repeat_count > 0);
}
else
repeatstate->slot = NULL;
}
ResetExprContext(econtext);
while (!repeatstate->repeat_done)
{
MemoryContext oldcxt;
bool isNull = false;
outerslot = ExecProcNode(outerPlanState(repeatstate));
if (TupIsNull(outerslot))
{
repeatstate->repeat_done = true;
return NULL;
}
econtext->ecxt_outertuple = outerslot;
econtext->ecxt_scantuple = outerslot;
/* Compute the number of times to output this tuple. */
oldcxt = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
repeatstate->repeat_count =
DatumGetInt32(ExecEvalExpr(repeatstate->expr_state, econtext,
&isNull, NULL));
Assert(!isNull);
MemoryContextSwitchTo(oldcxt);
if (repeatstate->repeat_count == 0)
continue;
if (repeatstate->repeat_count > 1)
repeatstate->slot = outerslot;
do
{
econtext->group_id = repeatstate->repeat_count - 1;
econtext->grouping = node->grouping;
repeatstate->repeat_count--;
/* Check the qual until we find one output tuple. */
if (ExecQual(repeatstate->ps.qual, econtext, false))
{
Gpmon_M_Incr_Rows_Out(GpmonPktFromRepeatState(repeatstate));
CheckSendPlanStateGpmonPkt(&repeatstate->ps);
return ExecProject(repeatstate->ps.ps_ProjInfo, NULL);
}
} while (repeatstate->repeat_count > 0);
}
return NULL;
}
RepeatState *
ExecInitRepeat(Repeat *node, EState *estate, int eflags)
{
RepeatState *repeatstate;
/* Check for unsupported flag */
Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)) ||
outerPlan(node) != NULL);
/*
* Create state structure.
*/
repeatstate = makeNode(RepeatState);
repeatstate->ps.plan = (Plan *)node;
repeatstate->ps.state = estate;
/* Create expression context for the node. */
ExecAssignExprContext(estate, &repeatstate->ps);
ExecInitResultTupleSlot(estate, &repeatstate->ps);
/* Initialize child expressions */
repeatstate->ps.targetlist = (List *)
ExecInitExpr((Expr *)node->plan.targetlist,
(PlanState *)repeatstate);
repeatstate->ps.qual = (List *)
ExecInitExpr((Expr *)node->plan.qual,
(PlanState *)repeatstate);
repeatstate->expr_state =
ExecInitExpr(node->repeatCountExpr,
(PlanState *)repeatstate);
/* Initialize child nodes */
outerPlanState(repeatstate) = ExecInitNode(outerPlan(node), estate, eflags);
/* Inner plan is not used. */
Assert(innerPlan(node) == NULL);
/* Initialize tuple type and projection info */
ExecAssignResultTypeFromTL(&repeatstate->ps);
ExecAssignProjectionInfo(&repeatstate->ps, NULL);
init_RepeatState(repeatstate);
initGpmonPktForRepeat((Plan *)node, &repeatstate->ps.gpmon_pkt, estate);
return repeatstate;
}
int
ExecCountSlotsRepeat(Repeat *node)
{
return ExecCountSlotsNode(outerPlan(node)) + 1;
}
void
ExecEndRepeat(RepeatState *node)
{
/* Free the ExprContext */
ExecFreeExprContext(&node->ps);
/* Clean out the tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
/* End the subplans */
ExecEndNode(outerPlanState(node));
EndPlanStateGpmonPkt(&node->ps);
}
void
ExecReScanRepeat(RepeatState *node, ExprContext *exprCtxt)
{
/* Clean out the tuple table */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
init_RepeatState(node);
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
*/
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}
/*
* init_RepeatState() -- initialize the RepeatState.
*/
static void
init_RepeatState(RepeatState *repeatstate)
{
repeatstate->repeat_done = false;
repeatstate->slot = NULL;
repeatstate->repeat_count = 0;
}
void
initGpmonPktForRepeat(Plan *planNode, gpmon_packet_t *gpmon_pkt, EState *estate)
{
Assert(planNode != NULL && gpmon_pkt != NULL && IsA(planNode, Repeat));
{
Assert(GPMON_REPEAT_TOTAL <= (int)GPMON_QEXEC_M_COUNT);
InitPlanNodeGpmonPkt(planNode, gpmon_pkt, estate, PMNT_Repeat,
(int64) planNode->plan_rows, NULL);
}
}