Skip to content

[fix](be) Harden FileScannerV2 schema and reader edge cases#65548

Open
Gabriel39 wants to merge 13 commits into
apache:masterfrom
Gabriel39:codex/fix-file-scanner-v2-review-issues
Open

[fix](be) Harden FileScannerV2 schema and reader edge cases#65548
Gabriel39 wants to merge 13 commits into
apache:masterfrom
Gabriel39:codex/fix-file-scanner-v2-review-issues

Conversation

@Gabriel39

@Gabriel39 Gabriel39 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: FileScannerV2 treated valid empty splits as scan failures, localized promoted nested struct predicates with mismatched operand types, and rejected whole Parquet schemas when unprojected leaves used unsupported logical types. Follow-up review also found that stop EOF could be counted as an empty file, unsupported requested leaves could reach metadata pruning before rejection, and reader-local page-cache range metadata lost warm non-exact reuse while lacking a bound. This change distinguishes stopped reads from empty splits, casts localized nested leaves back to table types, validates requested leaves before pruning and aggregate metadata, and shares bounded per-file range indexes through a bounded directory outside the ReadAt global hot path. Commented unit and regression cases cover empty CSV input, interrupted EOF, mixed Parquet struct leaf types, cross-reader non-exact cache reuse, bounded metadata, unprojected unsupported leaves, and an adjusted TIME_MILLIS predicate that statistics would otherwise prune.

A later review and external regression build exposed a separate COUNT pushdown ambiguity: COUNT(*) retained an arbitrary nullable scan slot after pruning, and BE inferred that placeholder as COUNT(column), producing 9015 instead of 10000 rows for special ORC data and 116 instead of 219 rows for Hive basic types. The fix now carries semantic COUNT arguments from Nereids through thrift to FileScannerV2; an empty argument list remains row-count semantics, while explicit COUNT(column) carries its mapped file column.

Release note

Fix FileScannerV2 compatibility for empty files, stopped reads, evolved nested predicates, and Parquet files containing unsupported logical columns; retain bounded cross-reader Parquet page-cache range reuse without a process-wide ReadAt lock. Also fix COUNT(*) aggregate pushdown when the planner-retained placeholder column contains NULL values.

Check List (For Author)

  • Test: Regression test / Unit Test
    • 56 targeted BE ASAN unit tests from the original change
    • 7 targeted BE ASAN COUNT pushdown unit tests, including the new nullable-placeholder COUNT(*) regression
    • Frontend rule coverage added for COUNT(*) and COUNT(column); execution on Gabriel was blocked by unrelated untracked cloud storage sources missing vendor SDKs
    • Existing external regression cases test_special_orc_formats and test_hive_basic_type reproduce the fixed COUNT(*) failures
    • test_file_scanner_v2_review_fixes regression suite
  • Behavior changed: Yes (valid empty splits are skipped, stop EOF is propagated, unsupported requested Parquet leaves fail before metadata pruning, and COUNT(*) is no longer inferred as COUNT(column))
  • Does this need documentation: No

@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?

@Gabriel39 Gabriel39 marked this pull request as ready for review July 13, 2026 11:34
@Gabriel39 Gabriel39 requested a review from yiguolei as a code owner July 13, 2026 11:34
@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at Jul 20th, 2026 12:23 AM.
Workflow run: https://github.com/apache/doris/actions/runs/29246737159

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17701	4116	4065	4065
q2	2057	330	206	206
q3	10268	1491	846	846
q4	4684	474	345	345
q5	7599	856	588	588
q6	178	175	135	135
q7	785	859	641	641
q8	9348	1823	1725	1725
q9	5696	4500	4466	4466
q10	6721	1824	1559	1559
q11	508	345	312	312
q12	714	558	416	416
q13	18096	3335	2775	2775
q14	265	260	244	244
q15	q16	793	778	711	711
q17	998	907	1043	907
q18	6966	6002	5579	5579
q19	1309	1208	1084	1084
q20	755	676	596	596
q21	6282	2849	2746	2746
q22	450	376	316	316
Total cold run time: 102173 ms
Total hot run time: 30262 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5120	4803	4763	4763
q2	304	360	221	221
q3	4989	5413	4697	4697
q4	2059	2166	1380	1380
q5	4728	4913	4663	4663
q6	227	179	129	129
q7	1913	1826	1541	1541
q8	2394	2109	2136	2109
q9	7713	7549	7220	7220
q10	4676	4630	4170	4170
q11	521	388	353	353
q12	731	744	531	531
q13	3014	3393	2773	2773
q14	268	273	253	253
q15	q16	678	691	601	601
q17	1269	1250	1250	1250
q18	7453	6938	6977	6938
q19	1111	1063	1102	1063
q20	2212	2224	1926	1926
q21	5238	4508	4418	4418
q22	530	457	416	416
Total cold run time: 57148 ms
Total hot run time: 51415 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 180840 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 57aa8de164269b487a79b6ca6ba0e1d1a393fefe, data reload: false

