/*
 * setPidIndex
 *   Set the hash table of Oids to scan.
 */
static void
setPidIndex(DynamicIndexScanState *node)
{
	Assert(node->pidxIndex == NULL);
	
	IndexScanState *indexState = (IndexScanState *)node;
	EState *estate = indexState->ss.ps.state;
	DynamicIndexScan *plan = (DynamicIndexScan *)indexState->ss.ps.plan;
	Assert(estate->dynamicTableScanInfo != NULL);
	/*
	 * Ensure that the dynahash exists even if the partition selector
	 * didn't choose any partition for current scan node [MPP-24169].
	 */
	InsertPidIntoDynamicTableScanInfo(plan->scan.partIndex, InvalidOid, InvalidPartitionSelectorId);

	Assert(NULL != estate->dynamicTableScanInfo->pidIndexes);
	Assert(estate->dynamicTableScanInfo->numScans >= plan->scan.partIndex);
	node->pidxIndex = estate->dynamicTableScanInfo->pidIndexes[plan->scan.partIndex - 1];
	Assert(node->pidxIndex != NULL);

	if (optimizer_partition_selection_log)
	{
		LogSelectedPartitionOids(node->pidxIndex);
	}
}
Example #2
0
/*
 * DynamicScan_CreateIterator
 * 		Creates an iterator state (i.e., DynamicPartitionIterator)
 * 		and saves it to the estate's DynamicTableScanInfo.
 */
static void
DynamicScan_CreateIterator(ScanState *scanState, Scan *scan)
{
	EState *estate = scanState->ps.state;
	Assert(NULL != estate);
	DynamicTableScanInfo *partitionInfo = estate->dynamicTableScanInfo;

	/*
	 * Ensure that the dynahash exists even if the partition selector
	 * didn't choose any partition for current scan node [MPP-24169].
	 */
	InsertPidIntoDynamicTableScanInfo(scan->partIndex, InvalidOid, InvalidPartitionSelectorId);

	Assert(NULL != partitionInfo && NULL != partitionInfo->pidIndexes);
	Assert(partitionInfo->numScans >= scan->partIndex);
	Assert(NULL == partitionInfo->iterators[scan->partIndex - 1]);

	DynamicPartitionIterator *iterator = palloc(sizeof(DynamicPartitionIterator));
	iterator->curRelOid = InvalidOid;
	iterator->partitionMemoryContext = AllocSetContextCreate(CurrentMemoryContext,
			 "DynamicTableScanPerPartition",
			 ALLOCSET_DEFAULT_MINSIZE,
			 ALLOCSET_DEFAULT_INITSIZE,
			 ALLOCSET_DEFAULT_MAXSIZE);
	iterator->partitionOids = partitionInfo->pidIndexes[scan->partIndex - 1];
	Assert(iterator->partitionOids != NULL);
	iterator->shouldCallHashSeqTerm = true;

	HASH_SEQ_STATUS *partitionIterator = palloc(sizeof(HASH_SEQ_STATUS));
	hash_seq_init(partitionIterator, iterator->partitionOids);

	iterator->partitionIterator = partitionIterator;

	partitionInfo->iterators[scan->partIndex - 1] = iterator;
}
/*
 * gp_partition_propagation
 *    Insert a partition oid into its pid-index.
 */
Datum
gp_partition_propagation(PG_FUNCTION_ARGS)
{
	int32 index = PG_GETARG_INT32(0);
	Oid partOid = PG_GETARG_OID(1);

	InsertPidIntoDynamicTableScanInfo(index, partOid, InvalidPartitionSelectorId);

	PG_RETURN_VOID();
}
/* ----------------------------------------------------------------
 *		ExecPartitionSelector(node)
 *
 *		Compute and propagate partition table Oids that will be
 *		used by Dynamic table scan. There are two ways of
 *		executing PartitionSelector.
 *
 *		1. Constant partition elimination
 *		Plan structure:
 *			Sequence
 *				|--PartitionSelector
 *				|--DynamicTableScan
 *		In this case, PartitionSelector evaluates constant partition
 *		constraints to compute and propagate partition table Oids.
 *		It only need to be called once.
 *
 *		2. Join partition elimination
 *		Plan structure:
 *			...:
 *				|--DynamicTableScan
 *				|--...
 *					|--PartitionSelector
 *						|--...
 *		In this case, PartitionSelector is in the same slice as
 *		DynamicTableScan, DynamicIndexScan or DynamicBitmapHeapScan.
 *		It is executed for each tuple coming from its child node.
 *		It evaluates partition constraints with the input tuple and
 *		propagate matched partition table Oids.
 *
 *
 * Instead of a Dynamic Table Scan, there can be other nodes that use
 * a PartSelected qual to filter rows, based on which partitions are
 * selected. Currently, ORCA uses Dynamic Table Scans, while plans
 * produced by the non-ORCA planner use gating Result nodes with
 * PartSelected quals, to exclude unwanted partitions.
 *
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecPartitionSelector(PartitionSelectorState *node)
{
	PartitionSelector *ps = (PartitionSelector *) node->ps.plan;
	EState	   *estate = node->ps.state;
	ExprContext *econtext = node->ps.ps_ExprContext;
	TupleTableSlot *inputSlot = NULL;
	TupleTableSlot *candidateOutputSlot = NULL;

	if (ps->staticSelection)
	{
		/* propagate the part oids obtained via static partition selection */
		partition_propagation(estate, ps->staticPartOids, ps->staticScanIds, ps->selectorId);
		return NULL;
	}

	/* Retrieve PartitionNode and access method from root table.
	 * We cannot do it during node initialization as
	 * DynamicTableScanInfo is not properly initialized yet.
	 */
	if (NULL == node->rootPartitionNode)
	{
		Assert(NULL != estate->dynamicTableScanInfo);
		getPartitionNodeAndAccessMethod
									(
									ps->relid,
									estate->dynamicTableScanInfo->partsMetadata,
									estate->es_query_cxt,
									&node->rootPartitionNode,
									&node->accessMethods
									);
	}

	if (NULL != outerPlanState(node))
	{
		/* Join partition elimination */
		/* get tuple from outer children */
		PlanState *outerPlan = outerPlanState(node);
		Assert(outerPlan);
		inputSlot = ExecProcNode(outerPlan);

		if (TupIsNull(inputSlot))
		{
			/* no more tuples from outerPlan */

			/*
			 * Make sure we have an entry for this scan id in
			 * dynamicTableScanInfo. Normally, this would've been done the
			 * first time a partition is selected, but we must ensure that
			 * there is an entry even if no partitions were selected.
			 * (The traditional Postgres planner uses this method.)
			 */
			if (ps->partTabTargetlist)
				InsertPidIntoDynamicTableScanInfo(estate, ps->scanId, InvalidOid, ps->selectorId);
			else
				LogPartitionSelection(estate, ps->selectorId);

			return NULL;
		}
	}

	/* partition elimination with the given input tuple */
	ResetExprContext(econtext);
	node->ps.ps_OuterTupleSlot = inputSlot;
	econtext->ecxt_outertuple = inputSlot;
	econtext->ecxt_scantuple = inputSlot;

	if (NULL != inputSlot)
	{
		candidateOutputSlot = ExecProject(node->ps.ps_ProjInfo, NULL);
	}

	/*
	 * If we have a partitioning projection, project the input tuple
	 * into a tuple that looks like tuples from the partitioned table, and use
	 * selectPartitionMulti() to select the partitions. (The traditional
	 * Postgres planner uses this method.)
	 */
	if (ps->partTabTargetlist)
	{
		TupleTableSlot *slot;
		List	   *oids;
		ListCell   *lc;

		slot = ExecProject(node->partTabProj, NULL);
		slot_getallattrs(slot);

		oids = selectPartitionMulti(node->rootPartitionNode,
									slot_get_values(slot),
									slot_get_isnull(slot),
									slot->tts_tupleDescriptor,
									node->accessMethods);
		foreach (lc, oids)
		{
			InsertPidIntoDynamicTableScanInfo(estate, ps->scanId, lfirst_oid(lc), ps->selectorId);
		}