diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 3cd6221d001..b125bcca694 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -313,7 +313,8 @@ static void pgss_post_parse_analyze(ParseState *pstate, Query *query, static PlannedStmt *pgss_planner(Query *parse, const char *query_string, int cursorOptions, - ParamListInfo boundParams); + ParamListInfo boundParams, + OptimizerOptions *optimizer_options); static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags); static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, @@ -866,7 +867,8 @@ static PlannedStmt * pgss_planner(Query *parse, const char *query_string, int cursorOptions, - ParamListInfo boundParams) + ParamListInfo boundParams, + OptimizerOptions *optimizer_options) { PlannedStmt *result; @@ -908,10 +910,10 @@ pgss_planner(Query *parse, { if (prev_planner_hook) result = prev_planner_hook(parse, query_string, cursorOptions, - boundParams); + boundParams, optimizer_options); else result = standard_planner(parse, query_string, cursorOptions, - boundParams); + boundParams, optimizer_options); } PG_FINALLY(); { @@ -945,10 +947,10 @@ pgss_planner(Query *parse, { if (prev_planner_hook) result = prev_planner_hook(parse, query_string, cursorOptions, - boundParams); + boundParams, optimizer_options); else result = standard_planner(parse, query_string, cursorOptions, - boundParams); + boundParams, optimizer_options); } return result; diff --git a/gpcontrib/pg_hint_plan/pg_hint_plan.c b/gpcontrib/pg_hint_plan/pg_hint_plan.c index 033a9d01200..1d37677019c 100644 --- a/gpcontrib/pg_hint_plan/pg_hint_plan.c +++ b/gpcontrib/pg_hint_plan/pg_hint_plan.c @@ -428,7 +428,7 @@ pg_hint_plan_add_paths_to_joinrel(PlannerInfo *root, static void *external_plan_hint_hook(Query *parse); #endif static PlannedStmt *pg_hint_plan_planner(Query *parse, const char *query_string, int cursorOptions, - ParamListInfo boundParams); + ParamListInfo boundParams, OptimizerOptions *optimizer_options); static RelOptInfo *pg_hint_plan_join_search(PlannerInfo *root, int levels_needed, List *initial_rels); @@ -3118,7 +3118,7 @@ pg_hint_plan_ProcessUtility(PlannedStmt *pstmt, const char *queryString, */ static PlannedStmt * pg_hint_plan_planner(Query *parse, const char *query_string, - int cursorOptions, ParamListInfo boundParams) + int cursorOptions, ParamListInfo boundParams, OptimizerOptions *optimizer_options) { int save_nestlevel; PlannedStmt *result; @@ -3236,9 +3236,9 @@ pg_hint_plan_planner(Query *parse, const char *query_string, } if (prev_planner) - result = (*prev_planner) (parse, query_string, cursorOptions, boundParams); + result = (*prev_planner) (parse, query_string, cursorOptions, boundParams, optimizer_options); else - result = standard_planner(parse, query_string, cursorOptions, boundParams); + result = standard_planner(parse, query_string, cursorOptions, boundParams, optimizer_options); current_hint_str = prev_hint_str; recurse_level--; @@ -3298,9 +3298,9 @@ pg_hint_plan_planner(Query *parse, const char *query_string, } current_hint_state = NULL; if (prev_planner) - result = (*prev_planner) (parse, query_string, cursorOptions, boundParams); + result = (*prev_planner) (parse, query_string, cursorOptions, boundParams, optimizer_options); else - result = standard_planner(parse, query_string, cursorOptions, boundParams); + result = standard_planner(parse, query_string, cursorOptions, boundParams, optimizer_options); /* The upper-level planner still needs the current hint state */ if (HintStateStack != NIL) diff --git a/src/backend/cdb/cdbllize.c b/src/backend/cdb/cdbllize.c index 070ed51b99c..a4037c36158 100644 --- a/src/backend/cdb/cdbllize.c +++ b/src/backend/cdb/cdbllize.c @@ -1506,6 +1506,7 @@ motion_sanity_walker(Node *node, sanity_result_t *result) { case T_Result: case T_WindowAgg: + case T_WindowHashAgg: case T_TableFunctionScan: case T_ShareInputScan: case T_Append: diff --git a/src/backend/cdb/cdbplan.c b/src/backend/cdb/cdbplan.c index 1979ad38f8b..f48d8448338 100644 --- a/src/backend/cdb/cdbplan.c +++ b/src/backend/cdb/cdbplan.c @@ -694,6 +694,25 @@ plan_tree_mutator(Node *node, return (Node *) newwindow; } break; + case T_WindowHashAgg: + { + WindowHashAgg *window = (WindowHashAgg *) node; + WindowHashAgg *newwindow; + + FLATCOPY(newwindow, window, WindowHashAgg); + PLANMUTATE(newwindow, window); + + COPYARRAY(newwindow, window, partNumCols, partColIdx); + COPYARRAY(newwindow, window, partNumCols, partOperators); + + COPYARRAY(newwindow, window, ordNumCols, ordColIdx); + COPYARRAY(newwindow, window, ordNumCols, ordOperators); + MUTATE(newwindow->startOffset, window->startOffset, Node *); + MUTATE(newwindow->endOffset, window->endOffset, Node *); + + return (Node *) newwindow; + } + break; case T_Unique: { diff --git a/src/backend/cdb/cdbtargeteddispatch.c b/src/backend/cdb/cdbtargeteddispatch.c index b297164e273..da6f40c5971 100644 --- a/src/backend/cdb/cdbtargeteddispatch.c +++ b/src/backend/cdb/cdbtargeteddispatch.c @@ -522,6 +522,7 @@ DirectDispatchUpdateContentIdsFromPlan(PlannerInfo *root, Plan *plan) DisableTargetedDispatch(&dispatchInfo); break; case T_WindowAgg: + case T_WindowHashAgg: case T_TableFunctionScan: case T_RecursiveUnion: /* no change to dispatchInfo */ diff --git a/src/backend/gpopt/CGPOptimizer.cpp b/src/backend/gpopt/CGPOptimizer.cpp index 2ab834173f1..11d08f8438a 100644 --- a/src/backend/gpopt/CGPOptimizer.cpp +++ b/src/backend/gpopt/CGPOptimizer.cpp @@ -45,7 +45,8 @@ PlannedStmt * CGPOptimizer::GPOPTOptimizedPlan( Query *query, bool * - had_unexpected_failure // output : set to true if optimizer unexpectedly failed to produce plan + had_unexpected_failure, // output : set to true if optimizer unexpectedly failed to produce plan + OptimizerOptions *opts ) { SOptContext gpopt_context; @@ -55,7 +56,7 @@ CGPOptimizer::GPOPTOptimizedPlan( GPOS_TRY { - plStmt = COptTasks::GPOPTOptimizedPlan(query, &gpopt_context); + plStmt = COptTasks::GPOPTOptimizedPlan(query, &gpopt_context, opts); // clean up context gpopt_context.Free(gpopt_context.epinQuery, gpopt_context.epinPlStmt); } @@ -199,9 +200,9 @@ CGPOptimizer::TerminateGPOPT() //--------------------------------------------------------------------------- extern "C" { PlannedStmt * -GPOPTOptimizedPlan(Query *query, bool *had_unexpected_failure) +GPOPTOptimizedPlan(Query *query, bool *had_unexpected_failure, OptimizerOptions *opts) { - return CGPOptimizer::GPOPTOptimizedPlan(query, had_unexpected_failure); + return CGPOptimizer::GPOPTOptimizedPlan(query, had_unexpected_failure, opts); } } diff --git a/src/backend/gpopt/config/CConfigParamMapping.cpp b/src/backend/gpopt/config/CConfigParamMapping.cpp index 802cf38785b..fcf4889ff8f 100644 --- a/src/backend/gpopt/config/CConfigParamMapping.cpp +++ b/src/backend/gpopt/config/CConfigParamMapping.cpp @@ -326,6 +326,12 @@ CConfigParamMapping::SConfigMappingElem CConfigParamMapping::m_elements[] = { false, // m_negate_param GPOS_WSZ_LIT( "Disable the dynamic seq/bitmap/index scan in partition table")}, + + {EopttraceEnableWindowHashAgg, &optimizer_force_window_hash_agg, + false, // m_negate_param + GPOS_WSZ_LIT( + "Enable create window hash agg")}, + }; //--------------------------------------------------------------------------- @@ -339,7 +345,8 @@ CConfigParamMapping::SConfigMappingElem CConfigParamMapping::m_elements[] = { CBitSet * CConfigParamMapping::PackConfigParamInBitset( CMemoryPool *mp, - ULONG xform_id // number of available xforms + ULONG xform_id, // number of available xforms + BOOL create_vec_plan ) { CBitSet *traceflag_bitset = GPOS_NEW(mp) CBitSet(mp, EopttraceSentinel); @@ -561,6 +568,10 @@ CConfigParamMapping::PackConfigParamInBitset( GPOPT_DISABLE_XFORM_TF(CXform::ExfRightOuterJoin2HashJoin)); } + if (create_vec_plan) { + traceflag_bitset->ExchangeSet(EopttraceEnableWindowHashAgg); + } + return traceflag_bitset; } diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp index c7b89c0384e..e706f5f68ac 100644 --- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp +++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp @@ -407,8 +407,13 @@ CTranslatorDXLToPlStmt::TranslateDXLOperatorToPlan( } case EdxlopPhysicalWindow: { - plan = TranslateDXLWindow(dxlnode, output_context, + if (CDXLPhysicalWindow::Cast(dxlnode->GetOperator())->IsWindowHashAgg()) { + plan = TranslateDXLWindowHashAgg(dxlnode, output_context, + ctxt_translation_prev_siblings); + } else { + plan = TranslateDXLWindowAgg(dxlnode, output_context, ctxt_translation_prev_siblings); + } break; } case EdxlopPhysicalSort: @@ -3040,16 +3045,121 @@ CTranslatorDXLToPlStmt::TranslateDXLAgg( return (Plan *) agg; } +static +int WindowFrameSpecToOptions(const EdxlFrameSpec &dxlFS) { + int winFrameOptions = 0; + if (EdxlfsRow == dxlFS) + { + winFrameOptions |= FRAMEOPTION_ROWS; + } + else if (EdxlfsGroups == dxlFS) + { + winFrameOptions |= FRAMEOPTION_GROUPS; + } + else + { + winFrameOptions |= FRAMEOPTION_RANGE; + } + return winFrameOptions; +} + +static +int WindowFrameExclusionStrategyToOptions(const EdxlFrameExclusionStrategy &dxlFES) { + int winFrameOptions = 0; + if (dxlFES == EdxlfesCurrentRow) + { + winFrameOptions |= FRAMEOPTION_EXCLUDE_CURRENT_ROW; + } + else if (dxlFES == EdxlfesGroup) + { + winFrameOptions |= FRAMEOPTION_EXCLUDE_GROUP; + } + else if (dxlFES == EdxlfesTies) + { + winFrameOptions |= FRAMEOPTION_EXCLUDE_TIES; + } + + return winFrameOptions; +} + +static +int WindowFrameStartBoundaryToOptions(const EdxlFrameBoundary &dxlFB) { + int winFrameOptions = 0; + if (dxlFB == EdxlfbUnboundedPreceding) + { + winFrameOptions |= FRAMEOPTION_START_UNBOUNDED_PRECEDING; + } + if (dxlFB == EdxlfbBoundedPreceding) + { + winFrameOptions |= FRAMEOPTION_START_OFFSET_PRECEDING; + } + if (dxlFB == EdxlfbCurrentRow) + { + winFrameOptions |= FRAMEOPTION_START_CURRENT_ROW; + } + if (dxlFB == EdxlfbBoundedFollowing) + { + winFrameOptions |= FRAMEOPTION_START_OFFSET_FOLLOWING; + } + if (dxlFB == EdxlfbUnboundedFollowing) + { + winFrameOptions |= FRAMEOPTION_START_UNBOUNDED_FOLLOWING; + } + if (dxlFB == EdxlfbDelayedBoundedPreceding) + { + winFrameOptions |= FRAMEOPTION_START_OFFSET_PRECEDING; + } + if (dxlFB == EdxlfbDelayedBoundedFollowing) + { + winFrameOptions |= FRAMEOPTION_START_OFFSET_FOLLOWING; + } + return winFrameOptions; +} + +static +int WindowFrameEndBoundaryToOptions(const EdxlFrameBoundary &dxlFB) { + int winFrameOptions = 0; + if (dxlFB == EdxlfbUnboundedPreceding) + { + winFrameOptions |= FRAMEOPTION_END_UNBOUNDED_PRECEDING; + } + if (dxlFB == EdxlfbBoundedPreceding) + { + winFrameOptions |= FRAMEOPTION_END_OFFSET_PRECEDING; + } + if (dxlFB == EdxlfbCurrentRow) + { + winFrameOptions |= FRAMEOPTION_END_CURRENT_ROW; + } + if (dxlFB == EdxlfbBoundedFollowing) + { + winFrameOptions |= FRAMEOPTION_END_OFFSET_FOLLOWING; + } + if (dxlFB == EdxlfbUnboundedFollowing) + { + winFrameOptions |= FRAMEOPTION_END_UNBOUNDED_FOLLOWING; + } + if (dxlFB == EdxlfbDelayedBoundedPreceding) + { + winFrameOptions |= FRAMEOPTION_END_OFFSET_PRECEDING; + } + if (dxlFB == EdxlfbDelayedBoundedFollowing) + { + winFrameOptions |= FRAMEOPTION_END_OFFSET_FOLLOWING; + } + return winFrameOptions; +} + //--------------------------------------------------------------------------- // @function: -// CTranslatorDXLToPlStmt::TranslateDXLWindow +// CTranslatorDXLToPlStmt::TranslateDXLWindowAgg // // @doc: // Translate DXL window node into GPDB window plan node // //--------------------------------------------------------------------------- Plan * -CTranslatorDXLToPlStmt::TranslateDXLWindow( +CTranslatorDXLToPlStmt::TranslateDXLWindowAgg( const CDXLNode *window_dxlnode, CDXLTranslateContext *output_context, CDXLTranslationContextArray *ctxt_translation_prev_siblings) { @@ -3104,9 +3214,6 @@ CTranslatorDXLToPlStmt::TranslateDXLWindow( const ULongPtrArray *part_by_cols_array = window_dxlop->GetPartByColsArray(); window->partNumCols = part_by_cols_array->Size(); - window->partColIdx = nullptr; - window->partOperators = nullptr; - window->partCollations = nullptr; if (window->partNumCols > 0) { @@ -3116,6 +3223,10 @@ CTranslatorDXLToPlStmt::TranslateDXLWindow( (Oid *) gpdb::GPDBAlloc(window->partNumCols * sizeof(Oid)); window->partCollations = (Oid *) gpdb::GPDBAlloc(window->partNumCols * sizeof(Oid)); + } else { + window->partColIdx = nullptr; + window->partOperators = nullptr; + window->partCollations = nullptr; } const ULONG num_of_part_cols = part_by_cols_array->Size(); @@ -3196,34 +3307,214 @@ CTranslatorDXLToPlStmt::TranslateDXLWindow( if (nullptr != window_key->GetWindowFrame()) { window->frameOptions = FRAMEOPTION_NONDEFAULT; - if (EdxlfsRow == window_frame->ParseDXLFrameSpec()) - { - window->frameOptions |= FRAMEOPTION_ROWS; - } - else if (EdxlfsGroups == window_frame->ParseDXLFrameSpec()) - { - window->frameOptions |= FRAMEOPTION_GROUPS; - } - else - { - window->frameOptions |= FRAMEOPTION_RANGE; - } + window->frameOptions |= WindowFrameSpecToOptions(window_frame->ParseDXLFrameSpec()); + window->frameOptions |= WindowFrameExclusionStrategyToOptions( + window_frame->ParseFrameExclusionStrategy()); - if (window_frame->ParseFrameExclusionStrategy() == - EdxlfesCurrentRow) - { - window->frameOptions |= FRAMEOPTION_EXCLUDE_CURRENT_ROW; - } - else if (window_frame->ParseFrameExclusionStrategy() == - EdxlfesGroup) + // translate the CDXLNodes representing the leading and trailing edge + CDXLTranslationContextArray *child_contexts = + GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp); + child_contexts->Append(&child_context); + + CMappingColIdVarPlStmt colid_var_mapping = + CMappingColIdVarPlStmt(m_mp, nullptr, child_contexts, + output_context, m_dxl_to_plstmt_context); + + // Translate lead boundary + // + // Note that we don't distinguish between the delayed and undelayed + // versions beoynd this point. Executor will make that decision + // without our help. + // + CDXLNode *win_frame_leading_dxlnode = window_frame->PdxlnLeading(); + window->frameOptions |= WindowFrameStartBoundaryToOptions( + CDXLScalarWindowFrameEdge::Cast(win_frame_leading_dxlnode->GetOperator()) + ->ParseDXLFrameBoundary()); + if (0 != win_frame_leading_dxlnode->Arity()) { - window->frameOptions |= FRAMEOPTION_EXCLUDE_GROUP; + window->startOffset = + (Node *) m_translator_dxl_to_scalar->TranslateDXLToScalar( + (*win_frame_leading_dxlnode)[0], &colid_var_mapping); } - else if (window_frame->ParseFrameExclusionStrategy() == EdxlfesTies) + + // And the same for the trail boundary + CDXLNode *win_frame_trailing_dxlnode = + window_frame->PdxlnTrailing(); + window->frameOptions |= WindowFrameEndBoundaryToOptions( + CDXLScalarWindowFrameEdge::Cast( + win_frame_trailing_dxlnode->GetOperator()) + ->ParseDXLFrameBoundary()); + + if (0 != win_frame_trailing_dxlnode->Arity()) { - window->frameOptions |= FRAMEOPTION_EXCLUDE_TIES; + window->endOffset = + (Node *) m_translator_dxl_to_scalar->TranslateDXLToScalar( + (*win_frame_trailing_dxlnode)[0], &colid_var_mapping); } + window->startInRangeFunc = window_frame->PdxlnStartInRangeFunc(); + window->endInRangeFunc = window_frame->PdxlnEndInRangeFunc(); + window->inRangeColl = window_frame->PdxlnInRangeColl(); + window->inRangeAsc = window_frame->PdxlnInRangeAsc(); + window->inRangeNullsFirst = window_frame->PdxlnInRangeNullsFirst(); + + // cleanup + child_contexts->Release(); + } + else + { + window->frameOptions = FRAMEOPTION_DEFAULTS; + } + } + + SetParamIds(plan); + + // cleanup + child_contexts->Release(); + + return (Plan *) window; +} + +//--------------------------------------------------------------------------- +// @function: +// CTranslatorDXLToPlStmt::TranslateDXLWindowHashAgg +// +// @doc: +// Translate DXL window node into GPDB window hash plan node +// +//--------------------------------------------------------------------------- +Plan * +CTranslatorDXLToPlStmt::TranslateDXLWindowHashAgg( + const CDXLNode *window_dxlnode, CDXLTranslateContext *output_context, + CDXLTranslationContextArray *ctxt_translation_prev_siblings) +{ + WindowHashAgg *window = MakeNode(WindowHashAgg); + + Plan *plan = &(window->plan); + plan->plan_node_id = m_dxl_to_plstmt_context->GetNextPlanId(); + + CDXLPhysicalWindow *window_dxlop = + CDXLPhysicalWindow::Cast(window_dxlnode->GetOperator()); + + // translate the operator costs + TranslatePlanCosts(window_dxlnode, plan); + + // translate children + CDXLNode *child_dxlnode = (*window_dxlnode)[EdxlwindowIndexChild]; + CDXLNode *project_list_dxlnode = (*window_dxlnode)[EdxlwindowIndexProjList]; + CDXLNode *filter_dxlnode = (*window_dxlnode)[EdxlwindowIndexFilter]; + + CDXLTranslateContext child_context(m_mp, true, + output_context->GetColIdToParamIdMap()); + Plan *child_plan = TranslateDXLOperatorToPlan( + child_dxlnode, &child_context, ctxt_translation_prev_siblings); + + CDXLTranslationContextArray *child_contexts = + GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp); + child_contexts->Append(&child_context); + + // translate proj list and filter + TranslateProjListAndFilter(project_list_dxlnode, filter_dxlnode, + nullptr, // translate context for the base table + child_contexts, // pdxltrctxRight, + &plan->targetlist, &plan->qual, output_context); + + ListCell *lc; + + foreach (lc, plan->targetlist) + { + TargetEntry *target_entry = (TargetEntry *) lfirst(lc); + if (IsA(target_entry->expr, WindowFunc)) + { + WindowFunc *window_func = (WindowFunc *) target_entry->expr; + window->winref = window_func->winref; + break; + } + } + + plan->lefttree = child_plan; + + // translate partition columns + const ULongPtrArray *part_by_cols_array = + window_dxlop->GetPartByColsArray(); + window->partNumCols = part_by_cols_array->Size(); + + if (window->partNumCols > 0) + { + window->partColIdx = (AttrNumber *) gpdb::GPDBAlloc( + window->partNumCols * sizeof(AttrNumber)); + window->partOperators = + (Oid *) gpdb::GPDBAlloc(window->partNumCols * sizeof(Oid)); + window->partCollations = + (Oid *) gpdb::GPDBAlloc(window->partNumCols * sizeof(Oid)); + } else { + window->partColIdx = nullptr; + window->partOperators = nullptr; + window->partCollations = nullptr; + } + + const ULONG num_of_part_cols = part_by_cols_array->Size(); + for (ULONG ul = 0; ul < num_of_part_cols; ul++) + { + ULONG part_colid = *((*part_by_cols_array)[ul]); + const TargetEntry *te_part_colid = + child_context.GetTargetEntry(part_colid); + if (nullptr == te_part_colid) + { + GPOS_RAISE(gpdxl::ExmaDXL, gpdxl::ExmiDXL2PlStmtAttributeNotFound, + part_colid); + } + window->partColIdx[ul] = te_part_colid->resno; + + // Also find the equality operators to use for each partitioning key col. + Oid type_id = gpdb::ExprType((Node *) te_part_colid->expr); + window->partOperators[ul] = gpdb::GetEqualityOp(type_id); + Assert(window->partOperators[ul] != 0); + window->partCollations[ul] = + gpdb::ExprCollation((Node *) te_part_colid->expr); + } + + // translate window keys + const ULONG size = window_dxlop->WindowKeysCount(); + if (size > 1) + { + GpdbEreport(ERRCODE_INTERNAL_ERROR, ERROR, + "ORCA produced a plan with more than one window key", + nullptr); + } + GPOS_ASSERT(size <= 1 && "cannot have more than one window key"); + + if (size == 1) + { + // translate the sorting columns used in the window key + const CDXLWindowKey *window_key = window_dxlop->GetDXLWindowKeyAt(0); + const CDXLWindowFrame *window_frame = window_key->GetWindowFrame(); + const CDXLNode *sort_col_list_dxlnode = window_key->GetSortColListDXL(); + + const ULONG num_of_cols = sort_col_list_dxlnode->Arity(); + + window->ordNumCols = num_of_cols; + window->ordColIdx = + (AttrNumber *) gpdb::GPDBAlloc(num_of_cols * sizeof(AttrNumber)); + window->ordOperators = + (Oid *) gpdb::GPDBAlloc(num_of_cols * sizeof(Oid)); + window->ordCollations = + (Oid *) gpdb::GPDBAlloc(num_of_cols * sizeof(Oid)); + window->ordNullsFirst = + (bool *) gpdb::GPDBAlloc(num_of_cols * sizeof(bool)); + // different with windowagg, sort should be full + TranslateSortCols(sort_col_list_dxlnode, &child_context, + window->ordColIdx, window->ordOperators, + window->ordCollations, window->ordNullsFirst); + + // translate the window frame specified in the window key + if (nullptr != window_key->GetWindowFrame()) + { + window->frameOptions = FRAMEOPTION_NONDEFAULT; + window->frameOptions |= WindowFrameSpecToOptions(window_frame->ParseDXLFrameSpec()); + window->frameOptions |= WindowFrameExclusionStrategyToOptions( + window_frame->ParseFrameExclusionStrategy()); + // translate the CDXLNodes representing the leading and trailing edge CDXLTranslationContextArray *child_contexts = GPOS_NEW(m_mp) CDXLTranslationContextArray(m_mp); @@ -3240,38 +3531,9 @@ CTranslatorDXLToPlStmt::TranslateDXLWindow( // without our help. // CDXLNode *win_frame_leading_dxlnode = window_frame->PdxlnLeading(); - EdxlFrameBoundary lead_boundary_type = - CDXLScalarWindowFrameEdge::Cast( - win_frame_leading_dxlnode->GetOperator()) - ->ParseDXLFrameBoundary(); - if (lead_boundary_type == EdxlfbUnboundedPreceding) - { - window->frameOptions |= FRAMEOPTION_START_UNBOUNDED_PRECEDING; - } - if (lead_boundary_type == EdxlfbBoundedPreceding) - { - window->frameOptions |= FRAMEOPTION_START_OFFSET_PRECEDING; - } - if (lead_boundary_type == EdxlfbCurrentRow) - { - window->frameOptions |= FRAMEOPTION_START_CURRENT_ROW; - } - if (lead_boundary_type == EdxlfbBoundedFollowing) - { - window->frameOptions |= FRAMEOPTION_START_OFFSET_FOLLOWING; - } - if (lead_boundary_type == EdxlfbUnboundedFollowing) - { - window->frameOptions |= FRAMEOPTION_START_UNBOUNDED_FOLLOWING; - } - if (lead_boundary_type == EdxlfbDelayedBoundedPreceding) - { - window->frameOptions |= FRAMEOPTION_START_OFFSET_PRECEDING; - } - if (lead_boundary_type == EdxlfbDelayedBoundedFollowing) - { - window->frameOptions |= FRAMEOPTION_START_OFFSET_FOLLOWING; - } + window->frameOptions |= WindowFrameStartBoundaryToOptions( + CDXLScalarWindowFrameEdge::Cast(win_frame_leading_dxlnode->GetOperator()) + ->ParseDXLFrameBoundary()); if (0 != win_frame_leading_dxlnode->Arity()) { window->startOffset = @@ -3282,38 +3544,11 @@ CTranslatorDXLToPlStmt::TranslateDXLWindow( // And the same for the trail boundary CDXLNode *win_frame_trailing_dxlnode = window_frame->PdxlnTrailing(); - EdxlFrameBoundary trail_boundary_type = + window->frameOptions |= WindowFrameEndBoundaryToOptions( CDXLScalarWindowFrameEdge::Cast( win_frame_trailing_dxlnode->GetOperator()) - ->ParseDXLFrameBoundary(); - if (trail_boundary_type == EdxlfbUnboundedPreceding) - { - window->frameOptions |= FRAMEOPTION_END_UNBOUNDED_PRECEDING; - } - if (trail_boundary_type == EdxlfbBoundedPreceding) - { - window->frameOptions |= FRAMEOPTION_END_OFFSET_PRECEDING; - } - if (trail_boundary_type == EdxlfbCurrentRow) - { - window->frameOptions |= FRAMEOPTION_END_CURRENT_ROW; - } - if (trail_boundary_type == EdxlfbBoundedFollowing) - { - window->frameOptions |= FRAMEOPTION_END_OFFSET_FOLLOWING; - } - if (trail_boundary_type == EdxlfbUnboundedFollowing) - { - window->frameOptions |= FRAMEOPTION_END_UNBOUNDED_FOLLOWING; - } - if (trail_boundary_type == EdxlfbDelayedBoundedPreceding) - { - window->frameOptions |= FRAMEOPTION_END_OFFSET_PRECEDING; - } - if (trail_boundary_type == EdxlfbDelayedBoundedFollowing) - { - window->frameOptions |= FRAMEOPTION_END_OFFSET_FOLLOWING; - } + ->ParseDXLFrameBoundary()); + if (0 != win_frame_trailing_dxlnode->Arity()) { window->endOffset = diff --git a/src/backend/gpopt/utils/COptTasks.cpp b/src/backend/gpopt/utils/COptTasks.cpp index 0f5aadbd82a..dd0e61116d8 100644 --- a/src/backend/gpopt/utils/COptTasks.cpp +++ b/src/backend/gpopt/utils/COptTasks.cpp @@ -913,7 +913,7 @@ COptTasks::OptimizeTask(void *ptr) { // set trace flags trace_flags = CConfigParamMapping::PackConfigParamInBitset( - mp, CXform::ExfSentinel); + mp, CXform::ExfSentinel, opt_ctxt->m_create_vec_plan); SetTraceflags(mp, trace_flags, &enabled_trace_flags, &disabled_trace_flags); @@ -1156,13 +1156,15 @@ COptTasks::Optimize(Query *query) // //--------------------------------------------------------------------------- PlannedStmt * -COptTasks::GPOPTOptimizedPlan(Query *query, SOptContext *gpopt_context) +COptTasks::GPOPTOptimizedPlan(Query *query, SOptContext *gpopt_context, OptimizerOptions *opts) { Assert(query); Assert(gpopt_context); gpopt_context->m_query = query; gpopt_context->m_should_generate_plan_stmt = true; + // Copy options in `OptimizerOptions` to `SOptContext` + gpopt_context->m_create_vec_plan = opts->create_vectorization_plan; Execute(&OptimizeTask, gpopt_context); return gpopt_context->m_plan_stmt; } diff --git a/src/backend/gporca/libgpdbcost/include/gpdbcost/CCostModelGPDB.h b/src/backend/gporca/libgpdbcost/include/gpdbcost/CCostModelGPDB.h index 9103a08ed8e..2b44693fa4e 100644 --- a/src/backend/gporca/libgpdbcost/include/gpdbcost/CCostModelGPDB.h +++ b/src/backend/gporca/libgpdbcost/include/gpdbcost/CCostModelGPDB.h @@ -107,6 +107,12 @@ class CCostModelGPDB : public ICostModel const CCostModelGPDB *pcmgpdb, const SCostingInfo *pci); + // cost of hash sequence project + static CCost CostHashSequenceProject(CMemoryPool *mp, + CExpressionHandle &exprhdl, + const CCostModelGPDB *pcmgpdb, + const SCostingInfo *pci); + // cost of CTE producer static CCost CostCTEProducer(CMemoryPool *mp, CExpressionHandle &exprhdl, const CCostModelGPDB *pcmgpdb, diff --git a/src/backend/gporca/libgpdbcost/src/CCostModelGPDB.cpp b/src/backend/gporca/libgpdbcost/src/CCostModelGPDB.cpp index a91fc4283fd..73330059c72 100644 --- a/src/backend/gporca/libgpdbcost/src/CCostModelGPDB.cpp +++ b/src/backend/gporca/libgpdbcost/src/CCostModelGPDB.cpp @@ -31,6 +31,7 @@ #include "gpopt/operators/CPhysicalMotionBroadcast.h" #include "gpopt/operators/CPhysicalPartitionSelector.h" #include "gpopt/operators/CPhysicalSequenceProject.h" +#include "gpopt/operators/CPhysicalHashSequenceProject.h" #include "gpopt/operators/CPhysicalStreamAgg.h" #include "gpopt/operators/CPhysicalUnionAll.h" #include "gpopt/operators/CPredicateUtils.h" @@ -1594,11 +1595,17 @@ CCostModelGPDB::CostSequenceProject(CMemoryPool *mp, CExpressionHandle &exprhdl, GPOS_ASSERT(COperator::EopPhysicalSequenceProject == exprhdl.Pop()->Eopid()); + const CDouble dTupDefaultProcCostUnit = + pcmgpdb->GetCostModelParams() + ->PcpLookup(CCostModelParamsGPDB::EcpTupDefaultProcCostUnit) + ->Get(); + GPOS_ASSERT(0 < dTupDefaultProcCostUnit); + CPhysicalSequenceProject *psp = CPhysicalSequenceProject::PopConvert(exprhdl.Pop()); - if (GPOS_FTRACE(EopttraceForceSplitWindowFunc) && + if (GPOS_FTRACE(EopttraceForceSplitWindowFunc) && psp->Pspt() == COperator::EsptypeGlobalTwoStep) { - return CCost(0); + return CCost(dTupDefaultProcCostUnit * 2); } const DOUBLE num_rows_outer = pci->PdRows()[0]; @@ -1614,12 +1621,59 @@ CCostModelGPDB::CostSequenceProject(CMemoryPool *mp, CExpressionHandle &exprhdl, ulSortCols += pos->UlSortColumns(); } + // we process (sorted window of) input tuples to compute window function values + CCost costLocal = + CCost(pci->NumRebinds() * (ulSortCols * num_rows_outer * dWidthOuter * + dTupDefaultProcCostUnit)); + CCost costChild = + CostChildren(mp, exprhdl, pci, pcmgpdb->GetCostModelParams()); + + return costLocal + costChild; +} + +//--------------------------------------------------------------------------- +// @function: +// CCostModelGPDB::CostSequenceProject +// +// @doc: +// Cost of sequence project +// +//--------------------------------------------------------------------------- +CCost +CCostModelGPDB::CostHashSequenceProject(CMemoryPool *mp, CExpressionHandle &exprhdl, + const CCostModelGPDB *pcmgpdb, + const SCostingInfo *pci) +{ + GPOS_ASSERT(nullptr != pcmgpdb); + GPOS_ASSERT(nullptr != pci); + GPOS_ASSERT(COperator::EopPhysicalHashSequenceProject == + exprhdl.Pop()->Eopid()); const CDouble dTupDefaultProcCostUnit = pcmgpdb->GetCostModelParams() ->PcpLookup(CCostModelParamsGPDB::EcpTupDefaultProcCostUnit) ->Get(); GPOS_ASSERT(0 < dTupDefaultProcCostUnit); + CPhysicalHashSequenceProject *psp = CPhysicalHashSequenceProject::PopConvert(exprhdl.Pop()); + + if (GPOS_FTRACE(EopttraceForceSplitWindowFunc) && + psp->Pspt() == COperator::EsptypeGlobalTwoStep) { + return CCost(dTupDefaultProcCostUnit); + } + + const DOUBLE num_rows_outer = pci->PdRows()[0]; + const DOUBLE dWidthOuter = pci->GetWidth()[0]; + + ULONG ulSortCols = 0; + COrderSpecArray *pdrgpos = + CPhysicalHashSequenceProject::PopConvert(psp)->Pdrgpos(); + const ULONG ulOrderSpecs = pdrgpos->Size(); + for (ULONG ul = 0; ul < ulOrderSpecs; ul++) + { + COrderSpec *pos = (*pdrgpos)[ul]; + ulSortCols += pos->UlSortColumns(); + } + // we process (sorted window of) input tuples to compute window function values CCost costLocal = CCost(pci->NumRebinds() * (ulSortCols * num_rows_outer * dWidthOuter * @@ -2462,18 +2516,26 @@ CCostModelGPDB::Cost( return CostSequenceProject(m_mp, exprhdl, this, pci); } + case COperator::EopPhysicalHashSequenceProject: + { + return CostHashSequenceProject(m_mp, exprhdl, this, pci); + } + case COperator::EopPhysicalCTEProducer: { return CostCTEProducer(m_mp, exprhdl, this, pci); } + case COperator::EopPhysicalCTEConsumer: { return CostCTEConsumer(m_mp, exprhdl, this, pci); } + case COperator::EopPhysicalConstTableGet: { return CostConstTableGet(m_mp, exprhdl, this, pci); } + case COperator::EopPhysicalDML: { return CostDML(m_mp, exprhdl, this, pci); diff --git a/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpec.h b/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpec.h index d8b4919674b..d3b47b95f80 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpec.h +++ b/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpec.h @@ -179,6 +179,9 @@ class CDistributionSpec : public CPropSpec } // print IOstream &OsPrint(IOstream &os) const override = 0; + virtual IOstream &OsPrintNoWrap(IOstream &os) const{ + return OsPrint(os); + } // return distribution partitioning type virtual EDistributionPartitioningType Edpt() const = 0; diff --git a/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpecHashed.h b/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpecHashed.h index 306b36f4ab9..5e4de6ac62a 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpecHashed.h +++ b/src/backend/gporca/libgpopt/include/gpopt/base/CDistributionSpecHashed.h @@ -178,7 +178,8 @@ class CDistributionSpecHashed : public CDistributionSpecRandom // print IOstream &OsPrint(IOstream &os) const override; - IOstream &OsPrintWithPrefix(IOstream &os, const char *prefix) const; + IOstream &OsPrintNoWrap(IOstream &os) const override; + IOstream &OsPrintWithPrefix(IOstream &os, const char *prefix, BOOL wrap = true) const; // return a hashed distribution on the maximal hashable subset of given columns static CDistributionSpecHashed *PdshashedMaximal(CMemoryPool *mp, diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h b/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h index 272bba90929..657e3082ef7 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h +++ b/src/backend/gporca/libgpopt/include/gpopt/operators/COperator.h @@ -213,6 +213,7 @@ class COperator : public CRefCount, public DbgPrintMixin EopPhysicalCTEProducer, EopPhysicalCTEConsumer, EopPhysicalSequenceProject, + EopPhysicalHashSequenceProject, EopPhysicalDynamicIndexScan, EopPhysicalInnerHashJoin, diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalHashSequenceProject.h b/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalHashSequenceProject.h new file mode 100644 index 00000000000..288c0873b47 --- /dev/null +++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalHashSequenceProject.h @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------- + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * CPhysicalHashSequenceProject.h + * + * IDENTIFICATION + * src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalHashSequenceProject.h + * + *------------------------------------------------------------------------- + */ + +#ifndef GPOPT_CPhysicalHashSequenceProject_H +#define GPOPT_CPhysicalHashSequenceProject_H + +#include "gpos/base.h" + +#include "gpopt/base/CWindowFrame.h" +#include "gpopt/operators/CPhysicalSequenceProject.h" + +namespace gpopt +{ +// fwd declarations +class CDistributionSpec; + +//--------------------------------------------------------------------------- +// @class: +// CPhysicalHashSequenceProject +// +// @doc: +// Physical Hash Sequence Project operator +// +//--------------------------------------------------------------------------- +class CPhysicalHashSequenceProject : public CPhysicalSequenceProject +{ +public: + CPhysicalHashSequenceProject(const CPhysicalHashSequenceProject &) = delete; + + // ctor + CPhysicalHashSequenceProject(CMemoryPool *mp, ESPType m_sptype, + CDistributionSpec *pds, + COrderSpecArray *pdrgpos, + CWindowFrameArray *pdrgpwf); + + // dtor + ~CPhysicalHashSequenceProject() override; + + // ident accessors + EOperatorId + Eopid() const override + { + return EopPhysicalHashSequenceProject; + } + + // operator name + const CHAR * + SzId() const override + { + return "CPhysicalHashSequenceProject"; + } + + // match function + BOOL Matches(COperator *pop) const override; + + // hashing function + ULONG HashValue() const override; + + // sensitivity to order of inputs + BOOL FInputOrderSensitive() const override; + + // compute required sort order of the n-th child + COrderSpec *PosRequired(CMemoryPool *mp, CExpressionHandle &exprhdl, + COrderSpec *posRequired, ULONG child_index, + CDrvdPropArray *pdrgpdpCtxt, + ULONG ulOptReq) const override; + + // return order property enforcing type for this operator + CEnfdProp::EPropEnforcingType EpetOrder( + CExpressionHandle &exprhdl, const CEnfdOrder *peo) const override; + + // return true if operator passes through stats obtained from children, + // this is used when computing stats during costing + BOOL + FPassThruStats() const override + { + return true; + } + + // print + IOstream &OsPrint(IOstream &os) const override; + + // conversion function + static CPhysicalHashSequenceProject * + PopConvert(COperator *pop) + { + GPOS_ASSERT(nullptr != pop); + GPOS_ASSERT(EopPhysicalHashSequenceProject == pop->Eopid()); + + return dynamic_cast(pop); + } + +}; // class CPhysicalHashSequenceProject + +} // namespace gpopt + +#endif // !GPOPT_CPhysicalHashSequenceProject_H + +// EOF diff --git a/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalSequenceProject.h b/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalSequenceProject.h index dc6afd1ecfa..e9d84d6edad 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalSequenceProject.h +++ b/src/backend/gporca/libgpopt/include/gpopt/operators/CPhysicalSequenceProject.h @@ -31,7 +31,7 @@ class CDistributionSpec; //--------------------------------------------------------------------------- class CPhysicalSequenceProject : public CPhysical { -private: +protected: // window type ESPType m_sptype; diff --git a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h index a3acaebb254..2c50e9e812f 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h +++ b/src/backend/gporca/libgpopt/include/gpopt/translate/CTranslatorExprToDXL.h @@ -244,7 +244,7 @@ class CTranslatorExprToDXL CDXLNode *PdxlnWindow(CExpression *pexprSeqPrj, CColRefArray *colref_array, CDistributionSpecArray *pdrgpdsBaseTables, - ULONG *pulNonGatherMotions, BOOL *pfDML); + ULONG *pulNonGatherMotions, BOOL *pfDML, BOOL fWindowHashAgg); CDXLNode *PdxlnNLJoin(CExpression *pexprNLJ, CColRefArray *colref_array, CDistributionSpecArray *pdrgpdsBaseTables, diff --git a/src/backend/gporca/libgpopt/include/gpopt/xforms/CXform.h b/src/backend/gporca/libgpopt/include/gpopt/xforms/CXform.h index fc7a1c8c7e6..904e6b4b1c8 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/xforms/CXform.h +++ b/src/backend/gporca/libgpopt/include/gpopt/xforms/CXform.h @@ -170,6 +170,7 @@ class CXform : public CRefCount, public DbgPrintMixin ExfSplitDQA, ExfSequenceProject2Apply, ExfImplementSequenceProject, + ExfImplementHashSequenceProject, ExfImplementAssert, ExfCTEAnchor2Sequence, ExfCTEAnchor2TrivialSelect, diff --git a/src/backend/gporca/libgpopt/include/gpopt/xforms/CXformImplementHashSequenceProject.h b/src/backend/gporca/libgpopt/include/gpopt/xforms/CXformImplementHashSequenceProject.h new file mode 100644 index 00000000000..1422a1bbaec --- /dev/null +++ b/src/backend/gporca/libgpopt/include/gpopt/xforms/CXformImplementHashSequenceProject.h @@ -0,0 +1,95 @@ +/*------------------------------------------------------------------------- + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * CXformImplementHashSequenceProject.h + * + * IDENTIFICATION + * src/backend/gporca/libgpopt/include/gpopt/xforms/CXformImplementHashSequenceProject.h + * + *------------------------------------------------------------------------- + */ +#ifndef GPOPT_CXformImplementHashSequenceProject_H +#define GPOPT_CXformImplementHashSequenceProject_H + +#include "gpos/base.h" + +#include "gpopt/operators/CExpressionHandle.h" +#include "gpopt/xforms/CXformImplementation.h" + +namespace gpopt +{ +using namespace gpos; + +//--------------------------------------------------------------------------- +// @class: +// CXformImplementHashSequenceProject +// +// @doc: +// Transform Project to ComputeScalar +// +//--------------------------------------------------------------------------- +class CXformImplementHashSequenceProject : public CXformImplementation +{ +private: +public: + CXformImplementHashSequenceProject( + const CXformImplementHashSequenceProject &) = delete; + + // ctor + explicit CXformImplementHashSequenceProject(CMemoryPool *mp); + + // dtor + ~CXformImplementHashSequenceProject() override = default; + + // ident accessors + EXformId + Exfid() const override + { + return ExfImplementHashSequenceProject; + } + + const CHAR * + SzId() const override + { + return "CXformImplementHashSequenceProject"; + } + + // compute xform promise for a given expression handle + EXformPromise + Exfp(CExpressionHandle &exprhdl) const override + { + if (exprhdl.DeriveHasSubquery(1)) + { + return CXform::ExfpNone; + } + + return CXform::ExfpHigh; + } + + // actual transform + void Transform(CXformContext *, CXformResult *, + CExpression *) const override; + +}; // class CXformImplementHashSequenceProject + +} // namespace gpopt + +#endif // !GPOPT_CXformImplementHashSequenceProject_H + +// EOF diff --git a/src/backend/gporca/libgpopt/include/gpopt/xforms/xforms.h b/src/backend/gporca/libgpopt/include/gpopt/xforms/xforms.h index 25e724c2128..d0972b2be2c 100644 --- a/src/backend/gporca/libgpopt/include/gpopt/xforms/xforms.h +++ b/src/backend/gporca/libgpopt/include/gpopt/xforms/xforms.h @@ -71,6 +71,7 @@ #include "gpopt/xforms/CXformImplementLimit.h" #include "gpopt/xforms/CXformImplementSequence.h" #include "gpopt/xforms/CXformImplementSequenceProject.h" +#include "gpopt/xforms/CXformImplementHashSequenceProject.h" #include "gpopt/xforms/CXformImplementSplit.h" #include "gpopt/xforms/CXformImplementTVF.h" #include "gpopt/xforms/CXformImplementTVFNoArgs.h" diff --git a/src/backend/gporca/libgpopt/src/base/CDistributionSpecHashed.cpp b/src/backend/gporca/libgpopt/src/base/CDistributionSpecHashed.cpp index 7636b0d74d4..0adf07022d8 100644 --- a/src/backend/gporca/libgpopt/src/base/CDistributionSpecHashed.cpp +++ b/src/backend/gporca/libgpopt/src/base/CDistributionSpecHashed.cpp @@ -858,9 +858,16 @@ CDistributionSpecHashed::OsPrint(IOstream &os) const return OsPrintWithPrefix(os, ""); } +IOstream & +CDistributionSpecHashed::OsPrintNoWrap(IOstream &os) const +{ + return OsPrintWithPrefix(os, "", false); +} + IOstream & CDistributionSpecHashed::OsPrintWithPrefix(IOstream &os, - const char *prefix) const + const char *prefix, + BOOL wrap) const { os << this->SzId() << ": [ "; const ULONG length = m_pdrgpexpr->Size(); @@ -876,7 +883,7 @@ CDistributionSpecHashed::OsPrintWithPrefix(IOstream &os, } else { - os << *(hash_expr); + hash_expr->OsPrint(os); // the expression added a newline, indent the following with the prefix os << prefix; } @@ -912,7 +919,8 @@ CDistributionSpecHashed::OsPrintWithPrefix(IOstream &os, if (nullptr != m_equiv_hash_exprs && m_equiv_hash_exprs->Size() > 0 && GPOS_FTRACE(EopttracePrintEquivDistrSpecs)) { - os << "," << std::endl; + os << ","; + if (wrap) os << std::endl; for (ULONG ul = 0; ul < m_equiv_hash_exprs->Size(); ul++) { CExpressionArray *equiv_distribution_exprs = diff --git a/src/backend/gporca/libgpopt/src/operators/CLogicalSequenceProject.cpp b/src/backend/gporca/libgpopt/src/operators/CLogicalSequenceProject.cpp index f0018ea02a8..4d20c7c5e26 100644 --- a/src/backend/gporca/libgpopt/src/operators/CLogicalSequenceProject.cpp +++ b/src/backend/gporca/libgpopt/src/operators/CLogicalSequenceProject.cpp @@ -369,6 +369,8 @@ CLogicalSequenceProject::PxfsCandidates(CMemoryPool *mp) const CXformSet *xform_set = GPOS_NEW(mp) CXformSet(mp); (void) xform_set->ExchangeSet(CXform::ExfSequenceProject2Apply); (void) xform_set->ExchangeSet(CXform::ExfImplementSequenceProject); + if (GPOS_FTRACE(EopttraceEnableWindowHashAgg)) + (void) xform_set->ExchangeSet(CXform::ExfImplementHashSequenceProject); return xform_set; } diff --git a/src/backend/gporca/libgpopt/src/operators/CPhysicalHashSequenceProject.cpp b/src/backend/gporca/libgpopt/src/operators/CPhysicalHashSequenceProject.cpp new file mode 100644 index 00000000000..4a6fee19a81 --- /dev/null +++ b/src/backend/gporca/libgpopt/src/operators/CPhysicalHashSequenceProject.cpp @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * CPhysicalHashSequenceProject.cpp + * + * IDENTIFICATION + * src/backend/gporca/libgpopt/src/operators/CPhysicalHashSequenceProject.cpp + * + *------------------------------------------------------------------------- + */ + +#include "gpopt/operators/CPhysicalHashSequenceProject.h" + +#include "gpos/base.h" + +#include "gpopt/base/CDistributionSpecAny.h" +#include "gpopt/base/CDistributionSpecHashed.h" +#include "gpopt/base/CDistributionSpecReplicated.h" +#include "gpopt/base/CDistributionSpecSingleton.h" +#include "gpopt/base/COptCtxt.h" +#include "gpopt/base/CUtils.h" +#include "gpopt/base/CWindowFrame.h" +#include "gpopt/cost/ICostModel.h" +#include "gpopt/operators/CExpressionHandle.h" +#include "gpopt/operators/CLogicalSequenceProject.h" +#include "gpopt/operators/CScalarIdent.h" + +using namespace gpopt; + +//--------------------------------------------------------------------------- +// @function: +// CPhysicalHashSequenceProject::CPhysicalHashSequenceProject +// +// @doc: +// Ctor +// +//--------------------------------------------------------------------------- +CPhysicalHashSequenceProject::CPhysicalHashSequenceProject(CMemoryPool *mp, + ESPType sptype, + CDistributionSpec *pds, + COrderSpecArray *pdrgpos, + CWindowFrameArray *pdrgpwf) + : CPhysicalSequenceProject(mp, sptype, pds, pdrgpos, pdrgpwf) +{} + +CPhysicalHashSequenceProject::~CPhysicalHashSequenceProject() {} + +COrderSpec * +CPhysicalHashSequenceProject::PosRequired(CMemoryPool *mp, + CExpressionHandle &, // exprhdl + COrderSpec *, // posRequired + ULONG +#ifdef GPOS_DEBUG + child_index +#endif // GPOS_DEBUG + , + CDrvdPropArray *, // pdrgpdpCtxt + ULONG // ulOptReq +) const +{ + GPOS_ASSERT(0 == child_index); + return GPOS_NEW(mp) COrderSpec(mp); +} + +// match function +BOOL +CPhysicalHashSequenceProject::Matches(COperator *pop) const +{ + GPOS_ASSERT(nullptr != pop); + if (Eopid() == pop->Eopid()) + { + CPhysicalHashSequenceProject *popHashSequenceProject = + CPhysicalHashSequenceProject::PopConvert(pop); + return m_sptype == popHashSequenceProject->Pspt() && + m_pds->Matches(popHashSequenceProject->Pds()) && + CWindowFrame::Equals(m_pdrgpwf, + popHashSequenceProject->Pdrgpwf()) && + COrderSpec::Equals(m_pdrgpos, + popHashSequenceProject->Pdrgpos()); + } + + return false; +} + +// hashing function + +ULONG +CPhysicalHashSequenceProject::HashValue() const +{ + BOOL ltrue = true; + ULONG ulHash = CPhysicalSequenceProject::HashValue(); + + ulHash = gpos::CombineHashes(ulHash, m_pds->HashValue()); + // combine a true hash value + ulHash = gpos::CombineHashes(ulHash, gpos::HashValue(<rue)); + + return ulHash; +} + +BOOL +CPhysicalHashSequenceProject::FInputOrderSensitive() const { + return false; +} + +CEnfdProp::EPropEnforcingType +CPhysicalHashSequenceProject::EpetOrder(CExpressionHandle &/*exprhdl*/, + const CEnfdOrder * +#ifdef GPOS_DEBUG + peo +#endif // GPOS_DEBUG +) const +{ + GPOS_ASSERT(nullptr != peo); + GPOS_ASSERT(!peo->PosRequired()->IsEmpty()); + + return CEnfdProp::EpetRequired; +} + + +IOstream &CPhysicalHashSequenceProject::OsPrint(IOstream &os) const +{ + os << SzId() << " ("; + CLogicalSequenceProject::OsPrintWindowType(os, m_sptype); + os << ", hashed) ("; + (void) m_pds->OsPrint(os); + os << ", "; + (void) COrderSpec::OsPrint(os, m_pdrgpos); + os << ", "; + (void) CWindowFrame::OsPrint(os, m_pdrgpwf); + + return os << ")"; +} + + +// EOF diff --git a/src/backend/gporca/libgpopt/src/operators/CPhysicalSequenceProject.cpp b/src/backend/gporca/libgpopt/src/operators/CPhysicalSequenceProject.cpp index 4b663137cf4..3c5aade6eb9 100644 --- a/src/backend/gporca/libgpopt/src/operators/CPhysicalSequenceProject.cpp +++ b/src/backend/gporca/libgpopt/src/operators/CPhysicalSequenceProject.cpp @@ -563,13 +563,12 @@ CPhysicalSequenceProject::OsPrint(IOstream &os) const { os << SzId() << " ("; CLogicalSequenceProject::OsPrintWindowType(os, m_sptype); - os << ") ("; - (void) m_pds->OsPrint(os); + os << ", non-hashed) ("; + (void) m_pds->OsPrintNoWrap(os); os << ", "; (void) COrderSpec::OsPrint(os, m_pdrgpos); os << ", "; (void) CWindowFrame::OsPrint(os, m_pdrgpwf); - return os << ")"; } diff --git a/src/backend/gporca/libgpopt/src/operators/Makefile b/src/backend/gporca/libgpopt/src/operators/Makefile index 5030aec79a0..faa0f9a70d6 100644 --- a/src/backend/gporca/libgpopt/src/operators/Makefile +++ b/src/backend/gporca/libgpopt/src/operators/Makefile @@ -130,6 +130,7 @@ OBJS = CExpression.o \ CPhysicalScan.o \ CPhysicalSequence.o \ CPhysicalSequenceProject.o \ + CPhysicalHashSequenceProject.o \ CPhysicalSerialUnionAll.o \ CPhysicalSort.o \ CPhysicalSplit.o \ diff --git a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp index fa1e7a1d17c..6119e2ba71f 100644 --- a/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp +++ b/src/backend/gporca/libgpopt/src/translate/CTranslatorExprToDXL.cpp @@ -58,6 +58,7 @@ #include "gpopt/operators/CPhysicalPartitionSelector.h" #include "gpopt/operators/CPhysicalScalarAgg.h" #include "gpopt/operators/CPhysicalSequenceProject.h" +#include "gpopt/operators/CPhysicalHashSequenceProject.h" #include "gpopt/operators/CPhysicalSort.h" #include "gpopt/operators/CPhysicalSplit.h" #include "gpopt/operators/CPhysicalSpool.h" @@ -313,8 +314,6 @@ CTranslatorExprToDXL::PdxlnTranslate(CExpression *pexpr, pdxlnPrL->ReplaceChild(ul, pdxlnPrElNew); } - - if (0 == ulNonGatherMotions) { CTranslatorExprToDXLUtils::SetDirectDispatchInfo( @@ -409,10 +408,11 @@ CTranslatorExprToDXL::CreateDXLNode(CExpression *pexpr, pexpr, colref_array, pdrgpdsBaseTables, pulNonGatherMotions, pfDML); break; + case COperator::EopPhysicalHashSequenceProject: case COperator::EopPhysicalSequenceProject: dxlnode = CTranslatorExprToDXL::PdxlnWindow( pexpr, colref_array, pdrgpdsBaseTables, pulNonGatherMotions, - pfDML); + pfDML, pexpr->Pop()->Eopid() == COperator::EopPhysicalHashSequenceProject); break; case COperator::EopPhysicalInnerNLJoin: case COperator::EopPhysicalInnerIndexNLJoin: @@ -6854,11 +6854,13 @@ CDXLNode * CTranslatorExprToDXL::PdxlnWindow(CExpression *pexprSeqPrj, CColRefArray *colref_array, CDistributionSpecArray *pdrgpdsBaseTables, - ULONG *pulNonGatherMotions, BOOL *pfDML) + ULONG *pulNonGatherMotions, BOOL *pfDML, + BOOL fWindowHashAgg) { GPOS_ASSERT(nullptr != pexprSeqPrj); - CPhysicalSequenceProject *popSeqPrj = + CPhysicalSequenceProject *popSeqPrj = fWindowHashAgg ? + CPhysicalHashSequenceProject::PopConvert(pexprSeqPrj->Pop()) : CPhysicalSequenceProject::PopConvert(pexprSeqPrj->Pop()); CDistributionSpec *pds = popSeqPrj->Pds(); ULongPtrArray *colids = GPOS_NEW(m_mp) ULongPtrArray(m_mp); @@ -6940,7 +6942,8 @@ CTranslatorExprToDXL::PdxlnWindow(CExpression *pexprSeqPrj, // construct a Window node CDXLPhysicalWindow *pdxlopWindow = - GPOS_NEW(m_mp) CDXLPhysicalWindow(m_mp, colids, pdrgpdxlwk); + GPOS_NEW(m_mp) CDXLPhysicalWindow(m_mp, colids, pdrgpdxlwk, + fWindowHashAgg); CDXLNode *pdxlnWindow = GPOS_NEW(m_mp) CDXLNode(m_mp, pdxlopWindow); pdxlnWindow->SetProperties(dxl_properties); @@ -6958,7 +6961,6 @@ CTranslatorExprToDXL::PdxlnWindow(CExpression *pexprSeqPrj, return pdxlnWindow; } - //--------------------------------------------------------------------------- // @function: // CTranslatorExprToDXL::PdxlnArray diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformFactory.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformFactory.cpp index 27267cc39c8..f54aa957ebc 100644 --- a/src/backend/gporca/libgpopt/src/xforms/CXformFactory.cpp +++ b/src/backend/gporca/libgpopt/src/xforms/CXformFactory.cpp @@ -248,6 +248,7 @@ CXformFactory::Instantiate() Add(GPOS_NEW(m_mp) CXformSplitDQA(m_mp)); Add(GPOS_NEW(m_mp) CXformSequenceProject2Apply(m_mp)); Add(GPOS_NEW(m_mp) CXformImplementSequenceProject(m_mp)); + Add(GPOS_NEW(m_mp) CXformImplementHashSequenceProject(m_mp)); Add(GPOS_NEW(m_mp) CXformImplementAssert(m_mp)); Add(GPOS_NEW(m_mp) CXformCTEAnchor2Sequence(m_mp)); Add(GPOS_NEW(m_mp) CXformCTEAnchor2TrivialSelect(m_mp)); diff --git a/src/backend/gporca/libgpopt/src/xforms/CXformImplementHashSequenceProject.cpp b/src/backend/gporca/libgpopt/src/xforms/CXformImplementHashSequenceProject.cpp new file mode 100644 index 00000000000..e01f95377fb --- /dev/null +++ b/src/backend/gporca/libgpopt/src/xforms/CXformImplementHashSequenceProject.cpp @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * CXformImplementHashSequenceProject.cpp + * + * IDENTIFICATION + * src/backend/gporca/libgpopt/src/xforms/CXformImplementHashSequenceProject.cpp + * + *------------------------------------------------------------------------- + */ + +#include "gpopt/xforms/CXformImplementHashSequenceProject.h" + +#include "gpos/base.h" + +#include "gpopt/operators/CLogicalSequenceProject.h" +#include "gpopt/operators/CPatternLeaf.h" +#include "gpopt/operators/CPhysicalHashSequenceProject.h" + + +using namespace gpopt; + + +//--------------------------------------------------------------------------- +// @function: +// CXformImplementHashSequenceProject::CXformImplementHashSequenceProject +// +// @doc: +// Ctor +// +//--------------------------------------------------------------------------- +CXformImplementHashSequenceProject::CXformImplementHashSequenceProject( + CMemoryPool *mp) + : // pattern + CXformImplementation(GPOS_NEW(mp) CExpression( + mp, GPOS_NEW(mp) CLogicalSequenceProject(mp), + GPOS_NEW(mp) CExpression( + mp, GPOS_NEW(mp) CPatternLeaf(mp)), // relational child + GPOS_NEW(mp) + CExpression(mp, GPOS_NEW(mp) CPatternLeaf(mp)) // scalar child + )) +{ +} + + +//--------------------------------------------------------------------------- +// @function: +// CXformImplementHashSequenceProject::Transform +// +// @doc: +// Actual transformation +// +//--------------------------------------------------------------------------- +void +CXformImplementHashSequenceProject::Transform(CXformContext *pxfctxt, + CXformResult *pxfres, + CExpression *pexpr) const +{ + GPOS_ASSERT(nullptr != pxfctxt); + GPOS_ASSERT(FPromising(pxfctxt->Pmp(), this, pexpr)); + GPOS_ASSERT(FCheckPattern(pexpr)); + + CMemoryPool *mp = pxfctxt->Pmp(); + + // extract components + CExpression *pexprRelational = (*pexpr)[0]; + CExpression *pexprScalar = (*pexpr)[1]; + + // addref all children + pexprRelational->AddRef(); + pexprScalar->AddRef(); + + // extract members of logical sequence project operator + CLogicalSequenceProject *popLogicalSequenceProject = + CLogicalSequenceProject::PopConvert(pexpr->Pop()); + COperator::ESPType sptype = popLogicalSequenceProject->Pspt(); + CDistributionSpec *pds = popLogicalSequenceProject->Pds(); + COrderSpecArray *pdrgpos = popLogicalSequenceProject->Pdrgpos(); + CWindowFrameArray *pdrgpwf = popLogicalSequenceProject->Pdrgpwf(); + pds->AddRef(); + pdrgpos->AddRef(); + pdrgpwf->AddRef(); + + // assemble physical operator + CExpression *pexprSequenceProject = GPOS_NEW(mp) CExpression( + mp, + GPOS_NEW(mp) + CPhysicalHashSequenceProject(mp, sptype, pds, pdrgpos, pdrgpwf), + pexprRelational, pexprScalar); + + // add alternative to results + pxfres->Add(pexprSequenceProject); +} + + +// EOF diff --git a/src/backend/gporca/libgpopt/src/xforms/Makefile b/src/backend/gporca/libgpopt/src/xforms/Makefile index 4283daedb4c..a51ddd6f564 100644 --- a/src/backend/gporca/libgpopt/src/xforms/Makefile +++ b/src/backend/gporca/libgpopt/src/xforms/Makefile @@ -58,6 +58,7 @@ OBJS = CDecorrelator.o \ CXformImplementLimit.o \ CXformImplementSequence.o \ CXformImplementSequenceProject.o \ + CXformImplementHashSequenceProject.o \ CXformImplementSplit.o \ CXformImplementTVF.o \ CXformImplementTVFNoArgs.o \ diff --git a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalWindow.h b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalWindow.h index 4df4c3bc27a..a1d304af502 100644 --- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalWindow.h +++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/operators/CDXLPhysicalWindow.h @@ -46,12 +46,14 @@ class CDXLPhysicalWindow : public CDXLPhysical // window keys CDXLWindowKeyArray *m_dxl_window_key_array; + BOOL m_window_hash_agg; + public: CDXLPhysicalWindow(CDXLPhysicalWindow &) = delete; //ctor CDXLPhysicalWindow(CMemoryPool *mp, ULongPtrArray *part_by_colid_array, - CDXLWindowKeyArray *window_key_array); + CDXLWindowKeyArray *window_key_array, BOOL fWindowHashAgg); //dtor ~CDXLPhysicalWindow() override; @@ -76,6 +78,9 @@ class CDXLPhysicalWindow : public CDXLPhysical // return the window key at a given position CDXLWindowKey *GetDXLWindowKeyAt(ULONG ulPos) const; + // is windowagg implements by window hash agg + BOOL IsWindowHashAgg() const; + // serialize operator in DXL format void SerializeToDXL(CXMLSerializer *xml_serializer, const CDXLNode *dxlnode) const override; 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 f4daec1305f..a03f4bb92dd 100644 --- a/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h +++ b/src/backend/gporca/libnaucrates/include/naucrates/dxl/xml/dxltokens.h @@ -237,6 +237,7 @@ enum Edxltoken EdxltokenScalarWindowFrameTrailingEdge, EdxltokenWindowKeyList, EdxltokenWindowKey, + EdxltokenWindowHashAgg, EdxltokenWindowSpecList, EdxltokenWindowSpec, diff --git a/src/backend/gporca/libnaucrates/include/naucrates/traceflags/traceflags.h b/src/backend/gporca/libnaucrates/include/naucrates/traceflags/traceflags.h index 2e0995fcd66..f433b28d062 100644 --- a/src/backend/gporca/libnaucrates/include/naucrates/traceflags/traceflags.h +++ b/src/backend/gporca/libnaucrates/include/naucrates/traceflags/traceflags.h @@ -238,6 +238,9 @@ enum EOptTraceFlag // Disable dynamic seq/bitmap/index scan EopttraceDisableDynamicTableScan = 103049, + // Enable window hash agg + EopttraceEnableWindowHashAgg = 103050, + /////////////////////////////////////////////////////// ///////////////////// statistics flags //////////////// ////////////////////////////////////////////////////// diff --git a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalWindow.cpp b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalWindow.cpp index 9c5e7ca4e9b..19112cf23ca 100644 --- a/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalWindow.cpp +++ b/src/backend/gporca/libnaucrates/src/operators/CDXLPhysicalWindow.cpp @@ -28,10 +28,12 @@ using namespace gpdxl; //--------------------------------------------------------------------------- CDXLPhysicalWindow::CDXLPhysicalWindow(CMemoryPool *mp, ULongPtrArray *part_by_colid_array, - CDXLWindowKeyArray *window_key_array) + CDXLWindowKeyArray *window_key_array, + BOOL fWindowHashAgg) : CDXLPhysical(mp), m_part_by_colid_array(part_by_colid_array), - m_dxl_window_key_array(window_key_array) + m_dxl_window_key_array(window_key_array), + m_window_hash_agg(fWindowHashAgg) { GPOS_ASSERT(nullptr != m_part_by_colid_array); GPOS_ASSERT(nullptr != m_dxl_window_key_array); @@ -122,6 +124,18 @@ CDXLPhysicalWindow::GetDXLWindowKeyAt(ULONG position) const return (*m_dxl_window_key_array)[position]; } +//--------------------------------------------------------------------------- +// @function: +// CDXLPhysicalWindow::IsWindowHashAgg +// +// @doc: +// Is windowagg implements by window hash agg +// +//--------------------------------------------------------------------------- +BOOL CDXLPhysicalWindow::IsWindowHashAgg() const { + return m_window_hash_agg; +} + //--------------------------------------------------------------------------- // @function: // CDXLPhysicalWindow::SerializeToDXL @@ -168,6 +182,8 @@ CDXLPhysicalWindow::SerializeToDXL(CXMLSerializer *xml_serializer, CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix), window_keys_list_str); + xml_serializer->AddAttribute( + CDXLTokens::GetDXLTokenStr(EdxltokenWindowHashAgg), m_window_hash_agg); xml_serializer->CloseElement( CDXLTokens::GetDXLTokenStr(EdxltokenNamespacePrefix), element_name); } diff --git a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalWindow.cpp b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalWindow.cpp index 50704f05d39..28801cbf271 100644 --- a/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalWindow.cpp +++ b/src/backend/gporca/libnaucrates/src/parser/CParseHandlerPhysicalWindow.cpp @@ -155,7 +155,7 @@ CParseHandlerPhysicalWindow::EndElement(const XMLCh *const, // element_uri, CDXLWindowKeyArray *window_key_array_dxlnode = window_key_list_parse_handler->GetDxlWindowKeyArray(); CDXLPhysicalWindow *window_op_dxlnode = GPOS_NEW(m_mp) CDXLPhysicalWindow( - m_mp, m_part_by_colid_array, window_key_array_dxlnode); + m_mp, m_part_by_colid_array, window_key_array_dxlnode, false); m_dxl_node = GPOS_NEW(m_mp) CDXLNode(m_mp, window_op_dxlnode); // 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 4ddfaf6fbed..2d56b2fce23 100644 --- a/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp +++ b/src/backend/gporca/libnaucrates/src/xml/dxltokens.cpp @@ -343,6 +343,7 @@ CDXLTokens::Init(CMemoryPool *mp) {EdxltokenWindowFrame, GPOS_WSZ_LIT("WindowFrame")}, {EdxltokenWindowKeyList, GPOS_WSZ_LIT("WindowKeyList")}, {EdxltokenWindowKey, GPOS_WSZ_LIT("WindowKey")}, + {EdxltokenWindowHashAgg, GPOS_WSZ_LIT("IsWindowHashAgg")}, {EdxltokenWindowSpecList, GPOS_WSZ_LIT("WindowSpecList")}, {EdxltokenWindowSpec, GPOS_WSZ_LIT("WindowSpec")}, diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 18ffeb3f784..e9c44880cb4 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -1473,6 +1473,43 @@ _copyWindowAgg(const WindowAgg *from) return newnode; } +/* + * _copyWindowHashAgg + */ +static WindowHashAgg * +_copyWindowHashAgg(const WindowHashAgg *from) +{ + WindowHashAgg *newnode = makeNode(WindowHashAgg); + + CopyPlanFields((const Plan *) from, (Plan *) newnode); + + COPY_SCALAR_FIELD(winref); + COPY_SCALAR_FIELD(partNumCols); + COPY_POINTER_FIELD(partColIdx, from->partNumCols * sizeof(AttrNumber)); + COPY_POINTER_FIELD(partOperators, from->partNumCols * sizeof(Oid)); + COPY_POINTER_FIELD(partCollations, from->partNumCols * sizeof(Oid)); + COPY_SCALAR_FIELD(ordNumCols); + + if (from->ordNumCols > 0) + { + COPY_POINTER_FIELD(ordColIdx, from->ordNumCols * sizeof(AttrNumber)); + COPY_POINTER_FIELD(ordOperators, from->ordNumCols * sizeof(Oid)); + COPY_POINTER_FIELD(ordCollations, from->ordNumCols * sizeof(Oid)); + COPY_POINTER_FIELD(ordNullsFirst, from->ordNumCols * sizeof(bool)); + } + + COPY_SCALAR_FIELD(frameOptions); + COPY_NODE_FIELD(startOffset); + COPY_NODE_FIELD(endOffset); + COPY_SCALAR_FIELD(startInRangeFunc); + COPY_SCALAR_FIELD(endInRangeFunc); + COPY_SCALAR_FIELD(inRangeColl); + COPY_SCALAR_FIELD(inRangeAsc); + COPY_SCALAR_FIELD(inRangeNullsFirst); + + return newnode; +} + /* * _copyUnique */ @@ -6562,6 +6599,9 @@ copyObjectImpl(const void *from) case T_WindowAgg: retval = _copyWindowAgg(from); break; + case T_WindowHashAgg: + retval = _copyWindowHashAgg(from); + break; case T_TableFunctionScan: retval = _copyTableFunctionScan(from); break; diff --git a/src/backend/nodes/outfast.c b/src/backend/nodes/outfast.c index 054fc06238a..cfc6a322c0d 100644 --- a/src/backend/nodes/outfast.c +++ b/src/backend/nodes/outfast.c @@ -1030,6 +1030,9 @@ _outNode(StringInfo str, void *obj) case T_WindowAgg: _outWindowAgg(str, obj); break; + case T_WindowHashAgg: + _outWindowHashAgg(str, obj); + break; case T_Group: _outGroup(str, obj); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 38f34f40b62..6b21ff93654 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1013,6 +1013,33 @@ _outWindowAgg(StringInfo str, const WindowAgg *node) WRITE_BOOL_FIELD(inRangeNullsFirst); } +static void +_outWindowHashAgg(StringInfo str, const WindowHashAgg *node) +{ + WRITE_NODE_TYPE("WINDOWHASHAGG"); + + _outPlanInfo(str, (const Plan *) node); + + WRITE_UINT_FIELD(winref); + WRITE_INT_FIELD(partNumCols); + WRITE_ATTRNUMBER_ARRAY(partColIdx, node->partNumCols); + WRITE_OID_ARRAY(partOperators, node->partNumCols); + WRITE_OID_ARRAY(partCollations, node->partNumCols); + WRITE_INT_FIELD(ordNumCols); + WRITE_ATTRNUMBER_ARRAY(ordColIdx, node->ordNumCols); + WRITE_OID_ARRAY(ordOperators, node->ordNumCols); + WRITE_OID_ARRAY(ordCollations, node->ordNumCols); + WRITE_BOOL_ARRAY(ordNullsFirst, node->ordNumCols); + WRITE_INT_FIELD(frameOptions); + WRITE_NODE_FIELD(startOffset); + WRITE_NODE_FIELD(endOffset); + WRITE_OID_FIELD(startInRangeFunc); + WRITE_OID_FIELD(endInRangeFunc); + WRITE_OID_FIELD(inRangeColl); + WRITE_BOOL_FIELD(inRangeAsc); + WRITE_BOOL_FIELD(inRangeNullsFirst); +} + static void _outGroup(StringInfo str, const Group *node) { @@ -4347,6 +4374,9 @@ outNode(StringInfo str, const void *obj) case T_WindowAgg: _outWindowAgg(str, obj); break; + case T_WindowHashAgg: + _outWindowHashAgg(str, obj); + break; case T_Group: _outGroup(str, obj); break; diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index c5223413071..3d0bd4b1533 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -564,6 +564,8 @@ plannode_type(Plan *p) return "TupleSplit"; case T_WindowAgg: return "WINDOWAGG"; + case T_WindowHashAgg: + return "WINDOWHASHAGG"; case T_TableFunctionScan: return "TABLEFUNCTIONSCAN"; case T_Unique: diff --git a/src/backend/nodes/readfast.c b/src/backend/nodes/readfast.c index 887f9eae433..0cf853e5847 100644 --- a/src/backend/nodes/readfast.c +++ b/src/backend/nodes/readfast.c @@ -2076,6 +2076,9 @@ readNodeBinary(void) case T_WindowAgg: return_value = _readWindowAgg(); break; + case T_WindowHashAgg: + return_value = _readWindowHashAgg(); + break; case T_TableFunctionScan: return_value = _readTableFunctionScan(); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 636e79d1cf4..cfe4c8d1d01 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -2534,6 +2534,35 @@ _readWindowAgg(void) READ_DONE(); } +static WindowHashAgg * +_readWindowHashAgg(void) +{ + READ_LOCALS(WindowHashAgg); + + ReadCommonPlan(&local_node->plan); + + READ_UINT_FIELD(winref); + READ_INT_FIELD(partNumCols); + READ_ATTRNUMBER_ARRAY(partColIdx, local_node->partNumCols); + READ_OID_ARRAY(partOperators, local_node->partNumCols); + READ_OID_ARRAY(partCollations, local_node->partNumCols); + READ_INT_FIELD(ordNumCols); + READ_ATTRNUMBER_ARRAY(ordColIdx, local_node->ordNumCols); + READ_OID_ARRAY(ordOperators, local_node->ordNumCols); + READ_OID_ARRAY(ordCollations, local_node->ordNumCols); + READ_BOOL_ARRAY(ordNullsFirst, local_node->ordNumCols); + READ_INT_FIELD(frameOptions); + READ_NODE_FIELD(startOffset); + READ_NODE_FIELD(endOffset); + READ_OID_FIELD(startInRangeFunc); + READ_OID_FIELD(endInRangeFunc); + READ_OID_FIELD(inRangeColl); + READ_BOOL_FIELD(inRangeAsc); + READ_BOOL_FIELD(inRangeNullsFirst); + + READ_DONE(); +} + /* * _readUnique */ @@ -3165,6 +3194,8 @@ parseNodeString(void) return_value = _readDQAExpr(); else if (MATCH("WINDOWAGG", 9)) return_value = _readWindowAgg(); + else if (MATCH("WINDOWHASHAGG", 13)) + return_value = _readWindowHashAgg(); else if (MATCH("UNIQUE", 6)) return_value = _readUnique(); else if (MATCH("GATHER", 6)) diff --git a/src/backend/optimizer/plan/orca.c b/src/backend/optimizer/plan/orca.c index 0d706129d58..dc6a88e73c6 100644 --- a/src/backend/optimizer/plan/orca.c +++ b/src/backend/optimizer/plan/orca.c @@ -41,7 +41,7 @@ #include "utils/lsyscache.h" /* GPORCA entry point */ -extern PlannedStmt * GPOPTOptimizedPlan(Query *parse, bool *had_unexpected_failure); +extern PlannedStmt * GPOPTOptimizedPlan(Query *parse, bool *had_unexpected_failure, OptimizerOptions *opts); static Plan *remove_redundant_results(PlannerInfo *root, Plan *plan); static Node *remove_redundant_results_mutator(Node *node, void *); @@ -89,7 +89,7 @@ log_optimizer(PlannedStmt *plan, bool fUnexpectedFailure) * This is the main entrypoint for invoking Orca. */ PlannedStmt * -optimize_query(Query *parse, int cursorOptions, ParamListInfo boundParams) +optimize_query(Query *parse, int cursorOptions, ParamListInfo boundParams, OptimizerOptions *options) { /* flag to check if optimizer unexpectedly failed to produce a plan */ bool fUnexpectedFailure = false; @@ -153,7 +153,7 @@ optimize_query(Query *parse, int cursorOptions, ParamListInfo boundParams) pqueryCopy = (Query *) transformGroupedWindows((Node *) pqueryCopy, NULL); /* Ok, invoke ORCA. */ - result = GPOPTOptimizedPlan(pqueryCopy, &fUnexpectedFailure); + result = GPOPTOptimizedPlan(pqueryCopy, &fUnexpectedFailure, options); log_optimizer(result, fUnexpectedFailure); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 22ec8b43266..e4b25e97b33 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -328,13 +328,16 @@ planner(Query *parse, const char *query_string, int cursorOptions, { PlannedStmt *result; instr_time starttime, endtime; + OptimizerOptions *optimizer_options; + optimizer_options = palloc(sizeof(OptimizerOptions)); + optimizer_options->create_vectorization_plan = false; if (planner_hook) { if (gp_log_optimization_time) INSTR_TIME_SET_CURRENT(starttime); - result = (*planner_hook) (parse, query_string, cursorOptions, boundParams); + result = (*planner_hook) (parse, query_string, cursorOptions, boundParams, optimizer_options); if (gp_log_optimization_time) { @@ -344,14 +347,14 @@ planner(Query *parse, const char *query_string, int cursorOptions, } } else - result = standard_planner(parse, query_string, cursorOptions, boundParams); - + result = standard_planner(parse, query_string, cursorOptions, boundParams, optimizer_options); + pfree(optimizer_options); return result; } PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, - ParamListInfo boundParams) + ParamListInfo boundParams, OptimizerOptions *optimizer_options) { PlannedStmt *result; PlannerGlobal *glob; @@ -404,7 +407,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions, INSTR_TIME_SET_CURRENT(starttime); #ifdef USE_ORCA - result = optimize_query(parse, cursorOptions, boundParams); + result = optimize_query(parse, cursorOptions, boundParams, optimizer_options); #else /* Make sure this branch is not taken in builds using --disable-orca. */ Assert(false); diff --git a/src/backend/optimizer/util/walkers.c b/src/backend/optimizer/util/walkers.c index 93834cb32f7..3b3d0311d06 100644 --- a/src/backend/optimizer/util/walkers.c +++ b/src/backend/optimizer/util/walkers.c @@ -403,6 +403,14 @@ plan_tree_walker(Node *node, if (walker(((WindowAgg *) node)->endOffset, context)) return true; break; + case T_WindowHashAgg: + if (walk_plan_node_fields((Plan *) node, walker, context)) + return true; + if (walker(((WindowHashAgg *) node)->startOffset, context)) + return true; + if (walker(((WindowHashAgg *) node)->endOffset, context)) + return true; + break; case T_Unique: if (walk_plan_node_fields((Plan *) node, walker, context)) diff --git a/src/backend/utils/misc/guc_gp.c b/src/backend/utils/misc/guc_gp.c index df83e03b766..02de621cb54 100644 --- a/src/backend/utils/misc/guc_gp.c +++ b/src/backend/utils/misc/guc_gp.c @@ -365,6 +365,7 @@ bool optimizer_enable_replicated_table; bool optimizer_enable_foreign_table; bool optimizer_enable_right_outer_join; bool optimizer_enable_query_parameter; +bool optimizer_force_window_hash_agg; /* Optimizer plan enumeration related GUCs */ bool optimizer_enumerate_plans; @@ -3288,6 +3289,17 @@ struct config_bool ConfigureNamesBool_gp[] = true, NULL, NULL, NULL }, + { + {"optimizer_force_window_hash_agg", PGC_USERSET, DEVELOPER_OPTIONS, + gettext_noop("Enable create window hash agg."), + NULL, + GUC_NOT_IN_SAMPLE + }, + &optimizer_force_window_hash_agg, // TODO: remove it before merge + false, + NULL, NULL, NULL + }, + { {"aqumv_allow_foreign_table", PGC_USERSET, DEVELOPER_OPTIONS, gettext_noop("allow answer query using materialized views which have foreign or external tables."), diff --git a/src/backend/utils/resource_manager/memquota.c b/src/backend/utils/resource_manager/memquota.c index f1e272e9f24..1cf5f805df9 100644 --- a/src/backend/utils/resource_manager/memquota.c +++ b/src/backend/utils/resource_manager/memquota.c @@ -247,6 +247,7 @@ IsMemoryIntensiveOperator(Node *node, PlannedStmt *stmt) case T_Hash: case T_BitmapIndexScan: case T_WindowAgg: + case T_WindowHashAgg: case T_TableFunctionScan: case T_FunctionScan: return true; diff --git a/src/include/gpopt/CGPOptimizer.h b/src/include/gpopt/CGPOptimizer.h index 243e42c6da1..4a191a8009a 100644 --- a/src/include/gpopt/CGPOptimizer.h +++ b/src/include/gpopt/CGPOptimizer.h @@ -18,6 +18,7 @@ extern "C" { #include "postgres.h" +#include "optimizer/orcaopt.h" #include "nodes/params.h" #include "nodes/parsenodes.h" #include "nodes/plannodes.h" @@ -30,7 +31,8 @@ class CGPOptimizer static PlannedStmt *GPOPTOptimizedPlan( Query *query, bool * - had_unexpected_failure // output : set to true if optimizer unexpectedly failed to produce plan + had_unexpected_failure, // output : set to true if optimizer unexpectedly failed to produce plan + OptimizerOptions *opts ); // serialize planned statement into DXL @@ -45,7 +47,8 @@ class CGPOptimizer extern "C" { extern PlannedStmt *GPOPTOptimizedPlan(Query *query, - bool *had_unexpected_failure); + bool *had_unexpected_failure, + OptimizerOptions *opts); extern char *SerializeDXLPlan(Query *query); extern void InitGPOPT(); extern void TerminateGPOPT(); diff --git a/src/include/gpopt/config/CConfigParamMapping.h b/src/include/gpopt/config/CConfigParamMapping.h index ec314640b9d..32d81825384 100644 --- a/src/include/gpopt/config/CConfigParamMapping.h +++ b/src/include/gpopt/config/CConfigParamMapping.h @@ -68,7 +68,7 @@ class CConfigParamMapping CConfigParamMapping(const CConfigParamMapping &) = delete; // pack enabled optimizer config params in a traceflag bitset - static CBitSet *PackConfigParamInBitset(CMemoryPool *mp, ULONG xform_id); + static CBitSet *PackConfigParamInBitset(CMemoryPool *mp, ULONG xform_id, BOOL create_vec_plan); }; } // namespace gpdxl diff --git a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h index b2cb6104fb2..625ed5cd0a3 100644 --- a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h +++ b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h @@ -291,12 +291,19 @@ class CTranslatorDXLToPlStmt ); // translate DXL window node into GPDB window node - Plan *TranslateDXLWindow( + Plan *TranslateDXLWindowAgg( const CDXLNode *motion_dxlnode, CDXLTranslateContext *output_context, CDXLTranslationContextArray * ctxt_translation_prev_siblings // translation contexts of previous siblings ); + // translate DXL window node into window hash agg node + Plan *TranslateDXLWindowHashAgg( + const CDXLNode *window_dxlnode, CDXLTranslateContext *output_context, + CDXLTranslationContextArray + *ctxt_translation_prev_siblings // translation contexts of previous siblings + ); + // translate DXL sort node into GPDB Sort plan node Plan *TranslateDXLSort( const CDXLNode *sort_dxlnode, CDXLTranslateContext *output_context, diff --git a/src/include/gpopt/utils/COptTasks.h b/src/include/gpopt/utils/COptTasks.h index 2de78c7667a..3fa5f91216c 100644 --- a/src/include/gpopt/utils/COptTasks.h +++ b/src/include/gpopt/utils/COptTasks.h @@ -15,6 +15,10 @@ #ifndef COptTasks_H #define COptTasks_H +extern "C" { +#include "optimizer/orcaopt.h" +} + #include "gpos/error/CException.h" #include "gpopt/base/CColRef.h" @@ -108,6 +112,9 @@ struct SOptContext // casting function static SOptContext *Cast(void *ptr); + // other options pass by OptimizerOptions + BOOL m_create_vec_plan; + }; // struct SOptContext class COptTasks @@ -160,7 +167,8 @@ class COptTasks // optimize Query->DXL->LExpr->Optimize->PExpr->DXL->PlannedStmt static PlannedStmt *GPOPTOptimizedPlan(Query *query, - SOptContext *gpopt_context); + SOptContext *gpopt_context, + OptimizerOptions *opts); // enable/disable a given xforms static bool SetXform(char *xform_str, bool should_disable); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 2ec47618998..30c0c09c6e4 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -103,6 +103,7 @@ typedef enum NodeTag T_Agg, T_TupleSplit, T_WindowAgg, + T_WindowHashAgg, T_Unique, T_Gather, T_GatherMerge, diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index d2b2d921fba..e4695fd56f2 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -1442,6 +1442,47 @@ typedef struct WindowAgg bool inRangeNullsFirst; /* nulls sort first for in_range tests? */ } WindowAgg; + +/* ---------------- + * window hash aggregate node + * + * A WindowHashAgg node implements window functions over zero or more + * ordering/framing specifications within a partition specification on + * appropriately UNORDERED input. + * + * CBDB does not create plans with `WindowHashAgg` for the row executor, + * but does for the vectorization executor. + * ---------------- + */ +typedef struct WindowHashAgg +{ + Plan plan; + Index winref; /* ID referenced by window functions */ + int partNumCols; /* number of columns in partition clause */ + AttrNumber *partColIdx; /* their indexes in the target list */ + Oid *partOperators; /* equality operators for partition columns */ + Oid *partCollations; /* collations for partition columns */ + /* + * Different with `WindowAgg`, WindowHashAgg may use the + * `order by` information. + */ + int ordNumCols; /* number of sort-key columns */ + AttrNumber *ordColIdx; /* their indexes in the target list */ + Oid *ordOperators; /* OIDs of operators to sort them by */ + Oid *ordCollations; /* OIDs of collations */ + bool *ordNullsFirst; /* NULLS FIRST/LAST directions */ + + int frameOptions; /* frame_clause options, see WindowDef */ + Node *startOffset; /* expression for starting bound, if any */ + Node *endOffset; /* expression for ending bound, if any */ + /* these fields are used with RANGE offset PRECEDING/FOLLOWING: */ + Oid startInRangeFunc; /* in_range function for startOffset */ + Oid endInRangeFunc; /* in_range function for endOffset */ + Oid inRangeColl; /* collation for in_range tests */ + bool inRangeAsc; /* use ASC sort order for in_range tests? */ + bool inRangeNullsFirst; /* nulls sort first for in_range tests? */ +} WindowHashAgg; + /* ---------------- * unique node * ---------------- diff --git a/src/include/optimizer/orca.h b/src/include/optimizer/orca.h index d26903fc085..a32af3f56fd 100644 --- a/src/include/optimizer/orca.h +++ b/src/include/optimizer/orca.h @@ -18,10 +18,11 @@ #define ORCA_H #include "pg_config.h" +#include "optimizer/orcaopt.h" #ifdef USE_ORCA -extern PlannedStmt * optimize_query(Query *parse, int cursorOptions, ParamListInfo boundParams); +extern PlannedStmt * optimize_query(Query *parse, int cursorOptions, ParamListInfo boundParams, OptimizerOptions *options); extern Node *transformGroupedWindows(Node *node, void *context); // plan_hint_hook generates HintState by parsing a Query. diff --git a/src/include/optimizer/orcaopt.h b/src/include/optimizer/orcaopt.h new file mode 100644 index 00000000000..2bb5395875c --- /dev/null +++ b/src/include/optimizer/orcaopt.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * orcaopt.h + * + * IDENTIFICATION + * src/include/optimizer/orcaopt.h + * + *------------------------------------------------------------------------- + */ +#ifndef ORCA_OPT_H +#define ORCA_OPT_H + +#include "pg_config.h" + +#ifdef USE_ORCA + +typedef struct OptimizerOptions +{ + bool create_vectorization_plan; +} OptimizerOptions; + +#endif + +#endif /* ORCA_H */ diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index 29aac021f38..610034b2c62 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -21,13 +21,14 @@ #include "nodes/pathnodes.h" #include "nodes/plannerconfig.h" #include "nodes/plannodes.h" - +#include "optimizer/orcaopt.h" /* Hook for plugins to get control in planner() */ typedef PlannedStmt *(*planner_hook_type) (Query *parse, const char *query_string, int cursorOptions, - ParamListInfo boundParams); + ParamListInfo boundParams, + OptimizerOptions *optimizer_options); extern PGDLLIMPORT planner_hook_type planner_hook; /* Hook for plugins to get control when grouping_planner() plans upper rels */ @@ -41,7 +42,8 @@ extern PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook; extern PlannedStmt *standard_planner(Query *parse, const char *query_string, int cursorOptions, - ParamListInfo boundParams); + ParamListInfo boundParams, + OptimizerOptions *optimizer_options); extern PlannerInfo *subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index de0f931c797..40838ba969d 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -546,6 +546,7 @@ extern bool optimizer_enable_replicated_table; extern bool optimizer_enable_foreign_table; extern bool optimizer_enable_right_outer_join; extern bool optimizer_enable_query_parameter; +extern bool optimizer_force_window_hash_agg; /* Optimizer plan enumeration related GUCs */ extern bool optimizer_enumerate_plans; diff --git a/src/include/utils/unsync_guc_name.h b/src/include/utils/unsync_guc_name.h index a2a325bd9ed..b3a19ca7b9f 100644 --- a/src/include/utils/unsync_guc_name.h +++ b/src/include/utils/unsync_guc_name.h @@ -440,6 +440,7 @@ "optimizer_enable_foreign_table", "optimizer_enable_right_outer_join", "optimizer_enable_query_parameter", + "optimizer_force_window_hash_agg", "optimizer_enforce_subplans", "optimizer_enumerate_plans", "optimizer_expand_fulljoin", diff --git a/src/test/modules/delay_execution/delay_execution.c b/src/test/modules/delay_execution/delay_execution.c index b3d0841ba80..03925c74880 100644 --- a/src/test/modules/delay_execution/delay_execution.c +++ b/src/test/modules/delay_execution/delay_execution.c @@ -44,17 +44,17 @@ void _PG_fini(void); /* planner_hook function to provide the desired delay */ static PlannedStmt * delay_execution_planner(Query *parse, const char *query_string, - int cursorOptions, ParamListInfo boundParams) + int cursorOptions, ParamListInfo boundParams, OptimizerOptions *optimizer_options) { PlannedStmt *result; /* Invoke the planner, possibly via a previous hook user */ if (prev_planner_hook) result = prev_planner_hook(parse, query_string, cursorOptions, - boundParams); + boundParams, optimizer_options); else result = standard_planner(parse, query_string, cursorOptions, - boundParams); + boundParams, optimizer_options); /* If enabled, delay by taking and releasing the specified lock */ if (post_planning_lock_id != 0) diff --git a/src/test/regress/hooktest/hook_test.c b/src/test/regress/hooktest/hook_test.c index bf0e6d5f5f0..d06d0fe1c44 100644 --- a/src/test/regress/hooktest/hook_test.c +++ b/src/test/regress/hooktest/hook_test.c @@ -15,7 +15,7 @@ PG_MODULE_MAGIC; static planner_hook_type prev_planner_hook = NULL; -static PlannedStmt *test_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams); +static PlannedStmt *test_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams, OptimizerOptions *optimizer_options); void _PG_init(void); void _PG_fini(void); @@ -34,16 +34,16 @@ _PG_fini(void) } static PlannedStmt * -test_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams) +test_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams, OptimizerOptions *optimizer_options) { PlannedStmt *stmt; elog(LOG, "In test_planner_hook"); if (prev_planner_hook) - stmt = (*prev_planner_hook) (parse, query_string, cursorOptions, boundParams); + stmt = (*prev_planner_hook) (parse, query_string, cursorOptions, boundParams, optimizer_options); else - stmt = standard_planner(parse, query_string, cursorOptions, boundParams); + stmt = standard_planner(parse, query_string, cursorOptions, boundParams, optimizer_options); return stmt; } diff --git a/src/test/unit/mock/gpopt_mock.c b/src/test/unit/mock/gpopt_mock.c index 39bf2c49e82..ae16a4cab75 100644 --- a/src/test/unit/mock/gpopt_mock.c +++ b/src/test/unit/mock/gpopt_mock.c @@ -3,6 +3,7 @@ #include "lib/stringinfo.h" #include "nodes/parsenodes.h" #include "nodes/plannodes.h" +#include "optimizer/orcaopt.h" char * SerializeDXLPlan(Query *pquery) @@ -12,7 +13,7 @@ SerializeDXLPlan(Query *pquery) } PlannedStmt * -GPOPTOptimizedPlan(Query *pquery, bool pfUnexpectedFailure) +GPOPTOptimizedPlan(Query *pquery, bool pfUnexpectedFailure, OptimizerOptions *opts) { elog(ERROR, "mock implementation of GPOPTOptimizedPlan called"); return NULL;