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
The following commit(s) were added to refs/heads/main by this push:
new 17a6d1c5a57 Fix: wrong aggno and aggtransno generated in ORCA
17a6d1c5a57 is described below
commit 17a6d1c5a572dacdafb376fb8abc42410bdb7423
Author: zhoujiaqi <[email protected]>
AuthorDate: Wed Jun 18 16:56:18 2025 +0800
Fix: wrong aggno and aggtransno generated in ORCA
This issue caused `AggRef` in the `targetlist` no longer share
the same `aggno` and `aggtransno`, which means AggRef would be
calculated repeatedly.
ex.
```
select
sum(a) <- aggref1
from
any_table
having
sum(a) < 100; <- won't use the result of aggref1 to do the
filter.
```
This problem was introduced when cloudberry cherry-picked PG14.
But after cloudberry was open-sourced, the history of the changes
had been merged, and this problem only exists in ORCA.
In PG14, it no longer computes shared AggRef in `ExecInitAgg`,
but moved the logic into the planner. However in ORCA, it only
uses `idx++` to generate aggno and aggtransno. I do think that
is a workaround logic.
The current commit fixes this behavior by adopting the same
logic as the planner. But it's worth noting that, in multi-stage
agg, the final agg often gets an outer reference `Var` in AggRef,
so for the final agg, it still cannot get the same aggno (this
logic is consistent with greenplum; in the TPCDS testing, even i
generating the same aggno for final agg, it didn't bring performance
improvement). But if necessary, we could consider moving the logic
from `dxltoplstmt` to the pre-processor, which could also reduce
some output columns.
---
src/backend/commands/explain.c | 40 +++++
src/backend/gpopt/gpdbwrappers.cpp | 134 +++++++++++++++
.../gpopt/translate/CContextDXLToPlStmt.cpp | 45 ++++-
.../gpopt/translate/CTranslatorDXLToPlStmt.cpp | 189 ++++++++++++++++-----
src/backend/optimizer/prep/prepagg.c | 26 +--
src/backend/utils/misc/guc.c | 10 ++
src/include/gpopt/gpdbwrappers.h | 23 +++
src/include/gpopt/translate/CContextDXLToPlStmt.h | 17 ++
.../gpopt/translate/CTranslatorDXLToPlStmt.h | 3 +
src/include/optimizer/prep.h | 8 +
src/include/utils/guc.h | 1 +
src/include/utils/unsync_guc_name.h | 1 +
src/test/regress/expected/aggregates.out | 121 +++++++++++++
src/test/regress/expected/aggregates_optimizer.out | 121 +++++++++++++
src/test/regress/sql/aggregates.sql | 77 +++++++++
15 files changed, 757 insertions(+), 59 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index c89d088c4a2..e87fb30e7c4 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -134,6 +134,7 @@ static void show_tablesample(TableSampleClause *tsc,
PlanState *planstate,
List *ancestors,
ExplainState *es);
static void show_sort_info(SortState *sortstate, ExplainState *es);
static void show_windowagg_keys(WindowAggState *waggstate, List *ancestors,
ExplainState *es);
+static void show_aggref_info(List *targetList, const char *qlabel,
ExplainState *es);
static void show_incremental_sort_info(IncrementalSortState *incrsortstate,
ExplainState *es);
static void show_hash_info(HashState *hashstate, ExplainState *es);
@@ -2737,6 +2738,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
case T_Agg:
show_agg_keys(castNode(AggState, planstate), ancestors,
es);
show_upper_qual(plan->qual, "Filter", planstate,
ancestors, es);
+ show_aggref_info(plan->targetlist,
"AggRefs(TargetList)", es);
show_hashagg_info((AggState *) planstate, es);
if (plan->qual)
show_instrumentation_count("Rows Removed by
Filter", 1,
@@ -3168,6 +3170,44 @@ show_sort_keys(SortState *sortstate, List *ancestors,
ExplainState *es)
ancestors, es);
}
+static void
+show_aggref_info(List *targetList, const char *qlabel, ExplainState *es) {
+ StringInfoData buf;
+ ListCell *lc;
+ bool already_got_one = false;
+
+ if (!Debug_print_aggref_in_explain) {
+ return;
+ }
+
+ initStringInfo(&buf);
+ appendStringInfoString(&buf, "[");
+
+ foreach (lc, targetList)
+ {
+ if (!IsA(lfirst(lc),TargetEntry)) {
+ continue;
+ }
+
+ TargetEntry *te = (TargetEntry *) lfirst(lc);
+ if (!IsA(te->expr, Aggref))
+ {
+ continue;
+ }
+
+ Aggref *aggref = (Aggref *) te->expr;
+ if (already_got_one) {
+ appendStringInfo(&buf, ", (%d, %d)", aggref->aggno,
aggref->aggtransno);
+ } else {
+ appendStringInfo(&buf, "(%d, %d)", aggref->aggno,
aggref->aggtransno);
+ already_got_one = true;
+ }
+ }
+ appendStringInfoString(&buf, "]");
+
+ ExplainPropertyText(qlabel, buf.data, es);
+}
+
static void
show_windowagg_keys(WindowAggState *waggstate, List *ancestors, ExplainState
*es)
{
diff --git a/src/backend/gpopt/gpdbwrappers.cpp
b/src/backend/gpopt/gpdbwrappers.cpp
index 3eed0ed1e40..bbc686c3e37 100644
--- a/src/backend/gpopt/gpdbwrappers.cpp
+++ b/src/backend/gpopt/gpdbwrappers.cpp
@@ -36,12 +36,14 @@ extern "C" {
#include "access/amapi.h"
#include "access/external.h"
#include "access/genam.h"
+#include "catalog/pg_aggregate.h"
#include "catalog/pg_inherits.h"
#include "foreign/fdwapi.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "optimizer/plancat.h"
+#include "optimizer/prep.h"
#include "optimizer/subselect.h"
#include "parser/parse_agg.h"
#include "partitioning/partdesc.h"
@@ -490,6 +492,15 @@ gpdb::TypeCollation(Oid type)
return 0;
}
+void
+gpdb::TypLenByVal(Oid typid, int16 *typlen, bool *typbyval)
+{
+ GP_WRAP_START;
+ {
+ get_typlenbyval(typid, typlen, typbyval);
+ }
+ GP_WRAP_END;
+}
List *
gpdb::ExtractNodesPlan(Plan *pl, int node_tag, bool descend_into_subqueries)
@@ -661,6 +672,129 @@ gpdb::ResolveAggregateTransType(Oid aggfnoid, Oid
aggtranstype, Oid *inputTypes,
return 0;
}
+static Datum
+GetAggInitVal(Datum textInitVal, Oid transtype)
+{
+ Oid typinput,
+ typioparam;
+ char *strInitVal;
+ Datum initVal;
+
+ getTypeInputInfo(transtype, &typinput, &typioparam);
+ strInitVal = TextDatumGetCString(textInitVal);
+ initVal = OidInputFunctionCall(typinput, strInitVal,
+ typioparam,
-1);
+ pfree(strInitVal);
+ return initVal;
+}
+
+void
+gpdb::GetAggregateInfo(Aggref *aggref, Oid *aggtransfn,
+ Oid *aggfinalfn, Oid *aggcombinefn,
+ Oid *aggserialfn, Oid *aggdeserialfn,
+ Oid *aggtranstype, int
*aggtransspace,
+ Datum *initValue, bool
*initValueIsNull,
+ bool *shareable)
+{
+ GP_WRAP_START;
+ {
+ HeapTuple aggTuple;
+ Form_pg_aggregate aggform;
+ Datum textInitVal;
+ Oid inputTypes[FUNC_MAX_ARGS];
+ int numArguments;
+
+ aggTuple = SearchSysCache1(AGGFNOID,
+
ObjectIdGetDatum(aggref->aggfnoid));
+ if (!HeapTupleIsValid(aggTuple))
+ elog(ERROR, "cache lookup failed for aggregate %u",
+ aggref->aggfnoid);
+
+ aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
+ *aggtransfn = aggform->aggtransfn;
+ *aggfinalfn = aggform->aggfinalfn;
+ *aggcombinefn = aggform->aggcombinefn;
+ *aggserialfn = aggform->aggserialfn;
+ *aggdeserialfn = aggform->aggdeserialfn;
+ *aggtranstype = aggform->aggtranstype;
+ *aggtransspace = aggform->aggtransspace;
+
+ (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE);
+
+
+ /*
+ * Resolve the possibly-polymorphic aggregate transition type.
+ */
+ /* extract argument types (ignoring any ORDER BY expressions) */
+ numArguments = get_aggregate_argtypes(aggref, inputTypes);
+
+ /* resolve actual type of transition state, if polymorphic */
+ *aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid,
+
*aggtranstype,
+
inputTypes,
+
numArguments);
+
+ /* get initial value */
+ textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
+
Anum_pg_aggregate_agginitval,
+
initValueIsNull);
+
+
+ if (*initValueIsNull)
+ *initValue = (Datum) 0;
+ else
+ *initValue = GetAggInitVal(textInitVal, *aggtranstype);
+
+ /*
+ * If finalfn is marked read-write, we can't share transition
states; but
+ * it is okay to share states for AGGMODIFY_SHAREABLE aggs.
+ *
+ * In principle, in a partial aggregate, we could share the
transition
+ * state even if the final function is marked as read-write,
because the
+ * partial aggregate doesn't execute the final function. But
it's too
+ * early to know whether we're going perform a partial
aggregate.
+ */
+ *shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE);
+
+ ReleaseSysCache(aggTuple);
+
+ }
+ GP_WRAP_END;
+}
+
+
+int
+gpdb::FindCompatibleAgg(List *agginfos, Aggref *newagg,
+ List **same_input_transnos)
+{
+
+ GP_WRAP_START;
+ {
+ return find_compatible_agg(agginfos, newagg,
same_input_transnos);
+ }
+ GP_WRAP_END;
+ return -1;
+}
+
+int
+gpdb::FindCompatibleTrans(List *aggtransinfos, bool shareable,
+ Oid aggtransfn, Oid
aggtranstype,
+ int transtypeLen, bool
transtypeByVal,
+ Oid aggcombinefn, Oid
aggserialfn,
+ Oid aggdeserialfn, Datum
initValue,
+ bool initValueIsNull, List
*transnos)
+{
+ GP_WRAP_START;
+ {
+ return find_compatible_trans(aggtransinfos, shareable,
aggtransfn,
+ aggtranstype, transtypeLen, transtypeByVal,
aggcombinefn, aggserialfn,
+ aggdeserialfn, initValue, initValueIsNull, transnos);
+ }
+ GP_WRAP_END;
+ return -1;
+}
+
+
Query *
gpdb::FlattenJoinAliasVar(Query *query, gpos::ULONG query_level)
{
diff --git a/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
b/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
index 376810a27f1..44b84abd29c 100644
--- a/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CContextDXLToPlStmt.cpp
@@ -56,7 +56,9 @@ CContextDXLToPlStmt::CContextDXLToPlStmt(
m_slices_list(nullptr),
m_result_relation_index(0),
m_distribution_policy(nullptr),
- m_part_selector_to_param_map(nullptr)
+ m_part_selector_to_param_map(nullptr),
+ m_agg_infos(nullptr),
+ m_agg_trans_infos(nullptr)
{
m_cte_producer_info = GPOS_NEW(m_mp) HMUlCTEProducerInfo(m_mp);
m_part_selector_to_param_map = GPOS_NEW(m_mp) UlongToUlongMap(m_mp);
@@ -159,8 +161,9 @@ CContextDXLToPlStmt::GetParamTypes()
//
//---------------------------------------------------------------------------
void
-CContextDXLToPlStmt::RegisterCTEProducerInfo(ULONG cte_id,
- ULongPtrArray *producer_output_colidx_map, ShareInputScan *siscan)
+CContextDXLToPlStmt::RegisterCTEProducerInfo(
+ ULONG cte_id, ULongPtrArray *producer_output_colidx_map,
+ ShareInputScan *siscan)
{
ULONG *key = GPOS_NEW(m_mp) ULONG(cte_id);
BOOL result GPOS_ASSERTS_ONLY = m_cte_producer_info->Insert(
@@ -575,4 +578,40 @@ CContextDXLToPlStmt::GetRTEIndexByAssignedQueryId(
return gpdb::ListLength(m_rtable_entries_list) + 1;
}
+void
+CContextDXLToPlStmt::AppendAggInfos(AggInfo *agginfo)
+{
+ m_agg_infos = gpdb::LAppend(m_agg_infos, agginfo);
+}
+
+void
+CContextDXLToPlStmt::AppendAggTransInfos(AggTransInfo *transinfo)
+{
+ m_agg_trans_infos = gpdb::LAppend(m_agg_trans_infos, transinfo);
+}
+
+void
+CContextDXLToPlStmt::ResetAggInfosAndTransInfos()
+{
+ ListCell *lc;
+ foreach (lc, m_agg_infos)
+ {
+ AggInfo *agginfo = (AggInfo *) lfirst(lc);
+ gpdb::GPDBFree(agginfo);
+ }
+
+ gpdb::ListFree(m_agg_infos);
+
+ foreach (lc, m_agg_trans_infos)
+ {
+ AggTransInfo *aggtransinfo = (AggTransInfo *) lfirst(lc);
+ gpdb::GPDBFree(aggtransinfo);
+ }
+
+ gpdb::ListFree(m_agg_trans_infos);
+
+ m_agg_infos = nullptr;
+ m_agg_trans_infos = nullptr;
+}
+
// EOF
diff --git a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
index 3e94e8d77f0..8aa1984badd 100644
--- a/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
+++ b/src/backend/gpopt/translate/CTranslatorDXLToPlStmt.cpp
@@ -2765,6 +2765,124 @@
CTranslatorDXLToPlStmt::TranslateDXLRedistributeMotionToResultHashFilters(
return (Plan *) result;
}
+
+//---------------------------------------------------------------------------
+// @function:
+// CTranslatorDXLToPlStmt::TranslateAggFillInfo
+//
+// @doc:
+// Fill the aggregate node with aggno and aggtransno
+//
+//---------------------------------------------------------------------------
+void
+CTranslatorDXLToPlStmt::TranslateAggFillInfo(CContextDXLToPlStmt *ctx,
+
Aggref *aggref)
+{
+ Oid aggtransfn;
+ Oid aggfinalfn;
+ Oid aggcombinefn;
+ Oid aggserialfn;
+ Oid aggdeserialfn;
+ Oid aggtranstype;
+ int32 aggtranstypmod;
+ int32 aggtransspace;
+
+ Datum initValue;
+ bool initValueIsNull;
+ List *same_input_transnos;
+
+ bool shareable;
+ int16 resulttypeLen;
+ bool resulttypeByVal;
+ int16 transtypeLen;
+ bool transtypeByVal;
+
+ int aggno, transno;
+
+ gpdb::GetAggregateInfo(aggref, &aggtransfn, &aggfinalfn,
+ &aggcombinefn, &aggserialfn,
&aggdeserialfn,
+ &aggtranstype,
&aggtransspace, &initValue,
+ &initValueIsNull,
&shareable);
+
+ /*
+ * If transition state is of same type as first aggregated input, assume
+ * it's the same typmod (same width) as well. This works for cases like
+ * MAX/MIN and is probably somewhat reasonable otherwise.
+ */
+ aggtranstypmod = -1;
+ if (aggref->args)
+ {
+ TargetEntry *tle = (TargetEntry *) linitial(aggref->args);
+
+ if (aggtranstype == gpdb::ExprType((Node *) tle->expr))
+ aggtranstypmod = gpdb::ExprTypeMod((Node *) tle->expr);
+ }
+
+ gpdb::TypLenByVal(aggref->aggtype, &resulttypeLen, &resulttypeByVal);
+
+ /*
+ * 1. See if this is identical to another aggregate function call that
+ * we've seen already.
+ */
+ aggno = gpdb::FindCompatibleAgg(ctx->GetAggInfos(), aggref,
+
&same_input_transnos);
+ if (aggno != -1)
+ {
+ AggInfo *agginfo = (AggInfo *)
gpdb::ListNth(ctx->GetAggInfos(), aggno);
+
+ transno = agginfo->transno;
+ }
+ else
+ {
+ AggInfo *agginfo = (AggInfo *) gpdb::GPDBAlloc(sizeof(AggInfo));
+
+ agginfo->finalfn_oid = aggfinalfn;
+ agginfo->representative_aggref = aggref;
+ agginfo->shareable = shareable;
+
+ aggno = gpdb::ListLength(ctx->GetAggInfos());
+ ctx->AppendAggInfos(agginfo);
+
+ gpdb::TypLenByVal(aggtranstype, &transtypeLen, &transtypeByVal);
+
+ /*
+ * 2. See if this aggregate can share transition state with
another
+ * aggregate that we've initialized already.
+ */
+ transno = gpdb::FindCompatibleTrans(
+ ctx->GetAggTransInfos(), shareable, aggtransfn,
aggtranstype,
+ transtypeLen, transtypeByVal, aggcombinefn, aggserialfn,
+ aggdeserialfn, initValue, initValueIsNull,
same_input_transnos);
+ if (transno == -1)
+ {
+ AggTransInfo *transinfo =
+ (AggTransInfo *)
gpdb::GPDBAlloc(sizeof(AggTransInfo));
+
+ transinfo->args = aggref->args;
+ transinfo->aggfilter = aggref->aggfilter;
+ transinfo->transfn_oid = aggtransfn;
+ transinfo->combinefn_oid = aggcombinefn;
+ transinfo->serialfn_oid = aggserialfn;
+ transinfo->deserialfn_oid = aggdeserialfn;
+ transinfo->aggtranstype = aggtranstype;
+ transinfo->aggtranstypmod = aggtranstypmod;
+ transinfo->transtypeLen = transtypeLen;
+ transinfo->transtypeByVal = transtypeByVal;
+ transinfo->aggtransspace = aggtransspace;
+ transinfo->initValue = initValue;
+ transinfo->initValueIsNull = initValueIsNull;
+
+ transno = gpdb::ListLength(ctx->GetAggTransInfos());
+ ctx->AppendAggTransInfos(transinfo);
+ }
+ agginfo->transno = transno;
+ }
+
+ // setting the aggno and transno
+ aggref->aggno = aggno;
+ aggref->aggtransno = transno;
+}
+
//---------------------------------------------------------------------------
// @function:
// CTranslatorDXLToPlStmt::TranslateDXLAgg
@@ -2812,44 +2930,6 @@ CTranslatorDXLToPlStmt::TranslateDXLAgg(
child_contexts,
// pdxltrctxRight,
&plan->targetlist,
&plan->qual, output_context);
- /*
- * GPDB_14_MERGE_FIXME: TODO Deduplicate aggregates and transition
functions in orca
- */
- // Set the aggsplit for the agg node
- ListCell *lc;
- INT aggsplit = 0;
- int idx = 0;
- ForEach (lc, plan->targetlist)
- {
- TargetEntry *te = (TargetEntry *) lfirst(lc);
- if (IsA(te->expr, Aggref))
- {
- Aggref *aggref = (Aggref *) te->expr;
-
- if (AGGSPLIT_INTERMEDIATE != aggsplit)
- {
- aggsplit |= aggref->aggsplit;
- }
-
- aggref->aggno = idx;
- aggref->aggtransno = idx;
- idx++;
- }
- }
- agg->aggsplit = (AggSplit) aggsplit;
-
- ForEach (lc, plan->qual)
- {
- Expr *expr = (Expr *) lfirst(lc);
- if (IsA(expr, Aggref))
- {
- Aggref *aggref = (Aggref *) expr;
- aggref->aggno = idx;
- aggref->aggtransno = idx;
- idx++;
- }
- }
-
plan->lefttree = child_plan;
// translate aggregation strategy
@@ -2919,6 +2999,39 @@ CTranslatorDXLToPlStmt::TranslateDXLAgg(
agg->numGroups =
std::max(1L, (long) std::min(agg->plan.plan_rows, (double)
LONG_MAX));
+
+ // Set the aggsplit,aggno,aggtransno for the agg node
+ ListCell *lc;
+ INT aggsplit = 0;
+ ForEach (lc, plan->targetlist)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(lc);
+ if (IsA(te->expr, Aggref))
+ {
+ Aggref *aggref = (Aggref *) te->expr;
+
+ if (AGGSPLIT_INTERMEDIATE != aggsplit)
+ {
+ aggsplit |= aggref->aggsplit;
+ }
+ TranslateAggFillInfo(m_dxl_to_plstmt_context, aggref);
+ }
+ }
+ agg->aggsplit = (AggSplit) aggsplit;
+
+ ForEach (lc, plan->qual)
+ {
+ Expr *expr = (Expr *) lfirst(lc);
+ if (IsA(expr, Aggref))
+ {
+ Aggref *aggref = (Aggref *) expr;
+ // ORCA won't create the qual but a scalar in AGG
+ TranslateAggFillInfo(m_dxl_to_plstmt_context, aggref);
+ }
+ }
+
+ m_dxl_to_plstmt_context->ResetAggInfosAndTransInfos();
+
SetParamIds(plan);
// cleanup
diff --git a/src/backend/optimizer/prep/prepagg.c
b/src/backend/optimizer/prep/prepagg.c
index 5388b1c4934..b16e4adb220 100644
--- a/src/backend/optimizer/prep/prepagg.c
+++ b/src/backend/optimizer/prep/prepagg.c
@@ -53,16 +53,6 @@
#include "utils/syscache.h"
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root);
-static int find_compatible_agg(PlannerInfo *root, Aggref *newagg,
- List
**same_input_transnos);
-static int find_compatible_trans(PlannerInfo *root, Aggref *newagg,
- bool
shareable,
- Oid
aggtransfn, Oid aggtranstype,
- int
transtypeLen, bool transtypeByVal,
- Oid
aggcombinefn,
- Oid
aggserialfn, Oid aggdeserialfn,
- Datum
initValue, bool initValueIsNull,
- List
*transnos);
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
/* -----------------
@@ -220,7 +210,7 @@ preprocess_aggref(Aggref *aggref, PlannerInfo *root)
* 1. See if this is identical to another aggregate function call that
* we've seen already.
*/
- aggno = find_compatible_agg(root, aggref, &same_input_transnos);
+ aggno = find_compatible_agg(root->agginfos, aggref,
&same_input_transnos);
if (aggno != -1)
{
AggInfo *agginfo = list_nth(root->agginfos, aggno);
@@ -266,7 +256,7 @@ preprocess_aggref(Aggref *aggref, PlannerInfo *root)
* 2. See if this aggregate can share transition state with
another
* aggregate that we've initialized already.
*/
- transno = find_compatible_trans(root, aggref, shareable,
+ transno = find_compatible_trans(root->aggtransinfos, shareable,
aggtransfn, aggtranstype,
transtypeLen, transtypeByVal,
aggcombinefn,
@@ -367,8 +357,8 @@ preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
* passed later to find_compatible_trans, to see if we can at least reuse
* the state value of another aggregate.
*/
-static int
-find_compatible_agg(PlannerInfo *root, Aggref *newagg,
+int
+find_compatible_agg(List *agginfos, Aggref *newagg,
List **same_input_transnos)
{
ListCell *lc;
@@ -390,7 +380,7 @@ find_compatible_agg(PlannerInfo *root, Aggref *newagg,
* same transition function will be checked later.)
*/
aggno = -1;
- foreach(lc, root->agginfos)
+ foreach(lc, agginfos)
{
AggInfo *agginfo = (AggInfo *) lfirst(lc);
Aggref *existingRef;
@@ -445,8 +435,8 @@ find_compatible_agg(PlannerInfo *root, Aggref *newagg,
* transition function and initial condition. (The inputs have already been
* verified to match.)
*/
-static int
-find_compatible_trans(PlannerInfo *root, Aggref *newagg, bool shareable,
+int
+find_compatible_trans(List *aggtransinfos, bool shareable,
Oid aggtransfn, Oid aggtranstype,
int transtypeLen, bool transtypeByVal,
Oid aggcombinefn,
@@ -463,7 +453,7 @@ find_compatible_trans(PlannerInfo *root, Aggref *newagg,
bool shareable,
foreach(lc, transnos)
{
int transno = lfirst_int(lc);
- AggTransInfo *pertrans = (AggTransInfo *)
list_nth(root->aggtransinfos, transno);
+ AggTransInfo *pertrans = (AggTransInfo *)
list_nth(aggtransinfos, transno);
/*
* if the transfns or transition state types are not the same
then the
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 626eeb7aa70..fae7f8a0e5c 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -582,6 +582,7 @@ bool Debug_print_parse = false;
bool Debug_print_rewritten = false;
bool Debug_pretty_print = true;
bool Debug_print_ivm = false;
+bool Debug_print_aggref_in_explain = false;
bool log_parser_stats = false;
bool log_planner_stats = false;
@@ -1545,6 +1546,15 @@ static struct config_bool ConfigureNamesBool[] =
false,
NULL, NULL, NULL
},
+ {
+ {"debug_print_aggref_in_explain", PGC_USERSET, LOGGING_WHAT,
+ gettext_noop("Logs the aggnos/aggtransno in explain."),
+ NULL
+ },
+ &Debug_print_aggref_in_explain,
+ false,
+ NULL, NULL, NULL
+ },
{
{"log_parser_stats", PGC_SUSET, STATS_MONITORING,
gettext_noop("Writes parser performance statistics to
the server log."),
diff --git a/src/include/gpopt/gpdbwrappers.h b/src/include/gpopt/gpdbwrappers.h
index cb75b2d493c..39e294db8fa 100644
--- a/src/include/gpopt/gpdbwrappers.h
+++ b/src/include/gpopt/gpdbwrappers.h
@@ -166,6 +166,9 @@ Oid ExprCollation(Node *expr);
// expression collation - GPDB_91_MERGE_FIXME
Oid TypeCollation(Oid type);
+// Byval type get len
+void TypLenByVal(Oid typid, int16 *typlen, bool *typbyval);
+
// extract nodes with specific tag from a plan tree
List *ExtractNodesPlan(Plan *pl, int node_tag, bool descend_into_subqueries);
@@ -183,6 +186,26 @@ int GetAggregateArgTypes(Aggref *aggref, Oid *inputTypes);
Oid ResolveAggregateTransType(Oid aggfnoid, Oid aggtranstype, Oid *inputTypes,
int numArguments);
+// intermediate result of given aggregate
+void GetAggregateInfo(Aggref *aggref, Oid *aggtransfn,
+ Oid *aggfinalfn, Oid *aggcombinefn,
+ Oid *aggserialfn, Oid *aggdeserialfn,
+ Oid *aggtranstype, int *aggtransspace,
+ Datum *initValue, bool
*initValueIsNull,
+ bool *shareable);
+
+int
+FindCompatibleAgg(List *agginfos, Aggref *newagg,
+ List **same_input_transnos);
+int
+FindCompatibleTrans(List *aggtransinfos, bool shareable,
+ Oid aggtransfn, Oid aggtranstype,
+ int transtypeLen, bool transtypeByVal,
+ Oid aggcombinefn, Oid aggserialfn,
+ Oid aggdeserialfn, Datum initValue,
+ bool initValueIsNull, List *transnos);
+
+
// replace Vars that reference JOIN outputs with references to the original
// relation variables instead
Query *FlattenJoinAliasVar(Query *query, gpos::ULONG query_level);
diff --git a/src/include/gpopt/translate/CContextDXLToPlStmt.h
b/src/include/gpopt/translate/CContextDXLToPlStmt.h
index 29e9eb4401b..3a1be11d196 100644
--- a/src/include/gpopt/translate/CContextDXLToPlStmt.h
+++ b/src/include/gpopt/translate/CContextDXLToPlStmt.h
@@ -127,6 +127,9 @@ private:
// hash map of the queryid (of DML query) and the target relation index
HMUlIndex *m_used_rte_indexes;
+ // the aggno and aggtransno in agg
+ List *m_agg_infos; /* AggInfo structs */
+ List *m_agg_trans_infos; /* AggTransInfo structs */
public:
// ctor/dtor
CContextDXLToPlStmt(CMemoryPool *mp, CIdGenerator *plan_id_counter,
@@ -233,6 +236,20 @@ public:
Index GetRTEIndexByAssignedQueryId(ULONG
assigned_query_id_for_target_rel,
BOOL
*is_rte_exists);
+ // List of AggInfo and AggTransInfo
+ inline List *GetAggInfos() const
+ {
+ return m_agg_infos;
+ }
+
+ inline List *GetAggTransInfos() const
+ {
+ return m_agg_trans_infos;
+ }
+
+ void AppendAggInfos(AggInfo *agginfo);
+ void AppendAggTransInfos(AggTransInfo *transinfo);
+ void ResetAggInfosAndTransInfos();
};
} // namespace gpdxl
diff --git a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
index 0507dc05105..b2cb6104fb2 100644
--- a/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
+++ b/src/include/gpopt/translate/CTranslatorDXLToPlStmt.h
@@ -647,6 +647,9 @@ private:
CDXLTranslationContextArray *ctxt_translation_prev_siblings,
CDXLTranslateContext *output_context,
CDXLNode *index_cond_list_dxlnode);
+
+ // fill the aggno and transno for the aggnode
+ static void TranslateAggFillInfo(CContextDXLToPlStmt *context, Aggref
*aggref);
};
} // namespace gpdxl
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index ca57e87b367..6dcf03f9234 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -54,6 +54,14 @@ extern void compute_agg_clause_costs(PlannerInfo *root,
AggSplit aggsplit,
AggClauseCosts
*agg_costs);
extern void preprocess_aggrefs(PlannerInfo *root, Node *clause);
+extern int find_compatible_agg(List *agginfos, Aggref *newagg, List
**same_input_transnos);
+extern int find_compatible_trans(List *aggtransinfos, bool shareable,
+ Oid
aggtransfn, Oid aggtranstype,
+ int
transtypeLen, bool transtypeByVal,
+ Oid
aggcombinefn,
+ Oid
aggserialfn, Oid aggdeserialfn,
+ Datum
initValue, bool initValueIsNull,
+ List
*transnos);
/*
* prototypes for prepunion.c
*/
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 30a9b3d3122..7c46011c2f2 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -261,6 +261,7 @@ extern bool Debug_print_parse;
extern bool Debug_print_rewritten;
extern bool Debug_pretty_print;
extern bool Debug_print_ivm;
+extern bool Debug_print_aggref_in_explain;
extern bool Debug_print_full_dtm;
extern bool Debug_print_snapshot_dtm;
diff --git a/src/include/utils/unsync_guc_name.h
b/src/include/utils/unsync_guc_name.h
index 959d2a89a73..7fc09fb45f3 100644
--- a/src/include/utils/unsync_guc_name.h
+++ b/src/include/utils/unsync_guc_name.h
@@ -89,6 +89,7 @@
"debug_print_slice_table",
"debug_print_snapshot_dtm",
"debug_print_ivm",
+ "debug_print_aggref_in_explain",
"debug_resource_group",
"debug_walrepl_rcv",
"debug_walrepl_snd",
diff --git a/src/test/regress/expected/aggregates.out
b/src/test/regress/expected/aggregates.out
index fadb82728f1..f81478dabd4 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -3279,3 +3279,124 @@ explain analyze select count(*) from pg_class, (select
count(*) > 0 from (select
Execution Time: 0.302 ms
(10 rows)
+-- test aggno
+create table tgb1(v1 int, v2 int, v3 int);
+NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'v1'
as the Apache Cloudberry data distribution key for this table.
+HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make
sure column(s) chosen are the optimal data distribution key to minimize skew.
+create table tgb2(v1 int, v2 int, v3 int);
+NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'v1'
as the Apache Cloudberry data distribution key for this table.
+HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make
sure column(s) chosen are the optimal data distribution key to minimize skew.
+insert into tgb1
values(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3);
+insert into tgb2
values(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3);
+set debug_print_aggref_in_explain to on;
+explain select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1 (slice1; segments: 3) (cost=145986.91..145999.46 rows=4
width=12)
+ -> Finalize HashAggregate (cost=145986.91..145999.41 rows=1 width=12)
+ Group Key: tgb2.v2
+ Filter: ((sum((tgb1.v3 * tgb2.v3)) > 100) AND (sum((tgb1.v3 *
tgb2.v3)) > 101) AND (sum((tgb1.v3 * tgb2.v3)) < 1020) AND (sum((tgb1.v3 *
tgb2.v3)) <> 103) AND (sum((tgb1.v3 * tgb2.v3)) >= 104) AND (avg((tgb1.v3 *
tgb2.v3)) <> '11'::numeric) AND (avg((tgb1.v3 * tgb2.v3)) <> '12'::numeric) AND
(avg((tgb2.v1 * tgb1.v1)) <> '13'::numeric) AND (sum(tgb1.v3) > 200))
+ AggRefs(TargetList): [(0, 0)]
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
(cost=145944.41..145974.41 rows=1000 width=84)
+ Hash Key: tgb2.v2
+ -> Partial HashAggregate (cost=145944.41..145954.41 rows=1000
width=84)
+ Group Key: tgb2.v2
+ AggRefs(TargetList): [(0, 0), (1, 1), (2, 2), (3, 3)]
+ -> Hash Join (cost=618.25..105488.34 rows=2022803
width=20)
+ Hash Cond: (tgb1.v1 = tgb2.v1)
+ -> Seq Scan on tgb1 (cost=0.00..293.67 rows=25967
width=8)
+ -> Hash (cost=293.67..293.67 rows=25967 width=12)
+ -> Seq Scan on tgb2 (cost=0.00..293.67
rows=25967 width=12)
+ Optimizer: Postgres query optimizer
+(16 rows)
+
+select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+ sum
+-----
+(0 rows)
+
+set optimizer_force_multistage_agg to on;
+explain select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1 (slice1; segments: 3) (cost=145986.91..145999.46 rows=4
width=12)
+ -> Finalize HashAggregate (cost=145986.91..145999.41 rows=1 width=12)
+ Group Key: tgb2.v2
+ Filter: ((sum((tgb1.v3 * tgb2.v3)) > 100) AND (sum((tgb1.v3 *
tgb2.v3)) > 101) AND (sum((tgb1.v3 * tgb2.v3)) < 1020) AND (sum((tgb1.v3 *
tgb2.v3)) <> 103) AND (sum((tgb1.v3 * tgb2.v3)) >= 104) AND (avg((tgb1.v3 *
tgb2.v3)) <> '11'::numeric) AND (avg((tgb1.v3 * tgb2.v3)) <> '12'::numeric) AND
(avg((tgb2.v1 * tgb1.v1)) <> '13'::numeric) AND (sum(tgb1.v3) > 200))
+ AggRefs(TargetList): [(0, 0)]
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
(cost=145944.41..145974.41 rows=1000 width=84)
+ Hash Key: tgb2.v2
+ -> Partial HashAggregate (cost=145944.41..145954.41 rows=1000
width=84)
+ Group Key: tgb2.v2
+ AggRefs(TargetList): [(0, 0), (1, 1), (2, 2), (3, 3)]
+ -> Hash Join (cost=618.25..105488.34 rows=2022803
width=20)
+ Hash Cond: (tgb1.v1 = tgb2.v1)
+ -> Seq Scan on tgb1 (cost=0.00..293.67 rows=25967
width=8)
+ -> Hash (cost=293.67..293.67 rows=25967 width=12)
+ -> Seq Scan on tgb2 (cost=0.00..293.67
rows=25967 width=12)
+ Optimizer: Postgres query optimizer
+(16 rows)
+
+select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+ sum
+-----
+(0 rows)
+
+reset debug_print_aggref_in_explain;
+reset optimizer_force_multistage_agg;
diff --git a/src/test/regress/expected/aggregates_optimizer.out
b/src/test/regress/expected/aggregates_optimizer.out
index 86dd330de84..a840742448b 100644
--- a/src/test/regress/expected/aggregates_optimizer.out
+++ b/src/test/regress/expected/aggregates_optimizer.out
@@ -3448,3 +3448,124 @@ DETAIL: Falling back to Postgres-based planner because
GPORCA does not support
Execution Time: 0.198 ms
(11 rows)
+-- test aggno
+create table tgb1(v1 int, v2 int, v3 int);
+NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'v1'
as the Apache Cloudberry data distribution key for this table.
+HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make
sure column(s) chosen are the optimal data distribution key to minimize skew.
+create table tgb2(v1 int, v2 int, v3 int);
+NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'v1'
as the Apache Cloudberry data distribution key for this table.
+HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make
sure column(s) chosen are the optimal data distribution key to minimize skew.
+insert into tgb1
values(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3);
+insert into tgb2
values(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3);
+set debug_print_aggref_in_explain to on;
+explain select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..862.00 rows=1 width=8)
+ -> Result (cost=0.00..862.00 rows=1 width=8)
+ Filter: (((sum((tgb1.v3 * tgb2.v3))) > 100) AND ((sum((tgb1.v3 *
tgb2.v3))) > 101) AND ((sum((tgb1.v3 * tgb2.v3))) < 1020) AND ((sum((tgb1.v3 *
tgb2.v3))) <> 103) AND ((sum((tgb1.v3 * tgb2.v3))) >= 104) AND ((avg((tgb1.v3 *
tgb2.v3))) <> '11'::numeric) AND ((avg((tgb1.v3 * tgb2.v3))) <> '12'::numeric)
AND ((avg((tgb2.v1 * tgb1.v1))) <> '13'::numeric) AND ((sum(tgb1.v3)) > 200))
+ -> HashAggregate (cost=0.00..862.00 rows=1 width=80)
+ Group Key: tgb2.v2
+ AggRefs(TargetList): [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0),
(0, 0), (1, 1), (1, 1), (2, 2), (3, 3)]
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
(cost=0.00..862.00 rows=1 width=20)
+ Hash Key: tgb2.v2
+ -> Hash Join (cost=0.00..862.00 rows=1 width=20)
+ Hash Cond: (tgb2.v1 = tgb1.v1)
+ -> Seq Scan on tgb2 (cost=0.00..431.00 rows=1
width=12)
+ -> Hash (cost=431.00..431.00 rows=1 width=8)
+ -> Seq Scan on tgb1 (cost=0.00..431.00
rows=1 width=8)
+ Optimizer: GPORCA
+(14 rows)
+
+select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+ sum
+-----
+(0 rows)
+
+set optimizer_force_multistage_agg to on;
+explain select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..862.00 rows=1 width=8)
+ -> Result (cost=0.00..862.00 rows=1 width=8)
+ Filter: (((sum((tgb1.v3 * tgb2.v3))) > 100) AND ((sum((tgb1.v3 *
tgb2.v3))) > 101) AND ((sum((tgb1.v3 * tgb2.v3))) < 1020) AND ((sum((tgb1.v3 *
tgb2.v3))) <> 103) AND ((sum((tgb1.v3 * tgb2.v3))) >= 104) AND ((avg((tgb1.v3 *
tgb2.v3))) <> '11'::numeric) AND ((avg((tgb1.v3 * tgb2.v3))) <> '12'::numeric)
AND ((avg((tgb2.v1 * tgb1.v1))) <> '13'::numeric) AND ((sum(tgb1.v3)) > 200))
+ -> Finalize HashAggregate (cost=0.00..862.00 rows=1 width=80)
+ Group Key: tgb2.v2
+ AggRefs(TargetList): [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4),
(5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]
+ -> Redistribute Motion 3:3 (slice2; segments: 3)
(cost=0.00..862.00 rows=1 width=84)
+ Hash Key: tgb2.v2
+ -> Streaming Partial HashAggregate (cost=0.00..862.00
rows=1 width=84)
+ Group Key: tgb2.v2
+ AggRefs(TargetList): [(0, 0), (0, 0), (0, 0), (0,
0), (0, 0), (0, 0), (1, 1), (1, 1), (2, 2), (3, 3)]
+ -> Redistribute Motion 3:3 (slice3; segments: 3)
(cost=0.00..862.00 rows=1 width=20)
+ -> Hash Join (cost=0.00..862.00 rows=1
width=20)
+ Hash Cond: (tgb2.v1 = tgb1.v1)
+ -> Seq Scan on tgb2
(cost=0.00..431.00 rows=1 width=12)
+ -> Hash (cost=431.00..431.00 rows=1
width=8)
+ -> Seq Scan on tgb1
(cost=0.00..431.00 rows=1 width=8)
+ Optimizer: GPORCA
+(18 rows)
+
+select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+ sum
+-----
+(0 rows)
+
+reset debug_print_aggref_in_explain;
+reset optimizer_force_multistage_agg;
diff --git a/src/test/regress/sql/aggregates.sql
b/src/test/regress/sql/aggregates.sql
index e376c0681d9..7229bbb6128 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -1447,3 +1447,80 @@ drop table agg_hash_4;
-- GitHub issue https://github.com/greenplum-db/gpdb/issues/12061
-- numsegments of the general locus should be -1 on create_minmaxagg_path
explain analyze select count(*) from pg_class, (select count(*) > 0 from
(select count(*) from pg_class where relnatts > 8) x) y;
+
+-- test aggno
+create table tgb1(v1 int, v2 int, v3 int);
+create table tgb2(v1 int, v2 int, v3 int);
+
+insert into tgb1
values(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3);
+insert into tgb2
values(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3),(1,2,3);
+
+set debug_print_aggref_in_explain to on;
+
+explain select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
+select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
+set optimizer_force_multistage_agg to on;
+explain select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
+select
+ sum(tgb1.v3 * tgb2.v3)
+from
+ tgb1,tgb2
+where
+ tgb1.v1 = tgb2.v1 group by tgb2.v2
+having sum(tgb1.v3 * tgb2.v3) > 100 and
+ sum(tgb1.v3 * tgb2.v3) > 101 and
+ sum(tgb1.v3 * tgb2.v3) < 1020 and
+ sum(tgb1.v3 * tgb2.v3) != 103 and
+ sum(tgb1.v3 * tgb2.v3) >= 104 and
+ avg(tgb1.v3 * tgb2.v3) != 11 and
+ avg(tgb1.v3 * tgb2.v3) != 12 and
+ avg(tgb2.v1 * tgb1.v1) != 13 and
+ sum(tgb1.v3) > 200;
+
+reset debug_print_aggref_in_explain;
+reset optimizer_force_multistage_agg;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]