From f2124d9eed32b8bb0d9cee693df68429f597015a Mon Sep 17 00:00:00 2001 From: Sanath Kumar Vobilisetty Date: Fri, 5 Aug 2022 13:15:10 -0500 Subject: [PATCH] Implemented InPlaceUpdate to be used for updates made on non-distribution columns. Currently, ORCA uses Split-Update for updates on both distribution and non-distribution columns. With this commit, ORCA uses an InPlaceUpdate whenever updates are made to non-distribution columns or non-partition keys, and Split Update if any of modified columns are either distribution or partition keys. Consider below setup where we are updating non-distibution column, b in the table foo. ` create table foo(a int, b int); explain update foo set b=4; ` ORCA produces plan with Split and Update nodes ``` Update on public.foo -> Result Output: foo_1.a, foo_1.b, (DMLAction), foo_1.ctid, foo_1.gp_segment_id -> Split Output: foo_1.a, foo_1.b, foo_1.ctid, foo_1.gp_segment_id, DMLAction -> Seq Scan on public.foo foo_1 Output: foo_1.a, foo_1.b, 4, foo_1.ctid, foo_1.gp_segment_id ``` There is no point in using a Split and Update for this as we are updating a non-distribution column which do not require any redistribution. This commit uses an InPlace Update to perform updates on non-distribution columns like Planner. Below is the new plan produced with this commit. New Plan ``` Update on public.foo -> Seq Scan on public.foo foo_1 Output: foo_1.a, 4, foo_1.ctid, foo_1.gp_segment_id Optimizer: Pivotal Optimizer (GPORCA) ``` greenplum 6 specific changes: 1. Some constructors have been changed because the list of arguments in 6X and 7X are different. 2. fixed a bug in CParseHandlerPhysicalDML::startElement where preserve_oids_xml was used instead of fSplit, which could lead to SIGSEGV during DML node parsing. 3. Changed create_index_hot test. Removed disabling the optimizer before updating since ORCA no longer uses split update in this case. (cherry picked from commit 3ced85b65732728edff66fd9a2ce6d7485d65a06) --- .../translate/CTranslatorDXLToPlStmt.cpp | 23 +- .../gporca/data/dxl/minidump/SelfUpdate.mdp | 81 ++-- .../dxl/minidump/UpdateCheckConstraint.mdp | 127 ++---- .../UpdateNoDistKeyMismatchedDistribution.mdp | 287 ++++++------- .../minidump/UpdateNoEnforceConstraints.mdp | 103 ++--- .../data/dxl/minidump/UpdateRandomDistr.mdp | 84 ++-- .../dxl/minidump/UpdateUniqueConstraint-2.mdp | 186 +++------ .../dxl/minidump/UpdateWindowGatherMerge.mdp | 318 +++++++------- .../data/dxl/minidump/UpdateWithHashJoin.mdp | 136 +++--- .../data/dxl/minidump/UpdateWithTriggers.mdp | 117 ++---- .../data/dxl/minidump/UpdateZeroRows.mdp | 387 ++++++++---------- .../minidump/UpdatingNonDistColSameTable.mdp | 73 ++-- .../UpdatingNonDistributionColumnFunc.mdp | 100 ++--- .../data/dxl/parse_tests/q60-DMLUpdate.xml | 2 +- .../gpopt/operators/CExpressionPreprocessor.h | 3 + .../include/gpopt/operators/CLogicalDML.h | 16 +- .../include/gpopt/operators/CLogicalUpdate.h | 12 +- .../include/gpopt/operators/CPhysicalDML.h | 12 +- .../src/operators/CExpressionPreprocessor.cpp | 96 ++++- .../libgpopt/src/operators/CLogicalDML.cpp | 60 ++- .../libgpopt/src/operators/CLogicalUpdate.cpp | 25 +- .../libgpopt/src/operators/CPhysicalDML.cpp | 46 +-- .../src/translate/CTranslatorDXLToExpr.cpp | 12 +- .../src/translate/CTranslatorExprToDXL.cpp | 7 +- .../src/xforms/CXformImplementDML.cpp | 3 +- .../libgpopt/src/xforms/CXformUpdate2DML.cpp | 89 ++-- .../libgpopt/src/xforms/CXformUtils.cpp | 2 +- .../naucrates/dxl/operators/CDXLPhysicalDML.h | 13 +- .../dxl/parser/CParseHandlerPhysicalDML.h | 3 + .../include/naucrates/dxl/xml/dxltokens.h | 1 + .../src/operators/CDXLPhysicalDML.cpp | 14 +- .../src/parser/CParseHandlerPhysicalDML.cpp | 15 +- .../gporca/libnaucrates/src/xml/dxltokens.cpp | 1 + .../gporca/server/src/unittest/CTestUtils.cpp | 2 +- .../isolation/expected/create_index_hot.out | 3 +- .../isolation/specs/create_index_hot.spec | 3 - .../gdd/concurrent_update_optimizer.out | 34 +- .../modify_table_data_corrupt_optimizer.out | 76 ++-- .../expected/DML_over_joins_optimizer.out | 83 ++-- .../regress/expected/bfv_dml_optimizer.out | 36 +- .../regress/expected/bfv_legacy_optimizer.out | 2 - src/test/regress/expected/gp_unique_rowid.out | 2 - .../expected/gp_unique_rowid_optimizer.out | 183 ++++----- .../regress/expected/gporca_optimizer.out | 35 +- .../expected/partition_pruning_optimizer.out | 43 +- src/test/regress/expected/qp_dml_joins.out | 4 +- .../expected/qp_dml_joins_optimizer.out | 4 +- .../expected/qp_orca_fallback_optimizer.out | 13 +- .../expected/updatable_views_optimizer.out | 52 ++- .../regress/expected/update_gp_optimizer.out | 69 ++-- src/test/regress/sql/gp_unique_rowid.sql | 2 - src/test/regress/sql/qp_dml_joins.sql | 4 +- 52 files changed, 1409 insertions(+), 1695 deletions(-) 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/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;