diff --git a/src/backend/executor/nodeDML.c b/src/backend/executor/nodeDML.c
index 33b2edf5387f..d7ba9cea7d15 100644
--- a/src/backend/executor/nodeDML.c
+++ b/src/backend/executor/nodeDML.c
@@ -57,6 +57,7 @@ ExecDML(DMLState *node)
{
return NULL;
}
+ EvalPlanQualSetSlot(&node->dml_epqstate, slot);
bool isnull = false;
int action = DatumGetUInt32(slot_getattr(slot, plannode->actionColIdx, &isnull));
@@ -145,7 +146,7 @@ ExecDML(DMLState *node)
segid,
NULL, /* GPDB_91_MERGE_FIXME: oldTuple? */
node->cleanedUpSlot,
- NULL /* DestReceiver */,
+ &node->dml_epqstate,
node->ps.state,
!isUpdate, /* GPDB_91_MERGE_FIXME: where to get canSetTag? */
PLANGEN_OPTIMIZER /* Plan origin */,
@@ -177,6 +178,8 @@ ExecInitDML(DML *node, EState *estate, int eflags)
CmdType operation = estate->es_plannedstmt->commandType;
ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
+ EvalPlanQualInit(&dmlstate->dml_epqstate, NULL, NULL, NIL, node->epqParam);
+
ExecInitResultTupleSlot(estate, &dmlstate->ps);
dmlstate->ps.targetlist = (List *)
@@ -184,6 +187,7 @@ ExecInitDML(DML *node, EState *estate, int eflags)
(PlanState *) dmlstate);
Plan *outerPlan = outerPlan(node);
+ EvalPlanQualSetPlan(&dmlstate->dml_epqstate, outerPlan, NULL);
outerPlanState(dmlstate) = ExecInitNode(outerPlan, estate, eflags);
/*
@@ -279,6 +283,7 @@ ExecEndDML(DMLState *node)
ExecFreeExprContext(&node->ps);
ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecClearTuple(node->cleanedUpSlot);
+ EvalPlanQualEnd(&node->dml_epqstate);
ExecEndNode(outerPlanState(node));
EndPlanStateGpmonPkt(&node->ps);
}
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 24ad14a3afde..e7eb74284405 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -961,17 +961,6 @@ ldelete:;
{
TupleTableSlot *epqslot;
- /*
- * TODO: DML node doesn't initialize `epqstate` parameter so
- * we exclude EPQ routine for this type of modification and
- * act as in RR and upper isolation levels.
- */
- if (!epqstate)
- ereport(ERROR,
- (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
- errmsg("could not serialize access due to concurrent update"),
- errhint("Use PostgreSQL Planner instead of Optimizer for this query via optimizer=off GUC setting")));
-
epqslot = EvalPlanQual(estate,
epqstate,
resultRelationDesc,
diff --git a/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp b/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
index 2ee1f329c8ba..2462059a14b7 100644
--- a/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
@@ -60,6 +60,7 @@ CContextDXLToPlStmt::CContextDXLToPlStmt(
{
m_cte_consumer_info = GPOS_NEW(m_mp) HMUlCTEConsumerInfo(m_mp);
m_num_partition_selectors_array = GPOS_NEW(m_mp) ULongPtrArray(m_mp);
+ m_used_rte_indexes = GPOS_NEW(m_mp) HMUlIndex(m_mp);
}
//---------------------------------------------------------------------------
@@ -74,6 +75,7 @@ CContextDXLToPlStmt::~CContextDXLToPlStmt()
{
m_cte_consumer_info->Release();
m_num_partition_selectors_array->Release();
+ m_used_rte_indexes->Release();
}
//---------------------------------------------------------------------------
@@ -462,4 +464,79 @@ CContextDXLToPlStmt::GetDistributionHashFuncForType(Oid typid)
return hashproc;
}
+RangeTblEntry *
+CContextDXLToPlStmt::GetRTEByIndex(Index index)
+{
+ return (RangeTblEntry *) gpdb::ListNth(*(m_rtable_entries_list),
+ int(index - 1));
+}
+
+//---------------------------------------------------------------------------
+// @function: of associated
+// CContextDXLToPlStmt::GetRTEIndexByTableDescr
+//
+// @doc:
+//
+// For given table descriptor this function returns index of rte in
+// m_rtable_entries_list for furhter processing and set a flag that
+// rte was processed.
+// In case of DML operations there is more than one table descr pointing
+// to the result relation and to detect position of already processed rte
+// `assigned_query_id_for_target_rel` of table descriptor is used.
+//---------------------------------------------------------------------------
+Index
+CContextDXLToPlStmt::GetRTEIndexByTableDescr(const CDXLTableDescr *table_descr,
+ BOOL *is_rte_exists)
+{
+ *is_rte_exists = false;
+
+ // `assigned_query_id_for_target_rel` is a "tag" of table descriptors, it
+ // shows id of query structure which contains result relation. If table
+ // descriptors have the same `assigned_query_id_for_target_rel` - these
+ // table descriptors point to the same result relation in `ModifyTable`
+ // operation. It's not zero (0) value (which equal to `UNASSIGNED_QUERYID`
+ // define) if: user query is a INSERT/UPDATE/DELETE (`ModifyTable`
+ // operation) and this table descriptor points to the result relation of
+ // operation, for ex.:
+ // ```sql
+ // create table b (i int, j int);
+ // create table c (i int);
+ // insert into b(i,j) values (1,2), (2,3), (3,4);
+ // insert into c(i) values (1), (2);
+ // delete from b where i in (select i from c);
+ // ```
+ // where `b` is a result relation (table descriptors pointing to it
+ // will have the same `assigned_query_id_for_target_rel` > 0), and
+ // `c` is not (all table descriptors which points to `c` will have
+ // `assigned_query_id_for_target_rel`=0 (equal to `UNASSIGNED_QUERYID`)
+ ULONG assigned_query_id_for_target_rel =
+ table_descr->GetAssignedQueryIdForTargetRel();
+ if (assigned_query_id_for_target_rel == UNASSIGNED_QUERYID)
+ {
+ return gpdb::ListLength(*(m_rtable_entries_list)) + 1;
+ }
+
+ Index *usedIndex =
+ m_used_rte_indexes->Find(&assigned_query_id_for_target_rel);
+
+ // `usedIndex` is a non NULL value in next case: table descriptor with
+ // the same `assigned_query_id_for_target_rel` was processed previously
+ // (so no need to create a new index for result relation like the relation
+ // itself)
+ if (usedIndex)
+ {
+ *is_rte_exists = true;
+ return *usedIndex;
+ }
+
+ // `assigned_query_id_for_target_rel` of table descriptor which points to
+ // result relation wasn't previously processed - create a new index.
+ Index new_index = gpdb::ListLength(*(m_rtable_entries_list)) + 1;
+ m_used_rte_indexes->Insert(GPOS_NEW(m_mp)
+ ULONG(assigned_query_id_for_target_rel),
+ GPOS_NEW(m_mp) Index(new_index));
+
+ return new_index;
+}
+
// EOF
diff --git a/src/backend/gpopt/translate/CContextQueryToDXL.cpp b/src/backend/gpopt/translate/CContextQueryToDXL.cpp
index 7cbd795fc742..7dc5630ff6f1 100644
--- a/src/backend/gpopt/translate/CContextQueryToDXL.cpp
+++ b/src/backend/gpopt/translate/CContextQueryToDXL.cpp
@@ -28,11 +28,19 @@ CContextQueryToDXL::CContextQueryToDXL(CMemoryPool *mp)
{
// map that stores gpdb att to optimizer col mapping
m_colid_counter = GPOS_NEW(mp) CIdGenerator(GPDXL_COL_ID_START);
+ m_queryid_counter = GPOS_NEW(mp) CIdGenerator(GPDXL_QUERY_ID_START);
m_cte_id_counter = GPOS_NEW(mp) CIdGenerator(GPDXL_CTE_ID_START);
}
CContextQueryToDXL::~CContextQueryToDXL()
{
+ GPOS_DELETE(m_queryid_counter);
GPOS_DELETE(m_colid_counter);
GPOS_DELETE(m_cte_id_counter);
}
+
+ULONG
+CContextQueryToDXL::GetNextQueryId()
+{
+ return m_queryid_counter->next_id();
+}
diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
index 878f638d2180..f3f8878aef2a 100644
--- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
@@ -484,19 +484,13 @@ CTranslatorDXLToPlStmt::TranslateDXLTblScan(
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
- // we will add the new range table entry as the last element of the range table
- Index index =
- gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
-
const CDXLTableDescr *dxl_table_descr =
phy_tbl_scan_dxlop->GetDXLTableDescr();
const IMDRelation *md_rel =
m_md_accessor->RetrieveRel(dxl_table_descr->MDId());
- RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
- dxl_table_descr, index, &base_table_context);
- GPOS_ASSERT(NULL != rte);
- rte->requiredPerms |= ACL_SELECT;
- m_dxl_to_plstmt_context->AddRTE(rte);
+
+ Index index =
+ ProcessDXLTblDescr(dxl_table_descr, &base_table_context, ACL_SELECT);
Plan *plan = NULL;
Plan *plan_return = NULL;
@@ -658,18 +652,13 @@ CTranslatorDXLToPlStmt::TranslateDXLIndexScan(
// 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(
- physical_idx_scan_dxlop->GetDXLTableDescr()->MDId());
+ const CDXLTableDescr *dxl_table_descr =
+ physical_idx_scan_dxlop->GetDXLTableDescr();
+ const IMDRelation *md_rel =
+ m_md_accessor->RetrieveRel(dxl_table_descr->MDId());
- RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
- physical_idx_scan_dxlop->GetDXLTableDescr(), index,
- &base_table_context);
- GPOS_ASSERT(NULL != rte);
- rte->requiredPerms |= ACL_SELECT;
- m_dxl_to_plstmt_context->AddRTE(rte);
+ Index index =
+ ProcessDXLTblDescr(dxl_table_descr, &base_table_context, ACL_SELECT);
IndexScan *index_scan = NULL;
index_scan = MakeNode(IndexScan);
@@ -800,18 +789,11 @@ CTranslatorDXLToPlStmt::TranslateDXLIndexOnlyScan(
// 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(
physical_idx_scan_dxlop->GetDXLTableDescr()->MDId());
- RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
- physical_idx_scan_dxlop->GetDXLTableDescr(), index,
- &base_table_context);
- GPOS_ASSERT(NULL != rte);
- rte->requiredPerms |= ACL_SELECT;
- m_dxl_to_plstmt_context->AddRTE(rte);
+ Index index =
+ ProcessDXLTblDescr(table_desc, &base_table_context, ACL_SELECT);
IndexOnlyScan *index_scan = MakeNode(IndexOnlyScan);
index_scan->scan.scanrelid = index;
@@ -3944,16 +3926,8 @@ CTranslatorDXLToPlStmt::TranslateDXLDynTblScan(
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
- // add the new range table entry as the last element of the range table
- Index index =
- gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
-
- RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
- dyn_tbl_scan_dxlop->GetDXLTableDescr(), index, &base_table_context);
- GPOS_ASSERT(NULL != rte);
- rte->requiredPerms |= ACL_SELECT;
-
- m_dxl_to_plstmt_context->AddRTE(rte);
+ Index index = ProcessDXLTblDescr(dyn_tbl_scan_dxlop->GetDXLTableDescr(),
+ &base_table_context, ACL_SELECT);
// create dynamic scan node
DynamicSeqScan *dyn_seq_scan = MakeNode(DynamicSeqScan);
@@ -4011,16 +3985,11 @@ CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan(
// 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 CDXLTableDescr *table_desc = dyn_index_scan_dxlop->GetDXLTableDescr();
+ const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_desc->MDId());
- 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);
+ Index index =
+ ProcessDXLTblDescr(table_desc, &base_table_context, ACL_SELECT);
DynamicIndexScan *dyn_idx_scan = MakeNode(DynamicIndexScan);
@@ -4033,9 +4002,12 @@ CTranslatorDXLToPlStmt::TranslateDXLDynIdxScan(
CMDIdGPDB::CastMdid(dyn_index_scan_dxlop->GetDXLIndexDescr()->MDId());
const IMDIndex *md_index = m_md_accessor->RetrieveIndex(mdid_index);
Oid index_oid = mdid_index->Oid();
+ RangeTblEntry *rte = m_dxl_to_plstmt_context->GetRTEByIndex(index);
GPOS_ASSERT(InvalidOid != index_oid);
dyn_idx_scan->indexscan.indexid = index_oid;
+
+ GPOS_ASSERT(NULL != rte);
dyn_idx_scan->logicalIndexInfo =
gpdb::GetLogicalIndexInfo(rte->relid, index_oid);
@@ -4161,22 +4133,17 @@ CTranslatorDXLToPlStmt::TranslateDXLDml(
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
- // add the new range table entry as the last element of the range table
- Index index =
- gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
- dml->scanrelid = index;
-
- m_result_rel_list = gpdb::LAppendInt(m_result_rel_list, index);
+ CDXLTableDescr *table_descr = phy_dml_dxlop->GetDXLTableDescr();
const IMDRelation *md_rel =
m_md_accessor->RetrieveRel(phy_dml_dxlop->GetDXLTableDescr()->MDId());
- CDXLTableDescr *table_descr = phy_dml_dxlop->GetDXLTableDescr();
- RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
- table_descr, index, &base_table_context);
- GPOS_ASSERT(NULL != rte);
- rte->requiredPerms |= acl_mode;
- m_dxl_to_plstmt_context->AddRTE(rte);
+ Index index =
+ ProcessDXLTblDescr(table_descr, &base_table_context, acl_mode);
+
+ dml->scanrelid = index;
+
+ m_result_rel_list = gpdb::LAppendInt(m_result_rel_list, index);
CDXLNode *project_list_dxlnode = (*dml_dxlnode)[0];
CDXLNode *child_dxlnode = (*dml_dxlnode)[1];
@@ -4234,6 +4201,7 @@ CTranslatorDXLToPlStmt::TranslateDXLDml(
plan->lefttree = child_plan;
plan->nMotionNodes = child_plan->nMotionNodes;
plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId();
+ dml->epqParam = m_dxl_to_plstmt_context->GetNextParamId();
if (CMD_INSERT == m_cmd_type && 0 == plan->nMotionNodes)
{
@@ -4656,40 +4624,74 @@ CTranslatorDXLToPlStmt::TranslateDXLRowTrigger(
//---------------------------------------------------------------------------
// @function:
-// CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry
+// CTranslatorDXLToPlStmt::ProcessDXLTblDescr
//
// @doc:
-// Translates a DXL table descriptor into a range table entry. If an index
-// descriptor is provided, we use the mapping from colids to index attnos
-// instead of table attnos
-//
-//---------------------------------------------------------------------------
-RangeTblEntry *
-CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry(
- const CDXLTableDescr *table_descr, Index index,
- CDXLTranslateContextBaseTable *base_table_context)
+// Translates a DXL table descriptor into a range table entry and stores
+// it in m_dxl_to_plstmt_context if it's needed (in case of DML operations
+// there is more than one table descriptors which point to the result
+// relation, so if rte was alredy translated, this rte will be updated and
+// index of this rte at m_dxl_to_plstmt_context->m_rtable_entries_list
+// (shortened as "rte_list"), will be returned, if the rte wasn't
+// translated, the newly created rte will be appended to rte_list and it's
+// index returned). Also this function fills base_table_context for the
+// mapping from colids to index attnos instead of table attnos.
+// Returns index of translated range table entry at the rte_list.
+//
+//---------------------------------------------------------------------------
+Index
+CTranslatorDXLToPlStmt::ProcessDXLTblDescr(
+ const CDXLTableDescr *table_descr,
+ CDXLTranslateContextBaseTable *base_table_context, AclMode acl_mode)
{
GPOS_ASSERT(NULL != table_descr);
+ BOOL rte_was_translated = false;
+ Index index = m_dxl_to_plstmt_context->GetRTEIndexByTableDescr(
+ table_descr, &rte_was_translated);
+
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
const ULONG num_of_non_sys_cols =
CTranslatorUtils::GetNumNonSystemColumns(md_rel);
- RangeTblEntry *rte = MakeNode(RangeTblEntry);
- rte->rtekind = RTE_RELATION;
-
// get oid for table
Oid oid = CMDIdGPDB::CastMdid(table_descr->MDId())->Oid();
GPOS_ASSERT(InvalidOid != oid);
- rte->relid = oid;
- rte->checkAsUser = table_descr->GetExecuteAsUserId();
- rte->requiredPerms |= ACL_NO_RIGHTS;
-
// save oid and range index in translation context
base_table_context->SetOID(oid);
base_table_context->SetRelIndex(index);
+ // save mapping col id -> index in translate context
+ const ULONG arity = table_descr->Arity();
+ for (ULONG ul = 0; ul < arity; ++ul)
+ {
+ const CDXLColDescr *dxl_col_descr = table_descr->GetColumnDescrAt(ul);
+ GPOS_ASSERT(NULL != dxl_col_descr);
+
+ INT attno = dxl_col_descr->AttrNum();
+ GPOS_ASSERT(0 != attno);
+
+ (void) base_table_context->InsertMapping(dxl_col_descr->Id(), attno);
+ }
+
+ // descriptor was already processed, and translated RTE is stored at
+ // context rtable list (only update required perms of this rte is needed)
+ if (rte_was_translated)
+ {
+ RangeTblEntry *rte = m_dxl_to_plstmt_context->GetRTEByIndex(index);
+ GPOS_ASSERT(NULL != rte);
+ rte->requiredPerms |= acl_mode;
+ return index;
+ }
+
+ // create a new RTE (and it's alias) and store it at context rtable list
+ RangeTblEntry *rte = MakeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = oid;
+ rte->checkAsUser = table_descr->GetExecuteAsUserId();
+ rte->requiredPerms |= acl_mode;
+
Alias *alias = MakeNode(Alias);
alias->colnames = NIL;
@@ -4698,19 +4700,12 @@ CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry(
table_descr->MdName()->GetMDName()->GetBuffer());
// get column names
- const ULONG arity = table_descr->Arity();
-
INT last_attno = 0;
-
for (ULONG ul = 0; ul < arity; ++ul)
{
const CDXLColDescr *dxl_col_descr = table_descr->GetColumnDescrAt(ul);
- GPOS_ASSERT(NULL != dxl_col_descr);
-
INT attno = dxl_col_descr->AttrNum();
- GPOS_ASSERT(0 != attno);
-
if (0 < attno)
{
// if attno > last_attno + 1, there were dropped attributes
@@ -4732,9 +4727,6 @@ CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry(
alias->colnames = gpdb::LAppend(alias->colnames, val_colname);
last_attno = attno;
}
-
- // save mapping col id -> index in translate context
- (void) base_table_context->InsertMapping(dxl_col_descr->Id(), attno);
}
// if there are any dropped columns at the end, add those too to the RangeTblEntry
@@ -4746,7 +4738,9 @@ CTranslatorDXLToPlStmt::TranslateDXLTblDescrToRangeTblEntry(
rte->eref = alias;
- return rte;
+ m_dxl_to_plstmt_context->AddRTE(rte);
+
+ return index;
}
//---------------------------------------------------------------------------
@@ -5691,18 +5685,10 @@ CTranslatorDXLToPlStmt::TranslateDXLBitmapTblScan(
// translation context for column mappings in the base relation
CDXLTranslateContextBaseTable base_table_context(m_mp);
- // add the new range table entry as the last element of the range table
- Index index =
- gpdb::ListLength(m_dxl_to_plstmt_context->GetRTableEntriesList()) + 1;
-
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
- RangeTblEntry *rte = TranslateDXLTblDescrToRangeTblEntry(
- table_descr, index, &base_table_context);
- GPOS_ASSERT(NULL != rte);
- rte->requiredPerms |= ACL_SELECT;
-
- m_dxl_to_plstmt_context->AddRTE(rte);
+ Index index =
+ ProcessDXLTblDescr(table_descr, &base_table_context, ACL_SELECT);
BitmapHeapScan *bitmap_tbl_scan;
diff --git a/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp b/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp
index 2292c777e9de..fbbd19bcf7cc 100644
--- a/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp
+++ b/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp
@@ -117,6 +117,8 @@ CTranslatorQueryToDXL::CTranslatorQueryToDXL(
GPOS_ASSERT(NULL != query);
CheckSupportedCmdType(query);
+ m_query_id = m_context->GetNextQueryId();
+
CheckRangeTable(query);
// GPDB_94_MERGE_FIXME: WITH CHECK OPTION views are not supported yet.
@@ -710,9 +712,10 @@ CTranslatorQueryToDXL::TranslateInsertQueryToDXL()
m_query->rtable, m_query->resultRelation - 1);
CDXLTableDescr *table_descr = CTranslatorUtils::GetTableDescr(
- m_mp, m_md_accessor, m_context->m_colid_counter, rte,
+ m_mp, m_md_accessor, m_context->m_colid_counter, rte, m_query_id,
&m_context->m_has_distributed_tables,
&m_context->m_has_replicated_tables);
+
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
if (!optimizer_enable_dml_triggers &&
CTranslatorUtils::RelHasTriggers(m_mp, m_md_accessor, md_rel,
@@ -1186,7 +1189,7 @@ CTranslatorQueryToDXL::TranslateDeleteQueryToDXL()
m_query->rtable, m_query->resultRelation - 1);
CDXLTableDescr *table_descr = CTranslatorUtils::GetTableDescr(
- m_mp, m_md_accessor, m_context->m_colid_counter, rte,
+ m_mp, m_md_accessor, m_context->m_colid_counter, rte, m_query_id,
&m_context->m_has_distributed_tables,
&m_context->m_has_replicated_tables);
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
@@ -1260,7 +1263,7 @@ CTranslatorQueryToDXL::TranslateUpdateQueryToDXL()
m_query->rtable, m_query->resultRelation - 1);
CDXLTableDescr *table_descr = CTranslatorUtils::GetTableDescr(
- m_mp, m_md_accessor, m_context->m_colid_counter, rte,
+ m_mp, m_md_accessor, m_context->m_colid_counter, rte, m_query_id,
&m_context->m_has_distributed_tables,
&m_context->m_has_replicated_tables);
const IMDRelation *md_rel = m_md_accessor->RetrieveRel(table_descr->MDId());
@@ -3247,10 +3250,20 @@ CTranslatorQueryToDXL::TranslateRTEToDXLLogicalGet(const RangeTblEntry *rte,
GPOS_WSZ_LIT("ONLY in the FROM clause"));
}
+ // query_id_for_target_rel is used to tag table descriptors assigned to target
+ // (result) relations one. In case of possible nested DML subqueries it's
+ // field points to target relation of corresponding Query structure of subquery.
+ ULONG query_id_for_target_rel = UNASSIGNED_QUERYID;
+ if (m_query->resultRelation > 0 &&
+ ULONG(m_query->resultRelation) == rt_index)
+ {
+ query_id_for_target_rel = m_query_id;
+ }
+
// construct table descriptor for the scan node from the range table entry
CDXLTableDescr *dxl_table_descr = CTranslatorUtils::GetTableDescr(
m_mp, m_md_accessor, m_context->m_colid_counter, rte,
- &m_context->m_has_distributed_tables,
+ query_id_for_target_rel, &m_context->m_has_distributed_tables,
&m_context->m_has_replicated_tables);
CDXLLogicalGet *dxl_op = NULL;
diff --git a/src/backend/gpopt/translate/CTranslatorUtils.cpp b/src/backend/gpopt/translate/CTranslatorUtils.cpp
index 53709414eb0e..f1721a0420b5 100644
--- a/src/backend/gpopt/translate/CTranslatorUtils.cpp
+++ b/src/backend/gpopt/translate/CTranslatorUtils.cpp
@@ -109,8 +109,9 @@ CDXLTableDescr *
CTranslatorUtils::GetTableDescr(CMemoryPool *mp, CMDAccessor *md_accessor,
CIdGenerator *id_generator,
const RangeTblEntry *rte,
- BOOL *is_distributed_table, // output
- BOOL *is_replicated_table // output
+ ULONG assigned_query_id_for_target_rel,
+ BOOL *is_distributed_table, // output
+ BOOL *is_replicated_table // output
)
{
// generate an MDId for the table desc.
@@ -134,7 +135,8 @@ CTranslatorUtils::GetTableDescr(CMemoryPool *mp, CMDAccessor *md_accessor,
CMDName *table_mdname = GPOS_NEW(mp) CMDName(mp, tablename);
CDXLTableDescr *table_descr =
- GPOS_NEW(mp) CDXLTableDescr(mp, mdid, table_mdname, rte->checkAsUser);
+ GPOS_NEW(mp) CDXLTableDescr(mp, mdid, table_mdname, rte->checkAsUser,
+ assigned_query_id_for_target_rel);
const ULONG len = rel->ColumnCount();
diff --git a/src/backend/gporca/data/dxl/minidump/Delete-Check-AssignedQueryIdForTargetRel.mdp b/src/backend/gporca/data/dxl/minidump/Delete-Check-AssignedQueryIdForTargetRel.mdp
new file mode 100644
index 000000000000..1e79ec3a93f5
--- /dev/null
+++ b/src/backend/gporca/data/dxl/minidump/Delete-Check-AssignedQueryIdForTargetRel.mdp
@@ -0,0 +1,455 @@
+
+
+ 10);
+
+ Physical plan:
+
+ QUERY PLAN
+---------------------------------------------------------------------------------------------------------
+ Delete (cost=0.00..862.02 rows=1 width=1)
+ -> Result (cost=0.00..862.00 rows=1 width=18)
+ -> Hash Semi Join (cost=0.00..862.00 rows=1 width=14)
+ Hash Cond: (test.i = test_1.i)
+ -> Seq Scan on test (cost=0.00..431.00 rows=1 width=14)
+ -> Hash (cost=431.00..431.00 rows=1 width=4)
+ -> Broadcast Motion 3:3 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=4)
+ -> Seq Scan on test test_1 (cost=0.00..431.00 rows=1 width=4)
+ Filter: (i > 10)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(10 rows)
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/libgpopt/include/gpopt/metadata/CTableDescriptor.h b/src/backend/gporca/libgpopt/include/gpopt/metadata/CTableDescriptor.h
index d18c204aa51f..04f7b3532da4 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/metadata/CTableDescriptor.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/metadata/CTableDescriptor.h
@@ -97,13 +97,20 @@ class CTableDescriptor : public CRefCount,
// returns true if this table descriptor has partial indexes
BOOL FDescriptorWithPartialIndexes();
+ // identifier of query to which current table belongs.
+ // This field is used for assigning current table entry with
+ // target one within DML operation. If descriptor doesn't point
+ // to the target (result) relation it has value UNASSIGNED_QUERYID
+ ULONG m_assigned_query_id_for_target_rel;
+
public:
// ctor
CTableDescriptor(CMemoryPool *, IMDId *mdid, const CName &,
BOOL convert_hash_to_random,
IMDRelation::Ereldistrpolicy rel_distr_policy,
IMDRelation::Erelstoragetype erelstoragetype,
- ULONG ulExecuteAsUser);
+ ULONG ulExecuteAsUser,
+ ULONG assigned_query_id_for_target_rel);
// dtor
virtual ~CTableDescriptor();
@@ -239,6 +246,12 @@ class CTableDescriptor : public CRefCount,
m_erelstoragetype == IMDRelation::ErelstorageAppendOnlyRows;
}
+ ULONG
+ GetAssignedQueryIdForTargetRel() const
+ {
+ return m_assigned_query_id_for_target_rel;
+ }
+
}; // class CTableDescriptor
} // namespace gpopt
diff --git a/src/backend/gporca/libgpopt/src/metadata/CTableDescriptor.cpp b/src/backend/gporca/libgpopt/src/metadata/CTableDescriptor.cpp
index d3c5bcb0425a..a5b11f9104ae 100644
--- a/src/backend/gporca/libgpopt/src/metadata/CTableDescriptor.cpp
+++ b/src/backend/gporca/libgpopt/src/metadata/CTableDescriptor.cpp
@@ -37,7 +37,8 @@ FORCE_GENERATE_DBGSTR(CTableDescriptor);
CTableDescriptor::CTableDescriptor(
CMemoryPool *mp, IMDId *mdid, const CName &name,
BOOL convert_hash_to_random, IMDRelation::Ereldistrpolicy rel_distr_policy,
- IMDRelation::Erelstoragetype erelstoragetype, ULONG ulExecuteAsUser)
+ IMDRelation::Erelstoragetype erelstoragetype, ULONG ulExecuteAsUser,
+ ULONG assigned_query_id_for_target_rel)
: m_mp(mp),
m_mdid(mdid),
m_name(mp, name),
@@ -51,7 +52,8 @@ CTableDescriptor::CTableDescriptor(
m_pdrgpbsKeys(NULL),
m_num_of_partitions(0),
m_execute_as_user_id(ulExecuteAsUser),
- m_fHasPartialIndexes(FDescriptorWithPartialIndexes())
+ m_fHasPartialIndexes(FDescriptorWithPartialIndexes()),
+ m_assigned_query_id_for_target_rel(assigned_query_id_for_target_rel)
{
GPOS_ASSERT(NULL != mp);
GPOS_ASSERT(mdid->IsValid());
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
index ef2edaa9015c..d9348b7beace 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
@@ -2099,7 +2099,8 @@ CTranslatorDXLToExpr::Ptabdesc(CDXLTableDescr *table_descr)
mdid->AddRef();
CTableDescriptor *ptabdesc = GPOS_NEW(m_mp) CTableDescriptor(
m_mp, mdid, CName(m_mp, &strName), pmdrel->ConvertHashToRandom(),
- rel_distr_policy, rel_storage_type, table_descr->GetExecuteAsUserId());
+ rel_distr_policy, rel_storage_type, table_descr->GetExecuteAsUserId(),
+ table_descr->GetAssignedQueryIdForTargetRel());
const ULONG ulColumns = table_descr->Arity();
for (ULONG ul = 0; ul < ulColumns; ul++)
@@ -2298,8 +2299,8 @@ CTranslatorDXLToExpr::PtabdescFromCTAS(CDXLLogicalCTAS *pdxlopCTAS)
CTableDescriptor *ptabdesc = GPOS_NEW(m_mp) CTableDescriptor(
m_mp, mdid, CName(m_mp, &strName), pmdrel->ConvertHashToRandom(),
rel_distr_policy, rel_storage_type,
- 0 // TODO: - Mar 5, 2014; ulExecuteAsUser
- );
+ 0, // TODO: - Mar 5, 2014; ulExecuteAsUser
+ UNASSIGNED_QUERYID);
// populate column information from the dxl table descriptor
CDXLColDescrArray *dxl_col_descr_array =
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
index 3748a6f6f589..b5c2a3b858bc 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
@@ -1365,7 +1365,8 @@ CTranslatorExprToDXL::PdxlnMultiExternalScan(
m_mp, extpart_mdid, extpart->Mdname().GetMDName(),
extpart->ConvertHashToRandom(), extpart->GetRelDistribution(),
extpart->RetrieveRelStorageType(),
- multi_extscan->Ptabdesc()->GetExecuteAsUserId());
+ multi_extscan->Ptabdesc()->GetExecuteAsUserId(),
+ multi_extscan->Ptabdesc()->GetAssignedQueryIdForTargetRel());
// Each scan shares the same col descriptors as the parent partitioned table
// FIXME: Dropped columns break the assumption above. Handle it correctly.
@@ -7569,7 +7570,8 @@ CTranslatorExprToDXL::MakeDXLTableDescr(const CTableDescriptor *ptabdesc,
mdid->AddRef();
CDXLTableDescr *table_descr = GPOS_NEW(m_mp)
- CDXLTableDescr(m_mp, mdid, pmdnameTbl, ptabdesc->GetExecuteAsUserId());
+ CDXLTableDescr(m_mp, mdid, pmdnameTbl, ptabdesc->GetExecuteAsUserId(),
+ ptabdesc->GetAssignedQueryIdForTargetRel());
const ULONG ulColumns = ptabdesc->ColumnCount();
// translate col descriptors
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLTableDescr.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLTableDescr.h
index 360b5f8841f7..f247aa87965c 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLTableDescr.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLTableDescr.h
@@ -20,6 +20,9 @@
#include "naucrates/md/CMDName.h"
#include "naucrates/md/IMDId.h"
+// default value for m_assigned_query_id_for_target_rel - no assigned query for table descriptor
+#define UNASSIGNED_QUERYID 0
+
namespace gpdxl
{
using namespace gpmd;
@@ -53,12 +56,19 @@ class CDXLTableDescr : public CRefCount
// private copy ctor
CDXLTableDescr(const CDXLTableDescr &);
+ // identifier of query to which current table belongs.
+ // This field is used for assigning current table entry with
+ // target one within DML operation. If descriptor doesn't point
+ // to the target (result) relation it has value UNASSIGNED_QUERYID
+ ULONG m_assigned_query_id_for_target_rel;
+
void SerializeMDId(CXMLSerializer *xml_serializer) const;
public:
// ctor/dtor
CDXLTableDescr(CMemoryPool *mp, IMDId *mdid, CMDName *mdname,
- ULONG ulExecuteAsUser);
+ ULONG ulExecuteAsUser,
+ ULONG assigned_query_id_for_target_rel = UNASSIGNED_QUERYID);
virtual ~CDXLTableDescr();
@@ -84,6 +94,9 @@ class CDXLTableDescr : public CRefCount
// serialize to dxl format
void SerializeToDXL(CXMLSerializer *xml_serializer) const;
+
+ // get assigned query id for target relation
+ ULONG GetAssignedQueryIdForTargetRel() const;
};
} // namespace gpdxl
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
index 8e3435be4841..4b90c6266d64 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
@@ -462,6 +462,7 @@ enum Edxltoken
EdxltokenIsNull,
EdxltokenLintValue,
EdxltokenDoubleValue,
+ EdxltokenAssignedQueryIdForTargetRel,
EdxltokenRelTemporary,
EdxltokenRelHasOids,
diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp
index 4a989408426a..18c0dd743301 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLOperatorFactory.cpp
@@ -1479,7 +1479,12 @@ CDXLOperatorFactory::MakeDXLTableDescr(CDXLMemoryManager *dxl_memory_manager,
EdxltokenTableDescr);
}
- return GPOS_NEW(mp) CDXLTableDescr(mp, mdid, mdname, user_id);
+ ULONG assigned_query_id_for_target_rel = ExtractConvertAttrValueToUlong(
+ dxl_memory_manager, attrs, EdxltokenAssignedQueryIdForTargetRel,
+ EdxltokenTableDescr, true /* is_optional */, UNASSIGNED_QUERYID);
+
+ return GPOS_NEW(mp) CDXLTableDescr(mp, mdid, mdname, user_id,
+ assigned_query_id_for_target_rel);
}
//---------------------------------------------------------------------------
diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLTableDescr.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLTableDescr.cpp
index 302b8ef1cc1d..91027851ec7c 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLTableDescr.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLTableDescr.cpp
@@ -30,12 +30,14 @@ using namespace gpdxl;
//
//---------------------------------------------------------------------------
CDXLTableDescr::CDXLTableDescr(CMemoryPool *mp, IMDId *mdid, CMDName *mdname,
- ULONG ulExecuteAsUser)
+ ULONG ulExecuteAsUser,
+ ULONG assigned_query_id_for_target_rel)
: m_mp(mp),
m_mdid(mdid),
m_mdname(mdname),
m_dxl_column_descr_array(NULL),
- m_execute_as_user_id(ulExecuteAsUser)
+ m_execute_as_user_id(ulExecuteAsUser),
+ m_assigned_query_id_for_target_rel(assigned_query_id_for_target_rel)
{
GPOS_ASSERT(NULL != m_mdname);
m_dxl_column_descr_array = GPOS_NEW(mp) CDXLColDescrArray(mp);
@@ -205,6 +207,13 @@ CDXLTableDescr::SerializeToDXL(CXMLSerializer *xml_serializer) const
m_execute_as_user_id);
}
+ if (UNASSIGNED_QUERYID != m_assigned_query_id_for_target_rel)
+ {
+ xml_serializer->AddAttribute(
+ CDXLTokens::GetDXLTokenStr(EdxltokenAssignedQueryIdForTargetRel),
+ m_assigned_query_id_for_target_rel);
+ }
+
// serialize columns
xml_serializer->OpenElement(
CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix),
@@ -227,4 +236,21 @@ CDXLTableDescr::SerializeToDXL(CXMLSerializer *xml_serializer) const
CDXLTokens::GetDXLTokenStr(EdxltokenTableDescr));
}
+
+//---------------------------------------------------------------------------
+// @function:
+// CDXLTableDescr::GetAssignedQueryIdForTargetRel
+//
+// @doc:
+// Return id of query, to which TableDescr belongs to
+// (if this descriptor points to a result (target) entry,
+// else UNASSIGNED_QUERYID returned)
+//
+//---------------------------------------------------------------------------
+ULONG
+CDXLTableDescr::GetAssignedQueryIdForTargetRel() const
+{
+ return m_assigned_query_id_for_target_rel;
+}
+
// EOF
diff --git a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
index b6737f18a344..3b57f8265ab5 100644
--- a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
+++ b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
@@ -510,6 +510,8 @@ CDXLTokens::Init(CMemoryPool *mp)
{EdxltokenIsNull, GPOS_WSZ_LIT("IsNull")},
{EdxltokenLintValue, GPOS_WSZ_LIT("LintValue")},
{EdxltokenDoubleValue, GPOS_WSZ_LIT("DoubleValue")},
+ {EdxltokenAssignedQueryIdForTargetRel,
+ GPOS_WSZ_LIT("AssignedQueryIdForTargetRel")},
{EdxltokenRelTemporary, GPOS_WSZ_LIT("IsTemporary")},
{EdxltokenRelHasOids, GPOS_WSZ_LIT("HasOids")},
diff --git a/src/backend/gporca/server/src/unittest/CTestUtils.cpp b/src/backend/gporca/server/src/unittest/CTestUtils.cpp
index 2e298aa58772..1004f1b4f7b7 100644
--- a/src/backend/gporca/server/src/unittest/CTestUtils.cpp
+++ b/src/backend/gporca/server/src/unittest/CTestUtils.cpp
@@ -196,7 +196,8 @@ CTestUtils::PtabdescPlainWithColNameFormat(
mp, mdid, nameTable,
false, // convert_hash_to_random
IMDRelation::EreldistrRandom, IMDRelation::ErelstorageHeap,
- 0 // ulExecuteAsUser
+ 0, // ulExecuteAsUser
+ 0 // UNASSIGNED_QUERYID
);
for (ULONG i = 0; i < num_cols; i++)
diff --git a/src/backend/gporca/server/src/unittest/dxl/statistics/CStatisticsTest.cpp b/src/backend/gporca/server/src/unittest/dxl/statistics/CStatisticsTest.cpp
index ff2c4f5f1c9e..d167b9dd91ea 100644
--- a/src/backend/gporca/server/src/unittest/dxl/statistics/CStatisticsTest.cpp
+++ b/src/backend/gporca/server/src/unittest/dxl/statistics/CStatisticsTest.cpp
@@ -316,7 +316,8 @@ CStatisticsTest::PtabdescTwoColumnSource(CMemoryPool *mp,
mp, GPOS_NEW(mp) CMDIdGPDB(GPOPT_TEST_REL_OID1, 1, 1), nameTable,
false, // convert_hash_to_random
IMDRelation::EreldistrRandom, IMDRelation::ErelstorageHeap,
- 0 // ulExecuteAsUser
+ 0, // ulExecuteAsUser
+ 0 // UNASSIGNED_QUERYID
);
for (ULONG i = 0; i < 2; i++)
diff --git a/src/backend/gporca/server/src/unittest/gpopt/minidump/CDMLTest.cpp b/src/backend/gporca/server/src/unittest/gpopt/minidump/CDMLTest.cpp
index c125388cf79a..cfcbef929c66 100644
--- a/src/backend/gporca/server/src/unittest/gpopt/minidump/CDMLTest.cpp
+++ b/src/backend/gporca/server/src/unittest/gpopt/minidump/CDMLTest.cpp
@@ -47,6 +47,7 @@ const CHAR *rgszDMLFileNames[] = {
"../data/dxl/minidump/InsertSortDistributed2MasterOnly.mdp",
"../data/dxl/minidump/InsertProjectSort.mdp",
"../data/dxl/minidump/InsertAssertSort.mdp",
+ "../data/dxl/minidump/Delete-Check-AssignedQueryIdForTargetRel.mdp",
"../data/dxl/minidump/UpdateRandomDistr.mdp",
"../data/dxl/minidump/DeleteRandomDistr.mdp",
"../data/dxl/minidump/DeleteRandomlyDistributedTableJoin.mdp",
diff --git a/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorDXLToExprTest.cpp b/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorDXLToExprTest.cpp
index 060e66e3ba8f..7e2a2b95987a 100644
--- a/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorDXLToExprTest.cpp
+++ b/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorDXLToExprTest.cpp
@@ -251,7 +251,8 @@ class GetBuilder
m_ptabdesc = GPOS_NEW(mp) CTableDescriptor(
mp, mdid, CName(&strTableName), convert_hash_to_random,
CMDRelationGPDB::EreldistrMasterOnly,
- CMDRelationGPDB::ErelstorageHeap, ulExecuteAsUser);
+ CMDRelationGPDB::ErelstorageHeap, ulExecuteAsUser,
+ 0 /* UNASSIGNED_QUERYID */);
}
void
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f865a436be80..dfdcd1dc6f7b 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1337,6 +1337,7 @@ _copyDML(const DML *from)
COPY_SCALAR_FIELD(actionColIdx);
COPY_SCALAR_FIELD(ctidColIdx);
COPY_SCALAR_FIELD(tupleoidColIdx);
+ COPY_SCALAR_FIELD(epqParam);
return newnode;
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 0dfe3360ab66..3ab88a337cab 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1215,6 +1215,7 @@ _outDML(StringInfo str, const DML *node)
WRITE_INT_FIELD(actionColIdx);
WRITE_INT_FIELD(ctidColIdx);
WRITE_INT_FIELD(tupleoidColIdx);
+ WRITE_INT_FIELD(epqParam);
_outPlanInfo(str, (Plan *) node);
}
diff --git a/src/backend/nodes/readfast.c b/src/backend/nodes/readfast.c
index de6c0c2c011a..0508552b6d95 100644
--- a/src/backend/nodes/readfast.c
+++ b/src/backend/nodes/readfast.c
@@ -2237,6 +2237,7 @@ _readDML(void)
READ_INT_FIELD(actionColIdx);
READ_INT_FIELD(ctidColIdx);
READ_INT_FIELD(tupleoidColIdx);
+ READ_INT_FIELD(epqParam);
readPlanInfo((Plan *)local_node);
diff --git a/src/include/gpopt/translate/CContextDXLToPlStmt.h b/src/include/gpopt/translate/CContextDXLToPlStmt.h
index 148798205613..28d2f826f0ed 100644
--- a/src/include/gpopt/translate/CContextDXLToPlStmt.h
+++ b/src/include/gpopt/translate/CContextDXLToPlStmt.h
@@ -90,6 +90,10 @@ class CContextDXLToPlStmt
CleanupDelete >
HMUlCTEConsumerInfo;
+ typedef CHashMap, gpos::Equals,
+ CleanupDelete, CleanupDelete >
+ HMUlIndex;
+
CMemoryPool *m_mp;
// counter for generating plan ids
@@ -128,6 +132,9 @@ class CContextDXLToPlStmt
// CTAS distribution policy
GpPolicy *m_distribution_policy;
+ // hash map of the queryid (of DML query) and the target relation index
+ HMUlIndex *m_used_rte_indexes;
+
public:
// ctor/dtor
CContextDXLToPlStmt(CMemoryPool *mp, CIdGenerator *plan_id_counter,
@@ -215,6 +222,12 @@ class CContextDXLToPlStmt
// based on decision made by DetermineDistributionHashOpclasses()
Oid GetDistributionHashOpclassForType(Oid typid);
Oid GetDistributionHashFuncForType(Oid typid);
+
+ // get rte from m_rtable_entries_list by given index
+ RangeTblEntry *GetRTEByIndex(Index index);
+
+ Index GetRTEIndexByTableDescr(const CDXLTableDescr *table_descr,
+ BOOL *is_rte_exists);
};
} // namespace gpdxl
diff --git a/src/include/gpopt/translate/CContextQueryToDXL.h b/src/include/gpopt/translate/CContextQueryToDXL.h
index 03add95c2f9e..368d81f0ba02 100644
--- a/src/include/gpopt/translate/CContextQueryToDXL.h
+++ b/src/include/gpopt/translate/CContextQueryToDXL.h
@@ -22,6 +22,7 @@
#define GPDXL_CTE_ID_START 1
#define GPDXL_COL_ID_START 1
+#define GPDXL_QUERY_ID_START 1
namespace gpdxl
{
@@ -53,6 +54,9 @@ class CContextQueryToDXL
// counter for generating unique CTE ids
CIdGenerator *m_cte_id_counter;
+ // counter for upper-level query and its subqueries
+ CIdGenerator *m_queryid_counter;
+
// does the query have any distributed tables?
BOOL m_has_distributed_tables;
@@ -71,6 +75,8 @@ class CContextQueryToDXL
// dtor
~CContextQueryToDXL();
+
+ ULONG GetNextQueryId();
};
} // namespace gpdxl
#endif // GPDXL_CContextQueryToDXL_H
diff --git a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
index 3a8cf515c140..3e3ce23f458f 100644
--- a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
+++ b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
@@ -464,9 +464,9 @@ class CTranslatorDXLToPlStmt
CDXLTranslateContextBaseTable *base_table_context);
// create range table entry from a table descriptor
- RangeTblEntry *TranslateDXLTblDescrToRangeTblEntry(
- const CDXLTableDescr *table_descr, Index index,
- CDXLTranslateContextBaseTable *base_table_context);
+ Index ProcessDXLTblDescr(const CDXLTableDescr *table_descr,
+ CDXLTranslateContextBaseTable *base_table_context,
+ AclMode acl_mode);
// translate DXL projection list into a target list
List *TranslateDXLProjList(
diff --git a/src/include/gpopt/translate/CTranslatorQueryToDXL.h b/src/include/gpopt/translate/CTranslatorQueryToDXL.h
index 9d5176a70e7c..8c5ba1d6f2a7 100644
--- a/src/include/gpopt/translate/CTranslatorQueryToDXL.h
+++ b/src/include/gpopt/translate/CTranslatorQueryToDXL.h
@@ -138,6 +138,10 @@ class CTranslatorQueryToDXL
// CTE producer IDs defined at the current query level
UlongBoolHashMap *m_cteid_at_current_query_level_map;
+ // id of current query (and for nested queries), it's used for correct assigning
+ // of relation links to target relation of DML query
+ ULONG m_query_id;
+
//ctor
// private constructor, called from the public factory function QueryToDXLInstance
CTranslatorQueryToDXL(
diff --git a/src/include/gpopt/translate/CTranslatorUtils.h b/src/include/gpopt/translate/CTranslatorUtils.h
index 9ba1d35b88ad..3fa5d2313d77 100644
--- a/src/include/gpopt/translate/CTranslatorUtils.h
+++ b/src/include/gpopt/translate/CTranslatorUtils.h
@@ -142,12 +142,10 @@ class CTranslatorUtils
CMDAccessor *md_accessor, IMDId *mdid);
// translate a RangeTableEntry into a CDXLTableDescr
- static CDXLTableDescr *GetTableDescr(CMemoryPool *mp,
- CMDAccessor *md_accessor,
- CIdGenerator *id_generator,
- const RangeTblEntry *rte,
- BOOL *is_distributed_table = NULL,
- BOOL *is_replicated_table = NULL);
+ static CDXLTableDescr *GetTableDescr(
+ CMemoryPool *mp, CMDAccessor *md_accessor, CIdGenerator *id_generator,
+ const RangeTblEntry *rte, ULONG assigned_query_id_for_target_rel,
+ BOOL *is_distributed_table = NULL, BOOL *is_replicated_table = NULL);
// translate a RangeTableEntry into a CDXLLogicalTVF
static CDXLLogicalTVF *ConvertToCDXLLogicalTVF(CMemoryPool *mp,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index be1ee1b7f23a..66b868c3db1d 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2829,6 +2829,7 @@ typedef struct DMLState
JunkFilter *junkfilter; /* filter that removes junk and dropped attributes */
TupleTableSlot *cleanedUpSlot; /* holds 'final' tuple which matches the target relation schema */
AttrNumber segid_attno; /* attribute number of "gp_segment_id" */
+ EPQState dml_epqstate;
} DMLState;
/*
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 19e38a9e2166..6b11dc7b6987 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -1328,7 +1328,7 @@ typedef struct DML
AttrNumber actionColIdx; /* index of action column into the target list */
AttrNumber ctidColIdx; /* index of ctid column into the target list */
AttrNumber tupleoidColIdx; /* index of tuple oid column into the target list */
-
+ int epqParam; /* ID of Param for EvalPlanQual re-eval */
} DML;
/*
diff --git a/src/test/isolation2/expected/gdd/concurrent_update.out b/src/test/isolation2/expected/gdd/concurrent_update.out
index eb54eb7ac44c..c10b20617c03 100644
--- a/src/test/isolation2/expected/gdd/concurrent_update.out
+++ b/src/test/isolation2/expected/gdd/concurrent_update.out
@@ -251,10 +251,7 @@ DROP
1q: ...
2q: ...
--- Currently the DML node (modification variant in ORCA) doesn't support EPQ
--- routine so concurrent modification is not possible in this case. User have
--- to be informed to fallback to postgres optimizer.
--- This test makes sense just for ORCA
+-- check that orca concurrent delete transaction won't delete tuple, updated in other transaction (which doesn't match predicate anymore)
create table test as select 0 as i distributed randomly;
CREATE 1
-- in session 1, turn off the optimizer so it will invoke heap_update
@@ -267,8 +264,6 @@ UPDATE 1
-- in session 2, in case of ORCA DML invokes EPQ
-- the following SQL will hang due to XID lock
2&: delete from test where i = 0;
--- commit session1's transaction so the above session2 will continue and emit
--- error about serialization failure in case of ORCA
1: end;
END
2<: <... completed>
@@ -278,6 +273,28 @@ DROP
1q: ...
2q: ...
+-- check that orca concurrent delete transaction will delete tuple, updated in other transaction (which still matches predicate)
+create table test as select 0 as i distributed randomly;
+CREATE 1
+-- in session 1, turn off the optimizer so it will invoke heap_update
+1: set optimizer = off;
+SET
+1: begin;
+BEGIN
+1: update test set i = i;
+UPDATE 1
+-- in session 2, in case of ORCA DML invokes EPQ
+-- the following SQL will hang due to XID lock
+2&: delete from test where i = 0;
+1: end;
+END
+2<: <... completed>
+DELETE 1
+drop table test;
+DROP
+1q: ...
+2q: ...
+
-- split update is to implement updating on hash keys,
-- it deletes the tuple and insert a new tuple in a
-- new segment, so it is not easy for other transaction
diff --git a/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out b/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out
index 5f3ed55c942e..89db75aedf17 100644
--- a/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out
+++ b/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out
@@ -251,10 +251,7 @@ DROP
1q: ...
2q: ...
--- Currently the DML node (modification variant in ORCA) doesn't support EPQ
--- routine so concurrent modification is not possible in this case. User have
--- to be informed to fallback to postgres optimizer.
--- This test makes sense just for ORCA
+-- check that orca concurrent delete transaction won't delete tuple, updated in other transaction (which doesn't match predicate anymore)
create table test as select 0 as i distributed randomly;
CREATE 1
-- in session 1, turn off the optimizer so it will invoke heap_update
@@ -267,13 +264,32 @@ UPDATE 1
-- in session 2, in case of ORCA DML invokes EPQ
-- the following SQL will hang due to XID lock
2&: delete from test where i = 0;
--- commit session1's transaction so the above session2 will continue and emit
--- error about serialization failure in case of ORCA
1: end;
END
2<: <... completed>
-ERROR: could not serialize access due to concurrent update
-HINT: Use PostgreSQL Planner instead of Optimizer for this query via optimizer=off GUC setting
+DELETE 0
+drop table test;
+DROP
+1q: ...
+2q: ...
+
+-- check that orca concurrent delete transaction will delete tuple, updated in other transaction (which still matches predicate)
+create table test as select 0 as i distributed randomly;
+CREATE 1
+-- in session 1, turn off the optimizer so it will invoke heap_update
+1: set optimizer = off;
+SET
+1: begin;
+BEGIN
+1: update test set i = i;
+UPDATE 1
+-- in session 2, in case of ORCA DML invokes EPQ
+-- the following SQL will hang due to XID lock
+2&: delete from test where i = 0;
+1: end;
+END
+2<: <... completed>
+DELETE 1
drop table test;
DROP
1q: ...
diff --git a/src/test/isolation2/expected/modify_table_data_corrupt_optimizer.out b/src/test/isolation2/expected/modify_table_data_corrupt_optimizer.out
index 25a23ba33967..370973709f75 100644
--- a/src/test/isolation2/expected/modify_table_data_corrupt_optimizer.out
+++ b/src/test/isolation2/expected/modify_table_data_corrupt_optimizer.out
@@ -200,7 +200,7 @@ explain (costs off) update tab1 set b = b + 1;
Update
-> Result
-> Redistribute Motion 3:3 (slice1; segments: 3)
- Hash Key: tab1.b
+ Hash Key: b
-> Split
-> Result
-> Seq Scan on tab1
diff --git a/src/test/isolation2/output/uao/parallel_delete_optimizer.source b/src/test/isolation2/output/uao/parallel_delete_optimizer.source
index 7646a9066bfb..832979779db1 100644
--- a/src/test/isolation2/output/uao/parallel_delete_optimizer.source
+++ b/src/test/isolation2/output/uao/parallel_delete_optimizer.source
@@ -19,15 +19,13 @@ DELETE 1
coalesce | mode | locktype | node
----------+---------------------+--------------------------+--------
ao | AccessExclusiveLock | append-only segment file | master
- ao | AccessShareLock | relation | master
ao | ExclusiveLock | relation | master
-(3 rows)
+(2 rows)
2: SELECT * FROM locktest_segments WHERE coalesce = 'ao';
coalesce | mode | locktype | node
----------+------------------+----------+------------
- ao | AccessShareLock | relation | n segments
ao | RowExclusiveLock | relation | n segments
-(2 rows)
+(1 row)
-- The case here should delete a tuple at the same seg with(2).
-- Under jump hash, (2) and (3) are on the same seg(seg0).
1&: DELETE FROM ao WHERE a = 3;
diff --git a/src/test/isolation2/output/uao/parallel_update_optimizer.source b/src/test/isolation2/output/uao/parallel_update_optimizer.source
index 6423a5f8e055..48a155a35285 100644
--- a/src/test/isolation2/output/uao/parallel_update_optimizer.source
+++ b/src/test/isolation2/output/uao/parallel_update_optimizer.source
@@ -19,16 +19,14 @@ UPDATE 1
coalesce | mode | locktype | node
----------+---------------------+--------------------------+--------
ao | AccessExclusiveLock | append-only segment file | master
- ao | AccessShareLock | relation | master
ao | ExclusiveLock | relation | master
-(3 rows)
+(2 rows)
2: SELECT * FROM locktest_segments WHERE coalesce = 'ao';
coalesce | mode | locktype | node
----------+---------------------+--------------------------+------------
ao | AccessExclusiveLock | append-only segment file | 1 segment
- ao | AccessShareLock | relation | n segments
ao | RowExclusiveLock | relation | n segments
-(3 rows)
+(2 rows)
-- The case here should update a tuple at the same seg with(2).
-- Under jump hash, (2) and (3) are on the same seg(seg0).
1&: UPDATE ao SET b = 42 WHERE a = 3;
diff --git a/src/test/isolation2/sql/gdd/concurrent_update.sql b/src/test/isolation2/sql/gdd/concurrent_update.sql
index f670df45456c..14d640b6c1ed 100644
--- a/src/test/isolation2/sql/gdd/concurrent_update.sql
+++ b/src/test/isolation2/sql/gdd/concurrent_update.sql
@@ -135,10 +135,7 @@ DROP TABLE t_concurrent_update;
1q:
2q:
--- Currently the DML node (modification variant in ORCA) doesn't support EPQ
--- routine so concurrent modification is not possible in this case. User have
--- to be informed to fallback to postgres optimizer.
--- This test makes sense just for ORCA
+-- check that orca concurrent delete transaction won't delete tuple, updated in other transaction (which doesn't match predicate anymore)
create table test as select 0 as i distributed randomly;
-- in session 1, turn off the optimizer so it will invoke heap_update
1: set optimizer = off;
@@ -147,8 +144,21 @@ create table test as select 0 as i distributed randomly;
-- in session 2, in case of ORCA DML invokes EPQ
-- the following SQL will hang due to XID lock
2&: delete from test where i = 0;
--- commit session1's transaction so the above session2 will continue and emit
--- error about serialization failure in case of ORCA
+1: end;
+2<:
+drop table test;
+1q:
+2q:
+
+-- check that orca concurrent delete transaction will delete tuple, updated in other transaction (which still matches predicate)
+create table test as select 0 as i distributed randomly;
+-- in session 1, turn off the optimizer so it will invoke heap_update
+1: set optimizer = off;
+1: begin;
+1: update test set i = i;
+-- in session 2, in case of ORCA DML invokes EPQ
+-- the following SQL will hang due to XID lock
+2&: delete from test where i = 0;
1: end;
2<:
drop table test;
diff --git a/src/test/regress/expected/ao_locks_optimizer.out b/src/test/regress/expected/ao_locks_optimizer.out
index 6401372ac96a..11a0cf585ef4 100644
--- a/src/test/regress/expected/ao_locks_optimizer.out
+++ b/src/test/regress/expected/ao_locks_optimizer.out
@@ -78,9 +78,8 @@ SELECT * FROM locktest_master where coalesce = 'ao_locks_table' or
coalesce | mode | locktype | node
----------------+---------------------+--------------------------+--------
ao_locks_table | AccessExclusiveLock | append-only segment file | master
- ao_locks_table | AccessShareLock | relation | master
ao_locks_table | ExclusiveLock | relation | master
-(3 rows)
+(2 rows)
SELECT * FROM locktest_segments where coalesce = 'ao_locks_table' or
coalesce like 'aovisimap%' or coalesce like 'aoseg%';
@@ -88,9 +87,8 @@ SELECT * FROM locktest_segments where coalesce = 'ao_locks_table' or
-----------------+------------------+----------+------------
aovisimap index | RowExclusiveLock | relation | 1 segment
ao_locks_table | RowExclusiveLock | relation | n segments
- ao_locks_table | AccessShareLock | relation | n segments
aovisimap table | RowExclusiveLock | relation | 1 segment
-(4 rows)
+(3 rows)
COMMIT;
BEGIN;
@@ -100,19 +98,17 @@ SELECT * FROM locktest_master where coalesce = 'ao_locks_table' or
coalesce | mode | locktype | node
----------------+---------------------+--------------------------+--------
ao_locks_table | AccessExclusiveLock | append-only segment file | master
- ao_locks_table | AccessShareLock | relation | master
ao_locks_table | ExclusiveLock | relation | master
-(3 rows)
+(2 rows)
SELECT * FROM locktest_segments where coalesce = 'ao_locks_table' or
coalesce like 'aovisimap%' or coalesce like 'aoseg%';
coalesce | mode | locktype | node
-----------------+---------------------+--------------------------+------------
- ao_locks_table | AccessShareLock | relation | n segments
aovisimap table | RowExclusiveLock | relation | 1 segment
ao_locks_table | AccessExclusiveLock | append-only segment file | 1 segment
aovisimap index | RowExclusiveLock | relation | 1 segment
ao_locks_table | RowExclusiveLock | relation | n segments
-(5 rows)
+(4 rows)
COMMIT;
diff --git a/src/test/regress/expected/bfv_dml_optimizer.out b/src/test/regress/expected/bfv_dml_optimizer.out
index 164d849c4eea..2598c3f63843 100644
--- a/src/test/regress/expected/bfv_dml_optimizer.out
+++ b/src/test/regress/expected/bfv_dml_optimizer.out
@@ -671,11 +671,11 @@ explain delete from foo using (select a from foo union all select b from bar) v;
-> Result (cost=0.00..1765380.23 rows=67 width=18)
-> Nested Loop (cost=0.00..1765380.23 rows=67 width=14)
Join Filter: true
- -> Seq Scan on foo foo_1 (cost=0.00..431.00 rows=4 width=14)
+ -> Seq Scan on foo (cost=0.00..431.00 rows=4 width=14)
-> Materialize (cost=0.00..862.00 rows=20 width=1)
-> Broadcast Motion 3:3 (slice1; segments: 3) (cost=0.00..862.00 rows=20 width=1)
-> Append (cost=0.00..862.00 rows=7 width=1)
- -> Seq Scan on foo (cost=0.00..431.00 rows=4 width=1)
+ -> Seq Scan on foo foo_1 (cost=0.00..431.00 rows=4 width=1)
-> Seq Scan on bar (cost=0.00..431.00 rows=4 width=1)
Optimizer: Pivotal Optimizer (GPORCA)
(11 rows)
diff --git a/src/test/regress/expected/partition_locking.out b/src/test/regress/expected/partition_locking.out
index 5cc7b3511f48..0101c71e594e 100644
--- a/src/test/regress/expected/partition_locking.out
+++ b/src/test/regress/expected/partition_locking.out
@@ -498,6 +498,8 @@ select * from locktest_master where coalesce not like 'gp_%' and coalesce not li
partlockt_1_prt_9_i_idx | RowExclusiveLock | relation | master
(19 rows)
+-- TODO: Seems RowExclusiveLock should be also applied on index of partlock table,
+-- like it's done in vanila postgres (lock on indexes should be eqaul to locks on table).
select * from locktest_segments where coalesce not like 'gp_%' and coalesce not like 'pg_%';
coalesce | mode | locktype | node
-------------------+------------------+----------+-----------
diff --git a/src/test/regress/expected/partition_locking_optimizer.out b/src/test/regress/expected/partition_locking_optimizer.out
index 944246d9ff30..5d05dba64e95 100644
--- a/src/test/regress/expected/partition_locking_optimizer.out
+++ b/src/test/regress/expected/partition_locking_optimizer.out
@@ -471,13 +471,14 @@ select * from locktest_master where coalesce not like 'gp_%' and coalesce not li
partlockt_1_prt_9 | ExclusiveLock | relation | master
(10 rows)
+-- TODO: Seems RowExclusiveLock should be also applied on index of partlock table,
+-- like it's done in vanila postgres (lock on indexes should be eqaul to locks on table).
select * from locktest_segments where coalesce not like 'gp_%' and coalesce not like 'pg_%';
- coalesce | mode | locktype | node
--------------------------+------------------+----------+------------
- partlockt | RowExclusiveLock | relation | n segments
- partlockt_1_prt_4 | AccessShareLock | relation | n segments
- partlockt_1_prt_4_i_idx | AccessShareLock | relation | n segments
-(3 rows)
+ coalesce | mode | locktype | node
+-------------------+------------------+----------+------------
+ partlockt | RowExclusiveLock | relation | n segments
+ partlockt_1_prt_4 | AccessShareLock | relation | n segments
+(2 rows)
commit;
-- drop index
diff --git a/src/test/regress/expected/updatable_views_optimizer.out b/src/test/regress/expected/updatable_views_optimizer.out
index b814e9ad11f0..dd78b17f92d9 100644
--- a/src/test/regress/expected/updatable_views_optimizer.out
+++ b/src/test/regress/expected/updatable_views_optimizer.out
@@ -369,7 +369,7 @@ EXPLAIN (costs off) UPDATE rw_view1 SET a=6 WHERE a=5;
-> Sort
Sort Key: (DMLAction)
-> Redistribute Motion 3:3 (slice1; segments: 3)
- Hash Key: base_tbl.a
+ Hash Key: a
-> Split
-> Result
-> Index Scan using base_tbl_pkey on base_tbl
@@ -449,7 +449,7 @@ EXPLAIN (costs off) UPDATE rw_view2 SET aaa=5 WHERE aaa=4;
-> Sort
Sort Key: (DMLAction)
-> Redistribute Motion 3:3 (slice1; segments: 3)
- Hash Key: base_tbl.a
+ Hash Key: a
-> Split
-> Result
-> Index Scan using base_tbl_pkey on base_tbl
@@ -2079,7 +2079,7 @@ EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (2, 'New row 2');
-> Result
-> Nested Loop Semi Join
Join Filter: true
- -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
+ -> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (id = 2)
-> Materialize
-> Broadcast Motion 1:3 (slice2; segments: 1)
@@ -2087,7 +2087,7 @@ EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (2, 'New row 2');
-> Result
-> Limit
-> Gather Motion 3:1 (slice1; segments: 3)
- -> Index Scan using base_tbl_pkey on base_tbl
+ -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
Index Cond: (id = 2)
Optimizer: Pivotal Optimizer (GPORCA) version 3.11.0
(38 rows)
diff --git a/src/test/regress/expected/update_optimizer.out b/src/test/regress/expected/update_optimizer.out
index cb9663bf26fb..7b72db84d3a1 100755
--- a/src/test/regress/expected/update_optimizer.out
+++ b/src/test/regress/expected/update_optimizer.out
@@ -341,7 +341,7 @@ EXPLAIN (COSTS OFF ) UPDATE tab3 SET C1 = C1 + 1, C5 = C5+1;
Update
-> Result
-> Redistribute Motion 3:3 (slice1; segments: 3)
- Hash Key: tab3.c1, tab3.c2, tab3.c3
+ Hash Key: c1, c2, c3
-> Split
-> Result
-> Seq Scan on tab3
diff --git a/src/test/regress/sql/partition_locking.sql b/src/test/regress/sql/partition_locking.sql
index d7df5a690a62..2e0cc78d432e 100644
--- a/src/test/regress/sql/partition_locking.sql
+++ b/src/test/regress/sql/partition_locking.sql
@@ -148,6 +148,8 @@ begin;
delete from partlockt where i = 4;
-- Known_opt_diff: MPP-20936
select * from locktest_master where coalesce not like 'gp_%' and coalesce not like 'pg_%';
+-- TODO: Seems RowExclusiveLock should be also applied on index of partlock table,
+-- like it's done in vanila postgres (lock on indexes should be eqaul to locks on table).
select * from locktest_segments where coalesce not like 'gp_%' and coalesce not like 'pg_%';
commit;