diff --git a/src/backend/executor/nodeDML.c b/src/backend/executor/nodeDML.c
index d5dc775273ad..bb47aacb5583 100644
--- a/src/backend/executor/nodeDML.c
+++ b/src/backend/executor/nodeDML.c
@@ -59,18 +59,17 @@ ExecDML(DMLState *node)
}
bool isnull = false;
- int action = DatumGetUInt32(slot_getattr(slot, plannode->actionColIdx, &isnull));
- Assert(!isnull);
-
- bool isUpdate = false;
- if (node->ps.state->es_plannedstmt->commandType == CMD_UPDATE)
+ int action = -1;
+ bool isUpdate = node->ps.state->es_plannedstmt->commandType == CMD_UPDATE;
+ // if it's not in place update
+ if (AttributeNumberIsValid(plannode->actionColIdx))
{
- isUpdate = true;
+ action = DatumGetUInt32(
+ slot_getattr(slot, plannode->actionColIdx, &isnull));
+ Assert(!isnull);
+ Assert(action == DML_INSERT || action == DML_DELETE);
}
- Assert(action == DML_INSERT || action == DML_DELETE);
-
-
/*
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle.
@@ -116,6 +115,13 @@ ExecDML(DMLState *node)
* es_result_relations will contain the only relation.
*/
node->ps.state->es_result_relation_info = relInfo;
+
+ /*
+ * Perform partition selection for in place update
+ */
+ if (isUpdate && !AttributeNumberIsValid(plannode->actionColIdx))
+ node->ps.state->es_result_relation_info =
+ slot_get_partition(node->cleanedUpSlot, node->ps.state);
}
/* GPDB_91_MERGE_FIXME:
* This kind of node is used by ORCA only. If in the future ORCA still uses
@@ -155,7 +161,7 @@ ExecDML(DMLState *node)
isUpdate,
InvalidOid);
}
- else /* DML_DELETE */
+ else
{
int32 segid = GpIdentity.segindex;
Datum ctid = slot_getattr(slot, plannode->ctidColIdx, &isnull);
@@ -172,16 +178,31 @@ ExecDML(DMLState *node)
Assert(!isnull);
}
- /* Correct tuple count by ignoring deletes when splitting tuples. */
- ExecDelete(tupleid,
- segid,
- NULL, /* GPDB_91_MERGE_FIXME: oldTuple? */
- node->cleanedUpSlot,
- NULL /* DestReceiver */,
- node->ps.state,
- !isUpdate, /* GPDB_91_MERGE_FIXME: where to get canSetTag? */
- PLANGEN_OPTIMIZER /* Plan origin */,
- isUpdate);
+ if (DML_DELETE == action)
+ {
+ /* Correct tuple count by ignoring deletes when splitting tuples. */
+ ExecDelete(tupleid,
+ segid,
+ NULL, /* GPDB_91_MERGE_FIXME: oldTuple? */
+ node->cleanedUpSlot,
+ NULL /* DestReceiver */,
+ node->ps.state,
+ !isUpdate, /* GPDB_91_MERGE_FIXME: where to get canSetTag? */
+ PLANGEN_OPTIMIZER /* Plan origin */,
+ isUpdate);
+ }
+ else
+ {
+ ExecUpdate(tupleid,
+ segid,
+ NULL, //oldtuple
+ node->cleanedUpSlot,
+ NULL, //planSlot
+ NULL /* DestReceiver */,
+ node->ps.state,
+ true,
+ PLANGEN_OPTIMIZER);
+ }
}
return slot;
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index db983735af40..ac6771cb5252 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1301,7 +1301,8 @@ ExecUpdate(ItemPointer tupleid,
TupleTableSlot *planSlot,
EPQState *epqstate,
EState *estate,
- bool canSetTag)
+ bool canSetTag,
+ PlanGenerator planGen)
{
ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
@@ -1370,8 +1371,12 @@ ExecUpdate(ItemPointer tupleid,
/* see if this update would move the tuple to a different partition */
if (estate->es_result_partitions)
+ {
checkPartitionUpdate(estate, slot, resultRelInfo);
+ if (planGen == PLANGEN_OPTIMIZER)
+ slot = reconstructMatchingTupleSlot(slot, resultRelInfo);
+ }
/* BEFORE ROW UPDATE Triggers */
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_update_before_row)
@@ -1571,6 +1576,17 @@ lreplace:;
{
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,
@@ -1942,7 +1958,7 @@ ExecModifyTable(ModifyTableState *node)
slot = ExecUpdate(tupleid, segid,
oldtuple, slot, planSlot,
&node->mt_epqstate, estate,
- node->canSetTag);
+ node->canSetTag, PLANGEN_PLANNER);
break;
}
diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
index 46d35e256c99..7b0d7826a52b 100644
--- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
@@ -4100,6 +4100,7 @@ CTranslatorDXLToPlStmt::TranslateDXLDml(
DML *dml = MakeNode(DML);
Plan *plan = &(dml->plan);
AclMode acl_mode = ACL_NO_RIGHTS;
+ BOOL isSplit = phy_dml_dxlop->FSplit();
switch (phy_dml_dxlop->GetDmlOpType())
{
@@ -4186,11 +4187,21 @@ CTranslatorDXLToPlStmt::TranslateDXLDml(
dml_target_list = target_list_with_dropped_cols;
}
- // Extract column numbers of the action and ctid columns from the
- // target list.
- dml->actionColIdx = AddTargetEntryForColId(&dml_target_list, &child_context,
- phy_dml_dxlop->ActionColId(),
- true /*is_resjunk*/);
+ // Doesn't needed for in place update
+ if (isSplit || CMD_UPDATE != m_cmd_type)
+ {
+ // Extract column numbers of the action and ctid columns from the
+ // target list.
+ dml->actionColIdx = AddTargetEntryForColId(
+ &dml_target_list, &child_context, phy_dml_dxlop->ActionColId(),
+ true /*is_resjunk*/);
+ GPOS_ASSERT(0 != dml->actionColIdx);
+ }
+ else
+ {
+ dml->actionColIdx = 0;
+ }
+
dml->ctidColIdx = AddTargetEntryForColId(&dml_target_list, &child_context,
phy_dml_dxlop->GetCtIdColId(),
true /*is_resjunk*/);
@@ -4205,8 +4216,6 @@ CTranslatorDXLToPlStmt::TranslateDXLDml(
dml->tupleoidColIdx = 0;
}
- GPOS_ASSERT(0 != dml->actionColIdx);
-
plan->targetlist = dml_target_list;
plan->lefttree = child_plan;
diff --git a/src/backend/gporca/data/dxl/minidump/SelfUpdate.mdp b/src/backend/gporca/data/dxl/minidump/SelfUpdate.mdp
index 77cd608aec88..42d4866e8c28 100644
--- a/src/backend/gporca/data/dxl/minidump/SelfUpdate.mdp
+++ b/src/backend/gporca/data/dxl/minidump/SelfUpdate.mdp
@@ -216,17 +216,17 @@ update t1 set b = c;
-
+
-
+
-
-
+
+
@@ -248,14 +248,14 @@ update t1 set b = c;
-
+
-
-
+
+
@@ -266,9 +266,6 @@ update t1 set b = c;
-
-
-
@@ -279,17 +276,14 @@ update t1 set b = c;
-
+
-
+
-
-
-
@@ -299,48 +293,23 @@ update t1 set b = c;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateCheckConstraint.mdp b/src/backend/gporca/data/dxl/minidump/UpdateCheckConstraint.mdp
index d57ae91617d9..13728135d504 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateCheckConstraint.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateCheckConstraint.mdp
@@ -294,17 +294,17 @@
-
+
-
+
-
-
+
+
@@ -330,14 +330,14 @@
-
+
-
-
+
+
@@ -351,9 +351,6 @@
-
-
-
@@ -377,15 +374,12 @@
-
+
-
-
-
@@ -398,8 +392,8 @@
-
-
+
+
@@ -411,17 +405,17 @@
-
+
-
+
+
+
+
-
-
-
@@ -434,33 +428,23 @@
-
-
-
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
@@ -468,56 +452,29 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateNoDistKeyMismatchedDistribution.mdp b/src/backend/gporca/data/dxl/minidump/UpdateNoDistKeyMismatchedDistribution.mdp
index d7dd7212dca9..ee6155e6e28b 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateNoDistKeyMismatchedDistribution.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateNoDistKeyMismatchedDistribution.mdp
@@ -302,18 +302,18 @@
-
-
+
+
-
+
-
-
+
+
@@ -335,14 +335,14 @@
-
+
-
-
+
+
@@ -353,75 +353,55 @@
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
-
+
@@ -432,9 +412,10 @@
-
+
+
-
+
@@ -445,38 +426,47 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -485,19 +475,35 @@
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
@@ -508,67 +514,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateNoEnforceConstraints.mdp b/src/backend/gporca/data/dxl/minidump/UpdateNoEnforceConstraints.mdp
index 6d2e6ade0c3e..dad87dacbdde 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateNoEnforceConstraints.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateNoEnforceConstraints.mdp
@@ -238,21 +238,21 @@ update constraints_tab SET notnullcol = NULL, positivecol =-1;
-
-
+
+
-
+
-
-
+
+
-
-
+
+
@@ -269,19 +269,19 @@ update constraints_tab SET notnullcol = NULL, positivecol =-1;
-
+
-
+
-
-
+
+
-
-
+
+
@@ -289,30 +289,17 @@ update constraints_tab SET notnullcol = NULL, positivecol =-1;
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
@@ -321,46 +308,22 @@ update constraints_tab SET notnullcol = NULL, positivecol =-1;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateRandomDistr.mdp b/src/backend/gporca/data/dxl/minidump/UpdateRandomDistr.mdp
index e7979bb06aa8..2f06ffe77147 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateRandomDistr.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateRandomDistr.mdp
@@ -195,15 +195,15 @@
-
-
+
+
-
+
-
-
+
+
@@ -222,13 +222,13 @@
-
+
-
+
-
-
+
+
@@ -239,24 +239,17 @@
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
@@ -265,42 +258,21 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateUniqueConstraint-2.mdp b/src/backend/gporca/data/dxl/minidump/UpdateUniqueConstraint-2.mdp
index f05bcb78f115..b7df53522f2e 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateUniqueConstraint-2.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateUniqueConstraint-2.mdp
@@ -764,18 +764,18 @@
-
-
+
+
-
+
-
-
+
+
@@ -791,16 +791,19 @@
-
+
-
+
-
-
+
+
+
+
+
@@ -808,22 +811,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
@@ -838,13 +831,18 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
@@ -853,12 +851,6 @@
-
-
-
-
-
-
@@ -867,93 +859,45 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateWindowGatherMerge.mdp b/src/backend/gporca/data/dxl/minidump/UpdateWindowGatherMerge.mdp
index 55d3f01242eb..1fb8164ee4d6 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateWindowGatherMerge.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateWindowGatherMerge.mdp
@@ -14,28 +14,26 @@
set i = tt.i
from (select (min(i) over (order by j)) as i, j from window_agg_test) tt
where t.j = tt.j;
- QUERY PLAN
- --------------------------------------------------------------------------------------------------------------------------------
- Update (cost=0.00..868.82 rows=34 width=1)
- -> Result (cost=0.00..862.05 rows=67 width=26)
- -> Explicit Redistribute Motion 3:3 (slice4; segments: 3) (cost=0.00..862.05 rows=67 width=22)
- -> Split (cost=0.00..862.05 rows=67 width=22)
- -> Hash Join (cost=0.00..862.04 rows=34 width=22)
- Hash Cond: (window_agg_test.j = window_agg_test_1.j)
- -> Redistribute Motion 1:3 (slice2; segments: 1) (cost=0.00..431.01 rows=100 width=8)
- Hash Key: window_agg_test.j
- -> Result (cost=0.00..431.01 rows=34 width=8)
- -> WindowAgg (cost=0.00..431.01 rows=34 width=8)
- Order By: window_agg_test.j
- -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.01 rows=100 width=8)
- Merge Key: window_agg_test.j
- -> Sort (cost=0.00..431.01 rows=34 width=8)
- Sort Key: window_agg_test.j
- -> Seq Scan on window_agg_test (cost=0.00..431.00 rows=34 width=8)
- -> Hash (cost=431.00..431.00 rows=34 width=18)
- -> Redistribute Motion 3:3 (slice3; segments: 3) (cost=0.00..431.00 rows=34 width=18)
- Hash Key: window_agg_test_1.j
- -> Seq Scan on window_agg_test window_agg_test_1 (cost=0.00..431.00 rows=34 width=18)
+ QUERY PLAN
+ --------------------------------------------------------------------------------------------------------------------
+ Update (cost=0.00..864.39 rows=34 width=1)
+ -> Explicit Redistribute Motion 3:3 (slice4; segments: 3) (cost=0.00..862.04 rows=34 width=18)
+ -> Hash Join (cost=0.00..862.04 rows=34 width=18)
+ Hash Cond: (window_agg_test.j = window_agg_test_1.j)
+ -> Redistribute Motion 1:3 (slice2; segments: 1) (cost=0.00..431.01 rows=100 width=8)
+ Hash Key: window_agg_test.j
+ -> Result (cost=0.00..431.01 rows=34 width=8)
+ -> WindowAgg (cost=0.00..431.01 rows=34 width=8)
+ Order By: window_agg_test.j
+ -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.01 rows=100 width=8)
+ Merge Key: window_agg_test.j
+ -> Sort (cost=0.00..431.01 rows=34 width=8)
+ Sort Key: window_agg_test.j
+ -> Seq Scan on window_agg_test (cost=0.00..431.00 rows=34 width=8)
+ -> Hash (cost=431.00..431.00 rows=34 width=14)
+ -> Redistribute Motion 3:3 (slice3; segments: 3) (cost=0.00..431.00 rows=34 width=14)
+ Hash Key: window_agg_test_1.j
+ -> Seq Scan on window_agg_test window_agg_test_1 (cost=0.00..431.00 rows=34 width=14)
Optimizer: Pivotal Optimizer (GPORCA)
(21 rows)
]]>
@@ -708,15 +706,15 @@
-
-
+
+
-
+
-
-
+
+
@@ -737,11 +735,11 @@
-
+
-
-
+
+
@@ -752,19 +750,16 @@
-
-
-
-
+
-
+
-
-
+
+
@@ -775,42 +770,37 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
+
@@ -821,44 +811,41 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
-
+
-
-
-
-
+
+
-
+
+
+
+
-
+
@@ -872,9 +859,11 @@
-
+
+
+
-
+
@@ -885,62 +874,63 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
@@ -952,48 +942,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateWithHashJoin.mdp b/src/backend/gporca/data/dxl/minidump/UpdateWithHashJoin.mdp
index e7e1b1db9797..da0d818009e8 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateWithHashJoin.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateWithHashJoin.mdp
@@ -300,10 +300,10 @@
-
-
+
+
-
+
@@ -327,9 +327,9 @@
-
+
-
+
@@ -344,13 +344,22 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -367,75 +376,44 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateWithTriggers.mdp b/src/backend/gporca/data/dxl/minidump/UpdateWithTriggers.mdp
index e626def55975..bc6c57727571 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateWithTriggers.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateWithTriggers.mdp
@@ -204,17 +204,17 @@
-
+
-
+
-
-
+
+
@@ -234,16 +234,16 @@
-
+
-
+
-
-
+
+
@@ -254,13 +254,10 @@
-
-
-
-
+
@@ -273,7 +270,7 @@
-
+
@@ -284,23 +281,20 @@
-
+
-
+
-
-
+
+
-
-
-
@@ -308,73 +302,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdateZeroRows.mdp b/src/backend/gporca/data/dxl/minidump/UpdateZeroRows.mdp
index 8e063421b638..45e9098f9cb2 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdateZeroRows.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdateZeroRows.mdp
@@ -409,229 +409,168 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdatingNonDistColSameTable.mdp b/src/backend/gporca/data/dxl/minidump/UpdatingNonDistColSameTable.mdp
index 0c724aa138bc..532fbccf1c05 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdatingNonDistColSameTable.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdatingNonDistColSameTable.mdp
@@ -234,17 +234,17 @@
-
+
-
+
-
-
+
+
@@ -264,16 +264,16 @@
-
+
-
+
-
-
+
+
@@ -284,48 +284,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/minidump/UpdatingNonDistributionColumnFunc.mdp b/src/backend/gporca/data/dxl/minidump/UpdatingNonDistributionColumnFunc.mdp
index 30bd81e5f423..8439bf043967 100644
--- a/src/backend/gporca/data/dxl/minidump/UpdatingNonDistributionColumnFunc.mdp
+++ b/src/backend/gporca/data/dxl/minidump/UpdatingNonDistributionColumnFunc.mdp
@@ -238,18 +238,18 @@
-
-
+
+
-
+
-
-
+
+
@@ -265,16 +265,24 @@
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
@@ -282,32 +290,17 @@
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -316,42 +309,21 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/gporca/data/dxl/parse_tests/q60-DMLUpdate.xml b/src/backend/gporca/data/dxl/parse_tests/q60-DMLUpdate.xml
index 038c6673722a..9d4a36f0031a 100644
--- a/src/backend/gporca/data/dxl/parse_tests/q60-DMLUpdate.xml
+++ b/src/backend/gporca/data/dxl/parse_tests/q60-DMLUpdate.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/CExpressionPreprocessor.h b/src/backend/gporca/libgpopt/include/gpopt/operators/CExpressionPreprocessor.h
index 003899edd69e..2f9d69008df6 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/operators/CExpressionPreprocessor.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CExpressionPreprocessor.h
@@ -213,6 +213,9 @@ class CExpressionPreprocessor
static CExpression *PexprTransposeSelectAndProject(CMemoryPool *mp,
CExpression *pexpr);
+ static CExpression *ConvertSplitUpdateToInPlaceUpdate(CMemoryPool *mp,
+ CExpression *expr);
+
static CExpression *CollapseSelectAndReplaceColref(CMemoryPool *mp,
CExpression *expr,
CColRef *pcolref,
diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalDML.h b/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalDML.h
index fe2effe20be6..3c2d68100800 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalDML.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalDML.h
@@ -40,7 +40,6 @@ class CLogicalDML : public CLogical
EdmlSentinel
};
- static const WCHAR m_rgwszDml[EdmlSentinel][10];
private:
// dml operator
@@ -67,6 +66,9 @@ class CLogicalDML : public CLogical
// tuple oid column if one exists
CColRef *m_pcrTupleOid;
+ // Split Update
+ BOOL m_fSplit;
+
// private copy ctor
CLogicalDML(const CLogicalDML &);
@@ -78,7 +80,7 @@ class CLogicalDML : public CLogical
CLogicalDML(CMemoryPool *mp, EDMLOperator edmlop,
CTableDescriptor *ptabdesc, CColRefArray *colref_array,
CBitSet *pbsModified, CColRef *pcrAction, CColRef *pcrCtid,
- CColRef *pcrSegmentId, CColRef *pcrTupleOid);
+ CColRef *pcrSegmentId, CColRef *pcrTupleOid, BOOL fSplit);
// dtor
virtual ~CLogicalDML();
@@ -153,6 +155,13 @@ class CLogicalDML : public CLogical
return m_pcrTupleOid;
}
+ // Is update using split
+ BOOL
+ FSplit() const
+ {
+ return m_fSplit;
+ }
+
// operator specific hash function
virtual ULONG HashValue() const;
@@ -245,6 +254,9 @@ class CLogicalDML : public CLogical
// debug print
virtual IOstream &OsPrint(IOstream &) const;
+ // Helper function to print DML operator type.
+ static void PrintOperatorType(IOstream &os, EDMLOperator, BOOL fSplit);
+
}; // class CLogicalDML
} // namespace gpopt
diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalUpdate.h b/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalUpdate.h
index bf54f4c5abd8..f0fdf02e1d59 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalUpdate.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CLogicalUpdate.h
@@ -49,6 +49,9 @@ class CLogicalUpdate : public CLogical
// tuple oid column
CColRef *m_pcrTupleOid;
+ // Is Split Update
+ BOOL m_fSplit;
+
// private copy ctor
CLogicalUpdate(const CLogicalUpdate &);
@@ -60,7 +63,7 @@ class CLogicalUpdate : public CLogical
CLogicalUpdate(CMemoryPool *mp, CTableDescriptor *ptabdesc,
CColRefArray *pdrgpcrDelete, CColRefArray *pdrgpcrInsert,
CColRef *pcrCtid, CColRef *pcrSegmentId,
- CColRef *pcrTupleOid);
+ CColRef *pcrTupleOid, BOOL fSplit);
// dtor
virtual ~CLogicalUpdate();
@@ -121,6 +124,13 @@ class CLogicalUpdate : public CLogical
return m_ptabdesc;
}
+ // Is update using split
+ BOOL
+ FSplit() const
+ {
+ return m_fSplit;
+ }
+
// operator specific hash function
virtual ULONG HashValue() const;
diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalDML.h b/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalDML.h
index d1e9f432ae1c..11ab82d25bab 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalDML.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalDML.h
@@ -69,6 +69,9 @@ class CPhysicalDML : public CPhysical
// compute required order spec
COrderSpec *PosComputeRequired(CMemoryPool *mp, CTableDescriptor *ptabdesc);
+ // Split Update
+ BOOL m_fSplit;
+
// compute local required columns
void ComputeRequiredLocalColumns(CMemoryPool *mp);
@@ -80,7 +83,7 @@ class CPhysicalDML : public CPhysical
CPhysicalDML(CMemoryPool *mp, CLogicalDML::EDMLOperator edmlop,
CTableDescriptor *ptabdesc, CColRefArray *pdrgpcrSource,
CBitSet *pbsModified, CColRef *pcrAction, CColRef *pcrCtid,
- CColRef *pcrSegmentId, CColRef *pcrTupleOid);
+ CColRef *pcrSegmentId, CColRef *pcrTupleOid, BOOL fSplit);
// dtor
virtual ~CPhysicalDML();
@@ -148,6 +151,13 @@ class CPhysicalDML : public CPhysical
return m_pdrgpcrSource;
}
+ // Is update using split
+ BOOL
+ FSplit() const
+ {
+ return m_fSplit;
+ }
+
// match function
virtual BOOL Matches(COperator *pop) const;
diff --git a/src/backend/gporca/libgpopt/src/operators/CExpressionPreprocessor.cpp b/src/backend/gporca/libgpopt/src/operators/CExpressionPreprocessor.cpp
index 081758d0dbc2..e49ed092c7b9 100644
--- a/src/backend/gporca/libgpopt/src/operators/CExpressionPreprocessor.cpp
+++ b/src/backend/gporca/libgpopt/src/operators/CExpressionPreprocessor.cpp
@@ -39,6 +39,7 @@
#include "gpopt/operators/CLogicalSetOp.h"
#include "gpopt/operators/CLogicalUnion.h"
#include "gpopt/operators/CLogicalUnionAll.h"
+#include "gpopt/operators/CLogicalUpdate.h"
#include "gpopt/operators/CNormalizer.h"
#include "gpopt/operators/COrderedAggPreprocessor.h"
#include "gpopt/operators/CPredicateUtils.h"
@@ -3057,6 +3058,89 @@ CExpressionPreprocessor::PexprTransposeSelectAndProject(CMemoryPool *mp,
}
}
+// Preprocessor function to decide if the Update operator to be proceeded with
+// split update or inplace update based on the columns modified by the update
+// operation.
+
+// Split Update if any of the modified columns is a distribution column or a partition key,
+// InPlace Update if all the modified columns are non-distribution columns and not partition keys.
+
+// Example: Update Modified non-distribution columns.
+// Input:
+// +--CLogicalUpdate ("foo"), Split Update, Delete Columns: ["a" (0), "b" (1)], Insert Columns: ["a" (0), "b" (9)], "ctid" (2), "gp_segment_id" (8)
+// +--CLogicalProject
+// |--CLogicalGet
+// +--CScalarProjectList
+//
+// Output:
+// +--CLogicalUpdate ("foo"), In-place Update, Delete Columns: ["a" (0), "b" (1)], Insert Columns: ["a" (0), "b" (9)], "ctid" (2), "gp_segment_id" (8)
+// +--CLogicalProject
+// |--CLogicalGet
+// +--CScalarProjectList
+
+CExpression *
+CExpressionPreprocessor::ConvertSplitUpdateToInPlaceUpdate(CMemoryPool *mp,
+ CExpression *pexpr)
+{
+ GPOS_ASSERT(NULL != mp);
+ GPOS_ASSERT(NULL != pexpr);
+ COperator *pop = pexpr->Pop();
+ if (COperator::EopLogicalUpdate != pop->Eopid())
+ {
+ pexpr->AddRef();
+ return pexpr;
+ }
+ CLogicalUpdate *popUpdate = CLogicalUpdate::PopConvert(pop);
+ CTableDescriptor *tabdesc = popUpdate->Ptabdesc();
+ CColRefArray *pdrgpcrInsert = popUpdate->PdrgpcrInsert();
+ CColRefArray *pdrgpcrDelete = popUpdate->PdrgpcrDelete();
+ const ULONG num_cols = pdrgpcrInsert->Size();
+ BOOL split_update = false;
+ CColRefArray *ppartColRefs = GPOS_NEW(mp) CColRefArray(mp);
+ const ULongPtrArray *pdrgpulPart = tabdesc->PdrgpulPart();
+ const ULONG ulPartKeys = pdrgpulPart->Size();
+
+ // Uses split update if any of the modified columns are either
+ // distribution or partition keys.
+ for (ULONG ul = 0; ul < ulPartKeys; ul++)
+ {
+ ULONG *pulPartKey = (*pdrgpulPart)[ul];
+ CColRef *colref = (*pdrgpcrInsert)[*pulPartKey];
+ ppartColRefs->Append(colref);
+ }
+
+ for (ULONG ul = 0; ul < num_cols; ul++)
+ {
+ CColRef *pcrInsert = (*pdrgpcrInsert)[ul];
+ CColRef *pcrDelete = (*pdrgpcrDelete)[ul];
+ // Checking if column is either distribution or partition key.
+ if (pcrInsert != pcrDelete &&
+ (pcrDelete->IsDistCol() || ppartColRefs->Find(pcrInsert) != NULL))
+ {
+ split_update = true;
+ break;
+ }
+ }
+ ppartColRefs->Release();
+ if (!split_update)
+ {
+ CExpression *pexprChild = (*pexpr)[0];
+ pexprChild->AddRef();
+ pdrgpcrInsert->AddRef();
+ pdrgpcrDelete->AddRef();
+ tabdesc->AddRef();
+ CExpression *pexprNew = GPOS_NEW(mp) CExpression(
+ mp,
+ GPOS_NEW(mp) CLogicalUpdate(
+ mp, tabdesc, pdrgpcrDelete, pdrgpcrInsert, popUpdate->PcrCtid(),
+ popUpdate->PcrSegmentId(), popUpdate->PcrTupleOid(), false),
+ pexprChild);
+ return pexprNew;
+ }
+ pexpr->AddRef();
+ return pexpr;
+}
+
// main driver, pre-processing of input logical expression
CExpression *
CExpressionPreprocessor::PexprPreprocess(
@@ -3257,12 +3341,18 @@ CExpressionPreprocessor::PexprPreprocess(
PexprTransposeSelectAndProject(mp, pexprExistWithPredFromINSubq);
pexprExistWithPredFromINSubq->Release();
- // (28) normalize expression again
- CExpression *pexprNormalized2 =
- CNormalizer::PexprNormalize(mp, pexprTransposeSelectAndProject);
+ // (28) convert split update to inplace update
+ CExpression *pexprSplitUpdateToInplace =
+ ConvertSplitUpdateToInPlaceUpdate(mp, pexprTransposeSelectAndProject);
GPOS_CHECK_ABORT;
pexprTransposeSelectAndProject->Release();
+ // (29) normalize expression again
+ CExpression *pexprNormalized2 =
+ CNormalizer::PexprNormalize(mp, pexprSplitUpdateToInplace);
+ GPOS_CHECK_ABORT;
+ pexprSplitUpdateToInplace->Release();
+
return pexprNormalized2;
}
diff --git a/src/backend/gporca/libgpopt/src/operators/CLogicalDML.cpp b/src/backend/gporca/libgpopt/src/operators/CLogicalDML.cpp
index ac37fda4f0fd..1e6c01061629 100644
--- a/src/backend/gporca/libgpopt/src/operators/CLogicalDML.cpp
+++ b/src/backend/gporca/libgpopt/src/operators/CLogicalDML.cpp
@@ -22,8 +22,6 @@
using namespace gpopt;
-const WCHAR CLogicalDML::m_rgwszDml[EdmlSentinel][10] = {
- GPOS_WSZ_LIT("Insert"), GPOS_WSZ_LIT("Delete"), GPOS_WSZ_LIT("Update")};
//---------------------------------------------------------------------------
// @function:
@@ -41,7 +39,8 @@ CLogicalDML::CLogicalDML(CMemoryPool *mp)
m_pcrAction(NULL),
m_pcrCtid(NULL),
m_pcrSegmentId(NULL),
- m_pcrTupleOid(NULL)
+ m_pcrTupleOid(NULL),
+ m_fSplit(true)
{
m_fPattern = true;
}
@@ -58,7 +57,8 @@ CLogicalDML::CLogicalDML(CMemoryPool *mp, EDMLOperator edmlop,
CTableDescriptor *ptabdesc,
CColRefArray *pdrgpcrSource, CBitSet *pbsModified,
CColRef *pcrAction, CColRef *pcrCtid,
- CColRef *pcrSegmentId, CColRef *pcrTupleOid)
+ CColRef *pcrSegmentId, CColRef *pcrTupleOid,
+ BOOL fSplit)
: CLogical(mp),
m_edmlop(edmlop),
m_ptabdesc(ptabdesc),
@@ -67,7 +67,8 @@ CLogicalDML::CLogicalDML(CMemoryPool *mp, EDMLOperator edmlop,
m_pcrAction(pcrAction),
m_pcrCtid(pcrCtid),
m_pcrSegmentId(pcrSegmentId),
- m_pcrTupleOid(pcrTupleOid)
+ m_pcrTupleOid(pcrTupleOid),
+ m_fSplit(fSplit)
{
GPOS_ASSERT(EdmlSentinel != edmlop);
GPOS_ASSERT(NULL != ptabdesc);
@@ -134,7 +135,8 @@ CLogicalDML::Matches(COperator *pop) const
m_pcrSegmentId == popDML->PcrSegmentId() &&
m_pcrTupleOid == popDML->PcrTupleOid() &&
m_ptabdesc->MDId()->Equals(popDML->Ptabdesc()->MDId()) &&
- m_pdrgpcrSource->Equals(popDML->PdrgpcrSource());
+ m_pdrgpcrSource->Equals(popDML->PdrgpcrSource()) &&
+ m_fSplit == popDML->FSplit();
}
//---------------------------------------------------------------------------
@@ -210,7 +212,7 @@ CLogicalDML::PopCopyWithRemappedColumns(CMemoryPool *mp,
return GPOS_NEW(mp)
CLogicalDML(mp, m_edmlop, m_ptabdesc, colref_array, m_pbsModified,
- pcrAction, pcrCtid, pcrSegmentId, pcrTupleOid);
+ pcrAction, pcrCtid, pcrSegmentId, pcrTupleOid, m_fSplit);
}
//---------------------------------------------------------------------------
@@ -346,9 +348,9 @@ CLogicalDML::OsPrint(IOstream &os) const
}
os << SzId() << " (";
- os << m_rgwszDml[m_edmlop] << ", ";
m_ptabdesc->Name().OsPrint(os);
- os << "), Affected Columns: [";
+ CLogicalDML::PrintOperatorType(os, m_edmlop, m_fSplit);
+ os << "Affected Columns: [";
CUtils::OsPrintDrgPcr(os, m_pdrgpcrSource);
os << "], Action: (";
m_pcrAction->OsPrint(os);
@@ -365,4 +367,44 @@ CLogicalDML::OsPrint(IOstream &os) const
return os;
}
+//---------------------------------------------------------------------------
+// @function:
+// CLogicalDML::PrintOperatorType
+//
+// @doc:
+// Helper function to print DML operator type based on the given operator
+// enum, used in OSPrint to print objects.
+//
+//---------------------------------------------------------------------------
+void
+CLogicalDML::PrintOperatorType(IOstream &os, EDMLOperator edmlOperator,
+ BOOL fSplit)
+{
+ switch (edmlOperator)
+ {
+ case EdmlInsert:
+ os << "), Insert, ";
+ break;
+
+ case EdmlDelete:
+ os << "), Delete, ";
+ break;
+
+ case EdmlUpdate:
+ if (fSplit)
+ {
+ os << "), Split Update, ";
+ }
+ else
+ {
+ os << "), In-place Update, ";
+ }
+ break;
+
+ default:
+ GPOS_ASSERT(!"Unrecognized DML Operator");
+ break;
+ }
+}
+
// EOF
diff --git a/src/backend/gporca/libgpopt/src/operators/CLogicalUpdate.cpp b/src/backend/gporca/libgpopt/src/operators/CLogicalUpdate.cpp
index 0b469ebcf267..00ba146931b8 100644
--- a/src/backend/gporca/libgpopt/src/operators/CLogicalUpdate.cpp
+++ b/src/backend/gporca/libgpopt/src/operators/CLogicalUpdate.cpp
@@ -36,7 +36,8 @@ CLogicalUpdate::CLogicalUpdate(CMemoryPool *mp)
m_pdrgpcrInsert(NULL),
m_pcrCtid(NULL),
m_pcrSegmentId(NULL),
- m_pcrTupleOid(NULL)
+ m_pcrTupleOid(NULL),
+ m_fSplit(true)
{
m_fPattern = true;
}
@@ -52,14 +53,16 @@ CLogicalUpdate::CLogicalUpdate(CMemoryPool *mp)
CLogicalUpdate::CLogicalUpdate(CMemoryPool *mp, CTableDescriptor *ptabdesc,
CColRefArray *pdrgpcrDelete,
CColRefArray *pdrgpcrInsert, CColRef *pcrCtid,
- CColRef *pcrSegmentId, CColRef *pcrTupleOid)
+ CColRef *pcrSegmentId, CColRef *pcrTupleOid,
+ BOOL fSplit)
: CLogical(mp),
m_ptabdesc(ptabdesc),
m_pdrgpcrDelete(pdrgpcrDelete),
m_pdrgpcrInsert(pdrgpcrInsert),
m_pcrCtid(pcrCtid),
m_pcrSegmentId(pcrSegmentId),
- m_pcrTupleOid(pcrTupleOid)
+ m_pcrTupleOid(pcrTupleOid),
+ m_fSplit(fSplit)
{
GPOS_ASSERT(NULL != ptabdesc);
@@ -118,7 +121,8 @@ CLogicalUpdate::Matches(COperator *pop) const
m_pcrTupleOid == popUpdate->PcrTupleOid() &&
m_ptabdesc->MDId()->Equals(popUpdate->Ptabdesc()->MDId()) &&
m_pdrgpcrDelete->Equals(popUpdate->PdrgpcrDelete()) &&
- m_pdrgpcrInsert->Equals(popUpdate->PdrgpcrInsert());
+ m_pdrgpcrInsert->Equals(popUpdate->PdrgpcrInsert()) &&
+ m_fSplit == popUpdate->FSplit();
}
//---------------------------------------------------------------------------
@@ -175,7 +179,7 @@ CLogicalUpdate::PopCopyWithRemappedColumns(CMemoryPool *mp,
}
return GPOS_NEW(mp)
CLogicalUpdate(mp, m_ptabdesc, pdrgpcrDelete, pdrgpcrInsert, pcrCtid,
- pcrSegmentId, pcrTupleOid);
+ pcrSegmentId, pcrTupleOid, m_fSplit);
}
//---------------------------------------------------------------------------
@@ -282,10 +286,17 @@ CLogicalUpdate::OsPrint(IOstream &os) const
{
return COperator::OsPrint(os);
}
-
os << SzId() << " (";
m_ptabdesc->Name().OsPrint(os);
- os << "), Delete Columns: [";
+ if (m_fSplit)
+ {
+ os << "), Split Update";
+ }
+ else
+ {
+ os << "), In-place Update";
+ }
+ os << ", Delete Columns: [";
CUtils::OsPrintDrgPcr(os, m_pdrgpcrDelete);
os << "], Insert Columns: [";
CUtils::OsPrintDrgPcr(os, m_pdrgpcrInsert);
diff --git a/src/backend/gporca/libgpopt/src/operators/CPhysicalDML.cpp b/src/backend/gporca/libgpopt/src/operators/CPhysicalDML.cpp
index 1546260dab5a..171b36817961 100644
--- a/src/backend/gporca/libgpopt/src/operators/CPhysicalDML.cpp
+++ b/src/backend/gporca/libgpopt/src/operators/CPhysicalDML.cpp
@@ -38,7 +38,8 @@ CPhysicalDML::CPhysicalDML(CMemoryPool *mp, CLogicalDML::EDMLOperator edmlop,
CTableDescriptor *ptabdesc,
CColRefArray *pdrgpcrSource, CBitSet *pbsModified,
CColRef *pcrAction, CColRef *pcrCtid,
- CColRef *pcrSegmentId, CColRef *pcrTupleOid)
+ CColRef *pcrSegmentId, CColRef *pcrTupleOid,
+ BOOL fSplit)
: CPhysical(mp),
m_edmlop(edmlop),
m_ptabdesc(ptabdesc),
@@ -50,7 +51,8 @@ CPhysicalDML::CPhysicalDML(CMemoryPool *mp, CLogicalDML::EDMLOperator edmlop,
m_pcrTupleOid(pcrTupleOid),
m_pds(NULL),
m_pos(NULL),
- m_pcrsRequiredLocal(NULL)
+ m_pcrsRequiredLocal(NULL),
+ m_fSplit(fSplit)
{
GPOS_ASSERT(CLogicalDML::EdmlSentinel != edmlop);
GPOS_ASSERT(NULL != ptabdesc);
@@ -80,33 +82,8 @@ CPhysicalDML::CPhysicalDML(CMemoryPool *mp, CLogicalDML::EDMLOperator edmlop,
// Update of the distribution key: This will be handled with a Split node below the DML node,
// with the split deleting the existing rows and this DML node inserting the new rows,
// so this is handled here like an insert, using hash distribution for all partitions.
- BOOL is_update_without_changing_distribution_key = false;
- if (CLogicalDML::EdmlUpdate == edmlop)
- {
- CDistributionSpecHashed *hashDistSpec =
- CDistributionSpecHashed::PdsConvert(m_pds);
- CColRefSet *updatedCols = GPOS_NEW(mp) CColRefSet(mp);
- CColRefSet *distributionCols = hashDistSpec->PcrsUsed(mp);
-
- // compute a ColRefSet of the updated columns
- for (ULONG c = 0; c < pdrgpcrSource->Size(); c++)
- {
- if (pbsModified->Get(c))
- {
- updatedCols->Include((*pdrgpcrSource)[c]);
- }
- }
-
- is_update_without_changing_distribution_key =
- !updatedCols->FIntersects(distributionCols);
-
- updatedCols->Release();
- distributionCols->Release();
- }
-
- if (CLogicalDML::EdmlDelete == edmlop ||
- is_update_without_changing_distribution_key)
+ if (CLogicalDML::EdmlDelete == edmlop || !fSplit)
{
m_pds->Release();
m_pds = GPOS_NEW(mp) CDistributionSpecRandom();
@@ -437,7 +414,8 @@ CPhysicalDML::Matches(COperator *pop) const
m_pcrSegmentId == popDML->PcrSegmentId() &&
m_pcrTupleOid == popDML->PcrTupleOid() &&
m_ptabdesc->MDId()->Equals(popDML->Ptabdesc()->MDId()) &&
- m_pdrgpcrSource->Equals(popDML->PdrgpcrSource());
+ m_pdrgpcrSource->Equals(popDML->PdrgpcrSource()) &&
+ m_fSplit == popDML->FSplit();
}
return false;
@@ -538,7 +516,11 @@ CPhysicalDML::ComputeRequiredLocalColumns(CMemoryPool *mp)
// include source columns
m_pcrsRequiredLocal->Include(m_pdrgpcrSource);
- m_pcrsRequiredLocal->Include(m_pcrAction);
+ // Action column is not required for InPlaceUpdate operator.
+ if (m_fSplit)
+ {
+ m_pcrsRequiredLocal->Include(m_pcrAction);
+ }
if (CLogicalDML::EdmlDelete == m_edmlop ||
CLogicalDML::EdmlUpdate == m_edmlop)
@@ -570,9 +552,9 @@ CPhysicalDML::OsPrint(IOstream &os) const
}
os << SzId() << " (";
- os << CLogicalDML::m_rgwszDml[m_edmlop] << ", ";
m_ptabdesc->Name().OsPrint(os);
- os << "), Source Columns: [";
+ CLogicalDML::PrintOperatorType(os, m_edmlop, m_fSplit);
+ os << "Source Columns: [";
CUtils::OsPrintDrgPcr(os, m_pdrgpcrSource);
os << "], Action: (";
m_pcrAction->OsPrint(os);
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
index 95557eef6d88..3bd1335ddbaa 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorDXLToExpr.cpp
@@ -1490,12 +1490,12 @@ CTranslatorDXLToExpr::PexprLogicalUpdate(const CDXLNode *dxlnode)
pcrTupleOid = LookupColRef(m_phmulcr, tuple_oid);
}
- return GPOS_NEW(m_mp)
- CExpression(m_mp,
- GPOS_NEW(m_mp) CLogicalUpdate(m_mp, ptabdesc, pdrgpcrDelete,
- pdrgpcrInsert, pcrCtid,
- pcrSegmentId, pcrTupleOid),
- pexprChild);
+ return GPOS_NEW(m_mp) CExpression(
+ m_mp,
+ GPOS_NEW(m_mp)
+ CLogicalUpdate(m_mp, ptabdesc, pdrgpcrDelete, pdrgpcrInsert,
+ pcrCtid, pcrSegmentId, pcrTupleOid, true),
+ pexprChild);
}
//---------------------------------------------------------------------------
diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
index db3d2a0f7c7c..7c10d2aaa347 100644
--- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
+++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp
@@ -5786,9 +5786,10 @@ CTranslatorExprToDXL::PdxlnDML(CExpression *pexpr,
CDXLDirectDispatchInfo *dxl_direct_dispatch_info =
GetDXLDirectDispatchInfo(pexpr);
- CDXLPhysicalDML *pdxlopDML = GPOS_NEW(m_mp) CDXLPhysicalDML(
- m_mp, dxl_dml_type, table_descr, pdrgpul, action_colid, ctid_colid,
- segid_colid, preserve_oids, tuple_oid, dxl_direct_dispatch_info);
+ CDXLPhysicalDML *pdxlopDML = GPOS_NEW(m_mp)
+ CDXLPhysicalDML(m_mp, dxl_dml_type, table_descr, pdrgpul, action_colid,
+ ctid_colid, segid_colid, preserve_oids, tuple_oid,
+ dxl_direct_dispatch_info, popDML->FSplit());
// project list
CColRefSet *pcrsOutput = pexpr->Prpp()->PcrsRequired();
diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformImplementDML.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformImplementDML.cpp
index 3c5b920e4760..2ccc77c2ad58 100644
--- a/src/backend/gporca/libgpopt/src/xforms/CXformImplementDML.cpp
+++ b/src/backend/gporca/libgpopt/src/xforms/CXformImplementDML.cpp
@@ -89,6 +89,7 @@ CXformImplementDML::Transform(CXformContext *pxfctxt, CXformResult *pxfres,
CColRef *pcrCtid = popDML->PcrCtid();
CColRef *pcrSegmentId = popDML->PcrSegmentId();
CColRef *pcrTupleOid = popDML->PcrTupleOid();
+ BOOL fSplit = popDML->FSplit();
// child of DML operator
CExpression *pexprChild = (*pexpr)[0];
@@ -99,7 +100,7 @@ CXformImplementDML::Transform(CXformContext *pxfctxt, CXformResult *pxfres,
mp,
GPOS_NEW(mp)
CPhysicalDML(mp, edmlop, ptabdesc, pdrgpcrSource, pbsModified,
- pcrAction, pcrCtid, pcrSegmentId, pcrTupleOid),
+ pcrAction, pcrCtid, pcrSegmentId, pcrTupleOid, fSplit),
pexprChild);
// add alternative to transformation result
pxfres->Add(pexprAlt);
diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformUpdate2DML.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformUpdate2DML.cpp
index a1cd4328d20e..80249bf2f82e 100644
--- a/src/backend/gporca/libgpopt/src/xforms/CXformUpdate2DML.cpp
+++ b/src/backend/gporca/libgpopt/src/xforms/CXformUpdate2DML.cpp
@@ -87,6 +87,7 @@ CXformUpdate2DML::Transform(CXformContext *pxfctxt, CXformResult *pxfres,
CColRef *pcrCtid = popUpdate->PcrCtid();
CColRef *pcrSegmentId = popUpdate->PcrSegmentId();
CColRef *pcrTupleOid = popUpdate->PcrTupleOid();
+ BOOL fSplit = popUpdate->FSplit();
// child of update operator
CExpression *pexprChild = (*pexpr)[0];
@@ -109,23 +110,32 @@ CXformUpdate2DML::Transform(CXformContext *pxfctxt, CXformResult *pxfres,
CMDAccessor *md_accessor = poctxt->Pmda();
CColumnFactory *col_factory = poctxt->Pcf();
- pdrgpcrDelete->AddRef();
- pdrgpcrInsert->AddRef();
-
const IMDType *pmdtype = md_accessor->PtMDType();
CColRef *pcrAction = col_factory->PcrCreate(pmdtype, default_type_modifier);
- CExpression *pexprProjElem = GPOS_NEW(mp) CExpression(
- mp, GPOS_NEW(mp) CScalarProjectElement(mp, pcrAction),
- GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CScalarDMLAction(mp)));
+ CExpression *pexprSplit = NULL;
+ if (fSplit)
+ {
+ pdrgpcrDelete->AddRef();
+ pdrgpcrInsert->AddRef();
+ CExpression *pexprProjElem = GPOS_NEW(mp) CExpression(
+ mp, GPOS_NEW(mp) CScalarProjectElement(mp, pcrAction),
+ GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CScalarDMLAction(mp)));
+
+ CExpression *pexprProjList = GPOS_NEW(mp)
+ CExpression(mp, GPOS_NEW(mp) CScalarProjectList(mp), pexprProjElem);
+ pexprSplit = GPOS_NEW(mp) CExpression(
+ mp,
+ GPOS_NEW(mp)
+ CLogicalSplit(mp, pdrgpcrDelete, pdrgpcrInsert, pcrCtid,
+ pcrSegmentId, pcrAction, pcrTupleOid),
+ pexprChild, pexprProjList);
+ }
+ else
+ {
+ pexprSplit = pexprChild;
+ }
- CExpression *pexprProjList = GPOS_NEW(mp)
- CExpression(mp, GPOS_NEW(mp) CScalarProjectList(mp), pexprProjElem);
- CExpression *pexprSplit = GPOS_NEW(mp) CExpression(
- mp,
- GPOS_NEW(mp) CLogicalSplit(mp, pdrgpcrDelete, pdrgpcrInsert, pcrCtid,
- pcrSegmentId, pcrAction, pcrTupleOid),
- pexprChild, pexprProjList);
// add assert checking that no NULL values are inserted for nullable columns or no check constraints are violated
COptimizerConfig *optimizer_config =
@@ -143,28 +153,45 @@ CXformUpdate2DML::Transform(CXformContext *pxfctxt, CXformResult *pxfres,
const ULONG num_cols = pdrgpcrInsert->Size();
- CBitSet *pbsModified = GPOS_NEW(mp) CBitSet(mp, ptabdesc->ColumnCount());
- for (ULONG ul = 0; ul < num_cols; ul++)
+ CExpression *pexprDML = NULL;
+ // create logical DML
+ ptabdesc->AddRef();
+ if (fSplit)
{
- CColRef *pcrInsert = (*pdrgpcrInsert)[ul];
- CColRef *pcrDelete = (*pdrgpcrDelete)[ul];
- if (pcrInsert != pcrDelete)
+ CBitSet *pbsModified =
+ GPOS_NEW(mp) CBitSet(mp, ptabdesc->ColumnCount());
+ for (ULONG ul = 0; ul < num_cols; ul++)
{
- // delete columns refer to the original tuple's descriptor, if it's different
- // from the corresponding insert column, then we're modifying the column
- // at that position
- pbsModified->ExchangeSet(ul);
+ CColRef *pcrInsert = (*pdrgpcrInsert)[ul];
+ CColRef *pcrDelete = (*pdrgpcrDelete)[ul];
+ if (pcrInsert != pcrDelete)
+ {
+ // delete columns refer to the original tuple's descriptor, if it's different
+ // from the corresponding insert column, then we're modifying the column
+ // at that position
+ pbsModified->ExchangeSet(ul);
+ }
}
+ pdrgpcrDelete->AddRef();
+ pexprDML = GPOS_NEW(mp) CExpression(
+ mp,
+ GPOS_NEW(mp)
+ CLogicalDML(mp, CLogicalDML::EdmlUpdate, ptabdesc,
+ pdrgpcrDelete, pbsModified, pcrAction, pcrCtid,
+ pcrSegmentId, pcrTupleOid, fSplit),
+ pexprAssertConstraints);
+ }
+ else
+ {
+ pdrgpcrInsert->AddRef();
+ pexprDML = GPOS_NEW(mp) CExpression(
+ mp,
+ GPOS_NEW(mp)
+ CLogicalDML(mp, CLogicalDML::EdmlUpdate, ptabdesc,
+ pdrgpcrInsert, GPOS_NEW(mp) CBitSet(mp), pcrAction,
+ pcrCtid, pcrSegmentId, NULL, fSplit),
+ pexprAssertConstraints);
}
- // create logical DML
- ptabdesc->AddRef();
- pdrgpcrDelete->AddRef();
- CExpression *pexprDML = GPOS_NEW(mp) CExpression(
- mp,
- GPOS_NEW(mp) CLogicalDML(mp, CLogicalDML::EdmlUpdate, ptabdesc,
- pdrgpcrDelete, pbsModified, pcrAction, pcrCtid,
- pcrSegmentId, pcrTupleOid),
- pexprAssertConstraints);
// TODO: - Oct 30, 2012; detect and handle AFTER triggers on update
diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp
index 10e83c485e4f..ffb87a324b86 100644
--- a/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp
+++ b/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp
@@ -1358,7 +1358,7 @@ CXformUtils::PexprLogicalDMLOverProject(CMemoryPool *mp,
GPOS_NEW(mp)
CLogicalDML(mp, edmlop, ptabdesc, colref_array,
GPOS_NEW(mp) CBitSet(mp) /*pbsModified*/, pcrAction,
- pcrCtid, pcrSegmentId, NULL /*pcrTupleOid*/),
+ pcrCtid, pcrSegmentId, NULL /*pcrTupleOid*/, true),
pexprProject);
CExpression *pexprOutput = pexprDML;
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDML.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDML.h
index e1a034a8a5b6..637d063251d6 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDML.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalDML.h
@@ -69,6 +69,9 @@ class CDXLPhysicalDML : public CDXLPhysical
// direct dispatch info for insert statements
CDXLDirectDispatchInfo *m_direct_dispatch_info;
+ // Is Split Update
+ BOOL m_fSplit;
+
// private copy ctor
CDXLPhysicalDML(const CDXLPhysicalDML &);
@@ -79,7 +82,8 @@ class CDXLPhysicalDML : public CDXLPhysical
ULongPtrArray *src_colids_array, ULONG action_colid,
ULONG ctid_colid, ULONG segid_colid, BOOL preserve_oids,
ULONG tuple_oid,
- CDXLDirectDispatchInfo *dxl_direct_dispatch_info);
+ CDXLDirectDispatchInfo *dxl_direct_dispatch_info,
+ BOOL fSplit);
// dtor
virtual ~CDXLPhysicalDML();
@@ -153,6 +157,13 @@ class CDXLPhysicalDML : public CDXLPhysical
return m_direct_dispatch_info;
}
+ // Is update using split
+ BOOL
+ FSplit() const
+ {
+ return m_fSplit;
+ }
+
#ifdef GPOS_DEBUG
// checks whether the operator has valid structure, i.e. number and
// types of child nodes
diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerPhysicalDML.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerPhysicalDML.h
index 52bfd921b8ce..510f408f4e97 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerPhysicalDML.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/parser/CParseHandlerPhysicalDML.h
@@ -59,6 +59,9 @@ class CParseHandlerPhysicalDML : public CParseHandlerPhysicalOp
// private copy ctor
CParseHandlerPhysicalDML(const CParseHandlerPhysicalDML &);
+ // Split Update
+ BOOL m_fSplit;
+
// process the start of an element
void StartElement(
const XMLCh *const element_uri, // URI of element's namespace
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 57595437b668..ff4e11d8d9fa 100644
--- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
+++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h
@@ -367,6 +367,7 @@ enum Edxltoken
EdxltokenGpSegmentIdColId,
EdxltokenTupleOidColId,
EdxltokenUpdatePreservesOids,
+ EdxltokenSplitUpdate,
EdxltokenInputSegments,
EdxltokenOutputSegments,
diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDML.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDML.cpp
index dee91cc08e30..11042300e66c 100644
--- a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDML.cpp
+++ b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalDML.cpp
@@ -32,7 +32,8 @@ CDXLPhysicalDML::CDXLPhysicalDML(
CMemoryPool *mp, const EdxlDmlType dxl_dml_type,
CDXLTableDescr *table_descr, ULongPtrArray *src_colids_array,
ULONG action_colid, ULONG ctid_colid, ULONG segid_colid, BOOL preserve_oids,
- ULONG tuple_oid, CDXLDirectDispatchInfo *dxl_direct_dispatch_info)
+ ULONG tuple_oid, CDXLDirectDispatchInfo *dxl_direct_dispatch_info,
+ BOOL fSplit)
: CDXLPhysical(mp),
m_dxl_dml_type(dxl_dml_type),
m_dxl_table_descr(table_descr),
@@ -42,7 +43,8 @@ CDXLPhysicalDML::CDXLPhysicalDML(
m_segid_colid(segid_colid),
m_preserve_oids(preserve_oids),
m_tuple_oid(tuple_oid),
- m_direct_dispatch_info(dxl_direct_dispatch_info)
+ m_direct_dispatch_info(dxl_direct_dispatch_info),
+ m_fSplit(fSplit)
{
GPOS_ASSERT(EdxldmlSentinel > dxl_dml_type);
GPOS_ASSERT(NULL != table_descr);
@@ -131,13 +133,19 @@ CDXLPhysicalDML::SerializeToDXL(CXMLSerializer *xml_serializer,
CDXLTokens::GetDXLTokenStr(EdxltokenGpSegmentIdColId), m_segid_colid);
if (Edxldmlupdate == m_dxl_dml_type)
+ {
+ xml_serializer->AddAttribute(
+ CDXLTokens::GetDXLTokenStr(EdxltokenSplitUpdate), m_fSplit);
+ }
+
+ if (Edxldmlupdate == m_dxl_dml_type && !m_fSplit)
{
xml_serializer->AddAttribute(
CDXLTokens::GetDXLTokenStr(EdxltokenUpdatePreservesOids),
m_preserve_oids);
}
- if (m_preserve_oids)
+ if (m_preserve_oids && !m_fSplit)
{
xml_serializer->AddAttribute(
CDXLTokens::GetDXLTokenStr(EdxltokenTupleOidColId), m_tuple_oid);
diff --git a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalDML.cpp b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalDML.cpp
index 8b0e90c3b202..e1b3806bcc94 100644
--- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalDML.cpp
+++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalDML.cpp
@@ -43,7 +43,8 @@ CParseHandlerPhysicalDML::CParseHandlerPhysicalDML(
m_ctid_colid(0),
m_segid_colid(0),
m_preserve_oids(false),
- m_tuple_oid_colid(0)
+ m_tuple_oid_colid(0),
+ m_fSplit(true)
{
}
@@ -125,6 +126,16 @@ CParseHandlerPhysicalDML::StartElement(const XMLCh *const, // element_uri,
EdxltokenTupleOidColId, EdxltokenPhysicalDMLUpdate);
}
+ const XMLCh *fSplit =
+ attrs.getValue(CDXLTokens::XmlstrToken(EdxltokenSplitUpdate));
+ if (NULL != fSplit)
+ {
+ m_fSplit = CDXLOperatorFactory::ConvertAttrValueToBool(
+ m_parse_handler_mgr->GetDXLMemoryManager(), fSplit,
+ EdxltokenSplitUpdate, EdxltokenPhysicalDMLUpdate);
+ }
+
+
// parse handler for physical operator
CParseHandlerBase *child_parse_handler =
CParseHandlerFactory::GetParseHandler(
@@ -225,7 +236,7 @@ CParseHandlerPhysicalDML::EndElement(const XMLCh *const, // element_uri,
CDXLPhysicalDML *dxl_op = GPOS_NEW(m_mp) CDXLPhysicalDML(
m_mp, m_dxl_dml_type, table_descr, m_src_colids_array, m_action_colid,
m_ctid_colid, m_segid_colid, m_preserve_oids, m_tuple_oid_colid,
- dxl_direct_dispatch_info);
+ dxl_direct_dispatch_info, m_fSplit);
m_dxl_node = GPOS_NEW(m_mp) CDXLNode(m_mp, dxl_op);
// set statistics and physical properties
diff --git a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
index e2bf166efd47..c68aeea6b0cd 100644
--- a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
+++ b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp
@@ -416,6 +416,7 @@ CDXLTokens::Init(CMemoryPool *mp)
{EdxltokenGpSegmentIdColId, GPOS_WSZ_LIT("SegmentIdCol")},
{EdxltokenTupleOidColId, GPOS_WSZ_LIT("TupleOidCol")},
{EdxltokenUpdatePreservesOids, GPOS_WSZ_LIT("PreserveOids")},
+ {EdxltokenSplitUpdate, GPOS_WSZ_LIT("IsSplitUpdate")},
{EdxltokenInputSegments, GPOS_WSZ_LIT("InputSegments")},
{EdxltokenOutputSegments, GPOS_WSZ_LIT("OutputSegments")},
diff --git a/src/backend/gporca/server/src/unittest/CTestUtils.cpp b/src/backend/gporca/server/src/unittest/CTestUtils.cpp
index c76a35ce4194..e66a83dd8cd4 100644
--- a/src/backend/gporca/server/src/unittest/CTestUtils.cpp
+++ b/src/backend/gporca/server/src/unittest/CTestUtils.cpp
@@ -1813,7 +1813,7 @@ CTestUtils::PexprLogicalUpdate(CMemoryPool *mp)
return GPOS_NEW(mp) CExpression(
mp,
GPOS_NEW(mp) CLogicalUpdate(mp, ptabdesc, pdrgpcrDelete, pdrgpcrInsert,
- colref, colref, NULL /*pcrTupleOid*/),
+ colref, colref, NULL /*pcrTupleOid*/, true),
pexprGet);
}
diff --git a/src/include/executor/execDML.h b/src/include/executor/execDML.h
index ff66c9e4cc4a..d53667263736 100644
--- a/src/include/executor/execDML.h
+++ b/src/include/executor/execDML.h
@@ -59,7 +59,8 @@ ExecUpdate(ItemPointer tupleid,
TupleTableSlot *planSlot,
EPQState *epqstate,
EState *estate,
- bool canSetTag);
+ bool canSetTag,
+ PlanGenerator planGen);
#endif /* EXECDML_H */
diff --git a/src/test/isolation/expected/create_index_hot.out b/src/test/isolation/expected/create_index_hot.out
index fb37c9a989d7..519318e1d9f0 100644
--- a/src/test/isolation/expected/create_index_hot.out
+++ b/src/test/isolation/expected/create_index_hot.out
@@ -1,6 +1,6 @@
Parsed test spec with 2 sessions
-starting permutation: s2begin s2select s1optimizeroff s1update s1createindexonc s2select s2forceindexscan s2select
+starting permutation: s2begin s2select s1update s1createindexonc s2select s2forceindexscan s2select
step s2begin: BEGIN ISOLATION LEVEL SERIALIZABLE;
step s2select: select '#' as expected, c from hot where c = '#'
union all
@@ -8,7 +8,6 @@ step s2select: select '#' as expected, c from hot where c = '#'
expected c
# #
-step s1optimizeroff: set optimizer = off;
step s1update: update hot set c = '$' where c = '#';
step s1createindexonc: create index idx_c on hot (c);
step s2select: select '#' as expected, c from hot where c = '#'
diff --git a/src/test/isolation/specs/create_index_hot.spec b/src/test/isolation/specs/create_index_hot.spec
index fe224c4917d1..bb80d8e3cdec 100644
--- a/src/test/isolation/specs/create_index_hot.spec
+++ b/src/test/isolation/specs/create_index_hot.spec
@@ -23,9 +23,7 @@ teardown
# Update a row, and create an index on the updated column. This produces
# a broken HOT chain.
-#FIXME do not turn off the optimizer when ORCA stops always using Split Update.
session "s1"
-step "s1optimizeroff" { set optimizer = off; }
step "s1update" { update hot set c = '$' where c = '#'; }
step "s1createindexonc" { create index idx_c on hot (c); }
@@ -41,7 +39,6 @@ permutation
"s2begin"
"s2select"
- "s1optimizeroff"
"s1update"
"s1createindexonc"
diff --git a/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out b/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out
index da71357fdba3..0508760f27a3 100644
--- a/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out
+++ b/src/test/isolation2/expected/gdd/concurrent_update_optimizer.out
@@ -353,29 +353,29 @@ UPDATE 1
-- make sure planner will contain InitPlan
-- NOTE: orca does not generate InitPlan.
2: explain update t_epq_subplans set b = b + 1 where a > -1.5 * (select max(a) from t_epq_subplans);
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
- Update (cost=0.00..1324032.68 rows=1 width=1)
- -> Split (cost=0.00..1324032.61 rows=1 width=22)
- -> Result (cost=0.00..1324032.61 rows=1 width=22)
- -> Seq Scan on t_epq_subplans (cost=0.00..1324032.61 rows=1 width=18)
- Filter: ((a)::numeric > ((-1.5) * ((SubPlan 1))::numeric))
- SubPlan 1 (slice0; segments: 3)
- -> Materialize (cost=0.00..431.00 rows=1 width=4)
- -> Broadcast Motion 1:3 (slice2; segments: 1) (cost=0.00..431.00 rows=3 width=4)
- -> Aggregate (cost=0.00..431.00 rows=1 width=4)
- -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=4)
- -> Aggregate (cost=0.00..431.00 rows=1 width=4)
- -> Seq Scan on t_epq_subplans t_epq_subplans_1 (cost=0.00..431.00 rows=1 width=4)
- Optimizer: Pivotal Optimizer (GPORCA)
-(14 rows)
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------------------------
+ Update (cost=0.00..1324032.63 rows=1 width=1)
+ -> Result (cost=0.00..1324032.61 rows=1 width=18)
+ -> Seq Scan on t_epq_subplans (cost=0.00..1324032.61 rows=1 width=18)
+ Filter: ((a)::numeric > ('-1.5'::numeric * ((SubPlan 1))::numeric))
+ SubPlan 1 (slice0; segments: 3)
+ -> Materialize (cost=0.00..431.00 rows=1 width=4)
+ -> Broadcast Motion 1:3 (slice2; segments: 1) (cost=0.00..431.00 rows=3 width=4)
+ -> Aggregate (cost=0.00..431.00 rows=1 width=4)
+ -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=4)
+ -> Aggregate (cost=0.00..431.00 rows=1 width=4)
+ -> Seq Scan on t_epq_subplans t_epq_subplans_1 (cost=0.00..431.00 rows=1 width=4)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(12 rows)
2&: update t_epq_subplans set b = b + 1 where a > -1.5 * (select max(a) from t_epq_subplans);
1: end;
END
-- session 2 should throw error and not PANIC
2<: <... completed>
-ERROR: tuple to be updated was already moved to another segment due to concurrent update (seg1 127.0.1.1:6003 pid=116712)
+ERROR: could not serialize access due to concurrent update (seg1 172.17.0.2:6003 pid=86009)
+HINT: Use PostgreSQL Planner instead of Optimizer for this query via optimizer=off GUC setting
1: drop table t_epq_subplans;
DROP
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 b313e608b524..d2fa1ca53b5c 100644
--- a/src/test/isolation2/expected/modify_table_data_corrupt_optimizer.out
+++ b/src/test/isolation2/expected/modify_table_data_corrupt_optimizer.out
@@ -107,25 +107,24 @@ ABORT
-- TODO: this case is for planner, it will not error out on 6X now,
-- because 6x does not remove explicit motion yet.
explain (costs off) update tab1 set a = 999 from tab2, tab3 where tab1.a = tab2.a and tab1.b = tab3.b;
- QUERY PLAN
----------------------------------------------------------------------------------
- Update
- -> Redistribute Motion 3:3 (slice2; segments: 3)
- Hash Key: tab1.b
- -> Split
- -> Result
- -> Hash Join
- Hash Cond: (tab2.a = tab1.a)
- -> Seq Scan on tab2
- -> Hash
- -> Broadcast Motion 3:3 (slice1; segments: 3)
- -> Hash Join
- Hash Cond: (tab3.b = tab1.b)
- -> Seq Scan on tab3
- -> Hash
- -> Seq Scan on tab1
- Optimizer: Pivotal Optimizer (GPORCA)
-(16 rows)
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Update
+ -> Result
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
+ Hash Key: tab1.b
+ -> Hash Join
+ Hash Cond: (tab2.a = tab1.a)
+ -> Seq Scan on tab2
+ -> Hash
+ -> Broadcast Motion 3:3 (slice1; segments: 3)
+ -> Hash Join
+ Hash Cond: (tab3.b = tab1.b)
+ -> Seq Scan on tab3
+ -> Hash
+ -> Seq Scan on tab1
+ Optimizer: Pivotal Optimizer (GPORCA)
+(15 rows)
begin;
BEGIN
update tab1 set a = 999 from tab2, tab3 where tab1.a = tab2.a and tab1.b = tab3.b;
@@ -163,26 +162,25 @@ ABORT
-- For orca, this will error out
explain (costs off) update tab1 set a = 999 from tab2, tab3 where tab1.a = tab2.a and tab1.b = tab3.a;
- QUERY PLAN
----------------------------------------------------------------------------------------------------
- Update
- -> Redistribute Motion 3:3 (slice3; segments: 3)
- Hash Key: tab1.b
- -> Split
- -> Result
- -> Hash Join
- Hash Cond: (tab3.a = tab1.b)
- -> Seq Scan on tab3
- -> Hash
- -> Broadcast Motion 3:3 (slice2; segments: 3)
- -> Hash Join
- Hash Cond: (tab2.a = tab1.a)
- -> Seq Scan on tab2
- -> Hash
- -> Broadcast Motion 3:3 (slice1; segments: 3)
- -> Seq Scan on tab1
- Optimizer: Pivotal Optimizer (GPORCA)
-(17 rows)
+ QUERY PLAN
+---------------------------------------------------------------------------------------------
+ Update
+ -> Result
+ -> Redistribute Motion 3:3 (slice3; segments: 3)
+ Hash Key: tab1.b
+ -> Hash Join
+ Hash Cond: (tab3.a = tab1.b)
+ -> Seq Scan on tab3
+ -> Hash
+ -> Broadcast Motion 3:3 (slice2; segments: 3)
+ -> Hash Join
+ Hash Cond: (tab2.a = tab1.a)
+ -> Seq Scan on tab2
+ -> Hash
+ -> Broadcast Motion 3:3 (slice1; segments: 3)
+ -> Seq Scan on tab1
+ Optimizer: Pivotal Optimizer (GPORCA)
+(16 rows)
begin;
BEGIN
update tab1 set a = 999 from tab2, tab3 where tab1.a = tab2.a and tab1.b = tab3.a;
diff --git a/src/test/regress/expected/DML_over_joins_optimizer.out b/src/test/regress/expected/DML_over_joins_optimizer.out
index a405ae22a33b..02411cbfdaab 100644
--- a/src/test/regress/expected/DML_over_joins_optimizer.out
+++ b/src/test/regress/expected/DML_over_joins_optimizer.out
@@ -24,7 +24,6 @@ insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
update r set b = r.b + 1 from s where r.a = s.a;
update r set b = r.b + 1 from s where r.a in (select a from s);
-ERROR: multiple updates to a row by the same query is not allowed (seg0 rhel62-vm1:25432 pid=32303)
delete from r using s where r.a = s.a;
delete from r;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
@@ -56,22 +55,21 @@ delete from s;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
explain update s set b = b + 1 where exists (select 1 from r where s.a = r.b);
- QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
- Update (cost=0.00..868.53 rows=34 width=1)
- -> Split (cost=0.00..862.80 rows=67 width=22)
- -> Result (cost=0.00..862.80 rows=34 width=22)
- -> Hash Semi Join (cost=0.00..862.80 rows=34 width=18)
- Hash Cond: (s.a = r.b)
- -> Seq Scan on s (cost=0.00..431.00 rows=34 width=18)
- Filter: (NOT (a IS NULL))
- -> Hash (cost=431.15..431.15 rows=3334 width=4)
- -> Result (cost=0.00..431.15 rows=3334 width=4)
- -> Redistribute Motion 3:3 (slice1; segments: 3) (cost=0.00..431.14 rows=3334 width=4)
- Hash Key: r.b
- -> Seq Scan on r (cost=0.00..431.07 rows=3334 width=4)
+ QUERY PLAN
+---------------------------------------------------------------------------------------------------------------------
+ Update (cost=0.00..865.14 rows=34 width=1)
+ -> Result (cost=0.00..862.80 rows=34 width=18)
+ -> Hash Semi Join (cost=0.00..862.80 rows=34 width=18)
+ Hash Cond: (s.a = r.b)
+ -> Seq Scan on s (cost=0.00..431.00 rows=34 width=18)
+ Filter: (NOT (a IS NULL))
+ -> Hash (cost=431.15..431.15 rows=3334 width=4)
+ -> Result (cost=0.00..431.15 rows=3334 width=4)
+ -> Redistribute Motion 3:3 (slice1; segments: 3) (cost=0.00..431.14 rows=3334 width=4)
+ Hash Key: r.b
+ -> Seq Scan on r (cost=0.00..431.07 rows=3334 width=4)
Optimizer: Pivotal Optimizer (GPORCA)
-(13 rows)
+(12 rows)
update s set b = b + 1 where exists (select 1 from r where s.a = r.b);
explain delete from s where exists (select 1 from r where s.a = r.b);
@@ -110,7 +108,6 @@ insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
update r set b = r.b + 1 from s where r.a = s.a;
update r set b = r.b + 1 from s where r.a in (select a from s);
-ERROR: multiple updates to a row by the same query is not allowed (seg2 rhel62-vm1:25434 pid=32307)
delete from r using s where r.a = s.a;
delete from r;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
@@ -162,7 +159,6 @@ insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
update r set b = r.b + 1 from s where r.a = s.a;
update r set b = r.b + 1 from s where r.a in (select a from s);
-ERROR: multiple updates to a row by the same query is not allowed (seg0 rhel62-vm1:25432 pid=32303)
delete from r using s where r.a = s.a;
delete from r;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
@@ -214,7 +210,6 @@ insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
update r set b = r.b + 1 from s where r.a = s.a;
update r set b = r.b + 1 from s where r.a in (select a from s);
-ERROR: multiple updates to a row by the same query is not allowed (seg2 rhel62-vm1:25434 pid=32307)
delete from r using s where r.a = s.a;
delete from r;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
@@ -266,7 +261,6 @@ insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
update r set b = r.b + 1 from s where r.a = s.a;
update r set b = r.b + 1 from s where r.a in (select a from s);
-ERROR: multiple updates to a row by the same query is not allowed (seg0 rhel62-vm1:25432 pid=32303)
delete from r using s where r.a = s.a;
delete from r;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
@@ -318,7 +312,6 @@ insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
insert into s select generate_series(1, 100), generate_series(1, 100) * 4;
update r set b = r.b + 1 from s where r.a = s.a;
update r set b = r.b + 1 from s where r.a in (select a from s);
-ERROR: multiple updates to a row by the same query is not allowed (seg0 rhel62-vm1:25432 pid=32303)
delete from r using s where r.a = s.a;
delete from r;
insert into r select generate_series(1, 10000), generate_series(1, 10000) * 3;
@@ -1346,32 +1339,16 @@ select r.* from r,s,sales where s.a = sales.day and sales.month = r.b;
(6 rows)
update r set b = r.b + 1 from s,sales where s.a = sales.day and sales.month = r.b;
-ERROR: multiple updates to a row by the same query is not allowed (seg1 rhel62-vm1:25433 pid=32305)
select r.* from r,s,sales where s.a = sales.day and sales.month = r.b-1;
a | b
---+----
- 1 | 3
- 1 | 3
- 1 | 3
- 1 | 3
- 2 | 6
- 2 | 6
- 2 | 6
- 2 | 6
- 2 | 6
- 2 | 6
- 2 | 6
- 3 | 9
- 3 | 9
- 3 | 9
- 3 | 9
- 3 | 9
- 4 | 12
- 4 | 12
- 4 | 12
- 4 | 12
- 4 | 12
-(21 rows)
+ 2 | 7
+ 3 | 10
+ 3 | 10
+ 4 | 13
+ 1 | 4
+ 1 | 4
+(6 rows)
-- ----------------------------------------------------------------------
-- Test: query02.sql
@@ -1662,14 +1639,13 @@ select distinct sales_par.* from sales_par,s where sales_par.id in (s.b, s.b+1)
(4 rows)
update sales_par set month = month+1 from s where sales_par.id in (s.b, s.b+1) and region = 'europe';
-ERROR: multiple updates to a row by the same query is not allowed (seg0 rhel62-vm1:25432 pid=32303)
select distinct sales_par.* from sales_par,s where sales_par.id in (s.b, s.b+1) and region='europe';
id | year | month | day | region
----+------+-------+-----+--------
- 13 | 2008 | 2 | 14 | europe
- 5 | 2007 | 6 | 6 | europe
- 17 | 2005 | 6 | 18 | europe
- 9 | 2004 | 10 | 10 | europe
+ 5 | 2007 | 7 | 6 | europe
+ 9 | 2004 | 11 | 10 | europe
+ 13 | 2008 | 3 | 14 | europe
+ 17 | 2005 | 7 | 18 | europe
(4 rows)
-- direct dispatch: partitioned table: delete --
@@ -1762,14 +1738,13 @@ select distinct sales_par.* from sales_par,s where sales_par.id in (s.b, s.b+1)
PREPARE plan3 AS update sales_par set month = month+1 from s where sales_par.id in (s.b, s.b+1) and region = 'europe';
EXECUTE plan3;
-ERROR: multiple updates to a row by the same query is not allowed (seg0 rhel62-vm1:25432 pid=32303)
select distinct sales_par.* from sales_par,s where sales_par.id in (s.b, s.b+1) and region='europe';
id | year | month | day | region
----+------+-------+-----+--------
- 13 | 2008 | 2 | 14 | europe
- 5 | 2007 | 6 | 6 | europe
- 17 | 2005 | 6 | 18 | europe
- 9 | 2004 | 10 | 10 | europe
+ 5 | 2007 | 7 | 6 | europe
+ 9 | 2004 | 11 | 10 | europe
+ 13 | 2008 | 3 | 14 | europe
+ 17 | 2005 | 7 | 18 | europe
(4 rows)
-- direct dispatch: partitioned table: delete --
diff --git a/src/test/regress/expected/bfv_dml_optimizer.out b/src/test/regress/expected/bfv_dml_optimizer.out
index 5b53b1bce19f..be443ed3cd4b 100644
--- a/src/test/regress/expected/bfv_dml_optimizer.out
+++ b/src/test/regress/expected/bfv_dml_optimizer.out
@@ -183,14 +183,13 @@ drop table m;
create table update_pk_test (a int primary key, b int) distributed by (a);
insert into update_pk_test values(1,1);
explain update update_pk_test set b = 5;
- QUERY PLAN
------------------------------------------------------------------------------------
- Update (cost=0.00..431.06 rows=1 width=1)
- -> Split (cost=0.00..431.00 rows=1 width=22)
- -> Result (cost=0.00..431.00 rows=1 width=22)
- -> Seq Scan on update_pk_test (cost=0.00..431.00 rows=1 width=18)
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Update (cost=0.00..431.02 rows=1 width=1)
+ -> Result (cost=0.00..431.00 rows=1 width=18)
+ -> Seq Scan on update_pk_test (cost=0.00..431.00 rows=1 width=14)
Optimizer: Pivotal Optimizer (GPORCA)
-(5 rows)
+(4 rows)
update update_pk_test set b = 5;
select * from update_pk_test order by 1,2;
@@ -596,19 +595,18 @@ create table bar (a int, b int) distributed randomly;
insert into foo (a, b) values (1, 2);
insert into bar (a, b) values (1, 2);
explain update foo set a=4 from bar where foo.a=bar.a;
- QUERY PLAN
----------------------------------------------------------------------------------------------------------------
- Update (cost=0.00..862.06 rows=1 width=1)
- -> Split (cost=0.00..862.00 rows=1 width=22)
- -> Result (cost=0.00..862.00 rows=1 width=22)
- -> Hash Join (cost=0.00..862.00 rows=1 width=18)
- Hash Cond: (foo.a = bar.a)
- -> Seq Scan on foo (cost=0.00..431.00 rows=1 width=18)
- -> 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 bar (cost=0.00..431.00 rows=1 width=4)
+ QUERY PLAN
+---------------------------------------------------------------------------------------------------------
+ Update (cost=0.00..862.02 rows=1 width=1)
+ -> Result (cost=0.00..862.00 rows=1 width=18)
+ -> Hash Join (cost=0.00..862.00 rows=1 width=14)
+ Hash Cond: (foo.a = bar.a)
+ -> Seq Scan on foo (cost=0.00..431.00 rows=1 width=18)
+ -> 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 bar (cost=0.00..431.00 rows=1 width=4)
Optimizer: Pivotal Optimizer (GPORCA)
-(10 rows)
+(9 rows)
update foo set a=4 from bar where foo.a=bar.a;
select * from foo;
diff --git a/src/test/regress/expected/bfv_legacy_optimizer.out b/src/test/regress/expected/bfv_legacy_optimizer.out
index 20024808293b..a7129568343b 100644
--- a/src/test/regress/expected/bfv_legacy_optimizer.out
+++ b/src/test/regress/expected/bfv_legacy_optimizer.out
@@ -86,10 +86,8 @@ HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sur
insert into bfv_int4_tbl values(123456), (-2147483647), (0), (-123456), (2147483647);
update bfv_s set c_v = 11
from bfv_int4_tbl a join bfv_int4_tbl b on (a.f1 = (select f1 from bfv_int4_tbl c where c.f1=b.f1));
-ERROR: multiple updates to a row by the same query is not allowed
update bfv_s set c_v = 11
from bfv_int4_tbl a join bfv_int4_tbl b on (a.f1 = (select f1 from bfv_int4_tbl c where c.f1=b.f1));
-ERROR: multiple updates to a row by the same query is not allowed
--
--
--
diff --git a/src/test/regress/expected/gp_unique_rowid.out b/src/test/regress/expected/gp_unique_rowid.out
index ec782ff45645..a9b0531fd91e 100644
--- a/src/test/regress/expected/gp_unique_rowid.out
+++ b/src/test/regress/expected/gp_unique_rowid.out
@@ -116,8 +116,6 @@ explain (costs off ) update rank_12402 set rank = 1 where id in (select id from
-- Test for fake ctid works well
-- issue: https://github.com/greenplum-db/gpdb/issues/12512
--- NOTE: orca use split-update, planner use update, behavior is different when
--- tuple is updated by self.
-- test ctid for subquery in update
create table t_12512(a int, b int, c int);
NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table.
diff --git a/src/test/regress/expected/gp_unique_rowid_optimizer.out b/src/test/regress/expected/gp_unique_rowid_optimizer.out
index 2babb807013f..d6e92eca9fa2 100644
--- a/src/test/regress/expected/gp_unique_rowid_optimizer.out
+++ b/src/test/regress/expected/gp_unique_rowid_optimizer.out
@@ -64,37 +64,34 @@ NOTICE: CREATE TABLE will create partition "rank1_12402_1_prt_2" for table "ran
-- It should create a unique_rowid plan.
-- but it creates a semi-join plan, due to we disallow unique_rowid path in inheritance_planner.
explain (costs off ) update rank_12402 set rank = 1 where id in (select id from rank1_12402) and value in (select value from rank1_12402);
- QUERY PLAN
---------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------
Update
- -> Split
- -> Result
+ -> Result
+ -> Hash Semi Join
+ Hash Cond: (rank_12402.value = rank1_12402_1.value)
-> Hash Semi Join
- Hash Cond: (rank_12402.value = rank1_12402_1.value)
- -> Hash Semi Join
- Hash Cond: (rank_12402.id = rank1_12402.id)
+ Hash Cond: (rank_12402.id = rank1_12402.id)
+ -> Sequence
+ -> Partition Selector for rank_12402 (dynamic scan id: 1)
+ Partitions selected: 2 (out of 2)
+ -> Dynamic Seq Scan on rank_12402 (dynamic scan id: 1)
+ -> Hash
-> Sequence
- -> Partition Selector for rank_12402 (dynamic scan id: 1)
+ -> Partition Selector for rank1_12402 (dynamic scan id: 2)
Partitions selected: 2 (out of 2)
- -> Dynamic Seq Scan on rank_12402 (dynamic scan id: 1)
- -> Hash
- -> Sequence
- -> Partition Selector for rank1_12402 (dynamic scan id: 2)
- Partitions selected: 2 (out of 2)
- -> Dynamic Seq Scan on rank1_12402 (dynamic scan id: 2)
- -> Hash
- -> Broadcast Motion 3:3 (slice1; segments: 3)
- -> Sequence
- -> Partition Selector for rank1_12402 (dynamic scan id: 3)
- Partitions selected: 2 (out of 2)
- -> Dynamic Seq Scan on rank1_12402 rank1_12402_1 (dynamic scan id: 3)
+ -> Dynamic Seq Scan on rank1_12402 (dynamic scan id: 2)
+ -> Hash
+ -> Broadcast Motion 3:3 (slice1; segments: 3)
+ -> Sequence
+ -> Partition Selector for rank1_12402 (dynamic scan id: 3)
+ Partitions selected: 2 (out of 2)
+ -> Dynamic Seq Scan on rank1_12402 rank1_12402_1 (dynamic scan id: 3)
Optimizer: Pivotal Optimizer (GPORCA)
-(24 rows)
+(22 rows)
-- Test for fake ctid works well
-- issue: https://github.com/greenplum-db/gpdb/issues/12512
--- NOTE: orca use split-update, planner use update, behavior is different when
--- tuple is updated by self.
-- test ctid for subquery in update
create table t_12512(a int, b int, c int);
NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table.
@@ -120,29 +117,28 @@ where e.x in
select b from t2_12512
)
;
- QUERY PLAN
-------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------------------------------------------------
Update
- -> Split
- -> Result
- -> Hash Semi Join
- Hash Cond: ((sum(t1_12512.a)) = (t2_12512.b)::bigint)
- -> Nested Loop
- Join Filter: true
- -> Seq Scan on t_12512
- -> Materialize
- -> Broadcast Motion 3:3 (slice2; segments: 3)
- -> Result
- -> HashAggregate
- Group Key: t1_12512.b
- -> Redistribute Motion 3:3 (slice1; segments: 3)
- Hash Key: t1_12512.b
- -> Seq Scan on t1_12512
- -> Hash
- -> Broadcast Motion 3:3 (slice3; segments: 3)
- -> Seq Scan on t2_12512
+ -> Result
+ -> Hash Semi Join
+ Hash Cond: ((sum(t1_12512.a)) = (t2_12512.b)::bigint)
+ -> Nested Loop
+ Join Filter: true
+ -> Seq Scan on t_12512
+ -> Materialize
+ -> Broadcast Motion 3:3 (slice2; segments: 3)
+ -> Result
+ -> HashAggregate
+ Group Key: t1_12512.b
+ -> Redistribute Motion 3:3 (slice1; segments: 3)
+ Hash Key: t1_12512.b
+ -> Seq Scan on t1_12512
+ -> Hash
+ -> Broadcast Motion 3:3 (slice3; segments: 3)
+ -> Seq Scan on t2_12512
Optimizer: Pivotal Optimizer (GPORCA)
-(20 rows)
+(19 rows)
update t_12512 set b = 1
from
@@ -155,7 +151,6 @@ where e.x in
select b from t2_12512
)
;
-ERROR: multiple updates to a row by the same query is not allowed (seg0 127.0.1.1:6002 pid=31136)
-- test fake ctid for functions
explain (costs off)
update t_12512 set b = 1
@@ -168,24 +163,23 @@ where e.x in
select b from t2_12512
)
;
- QUERY PLAN
----------------------------------------------------------------------------
+ QUERY PLAN
+---------------------------------------------------------------------
Update
- -> Split
- -> Result
- -> Hash Semi Join
- Hash Cond: ("outer".x = t2_12512.b)
- -> Nested Loop
- Join Filter: true
- -> Seq Scan on t_12512
- -> Materialize
+ -> Result
+ -> Hash Semi Join
+ Hash Cond: ("outer".x = t2_12512.b)
+ -> Nested Loop
+ Join Filter: true
+ -> Seq Scan on t_12512
+ -> Materialize
+ -> Result
-> Result
- -> Result
- -> Hash
- -> Broadcast Motion 3:3 (slice1; segments: 3)
- -> Seq Scan on t2_12512
+ -> Hash
+ -> Broadcast Motion 3:3 (slice1; segments: 3)
+ -> Seq Scan on t2_12512
Optimizer: Pivotal Optimizer (GPORCA)
-(15 rows)
+(14 rows)
update t_12512 set b = 1
from
@@ -209,27 +203,21 @@ where e.x in
select b from t2_12512
)
;
- QUERY PLAN
-------------------------------------------------------------------------------------
+ QUERY PLAN
+---------------------------------------------------------------------
Update
- -> Redistribute Motion 3:3 (slice3; segments: 3)
- Hash Key: t_12512.a
- -> Split
- -> Result
- -> Hash Semi Join
- Hash Cond: ("Values".column1 = t2_12512.b)
- -> Redistribute Motion 3:3 (slice1; segments: 3)
- Hash Key: "Values".column1
- -> Nested Loop
- Join Filter: true
- -> Seq Scan on t_12512
- -> Values Scan on "Values"
- -> Hash
- -> Redistribute Motion 3:3 (slice2; segments: 3)
- Hash Key: t2_12512.b
- -> Seq Scan on t2_12512
+ -> Result
+ -> Hash Semi Join
+ Hash Cond: ("Values".column1 = t2_12512.b)
+ -> Nested Loop
+ Join Filter: true
+ -> Seq Scan on t_12512
+ -> Values Scan on "Values"
+ -> Hash
+ -> Broadcast Motion 3:3 (slice1; segments: 3)
+ -> Seq Scan on t2_12512
Optimizer: Pivotal Optimizer (GPORCA)
-(18 rows)
+(12 rows)
update t_12512 set b = 1
from
@@ -241,7 +229,6 @@ where e.x in
select b from t2_12512
)
;
-ERROR: multiple updates to a row by the same query is not allowed (seg0 127.0.1.1:6002 pid=31136)
-- test fake ctid for external scan
CREATE OR REPLACE FUNCTION write_to_file_12512() RETURNS integer AS
'$libdir/gpextprotocol.so', 'demoprot_export' LANGUAGE C STABLE;
@@ -269,26 +256,25 @@ where e.x in
select b from t2_12512
)
;
- QUERY PLAN
----------------------------------------------------------------------------------------------
+ QUERY PLAN
+---------------------------------------------------------------------------------------
Update
- -> Redistribute Motion 3:3 (slice3; segments: 3)
- Hash Key: t_12512.a
- -> Split
- -> Result
- -> Nested Loop
- Join Filter: true
- -> Broadcast Motion 3:3 (slice2; segments: 3)
- -> Seq Scan on t_12512
- -> Materialize
- -> Hash Semi Join
- Hash Cond: (ext_r_12512.a = t2_12512.b)
- -> External Scan on ext_r_12512
- -> Hash
- -> Broadcast Motion 3:3 (slice1; segments: 3)
- -> Seq Scan on t2_12512
+ -> Result
+ -> Redistribute Motion 3:3 (slice3; segments: 3)
+ Hash Key: t_12512.a
+ -> Nested Loop
+ Join Filter: true
+ -> Broadcast Motion 3:3 (slice2; segments: 3)
+ -> Seq Scan on t_12512
+ -> Materialize
+ -> Hash Semi Join
+ Hash Cond: (ext_r_12512.a = t2_12512.b)
+ -> External Scan on ext_r_12512
+ -> Hash
+ -> Broadcast Motion 3:3 (slice1; segments: 3)
+ -> Seq Scan on t2_12512
Optimizer: Pivotal Optimizer (GPORCA)
-(17 rows)
+(16 rows)
update t_12512 set b = 1
from
@@ -300,7 +286,6 @@ where e.x in
select b from t2_12512
)
;
-ERROR: multiple updates to a row by the same query is not allowed (seg0 127.0.1.1:6002 pid=31136)
-- reset fault injector
select gp_inject_fault('low_unique_rowid_path_cost', 'reset', dbid) from gp_segment_configuration where role = 'p' and content = -1;
gp_inject_fault
diff --git a/src/test/regress/expected/gporca_optimizer.out b/src/test/regress/expected/gporca_optimizer.out
index c362caeb1ed0..03a6e4779204 100644
--- a/src/test/regress/expected/gporca_optimizer.out
+++ b/src/test/regress/expected/gporca_optimizer.out
@@ -14688,25 +14688,24 @@ update window_agg_test t
set i = tt.i
from (select (min(i) over (order by j)) as i, j from window_agg_test) tt
where t.j = tt.j;
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
- Update (cost=0.00..862.06 rows=1 width=1)
- -> Explicit Redistribute Motion 1:3 (slice3; segments: 1) (cost=0.00..862.00 rows=2 width=22)
- -> Split (cost=0.00..862.00 rows=1 width=22)
- -> Hash Join (cost=0.00..862.00 rows=1 width=22)
- Hash Cond: (window_agg_test.j = window_agg_test_1.j)
- -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=18)
- -> Seq Scan on window_agg_test (cost=0.00..431.00 rows=1 width=18)
- -> Hash (cost=431.00..431.00 rows=1 width=8)
- -> WindowAgg (cost=0.00..431.00 rows=1 width=8)
- Order By: window_agg_test_1.j
- -> Gather Motion 3:1 (slice2; segments: 3) (cost=0.00..431.00 rows=1 width=8)
- Merge Key: window_agg_test_1.j
- -> Sort (cost=0.00..431.00 rows=1 width=8)
- Sort Key: window_agg_test_1.j
- -> Seq Scan on window_agg_test window_agg_test_1 (cost=0.00..431.00 rows=1 width=8)
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------------------
+ Update (cost=0.00..862.02 rows=1 width=1)
+ -> Explicit Redistribute Motion 1:3 (slice3; segments: 1) (cost=0.00..862.00 rows=1 width=18)
+ -> Hash Join (cost=0.00..862.00 rows=1 width=18)
+ Hash Cond: (window_agg_test.j = window_agg_test_1.j)
+ -> Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=14)
+ -> Seq Scan on window_agg_test (cost=0.00..431.00 rows=1 width=14)
+ -> Hash (cost=431.00..431.00 rows=1 width=8)
+ -> WindowAgg (cost=0.00..431.00 rows=1 width=8)
+ Order By: window_agg_test_1.j
+ -> Gather Motion 3:1 (slice2; segments: 3) (cost=0.00..431.00 rows=1 width=8)
+ Merge Key: window_agg_test_1.j
+ -> Sort (cost=0.00..431.00 rows=1 width=8)
+ Sort Key: window_agg_test_1.j
+ -> Seq Scan on window_agg_test window_agg_test_1 (cost=0.00..431.00 rows=1 width=8)
Optimizer: Pivotal Optimizer (GPORCA)
-(16 rows)
+(15 rows)
----------------------------------
-- Test ORCA support for const TVF
diff --git a/src/test/regress/expected/partition_pruning_optimizer.out b/src/test/regress/expected/partition_pruning_optimizer.out
index f4ec9f93d04c..acfc8a41538f 100644
--- a/src/test/regress/expected/partition_pruning_optimizer.out
+++ b/src/test/regress/expected/partition_pruning_optimizer.out
@@ -3084,30 +3084,29 @@ from (
) src
where trg.key1 = src.key1
and trg.key1 = 2;
- QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------
Update
- -> Split
- -> Hash Join
- Hash Cond: (t_part1.key1 = t_part1_1.key1)
- -> Sequence
- -> Partition Selector for t_part1 (dynamic scan id: 1)
- Partitions selected: 1 (out of 399)
- -> Dynamic Seq Scan on t_part1 (dynamic scan id: 1)
- Filter: (key1 = 2)
- -> Hash
- -> Broadcast Motion 1:3 (slice2; segments: 1)
- -> Result
- Filter: (t_part1_1.key1 = 2)
- -> WindowAgg
- -> Gather Motion 3:1 (slice1; segments: 3)
- -> Sequence
- -> Partition Selector for t_part1 (dynamic scan id: 2)
- Partitions selected: 1 (out of 399)
- -> Dynamic Seq Scan on t_part1 t_part1_1 (dynamic scan id: 2)
- Filter: (key1 = 2)
+ -> Hash Join
+ Hash Cond: (t_part1.key1 = t_part1_1.key1)
+ -> Sequence
+ -> Partition Selector for t_part1 (dynamic scan id: 1)
+ Partitions selected: 1 (out of 399)
+ -> Dynamic Seq Scan on t_part1 (dynamic scan id: 1)
+ Filter: (key1 = 2)
+ -> Hash
+ -> Broadcast Motion 1:3 (slice2; segments: 1)
+ -> Result
+ Filter: (t_part1_1.key1 = 2)
+ -> WindowAgg
+ -> Gather Motion 3:1 (slice1; segments: 3)
+ -> Sequence
+ -> Partition Selector for t_part1 (dynamic scan id: 2)
+ Partitions selected: 1 (out of 399)
+ -> Dynamic Seq Scan on t_part1 t_part1_1 (dynamic scan id: 2)
+ Filter: (key1 = 2)
Optimizer: Pivotal Optimizer (GPORCA)
-(22 rows)
+(20 rows)
DROP TABLE t_part1;
-- Test that the dynamic partition pruning should not be performed if the partition's opclass and the
diff --git a/src/test/regress/expected/qp_dml_joins.out b/src/test/regress/expected/qp_dml_joins.out
index ee771430291c..2309bf400bf6 100644
--- a/src/test/regress/expected/qp_dml_joins.out
+++ b/src/test/regress/expected/qp_dml_joins.out
@@ -4050,8 +4050,8 @@ SELECT SUM(b) FROM dml_heap_r;
(1 row)
--Negative test - Update WHERE join returns more than one tuple with different values.
-CREATE TABLE dml_heap_u as SELECT i as a, 1 as b FROM generate_series(1,10)i;
-CREATE TABLE dml_heap_v as SELECT i as a ,i as b FROM generate_series(1,10)i;
+CREATE TABLE dml_heap_u as SELECT i as a, 1 as b FROM generate_series(1,10)i distributed by (a);
+CREATE TABLE dml_heap_v as SELECT i as a ,i as b FROM generate_series(1,10)i distributed by (a);
SELECT SUM(a) FROM dml_heap_v;
sum
-----
diff --git a/src/test/regress/expected/qp_dml_joins_optimizer.out b/src/test/regress/expected/qp_dml_joins_optimizer.out
index 221aac698eb4..6c4821eed73a 100644
--- a/src/test/regress/expected/qp_dml_joins_optimizer.out
+++ b/src/test/regress/expected/qp_dml_joins_optimizer.out
@@ -4068,8 +4068,8 @@ SELECT SUM(b) FROM dml_heap_r;
(1 row)
--Negative test - Update WHERE join returns more than one tuple with different values.
-CREATE TABLE dml_heap_u as SELECT i as a, 1 as b FROM generate_series(1,10)i;
-CREATE TABLE dml_heap_v as SELECT i as a ,i as b FROM generate_series(1,10)i;
+CREATE TABLE dml_heap_u as SELECT i as a, 1 as b FROM generate_series(1,10)i distributed by (a);
+CREATE TABLE dml_heap_v as SELECT i as a ,i as b FROM generate_series(1,10)i distributed by (a);
SELECT SUM(a) FROM dml_heap_v;
sum
-----
diff --git a/src/test/regress/expected/qp_orca_fallback_optimizer.out b/src/test/regress/expected/qp_orca_fallback_optimizer.out
index 2bee48b0aecd..1f5ac634ae52 100644
--- a/src/test/regress/expected/qp_orca_fallback_optimizer.out
+++ b/src/test/regress/expected/qp_orca_fallback_optimizer.out
@@ -57,14 +57,13 @@ DETAIL: Feature not supported: UPDATE with constraints
set optimizer_enable_dml_constraints=on;
explain update constr_tab set b = 10;
- QUERY PLAN
--------------------------------------------------------------------------------
- Update (cost=0.00..431.08 rows=1 width=1)
- -> Split (cost=0.00..431.00 rows=1 width=30)
- -> Result (cost=0.00..431.00 rows=1 width=30)
- -> Seq Scan on constr_tab (cost=0.00..431.00 rows=1 width=26)
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Update (cost=0.00..431.03 rows=1 width=1)
+ -> Result (cost=0.00..431.00 rows=1 width=26)
+ -> Seq Scan on constr_tab (cost=0.00..431.00 rows=1 width=22)
Optimizer: Pivotal Optimizer (GPORCA)
-(5 rows)
+(4 rows)
-- Same, with NOT NULL constraint.
DROP TABLE IF EXISTS constr_tab;
diff --git a/src/test/regress/expected/updatable_views_optimizer.out b/src/test/regress/expected/updatable_views_optimizer.out
index 8e10f46593d8..089d0b842689 100644
--- a/src/test/regress/expected/updatable_views_optimizer.out
+++ b/src/test/regress/expected/updatable_views_optimizer.out
@@ -642,21 +642,20 @@ SELECT * FROM rw_view2;
(2 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
- QUERY PLAN
--------------------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------
Update
- -> Split
- -> Hash Join
- Hash Cond: (base_tbl.a = base_tbl_1.a)
- -> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: (a = 2)
- -> Hash
- -> Result
- Filter: ((base_tbl_1.a = 2) AND (base_tbl_1.a < 10))
- -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
- Index Cond: (a > 0)
+ -> Hash Join
+ Hash Cond: (base_tbl.a = base_tbl_1.a)
+ -> Index Scan using base_tbl_pkey on base_tbl
+ Index Cond: (a = 2)
+ -> Hash
+ -> Result
+ Filter: ((base_tbl_1.a = 2) AND (base_tbl_1.a < 10))
+ -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
+ Index Cond: (a > 0)
Optimizer: Pivotal Optimizer (GPORCA)
-(12 rows)
+(11 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
QUERY PLAN
@@ -2071,22 +2070,21 @@ EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (2, 'New row 2');
Optimizer: Pivotal Optimizer (GPORCA) version 3.1.0
Update
- -> Split
- -> Result
- -> Nested Loop Semi Join
- Join Filter: true
- -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
- Index Cond: (id = 2)
- -> Materialize
- -> Broadcast Motion 1:3 (slice2; segments: 1)
+ -> Result
+ -> Nested Loop Semi Join
+ Join Filter: true
+ -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1
+ Index Cond: (id = 2)
+ -> Materialize
+ -> Broadcast Motion 1:3 (slice2; segments: 1)
+ -> Result
-> Result
- -> Result
- -> Limit
- -> Gather Motion 3:1 (slice1; segments: 3)
- -> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: (id = 2)
+ -> Limit
+ -> Gather Motion 3:1 (slice1; segments: 3)
+ -> Index Scan using base_tbl_pkey on base_tbl
+ Index Cond: (id = 2)
Optimizer: Pivotal Optimizer (GPORCA)
-(37 rows)
+(36 rows)
INSERT INTO rw_view1 VALUES (2, 'New row 2');
SELECT * FROM base_tbl;
diff --git a/src/test/regress/expected/update_gp_optimizer.out b/src/test/regress/expected/update_gp_optimizer.out
index 3edebee2b0e1..ff1977180fc9 100644
--- a/src/test/regress/expected/update_gp_optimizer.out
+++ b/src/test/regress/expected/update_gp_optimizer.out
@@ -123,45 +123,44 @@ EXPLAIN (COSTS OFF) UPDATE keo1 SET user_vie_act_cntr_marg_cum = 234.682 FROM
(SELECT min (keo4.keo_para_budget_date) FROM keo4)))
) t1
WHERE t1.user_vie_project_code_pk = keo1.user_vie_project_code_pk;
- QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Update
- -> Split
- -> Result
+ -> Result
+ -> Hash Join
+ Hash Cond: ((keo1_1.user_vie_project_code_pk)::text = (keo2.projects_pk)::text)
-> Hash Join
- Hash Cond: ((keo1_1.user_vie_project_code_pk)::text = (keo2.projects_pk)::text)
- -> Hash Join
- Hash Cond: ((keo1.user_vie_project_code_pk)::text = (keo1_1.user_vie_project_code_pk)::text)
- -> Seq Scan on keo1
- -> Hash
- -> Broadcast Motion 1:3 (slice5; segments: 1)
- -> Hash Join
- Hash Cond: ((keo1_1.user_vie_fiscal_year_period_sk)::text = (max((keo3.sky_per)::text)))
- -> Gather Motion 3:1 (slice1; segments: 3)
- -> Seq Scan on keo1 keo1_1
- -> Hash
- -> Aggregate
- -> Hash Join
- Hash Cond: ((keo3.bky_per)::text = (keo4.keo_para_required_period)::text)
- -> Gather Motion 3:1 (slice2; segments: 3)
- -> Seq Scan on keo3
- -> Hash
- -> Assert
- Assert Cond: ((row_number() OVER (?)) = 1)
- -> WindowAgg
- -> Hash Join
- Hash Cond: ((keo4.keo_para_budget_date)::text = (min((keo4_1.keo_para_budget_date)::text)))
- -> Gather Motion 3:1 (slice3; segments: 3)
- -> Seq Scan on keo4
- -> Hash
- -> Aggregate
- -> Gather Motion 3:1 (slice4; segments: 3)
- -> Seq Scan on keo4 keo4_1
+ Hash Cond: ((keo1.user_vie_project_code_pk)::text = (keo1_1.user_vie_project_code_pk)::text)
+ -> Seq Scan on keo1
-> Hash
- -> Broadcast Motion 3:3 (slice6; segments: 3)
- -> Seq Scan on keo2
+ -> Broadcast Motion 1:3 (slice5; segments: 1)
+ -> Hash Join
+ Hash Cond: ((keo1_1.user_vie_fiscal_year_period_sk)::text = (max((keo3.sky_per)::text)))
+ -> Gather Motion 3:1 (slice1; segments: 3)
+ -> Seq Scan on keo1 keo1_1
+ -> Hash
+ -> Aggregate
+ -> Hash Join
+ Hash Cond: ((keo3.bky_per)::text = (keo4.keo_para_required_period)::text)
+ -> Gather Motion 3:1 (slice2; segments: 3)
+ -> Seq Scan on keo3
+ -> Hash
+ -> Assert
+ Assert Cond: ((row_number() OVER (?)) = 1)
+ -> WindowAgg
+ -> Hash Join
+ Hash Cond: ((keo4.keo_para_budget_date)::text = (min((keo4_1.keo_para_budget_date)::text)))
+ -> Gather Motion 3:1 (slice3; segments: 3)
+ -> Seq Scan on keo4
+ -> Hash
+ -> Aggregate
+ -> Gather Motion 3:1 (slice4; segments: 3)
+ -> Seq Scan on keo4 keo4_1
+ -> Hash
+ -> Broadcast Motion 3:3 (slice6; segments: 3)
+ -> Seq Scan on keo2
Optimizer: Pivotal Optimizer (GPORCA)
-(36 rows)
+(35 rows)
UPDATE keo1 SET user_vie_act_cntr_marg_cum = 234.682 FROM
( SELECT a.user_vie_project_code_pk FROM keo1 a INNER JOIN keo2 b
diff --git a/src/test/regress/sql/gp_unique_rowid.sql b/src/test/regress/sql/gp_unique_rowid.sql
index f1dcd9e969d3..ad66e3b82fee 100644
--- a/src/test/regress/sql/gp_unique_rowid.sql
+++ b/src/test/regress/sql/gp_unique_rowid.sql
@@ -51,8 +51,6 @@ explain (costs off ) update rank_12402 set rank = 1 where id in (select id from
-- Test for fake ctid works well
-- issue: https://github.com/greenplum-db/gpdb/issues/12512
--- NOTE: orca use split-update, planner use update, behavior is different when
--- tuple is updated by self.
-- test ctid for subquery in update
create table t_12512(a int, b int, c int);
diff --git a/src/test/regress/sql/qp_dml_joins.sql b/src/test/regress/sql/qp_dml_joins.sql
index 5550cab5b87b..01614f3a3f38 100644
--- a/src/test/regress/sql/qp_dml_joins.sql
+++ b/src/test/regress/sql/qp_dml_joins.sql
@@ -1735,8 +1735,8 @@ UPDATE dml_heap_r SET b = MAX(dml_heap_s.b) FROM dml_heap_s WHERE dml_heap_r.b =
SELECT SUM(b) FROM dml_heap_r;
--Negative test - Update WHERE join returns more than one tuple with different values.
-CREATE TABLE dml_heap_u as SELECT i as a, 1 as b FROM generate_series(1,10)i;
-CREATE TABLE dml_heap_v as SELECT i as a ,i as b FROM generate_series(1,10)i;
+CREATE TABLE dml_heap_u as SELECT i as a, 1 as b FROM generate_series(1,10)i distributed by (a);
+CREATE TABLE dml_heap_v as SELECT i as a ,i as b FROM generate_series(1,10)i distributed by (a);
SELECT SUM(a) FROM dml_heap_v;
UPDATE dml_heap_v SET a = dml_heap_u.a FROM dml_heap_u WHERE dml_heap_u.b = dml_heap_v.b;
SELECT SUM(a) FROM dml_heap_v;