This is an automated email from the ASF dual-hosted git repository. maxyang pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudberry.git
commit f0a6160d3ccc1290c3b733b633ff298d26707340 Author: David Kimura <[email protected]> AuthorDate: Tue Sep 27 08:57:37 2022 -0700 [ORCA] Allow empty target list (#14159) There were a lot of asserts on NULL != target_list in the translator, but most of them were unnecessary. Fix ORCA to handle empty target list. - Add trace fallback to union testcase - Fix up CXformDifference2LeftAntiSemiJoin to handle case of empty columns Following SQL works ``` EXPLAIN (COSTS OFF) SELECT UNION SELECT; ``` --- .../gpopt/translate/CTranslatorQueryToDXL.cpp | 35 --------- src/backend/gpopt/translate/CTranslatorUtils.cpp | 8 +- .../gporca/libgpopt/src/base/CKeyCollection.cpp | 2 +- src/backend/gporca/libgpopt/src/base/CUtils.cpp | 1 - .../xforms/CXformDifference2LeftAntiSemiJoin.cpp | 32 +++++--- .../gporca/libgpopt/src/xforms/CXformUtils.cpp | 2 +- src/test/regress/expected/union.out | 2 + src/test/regress/expected/union_optimizer.out | 86 ++++++++++++++-------- src/test/regress/sql/union.sql | 3 + 9 files changed, 85 insertions(+), 86 deletions(-) diff --git a/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp b/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp index c4cfe8e22d..cacd2845f5 100644 --- a/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp +++ b/src/backend/gpopt/translate/CTranslatorQueryToDXL.cpp @@ -2720,7 +2720,6 @@ CTranslatorQueryToDXL::CreateDXLSetOpFromColumns( CDXLNodeArray *children_dxlnodes, BOOL is_cast_across_input, BOOL keep_res_junked) const { - GPOS_ASSERT(nullptr != output_target_list); GPOS_ASSERT(nullptr != output_colids); GPOS_ASSERT(nullptr != input_colids); GPOS_ASSERT(nullptr != children_dxlnodes); @@ -2838,7 +2837,6 @@ CTranslatorQueryToDXL::SetOpNeedsCast(List *target_list, IMdIdArray *input_col_mdids) { GPOS_ASSERT(nullptr != input_col_mdids); - GPOS_ASSERT(nullptr != target_list); GPOS_ASSERT( input_col_mdids->Size() <= gpdb::ListLength(target_list)); // there may be resjunked columns @@ -2880,39 +2878,6 @@ CTranslatorQueryToDXL::TranslateSetOpChild(Node *child_node, GPOS_ASSERT(nullptr != colids); GPOS_ASSERT(nullptr != input_col_mdids); - // GPDB_12_MERGE_FIXME: We have to fallback here because otherwise we trip - // the following assert in ORCA: - // - // INFO: GPORCA failed to produce a plan, falling back to planner - // DETAIL: CKeyCollection.cpp:84: Failed assertion: __null != colref_array && 0 < colref_array->Size() - // Stack trace: - // 1 0x000055c239243b8a gpos::CException::Raise + 278 - // 2 0x000055c2393ab075 gpopt::CKeyCollection::CKeyCollection + 221 - // 3 0x000055c239449ab6 gpopt::CLogicalSetOp::DeriveKeyCollection + 98 - // 4 0x000055c2393a5a67 gpopt::CDrvdPropRelational::DeriveKeyCollection + 135 - // 5 0x000055c2393a4937 gpopt::CDrvdPropRelational::Derive + 197 - // 6 0x000055c239405d9f gpopt::CExpression::PdpDerive + 703 - // 7 0x000055c2394d1e14 gpopt::CMemo::PgroupInsert + 512 - // 8 0x000055c2393dd734 gpopt::CEngine::PgroupInsert + 632 - // 9 0x000055c2393dcd73 gpopt::CEngine::InitLogicalExpression + 225 - // 10 0x000055c2393dd106 gpopt::CEngine::Init + 884 - // 11 0x000055c23949da9f gpopt::COptimizer::PexprOptimize + 103 - // 12 0x000055c23949d3d8 gpopt::COptimizer::PdxlnOptimize + 1414 - // 13 0x000055c23960e55e COptTasks::OptimizeTask + 1530 - // 14 0x000055c2392572b6 gpos::CTask::Execute + 196 - // 15 0x000055c239259dbf gpos::CWorker::Execute + 191 - // 16 0x000055c2392556b5 gpos::CAutoTaskProxy::Execute + 221 - // 17 0x000055c23925c0c0 gpos_exec + 876 - // - // Currently there are a lot of asserts on NULL != target_list in the - // translator, but most of them are unnecessary. We should instead fix ORCA - // to handle empty target list. - if (NIL == target_list) - { - GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiQuery2DXLUnsupportedFeature, - GPOS_WSZ_LIT("Empty target list")); - } - if (IsA(child_node, RangeTblRef)) { RangeTblRef *range_tbl_ref = (RangeTblRef *) child_node; diff --git a/src/backend/gpopt/translate/CTranslatorUtils.cpp b/src/backend/gpopt/translate/CTranslatorUtils.cpp index bf5698d2f2..c5cac56e35 100644 --- a/src/backend/gpopt/translate/CTranslatorUtils.cpp +++ b/src/backend/gpopt/translate/CTranslatorUtils.cpp @@ -1146,7 +1146,6 @@ CTranslatorUtils::GenerateColIds( is_outer_ref, // array of flags indicating if input columns are outer references CIdGenerator *colid_generator) { - GPOS_ASSERT(nullptr != target_list); GPOS_ASSERT(nullptr != input_mdid_arr); GPOS_ASSERT(nullptr != input_colids); GPOS_ASSERT(nullptr != is_outer_ref); @@ -1206,7 +1205,10 @@ CTranslatorUtils::FixUnknownTypeConstant(Query *old_query, List *output_target_list) { GPOS_ASSERT(nullptr != old_query); - GPOS_ASSERT(nullptr != output_target_list); + if (nullptr == output_target_list) + { + return old_query; + } Query *new_query = nullptr; @@ -1346,8 +1348,6 @@ ULongPtrArray * CTranslatorUtils::GetPosInTargetList(CMemoryPool *mp, List *target_list, BOOL keep_res_junked) { - GPOS_ASSERT(nullptr != target_list); - ListCell *target_entry_cell = nullptr; ULongPtrArray *positions = GPOS_NEW(mp) ULongPtrArray(mp); ULONG ul = 0; diff --git a/src/backend/gporca/libgpopt/src/base/CKeyCollection.cpp b/src/backend/gporca/libgpopt/src/base/CKeyCollection.cpp index dc39b41550..07a8124d00 100644 --- a/src/backend/gporca/libgpopt/src/base/CKeyCollection.cpp +++ b/src/backend/gporca/libgpopt/src/base/CKeyCollection.cpp @@ -67,7 +67,7 @@ CKeyCollection::CKeyCollection(CMemoryPool *mp, CColRefArray *colref_array) : m_pdrgpcrs(nullptr) { GPOS_ASSERT(nullptr != mp); - GPOS_ASSERT(nullptr != colref_array && 0 < colref_array->Size()); + GPOS_ASSERT(nullptr != colref_array); m_pdrgpcrs = GPOS_NEW(mp) CColRefSetArray(mp); diff --git a/src/backend/gporca/libgpopt/src/base/CUtils.cpp b/src/backend/gporca/libgpopt/src/base/CUtils.cpp index 536e7c0606..5d18422106 100644 --- a/src/backend/gporca/libgpopt/src/base/CUtils.cpp +++ b/src/backend/gporca/libgpopt/src/base/CUtils.cpp @@ -3708,7 +3708,6 @@ CUtils::PexprConjINDFCond(CMemoryPool *mp, CColRef2dArray *pdrgpdrgpcrInput) // assemble the new scalar condition CExpression *pexprScCond = nullptr; const ULONG length = (*pdrgpdrgpcrInput)[0]->Size(); - GPOS_ASSERT(0 != length); GPOS_ASSERT(length == (*pdrgpdrgpcrInput)[1]->Size()); CExpressionArray *pdrgpexprInput = diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformDifference2LeftAntiSemiJoin.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformDifference2LeftAntiSemiJoin.cpp index c2dc3c74ab..f4a0daf028 100644 --- a/src/backend/gporca/libgpopt/src/xforms/CXformDifference2LeftAntiSemiJoin.cpp +++ b/src/backend/gporca/libgpopt/src/xforms/CXformDifference2LeftAntiSemiJoin.cpp @@ -83,18 +83,26 @@ CXformDifference2LeftAntiSemiJoin::Transform(CXformContext *pxfctxt, GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CLogicalLeftAntiSemiJoin(mp), pexprLeftChild, pexprRightChild, pexprScCond); - // assemble the aggregate operator - pdrgpcrOutput->AddRef(); - - CExpression *pexprProjList = - GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CScalarProjectList(mp), - GPOS_NEW(mp) CExpressionArray(mp)); - - CExpression *pexprAgg = CUtils::PexprLogicalGbAggGlobal( - mp, pdrgpcrOutput, pexprLASJ, pexprProjList); - - // add alternative to results - pxfres->Add(pexprAgg); + if (pdrgpcrOutput->Size() > 0) + { + // assemble the aggregate operator + pdrgpcrOutput->AddRef(); + + CExpression *pexprProjList = + GPOS_NEW(mp) CExpression(mp, GPOS_NEW(mp) CScalarProjectList(mp), + GPOS_NEW(mp) CExpressionArray(mp)); + + CExpression *pexprAgg = CUtils::PexprLogicalGbAggGlobal( + mp, pdrgpcrOutput, pexprLASJ, pexprProjList); + + // add alternative to results + pxfres->Add(pexprAgg); + } + else + { + // skip the aggregate operator if output columns is empty + pxfres->Add(pexprLASJ); + } } // EOF diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp index bf2d321802..04ebf2c13a 100644 --- a/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp +++ b/src/backend/gporca/libgpopt/src/xforms/CXformUtils.cpp @@ -2211,7 +2211,7 @@ CXformUtils::PexprWindowWithRowNumber(CMemoryPool *mp, { // partitioning information CDistributionSpec *pds = nullptr; - if (nullptr != pdrgpcrInput) + if (nullptr != pdrgpcrInput && 0 < pdrgpcrInput->Size()) { CExpressionArray *pdrgpexprInput = CUtils::PdrgpexprScalarIdents(mp, pdrgpcrInput); diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index dca88da8de..a952417fcc 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -1,3 +1,4 @@ +set optimizer_trace_fallback = on; -- -- UNION (also INTERSECT, EXCEPT) -- @@ -1527,3 +1528,4 @@ where (x = 0) or (q1 >= q2 and q1 <= q2); 4567890123456789 | 4567890123456789 | 1 (6 rows) +reset optimizer_trace_fallback; diff --git a/src/test/regress/expected/union_optimizer.out b/src/test/regress/expected/union_optimizer.out index f439f9dd59..42de63f9b7 100644 --- a/src/test/regress/expected/union_optimizer.out +++ b/src/test/regress/expected/union_optimizer.out @@ -1,3 +1,4 @@ +set optimizer_trace_fallback = on; -- -- UNION (also INTERSECT, EXCEPT) -- @@ -1020,25 +1021,29 @@ set enable_hashagg = true; set enable_sort = false; explain (costs off) select from generate_series(1,5) union select from generate_series(1,3); - QUERY PLAN ----------------------------------------------------------------- - HashAggregate - -> Append - -> Function Scan on generate_series - -> Function Scan on generate_series generate_series_1 -(4 rows) - -explain (costs off) -select from generate_series(1,5) intersect select from generate_series(1,3); QUERY PLAN ---------------------------------------------------------------------- - HashSetOp Intersect + Aggregate -> Append - -> Subquery Scan on "*SELECT* 1" + -> Aggregate -> Function Scan on generate_series - -> Subquery Scan on "*SELECT* 2" + -> Aggregate -> Function Scan on generate_series generate_series_1 -(6 rows) + Optimizer: Pivotal Optimizer (GPORCA) +(7 rows) + +explain (costs off) +select from generate_series(1,5) intersect select from generate_series(1,3); + QUERY PLAN +---------------------------------------------------------------- + Nested Loop + Join Filter: true + -> Aggregate + -> Function Scan on generate_series generate_series_1 + -> Aggregate + -> Function Scan on generate_series + Optimizer: Pivotal Optimizer (GPORCA) +(7 rows) select from generate_series(1,5) union select from generate_series(1,3); -- @@ -1069,25 +1074,29 @@ set enable_hashagg = false; set enable_sort = true; explain (costs off) select from generate_series(1,5) union select from generate_series(1,3); - QUERY PLAN ----------------------------------------------------------------- - Unique - -> Append - -> Function Scan on generate_series - -> Function Scan on generate_series generate_series_1 -(4 rows) - -explain (costs off) -select from generate_series(1,5) intersect select from generate_series(1,3); QUERY PLAN ---------------------------------------------------------------------- - SetOp Intersect + Aggregate -> Append - -> Subquery Scan on "*SELECT* 1" + -> Aggregate -> Function Scan on generate_series - -> Subquery Scan on "*SELECT* 2" + -> Aggregate -> Function Scan on generate_series generate_series_1 -(6 rows) + Optimizer: Pivotal Optimizer (GPORCA) +(7 rows) + +explain (costs off) +select from generate_series(1,5) intersect select from generate_series(1,3); + QUERY PLAN +---------------------------------------------------------------- + Nested Loop + Join Filter: true + -> Aggregate + -> Function Scan on generate_series generate_series_1 + -> Aggregate + -> Function Scan on generate_series + Optimizer: Pivotal Optimizer (GPORCA) +(7 rows) select from generate_series(1,5) union select from generate_series(1,3); -- @@ -1213,8 +1222,10 @@ explain (costs off) UNION ALL SELECT ab FROM t2) t ORDER BY 1 LIMIT 8; - QUERY PLAN ------------------------------------------------------------------ +INFO: GPORCA failed to produce a plan, falling back to planner +DETAIL: Feature not supported: Inherited tables + QUERY PLAN +------------------------------------------------------------ Limit -> Gather Motion 3:1 (slice1; segments: 3) Merge Key: ((t1.a || t1.b)) @@ -1233,6 +1244,8 @@ explain (costs off) UNION ALL SELECT ab FROM t2) t ORDER BY 1 LIMIT 8; +INFO: GPORCA failed to produce a plan, falling back to planner +DETAIL: Feature not supported: Inherited tables ab ---- ab @@ -1261,6 +1274,8 @@ select event_id union all select event_id from other_events) ss order by event_id; +INFO: GPORCA failed to produce a plan, falling back to planner +DETAIL: Feature not supported: Inherited tables QUERY PLAN ---------------------------------------------------------------- Gather Motion 3:1 (slice1; segments: 3) @@ -1285,6 +1300,8 @@ explain (costs off) UNION ALL SELECT 2 AS t, * FROM tenk1 b) c WHERE t = 2; +INFO: GPORCA failed to produce a plan, falling back to planner +DETAIL: Feature not supported: Non-default collation QUERY PLAN ------------------------------------------ Gather Motion 3:1 (slice1; segments: 3) @@ -1369,8 +1386,10 @@ SELECT * FROM SELECT 2 AS t, 4 AS x) ss WHERE x > 3 ORDER BY x; - QUERY PLAN ------------------------------------------------------------------------------- +INFO: GPORCA failed to produce a plan, falling back to planner +DETAIL: Feature not supported: SIRV functions + QUERY PLAN +------------------------------------------------------------------------- Sort Sort Key: ss.x -> Subquery Scan on ss @@ -1393,6 +1412,8 @@ SELECT * FROM SELECT 2 AS t, 4 AS x) ss WHERE x > 3 ORDER BY x; +INFO: GPORCA failed to produce a plan, falling back to planner +DETAIL: Feature not supported: SIRV functions t | x ---+--- 2 | 4 @@ -1551,3 +1572,4 @@ where (x = 0) or (q1 >= q2 and q1 <= q2); 4567890123456789 | 4567890123456789 | 1 (6 rows) +reset optimizer_trace_fallback; diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index f673a2e049..3edcd9fdac 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -1,3 +1,4 @@ +set optimizer_trace_fallback = on; -- -- UNION (also INTERSECT, EXCEPT) -- @@ -550,3 +551,5 @@ select * from union all select *, 1 as x from int8_tbl b) ss where (x = 0) or (q1 >= q2 and q1 <= q2); + +reset optimizer_trace_fallback; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
