/*-------------------------------------------------------------------------
 *
 * cdbpathtoplan.c
 *
 * Portions Copyright (c) 2005-2008, Greenplum inc
 * Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates.
 * 
 *
 * IDENTIFICATION
 *	    src/backend/cdb/cdbpathtoplan.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "cdb/cdbpathlocus.h"
#include "cdb/cdbllize.h"		/* makeFlow() */
#include "cdb/cdbpathtoplan.h"	/* me */
#include "cdb/cdbutil.h"
#include "cdb/cdbvars.h"
#include "nodes/pathnodes.h"

/*
 * cdbpathtoplan_create_flow
 */
Flow *
cdbpathtoplan_create_flow(PlannerInfo *root,
						  CdbPathLocus locus)
{
	Flow	   *flow = NULL;

	/* Distribution */
	if (CdbPathLocus_IsEntry(locus))
	{
		flow = makeFlow(FLOW_SINGLETON, 1);
		flow->segindex = -1;
	}
	else if (CdbPathLocus_IsSingleQE(locus))
	{
		flow = makeFlow(FLOW_SINGLETON, locus.numsegments);
		flow->segindex = 0;
	}
	else if (CdbPathLocus_IsGeneral(locus))
	{
		if (Gp_role == GP_ROLE_DISPATCH)
			flow = makeFlow(FLOW_SINGLETON, getgpsegmentCount());
		else
			flow = makeFlow(FLOW_SINGLETON, 1); /* dummy flow */
		flow->segindex = 0;
	}
	else if (CdbPathLocus_IsSegmentGeneral(locus))
	{
		flow = makeFlow(FLOW_SINGLETON, locus.numsegments);
		flow->segindex = 0;
	}
	else if (CdbPathLocus_IsSegmentGeneralWorkers(locus))
	{
		flow = makeFlow(FLOW_SINGLETON, locus.numsegments);
		flow->segindex = 0;
	}
	else if (CdbPathLocus_IsReplicated(locus))
	{
		/* CBDB_PARALLEL_FIXME: What if ReplicatedWorkers? */
		flow = makeFlow(FLOW_REPLICATED, locus.numsegments);
	}
	else if (CdbPathLocus_IsHashed(locus) ||
			 CdbPathLocus_IsHashedWorkers(locus) ||
			 CdbPathLocus_IsHashedOJ(locus))
	{
		flow = makeFlow(FLOW_PARTITIONED, locus.numsegments);

		/*
		 * hashExpr can be NIL if the rel is partitioned on columns that
		 * aren't projected (i.e. are not present in the result of this Path
		 * operator).
		 */
	}
	else if (CdbPathLocus_IsStrewn(locus))
		flow = makeFlow(FLOW_PARTITIONED, locus.numsegments);
	else if (CdbPathLocus_IsOuterQuery(locus))
	{
		/*
		 * A plan that's attached to the outer query later on will run on
		 * the same segments as the outer query. We don't know what the
		 * locus of the outer query is yet, so just mark the plan with a
		 * dummy Flow. It's good enough for the rest of the planner.
		 */
		flow = makeFlow(FLOW_SINGLETON, 1);
	}
	else
		elog(ERROR, "incorrect locus type %d to create flow", locus.locustype);

	flow->locustype = locus.locustype;
	return flow;
}								/* cdbpathtoplan_create_flow */
