Skip to content

[feature](agg_state) Add aggregate state combine combinator - #66942

Merged
HappenLee merged 11 commits into
apache:masterfrom
HappenLee:feature/agg-state-combine
Sep 1, 2026
Merged

[feature](agg_state) Add aggregate state combine combinator#66942
HappenLee merged 11 commits into
apache:masterfrom
HappenLee:feature/agg-state-combine

Conversation

@HappenLee

@HappenLee HappenLee commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary:

Existing <aggregate>_state plus <aggregate>_union constructs and serializes one aggregate state for every input row before merging those states. For queries with tens of millions of raw rows, this per-row state materialization can erase much of the pre-aggregation benefit.

This PR adds a generic <aggregate>_combine(...) combinator. It feeds raw arguments directly into the nested aggregate function and emits one compatible AggState per group. For example, avg_combine(x) is aggregation-equivalent to avg_union(avg_state(x)), while avoiding a serialized AVG state for every source row. The resulting state remains consumable by the existing _union and _merge combinators.

The BE wrapper preserves the nested aggregate state layout and delegates raw accumulation, partial serialization, merge/deserialization, nullable handling, and fixed-length serialized column creation. Nereids resolves and translates the generic combinator and supports MV roll-up through the matching _union function. Zero-argument aggregates, DISTINCT, and aggregate ORDER BY expressions are rejected for now.

Dynamically synthesized <aggregate>_state, <aggregate>_merge, <aggregate>_union, <aggregate>_combine, and <aggregate>_foreach names are reserved for built-in combinators. New UDFs cannot use these names, and unqualified calls resolve to the built-in combinator without same-named UDF fallback. Existing UDFs can still be addressed with an explicit database qualifier.

Release note

Add the experimental <aggregate>_combine(...) combinator for directly producing reusable aggregate states. Dynamically synthesized aggregate-state combinator names are reserved for built-in functions.

Check List (For Author)

  • Test
    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:

Regression coverage: test_agg_state_avg, including nullable input, all-null input, grouped partial aggregation, and compatibility with avg_union(avg_state(...)).

Unit coverage: AggregateStateCombineTest, CombineCombinatorTest, FillUpMissingSlotsTest, and CreateFunctionTest. Full BE and FE builds also passed; clang-tidy reported no warnings for the changed BE files.

  • Behavior changed:

    • No.
    • Yes. Adds a new aggregate-state combinator and reserves dynamically synthesized aggregate-state combinator names for built-in functions.
  • Does this need documentation?

    • No. The function is covered by the existing experimental AggState feature.
    • Yes.

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@HappenLee

Copy link
Copy Markdown
Contributor Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: All Codex review accounts are usage-limited; earliest retry is 2026-08-20T03:35:00Z.
Workflow run: https://github.com/apache/doris/actions/runs/32230645299

Please trigger /review again after that time.

@HappenLee

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 17395 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit c9f81a310cf3ba70de6c6aa6aab50931144a5186, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17677	3147	3115	3115
q2	2051	234	153	153
q3	10298	882	523	523
q4	4672	252	206	206
q5	7666	554	398	398
q6	138	114	96	96
q7	542	523	395	395
q8	9243	879	918	879
q9	3487	2440	2429	2429
q10	6486	868	736	736
q11	475	266	231	231
q12	689	395	323	323
q13	17868	1531	1166	1166
q14	170	147	138	138
q15	q16	432	399	364	364
q17	804	822	743	743
q18	3175	2267	2255	2255
q19	1112	958	795	795
q20	626	553	471	471
q21	5236	1740	1884	1740
q22	338	271	239	239
Total cold run time: 93185 ms
Total hot run time: 17395 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3519	3428	3452	3428
q2	211	220	159	159
q3	2216	2360	2199	2199
q4	1204	1180	908	908
q5	2200	2141	2112	2112
q6	173	126	87	87
q7	1033	921	891	891
q8	1635	1457	1430	1430
q9	3174	3128	3143	3128
q10	1831	1839	1637	1637
q11	359	278	260	260
q12	463	438	337	337
q13	1472	1525	1182	1182
q14	170	164	157	157
q15	q16	391	398	361	361
q17	1076	1052	1053	1052
q18	5022	4412	4787	4412
q19	1045	860	886	860
q20	977	931	839	839
q21	3844	3111	3291	3111
q22	398	347	327	327
Total cold run time: 32413 ms
Total hot run time: 28877 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 83953 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit c9f81a310cf3ba70de6c6aa6aab50931144a5186, data reload: false

query5	4256	426	329	329
query6	423	186	148	148
query7	4840	448	269	269
query8	295	128	129	128
query9	8682	2936	2917	2917
query10	406	267	211	211
query11	5385	1053	920	920
query12	126	71	71	71
query13	1198	445	337	337
query14	6029	2276	2124	2124
query14_1	2034	2018	1995	1995
query15	178	117	111	111
query16	927	377	350	350
query17	817	466	363	363
query18	2341	338	239	239
query19	169	149	115	115
query20	73	70	69	69
query21	207	118	100	100
query22	5341	5344	5266	5266
query23	6519	6242	6106	6106
query23_1	6042	6034	5974	5974
query24	7279	1093	775	775
query24_1	792	810	798	798
query25	449	310	271	271
query26	1256	278	155	155
query27	2700	447	281	281
query28	4657	1531	1508	1508
query29	981	454	369	369
query30	277	177	155	155
query31	869	435	365	365
query32	100	53	50	50
query33	465	231	190	190
query34	1022	833	490	490
query35	413	414	367	367
query36	560	569	533	533
query37	125	83	71	71
query38	999	863	856	856
query39	508	496	499	496
query39_1	503	459	444	444
query40	223	128	115	115
query41	57	57	55	55
query42	81	82	80	80
query43	248	251	218	218
query44	1066	557	558	557
query45	118	109	109	109
query46	811	882	532	532
query47	777	763	732	732
query48	309	322	229	229
query49	548	244	220	220
query50	842	323	254	254
query51	8374	8230	8222	8222
query52	74	83	70	70
query53	215	212	159	159
query54	238	186	164	164
query55	74	62	65	62
query56	225	219	247	219
query57	711	673	646	646
query58	222	187	198	187
query59	1243	1261	1112	1112
query60	249	210	214	210
query61	118	110	129	110
query62	350	206	192	192
query63	187	162	160	160
query64	2733	679	635	635
query65	1635	1580	1599	1580
query66	1854	331	263	263
query67	9846	9734	9715	9715
query68	2740	1254	816	816
query69	343	233	207	207
query70	669	619	621	619
query71	285	270	242	242
query72	2297	1742	1517	1517
query73	657	606	366	366
query74	1584	1232	1145	1145
query75	1261	1162	1010	1010
query76	2299	744	569	569
query77	255	254	215	215
query78	4140	3646	3216	3216
query79	2897	836	554	554
query80	1599	392	344	344
query81	513	201	176	176
query82	661	134	105	105
query83	345	252	232	232
query84	301	129	103	103
query85	887	445	383	383
query86	388	176	167	167
query87	1041	966	887	887
query88	2830	2144	2127	2127
query89	316	228	204	204
query90	1933	141	147	141
query91	157	145	126	126
query92	48	45	45	45
query93	1704	1112	771	771
query94	631	253	218	218
query95	654	444	340	340
query96	868	577	280	280
query97	1087	1051	1051	1051
query98	175	137	139	137
query99	442	354	321	321
Total cold run time: 179115 ms
Total hot run time: 83953 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.55 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit c9f81a310cf3ba70de6c6aa6aab50931144a5186, data reload: false