query5	4356	634	486	486
query6	446	215	203	203
query7	4849	623	331	331
query8	344	197	174	174
query9	8784	4065	4088	4065
query10	510	335	334	334
query11	5977	2355	2133	2133
query12	168	104	102	102
query13	1252	602	408	408
query14	6220	5228	4946	4946
query14_1	4261	4268	4278	4268
query15	208	203	181	181
query16	1020	485	466	466
query17	1087	740	574	574
query18	2422	462	340	340
query19	207	187	148	148
query20	111	111	115	111
query21	244	160	129	129
query22	13523	13609	13462	13462
query23	17470	16568	16136	16136
query23_1	16307	16293	16273	16273
query24	7575	1804	1331	1331
query24_1	1309	1324	1298	1298
query25	571	473	392	392
query26	1335	345	222	222
query27	2585	627	394	394
query28	4461	2036	2028	2028
query29	1087	646	509	509
query30	337	264	227	227
query31	1131	1094	991	991
query32	122	63	61	61
query33	519	330	257	257
query34	1164	1144	644	644
query35	769	792	673	673
query36	1432	1435	1269	1269
query37	151	106	99	99
query38	1875	1688	1647	1647
query39	918	932	871	871
query39_1	879	887	878	878
query40	248	168	145	145
query41	76	71	70	70
query42	97	98	93	93
query43	318	325	280	280
query44	1437	772	768	768
query45	202	190	180	180
query46	1056	1199	764	764
query47	2455	2432	2283	2283
query48	400	402	316	316
query49	614	439	328	328
query50	1088	429	341	341
query51	10789	10938	10884	10884
query52	89	94	79	79
query53	277	287	213	213
query54	294	248	246	246
query55	82	72	68	68
query56	314	324	302	302
query57	1462	1425	1335	1335
query58	304	274	248	248
query59	1571	1622	1477	1477
query60	334	304	268	268
query61	201	151	150	150
query62	713	653	592	592
query63	236	203	198	198
query64	2854	1066	844	844
query65	4855	4756	4776	4756
query66	1814	513	382	382
query67	29601	29403	29397	29397
query68	2992	1559	1020	1020
query69	405	306	263	263
query70	1064	970	937	937
query71	352	324	299	299
query72	3138	2827	2400	2400
query73	788	825	443	443
query74	5142	4995	4796	4796
query75	2603	2608	2229	2229
query76	2324	1183	792	792
query77	357	379	283	283
query78	12388	12502	11656	11656
query79	1392	1162	762	762
query80	1293	579	474	474
query81	522	318	286	286
query82	630	161	124	124
query83	362	322	294	294
query84	294	164	131	131
query85	971	596	512	512
query86	421	310	253	253
query87	1820	1830	1768	1768
query88	3661	2793	2747	2747
query89	454	407	352	352
query90	1932	201	187	187
query91	202	195	164	164
query92	62	63	59	59
query93	1596	1528	918	918
query94	722	358	329	329
query95	789	596	474	474
query96	1030	860	346	346
query97	2698	2713	2580	2580
query98	227	223	197	197
query99	1162	1177	1021	1021
Total cold run time: 265983 ms
Total hot run time: 180840 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.10	0.05	0.05
query3	0.26	0.14	0.13
query4	1.61	0.14	0.14
query5	0.25	0.25	0.22
query6	1.26	1.08	1.04
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.37	0.31	0.31
query10	0.55	0.54	0.56
query11	0.19	0.14	0.14
query12	0.18	0.14	0.14
query13	0.47	0.47	0.49
query14	1.01	1.00	1.02
query15	0.60	0.59	0.60
query16	0.31	0.32	0.31
query17	1.12	1.10	1.13
query18	0.23	0.21	0.21
query19	2.02	2.03	1.96
query20	0.02	0.01	0.01
query21	15.46	0.23	0.14
query22	4.87	0.06	0.06
query23	16.12	0.31	0.13
query24	3.02	0.44	0.32
query25	0.12	0.04	0.03
query26	0.73	0.22	0.16
query27	0.04	0.04	0.04
query28	3.57	0.89	0.56
query29	12.49	4.08	3.18
query30	0.27	0.15	0.16
query31	2.77	0.61	0.31
query32	3.21	0.59	0.48
query33	3.15	3.29	3.17
query34	15.63	4.23	3.53
query35	3.51	3.52	3.53
query36	0.54	0.43	0.44
query37	0.08	0.06	0.07
query38	0.06	0.04	0.04
query39	0.03	0.03	0.03
query40	0.18	0.16	0.15
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.67 s
Total hot run time: 24.99 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 67.69% (44/65) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.01% (23635/41458)
Line Coverage 40.68% (231256/568436)
Region Coverage 36.58% (182762/499619)
Branch Coverage 37.69% (81680/216740)

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at Jul 20th, 2026 12:23 AM.
Workflow run: https://github.com/apache/doris/actions/runs/29255600260

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@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.

I found four issues that should be fixed before merging.

Checkpoint summary: the PR is focused on FileScannerV2/format-v2 edge cases and has useful unit/regression coverage, but the current implementation still has correctness issues around stop-vs-empty EOF handling and unsupported Parquet logical types. The page-cache range refactor also introduces two performance/lifecycle regressions: non-exact warm-cache reuse is lost across readers, and the new reader-local index is unbounded. I did not run BE/regression tests in this review-only runner; the checkout is a single shallow commit with the base/parent SHA unavailable, so validation was static against the bundled authoritative PR diff and GitHub PR metadata. User focus: no additional focus points were provided.

Comment thread be/src/exec/scan/file_scanner_v2.cpp Outdated
Comment thread be/src/format_v2/parquet/parquet_column_schema.cpp
Comment thread be/src/format_v2/parquet/parquet_file_context.cpp Outdated
Comment thread be/src/format_v2/parquet/parquet_file_context.cpp
@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@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.

I found two remaining correctness issues after the current fixes: primitive COUNT(column) aggregate pushdown can still bypass the unsupported Parquet logical-type validation, and the generic EOF skip can still downgrade a malformed Native file into an empty split. I rechecked the scanner EOF, unsupported Parquet type, nested column-mapper, and page-cache range-directory surfaces against the existing review threads and did not find additional distinct findings.

Validation was static only; I did not run builds or tests because this review invocation is read-only per the bundled prompt.

Comment thread be/src/format_v2/parquet/parquet_reader.cpp
Comment thread be/src/exec/scan/file_scanner_v2.cpp
@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 83.13% (138/166) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.10% (23692/41495)
Line Coverage 40.80% (232166/569029)
Region Coverage 36.65% (183337/500274)
Branch Coverage 37.79% (82071/217148)

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17656	4100	4127	4100
q2	2027	336	203	203
q3	10274	1467	843	843
q4	4684	479	338	338
q5	7557	860	570	570
q6	188	170	140	140
q7	774	838	617	617
q8	9333	1621	1546	1546
q9	5651	4483	4403	4403
q10	6857	1822	1539	1539
q11	500	345	324	324
q12	696	560	436	436
q13	18085	3401	2728	2728
q14	279	263	239	239
q15	q16	791	783	711	711
q17	1024	926	1039	926
q18	7246	5876	5598	5598
q19	1287	1207	1020	1020
q20	751	667	514	514
q21	5913	2684	2562	2562
q22	435	368	302	302
Total cold run time: 102008 ms
Total hot run time: 29659 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4617	4305	4322	4305
q2	295	317	222	222
q3	4647	5030	4422	4422
q4	2080	2168	1369	1369
q5	4522	4385	4369	4369
q6	227	176	131	131
q7	1915	2099	1724	1724
q8	2627	2283	2257	2257
q9	8267	8290	7892	7892
q10	4765	4732	4287	4287
q11	604	437	369	369
q12	767	773	557	557
q13	3308	3543	2988	2988
q14	310	301	278	278
q15	q16	726	746	661	661
q17	1390	1420	1362	1362
q18	8020	7518	7306	7306
q19	1128	1158	1074	1074
q20	2198	2220	1936	1936
q21	5385	4706	4518	4518
q22	521	461	392	392
Total cold run time: 58319 ms
Total hot run time: 52419 ms

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@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.

I found one remaining correctness issue in the COUNT aggregate request construction. The rest of the reviewed areas look covered by the current fixes or by existing review threads.

Checkpoint conclusions: the PR goal is clear and mostly addressed; the change is focused around FileScannerV2/format-v2 review fixes; I did not find new concurrency or lifecycle problems in the scanner stop/empty split or page-cache range-directory paths; no new config or persistence compatibility changes are introduced; existing parallel paths were checked for scanner EOF, Parquet/ORC aggregate semantics, and page-cache behavior; test coverage was reviewed statically but not run in this review-only environment; observability changes are limited to the empty-file counter and look consistent. User focus: no additional user-provided focus beyond the full PR review.

@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.

Correcting the inline anchor for the COUNT aggregate request construction issue; see inline.

Comment thread be/src/format_v2/table_reader.h Outdated
@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17696	4106	4103	4103
q2	2037	340	205	205
q3	10254	1438	841	841
q4	4689	496	343	343
q5	7518	865	591	591
q6	183	175	139	139
q7	782	824	631	631
q8	9375	1584	1659	1584
q9	5587	4396	4348	4348
q10	6768	1811	1499	1499
q11	507	344	315	315
q12	713	571	421	421
q13	18183	3321	2764	2764
q14	282	268	236	236
q15	q16	790	793	723	723
q17	958	1006	991	991
q18	7571	5742	5443	5443
q19	1325	1258	1056	1056
q20	758	666	562	562
q21	6404	2882	2777	2777
q22	471	392	321	321
Total cold run time: 102851 ms
Total hot run time: 29893 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5150	4750	5218	4750
q2	301	335	222	222
q3	4956	5291	4719	4719
q4	2109	2191	1373	1373
q5	4944	4716	4665	4665
q6	231	182	128	128
q7	1978	1738	1548	1548
q8	2400	2119	2150	2119
q9	7617	7154	7184	7154
q10	4634	4560	4130	4130
q11	534	388	354	354
q12	737	758	531	531
q13	3033	3357	2797	2797
q14	274	282	252	252
q15	q16	683	693	610	610
q17	1283	1248	1238	1238
q18	7406	6868	7006	6868
q19	1077	1068	1052	1052
q20	2226	2221	1951	1951
q21	5267	4598	4447	4447
q22	523	452	429	429
Total cold run time: 57363 ms
Total hot run time: 51337 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 178193 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 cc9750751fcd638dd86b621a01fc8855fb5cec69, data reload: false

query5	4323	642	491	491
query6	485	220	198	198
query7	4855	621	344	344
query8	361	187	174	174
query9	8757	4037	4033	4033
query10	478	393	319	319
query11	5946	2330	2132	2132
query12	164	108	106	106
query13	1321	608	416	416
query14	6259	5256	4885	4885
query14_1	4268	4270	4229	4229
query15	216	205	179	179
query16	1013	475	476	475
query17	954	727	599	599
query18	2485	480	351	351
query19	228	193	154	154
query20	113	108	111	108
query21	238	155	135	135
query22	13579	13501	13262	13262
query23	17553	16550	16073	16073
query23_1	16226	16210	16308	16210
query24	7539	1784	1286	1286
query24_1	1324	1270	1279	1270
query25	574	470	399	399
query26	1339	336	208	208
query27	2639	570	359	359
query28	4433	2018	2003	2003
query29	1103	634	501	501
query30	338	262	234	234
query31	1123	1097	970	970
query32	131	63	64	63
query33	536	356	294	294
query34	1184	1100	640	640
query35	764	801	654	654
query36	1198	1196	1040	1040
query37	152	110	95	95
query38	1885	1698	1597	1597
query39	878	898	836	836
query39_1	827	840	852	840
query40	260	157	142	142
query41	66	64	63	63
query42	92	91	91	91
query43	321	324	280	280
query44	1392	772	777	772
query45	188	185	180	180
query46	1072	1170	763	763
query47	2152	2142	2054	2054
query48	383	388	289	289
query49	592	408	333	333
query50	996	393	323	323
query51	10996	10692	10941	10692
query52	86	87	76	76
query53	261	279	203	203
query54	284	239	215	215
query55	73	72	65	65
query56	304	279	273	273
query57	1328	1290	1232	1232
query58	305	267	264	264
query59	1579	1668	1463	1463
query60	310	275	254	254
query61	151	152	150	150
query62	545	498	436	436
query63	241	197	197	197
query64	2894	1063	838	838
query65	4697	4614	4652	4614
query66	1836	504	380	380
query67	29388	29303	29095	29095
query68	3078	1527	928	928
query69	400	300	347	300
query70	1107	1022	958	958
query71	364	313	292	292
query72	3092	2692	2479	2479
query73	845	756	426	426
query74	5038	4926	4719	4719
query75	2511	2541	2119	2119
query76	2365	1170	801	801
query77	354	367	282	282
query78	11970	11806	11311	11311
query79	1448	1138	732	732
query80	1305	540	449	449
query81	526	311	273	273
query82	1069	155	120	120
query83	395	318	292	292
query84	325	157	135	135
query85	985	602	508	508
query86	451	300	288	288
query87	1826	1825	1757	1757
query88	3706	2820	2817	2817
query89	434	384	326	326
query90	1921	190	195	190
query91	212	192	173	173
query92	66	65	57	57
query93	1592	1504	1041	1041
query94	845	374	326	326
query95	769	578	469	469
query96	1030	799	381	381
query97	2647	2651	2489	2489
query98	216	206	201	201
query99	1082	1113	969	969
Total cold run time: 264932 ms
Total hot run time: 178193 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.28	0.14	0.14
query4	1.61	0.14	0.15
query5	0.27	0.22	0.22
query6	1.25	1.07	1.10
query7	0.04	0.00	0.00
query8	0.06	0.04	0.03
query9	0.38	0.33	0.31
query10	0.56	0.55	0.58
query11	0.20	0.14	0.15
query12	0.18	0.15	0.16
query13	0.49	0.48	0.47
query14	1.04	1.02	1.01
query15	0.61	0.58	0.59
query16	0.34	0.34	0.33
query17	1.08	1.12	1.08
query18	0.23	0.23	0.22
query19	2.01	1.93	1.92
query20	0.01	0.02	0.01
query21	15.46	0.22	0.13
query22	4.91	0.06	0.05
query23	16.10	0.30	0.12
query24	2.89	0.40	0.32
query25	0.12	0.04	0.05
query26	0.75	0.20	0.14
query27	0.06	0.04	0.04
query28	3.51	0.92	0.53
query29	12.51	4.09	3.23
query30	0.27	0.15	0.17
query31	2.78	0.59	0.31
query32	3.22	0.59	0.49
query33	3.21	3.15	3.21
query34	15.52	4.23	3.54
query35	3.58	3.56	3.55
query36	0.56	0.44	0.42
query37	0.10	0.06	0.07
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.16	0.16
query41	0.10	0.03	0.02
query42	0.04	0.04	0.03
query43	0.05	0.04	0.04
Total cold run time: 96.75 s
Total hot run time: 25.01 s

