You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudberry.apache.org by ma...@apache.org on 2024/12/24 08:13:28 UTC

(cloudberry) 03/11: Adds Orca support for Dynamic Table Scan

This is an automated email from the ASF dual-hosted git repository.

maxyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit ef95449dba27cea8c81069f5e888c53ec1f4101b
Author: Chris Hajas <ch...@vmware.com>
AuthorDate: Mon May 23 14:47:03 2022 -0700

    Adds Orca support for Dynamic Table Scan
---
 src/backend/executor/execDynamicScan.c             | 158 ---------------------
 src/backend/executor/nodeDynamicSeqscan.c          | 148 ++++++++-----------
 .../gpopt/translate/CTranslatorDXLToPlStmt.cpp     |  33 ++++-
 .../src/translate/CTranslatorExprToDXL.cpp         | 154 +++-----------------
 .../dxl/operators/CDXLPhysicalDynamicTableScan.h   |  21 ++-
 .../dxl/parser/CParseHandlerDynamicTableScan.h     |   6 +-
 .../src/operators/CDXLPhysicalDynamicTableScan.cpp |  57 +++-----
 .../src/parser/CParseHandlerDynamicTableScan.cpp   |  30 ++--
 src/include/executor/execDynamicScan.h             |  28 ----
 9 files changed, 163 insertions(+), 472 deletions(-)

diff --git a/src/backend/executor/execDynamicScan.c b/src/backend/executor/execDynamicScan.c
deleted file mode 100644
index d0496f2e50..0000000000
--- a/src/backend/executor/execDynamicScan.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * execDynamicScan.c
- *	  Support routines for iterating through dynamically chosen partitions of a relation
- *
- * Portions Copyright (c) 2014-Present VMware, Inc. or its affiliates.
- *
- *
- * IDENTIFICATION
- *	    src/backend/executor/execDynamicScan.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "cdb/partitionselection.h"
-#include "executor/executor.h"
-#include "executor/execDynamicScan.h"
-#include "parser/parsetree.h"
-
-/*
- * isDynamicScan
- * 		Returns true if the scan node is dynamic (i.e., determining
- * 		relations to scan at runtime).
- */
-bool
-isDynamicScan(const Plan *plan)
-{
-	switch (nodeTag(plan))
-	{
-		case T_DynamicSeqScan:
-		case T_DynamicIndexScan:
-		case T_DynamicBitmapHeapScan:
-		case T_DynamicBitmapIndexScan:
-			return true;
-
-		default:
-			return false;
-	}
-}
-
-/*
- * DynamicScan_GetDynamicScanId
- *		Returns the index into EState->dynamicTableScanInfo arrays for this
- *      dynamic scan node.
- */
-static int
-DynamicScan_GetDynamicScanId(Plan *plan)
-{
-	switch (nodeTag(plan))
-	{
-		case T_DynamicSeqScan:
-			return ((DynamicSeqScan *) plan)->partIndex;
-
-		case T_DynamicIndexScan:
-			return ((DynamicIndexScan *) plan)->partIndex;
-
-		case T_DynamicBitmapHeapScan:
-			return ((DynamicBitmapHeapScan *) plan)->partIndex;
-
-		case T_DynamicBitmapIndexScan:
-			return ((DynamicBitmapIndexScan *) plan)->partIndex;
-
-		default:
-			elog(ERROR, "unknown dynamic scan node type %u", nodeTag(plan));
-	}
-}
-
-/*
- * DynamicScan_GetDynamicScanIdPrintable
- *		Return "printable" scan id for a node, for EXPLAIN
- */
-int
-DynamicScan_GetDynamicScanIdPrintable(Plan *plan)
-{
-	switch (nodeTag(plan))
-	{
-		case T_DynamicSeqScan:
-			return ((DynamicSeqScan *) plan)->partIndexPrintable;
-
-		case T_DynamicIndexScan:
-			return ((DynamicIndexScan *) plan)->partIndexPrintable;
-
-		case T_DynamicBitmapHeapScan:
-			return ((DynamicBitmapHeapScan *) plan)->partIndexPrintable;
-
-		case T_DynamicBitmapIndexScan:
-			return ((DynamicBitmapIndexScan *) plan)->partIndexPrintable;
-
-		default:
-			elog(ERROR, "unknown dynamic scan node type %u", nodeTag(plan));
-	}
-}
-
-/*
- * DynamicScan_GetTableOid
- * 		Returns the Oid of the table/partition to scan.
- *
- *		A partition must have been selected already.
- */
-Oid
-DynamicScan_GetTableOid(ScanState *scanState)
-{
-	int			partIndex;
-	Oid			curRelOid;
-
-	partIndex = DynamicScan_GetDynamicScanId(scanState->ps.plan);
-
-	/* Get the oid of the current relation */
-	Assert(NULL != scanState->ps.state->dynamicTableScanInfo);
-	Assert(partIndex <= scanState->ps.state->dynamicTableScanInfo->numScans);
-
-	curRelOid = scanState->ps.state->dynamicTableScanInfo->curRelOids[partIndex - 1];
-	if (!OidIsValid(curRelOid))
-		elog(ERROR, "no partition selected for dynamic scan id %d", partIndex);
-
-	return curRelOid;
-}
-
-/*
- * DynamicScan_SetTableOid
- * 		Select a partition to scan in a dynamic scan.
- *
- *		This is used to advertise the selected partition in EState->dynamicTableScanInfo.
- */
-void
-DynamicScan_SetTableOid(ScanState *scanState, Oid curRelOid)
-{
-	int			partIndex;
-
-	partIndex = DynamicScan_GetDynamicScanId(scanState->ps.plan);
-
-	Assert(NULL != scanState->ps.state->dynamicTableScanInfo);
-	Assert(partIndex <= scanState->ps.state->dynamicTableScanInfo->numScans);
-
-	scanState->ps.state->dynamicTableScanInfo->curRelOids[partIndex - 1] = curRelOid;
-}
-
-/*
- * DynamicScan_RemapExpression
- * 		Re-maps the expression using the provided attMap.
- */
-bool
-DynamicScan_RemapExpression(ScanState *scanState, AttrNumber *attMap, Node *expr)
-{
-	if (!isDynamicScan(scanState->ps.plan))
-	{
-		return false;
-	}
-
-	if (NULL != attMap)
-	{
-		change_varattnos_of_a_varno((Node*)expr, attMap, ((Scan *)scanState->ps.plan)->scanrelid);
-		return true;
-	}
-
-	return false;
-}
diff --git a/src/backend/executor/nodeDynamicSeqscan.c b/src/backend/executor/nodeDynamicSeqscan.c
index 9a0d31fc1a..717a1849a4 100644
--- a/src/backend/executor/nodeDynamicSeqscan.c
+++ b/src/backend/executor/nodeDynamicSeqscan.c
@@ -8,13 +8,11 @@
  * DynamicSeqScan node scans each relation one after the other. For each
  * relation, it opens the table, scans the tuple, and returns relevant tuples.
  *
- * GPDB_12_MERGE_FIXME: This is currently disabled altogether. If it is
- * resurrected, some changes are needed to GPORCA. The way Partition
- * Selectors work has been heavily rewritten, there's no global hash table
- * of selected partitions anymore. For "static selection", there's a
- * partOids field in the DynamicSeqScan plan node that holds the selected
- * partitions; but none of the code in this file has been fixed to
- * actually work that way. Same with all the other Dynamic*Scan nodes.
+ * This has a smaller plan size than using an append with many partitions.
+ * Instead of determining the column mapping for each partition during planning,
+ * this mapping is determined during execution. When there are many partitions
+ * with many columns, the plan size improvement becomes very large, on the order of
+ * 100+ MB in some cases.
  *
  * Portions Copyright (c) 2012 - present, EMC/Greenplum
  * Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates.
@@ -30,81 +28,16 @@
 #include "executor/executor.h"
 #include "executor/instrument.h"
 #include "nodes/execnodes.h"
-#include "nodes/nodeFuncs.h"
-#include "executor/execDynamicScan.h"
+#include "executor/execPartition.h"
 #include "executor/nodeDynamicSeqscan.h"
 #include "executor/nodeSeqscan.h"
-#include "utils/hsearch.h"
-#include "parser/parsetree.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
-#include "cdb/cdbvars.h"
 #include "access/table.h"
 #include "access/tableam.h"
 
 static void CleanupOnePartition(DynamicSeqScanState *node);
 
-/*
- * During attribute re-mapping for heterogeneous partitions, we use
- * this struct to identify which varno's attributes will be re-mapped.
- * Using this struct as a *context* during expression tree walking, we
- * can skip varattnos that do not belong to a given varno.
- */
-typedef struct AttrMapContext
-{
-	const AttrNumber *newattno; /* The mapping table to remap the varattno */
-	Index		varno;			/* Which rte's varattno to re-map */
-} AttrMapContext;
-
-/*
- * Remaps the varattno of a varattno in a Var node using an attribute map.
- */
-static bool
-change_varattnos_varno_walker(Node *node, const AttrMapContext *attrMapCxt)
-{
-	if (node == NULL)
-		return false;
-	if (IsA(node, Var))
-	{
-		Var		   *var = (Var *) node;
-
-		if (var->varlevelsup == 0 && (var->varno == attrMapCxt->varno) &&
-			var->varattno > 0)
-		{
-			/*
-			 * ??? the following may be a problem when the node is multiply
-			 * referenced though stringToNode() doesn't create such a node
-			 * currently.
-			 */
-			Assert(attrMapCxt->newattno[var->varattno - 1] > 0);
-			var->varattno = var->varoattno = attrMapCxt->newattno[var->varattno - 1];
-		}
-		return false;
-	}
-	return expression_tree_walker(node, change_varattnos_varno_walker,
-	                              (void *) attrMapCxt);
-}
-
-/*
- * Replace varattno values for a given varno RTE index in an expression
- * tree according to the given map array, that is, varattno N is replaced
- * by newattno[N-1].  It is caller's responsibility to ensure that the array
- * is long enough to define values for all user varattnos present in the tree.
- * System column attnos remain unchanged.
- *
- * Note that the passed node tree is modified in-place!
- */
-static void
-change_varattnos_of_a_varno(Node *node, const AttrNumber *newattno, Index varno)
-{
-	AttrMapContext attrMapCxt;
-
-	attrMapCxt.newattno = newattno;
-	attrMapCxt.varno = varno;
-
-	(void) change_varattnos_varno_walker(node, &attrMapCxt);
-}
-
 DynamicSeqScanState *
 ExecInitDynamicSeqScan(DynamicSeqScan *node, EState *estate, int eflags)
 {
@@ -120,7 +53,7 @@ ExecInitDynamicSeqScan(DynamicSeqScan *node, EState *estate, int eflags)
 	state->ss.ps.plan = (Plan *) node;
 	state->ss.ps.state = estate;
 	state->ss.ps.ExecProcNode = ExecDynamicSeqScan;
-
+	state->did_pruning = false;
 	state->scan_state = SCAN_INIT;
 
 	/* Initialize child expressions. This is needed to find subplans. */
@@ -150,6 +83,8 @@ ExecInitDynamicSeqScan(DynamicSeqScan *node, EState *estate, int eflags)
 
 	state->scanrelid = node->seqscan.scanrelid;
 
+	state->as_prune_state = NULL;
+
 	/*
 	 * This context will be reset per-partition to free up per-partition
 	 * qual and targetlist allocations
@@ -159,7 +94,6 @@ ExecInitDynamicSeqScan(DynamicSeqScan *node, EState *estate, int eflags)
 									 ALLOCSET_DEFAULT_MINSIZE,
 									 ALLOCSET_DEFAULT_INITSIZE,
 									 ALLOCSET_DEFAULT_MAXSIZE);
-
 	return state;
 }
 
@@ -190,6 +124,13 @@ initNextTableToScan(DynamicSeqScanState *node)
 	else
 		return false;
 
+	/* Collect number of partitions scanned in EXPLAIN ANALYZE */
+	if (NULL != scanState->ps.instrument)
+	{
+		Instrumentation *instr = scanState->ps.instrument;
+		instr->numPartScanned++;
+	}
+
 	currentRelation = scanState->ss_currentRelation =
 		table_open(node->partOids[node->whichPart], AccessShareLock);
 
@@ -211,11 +152,6 @@ initNextTableToScan(DynamicSeqScanState *node)
 	/* If attribute remapping is not necessary, then do not change the varattno */
 	if (attMap)
 	{
-		/*
-		 * FIXME: Ewww, this doesn't really belong in the executor. The optimizer
-		 * really should explicitly pass a qual and a tlist to us, for each
-		 * partition
-		 */
 		change_varattnos_of_a_varno((Node*)scanState->ps.plan->qual, attMap, node->scanrelid);
 		change_varattnos_of_a_varno((Node*)scanState->ps.plan->targetlist, attMap, node->scanrelid);
 
@@ -227,9 +163,9 @@ initNextTableToScan(DynamicSeqScanState *node)
 	}
 
 	/*
-	 * For the very first partition, the targetlist of planstate is set to null. So, we must
-	 * initialize quals and targetlist, regardless of remapping requirements. For later
-	 * partitions, we only initialize quals and targetlist if a column re-mapping is necessary.
+	 * For the very first partition, the qual of planstate is set to null. So, we must
+	 * initialize quals, regardless of remapping requirements. For later
+	 * partitions, we only initialize quals if a column re-mapping is necessary.
 	 */
 	if (attMap || node->firstPartition)
 	{
@@ -247,7 +183,6 @@ initNextTableToScan(DynamicSeqScanState *node)
 	if (attMap)
 		pfree(attMap);
 
-//	DynamicScan_SetTableOid(&node->ss, *pid);
 	node->seqScanState = ExecInitSeqScanForPartition(&plan->seqscan, estate,
 													 currentRelation);
 	return true;
@@ -260,6 +195,33 @@ ExecDynamicSeqScan(PlanState *pstate)
 	DynamicSeqScanState *node = castNode(DynamicSeqScanState, pstate);
 	TupleTableSlot *slot = NULL;
 
+	DynamicSeqScan	   *plan = (DynamicSeqScan *) node->ss.ps.plan;
+	node->as_valid_subplans = NULL;
+	if (NULL != plan->join_prune_paramids && !node->did_pruning)
+	{
+		node->did_pruning = true;
+		node->as_valid_subplans =
+			ExecFindMatchingSubPlans(node->as_prune_state,
+									 node->ss.ps.state,
+									 list_length(plan->partOids),
+									 plan->join_prune_paramids);
+
+		int i = 0;
+		int partOidIdx = -1;
+		List *newPartOids = NIL;
+		ListCell *lc;
+		for(i = 0; i < bms_num_members(node->as_valid_subplans); i++)
+		{
+			partOidIdx = bms_next_member(node->as_valid_subplans, partOidIdx);
+			newPartOids = lappend_oid(newPartOids, node->partOids[partOidIdx]);
+		}
+
+		node->partOids = palloc(sizeof(Oid) * list_length(newPartOids));
+		foreach_with_count(lc, newPartOids, i)
+			node->partOids[i] = lfirst_oid(lc);
+		node->nOids = list_length(newPartOids);
+	}
+
 	/*
 	 * Scan the table to find next tuple to return. If the current table
 	 * is finished, close it and open the next table for scan.
@@ -337,5 +299,21 @@ ExecReScanDynamicSeqScan(DynamicSeqScanState *node)
 {
 	DynamicSeqScanEndCurrentScan(node);
 
-	/* Force reloading the partition hash table */
+	// reset partition internal state
+
+	/*
+	 * If any PARAM_EXEC Params used in pruning expressions have changed, then
+	 * we'd better unset the valid subplans so that they are reselected for
+	 * the new parameter values.
+	 */
+	if (node->as_prune_state &&
+		bms_overlap(node->ss.ps.chgParam,
+					node->as_prune_state->execparamids))
+	{
+		bms_free(node->as_valid_subplans);
+		node->as_valid_subplans = NULL;
+	}
+
+	node->whichPart = -1;
+
 }
diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
index d443c7bd19..7ddfcfccaf 100644
--- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
@@ -4054,9 +4054,36 @@ CTranslatorDXLToPlStmt::TranslateDXLDynTblScan(
 	DynamicSeqScan *dyn_seq_scan = MakeNode(DynamicSeqScan);
 
 	dyn_seq_scan->seqscan.scanrelid = index;
-	dyn_seq_scan->partIndex = dyn_tbl_scan_dxlop->GetPartIndexId();
-	dyn_seq_scan->partIndexPrintable =
-		dyn_tbl_scan_dxlop->GetPartIndexIdPrintable();
+
+	IMdIdArray *parts = dyn_tbl_scan_dxlop->GetParts();
+
+	List *oids_list = NIL;
+
+	for (ULONG ul = 0; ul < parts->Size(); ul++)
+	{
+		Oid part = CMDIdGPDB::CastMdid((*parts)[ul])->Oid();
+		oids_list = gpdb::LAppendOid(oids_list, part);
+	}
+
+	dyn_seq_scan->partOids = oids_list;
+
+	dyn_seq_scan->join_prune_paramids = NIL;
+
+	OID oid_type =
+		CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
+			->Oid();
+
+	const ULongPtrArray *selector_ids = dyn_tbl_scan_dxlop->GetSelectorIds();
+
+	for (ULONG ul = 0; ul < selector_ids->Size(); ++ul)
+	{
+		ULONG selector_id = *(*selector_ids)[ul];
+		ULONG param_id = m_dxl_to_plstmt_context->GetParamIdForSelector(
+			oid_type, selector_id);
+		dyn_seq_scan->join_prune_paramids =
+			gpdb::LAppendInt(dyn_seq_scan->join_prune_paramids, param_id);
+	}
+
 
 	Plan *plan = &(dyn_seq_scan->seqscan.plan);
 	plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
index b322ac5595..bca5ff694a 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
@@ -1358,9 +1358,26 @@ CTranslatorExprToDXL::PdxlnDynamicTableScan(
 	}
 
 	// construct dynamic table scan operator
+	IMdIdArray *part_mdids = popDTS->GetPartitionMdids();
+	part_mdids->AddRef();
+
+	ULongPtrArray *selector_ids = GPOS_NEW(m_mp) ULongPtrArray(m_mp);
+	CPartitionPropagationSpec *pps_reqd =
+		pexprDTS->Prpp()->Pepp()->PppsRequired();
+	if (pps_reqd->Contains(popDTS->ScanId()))
+	{
+		const CBitSet *bs = pps_reqd->SelectorIds(popDTS->ScanId());
+		CBitSetIter bsi(*bs);
+		for (ULONG ul = 0; bsi.Advance(); ul++)
+		{
+			selector_ids->Append(GPOS_NEW(m_mp) ULONG(bsi.Bit()));
+		}
+	}
+
+
 	CDXLPhysicalDynamicTableScan *pdxlopDTS =
-		GPOS_NEW(m_mp) CDXLPhysicalDynamicTableScan(
-			m_mp, table_descr, 0 /* CHRIS */, popDTS->ScanId());
+		GPOS_NEW(m_mp) CDXLPhysicalDynamicTableScan(m_mp, table_descr,
+													part_mdids, selector_ids);
 
 	CDXLNode *pdxlnDTS = GPOS_NEW(m_mp) CDXLNode(m_mp, pdxlopDTS);
 	pdxlnDTS->SetProperties(pdxlpropDTS);
@@ -1390,139 +1407,6 @@ CTranslatorExprToDXL::PdxlnDynamicTableScan(
 	pdrgpdsBaseTables->Append(pds);
 
 	return pdxlnDTS;
-
-	/*
-	GPOS_ASSERT(nullptr != pexprDTS);
-	GPOS_ASSERT_IFF(nullptr != pexprScalarCond, nullptr != dxl_properties);
-
-	CPhysicalDynamicTableScan *popDTS =
-		CPhysicalDynamicTableScan::PopConvert(pexprDTS->Pop());
-
-	ULongPtrArray *selector_ids = GPOS_NEW(m_mp) ULongPtrArray(m_mp);
-	CPartitionPropagationSpec *pps_reqd =
-		pexprDTS->Prpp()->Pepp()->PppsRequired();
-	if (pps_reqd->Contains(popDTS->ScanId()))
-	{
-		const CBitSet *bs = pps_reqd->SelectorIds(popDTS->ScanId());
-		CBitSetIter bsi(*bs);
-		for (ULONG ul = 0; bsi.Advance(); ul++)
-		{
-			selector_ids->Append(GPOS_NEW(m_mp) ULONG(bsi.Bit()));
-		}
-	}
-
-	// construct plan costs
-	CDXLPhysicalProperties *pdxlpropDTS = GetProperties(pexprDTS);
-
-	if (nullptr != dxl_properties)
-	{
-		CWStringDynamic *rows_out_str = GPOS_NEW(m_mp) CWStringDynamic(
-			m_mp,
-			dxl_properties->GetDXLOperatorCost()->GetRowsOutStr()->GetBuffer());
-		CWStringDynamic *pstrCost = GPOS_NEW(m_mp)
-			CWStringDynamic(m_mp, dxl_properties->GetDXLOperatorCost()
-									  ->GetTotalCostStr()
-									  ->GetBuffer());
-
-		pdxlpropDTS->GetDXLOperatorCost()->SetRows(rows_out_str);
-		pdxlpropDTS->GetDXLOperatorCost()->SetCost(pstrCost);
-		dxl_properties->Release();
-	}
-	GPOS_ASSERT(nullptr != pexprDTS->Prpp());
-
-	// construct projection list for top-level Append node
-	CColRefSet *pcrsOutput = pexprDTS->Prpp()->PcrsRequired();
-	CDXLNode *pdxlnPrLAppend = PdxlnProjList(pcrsOutput, colref_array);
-	CDXLTableDescr *root_dxl_table_descr = MakeDXLTableDescr(
-		popDTS->Ptabdesc(), popDTS->PdrgpcrOutput(), pexprDTS->Prpp());
-
-	// Construct the Append node - even when there is only one child partition.
-	// This is done for two reasons:
-	// * Dynamic partition pruning
-	//   Even if one partition is present in the statically pruned plan, we could
-	//   still dynamically prune it away. This needs an Append node.
-	// * Col mappings issues
-	//   When the first selected child partition's cols have different types/order
-	//   than the root partition, we can no longer re-use the colrefs of the root
-	//   partition, since colrefs are immutable. Thus, we create new colrefs for
-	//   this partition. But, if there is no Append (in case of just one selected
-	//   partition), then we also go through update all references above the DTS
-	//   with the new colrefs. For simplicity, we decided to keep the Append
-	//   around to maintain this projection (mapping) from the old root colrefs
-	//   to the first selected partition colrefs.
-	//
-	// GPDB_12_MERGE_FIXME: An Append on a single TableScan can be removed in
-	// CTranslatorDXLToPlstmt since these points do not apply there.
-	CDXLNode *pdxlnAppend = GPOS_NEW(m_mp) CDXLNode(
-		m_mp,
-		GPOS_NEW(m_mp) CDXLPhysicalAppend(m_mp, false, false, popDTS->ScanId(),
-										  root_dxl_table_descr, selector_ids));
-	pdxlnAppend->SetProperties(pdxlpropDTS);
-	pdxlnAppend->AddChild(pdxlnPrLAppend);
-	pdxlnAppend->AddChild(PdxlnFilter(nullptr));
-
-	IMdIdArray *part_mdids = popDTS->GetPartitionMdids();
-	for (ULONG ul = 0; ul < part_mdids->Size(); ++ul)
-	{
-		IMDId *part_mdid = (*part_mdids)[ul];
-		const IMDRelation *part = m_pmda->RetrieveRel(part_mdid);
-
-		CTableDescriptor *part_tabdesc =
-			MakeTableDescForPart(part, popDTS->Ptabdesc());
-
-		// Create new colrefs for the child partition. The ColRefs from root
-		// DTS, which may be used in any parent node, can no longer be exported
-		// by a child of the Append node. Thus it is exported by the Append
-		// node itself, and new colrefs are created here.
-		CColRefArray *part_colrefs = GPOS_NEW(m_mp) CColRefArray(m_mp);
-		for (ULONG ul_col = 0; ul_col < part_tabdesc->ColumnCount(); ++ul_col)
-		{
-			const CColumnDescriptor *cd = part_tabdesc->Pcoldesc(ul_col);
-			CColRef *cr = m_pcf->PcrCreate(cd->RetrieveType(),
-										   cd->TypeModifier(), cd->Name());
-			part_colrefs->Append(cr);
-		}
-
-		CDXLTableDescr *dxl_table_descr =
-			MakeDXLTableDescr(part_tabdesc, part_colrefs, pexprDTS->Prpp());
-		part_tabdesc->Release();
-
-		CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(
-			m_mp, GPOS_NEW(m_mp) CDXLPhysicalTableScan(m_mp, dxl_table_descr));
-
-		// GPDB_12_MERGE_FIXME: Compute stats & properties per scan
-		pdxlpropDTS->AddRef();
-		dxlnode->SetProperties(pdxlpropDTS);
-
-		// ColRef -> index in child table desc (per partition)
-		auto root_col_mapping = (*popDTS->GetRootColMappingPerPart())[ul];
-
-		// construct projection list, re-ordered to match root DTS
-		CDXLNode *pdxlnPrL = PdxlnProjListForChildPart(
-			root_col_mapping, part_colrefs, pcrsOutput, colref_array);
-		dxlnode->AddChild(pdxlnPrL);  // project list
-
-		// construct the filter
-		CDXLNode *filter_dxlnode = PdxlnFilter(
-			PdxlnCondForChildPart(root_col_mapping, part_colrefs,
-								  popDTS->PdrgpcrOutput(), pexprScalarCond));
-		dxlnode->AddChild(filter_dxlnode);	// filter
-
-		// add to the other scans under the created Append node
-		pdxlnAppend->AddChild(dxlnode);
-
-		// cleanup
-		part_colrefs->Release();
-	}
-
-	CDistributionSpec *pds = pexprDTS->GetDrvdPropPlan()->Pds();
-	pds->AddRef();
-	pdrgpdsBaseTables->Append(pds);
-
-	GPOS_ASSERT(pdxlnAppend);
-	return pdxlnAppend;
-
- */
 }
 
 //---------------------------------------------------------------------------
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h
index f0b46d9b3f..786659e3af 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h
@@ -44,19 +44,17 @@ private:
 	// table descriptor for the scanned table
 	CDXLTableDescr *m_dxl_table_descr;
 
-	// id of partition index structure
-	ULONG m_part_index_id;
+	IMdIdArray *m_part_mdids;
 
-	// printable partition index id
-	ULONG m_part_index_id_printable;
+	ULongPtrArray *m_selector_ids = nullptr;
 
 public:
 	CDXLPhysicalDynamicTableScan(CDXLPhysicalDynamicTableScan &) = delete;
 
 	// ctor
 	CDXLPhysicalDynamicTableScan(CMemoryPool *mp, CDXLTableDescr *table_descr,
-								 ULONG part_idx_id,
-								 ULONG part_idx_id_printable);
+								 IMdIdArray *part_mdids,
+								 ULongPtrArray *selector_ids);
 
 	// dtor
 	~CDXLPhysicalDynamicTableScan() override;
@@ -70,12 +68,13 @@ public:
 	// table descriptor
 	const CDXLTableDescr *GetDXLTableDescr() const;
 
-	// partition index id
-	ULONG GetPartIndexId() const;
-
-	// printable partition index id
-	ULONG GetPartIndexIdPrintable() const;
+	IMdIdArray *GetParts() const;
 
+	const ULongPtrArray *
+	GetSelectorIds() const
+	{
+		return m_selector_ids;
+	}
 	// serialize operator in DXL format
 	void SerializeToDXL(CXMLSerializer *xml_serializer,
 						const CDXLNode *node) const override;
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicTableScan.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicTableScan.h
index 8b5b1d6b4a..c3c1969451 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicTableScan.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicTableScan.h
@@ -36,11 +36,7 @@ class CDXLPhysicalDynamicTableScan;
 class CParseHandlerDynamicTableScan : public CParseHandlerPhysicalOp
 {
 private:
-	// the id of the partition index structure
-	ULONG m_part_index_id;
-
-	// printable partition index id
-	ULONG m_part_index_id_printable;
+	ULongPtrArray *m_selector_ids;
 
 	// process the start of an element
 	void StartElement(
diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicTableScan.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicTableScan.cpp
index f5dc4d0ae1..4731259db0 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicTableScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicTableScan.cpp
@@ -12,8 +12,10 @@
 
 #include "naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h"
 
+#include "naucrates/dxl/CDXLUtils.h"
 #include "naucrates/dxl/operators/CDXLNode.h"
 #include "naucrates/dxl/xml/CXMLSerializer.h"
+#include "naucrates/md/IMDCacheObject.h"
 
 using namespace gpos;
 using namespace gpdxl;
@@ -28,12 +30,13 @@ using namespace gpdxl;
 //
 //---------------------------------------------------------------------------
 CDXLPhysicalDynamicTableScan::CDXLPhysicalDynamicTableScan(
-	CMemoryPool *mp, CDXLTableDescr *table_descr, ULONG part_idx_id,
-	ULONG part_idx_id_printable)
+	CMemoryPool *mp, CDXLTableDescr *table_descr, IMdIdArray *part_mdids,
+	ULongPtrArray *selector_ids)
 	: CDXLPhysical(mp),
 	  m_dxl_table_descr(table_descr),
-	  m_part_index_id(part_idx_id),
-	  m_part_index_id_printable(part_idx_id_printable)
+	  m_part_mdids(part_mdids),
+	  m_selector_ids(selector_ids)
+
 {
 	GPOS_ASSERT(nullptr != table_descr);
 }
@@ -50,6 +53,8 @@ CDXLPhysicalDynamicTableScan::CDXLPhysicalDynamicTableScan(
 CDXLPhysicalDynamicTableScan::~CDXLPhysicalDynamicTableScan()
 {
 	m_dxl_table_descr->Release();
+	m_part_mdids->Release();
+	CRefCount::SafeRelease(m_selector_ids);
 }
 
 //---------------------------------------------------------------------------
@@ -95,32 +100,10 @@ CDXLPhysicalDynamicTableScan::GetDXLTableDescr() const
 	return m_dxl_table_descr;
 }
 
-//---------------------------------------------------------------------------
-//	@function:
-//		CDXLPhysicalDynamicTableScan::GetPartIndexId
-//
-//	@doc:
-//		Id of partition index
-//
-//---------------------------------------------------------------------------
-ULONG
-CDXLPhysicalDynamicTableScan::GetPartIndexId() const
-{
-	return m_part_index_id;
-}
-
-//---------------------------------------------------------------------------
-//	@function:
-//		CDXLPhysicalDynamicTableScan::GetPartIndexIdPrintable
-//
-//	@doc:
-//		Printable partition index id
-//
-//---------------------------------------------------------------------------
-ULONG
-CDXLPhysicalDynamicTableScan::GetPartIndexIdPrintable() const
+IMdIdArray *
+CDXLPhysicalDynamicTableScan::GetParts() const
 {
-	return m_part_index_id_printable;
+	return m_part_mdids;
 }
 
 //---------------------------------------------------------------------------
@@ -139,16 +122,18 @@ CDXLPhysicalDynamicTableScan::SerializeToDXL(CXMLSerializer *xml_serializer,
 
 	xml_serializer->OpenElement(
 		CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix), element_name);
+	CWStringDynamic *serialized_selector_ids =
+		CDXLUtils::Serialize(m_mp, m_selector_ids);
 	xml_serializer->AddAttribute(
-		CDXLTokens::GetDXLTokenStr(EdxltokenPartIndexId), m_part_index_id);
-	if (m_part_index_id_printable != m_part_index_id)
-	{
-		xml_serializer->AddAttribute(
-			CDXLTokens::GetDXLTokenStr(EdxltokenPartIndexIdPrintable),
-			m_part_index_id_printable);
-	}
+		CDXLTokens::GetDXLTokenStr(EdxltokenSelectorIds),
+		serialized_selector_ids);
+	GPOS_DELETE(serialized_selector_ids);
 	node->SerializePropertiesToDXL(xml_serializer);
 	node->SerializeChildrenToDXL(xml_serializer);
+	IMDCacheObject::SerializeMDIdList(
+		xml_serializer, m_part_mdids,
+		CDXLTokens::GetDXLTokenStr(EdxltokenPartitions),
+		CDXLTokens::GetDXLTokenStr(EdxltokenPartition));
 	m_dxl_table_descr->SerializeToDXL(xml_serializer);
 	xml_serializer->CloseElement(
 		CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix), element_name);
diff --git a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicTableScan.cpp b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicTableScan.cpp
index 8cfd57a3a4..9c78c4549e 100644
--- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicTableScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicTableScan.cpp
@@ -16,6 +16,7 @@
 #include "naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h"
 #include "naucrates/dxl/parser/CParseHandlerFactory.h"
 #include "naucrates/dxl/parser/CParseHandlerFilter.h"
+#include "naucrates/dxl/parser/CParseHandlerMetadataIdList.h"
 #include "naucrates/dxl/parser/CParseHandlerProjList.h"
 #include "naucrates/dxl/parser/CParseHandlerProperties.h"
 #include "naucrates/dxl/parser/CParseHandlerTableDescr.h"
@@ -67,17 +68,10 @@ CParseHandlerDynamicTableScan::StartElement(
 				   str->GetBuffer());
 	}
 
-	m_part_index_id = CDXLOperatorFactory::ExtractConvertAttrValueToUlong(
-		m_parse_handler_mgr->GetDXLMemoryManager(), attrs, EdxltokenPartIndexId,
+	m_selector_ids = CDXLOperatorFactory::ExtractConvertValuesToArray(
+		m_parse_handler_mgr->GetDXLMemoryManager(), attrs, EdxltokenSelectorIds,
 		EdxltokenPhysicalDynamicTableScan);
 
-	m_part_index_id_printable =
-		CDXLOperatorFactory::ExtractConvertAttrValueToUlong(
-			m_parse_handler_mgr->GetDXLMemoryManager(), attrs,
-			EdxltokenPartIndexIdPrintable, EdxltokenPhysicalDynamicTableScan,
-			true,  //is_optional
-			m_part_index_id);
-
 	// create child node parsers in reverse order of their expected occurrence
 
 	// parse handler for table descriptor
@@ -87,6 +81,13 @@ CParseHandlerDynamicTableScan::StartElement(
 			m_parse_handler_mgr, this);
 	m_parse_handler_mgr->ActivateParseHandler(table_descr_parse_handler);
 
+	CParseHandlerBase *partition_mdids_parse_handler =
+		CParseHandlerFactory::GetParseHandler(
+			m_mp, CDXLTokens::XmlstrToken(EdxltokenMetadataIdList),
+			m_parse_handler_mgr, this);
+	m_parse_handler_mgr->ActivateParseHandler(partition_mdids_parse_handler);
+
+
 	// parse handler for the filter
 	CParseHandlerBase *filter_parse_handler =
 		CParseHandlerFactory::GetParseHandler(
@@ -112,6 +113,7 @@ CParseHandlerDynamicTableScan::StartElement(
 	this->Append(prop_parse_handler);
 	this->Append(proj_list_parse_handler);
 	this->Append(filter_parse_handler);
+	this->Append(partition_mdids_parse_handler);
 	this->Append(table_descr_parse_handler);
 }
 
@@ -146,16 +148,22 @@ CParseHandlerDynamicTableScan::EndElement(const XMLCh *const,  // element_uri,
 		dynamic_cast<CParseHandlerProjList *>((*this)[1]);
 	CParseHandlerFilter *filter_parse_handler =
 		dynamic_cast<CParseHandlerFilter *>((*this)[2]);
+	CParseHandlerMetadataIdList *partition_mdids_parse_handler =
+		dynamic_cast<CParseHandlerMetadataIdList *>((*this)[3]);
 	CParseHandlerTableDescr *table_descr_parse_handler =
-		dynamic_cast<CParseHandlerTableDescr *>((*this)[3]);
+		dynamic_cast<CParseHandlerTableDescr *>((*this)[4]);
 
 
 	// set table descriptor
 	CDXLTableDescr *table_descr = table_descr_parse_handler->GetDXLTableDescr();
 	table_descr->AddRef();
+
+	IMdIdArray *mdid_partitions_array =
+		partition_mdids_parse_handler->GetMdIdArray();
+	mdid_partitions_array->AddRef();
 	CDXLPhysicalDynamicTableScan *dxl_op =
 		GPOS_NEW(m_mp) CDXLPhysicalDynamicTableScan(
-			m_mp, table_descr, m_part_index_id, m_part_index_id_printable);
+			m_mp, table_descr, mdid_partitions_array, m_selector_ids);
 
 	m_dxl_node = GPOS_NEW(m_mp) CDXLNode(m_mp, dxl_op);
 	// set statictics and physical properties
diff --git a/src/include/executor/execDynamicScan.h b/src/include/executor/execDynamicScan.h
deleted file mode 100644
index f41ae5d34c..0000000000
--- a/src/include/executor/execDynamicScan.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*--------------------------------------------------------------------------
- *
- * execDynamicScan.h
- *	 Definitions and API functions for execDynamicScan.c
- *
- * Copyright (c) 2014-Present VMware, Inc. or its affiliates.
- *
- *
- * IDENTIFICATION
- *	    src/include/executor/execDynamicScan.h
- *
- *--------------------------------------------------------------------------
- */
-#ifndef EXECDYNAMICSCAN_H
-#define EXECDYNAMICSCAN_H
-
-#include "access/attnum.h"
-#include "nodes/execnodes.h"
-
-extern bool isDynamicScan(const Plan *p);
-extern int DynamicScan_GetDynamicScanIdPrintable(Plan *plan);
-
-extern Oid DynamicScan_GetTableOid(ScanState *scanState);
-extern void DynamicScan_SetTableOid(ScanState *scanState, Oid curRelOid);
-
-extern bool DynamicScan_RemapExpression(ScanState *scanState, AttrNumber *attMap, Node *expr);
-
-#endif   /* EXECDYNAMICSCAN_H */


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cloudberry.apache.org
For additional commands, e-mail: commits-help@cloudberry.apache.org