query1	0.01	0.01	0.01
query2	0.07	0.04	0.04
query3	0.25	0.11	0.11
query4	1.60	0.09	0.10
query5	0.17	0.16	0.16
query6	1.28	0.68	0.70
query7	0.04	0.00	0.01
query8	0.05	0.03	0.03
query9	0.28	0.22	0.21
query10	0.34	0.33	0.34
query11	0.16	0.11	0.11
query12	0.15	0.13	0.12
query13	0.31	0.32	0.32
query14	0.44	0.45	0.44
query15	0.35	0.35	0.35
query16	0.23	0.22	0.25
query17	0.68	0.70	0.69
query18	0.18	0.16	0.16
query19	1.12	1.09	1.18
query20	0.01	0.01	0.01
query21	15.44	0.18	0.12
query22	5.05	0.04	0.04
query23	16.18	0.24	0.10
query24	3.03	0.35	0.25
query25	0.12	0.04	0.03
query26	0.79	0.18	0.12
query27	0.04	0.03	0.03
query28	3.65	0.54	0.28
query29	12.50	3.13	2.54
query30	0.25	0.12	0.12
query31	2.80	0.38	0.18
query32	3.54	0.31	0.23
query33	1.37	1.41	1.52
query34	15.37	2.23	1.74
query35	1.72	1.73	1.68
query36	0.51	0.29	0.29
query37	0.06	0.04	0.04
query38	0.04	0.04	0.02
query39	0.04	0.02	0.03
query40	0.12	0.08	0.08
query41	0.07	0.03	0.02
query42	0.03	0.03	0.02
query43	0.04	0.02	0.03
Total cold run time: 90.48 s
Total hot run time: 14.55 s

@HappenLee

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 28.18% (31/110) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 62.19% (28946/46543)
Line Coverage 47.26% (302797/640749)
Region Coverage 42.93% (244419/569287)
Branch Coverage 44.49% (113711/255587)

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: All Codex review accounts are usage-limited; earliest retry is 2026-08-20T03:35:00Z.
Workflow run: https://github.com/apache/doris/actions/runs/32267897773

Please trigger /review again after that time.

@HappenLee
HappenLee force-pushed the feature/agg-state-combine branch from c9f81a3 to 40b1c15 Compare August 24, 2026 03:27
@HappenLee

Copy link
Copy Markdown
Contributor Author

run buildall

@HappenLee

Copy link
Copy Markdown
Contributor Author

Review summary for rebased head 40b1c15: the combine aggregate-state path is wired through BE and FE, argument/return state compatibility is validated, and FE unit plus regression coverage is included. git diff --check passes. I found no blocking issue in this review. A formal GitHub review could not be created because the authenticated account is the PR author, so this summary is posted as a PR comment.

@HappenLee

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 17477 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 40b1c15314b5fdd5f3178a0dbcc257e6a7a9f0e2, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17568	3061	3069	3061
q2	1884	239	157	157
q3	10460	902	514	514
q4	4669	251	200	200
q5	7683	572	386	386
q6	139	117	93	93
q7	532	526	395	395
q8	9239	903	894	894
q9	3479	2427	2494	2427
q10	6488	871	735	735
q11	446	264	241	241
q12	684	400	336	336
q13	17837	1546	1172	1172
q14	160	151	139	139
q15	q16	438	402	369	369
q17	839	830	795	795
q18	3101	2269	2253	2253
q19	1123	953	772	772
q20	661	494	452	452
q21	4930	1846	1912	1846
q22	325	268	240	240
Total cold run time: 92685 ms
Total hot run time: 17477 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3388	3353	3354	3353
q2	205	217	157	157
q3	2243	2337	2160	2160
q4	1207	1186	903	903
q5	2197	2145	2119	2119
q6	173	120	87	87
q7	1068	938	873	873
q8	1617	1444	1437	1437
q9	3144	3138	3118	3118
q10	1872	1817	1618	1618
q11	360	273	258	258
q12	459	434	342	342
q13	1475	1537	1163	1163
q14	182	176	159	159
q15	q16	404	398	357	357
q17	1061	1050	1038	1038
q18	4969	4379	4807	4379
q19	885	865	880	865
q20	998	930	820	820
q21	3737	3240	3347	3240
q22	401	370	344	344
Total cold run time: 32045 ms
Total hot run time: 28790 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 83584 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 40b1c15314b5fdd5f3178a0dbcc257e6a7a9f0e2, data reload: false

query5	4277	407	344	344
query6	414	164	155	155
query7	4866	479	277	277
query8	294	124	121	121
query9	8677	2960	2986	2960
query10	448	261	208	208
query11	5385	1060	907	907
query12	112	69	73	69
query13	1190	452	318	318
query14	6042	2229	2097	2097
query14_1	1958	1936	1959	1936
query15	168	123	110	110
query16	928	392	360	360
query17	782	441	367	367
query18	2307	343	249	249
query19	166	148	120	120
query20	75	70	71	70
query21	216	118	103	103
query22	5415	5284	5282	5282
query23	6748	6259	5966	5966
query23_1	6288	6088	6162	6088
query24	7271	1077	780	780
query24_1	782	747	756	747
query25	407	280	247	247
query26	1249	261	160	160
query27	2717	421	292	292
query28	4663	1501	1517	1501
query29	941	423	337	337
query30	275	182	154	154
query31	852	433	353	353
query32	103	48	48	48
query33	458	219	171	171
query34	970	845	486	486
query35	411	392	347	347
query36	582	559	519	519
query37	119	80	76	76
query38	1006	857	818	818
query39	493	497	476	476
query39_1	475	488	493	488
query40	219	120	116	116
query41	56	53	52	52
query42	80	75	80	75
query43	245	246	212	212
query44	1010	544	553	544
query45	118	109	103	103
query46	781	855	508	508
query47	768	758	725	725
query48	325	316	235	235
query49	552	255	196	196
query50	834	339	269	269
query51	8127	8068	8069	8068
query52	75	83	70	70
query53	215	224	162	162
query54	249	212	190	190
query55	79	63	57	57
query56	269	244	308	244
query57	695	674	655	655
query58	240	208	202	202
query59	1209	1260	1128	1128
query60	282	221	222	221
query61	165	152	134	134
query62	357	221	203	203
query63	185	154	153	153
query64	2651	676	606	606
query65	1631	1607	1597	1597
query66	1841	305	247	247
query67	9850	9912	9754	9754
query68	3039	1233	724	724
query69	347	237	192	192
query70	723	613	605	605
query71	314	269	258	258
query72	2430	1802	1607	1607
query73	688	583	337	337
query74	2021	1221	1130	1130
query75	1242	1153	1030	1030
query76	2405	741	557	557
query77	260	267	215	215
query78	3900	3681	3191	3191
query79	2668	881	569	569
query80	1616	395	342	342
query81	493	198	175	175
query82	621	124	97	97
query83	332	258	237	237
query84	306	127	104	104
query85	864	430	388	388
query86	396	173	163	163
query87	1029	973	925	925
query88	2793	2086	2113	2086
query89	314	226	209	209
query90	2004	146	143	143
query91	155	146	126	126
query92	53	46	46	46
query93	1559	1110	743	743
query94	674	257	216	216
query95	610	358	423	358
query96	761	605	273	273
query97	1061	1059	1030	1030
query98	168	146	136	136
query99	418	353	314	314
Total cold run time: 179287 ms
Total hot run time: 83584 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.81 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 40b1c15314b5fdd5f3178a0dbcc257e6a7a9f0e2, data reload: false