Gabriel39 added a commit to Gabriel39/incubator-doris that referenced this pull request Jul 14, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65548

Problem Summary: File aggregate pushdown inferred COUNT(column) from a single post-pruning scan mapping. COUNT(*) also retains an arbitrary placeholder slot, so a nullable placeholder made Parquet and ORC readers count non-null values instead of rows. Carry the semantic COUNT arguments from Nereids through the scan thrift contract, keep true COUNT(*) column-free, and fall back when an explicit COUNT argument cannot be mapped directly. Also default split-level conjunct overrides to nullopt so existing standalone readers compile and preserve their initial predicate snapshot.

### Release note

Fix COUNT(*) results for Parquet and ORC file scans when the retained placeholder column contains NULL values.

### Check List (For Author)

- Test: Unit Test
    - 7 targeted Backend ASAN unit tests
    - Added Frontend rule coverage for COUNT(*) and COUNT(column); execution was blocked by unrelated untracked cloud storage sources missing vendor SDKs in the validation workspace
- Behavior changed: Yes (file aggregate pushdown now distinguishes COUNT(*) from COUNT(column) explicitly)
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 69.44% (25/36) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65548

Problem Summary: File-local nested predicate rewriting ignored nullable-file to required-table schema contracts, allowing NULL rows to be filtered before TableReader could reject them. Iceberg equality-delete also used an arbitrary physical column as a row-count carrier when all keys were missing, so an unsupported unprojected Parquet leaf could fail an otherwise valid projection. Keep such nested predicates above TableReader and use virtual row position as the equality-delete carrier.

### Release note

Fix schema-evolved nested predicate validation and Iceberg equality-delete scans with unsupported unprojected Parquet columns.

### Check List (For Author)

- Test: Unit Test
    - ./run-be-ut.sh --run --filter="ColumnMapperCastTest.NestedElementAt*:IcebergV2ReaderTest.IcebergEqualityDelete*" -j 96 (19 tests passed)
- Behavior changed: Yes. Unsafe nested predicates remain table-level, and missing-key equality deletes use virtual row position for batch sizing.
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 88.46% (345/390) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.25% (23827/41622)
Line Coverage 41.00% (234251/571289)
Region Coverage 36.83% (184956/502162)
Branch Coverage 37.96% (82883/218359)

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@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.

I found one remaining correctness issue in the current head after checking the updated COUNT argument plumbing and existing review threads.

Checkpoint conclusions:

  • Goal/current code: the PR is a focused follow-up for FileScannerV2/format-v2 EOF handling, Parquet unsupported type validation, page-cache range metadata, struct predicate localization, and explicit COUNT argument propagation. Most previously reported paths are addressed, but external table-level COUNT split planning still has a wrong-result path for COUNT(col).
  • Scope: the changes are concentrated and supported by BE/FE unit tests plus a TVF regression case.
  • Concurrency/lifecycle: scanner stop-vs-empty EOF handling, TableReader abort/close paths, and page-cache range-directory locking/caps were reviewed; no new non-duplicate lifecycle issue was found.
  • Compatibility/parallel paths: FE translator, V1 scanner, V2 scanner/TableReader, table-level row count, Parquet aggregate validation, Iceberg/Paimon table-format planning, and rolling-upgrade duplicate context were checked. The accepted issue is distinct from the existing BE table-level-row-count comment because it happens before BE fallback.
  • Tests: reviewed statically. I did not run builds or tests because the review prompt makes this a read-only review runner, and this checkout is missing .worktree_initialized, thirdparty/installed, and thirdparty/installed/bin/protoc.
  • User focus: no additional user-provided review focus.

Subagent convergence: Round 1 used FE, BE, format-v2, COUNT-risk, and EOF/unsupported/page-cache-risk subagents. Round 2 reran convergence after accepting the COUNT split-pruning finding; both convergence agents returned NO_NEW_VALUABLE_FINDINGS.

@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.

Correcting the inline anchor for the COUNT split-pruning issue; see inline.

@Override
protected void toThrift(TPlanNode planNode) {
planNode.setPushDownAggTypeOpt(pushDownAggNoGroupingOp);
planNode.setPushDownCountSlotIds(

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.

This still leaves a pre-BE table-format COUNT path using the raw COUNT flag. For COUNT(required_col), the planner now serializes a non-empty push_down_count_slot_ids, and BE correctly falls back instead of consuming table-level row counts. But Iceberg and Paimon decide their table-level count split planning before BE sees this field: IcebergScanNode.isBatchMode()/doGetSplits() and PaimonScanNode check only getPushDownAggNoGroupingOp() == COUNT, then keep just one or parallel * numBackends count splits and assign the total row count to them. Since BE ignores that assigned count for non-empty arguments, it scans only the retained subset of real splits, so COUNT(non_null_col) can undercount any table with more data splits than the retained representatives. Please gate the Iceberg/Paimon table-level count split reduction on the explicit COUNT(*) marker, or otherwise avoid dropping real splits whenever pushDownCountSlotIds is non-empty.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17597	4070	3994	3994
q2	2011	325	200	200
q3	10228	1411	847	847
q4	4685	485	344	344
q5	7505	844	569	569
q6	190	175	137	137
q7	749	827	612	612
q8	9367	1539	1563	1539
q9	5590	4332	4382	4332
q10	6739	1757	1451	1451
q11	505	362	311	311
q12	699	553	435	435
q13	18093	3505	2779	2779
q14	267	262	249	249
q15	q16	791	769	706	706
q17	1260	895	897	895
q18	6869	5912	5619	5619
q19	1395	1267	1075	1075
q20	771	650	541	541
q21	6074	2568	2409	2409
q22	443	360	295	295
Total cold run time: 101828 ms
Total hot run time: 29339 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4376	4283	4275	4275
q2	296	321	213	213
q3	4554	4964	4421	4421
q4	2048	2166	1342	1342
q5	4397	4303	4280	4280
q6	223	172	126	126
q7	1677	1829	1821	1821
q8	2651	2195	2172	2172
q9	7973	8149	7758	7758
q10	4683	4642	4182	4182
q11	576	410	373	373
q12	736	776	556	556
q13	3181	3631	2936	2936
q14	308	301	292	292
q15	q16	726	749	653	653
q17	1354	1281	1345	1281
q18	8246	7366	7312	7312
q19	1154	1103	1138	1103
q20	2229	2217	1942	1942
q21	5234	4581	4317	4317
q22	510	471	411	411
Total cold run time: 57132 ms
Total hot run time: 51766 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 178329 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 aa2a87fb2ef34c65aeb2018ffa397025bc799c71, data reload: false

query5	4347	656	498	498
query6	477	239	212	212
query7	4849	590	336	336
query8	339	189	174	174
query9	8791	4157	4132	4132
query10	474	365	307	307
query11	5971	2332	2147	2147
query12	167	111	102	102
query13	1256	575	428	428
query14	6284	5235	4898	4898
query14_1	4282	4333	4275	4275
query15	216	202	182	182
query16	1044	493	466	466
query17	1137	721	585	585
query18	2717	491	356	356
query19	233	192	157	157
query20	111	109	111	109
query21	234	165	137	137
query22	13513	13593	13360	13360
query23	17389	16436	16203	16203
query23_1	16275	16266	16233	16233
query24	7533	1797	1269	1269
query24_1	1307	1276	1302	1276
query25	574	469	386	386
query26	1326	336	204	204
query27	2553	558	388	388
query28	4438	2020	2001	2001
query29	1103	633	496	496
query30	352	263	234	234
query31	1119	1106	985	985
query32	117	64	64	64
query33	559	314	243	243
query34	1143	1141	652	652
query35	757	791	660	660
query36	1198	1180	1063	1063
query37	153	106	92	92
query38	1868	1658	1646	1646
query39	900	878	848	848
query39_1	845	827	836	827
query40	248	160	139	139
query41	64	61	63	61
query42	89	91	91	91
query43	335	328	279	279
query44	1455	798	774	774
query45	195	195	176	176
query46	1113	1196	722	722
query47	2141	2108	2037	2037
query48	391	418	289	289
query49	569	412	307	307
query50	1055	408	320	320
query51	10848	10613	10670	10613
query52	85	86	80	80
query53	255	285	199	199
query54	273	230	206	206
query55	75	70	64	64
query56	273	292	284	284
query57	1326	1276	1211	1211
query58	292	273	252	252
query59	1553	1693	1463	1463
query60	315	265	260	260
query61	159	147	150	147
query62	538	495	426	426
query63	237	197	198	197
query64	2793	1039	845	845
query65	4756	4633	4659	4633
query66	1760	509	373	373
query67	29357	29287	29185	29185
query68	3545	1609	1022	1022
query69	422	312	267	267
query70	1069	957	1000	957
query71	333	343	309	309
query72	3058	2789	2324	2324
query73	822	798	442	442
query74	5056	4890	4709	4709
query75	2521	2496	2139	2139
query76	2324	1185	815	815
query77	361	384	286	286
query78	11896	11938	11388	11388
query79	1377	1175	779	779
query80	1317	527	445	445
query81	525	330	283	283
query82	629	152	125	125
query83	362	314	298	298
query84	283	164	129	129
query85	949	593	502	502
query86	423	286	274	274
query87	1828	1825	1750	1750
query88	3672	2836	2744	2744
query89	420	368	326	326
query90	2069	200	188	188
query91	199	189	165	165
query92	62	63	54	54
query93	1663	1558	975	975
query94	719	354	324	324
query95	786	578	453	453
query96	1082	797	336	336
query97	2666	2626	2511	2511
query98	209	202	200	200
query99	1114	1099	990	990
Total cold run time: 264728 ms
Total hot run time: 178329 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.25	0.14	0.14
query4	1.64	0.13	0.13
query5	0.24	0.24	0.22
query6	1.27	1.09	1.03
query7	0.04	0.00	0.00
query8	0.06	0.04	0.04
query9	0.40	0.31	0.32
query10	0.56	0.55	0.54
query11	0.19	0.15	0.14
query12	0.18	0.14	0.14
query13	0.48	0.48	0.48
query14	1.01	1.02	0.99
query15	0.62	0.62	0.60
query16	0.31	0.31	0.34
query17	1.13	1.09	1.12
query18	0.23	0.21	0.21
query19	2.03	2.02	1.90
query20	0.02	0.02	0.01
query21	15.43	0.23	0.13
query22	4.81	0.06	0.05
query23	16.16	0.31	0.12
query24	3.03	0.45	0.33
query25	0.11	0.05	0.04
query26	0.74	0.22	0.16
query27	0.05	0.03	0.03
query28	3.47	0.95	0.53
query29	12.54	4.09	3.21
query30	0.27	0.15	0.15
query31	2.77	0.61	0.31
query32	3.23	0.60	0.49
query33	3.15	3.34	3.22
query34	15.72	4.22	3.53
query35	3.54	3.56	3.56
query36	0.55	0.46	0.43
query37	0.08	0.07	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.16	0.16
query41	0.09	0.04	0.03
query42	0.04	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.85 s
Total hot run time: 24.99 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 63.89% (23/36) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 91.75% (367/400) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.88% (30400/40599)
Line Coverage 58.98% (334801/567682)
Region Coverage 55.49% (279668/504027)
Branch Coverage 56.85% (124194/218441)

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65548

Problem Summary: Iceberg and Paimon table-level COUNT planning used only the aggregate opcode, so COUNT(column) could discard most real data splits and attach a metadata row count. Backend correctly rejects that shortcut for explicit COUNT arguments and falls back to reading the column, but then scans only the retained representatives and undercounts multi-split tables. Restrict FE metadata COUNT split reduction to the explicit COUNT(*) marker and preserve all real splits for COUNT(column).

### Release note

Fix incorrect COUNT(column) results on multi-split Iceberg and Paimon tables when table-level count pushdown is enabled.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.datasource.iceberg.source.IcebergScanNodeTest,org.apache.doris.datasource.paimon.source.PaimonScanNodeTest (23 tests passed)
- Behavior changed: Yes. Only COUNT(*)/COUNT(1) may replace real Iceberg or Paimon splits with metadata count representatives; COUNT(column) keeps all real splits.
- Does this need documentation: No
@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@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 complete. I found one remaining correctness issue and submitted it inline.

Checkpoint conclusions:

  • Goal/test coverage: the PR mostly addresses the COUNT argument split, empty-file EOF handling, unsupported Parquet validation, page-cache range reuse, and struct-predicate localization, but it is missing coverage for COUNT(*) when column pruning keeps an unsupported Parquet placeholder.
  • Scope/focus: the changes are focused on the reviewed scanner/format/planner paths. The user focus file contains no additional focus points.
  • Compatibility and parallel paths: reviewed FE/BE thrift propagation, V1/V2 scanners, TableReader, Iceberg/Paimon table-level count handling, and Hive/TVF parallel paths. No additional non-duplicate issue found.
  • Error handling and data correctness: reviewed EOF status propagation and unsupported logical-type rejection. Native zero-byte EOF concerns are already covered by existing review threads; the inline comment covers the remaining distinct data-correctness gap.
  • Concurrency/lifecycle/performance: reviewed page-cache range directory lifetime, locking, stale-range pruning, and split/reader lifecycle. No additional issue found.
  • Tests: static review only; no builds or tests were run per the review prompt.

Round 2 convergence completed with all subagents returning NO_NEW_VALUABLE_FINDINGS for the final comment set.

// bloom filters or page indexes inspect their physical fallback type. For example, a predicate
// on TIME_MILLIS must fail here even when its INT32 statistics would prune every row group;
// otherwise the same unsupported SELECT could fail or silently succeed depending on data.
RETURN_IF_ERROR(validate_requested_columns_supported(_state->file_schema, *request_snapshot));

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.

This still lets an explicit COUNT(*) observe the column-pruning placeholder before the aggregate path can use the empty COUNT request. TableReader::open_reader() builds a normal FileScanRequest from _projected_columns and calls reader->open(file_request) before _try_materialize_aggregate_pushdown_rows(). Since Nereids keeps one minimum-width scan slot when COUNT(*) needs no output slots, a file whose retained placeholder is an unsupported TIME_MILLIS leaf reaches this validation in non_predicate_columns and fails, even though the later COUNT() aggregate request would correctly have no columns and could answer from row-group counts. Please skip placeholder validation/open for explicit COUNT() metadata pushdown, or use a supported/virtual carrier, and add coverage where COUNT(*) is planned over an unsupported placeholder column.

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65548

Problem Summary: Explicit COUNT(*) keeps a planner placeholder scan slot even though file aggregate metadata needs no column. TableReader opened the normal Parquet scan request before aggregate materialization, so an unsupported logical leaf such as adjusted TIME_MILLIS could be rejected as if it were user-projected and make COUNT(*) fail. Mark non-predicate columns as placeholders only after the existing COUNT(*) aggregate safety gate succeeds, and skip unsupported-type validation only for those placeholders while preserving strict predicate, COUNT(column), and ordinary projection validation.

### Release note

Fix COUNT(*) failures on Parquet files where column pruning retains an unsupported logical-type placeholder.

### Check List (For Author)

- Test: Unit Test
    - run-be-ut.sh targeted 4 tests (all passed)
- Behavior changed: Yes. Eligible COUNT(*) metadata pushdown ignores planner-only non-predicate placeholder validation; actual projections and COUNT(column) remain unchanged.
- Does this need documentation: No
@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@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.

I completed the requested review cycle against the authoritative diff and existing review threads, including a second convergence round after accepting the remaining candidate. Subagents D, E, and the focused M1 reviewer all returned NO_NEW_VALUABLE_FINDINGS for the current final comment set.

I found one remaining non-duplicate correctness issue: explicit COUNT() can still fail in the delete-forced row-scan fallback path because the arbitrary retained placeholder is only marked as a COUNT() placeholder when aggregate metadata pushdown is supported. Existing threads already cover the rolling-upgrade, V1/table-level COUNT, Native EOF, page-cache, struct nullability, equality-delete carrier, and metadata-eligible COUNT(*) placeholder cases, so I did not duplicate them.

Review checkpoints: the patch is focused on prior review fixes, but M1 leaves a correctness gap; FE/BE COUNT propagation, V1/V2 scanner behavior, Iceberg/Paimon table-level split planning, parquet unsupported-column validation, Native EOF handling, struct predicate localization, page-cache lifecycle, and delete/equality-delete carriers were checked. No config, transaction, persistence, write-path, or observability change introduced a separate finding in this diff. I did not run builds or tests, per the review-only instructions.

Comment thread be/src/format_v2/table_reader.h Outdated
// would fail before the empty aggregate request can count rows from footer metadata. Mark
// placeholders only after the same safety gate used by aggregate materialization succeeds;
// COUNT(col), filters, deletes and pending runtime filters keep normal column validation.
file_request->non_predicate_columns_are_count_star_placeholders =

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.

This still leaves a COUNT() fallback path observing the arbitrary placeholder column. The marker is set only when _supports_aggregate_pushdown(COUNT) is true, but that returns false as soon as position deletes, deletion vectors, or Iceberg equality deletes are present. When table-level row count is not assigned, get_block() then falls through to the normal file-reader path; Parquet validates and later reads every non-predicate column because the marker is false, while delete filtering only needs the virtual row-position predicate column. So an Iceberg split whose retained COUNT() placeholder is an unsupported TIME_MILLIS leaf can reject COUNT(*) even though the value is never part of the aggregate. Please carry the explicit COUNT(*) placeholder state into the delete-filter fallback path and use a row-position/default-row carrier, or otherwise avoid validating/reading the placeholder while still validating real predicate/delete columns.

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65548

Problem Summary: Explicit COUNT(*) keeps a planner-only scan slot after column pruning. The previous implementation marked that slot only when metadata aggregate pushdown was eligible. Position deletes, deletion vectors, equality deletes, predicates, or pending runtime filters disable aggregate pushdown and fall back to row scanning, causing Parquet to validate and decode the arbitrary placeholder again. An unsupported logical leaf such as adjusted TIME_MILLIS could therefore reject COUNT(*) even though only the surviving row count was needed. Record exact COUNT(*) placeholder column ids independently of aggregate eligibility, keep real predicate and delete columns strict, and synthesize default values for surviving placeholder rows without physical column IO.

### Release note

Fix COUNT(*) fallback scans over Parquet files whose planner-only placeholder uses an unsupported logical type.

### Check List (For Author)

- Test: Unit Test
    - 4 targeted BE ASAN unit tests passed
- Behavior changed: Yes. COUNT(*) fallback scans no longer validate or read planner-only non-predicate placeholders; predicates, delete keys, COUNT(column), and normal projections remain unchanged.
- Does this need documentation: No
@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.62% (1908/2458)
Line Coverage 64.47% (34148/52966)
Region Coverage 64.91% (17574/27076)
Branch Coverage 54.06% (9419/17424)

@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.

I found two issues that should be fixed before this lands.

  1. A struct-child predicate fallback can run a non-lossless file-to-table cast below TableReader and filter away rows that normal table materialization would reject.
  2. Hive and TVF COUNT(col) fallback scans can still lose normal file-split parallelism because their no-split shortcut checks the raw COUNT opcode instead of the semantic COUNT(*) state.

Review checkpoints: the PR addresses several prior review issues, but these two gaps remain. Compatibility and mixed-version COUNT handling were reviewed; the new-field rolling-upgrade concern is already covered by an existing thread. BE scanner/format lifecycle, EOF handling, unsupported Parquet placeholder handling, page-cache range metadata, FE COUNT argument propagation, and changed test coverage were rechecked with subagents. No additional user-provided review focus was specified. I did not run builds or tests in this review-only runner.

if (file_literal != nullptr) {
children[literal_child_idx] = std::move(file_literal);
} else {
children[struct_child_idx] = cast_file_expr_to_table_type(children[struct_child_idx],

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.

This fallback still runs a non-lossless file-to-table cast below TableReader, so it can hide rows that normal materialization would reject. For example, take an old file STRUCT<a: BIGINT NOT NULL> mapped to a required table STRUCT<a: INT NOT NULL> and filter s.a = 1. Because BIGINT->INT is not lossless, rewrite_literal_to_file_type() returns null, but this branch still localizes the predicate as CAST(file_s.a AS INT) = 1. In non-strict mode an overflow value such as 2147483648 becomes NULL, the predicate drops that row, and _align_column_nullability() never sees the cast-produced NULL that the normal table materialization path would reject for the required INT child. Please keep this predicate at table level whenever the file-to-table leaf cast is not lossless, or otherwise prove the fallback cast cannot change the NULL/error behavior before filtering.

*/
protected boolean isTableLevelCountStarPushdown() {
return pushDownAggNoGroupingOp == TPushAggOp.COUNT && pushDownCountSlotIds.isEmpty();
}

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.

This semantic COUNT() helper also needs to cover the other FE count-split shortcuts. Hive and TVF still check only getPushDownAggNoGroupingOp() == COUNT before calling FileSplitter.needSplitForCountPushdown(). When that returns false, they pass splittable=false to splitFile(), so a large splittable file becomes one full-file range. That was fine when the scan really used metadata only, but this PR makes non-empty COUNT arguments fall back to real row scans for unsafe mappings, filters/deletes, or old/unknown semantics. A Hive/TVF COUNT(col) fallback can therefore lose normal scan parallelism even though the result is still correct. Please gate those no-split shortcuts on the explicit COUNT()/COUNT(1) state, or keep normal splitting whenever pushDownCountSlotIds is non-empty.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17625	4154	4093	4093
q2	2014	320	204	204
q3	10272	1464	836	836
q4	4683	471	354	354
q5	7637	858	580	580
q6	181	174	142	142
q7	767	819	598	598
q8	9324	1603	1598	1598
q9	5619	4432	4366	4366
q10	6792	1768	1486	1486
q11	507	343	323	323
q12	715	563	448	448
q13	18152	3421	2749	2749
q14	268	257	242	242
q15	q16	782	775	708	708
q17	950	1048	901	901
q18	7011	5759	5649	5649
q19	1160	1372	1129	1129
q20	731	628	547	547
q21	5795	2699	2423	2423
q22	442	356	309	309
Total cold run time: 101427 ms
Total hot run time: 29685 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4465	4309	4351	4309
q2	277	318	217	217
q3	4569	4991	4419	4419
q4	2082	2148	1367	1367
q5	4409	4280	4290	4280
q6	232	174	131	131
q7	1730	1986	1853	1853
q8	2648	2211	2231	2211
q9	8035	8218	7799	7799
q10	4797	4674	4273	4273
q11	564	429	388	388
q12	794	796	576	576
q13	3288	3534	2992	2992
q14	289	291	271	271
q15	q16	710	738	653	653
q17	1366	1342	1380	1342
q18	8002	7520	7378	7378
q19	1181	1144	1093	1093
q20	2209	2223	1947	1947
q21	5325	4747	4478	4478
q22	526	445	398	398
Total cold run time: 57498 ms
Total hot run time: 52375 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177238 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 ebd5175cdb97413c4cdc8d87e05a86b12be91a0c, data reload: false

query5	4334	637	486	486
query6	487	225	203	203
query7	4839	586	338	338
query8	344	195	193	193
query9	8795	4118	4132	4118
query10	490	352	310	310
query11	5838	2352	2160	2160
query12	165	103	103	103
query13	1289	571	447	447
query14	6220	5249	4988	4988
query14_1	4230	4238	4238	4238
query15	211	216	173	173
query16	1018	466	435	435
query17	1102	696	568	568
query18	2506	458	339	339
query19	197	185	144	144
query20	116	105	109	105
query21	234	156	137	137
query22	13643	13511	13357	13357
query23	17349	16437	16040	16040
query23_1	16253	16255	16284	16255
query24	7524	1790	1275	1275
query24_1	1318	1296	1330	1296
query25	575	467	410	410
query26	1332	369	219	219
query27	2580	644	390	390
query28	4477	1999	2012	1999
query29	1093	643	521	521
query30	337	258	226	226
query31	1128	1089	987	987
query32	108	65	64	64
query33	568	341	268	268
query34	1187	1163	662	662
query35	773	785	692	692
query36	1231	1169	1040	1040
query37	161	115	95	95
query38	1907	1708	1666	1666
query39	894	871	843	843
query39_1	836	865	841	841
query40	252	164	142	142
query41	75	70	69	69
query42	96	94	94	94
query43	336	333	305	305
query44	1469	785	766	766
query45	201	182	185	182
query46	1093	1220	754	754
query47	2092	2075	1968	1968
query48	420	439	297	297
query49	598	434	324	324
query50	1063	427	333	333
query51	10964	10616	10685	10616
query52	89	92	76	76
query53	266	284	204	204
query54	305	260	252	252
query55	78	77	71	71
query56	328	299	319	299
query57	1349	1280	1200	1200
query58	309	276	265	265
query59	1591	1634	1393	1393
query60	307	285	260	260
query61	182	173	177	173
query62	577	499	420	420
query63	240	200	196	196
query64	2807	1051	841	841
query65	4723	4597	4651	4597
query66	1798	511	358	358
query67	29318	29318	28464	28464
query68	3384	1510	952	952
query69	405	306	262	262
query70	1058	950	980	950
query71	335	318	317	317
query72	3063	2769	2315	2315
query73	889	766	432	432
query74	5107	4884	4722	4722
query75	2528	2483	2130	2130
query76	2347	1169	812	812
query77	361	378	288	288
query78	11929	11825	11337	11337
query79	1440	1214	762	762
query80	1299	541	464	464
query81	554	314	278	278
query82	573	160	120	120
query83	403	330	292	292
query84	277	161	131	131
query85	996	607	509	509
query86	425	291	290	290
query87	1852	1837	1731	1731
query88	3781	2814	2796	2796
query89	422	375	325	325
query90	1947	204	197	197
query91	202	194	166	166
query92	66	65	58	58
query93	1637	1601	1071	1071
query94	718	366	314	314
query95	792	501	462	462
query96	1012	796	361	361
query97	2653	2640	2474	2474
query98	210	216	204	204
query99	1087	1135	963	963
Total cold run time: 264695 ms
Total hot run time: 177238 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.25	0.14	0.14
query4	1.62	0.15	0.14
query5	0.24	0.22	0.22
query6	1.24	1.04	1.05
query7	0.04	0.00	0.00
query8	0.05	0.04	0.03
query9	0.41	0.32	0.32
query10	0.58	0.55	0.56
query11	0.20	0.14	0.15
query12	0.19	0.15	0.15
query13	0.47	0.47	0.47
query14	1.04	1.01	1.01
query15	0.60	0.61	0.60
query16	0.32	0.33	0.33
query17	1.12	1.09	1.10
query18	0.22	0.20	0.21
query19	2.00	1.94	1.94
query20	0.01	0.01	0.01
query21	15.47	0.20	0.13
query22	4.94	0.06	0.05
query23	16.12	0.31	0.13
query24	3.01	0.42	0.32
query25	0.11	0.05	0.04
query26	0.72	0.22	0.14
query27	0.05	0.04	0.04
query28	3.55	0.95	0.50
query29	12.51	4.18	3.33
query30	0.27	0.16	0.15
query31	2.78	0.60	0.32
query32	3.21	0.59	0.49
query33	3.26	3.15	3.24
query34	15.63	4.22	3.53
query35	3.50	3.52	3.51
query36	0.56	0.43	0.42
query37	0.08	0.06	0.07
query38	0.06	0.04	0.04
query39	0.04	0.03	0.02
query40	0.19	0.18	0.16
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.93 s
Total hot run time: 25.06 s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants