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:29 UTC

(cloudberry) 04/11: Adds Orca support for Dynamic Index 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 2617770361b6b1c8c804dec78040e15301a0d49b
Author: Chris Hajas <ch...@vmware.com>
AuthorDate: Mon May 23 14:51:47 2022 -0700

    Adds Orca support for Dynamic Index Scan
---
 src/backend/executor/nodeDynamicIndexscan.c        | 176 +++++++-------------
 src/backend/executor/nodeIndexscan.c               |  39 +++--
 .../gpopt/translate/CTranslatorDXLToPlStmt.cpp     | 136 +++++++++++++++-
 .../src/translate/CTranslatorExprToDXL.cpp         | 179 ++++++++-------------
 .../dxl/operators/CDXLPhysicalDynamicIndexScan.h   |  29 ++--
 .../dxl/parser/CParseHandlerDynamicIndexScan.h     |   6 +-
 .../naucrates/dxl/parser/CParseHandlerIndexScan.h  |   4 +-
 .../src/operators/CDXLPhysicalDynamicIndexScan.cpp |  62 +++----
 .../src/operators/CDXLPhysicalIndexScan.cpp        |   7 +
 .../src/parser/CParseHandlerDynamicIndexScan.cpp   |  15 +-
 .../src/parser/CParseHandlerIndexOnlyScan.cpp      |   3 +-
 .../src/parser/CParseHandlerIndexScan.cpp          |  24 ++-
 src/include/executor/nodeDynamicIndexscan.h        |   6 +-
 .../gpopt/translate/CTranslatorDXLToPlStmt.h       |  12 +-
 14 files changed, 360 insertions(+), 338 deletions(-)

diff --git a/src/backend/executor/nodeDynamicIndexscan.c b/src/backend/executor/nodeDynamicIndexscan.c
index 2fcad60607..5115fa9d9c 100644
--- a/src/backend/executor/nodeDynamicIndexscan.c
+++ b/src/backend/executor/nodeDynamicIndexscan.c
@@ -20,17 +20,17 @@
 
 #include "postgres.h"
 
-#include "cdb/cdbvars.h"
-#include "cdb/partitionselection.h"
-#include "executor/execDynamicScan.h"
+#include "catalog/partition.h"
 #include "executor/executor.h"
 #include "executor/instrument.h"
 #include "nodes/execnodes.h"
+#include "executor/execPartition.h"
 #include "executor/nodeIndexscan.h"
 #include "executor/nodeDynamicIndexscan.h"
-#include "access/genam.h"
-#include "nodes/nodeFuncs.h"
+#include "access/table.h"
+#include "access/tableam.h"
 #include "utils/memutils.h"
+#include "utils/rel.h"
 
 /*
  * Initialize ScanState in DynamicIndexScan.
@@ -39,6 +39,8 @@ DynamicIndexScanState *
 ExecInitDynamicIndexScan(DynamicIndexScan *node, EState *estate, int eflags)
 {
 	DynamicIndexScanState *dynamicIndexScanState;
+	ListCell *lc;
+	int i;
 
 	/* check for unsupported flags */
 	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -46,9 +48,15 @@ ExecInitDynamicIndexScan(DynamicIndexScan *node, EState *estate, int eflags)
 	dynamicIndexScanState = makeNode(DynamicIndexScanState);
 	dynamicIndexScanState->ss.ps.plan = (Plan *) node;
 	dynamicIndexScanState->ss.ps.state = estate;
+	dynamicIndexScanState->ss.ps.ExecProcNode = ExecDynamicIndexScan;
 	dynamicIndexScanState->eflags = eflags;
 
 	dynamicIndexScanState->scan_state = SCAN_INIT;
+	dynamicIndexScanState->whichPart = -1;
+	dynamicIndexScanState->nOids = list_length(node->partOids);
+	dynamicIndexScanState->partOids = palloc(sizeof(Oid) * dynamicIndexScanState->nOids);
+	foreach_with_count(lc, node->partOids, i)
+		dynamicIndexScanState->partOids[i] = lfirst_oid(lc);
 
 	/*
 	 * Initialize child expressions
@@ -57,24 +65,19 @@ ExecInitDynamicIndexScan(DynamicIndexScan *node, EState *estate, int eflags)
 	 * to do all evaluation for us. But I think this is still needed to
 	 * find and process any SubPlans. See comment in ExecInitIndexScan.
 	 */
-	dynamicIndexScanState->ss.ps.targetlist = (List *)
-		ExecInitExpr((Expr *) node->indexscan.scan.plan.targetlist,
+	dynamicIndexScanState->ss.ps.qual = ExecInitQual(node->indexscan.scan.plan.qual,
 					 (PlanState *) dynamicIndexScanState);
-	dynamicIndexScanState->ss.ps.qual = (List *)
-		ExecInitExpr((Expr *) node->indexscan.scan.plan.qual,
-					 (PlanState *) dynamicIndexScanState);
-	(void) ExecInitExpr((Expr *) node->indexscan.indexqualorig,
-						(PlanState *) dynamicIndexScanState);
 
 	/*
 	 * tuple table initialization
 	 */
-	ExecInitResultTupleSlot(estate, &dynamicIndexScanState->ss.ps);
+	Relation scanRel = ExecOpenScanRelation(estate, node->indexscan.scan.scanrelid, eflags);
+	ExecInitScanTupleSlot(estate, &dynamicIndexScanState->ss, RelationGetDescr(scanRel), table_slot_callbacks(scanRel));
 
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
-	ExecAssignResultTypeFromTL(&dynamicIndexScanState->ss.ps);
+	ExecInitResultTypeTL(&dynamicIndexScanState->ss.ps);
 
 	/*
 	 * This context will be reset per-partition to free up per-partition
@@ -110,9 +113,6 @@ DynamicIndexScan_ReMapColumns(DynamicIndexScan *dIndexScan, Oid oldOid, Oid newO
 
 	if (attMap)
 	{
-		IndexScan_MapLogicalIndexInfo(dIndexScan->logicalIndexInfo, attMap,
-									  indexScan->scan.scanrelid);
-
 		/* Also map attrnos in targetlist and quals */
 		change_varattnos_of_a_varno((Node *) indexScan->scan.plan.targetlist,
 									attMap, indexScan->scan.scanrelid);
@@ -144,7 +144,8 @@ beginCurrentIndexScan(DynamicIndexScanState *node, EState *estate,
 	/*
 	 * open the base relation and acquire appropriate lock on it.
 	 */
-	currentRelation = heap_open(tableOid, AccessShareLock);
+	currentRelation = table_open(tableOid, AccessShareLock);
+	node->ss.ss_currentRelation = currentRelation;
 
 	save_tupletable = estate->es_tupleTable;
 	estate->es_tupleTable = NIL;
@@ -157,18 +158,18 @@ beginCurrentIndexScan(DynamicIndexScanState *node, EState *estate,
 	if (!OidIsValid(node->columnLayoutOid))
 	{
 		/* Very first partition */
-		node->columnLayoutOid = rel_partition_get_root(tableOid);
+		// Just get the direct parent, we don't support multi-level partitioning
+		node->columnLayoutOid = get_partition_parent(tableOid);
 	}
 	DynamicIndexScan_ReMapColumns(dynamicIndexScan,
-								  node->columnLayoutOid, tableOid);
+								  tableOid, node->columnLayoutOid);
 	node->columnLayoutOid = tableOid;
 
-	indexOid = getPhysicalIndexRelid(currentRelation, dynamicIndexScan->logicalIndexInfo);
+	indexOid = index_get_partition(currentRelation, dynamicIndexScan->indexscan.indexid);
 	if (!OidIsValid(indexOid))
 		elog(ERROR, "failed to find index for partition \"%s\" in dynamic index scan",
 			 RelationGetRelationName(currentRelation));
 
-	DynamicScan_SetTableOid(&node->ss, tableOid);
 	node->indexScanState = ExecInitIndexScanForPartition(&dynamicIndexScan->indexscan, estate,
 														 node->eflags,
 														 currentRelation, indexOid);
@@ -188,6 +189,7 @@ endCurrentIndexScan(DynamicIndexScanState *node)
 	{
 		ExecEndIndexScan(node->indexScanState);
 		node->indexScanState = NULL;
+		table_close(node->ss.ss_currentRelation, NoLock);
 	}
 	ExecResetTupleTable(node->tuptable, true);
 	node->tuptable = NIL;
@@ -208,16 +210,10 @@ initNextIndexToScan(DynamicIndexScanState *node)
 	{
 		/* This is the oid of a partition of the table (*not* index) */
 		Oid			tableOid;
-		Oid		   *pid;
-
-		pid = hash_seq_search(&node->pidxStatus);
-		if (pid == NULL)
-		{
-			/* Return if all parts have been scanned. */
-			node->shouldCallHashSeqTerm = false;
+		if (++node->whichPart < node->nOids)
+			tableOid = node->partOids[node->whichPart];
+		else
 			return false;
-		}
-		tableOid = *pid;
 
 		/* Collect number of partitions scanned in EXPLAIN ANALYZE */
 		if (node->ss.ps.instrument)
@@ -233,53 +229,40 @@ initNextIndexToScan(DynamicIndexScanState *node)
 	return true;
 }
 
-/*
- * setPidIndex
- *   Set the hash table of Oids to scan.
- */
-static void
-setPidIndex(DynamicIndexScanState *node)
-{
-	IndexScanState *indexState = (IndexScanState *)node;
-	DynamicIndexScan *plan = (DynamicIndexScan *) indexState->ss.ps.plan;
-	EState	   *estate = indexState->ss.ps.state;
-	int			partIndex = plan->partIndex;
-
-	Assert(node->pidxIndex == NULL);
-	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(estate, partIndex,
-									  InvalidOid, InvalidPartitionSelectorId);
-
-	Assert(NULL != estate->dynamicTableScanInfo->pidIndexes);
-	Assert(estate->dynamicTableScanInfo->numScans >= partIndex);
-	node->pidxIndex = estate->dynamicTableScanInfo->pidIndexes[partIndex - 1];
-	Assert(node->pidxIndex != NULL);
-}
-
 /*
  * Execution of DynamicIndexScan
  */
 TupleTableSlot *
-ExecDynamicIndexScan(DynamicIndexScanState *node)
+ExecDynamicIndexScan(PlanState *pstate)
 {
+	DynamicIndexScanState *node = castNode(DynamicIndexScanState, pstate);
 	TupleTableSlot *slot = NULL;
 
-	/*
-	 * If this is called the first time, find the pid index that contains all unique
-	 * partition pids for this node to scan.
-	 */
-	if (node->pidxIndex == NULL)
+	DynamicIndexScan	   *plan = (DynamicIndexScan *) node->ss.ps.plan;
+	node->as_valid_subplans = NULL;
+	if (NULL != plan->join_prune_paramids && !node->did_pruning)
 	{
-		setPidIndex(node);
-		Assert(node->pidxIndex != NULL);
+		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;
+		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]);
+		}
 
-		hash_seq_init(&node->pidxStatus, node->pidxIndex);
-		node->shouldCallHashSeqTerm = true;
+		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);
 	}
 
 	/*
@@ -289,7 +272,7 @@ ExecDynamicIndexScan(DynamicIndexScanState *node)
 	while (TupIsNull(slot) &&
 		   initNextIndexToScan(node))
 	{
-		slot = ExecIndexScan(node->indexScanState);
+		slot = ExecProcNode(&node->indexScanState->ss.ps);
 
 		if (TupIsNull(slot))
 		{
@@ -311,12 +294,6 @@ ExecEndDynamicIndexScan(DynamicIndexScanState *node)
 
 	node->scan_state = SCAN_END;
 
-	if (node->shouldCallHashSeqTerm)
-	{
-		hash_seq_term(&node->pidxStatus);
-		node->shouldCallHashSeqTerm = false;
-	}
-
 	MemoryContextDelete(node->partitionMemoryContext);
 }
 
@@ -332,47 +309,8 @@ ExecReScanDynamicIndex(DynamicIndexScanState *node)
 		node->indexScanState = NULL;
 	}
 	node->scan_state = SCAN_INIT;
-
-	if (node->shouldCallHashSeqTerm)
-	{
-		hash_seq_term(&node->pidxStatus);
-		node->shouldCallHashSeqTerm = false;
-	}
-
-	/* Force reloading the hash table */
-	node->pidxIndex = NULL;
-}
-
-
-/*
- * IndexScan_MapLogicalIndexInfo
- *             Remaps the columns of the expressions of a provided logicalIndexInfo
- *             using attMap for a given varno.
- *
- *             Returns true if mapping was done.
- */
-bool
-IndexScan_MapLogicalIndexInfo(LogicalIndexInfo *logicalIndexInfo, AttrNumber *attMap, Index varno)
-{
-	if (NULL == attMap)
-	{
-		/* Columns are already aligned, and therefore, no mapping is necessary */
-		return false;
-	}
-	/* map the attrnos if necessary */
-	for (int i = 0; i < logicalIndexInfo->nColumns; i++)
-	{
-		if (logicalIndexInfo->indexKeys[i] != 0)
-		{
-			logicalIndexInfo->indexKeys[i] = attMap[(logicalIndexInfo->indexKeys[i]) - 1];
-		}
-	}
-
-	/* map the attrnos in the indExprs and indPred */
-	change_varattnos_of_a_varno((Node *)logicalIndexInfo->indPred, attMap, varno);
-	change_varattnos_of_a_varno((Node *)logicalIndexInfo->indExprs, attMap, varno);
-
-	return true;
+	// reset partition internal state
+	node->whichPart = -1;
 }
 
 /*
@@ -388,7 +326,7 @@ IndexScan_GetColumnMapping(Oid oldOid, Oid newOid)
 	if (oldOid == newOid)
 		return NULL;
 
-	AttrNumber      *attMap;
+	AttrNumber	  *attMap;
 
 	Relation oldRel = heap_open(oldOid, AccessShareLock);
 	Relation newRel = heap_open(newOid, AccessShareLock);
@@ -396,7 +334,7 @@ IndexScan_GetColumnMapping(Oid oldOid, Oid newOid)
 	TupleDesc oldTupDesc = oldRel->rd_att;
 	TupleDesc newTupDesc = newRel->rd_att;
 
-	attMap = varattnos_map(oldTupDesc, newTupDesc);
+	attMap = convert_tuples_by_name_map_if_req(oldTupDesc, newTupDesc, "unused msg");
 
 	heap_close(oldRel, AccessShareLock);
 	heap_close(newRel, AccessShareLock);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 690f80970b..77e6cee0ee 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -911,8 +911,22 @@ ExecIndexRestrPos(IndexScanState *node)
 IndexScanState *
 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 {
-	IndexScanState *indexstate;
 	Relation	currentRelation;
+
+	/*
+	 * open the base relation and acquire appropriate lock on it.
+	 */
+	currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
+
+	return ExecInitIndexScanForPartition(node, estate, eflags,
+	                                     currentRelation, node->indexid);
+}
+
+IndexScanState *
+ExecInitIndexScanForPartition(IndexScan *node, EState *estate, int eflags,
+	                          Relation currentRelation, Oid indexid)
+{
+	IndexScanState *indexstate;
 	LOCKMODE	lockmode;
 
 	/*
@@ -930,11 +944,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 	 */
 	ExecAssignExprContext(estate, &indexstate->ss.ps);
 
-	/*
-	 * open the scan relation
-	 */
-	currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
-
 	indexstate->ss.ss_currentRelation = currentRelation;
 	indexstate->ss.ss_currentScanDesc = NULL;	/* no heap scan here */
 
@@ -962,11 +971,11 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 	 * in the expression must be found now...)
 	 */
 	indexstate->ss.ps.qual =
-		ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
+			ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
 	indexstate->indexqualorig =
-		ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
+			ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
 	indexstate->indexorderbyorig =
-		ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
+			ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
 
 	/*
 	 * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
@@ -978,7 +987,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 
 	/* Open the index relation. */
 	lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
-	indexstate->iss_RelationDesc = index_open(node->indexid, lockmode);
+	indexstate->iss_RelationDesc = index_open(indexid, lockmode);
 
 	/*
 	 * Initialize index-specific scan state
@@ -1030,11 +1039,11 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 		Assert(numOrderByKeys == list_length(node->indexorderbyops));
 		Assert(numOrderByKeys == list_length(node->indexorderbyorig));
 		indexstate->iss_SortSupport = (SortSupportData *)
-			palloc0(numOrderByKeys * sizeof(SortSupportData));
+				palloc0(numOrderByKeys * sizeof(SortSupportData));
 		indexstate->iss_OrderByTypByVals = (bool *)
-			palloc(numOrderByKeys * sizeof(bool));
+				palloc(numOrderByKeys * sizeof(bool));
 		indexstate->iss_OrderByTypLens = (int16 *)
-			palloc(numOrderByKeys * sizeof(int16));
+				palloc(numOrderByKeys * sizeof(int16));
 		i = 0;
 		forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
 		{
@@ -1063,9 +1072,9 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 
 		/* allocate arrays to hold the re-calculated distances */
 		indexstate->iss_OrderByValues = (Datum *)
-			palloc(numOrderByKeys * sizeof(Datum));
+				palloc(numOrderByKeys * sizeof(Datum));
 		indexstate->iss_OrderByNulls = (bool *)
-			palloc(numOrderByKeys * sizeof(bool));
+				palloc(numOrderByKeys * sizeof(bool));
 
 		/* and initialize the reorder queue */
 		indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
index 7ddfcfccaf..425e05f55e 100644
--- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
@@ -66,6 +66,7 @@ extern "C" {
 #include "naucrates/dxl/operators/CDXLPhysicalCTEConsumer.h"
 #include "naucrates/dxl/operators/CDXLPhysicalCTEProducer.h"
 #include "naucrates/dxl/operators/CDXLPhysicalDynamicBitmapTableScan.h"
+#include "naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h"
 #include "naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h"
 #include "naucrates/dxl/operators/CDXLPhysicalGatherMotion.h"
 #include "naucrates/dxl/operators/CDXLPhysicalHashJoin.h"
@@ -430,7 +431,12 @@ CTranslatorDXLToPlStmt::TranslateDXLOperatorToPlan(
 										  ctxt_translation_prev_siblings);
 			break;
 		}
-		/* case EdxlopPhysicalDynamicIndexScan: { plan = TranslateDXLDynIdxScan(dxlnode, output_context, ctxt_translation_prev_siblings); break;} */
+		case EdxlopPhysicalDynamicIndexScan:
+		{
+			plan = TranslateDXLDynIdxScan(dxlnode, output_context,
+										  ctxt_translation_prev_siblings);
+			break;
+		}
 		case EdxlopPhysicalTVF:
 		{
 			plan = TranslateDXLTvf(dxlnode, output_context,
@@ -4106,12 +4112,130 @@ CTranslatorDXLToPlStmt::TranslateDXLDynTblScan(
 		&plan->targetlist, &plan->qual, output_context);
 
 	SetParamIds(plan);
-	/*
-	 * 	auto *prune_result = m_dxl_to_plstmt_context->GetStaticPruneResult(
-		dyn_tbl_scan_dxlop->GetPartIndexIdPrintable());
 
-	dyn_seq_scan->partOids = prune_result;
-*/
+	return plan;
+}
+
+//---------------------------------------------------------------------------
+//	@function:
+//		CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan
+//
+//	@doc:
+//		Translates a DXL dynamic index scan node into a DynamicIndexScan node
+//
+//---------------------------------------------------------------------------
+Plan *
+CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan(
+	const CDXLNode *dyn_idx_scan_dxlnode, CDXLTranslateContext *output_context,
+	CDXLTranslationContextArray *ctxt_translation_prev_siblings)
+{
+	CDXLPhysicalDynamicIndexScan *dyn_index_scan_dxlop =
+		CDXLPhysicalDynamicIndexScan::Cast(dyn_idx_scan_dxlnode->GetOperator());
+
+	// translation context for column mappings in the base relation
+	CDXLTranslateContextBaseTable base_table_context(m_mp);
+
+	Index index =
+		gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
+
+	const IMDRelation *md_rel = m_md_accessor->RetrieveRel(
+		dyn_index_scan_dxlop->GetDXLTableDescr()->MDId());
+	RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
+		dyn_index_scan_dxlop->GetDXLTableDescr(), index, &base_table_context);
+	GPOS_ASSERT(NULL != rte);
+	rte->requiredPerms |= ACL_SELECT;
+	m_dxl_to_plstmt_context->AddRTE(rte);
+
+	DynamicIndexScan *dyn_idx_scan = MakeNode(DynamicIndexScan);
+
+	dyn_idx_scan->indexscan.scan.scanrelid = index;
+
+	IMdIdArray *parts = dyn_index_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_idx_scan->partOids = oids_list;
+
+	dyn_idx_scan->join_prune_paramids = NIL;
+
+	OID oid_type =
+		CMDIdGPDB::CastMdid(m_md_accessor->PtMDType<IMDTypeInt4>()->MDId())
+			->Oid();
+	const ULongPtrArray *selector_ids = dyn_index_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_idx_scan->join_prune_paramids =
+			gpdb::LAppendInt(dyn_idx_scan->join_prune_paramids, param_id);
+	}
+
+	CMDIdGPDB *mdid_index =
+		CMDIdGPDB::CastMdid(dyn_index_scan_dxlop->GetDXLIndexDescr()->MDId());
+	const IMDIndex *md_index = m_md_accessor->RetrieveIndex(mdid_index);
+	Oid index_oid = mdid_index->Oid();
+
+	GPOS_ASSERT(InvalidOid != index_oid);
+	dyn_idx_scan->indexscan.indexid = index_oid;
+
+	Plan *plan = &(dyn_idx_scan->indexscan.scan.plan);
+	plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
+
+	// translate operator costs
+	TranslatePlanCosts(dyn_idx_scan_dxlnode, plan);
+
+	// an index scan node must have 3 children: projection list, filter and index condition list
+	GPOS_ASSERT(3 == dyn_idx_scan_dxlnode->Arity());
+
+	// translate proj list and filter
+	CDXLNode *project_list_dxlnode = (*dyn_idx_scan_dxlnode)
+		[CDXLPhysicalDynamicIndexScan::EdxldisIndexProjList];
+	CDXLNode *filter_dxlnode = (*dyn_idx_scan_dxlnode)
+		[CDXLPhysicalDynamicIndexScan::EdxldisIndexFilter];
+	CDXLNode *index_cond_list_dxlnode = (*dyn_idx_scan_dxlnode)
+		[CDXLPhysicalDynamicIndexScan::EdxldisIndexCondition];
+
+	// translate proj list
+	plan->targetlist =
+		TranslateDXLProjList(project_list_dxlnode, &base_table_context,
+							 NULL /*child_contexts*/, output_context);
+
+	// translate index filter
+	plan->qual = TranslateDXLIndexFilter(filter_dxlnode, output_context,
+										 &base_table_context,
+										 ctxt_translation_prev_siblings);
+
+	dyn_idx_scan->indexscan.indexorderdir = CTranslatorUtils::GetScanDirection(
+		dyn_index_scan_dxlop->GetIndexScanDir());
+
+	// translate index condition list
+	List *index_cond = NIL;
+	List *index_orig_cond = NIL;
+	List *index_strategy_list = NIL;
+	List *index_subtype_list = NIL;
+
+	TranslateIndexConditions(
+		index_cond_list_dxlnode, dyn_index_scan_dxlop->GetDXLTableDescr(),
+		false,	// is_bitmap_index_probe
+		md_index, md_rel, output_context, &base_table_context,
+		ctxt_translation_prev_siblings, &index_cond, &index_orig_cond,
+		&index_strategy_list, &index_subtype_list);
+
+
+	dyn_idx_scan->indexscan.indexqual = index_cond;
+	dyn_idx_scan->indexscan.indexqualorig = index_orig_cond;
+
+	SetParamIds(plan);
+
+	return (Plan *) dyn_idx_scan;
 }
 //---------------------------------------------------------------------------
 //	@function:
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
index bca5ff694a..efc6c873a4 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
@@ -101,6 +101,8 @@
 #include "naucrates/dxl/operators/CDXLPhysicalCTAS.h"
 #include "naucrates/dxl/operators/CDXLPhysicalCTEConsumer.h"
 #include "naucrates/dxl/operators/CDXLPhysicalCTEProducer.h"
+#include "naucrates/dxl/operators/CDXLPhysicalDynamicBitmapTableScan.h"
+#include "naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h"
 #include "naucrates/dxl/operators/CDXLPhysicalDynamicTableScan.h"
 #include "naucrates/dxl/operators/CDXLPhysicalExternalScan.h"
 #include "naucrates/dxl/operators/CDXLPhysicalGatherMotion.h"
@@ -1577,140 +1579,97 @@ CTranslatorExprToDXL::PdxlnDynamicIndexScan(
 	CExpression *pexprDIS, CColRefArray *colref_array,
 	CDXLPhysicalProperties *dxl_properties, CReqdPropPlan *prpp)
 {
-	GPOS_ASSERT(nullptr != pexprDIS);
-	GPOS_ASSERT(nullptr != dxl_properties);
-	GPOS_ASSERT(nullptr != prpp);
+	GPOS_ASSERT(NULL != pexprDIS);
+	GPOS_ASSERT(NULL != dxl_properties);
+	GPOS_ASSERT(NULL != prpp);
 
 	CPhysicalDynamicIndexScan *popDIS =
 		CPhysicalDynamicIndexScan::PopConvert(pexprDIS->Pop());
+	CColRefArray *pdrgpcrOutput = popDIS->PdrgpcrOutput();
 
-	// construct projection list
-	CColRefSet *pcrsOutput = prpp->PcrsRequired();
-	CDXLNode *pdxlnPrLAppend = PdxlnProjList(pcrsOutput, colref_array);
-
-	IMdIdArray *part_mdids = popDIS->GetPartitionMdids();
+	// translate table descriptor
+	CDXLTableDescr *table_descr =
+		MakeDXLTableDescr(popDIS->Ptabdesc(), pdrgpcrOutput, pexprDIS->Prpp());
 
-	CDXLNode *pdxlnResult = GPOS_NEW(m_mp)
-		CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLPhysicalAppend(m_mp, false, false));
-	// GPDB_12_MERGE_FIXME: set plan costs
-	pdxlnResult->SetProperties(dxl_properties);
-	pdxlnResult->AddChild(pdxlnPrLAppend);
-	pdxlnResult->AddChild(PdxlnFilter(nullptr));
+	// create index descriptor
+	CIndexDescriptor *pindexdesc = popDIS->Pindexdesc();
+	CMDName *pmdnameIndex =
+		GPOS_NEW(m_mp) CMDName(m_mp, pindexdesc->Name().Pstr());
+	IMDId *pmdidIndex = pindexdesc->MDId();
+	pmdidIndex->AddRef();
+	CDXLIndexDescr *dxl_index_descr =
+		GPOS_NEW(m_mp) CDXLIndexDescr(pmdidIndex, pmdnameIndex);
 
-	// construct set of child indexes from parent list of child indexes
-	IMDId *pmdidIndex = popDIS->Pindexdesc()->MDId();
-	const IMDIndex *md_index = m_pmda->RetrieveIndex(pmdidIndex);
-	IMdIdArray *child_indexes = md_index->ChildIndexMdids();
 
-	MdidHashSet *child_index_mdids_set = GPOS_NEW(m_mp) MdidHashSet(m_mp);
-	for (ULONG ul = 0; ul < child_indexes->Size(); ul++)
-	{
-		(*child_indexes)[ul]->AddRef();
-		child_index_mdids_set->Insert((*child_indexes)[ul]);
-	}
+	// construct dynamic table scan operator
+	IMdIdArray *part_mdids = popDIS->GetPartitionMdids();
+	part_mdids->AddRef();
 
-	for (ULONG ul = 0; ul < part_mdids->Size(); ++ul)
+	ULongPtrArray *selector_ids = GPOS_NEW(m_mp) ULongPtrArray(m_mp);
+	CPartitionPropagationSpec *pps_reqd = prpp->Pepp()->PppsRequired();
+	if (pps_reqd->Contains(popDIS->ScanId()))
 	{
-		IMDId *part_mdid = (*part_mdids)[ul];
-		const IMDRelation *part = m_pmda->RetrieveRel(part_mdid);
-
-		CPhysicalDynamicIndexScan *popDIS =
-			CPhysicalDynamicIndexScan::PopConvert(pexprDIS->Pop());
-
-		// GPDB_12_MERGE_FIXME: ideally MakeTableDescForPart(part, pexprDIS->DeriveTableDescriptor());
-		// should just work, at this point all properties should've been derived, but we
-		// haven't derived the table descriptor.
-		CTableDescriptor *part_tabdesc =
-			MakeTableDescForPart(part, popDIS->Ptabdesc());
-
-		// create new colrefs for every child partition
-		CColRefArray *part_colrefs = GPOS_NEW(m_mp) CColRefArray(m_mp);
-		for (ULONG ul = 0; ul < part_tabdesc->ColumnCount(); ++ul)
+		const CBitSet *bs = pps_reqd->SelectorIds(popDIS->ScanId());
+		CBitSetIter bsi(*bs);
+		for (ULONG ul = 0; bsi.Advance(); ul++)
 		{
-			const CColumnDescriptor *cd = part_tabdesc->Pcoldesc(ul);
-			CColRef *cr = m_pcf->PcrCreate(cd->RetrieveType(),
-										   cd->TypeModifier(), cd->Name());
-			part_colrefs->Append(cr);
+			selector_ids->Append(GPOS_NEW(m_mp) ULONG(bsi.Bit()));
 		}
+	}
 
-		CDXLTableDescr *dxl_table_descr =
-			MakeDXLTableDescr(part_tabdesc, part_colrefs, pexprDIS->Prpp());
-		part_tabdesc->Release();
-
-		CIndexDescriptor *pindexdesc = popDIS->Pindexdesc();
-		CDXLIndexDescr *dxl_index_descr = PdxlnIndexDescForPart(
-			m_mp, child_index_mdids_set, part, pindexdesc->Name().Pstr());
+	// TODO: we assume that the index are always forward access.
 
-		// Finally create the IndexScan DXL node
-		CDXLNode *dxlnode = GPOS_NEW(m_mp) CDXLNode(
-			m_mp, GPOS_NEW(m_mp) CDXLPhysicalIndexScan(
-					  m_mp, dxl_table_descr, dxl_index_descr, EdxlisdForward));
+	CDXLNode *pdxlnDIS = GPOS_NEW(m_mp)
+		CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLPhysicalDynamicIndexScan(
+						   m_mp, table_descr, dxl_index_descr, EdxlisdForward,
+						   part_mdids, selector_ids));
 
-		// GPDB_12_MERGE_FIXME: Compute stats & properties per scan
-		dxl_properties->AddRef();
-		dxlnode->SetProperties(dxl_properties);
+	// set plan costs
+	pdxlnDIS->SetProperties(dxl_properties);
 
-		// construct projection list
-		auto root_col_mapping = (*popDIS->GetRootColMappingPerPart())[ul];
+	// construct projection list
+	CColRefSet *pcrsOutput = prpp->PcrsRequired();
+	CDXLNode *pdxlnPrL = PdxlnProjList(pcrsOutput, colref_array);
 
-		CDXLNode *pdxlnPrL = PdxlnProjListForChildPart(
-			root_col_mapping, part_colrefs, pcrsOutput, colref_array);
-		dxlnode->AddChild(pdxlnPrL);  // project list
+	// translate index predicates
+	CExpression *pexprCond = (*pexprDIS)[0];
+	CDXLNode *pdxlnIndexCondList = GPOS_NEW(m_mp)
+		CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarIndexCondList(m_mp));
 
-		CDXLNode *filter_dxlnode;
-		if (2 == pexprDIS->Arity())
-		{
-			// translate residual predicates into the filter node
-			CExpression *pexprResidualCond = (*pexprDIS)[1];
+	CExpressionArray *pdrgpexprConds =
+		CPredicateUtils::PdrgpexprConjuncts(m_mp, pexprCond);
+	const ULONG length = pdrgpexprConds->Size();
+	for (ULONG ul = 0; ul < length; ul++)
+	{
+		CExpression *pexprIndexCond = (*pdrgpexprConds)[ul];
+		CDXLNode *pdxlnIndexCond = PdxlnScalar(pexprIndexCond);
+		pdxlnIndexCondList->AddChild(pdxlnIndexCond);
+	}
+	pdrgpexprConds->Release();
 
-			if (COperator::EopScalarConst != pexprResidualCond->Pop()->Eopid())
-			{
-				// construct the filter
-				filter_dxlnode = PdxlnFilter(PdxlnCondForChildPart(
-					root_col_mapping, part_colrefs, popDIS->PdrgpcrOutput(),
-					pexprResidualCond));
-			}
-			else
-			{
-				filter_dxlnode = PdxlnFilter(nullptr);
-			}
-		}
-		else
+	CDXLNode *pdxlnResidualCond = NULL;
+	if (2 == pexprDIS->Arity())
+	{
+		// translate residual predicates into the filter node
+		CExpression *pexprResidualCond = (*pexprDIS)[1];
+		if (COperator::EopScalarConst != pexprResidualCond->Pop()->Eopid())
 		{
-			// construct an empty filter
-			filter_dxlnode = PdxlnFilter(nullptr);
+			pdxlnResidualCond = PdxlnScalar(pexprResidualCond);
 		}
-		dxlnode->AddChild(filter_dxlnode);	// filter
-
-		// translate index predicates
-		CExpression *pexprCond = (*pexprDIS)[0];
-		CDXLNode *pdxlnIndexCondList = GPOS_NEW(m_mp)
-			CDXLNode(m_mp, GPOS_NEW(m_mp) CDXLScalarIndexCondList(m_mp));
+	}
 
-		CExpressionArray *pdrgpexprConds =
-			CPredicateUtils::PdrgpexprConjuncts(m_mp, pexprCond);
-		const ULONG length = pdrgpexprConds->Size();
-		for (ULONG ul = 0; ul < length; ul++)
-		{
-			CExpression *pexprIndexCond = (*pdrgpexprConds)[ul];
-			// construct the condition as a filter
-			CDXLNode *pdxlnIndexCond =
-				PdxlnCondForChildPart(root_col_mapping, part_colrefs,
-									  popDIS->PdrgpcrOutput(), pexprIndexCond);
-			pdxlnIndexCondList->AddChild(pdxlnIndexCond);
-		}
-		pdrgpexprConds->Release();
-		dxlnode->AddChild(pdxlnIndexCondList);
+	CDXLNode *filter_dxlnode = PdxlnFilter(pdxlnResidualCond);
 
-		// add to the other scans under the created Append node
-		pdxlnResult->AddChild(dxlnode);
+	pdxlnDIS->AddChild(pdxlnPrL);
+	pdxlnDIS->AddChild(filter_dxlnode);
+	pdxlnDIS->AddChild(pdxlnIndexCondList);
 
-		// cleanup
-		part_colrefs->Release();
-	}
-	child_index_mdids_set->Release();
+#ifdef GPOS_DEBUG
+	pdxlnDIS->GetOperator()->AssertValid(pdxlnDIS,
+										 false /* validate_children */);
+#endif
 
-	return pdxlnResult;
+	return pdxlnDIS;
 }
 
 
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h
index bc1c8bf081..14d3bded7e 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.h
@@ -35,18 +35,16 @@ private:
 	// table descriptor for the scanned table
 	CDXLTableDescr *m_dxl_table_descr;
 
-	// part index id
-	ULONG m_part_index_id;
-
-	// printable partition index id
-	ULONG m_part_index_id_printable;
-
 	// index descriptor associated with the scanned table
 	CDXLIndexDescr *m_dxl_index_descr;
 
 	// scan direction of the index
 	EdxlIndexScanDirection m_index_scan_dir;
 
+	IMdIdArray *m_part_mdids;
+
+	ULongPtrArray *m_selector_ids = nullptr;
+
 public:
 	CDXLPhysicalDynamicIndexScan(CDXLPhysicalDynamicIndexScan &) = delete;
 
@@ -61,9 +59,10 @@ public:
 
 	//ctor
 	CDXLPhysicalDynamicIndexScan(CMemoryPool *mp, CDXLTableDescr *table_descr,
-								 ULONG part_idx_id, ULONG part_idx_id_printable,
 								 CDXLIndexDescr *dxl_index_descr,
-								 EdxlIndexScanDirection idx_scan_direction);
+								 EdxlIndexScanDirection idx_scan_direction,
+								 IMdIdArray *part_mdids,
+								 ULongPtrArray *selector_ids);
 
 	//dtor
 	~CDXLPhysicalDynamicIndexScan() override;
@@ -80,15 +79,17 @@ public:
 	//table descriptor
 	const CDXLTableDescr *GetDXLTableDescr() const;
 
-	// partition index id
-	ULONG GetPartIndexId() const;
-
-	// printable partition index id
-	ULONG GetPartIndexIdPrintable() const;
-
 	// scan direction
 	EdxlIndexScanDirection GetIndexScanDir() 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/CParseHandlerDynamicIndexScan.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicIndexScan.h
index b5a2738e39..e173af8c8b 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicIndexScan.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerDynamicIndexScan.h
@@ -35,11 +35,7 @@ XERCES_CPP_NAMESPACE_USE
 class CParseHandlerDynamicIndexScan : public CParseHandlerIndexScan
 {
 private:
-	// part index id
-	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/include/naucrates/dxl/parser/CParseHandlerIndexScan.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerIndexScan.h
index e1fcba1232..3c6a873084 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerIndexScan.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerIndexScan.h
@@ -60,8 +60,8 @@ protected:
 
 	// common EndElement functionality for IndexScan and IndexOnlyScan
 	void EndElementHelper(const XMLCh *const element_local_name,
-						  Edxltoken token_type, ULONG part_idx_id = 0,
-						  ULONG part_idx_id_printable = 0);
+						  Edxltoken token_type,
+						  ULongPtrArray *selector_ids = nullptr);
 
 public:
 	CParseHandlerIndexScan(const CParseHandlerIndexScan &) = delete;
diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicIndexScan.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicIndexScan.cpp
index dbcb9439a1..e8e1a0ecd4 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicIndexScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDynamicIndexScan.cpp
@@ -11,8 +11,10 @@
 
 #include "naucrates/dxl/operators/CDXLPhysicalDynamicIndexScan.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;
@@ -27,15 +29,15 @@ using namespace gpdxl;
 //
 //---------------------------------------------------------------------------
 CDXLPhysicalDynamicIndexScan::CDXLPhysicalDynamicIndexScan(
-	CMemoryPool *mp, CDXLTableDescr *table_descr, ULONG part_idx_id,
-	ULONG part_idx_id_printable, CDXLIndexDescr *dxl_index_descr,
-	EdxlIndexScanDirection idx_scan_direction)
+	CMemoryPool *mp, CDXLTableDescr *table_descr,
+	CDXLIndexDescr *dxl_index_descr, EdxlIndexScanDirection idx_scan_direction,
+	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_dxl_index_descr(dxl_index_descr),
-	  m_index_scan_dir(idx_scan_direction)
+	  m_index_scan_dir(idx_scan_direction),
+	  m_part_mdids(part_mdids),
+	  m_selector_ids(selector_ids)
 {
 	GPOS_ASSERT(nullptr != m_dxl_table_descr);
 	GPOS_ASSERT(nullptr != m_dxl_index_descr);
@@ -53,6 +55,8 @@ CDXLPhysicalDynamicIndexScan::~CDXLPhysicalDynamicIndexScan()
 {
 	m_dxl_index_descr->Release();
 	m_dxl_table_descr->Release();
+	m_part_mdids->Release();
+	CRefCount::SafeRelease(m_selector_ids);
 }
 
 //---------------------------------------------------------------------------
@@ -125,32 +129,10 @@ CDXLPhysicalDynamicIndexScan::GetDXLTableDescr() const
 	return m_dxl_table_descr;
 }
 
-//---------------------------------------------------------------------------
-//	@function:
-//		CDXLPhysicalDynamicIndexScan::GetPartIndexId
-//
-//	@doc:
-//		Part index id
-//
-//---------------------------------------------------------------------------
-ULONG
-CDXLPhysicalDynamicIndexScan::GetPartIndexId() const
-{
-	return m_part_index_id;
-}
-
-//---------------------------------------------------------------------------
-//	@function:
-//		CDXLPhysicalDynamicIndexScan::GetPartIndexIdPrintable
-//
-//	@doc:
-//		Printable partition index id
-//
-//---------------------------------------------------------------------------
-ULONG
-CDXLPhysicalDynamicIndexScan::GetPartIndexIdPrintable() const
+IMdIdArray *
+CDXLPhysicalDynamicIndexScan::GetParts() const
 {
-	return m_part_index_id_printable;
+	return m_part_mdids;
 }
 
 //---------------------------------------------------------------------------
@@ -173,14 +155,12 @@ CDXLPhysicalDynamicIndexScan::SerializeToDXL(CXMLSerializer *xml_serializer,
 		CDXLTokens::GetDXLTokenStr(EdxltokenIndexScanDirection),
 		CDXLOperator::GetIdxScanDirectionStr(m_index_scan_dir));
 
+	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);
 
 	// serialize properties
 	node->SerializePropertiesToDXL(xml_serializer);
@@ -188,6 +168,12 @@ CDXLPhysicalDynamicIndexScan::SerializeToDXL(CXMLSerializer *xml_serializer,
 	// serialize children
 	node->SerializeChildrenToDXL(xml_serializer);
 
+	// serialize partition mdids
+	IMDCacheObject::SerializeMDIdList(
+		xml_serializer, m_part_mdids,
+		CDXLTokens::GetDXLTokenStr(EdxltokenPartitions),
+		CDXLTokens::GetDXLTokenStr(EdxltokenPartition));
+
 	// serialize index descriptor
 	m_dxl_index_descr->SerializeToDXL(xml_serializer);
 
diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalIndexScan.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalIndexScan.cpp
index 1424fabdca..38e6308e3e 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalIndexScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalIndexScan.cpp
@@ -13,6 +13,7 @@
 
 #include "naucrates/dxl/operators/CDXLNode.h"
 #include "naucrates/dxl/xml/CXMLSerializer.h"
+#include "naucrates/md/IMDCacheObject.h"
 
 using namespace gpos;
 using namespace gpdxl;
@@ -148,6 +149,12 @@ CDXLPhysicalIndexScan::SerializeToDXL(CXMLSerializer *xml_serializer,
 	// serialize children
 	node->SerializeChildrenToDXL(xml_serializer);
 
+	// serialize partition mdids (null in this case)
+	IMdIdArray *empty = GPOS_NEW(m_mp) IMdIdArray(m_mp);
+	IMDCacheObject::SerializeMDIdList(
+		xml_serializer, empty, CDXLTokens::GetDXLTokenStr(EdxltokenPartitions),
+		CDXLTokens::GetDXLTokenStr(EdxltokenPartition));
+	empty->Release();
 	// serialize index descriptor
 	m_dxl_index_descr->SerializeToDXL(xml_serializer);
 
diff --git a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicIndexScan.cpp b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicIndexScan.cpp
index 48983c8b73..ea511e20de 100644
--- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicIndexScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerDynamicIndexScan.cpp
@@ -43,9 +43,7 @@ XERCES_CPP_NAMESPACE_USE
 CParseHandlerDynamicIndexScan::CParseHandlerDynamicIndexScan(
 	CMemoryPool *mp, CParseHandlerManager *parse_handler_mgr,
 	CParseHandlerBase *parse_handler_root)
-	: CParseHandlerIndexScan(mp, parse_handler_mgr, parse_handler_root),
-	  m_part_index_id(0),
-	  m_part_index_id_printable(0)
+	: CParseHandlerIndexScan(mp, parse_handler_mgr, parse_handler_root)
 {
 }
 
@@ -67,14 +65,9 @@ CParseHandlerDynamicIndexScan::StartElement(
 	StartElementHelper(element_local_name, attrs,
 					   EdxltokenPhysicalDynamicIndexScan);
 
-	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,
 		EdxltokenPhysicalDynamicIndexScan);
-	m_part_index_id_printable =
-		CDXLOperatorFactory::ExtractConvertAttrValueToUlong(
-			m_parse_handler_mgr->GetDXLMemoryManager(), attrs,
-			EdxltokenPartIndexIdPrintable, EdxltokenPhysicalDynamicIndexScan,
-			true /*is_optional*/, m_part_index_id);
 }
 
 //---------------------------------------------------------------------------
@@ -92,7 +85,7 @@ CParseHandlerDynamicIndexScan::EndElement(const XMLCh *const,  // element_uri,
 )
 {
 	EndElementHelper(element_local_name, EdxltokenPhysicalDynamicIndexScan,
-					 m_part_index_id, m_part_index_id_printable);
+					 m_selector_ids /*m_selector_ids*/);
 }
 
 
diff --git a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexOnlyScan.cpp b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexOnlyScan.cpp
index 30fe0fc3ab..c46f789260 100644
--- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexOnlyScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexOnlyScan.cpp
@@ -68,7 +68,8 @@ CParseHandlerIndexOnlyScan::EndElement(const XMLCh *const,	// element_uri,
 									   const XMLCh *const  // element_qname
 )
 {
-	EndElementHelper(element_local_name, EdxltokenPhysicalIndexOnlyScan);
+	EndElementHelper(element_local_name, EdxltokenPhysicalIndexOnlyScan,
+					 nullptr);
 }
 
 // EOF
diff --git a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexScan.cpp b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexScan.cpp
index b4d6282442..becb70f640 100644
--- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexScan.cpp
+++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerIndexScan.cpp
@@ -24,6 +24,7 @@
 #include "naucrates/dxl/parser/CParseHandlerFilter.h"
 #include "naucrates/dxl/parser/CParseHandlerIndexCondList.h"
 #include "naucrates/dxl/parser/CParseHandlerIndexDescr.h"
+#include "naucrates/dxl/parser/CParseHandlerMetadataIdList.h"
 #include "naucrates/dxl/parser/CParseHandlerProjList.h"
 #include "naucrates/dxl/parser/CParseHandlerProperties.h"
 #include "naucrates/dxl/parser/CParseHandlerScalarOp.h"
@@ -129,6 +130,12 @@ CParseHandlerIndexScan::StartElementHelper(
 			m_parse_handler_mgr, this);
 	m_parse_handler_mgr->ActivateParseHandler(index_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 index condition list
 	CParseHandlerBase *index_condition_list_parse_handler =
 		CParseHandlerFactory::GetParseHandler(
@@ -163,6 +170,7 @@ CParseHandlerIndexScan::StartElementHelper(
 	this->Append(proj_list_parse_handler);
 	this->Append(filter_parse_handler);
 	this->Append(index_condition_list_parse_handler);
+	this->Append(partition_mdids_parse_handler);
 	this->Append(index_descr_parse_handler);
 	this->Append(table_descr_parse_handler);
 }
@@ -178,8 +186,7 @@ CParseHandlerIndexScan::StartElementHelper(
 void
 CParseHandlerIndexScan::EndElementHelper(const XMLCh *const element_local_name,
 										 Edxltoken token_type,
-										 ULONG part_idx_id,
-										 ULONG part_idx_id_printable)
+										 ULongPtrArray *selector_ids)
 {
 	if (0 != XMLString::compareString(CDXLTokens::XmlstrToken(token_type),
 									  element_local_name))
@@ -199,10 +206,12 @@ CParseHandlerIndexScan::EndElementHelper(const XMLCh *const element_local_name,
 		dynamic_cast<CParseHandlerFilter *>((*this)[2]);
 	CParseHandlerIndexCondList *index_condition_list_parse_handler =
 		dynamic_cast<CParseHandlerIndexCondList *>((*this)[3]);
+	CParseHandlerMetadataIdList *partition_mdids_parse_handler =
+		dynamic_cast<CParseHandlerMetadataIdList *>((*this)[4]);
 	CParseHandlerIndexDescr *index_descr_parse_handler =
-		dynamic_cast<CParseHandlerIndexDescr *>((*this)[4]);
+		dynamic_cast<CParseHandlerIndexDescr *>((*this)[5]);
 	CParseHandlerTableDescr *table_descr_parse_handler =
-		dynamic_cast<CParseHandlerTableDescr *>((*this)[5]);
+		dynamic_cast<CParseHandlerTableDescr *>((*this)[6]);
 
 	CDXLTableDescr *dxl_table_descr =
 		table_descr_parse_handler->GetDXLTableDescr();
@@ -229,9 +238,12 @@ CParseHandlerIndexScan::EndElementHelper(const XMLCh *const element_local_name,
 	{
 		GPOS_ASSERT(EdxltokenPhysicalDynamicIndexScan == token_type);
 
+		IMdIdArray *mdid_partitions_array =
+			partition_mdids_parse_handler->GetMdIdArray();
+		mdid_partitions_array->AddRef();
 		dxl_op = GPOS_NEW(m_mp) CDXLPhysicalDynamicIndexScan(
-			m_mp, dxl_table_descr, part_idx_id, part_idx_id_printable,
-			dxl_index_descr, m_index_scan_dir);
+			m_mp, dxl_table_descr, dxl_index_descr, m_index_scan_dir,
+			mdid_partitions_array, selector_ids);
 		m_dxl_node = GPOS_NEW(m_mp) CDXLNode(m_mp, dxl_op);
 	}
 
diff --git a/src/include/executor/nodeDynamicIndexscan.h b/src/include/executor/nodeDynamicIndexscan.h
index 2fdf08d594..64e9045423 100644
--- a/src/include/executor/nodeDynamicIndexscan.h
+++ b/src/include/executor/nodeDynamicIndexscan.h
@@ -16,15 +16,11 @@
 
 #include "nodes/execnodes.h"
 
-/* GPDB_12_MERGE_FIXME */
-#if 0
 extern DynamicIndexScanState *ExecInitDynamicIndexScan(DynamicIndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecDynamicIndexScan(DynamicIndexScanState *node);
+extern TupleTableSlot *ExecDynamicIndexScan(PlanState *node);
 extern void ExecEndDynamicIndexScan(DynamicIndexScanState *node);
 extern void ExecReScanDynamicIndex(DynamicIndexScanState *node);
 
-extern bool IndexScan_MapLogicalIndexInfo(LogicalIndexInfo *logicalIndexInfo, AttrNumber *attMap, Index varno);
 extern AttrNumber *IndexScan_GetColumnMapping(Oid oldOid, Oid newOid);
-#endif
 
 #endif
diff --git a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
index c157850e51..dbb7662904 100644
--- a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
+++ b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
@@ -342,12 +342,12 @@ private:
 	);
 
 	// translate a dynamic index scan operator
-	/* Plan *TranslateDXLDynIdxScan */
-	/* 	( */
-	/* 	const CDXLNode *dyn_idx_scan_dxlnode, */
-	/* 	CDXLTranslateContext *output_context, */
-	/* 	CDXLTranslationContextArray *ctxt_translation_prev_siblings // translation contexts of previous siblings */
-	/* 	); */
+	Plan *TranslateDXLDynIdxScan(
+		const CDXLNode *dyn_idx_scan_dxlnode,
+		CDXLTranslateContext *output_context,
+		CDXLTranslationContextArray *
+			ctxt_translation_prev_siblings	// translation contexts of previous siblings
+	);
 
 	// translate a DML operator
 	Plan *TranslateDXLDml(


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