query1	0.00	0.00	0.01
query2	0.07	0.04	0.04
query3	0.24	0.11	0.11
query4	1.61	0.10	0.10
query5	0.18	0.16	0.16
query6	1.25	0.69	0.67
query7	0.03	0.01	0.00
query8	0.05	0.04	0.03
query9	0.30	0.22	0.21
query10	0.36	0.34	0.35
query11	0.16	0.11	0.11
query12	0.14	0.13	0.12
query13	0.31	0.31	0.31
query14	0.45	0.44	0.45
query15	0.35	0.35	0.36
query16	0.23	0.21	0.23
query17	0.70	0.71	0.64
query18	0.19	0.16	0.17
query19	1.22	1.22	1.23
query20	0.01	0.01	0.01
query21	15.46	0.16	0.11
query22	5.09	0.04	0.04
query23	16.21	0.25	0.11
query24	2.97	0.31	0.27
query25	0.10	0.04	0.03
query26	0.84	0.16	0.12
query27	0.04	0.03	0.03
query28	3.64	0.54	0.28
query29	12.48	3.20	2.56
query30	0.26	0.12	0.13
query31	2.75	0.37	0.18
query32	3.52	0.33	0.25
query33	1.47	1.53	1.46
query34	15.37	2.22	1.76
query35	1.76	1.77	1.75
query36	0.46	0.28	0.29
query37	0.06	0.04	0.04
query38	0.04	0.02	0.02
query39	0.03	0.03	0.02
query40	0.12	0.08	0.08
query41	0.06	0.02	0.02
query42	0.03	0.03	0.02
query43	0.03	0.03	0.03
Total cold run time: 90.64 s
Total hot run time: 14.81 s

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for seven blocking correctness issues and one P2 error-handling issue; each has a concrete trigger in the inline comments.

Checkpoint conclusions:

  • Goal and accomplishment: direct raw aggregation into a reusable AggState is a sound optimization, and the avg happy path preserves the existing state layout, but the generic combinator contract is not met for several admitted aggregates and plan shapes.
  • Scope and focus: all 14 authoritative changed files and the relevant FE builder/translator/planner/MV paths plus BE evaluator/state consumers were reviewed. No additional user focus was supplied.
  • Correctness and parallel paths: grouped/no-key, one/two-phase, merge/union, scalar and correlated subqueries, analytic windows, MV creation/roll-up, constructor-expanded overloads, invalid base names, and specialized aggregate policies were traced. The inline findings cover the surviving failures.
  • Concurrency: no new locks, threads, or shared mutable ownership were introduced; no concurrency defect was found.
  • Lifecycle and resources: create/reset/destroy and serialized-column ownership delegate consistently. The AI failure is initialization, not a leak: required QueryContext never reaches the nested function.
  • Configuration and compatibility: no new config, persisted metadata field, or wire protocol was added, and ordinary state bytes remain compatible with _state/_union/_merge. Session-selected phase/window behavior and terminal serialization expose correctness gaps called out inline.
  • Transactions and persistence: no transaction, retry, or durable-write semantics changed. Synchronous MV construction is the relevant storage boundary and currently fails before materialization.
  • FE/BE contract: ordinary subtype/arity checks are coherent, but canonical AI children, nullability, phase policy, window attributes, and terminal serialization are not fully propagated.
  • Performance: the intended removal of per-row state serialization is preserved on the valid avg path; no separate hot-path regression was found.
  • Tests: the added avg unit/regression coverage checks grouped, nullable, all-null, fixed-length, and compatibility behavior, but misses AI overloads/setup, scalar/correlated subqueries, sliding windows, MV creation, phase-restricted aggregates, non-aggregate suffixes, and terminal two-phase serialization. Per the review prompt, no builds or tests were run locally. Live style, license, secrets, Cloud UT, and performance checks pass; FE UT, BE UT, compile, and code-review remain pending.
  • Observability: no new metric/log requirement was identified; several failures occur during analysis/setup or return wrong state values, so tests and explicit validation are the important guardrails.
  • Review status: round 3 reached the configured cap and still produced the terminal-serialization finding, so this review is capped/incomplete, not converged.

_function->deserialize_and_merge_from_column_range(place, column, begin, end, arena);
}

void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve merged states with terminal serialization

In the required two-phase path for orthogonal_bitmap_expr_calculate[_count]_combine, local serialization finalizes the raw calculator into a separate result, and global merge accumulates only that field. This finalizer serializes the merged state again; the nested write() then overwrites result from the global state's empty raw calculator, emitting zero or an empty bitmap. The matching _merge therefore returns the wrong value. Please gate _combine on an explicit merge-stable serialization capability or preserve the merged serialized result, and add forced two-phase count and bitmap tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The orthogonal bitmap aggregate family now implements NotSupportAggState, so _state, _merge, _union, and _combine are rejected during FE function resolution instead of entering an unsupported terminal-serialization path. The unit test covers all affected orthogonal aggregate classes.

previous_is_nul, end_is_nul, has_null, use_null_result, could_use_previous_result);
}

void set_query_context(QueryContext* context) override {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Propagate QueryContext to the wrapped AI aggregate

FunctionRegistry now accepts ai_agg_combine(...), but AggFnEvaluator::prepare() calls set_query_context() only when the outer name is exactly ai_agg. For ai_agg_combine, this forwarding method is never called; AggregateFunctionAIAgg::create() stores a null context and its first add() dereferences _ctx in prepare(), which can crash the BE. Please key this setup off the nested aggregate/capability (or explicitly handle the combinator) and cover a valid three-argument AI combine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by rejecting ai_agg_state and ai_agg_combine during FE function resolution. AIAgg now implements NotSupportAggStateCreation, which prevents a wrapped AI aggregate without the required query context from reaching BE. Full AI AggState support can be added later after its context and canonical arguments are modeled correctly.

argument_types[i]->get_name());
}
}
_function = AggregateStateCombine::create(state_type->get_nested_function(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Build a window-aware nested state for _combine

This reuses the DataTypeAggState nested function, which is constructed with the default is_window_function=false, even when this evaluator represents an analytic window. The wrapper still forwards incremental support. For nullable Avg, a bounded-frame transition from a non-null row to an all-null frame reaches a window-only DCHECK in debug builds; in release it never tracks null_count and serializes a populated count-zero state, so merging that state produces a non-NULL/NaN result instead of NULL. Please construct a window-aware nested function or disable incremental mode for this case, and test non-null-to-all-null frame transitions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. WindowFunctionChecker now explicitly rejects CombineCombinator, so _combine cannot be planned as a window function until a window-aware nested state is implemented. A unit test verifies the analysis rejection.

if (!(queryAggregateFunction instanceof Combinator)
&& (viewFunction instanceof UnionCombinator || viewFunction instanceof StateCombinator)) {
&& (viewFunction instanceof UnionCombinator || viewFunction instanceof StateCombinator
|| viewFunction instanceof CombineCombinator)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Store combine state directly in synchronous MVs

Allowing CombineCombinator here makes it a valid view-side roll-up expression, but CreateMaterializedViewCommand still treats every generic aggregate as a raw aggregate and wraps it with StateCombinator.create(). For avg_combine(v), that constructs a synthetic avg_combine_state and null-unboxes aggFuncNameNullableMap.get("avg_combine"), so CREATE MATERIALIZED VIEW ... avg_combine(v) fails before rewrite. Please recognize _combine as already state-valued (or reject this MV form deliberately) and cover MV creation plus roll-up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Synchronous MV analysis now explicitly rejects CombineCombinator instead of storing it through the existing aggregate-state rewrite path. A regression test covers the expected analysis error.

if (combinatorSuffix.equalsIgnoreCase(COMBINE)) {
// DataTypeAggState needs at least one subtype, so zero-argument aggregates such as
// count(*) cannot produce an AggState yet. count_combine(1) remains supported.
return !arguments.isEmpty() && nestedBuilder.canApply(arguments);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Filter _combine resolution to aggregate builders

This branch only checks the nested builder's signature, while dynamic suffix lookup tries every built-in registered under the base name. Thus abs_combine(1) retains the scalar Abs builder and buildState() later casts the built scalar to AggregateFunction, throwing an internal ClassCastException instead of a normal analysis error. Require the nested builder's class to be an aggregate before advertising this combinator, and add a negative scalar-name test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. AggCombinerFunctionBuilder.canApply first verifies that the nested builder represents an AggregateFunction. Scalar names such as abs_combine now fail normal function resolution instead of reaching the aggregate cast and throwing an internal exception. Covered by unit test.

if (!arguments.isEmpty() && arguments.get(0) instanceof Boolean && (Boolean) arguments.get(0)) {
throw new IllegalStateException(name + " doesn't support DISTINCT");
}
return Pair.of(new CombineCombinator((List<Expression>) arguments, nestedFunction), nestedFunction);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve constructor-expanded arguments in the combine expression

AIAgg(text, task) prepends the default resource and canonicalizes itself to three children, but this branch discards nestedFunction.children() and builds CombineCombinator from the original two arguments. The resulting AggStateType and translated TExpr contain only two columns, while the BE AI aggregate unconditionally reads columns[2], causing an out-of-bounds access. Please propagate the nested function's canonical children (while handling the DISTINCT marker) or reject arity-changing builders, and cover the default-resource overload.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed for this PR by explicitly disabling ai_agg_state and ai_agg_combine at function resolution. This avoids constructing an AggState from the non-canonical two-argument child list while AIAgg expands it to three arguments internally. Canonical AI AggState support is deferred to a follow-up.

* Aggregate inputs into the nested function's serialized state.
*/
public class CombineCombinator extends AggregateFunction
implements ExplicitlyCastableSignature, AlwaysNotNullable, Combinator, RollUpTrait {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve the non-null empty state across scalar subqueries

This aggregate promises a non-null state through AlwaysNotNullable, but scalar-subquery nullability adjustment and correlated empty-input repair only recognize NotNullableAggregateFunction. As a result, (select avg_combine(v) from r) is exposed as nullable, and feeding that state to _merge or _union reaches BE as Nullable(AggState), which AggFnEvaluator::prepare() rejects. Correlated unnesting can also substitute SQL NULL for an unmatched key instead of the serialized empty state. Please integrate _combine with the scalar-aggregate empty-input contract (or prevent these rewrites/uses) and cover uncorrelated plus unmatched-correlated cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged and deferred to a follow-up PR, as discussed in #66942 (comment). This is shared by _union and _combine: correlated scalar-subquery rewriting needs a typed empty AggState expression and a common empty-input result contract. We will fix both combinators uniformly rather than special-casing _combine in this PR.

}

@Override
protected List<DataType> intermediateTypes() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Delegate the nested aggregate's phase support

The wrapper delegates intermediateTypes() here but inherits the base supportAggregatePhase(), which returns true for every phase. Consequently orthogonal_bitmap_expr_calculate[_count]_combine(...) appears eligible for a forced agg_phase=1 INPUT_TO_RESULT plan even though both nested aggregates explicitly support only AggregatePhase.TWO. Please delegate this policy to nested and add a phase-selection test for a two-phase-only aggregate; the supported two-phase serialization path also needs the separate state-preservation fix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. CombineCombinator.supportAggregatePhase now delegates to the nested aggregate function, so aggregates that disallow a phase remain disallowed after wrapping. The orthogonal bitmap functions are additionally rejected from AggState combinators, and the delegation behavior is covered by unit test.

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 45.45% (50/110) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.94% (34314/45187)
Line Coverage 60.92% (386628/634637)
Region Coverage 57.00% (323853/568142)
Branch Coverage 57.85% (147762/255436)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 61.18% (52/85) 🎉
Increment coverage report
Complete coverage report

@HappenLee

Copy link
Copy Markdown
Contributor Author

Follow-up issue: correlated scalar subqueries containing _combine or _union need unified empty-input handling.

Both combinators produce an AggState and are AlwaysNotNullable: on empty input they should return a non-null serialized empty state. However, after decorrelation to a left outer join, an unmatched group produces SQL NULL. The current SubqueryToApply repair only handles NotNullableAggregateFunction through resultForEmptyInput(), while _combine/_union have no typed empty-AggState expression that can be used as the fallback value. Simply making the combinators nullable would only hide the semantic mismatch.

A complete fix should introduce a shared empty-input-result contract and a typed empty AggState expression generated by BE, then rewrite the output as ifnull(state_slot, empty_agg_state), consistently for both _combine and _union. Since this requires broader FE/BE support, we will handle it uniformly in a follow-up PR instead of special-casing it in this PR.

HappenLee added a commit to HappenLee/incubator-doris that referenced this pull request Aug 24, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: The aggregate combine path admitted orthogonal bitmap aggregates whose states are not safe for AggState serialization, did not propagate QueryContext to AI aggregate combinators, allowed unsupported synchronous materialized view definitions, and ignored nested aggregate phase restrictions. Mark orthogonal bitmap aggregates as unsupported by AggState combinators, propagate AI query context by function-name prefix, reject combine functions in synchronous materialized view analysis, and delegate aggregate phase support to the nested function.

### Release note

Harden aggregate state combine validation and execution setup.

### Check List (For Author)

- Test:
    - Unit Test: CombineCombinatorTest
    - Regression test: Added synchronous materialized view rejection coverage to test_agg_state_avg; not run locally because no worktree-local cluster was started
    - BE Unit Test: Not run because run-be-ut.sh requires updating the datasketches-cpp submodule before compilation
- Behavior changed: Yes. Orthogonal bitmap AggState combinators and synchronous materialized views using _combine are rejected during analysis.
- Does this need documentation: No
HappenLee added a commit to HappenLee/incubator-doris that referenced this pull request Aug 24, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: Aggregate combine functions reused nested states that were not constructed with window semantics, and dynamic combinator resolution could wrap scalar function builders and later fail with an internal class cast. Reject combine functions during window analysis and only advertise AggState combinators for aggregate function builders.

### Release note

Reject aggregate combine window functions and scalar functions with AggState combinator suffixes during analysis.

### Check List (For Author)

- Test:
    - Unit Test: CombineCombinatorTest
    - Unit Test: CheckAndStandardizeWindowFunctionTest
- Behavior changed: Yes. Aggregate combine window functions and scalar functions with AggState combinator suffixes now return analysis errors.
- Does this need documentation: No
HappenLee added a commit to HappenLee/incubator-doris that referenced this pull request Aug 24, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: AI_AGG normalizes two-argument calls by adding a default resource, while AggState-producing combinators preserve the original arguments. This can create mismatched AggState signatures and invalid backend execution. Reject ai_agg_state and ai_agg_combine during function resolution until canonical AggState support is implemented.

### Release note

AI_AGG no longer supports the _state and _combine combinators.

### Check List (For Author)

- Test: Unit Test
    - CombineCombinatorTest
- Behavior changed: Yes. ai_agg_state and ai_agg_combine now fail analysis.
- Does this need documentation: No
@HappenLee

Copy link
Copy Markdown
Contributor Author

/review

HappenLee added a commit to HappenLee/incubator-doris that referenced this pull request Aug 24, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: FE Checkstyle rejected the imports in CombineCombinatorTest because AIAgg was not in the required custom lexicographical order. Sort the imports according to the repository rule.

### Release note

None

### Check List (For Author)

- Test: Manual test
    - mvn -T 48 clean checkstyle:check
- Behavior changed: No
- Does this need documentation: No
@HappenLee HappenLee changed the title [feature](agg-state) Add aggregate state combine combinator [feature](agg_state) Add aggregate state combine combinator Aug 26, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review result: requesting changes on head 4c317b6d04fe91f3bed5bb32cab142426f16d5c3 after two converged review rounds. One new inline P1 is attached.

Blocking finding:

  • _combine has no execution-version or backend-capability fence for an old BE that remains query-available as a cloud smooth-upgrade source. The new FE metadata reaches the target-base AGG_STATE branch and fails during evaluator preparation.

Critical checkpoint conclusions:

  • Goal and correctness: the current-FE/current-BE raw-input-to-serialized-state path is coherent, including grouped/non-grouped finalization, partial/streaming aggregation, nullable/all-null states, and merge/union consumption. The mixed-version dispatch path is the surviving blocker.
  • Scope and user focus: all 27 authoritative changed files plus relevant binding, scheduling, cast, MV/window, and BE aggregation consumers were swept. No extra user-provided focus was supplied, and no unrelated source change was found.
  • Concurrency, lifecycle, and memory: the wrapper adds no shared mutable state, threads, locks, or ownership cycle; nested create/reset/destroy, size/alignment, context, blockability, COW ownership, and append-safe result serialization were traced without a distinct defect.
  • Compatibility and FE/BE metadata: function name, raw parameter types/nullability, AggState return metadata, and binary type agree on current binaries. Base and head both advertise BE execution version 13, while cloud smooth-upgrade worker selection can retain an old source BE; that missing capability boundary is the inline issue.
  • Parallel paths and conditions: DISTINCT, zero-argument, ordered/window, AI, orthogonal bitmap, foreach, synchronous/asynchronous MV, aliases, CTE/subquery, UNION/CASE common types, explicit casts, and sinks were checked. Existing scalar-subquery and Decimal256 limitations remain on their live threads and were not duplicated.
  • Error handling and nullability: current-branch type/name/arity mismatches return contextual Status errors, invariants fail loudly, const/nullable arguments are materialized or delegated consistently, and no swallowed error survived. The old-BE prepare failure should instead be prevented by planning/scheduling.
  • Tests and expected results: the new BE, FE, and regression coverage and every expected AVG result were inspected. Mixed-version scheduling is not covered. No build or test command was run because the authoritative review prompt prohibits it.
  • Observability, persistence, transactions, writes, and configuration: no new metric/logging requirement, persisted format, EditLog, transaction protocol, storage-write path, or configuration default is introduced.
  • Performance: the intended avoidance of per-row state materialization is present; current result/partial paths did not reveal a separate CPU, copy, or peak-memory blocker.
  • Final falsification: a proposed UNION exact-policy issue was rejected before submission because the later non-loose CheckCast rejects the non-identical AggState cast before translation. A cross-name merge/union validation mismatch was also dismissed as pre-existing.

Review status: complete and converged after Round 2. BE, FE, and risk-focused passes each ended with NO_NEW_VALUABLE_FINDINGS; every other candidate was dismissed with code evidence or duplicate-fenced.

Function aggregateFunction = functionCallExpr.getFn();
aggregateFunction.setName(new FunctionName(combinator.getName()));
aggregateFunction.setArgs(arguments.stream().map(Expr::getType).collect(Collectors.toList()));
aggregateFunction.setBinaryType(Function.BinaryType.AGG_STATE);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Fence _combine during cloud smooth upgrades. This translator sends raw arguments with binary_type=AGG_STATE, but the target-base BE treats every AGG_STATE function as a one-argument merge/union consumer. Base and head both advertise execution version 13, and cloud worker selection can still choose an isSmoothUpgradeSrc BE because Backend.isQueryAvailable() does not exclude it. avg_combine(INT) then fails old-BE prepare (input type must be agg_state; multi-argument combines fail arity). Please add an execution-version/backend-capability or smooth-upgrade-source fence and cover mixed-version scheduling.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for raising this. This failure path requires a new FE that can plan and emit _combine to coexist with an old, query-eligible BE.

Under the supported Doris upgrade contract, all BEs are upgraded before any FE is upgraded:

  • During the mixed-BE phase, the FE is still old and cannot resolve or emit _combine.
  • During the FE rolling-upgrade phase, all BEs have already been upgraded and support AggregateStateCombine.

Therefore, isSmoothUpgradeSrc() being query-available by itself does not make this path reachable. The documented Cloud upgrade procedure explicitly requires confirming that all BE instances have been upgraded before upgrading FE:
https://doris.apache.org/docs/4.x/compute-storage-decoupled/upgrade/

The general upgrade procedure states the same BE-before-FE ordering:
https://doris.apache.org/docs/dev/admin-manual/cluster-management/upgrade/

Keeping the same be_exec_version is also expected here because this change does not alter the serialized block format; compatibility is provided by the BE-first rollout order.

Unless there is a supported Cloud rollout workflow in which a new FE is deployed before every old smooth-upgrade source BE in every compute group has been retired, this mixed-version path is outside the supported upgrade sequence and should not require a runtime fence. Please identify such a supported workflow if one exists; otherwise I believe this finding can be resolved.

@HappenLee

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16881 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 4c317b6d04fe91f3bed5bb32cab142426f16d5c3, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17587	3000	2993	2993
q2	2297	268	231	231
q3	10030	885	508	508
q4	4677	248	196	196
q5	7677	564	378	378
q6	138	111	92	92
q7	535	503	393	393
q8	9240	925	949	925
q9	3473	2388	2390	2388
q10	6499	827	708	708
q11	398	190	176	176
q12	614	252	194	194
q13	18155	1514	1174	1174
q14	159	155	144	144
q15	q16	437	398	366	366
q17	1405	883	856	856
q18	3042	2219	2229	2219
q19	1121	953	789	789
q20	373	281	197	197
q21	5246	1730	1844	1730
q22	320	264	224	224
Total cold run time: 93423 ms
Total hot run time: 16881 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3385	3313	3297	3297
q2	502	391	357	357
q3	2212	2313	2201	2201
q4	1172	1150	874	874
q5	2147	2089	2066	2066
q6	171	125	85	85
q7	997	941	843	843
q8	1588	1396	1381	1381
q9	3082	3062	3048	3048
q10	1812	1777	1605	1605
q11	351	264	248	248
q12	448	427	337	337
q13	1476	1540	1146	1146
q14	161	178	167	167
q15	q16	398	393	360	360
q17	3629	3295	3159	3159
q18	4825	4422	4789	4422
q19	7233	815	828	815
q20	944	928	803	803
q21	3729	2937	3162	2937
q22	393	343	321	321
Total cold run time: 40655 ms
Total hot run time: 30472 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 82362 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 4c317b6d04fe91f3bed5bb32cab142426f16d5c3, data reload: false

query5	4266	410	343	343
query6	416	141	126	126
query7	4933	441	247	247
query8	303	128	120	120
query9	8681	2850	2865	2850
query10	389	221	178	178
query11	5390	1046	909	909
query12	118	71	70	70
query13	1195	439	319	319
query14	6164	2182	2042	2042
query14_1	1927	1921	1919	1919
query15	185	114	106	106
query16	1059	371	356	356
query17	816	465	369	369
query18	2345	320	232	232
query19	180	141	109	109
query20	72	70	69	69
query21	202	102	87	87
query22	5447	5334	5328	5328
query23	6583	6189	5924	5924
query23_1	6110	6128	6070	6070
query24	7342	1079	798	798
query24_1	774	780	782	780
query25	449	311	262	262
query26	1261	248	134	134
query27	2750	409	257	257
query28	4728	1499	1487	1487
query29	962	443	361	361
query30	264	147	130	130
query31	843	397	329	329
query32	141	86	78	78
query33	472	237	176	176
query34	1025	831	486	486
query35	404	385	331	331
query36	571	563	538	538
query37	125	79	70	70
query38	1015	841	794	794
query39	499	491	473	473
query39_1	458	480	457	457
query40	205	95	78	78
query41	58	56	59	56
query42	73	72	72	72
query43	240	239	208	208
query44	1056	553	569	553
query45	117	111	103	103
query46	756	854	518	518
query47	763	758	701	701
query48	323	313	224	224
query49	546	248	191	191
query50	757	259	190	190
query51	7967	7969	7999	7969
query52	66	68	59	59
query53	194	199	151	151
query54	309	169	147	147
query55	78	57	52	52
query56	206	167	181	167
query57	699	670	650	650
query58	206	157	157	157
query59	1247	1218	1103	1103
query60	244	181	166	166
query61	119	114	116	114
query62	399	202	171	171
query63	176	147	138	138
query64	2792	708	563	563
query65	1664	1677	1659	1659
query66	1819	268	201	201
query67	10289	10299	10045	10045
query68	2780	1205	741	741
query69	367	228	191	191
query70	657	627	626	626
query71	262	173	166	166
query72	2383	1815	1572	1572
query73	690	579	341	341
query74	1643	1273	1170	1170
query75	1211	1142	999	999
query76	2294	747	588	588
query77	258	260	215	215
query78	3966	3838	3331	3331
query79	2433	799	585	585
query80	1590	326	274	274
query81	487	153	133	133
query82	718	134	97	97
query83	286	207	184	184
query84	303	110	90	90
query85	844	355	300	300
query86	461	175	176	175
query87	1007	960	881	881
query88	2821	2099	2119	2099
query89	308	197	177	177
query90	2008	139	123	123
query91	132	117	99	99
query92	77	69	63	63
query93	1609	1093	758	758
query94	699	254	199	199
query95	540	307	232	232
query96	815	556	262	262
query97	1085	1048	1015	1015
query98	176	132	132	132
query99	492	335	304	304
Total cold run time: 179199 ms
Total hot run time: 82362 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.8 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 4c317b6d04fe91f3bed5bb32cab142426f16d5c3, data reload: false

query1	0.01	0.00	0.01
query2	0.15	0.04	0.04
query3	0.26	0.11	0.11
query4	1.60	0.09	0.10
query5	0.19	0.17	0.16
query6	1.24	0.72	0.69
query7	0.04	0.01	0.00
query8	0.04	0.02	0.02
query9	0.32	0.22	0.23
query10	0.36	0.36	0.36
query11	0.22	0.12	0.12
query12	0.15	0.11	0.12
query13	0.32	0.31	0.32
query14	0.48	0.47	0.44
query15	0.35	0.37	0.34
query16	0.23	0.22	0.22
query17	0.67	0.66	0.71
query18	0.18	0.17	0.16
query19	1.18	1.16	1.23
query20	0.02	0.01	0.01
query21	15.49	0.17	0.12
query22	4.99	0.04	0.04
query23	16.25	0.25	0.10
query24	5.47	0.32	0.27
query25	0.15	0.05	0.04
query26	0.75	0.16	0.12
query27	0.03	0.03	0.03
query28	3.64	0.57	0.29
query29	12.45	3.12	2.54
query30	0.28	0.11	0.12
query31	2.78	0.37	0.17
query32	3.53	0.33	0.23
query33	1.50	1.52	1.53
query34	15.34	2.15	1.79
query35	1.74	1.77	1.72
query36	0.49	0.30	0.27
query37	0.10	0.04	0.03
query38	0.05	0.03	0.03
query39	0.06	0.03	0.02
query40	0.13	0.07	0.07
query41	0.16	0.02	0.02
query42	0.09	0.02	0.02
query43	0.04	0.03	0.03
Total cold run time: 93.52 s
Total hot run time: 14.8 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 73.23% (93/127) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 45.38% (59/130) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.96% (34381/45262)
Line Coverage 60.98% (387433/635348)
Region Coverage 57.08% (324713/568915)
Branch Coverage 57.91% (148165/255832)

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Existing <aggregate>_state plus <aggregate>_union constructs and serializes one aggregate state for every input row before merging those states. Add <aggregate>_combine to aggregate raw inputs directly with the nested aggregate function and emit one compatible AggState, preserving partial aggregation and avoiding per-row state materialization.

### Release note

Add the experimental <aggregate>_combine(...) combinator for directly producing reusable aggregate states.

### Check List (For Author)

- Test:
    - Regression test: test_agg_state_avg
    - Unit Test: AggregateStateCombineTest and CombineCombinatorTest
- Behavior changed: Yes. Adds a new aggregate-state combinator.
- Does this need documentation: No. The function is covered by the existing experimental AggState feature.
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: The aggregate combine path admitted orthogonal bitmap aggregates whose states are not safe for AggState serialization, did not propagate QueryContext to AI aggregate combinators, allowed unsupported synchronous materialized view definitions, and ignored nested aggregate phase restrictions. Mark orthogonal bitmap aggregates as unsupported by AggState combinators, propagate AI query context by function-name prefix, reject combine functions in synchronous materialized view analysis, and delegate aggregate phase support to the nested function.

### Release note

Harden aggregate state combine validation and execution setup.

### Check List (For Author)

- Test:
    - Unit Test: CombineCombinatorTest
    - Regression test: Added synchronous materialized view rejection coverage to test_agg_state_avg; not run locally because no worktree-local cluster was started
    - BE Unit Test: Not run because run-be-ut.sh requires updating the datasketches-cpp submodule before compilation
- Behavior changed: Yes. Orthogonal bitmap AggState combinators and synchronous materialized views using _combine are rejected during analysis.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: Aggregate combine functions reused nested states that were not constructed with window semantics, and dynamic combinator resolution could wrap scalar function builders and later fail with an internal class cast. Reject combine functions during window analysis and only advertise AggState combinators for aggregate function builders.

### Release note

Reject aggregate combine window functions and scalar functions with AggState combinator suffixes during analysis.

### Check List (For Author)

- Test:
    - Unit Test: CombineCombinatorTest
    - Unit Test: CheckAndStandardizeWindowFunctionTest
- Behavior changed: Yes. Aggregate combine window functions and scalar functions with AggState combinator suffixes now return analysis errors.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: AI_AGG normalizes two-argument calls by adding a default resource, while AggState-producing combinators preserve the original arguments. This can create mismatched AggState signatures and invalid backend execution. Reject ai_agg_state and ai_agg_combine during function resolution until canonical AggState support is implemented.

### Release note

AI_AGG no longer supports the _state and _combine combinators.

### Check List (For Author)

- Test: Unit Test
    - CombineCombinatorTest
- Behavior changed: Yes. ai_agg_state and ai_agg_combine now fail analysis.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: FE Checkstyle rejected the imports in CombineCombinatorTest because AIAgg was not in the required custom lexicographical order. Sort the imports according to the repository rule.

### Release note

None

### Check List (For Author)

- Test: Manual test
    - mvn -T 48 clean checkstyle:check
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: AggState capability checks were inconsistent across SQL binding and synchronous materialized view rewriting. AI aggregates could still bind merge and union wrappers, orthogonal aggregate foreach support was accidentally blocked, combine accepted DISTINCT during overload matching and failed later with an unchecked exception, and synchronous materialized views bypassed the function-builder capability check. Use the common NotSupportAggState marker for AI and orthogonal aggregates, preserve foreach support, reject DISTINCT combine calls during binding, and enforce the capability in StateCombinator construction so all state creation paths share the same rule.

### Release note

Unsupported AggState wrappers are rejected during FE analysis while orthogonal foreach remains available.

### Check List (For Author)

- Test: Unit Test and regression test coverage
    - Unit Test: CombineCombinatorTest
    - Regression test: Added synchronous materialized view rejection coverage (not run locally)
    - FE Checkstyle: Passed
- Behavior changed: Yes. Unsupported AI AggState wrappers, DISTINCT combine calls, and unsupported synchronous materialized view state creation are rejected during analysis.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: Restore exact QueryContext dispatch for ai_agg, classify dynamically synthesized _combine functions as aggregate functions before argument binding while preserving UDF precedence, and leave incompatible CombineCombinator AggState casts to the standard cast checker instead of rewriting mismatched child metadata.

### Release note

Fix aggregate-state combine analysis and reject incompatible combine AggState casts with a normal analysis error.

### Check List (For Author)

- Test: Unit Test
    - CombineCombinatorTest
    - FillUpMissingSlotsTest#testCombineCombinatorBindsArgumentsInAggregateInputScope
    - BE clang-format check
    - FE checkstyle
- Behavior changed: Yes. Dynamic _combine calls bind in aggregate input scope, incompatible combine AggState casts are rejected, and QueryContext dispatch only applies to ai_agg.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: AggregateStateCombine delegated every output row to the nested serialize_without_key_to_column implementation. Nullable count resizes that destination to one row, so grouped combine output overwrote earlier states. Serialize grouped places through the nested batch interface and append the resulting states to the destination column. Also serialize a single result into an empty temporary column before appending it, preserving existing rows.

### Release note

Fix grouped _combine output for aggregate states whose single-state serializer does not append.

### Check List (For Author)

- Test: Unit Test
    - AggregateStateCombineTest.*
    - BE format, header hygiene, and clang-tidy checks
- Behavior changed: Yes, grouped _combine now preserves one state per group
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: `_combine` states could enter the existing loose AggState coercion path for explicit CAST and INSERT sinks. After aggregate extraction, the cast could no longer retarget the raw producer, so analysis accepted the conversion initially and rejected it later with an inconsistent error. Mark `_combine` output as exact-match-only during planning, preserve that policy across type conversion, and reject subtype or argument-nullability mismatches with an actionable analysis error. Existing `_state` loose coercion remains unchanged.

### Release note

Reject non-exact AggState CAST and INSERT coercion for `_combine` with a clear analysis error.

### Check List (For Author)

- Test:
    - Unit Test: Added exact subtype/nullability checks, explicit CAST coverage, and a compatibility assertion for existing `_state` coercion. Local execution was blocked by an unrelated `apache/master` testCompile error in `InsertIntoTableCommandTableStreamTest`; FE CheckStyle and main-source compilation passed.
    - Regression test: Added rejected non-exact CAST/INSERT cases and an accepted exact INSERT case; not run locally because the rebased master testCompile error prevented producing a complete FE build.
- Behavior changed: Yes. `_combine` output now accepts only exact AggState matches.
- Does this need documentation: No.
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: FunctionRegistry classified unknown `_combine` names as aggregate functions from the nested function name before argument-aware resolution. This diverged from the existing `_union` behavior and could bind an exact scalar UDF such as a two-argument `avg_combine` in the wrong aggregate scope. BE combine finalization also serialized into a temporary column and then deep-copied variable-width states even when the destination was empty. Remove the name-only `_combine` classification fallback, preserve argument-aware combinator and exact UDF resolution, and serialize directly into empty single-row and vector destinations while retaining the append-safe fallback for nonempty destinations.

### Release note

Resolve exact scalar UDFs ending in `_combine` correctly and avoid redundant copies when finalizing combine states into empty output columns.

### Check List (For Author)

- Test:
    - Unit Test: BE AggregateStateCombineTest passed all 4 tests, including an 8-by-4096-row grouped array-state combine/merge case. FE CombineCombinatorTest passed. FillUpMissingSlotsTest compiled, but its embedded FE setup could not run because the host TCP ephemeral port pool was exhausted before either target method started.
- Behavior changed: Yes. Unknown `_combine` names now follow the historical `_union` pre-binding behavior, and empty combine output columns use direct serialization.
- Does this need documentation: No.
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66942

Problem Summary: Dynamic aggregate-state combinators are synthesized from built-in aggregate names, but `_combine` pre-binding and final resolution diverged while attempting to preserve same-named UDF fallback. This could bind valid `avg_combine` arguments in aggregate-output scope before resolving the call as an aggregate. Treat all dynamically synthesized AggState combinator names as reserved built-in names, reject UDF creation with those names, remove the same-name UDF compatibility path, and verify HAVING and ORDER BY bind the raw input slot.

### Release note

Reserve dynamically synthesized aggregate-state combinator names for built-in functions.

### Check List (For Author)

- Test: Unit Test
    - CombineCombinatorTest
    - FillUpMissingSlotsTest
    - CreateFunctionTest
- Behavior changed: Yes. Dynamic aggregate-state combinator names can no longer be created as UDFs.
- Does this need documentation: No
@HappenLee
HappenLee force-pushed the feature/agg-state-combine branch from 4c317b6 to 4052cec Compare August 31, 2026 01:11
@HappenLee

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 50.00% (65/130) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.90% (34441/45376)
Line Coverage 60.87% (387497/636573)
Region Coverage 57.03% (325292/570415)
Branch Coverage 57.82% (148321/256500)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 17.44% (86/493) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16780 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 4052cec45676de451b1d703ac96bc37d741ad8e1, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17553	3041	2977	2977
q2	2067	254	210	210
q3	10284	903	519	519
q4	4677	247	200	200
q5	7684	562	383	383
q6	136	110	90	90
q7	541	505	390	390
q8	9235	911	900	900
q9	3507	2440	2384	2384
q10	6526	854	708	708
q11	398	197	175	175
q12	612	255	201	201
q13	18122	1503	1146	1146
q14	159	158	135	135
q15	q16	422	400	365	365
q17	1326	852	762	762
q18	3081	2301	2252	2252
q19	1121	824	790	790
q20	369	288	203	203
q21	4811	1764	1846	1764
q22	333	263	226	226
Total cold run time: 92964 ms
Total hot run time: 16780 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3352	3313	3303	3303
q2	502	395	371	371
q3	2284	2299	2156	2156
q4	1188	1154	889	889
q5	2160	2145	2122	2122
q6	164	114	86	86
q7	1041	898	837	837
q8	1594	1408	1409	1408
q9	3143	3091	3061	3061
q10	1855	1827	1613	1613
q11	351	274	245	245
q12	449	435	347	347
q13	1452	1515	1141	1141
q14	175	166	170	166
q15	q16	391	395	359	359
q17	3662	3330	3309	3309
q18	4838	4396	4752	4396
q19	854	782	786	782
q20	1155	992	831	831
q21	3827	3056	3276	3056
q22	394	344	343	343
Total cold run time: 34831 ms
Total hot run time: 30821 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 81599 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 4052cec45676de451b1d703ac96bc37d741ad8e1, data reload: false

query5	4270	404	334	334
query6	383	144	121	121
query7	4971	437	233	233
query8	297	124	113	113
query9	8699	2861	2863	2861
query10	371	213	187	187
query11	5364	1032	916	916
query12	117	71	75	71
query13	1205	447	312	312
query14	6049	2188	2087	2087
query14_1	1976	1952	1927	1927
query15	173	120	111	111
query16	909	373	349	349
query17	805	451	372	372
query18	2332	337	247	247
query19	168	146	115	115
query20	71	71	77	71
query21	199	102	87	87
query22	5399	5276	5331	5276
query23	6724	6143	5996	5996
query23_1	6044	5986	6019	5986
query24	7293	1123	753	753
query24_1	752	748	779	748
query25	406	283	237	237
query26	1221	222	126	126
query27	2816	431	253	253
query28	4670	1470	1489	1470
query29	910	429	326	326
query30	247	153	130	130
query31	821	397	326	326
query32	121	68	74	68
query33	449	209	165	165
query34	971	809	478	478
query35	392	399	338	338
query36	552	568	519	519
query37	119	85	66	66
query38	1000	831	801	801
query39	519	494	466	466
query39_1	491	458	463	458
query40	202	88	76	76
query41	53	56	52	52
query42	76	74	72	72
query43	236	241	203	203
query44	1008	534	543	534
query45	108	102	96	96
query46	769	830	542	542
query47	766	761	733	733
query48	318	294	219	219
query49	521	255	213	213
query50	703	257	202	202
query51	8183	8143	8053	8053
query52	71	68	59	59
query53	192	201	149	149
query54	226	200	197	197
query55	82	59	56	56
query56	186	183	183	183
query57	671	671	675	671
query58	209	165	148	148
query59	1197	1212	1118	1118
query60	242	182	170	170
query61	114	104	114	104
query62	359	205	176	176
query63	166	139	150	139
query64	2698	730	597	597
query65	1625	1628	1564	1564
query66	1820	271	201	201
query67	10061	9508	9383	9383
query68	3002	1179	768	768
query69	341	211	193	193
query70	654	668	620	620
query71	256	175	166	166
query72	2327	1771	1623	1623
query73	652	590	345	345
query74	1983	1226	1149	1149
query75	1176	1093	957	957
query76	2366	737	529	529
query77	257	258	202	202
query78	3894	3683	3221	3221
query79	2037	806	587	587
query80	1412	324	267	267
query81	481	159	131	131
query82	615	127	100	100
query83	279	209	188	188
query84	293	112	84	84
query85	787	346	287	287
query86	386	189	166	166
query87	1016	953	907	907
query88	2760	2097	2116	2097
query89	285	195	177	177
query90	1982	128	121	121
query91	127	120	99	99
query92	80	71	60	60
query93	1385	1076	760	760
query94	642	238	217	217
query95	525	244	296	244
query96	797	561	268	268
query97	1048	1060	1048	1048
query98	139	138	133	133
query99	412	347	305	305
Total cold run time: 176981 ms
Total hot run time: 81599 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.44 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 4052cec45676de451b1d703ac96bc37d741ad8e1, data reload: false

query1	0.00	0.00	0.01
query2	0.07	0.03	0.04
query3	0.24	0.11	0.11
query4	1.60	0.09	0.09
query5	0.17	0.16	0.16
query6	1.26	0.67	0.71
query7	0.03	0.01	0.00
query8	0.05	0.03	0.04
query9	0.28	0.21	0.22
query10	0.35	0.35	0.36
query11	0.16	0.12	0.11
query12	0.15	0.13	0.12
query13	0.30	0.31	0.31
query14	0.45	0.45	0.45
query15	0.36	0.35	0.35
query16	0.22	0.23	0.22
query17	0.69	0.70	0.65
query18	0.18	0.17	0.16
query19	1.10	1.17	1.15
query20	0.01	0.01	0.01
query21	15.47	0.16	0.12
query22	5.06	0.05	0.04
query23	16.17	0.25	0.10
query24	3.10	0.33	0.25
query25	0.11	0.04	0.04
query26	0.77	0.16	0.12
query27	0.04	0.02	0.03
query28	3.65	0.57	0.27
query29	12.45	3.17	2.54
query30	0.24	0.12	0.12
query31	2.75	0.37	0.17
query32	3.52	0.32	0.23
query33	1.43	1.33	1.42
query34	15.37	2.20	1.77
query35	1.77	1.75	1.67
query36	0.45	0.29	0.28
query37	0.05	0.04	0.03
query38	0.04	0.03	0.02
query39	0.03	0.03	0.02
query40	0.12	0.07	0.06
query41	0.07	0.02	0.03
query42	0.03	0.02	0.03
query43	0.03	0.02	0.03
Total cold run time: 90.39 s
Total hot run time: 14.44 s

@HappenLee
HappenLee merged commit 824401b into apache:master Sep 1, 2026
31 of 33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants