Skip to content

[fix](paimon) Correct pruned struct field reads - #66223

Merged
Gabriel39 merged 1 commit into
apache:masterfrom
Gabriel39:ai/doris-26920-26923-paimon-jni-fixes
Jul 29, 2026
Merged

[fix](paimon) Correct pruned struct field reads#66223
Gabriel39 merged 1 commit into
apache:masterfrom
Gabriel39:ai/doris-26920-26923-paimon-jni-fixes

Conversation

@Gabriel39

@Gabriel39 Gabriel39 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

  • Preserve the full Paimon RowType arity when reading projected struct fields.
  • Add unit coverage for non-leading, non-contiguous, and complete struct projections backed by a binary row.

Problem summary

Struct projection entries use original child indexes, but the scanner initialized the nested binary row with the number of projected fields. A projection such as the third child therefore created a one-field row and then accessed index two, producing incorrect reads or an out-of-bounds failure.

Regression coverage

  • testUnpackNonLeadingStructField constructs a three-field binary row and projects only original field index 2. The previous implementation fails with index (2) should < 1.
  • testUnpackNonContiguousStructFields projects original field indexes 0 and 2. The previous implementation fails with index (2) should < 2.
  • testUnpackCompleteStruct protects the existing full-struct behavior.
  • With this fix restored, all three tests pass with Maven build caching disabled.

Validation

  • Reverted the row-arity fix locally and confirmed that the two pruned-field regression tests fail.
  • Restored the fix and reran the same test class: 3 tests, 0 failures, 0 errors.
  • Ran all Paimon scanner test classes with Maven build caching disabled: 15 tests, 0 failures, 0 errors.
  • Checkstyle passed for the affected reactor modules.

@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

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39
Gabriel39 marked this pull request as ready for review July 29, 2026 07:23
@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage `` 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17778	4091	4075	4075
q2	2209	326	216	216
q3	10134	1459	847	847
q4	4738	472	339	339
q5	7997	851	572	572
q6	268	176	137	137
q7	776	837	625	625
q8	10594	1567	1552	1552
q9	5911	4344	4345	4344
q10	6762	1723	1468	1468
q11	518	365	318	318
q12	756	594	452	452
q13	18140	3463	2787	2787
q14	266	271	250	250
q15	q16	791	786	708	708
q17	1029	958	1059	958
q18	6956	5823	5515	5515
q19	1166	1254	1164	1164
q20	854	700	573	573
q21	5492	2625	2388	2388
q22	432	352	303	303
Total cold run time: 103567 ms
Total hot run time: 29591 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4380	4291	4313	4291
q2	292	317	211	211
q3	4597	4940	4401	4401
q4	2043	2163	1377	1377
q5	4408	4287	4296	4287
q6	242	183	128	128
q7	2047	1855	1651	1651
q8	2620	2178	2127	2127
q9	7817	7738	7811	7738
q10	4695	4647	4254	4254
q11	574	399	374	374
q12	904	805	547	547
q13	3289	3559	3016	3016
q14	305	298	276	276
q15	q16	729	757	649	649
q17	1408	1343	1344	1343
q18	8156	7502	6973	6973
q19	1106	1096	1097	1096
q20	2250	2222	1972	1972
q21	5223	4536	4450	4450
q22	519	476	416	416
Total cold run time: 57604 ms
Total hot run time: 51577 ms

@hello-stephen

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

query5	4313	633	489	489
query6	468	222	203	203
query7	4866	589	360	360
query8	342	187	171	171
query9	8787	4153	4117	4117
query10	531	354	291	291
query11	5914	2378	2145	2145
query12	157	107	102	102
query13	1277	618	438	438
query14	6247	5260	4922	4922
query14_1	4303	4299	4320	4299
query15	213	206	185	185
query16	1037	475	507	475
query17	1150	701	554	554
query18	2530	462	343	343
query19	211	191	142	142
query20	114	110	107	107
query21	240	160	137	137
query22	13607	13609	13360	13360
query23	17554	16525	16164	16164
query23_1	16280	16239	16330	16239
query24	7430	1758	1289	1289
query24_1	1289	1276	1281	1276
query25	559	442	348	348
query26	1344	345	211	211
query27	2596	624	367	367
query28	4452	2047	2028	2028
query29	1079	633	475	475
query30	340	269	222	222
query31	1129	1093	990	990
query32	113	65	60	60
query33	539	318	246	246
query34	1161	1194	634	634
query35	784	784	683	683
query36	1052	1016	893	893
query37	148	102	87	87
query38	1884	1713	1672	1672
query39	880	882	871	871
query39_1	837	848	827	827
query40	252	161	147	147
query41	65	63	64	63
query42	95	92	94	92
query43	325	341	287	287
query44	1445	781	765	765
query45	190	179	171	171
query46	1079	1209	712	712
query47	2127	2102	1940	1940
query48	389	407	303	303
query49	567	412	305	305
query50	1067	445	350	350
query51	10676	10433	10396	10396
query52	86	89	74	74
query53	271	285	203	203
query54	292	238	220	220
query55	73	71	67	67
query56	295	290	292	290
query57	1321	1287	1188	1188
query58	298	272	257	257
query59	1571	1662	1429	1429
query60	316	281	258	258
query61	168	151	154	151
query62	541	498	430	430
query63	245	204	204	204
query64	2833	1153	997	997
query65	4758	4649	4688	4649
query66	1820	526	401	401
query67	29459	29498	29202	29202
query68	3271	1518	1052	1052
query69	424	323	278	278
query70	940	845	851	845
query71	379	341	313	313
query72	3222	2910	2339	2339
query73	846	829	436	436
query74	5095	4957	4719	4719
query75	2552	2515	2149	2149
query76	2314	1180	796	796
query77	343	383	287	287
query78	11956	12046	11439	11439
query79	1423	1199	791	791
query80	1262	567	473	473
query81	520	338	290	290
query82	596	157	119	119
query83	369	334	300	300
query84	287	158	134	134
query85	982	634	578	578
query86	415	252	236	236
query87	1840	1837	1761	1761
query88	3763	2883	2794	2794
query89	428	379	342	342
query90	1898	206	199	199
query91	200	190	169	169
query92	64	64	53	53
query93	1756	1563	1005	1005
query94	700	365	321	321
query95	794	520	476	476
query96	1061	787	407	407
query97	2643	2619	2483	2483
query98	223	219	213	213
query99	1099	1103	1000	1000
Total cold run time: 264457 ms
Total hot run time: 177962 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.25	0.14	0.13
query4	1.63	0.14	0.13
query5	0.25	0.22	0.22
query6	1.24	1.09	1.09
query7	0.04	0.01	0.01
query8	0.05	0.03	0.03
query9	0.40	0.31	0.32
query10	0.56	0.57	0.55
query11	0.19	0.13	0.13
query12	0.18	0.14	0.13
query13	0.47	0.47	0.48
query14	1.03	1.00	1.01
query15	0.64	0.59	0.60
query16	0.31	0.32	0.31
query17	1.16	1.13	1.13
query18	0.22	0.22	0.22
query19	2.02	1.95	1.95
query20	0.02	0.01	0.01
query21	15.43	0.22	0.15
query22	4.87	0.06	0.05
query23	16.12	0.33	0.11
query24	2.90	0.43	0.32
query25	0.11	0.06	0.04
query26	0.77	0.21	0.16
query27	0.04	0.03	0.04
query28	3.51	0.93	0.52
query29	12.46	4.14	3.27
query30	0.27	0.14	0.15
query31	2.77	0.59	0.32
query32	3.22	0.59	0.49
query33	3.16	3.26	3.22
query34	15.48	4.23	3.53
query35	3.52	3.52	3.55
query36	0.55	0.44	0.43
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.16	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.03	0.03
Total cold run time: 96.46 s
Total hot run time: 25.13 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.

Review completed for head f02cd306e8858d0cd655a4948b6b58d8cc4dc32d.

Requesting changes because the advertised pruned-struct failure is not reachable through the current Paimon scanner bridge, and the new tests manufacture the missing original-index list instead of exercising the production caller.

Critical checkpoint conclusions:

  • Goal and proof: not achieved. The helper-level binary-row tests fail on the old code, but no production Paimon scan can currently supply their [2] or [0,2] index lists.
  • Scope and clarity: the patch is small, but the new comment states an original-child-index invariant that the production bridge does not provide.
  • Concurrency and lifecycle: not applicable; the change is synchronous row decoding and adds no managed lifetime.
  • Configuration, persistence, transactions, data writes, and FE/BE variables: no changes.
  • Compatibility and parallel paths: no serialized-format change. Legacy JNI, Format V2 JNI, and recursive struct/array/map paths all retain full struct shapes today, so the same reachability gap applies throughout.
  • Error handling and observability: no new error boundary or operational signal is needed for this local helper change.
  • Tests/results: no local build or test was run because the review runner explicitly forbids builds. Static review found that the added unit tests bypass VectorColumn.appendValue, so passing results do not establish the claimed end-to-end fix.
  • Performance: no reachable hot-path behavior changes at this head.

There was no additional user-provided review focus; the complete two-file PR and its upstream/downstream paths were reviewed.

InternalRow row = record.getRow(idx, structFieldIndex.size());
RowType rowType = (RowType) dataType;
// Projection entries are original child indexes, so the binary row must keep the full RowType arity.
InternalRow row = record.getRow(idx, rowType.getFieldCount());

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] Reproduce this through the scanner's real index list

This line changes behavior only when structFieldIndex.size() differs from the full Paimon RowType arity, but that state is not reachable today. LogicalFileScan.supportPruneNestedColumn() excludes Paimon, both JNI paths therefore serialize the full Doris struct, and VectorColumn generates the full dense [0..N-1] list; PaimonJniScanner also applies only a top-level projection. The old size already equaled the full row arity. The new tests bypass this bridge by directly injecting [2] and [0, 2], so they fail before the patch without reproducing a scanner request. Please wire the actual nested-field mapping through the JNI path and test it through VectorColumn.appendValue/the scanner boundary; as written, the advertised production failure is not fixed.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 0.00% (0/90) 🎉
Increment coverage report
Complete coverage report

@Gabriel39
Gabriel39 merged commit 5ede4b6 into apache:master Jul 29, 2026
36 checks passed
github-actions Bot pushed a commit that referenced this pull request Jul 29, 2026
## Proposed changes

- Preserve the full Paimon `RowType` arity when reading projected struct
fields.
- Add unit coverage for non-leading, non-contiguous, and complete struct
projections backed by a binary row.

## Problem summary

Struct projection entries use original child indexes, but the scanner
initialized the nested binary row with the number of projected fields. A
projection such as the third child therefore created a one-field row and
then accessed index two, producing incorrect reads or an out-of-bounds
failure.

## Regression coverage

- `testUnpackNonLeadingStructField` constructs a three-field binary row
and projects only original field index 2. The previous implementation
fails with `index (2) should < 1`.
- `testUnpackNonContiguousStructFields` projects original field indexes
0 and 2. The previous implementation fails with `index (2) should < 2`.
- `testUnpackCompleteStruct` protects the existing full-struct behavior.
- With this fix restored, all three tests pass with Maven build caching
disabled.

## Validation

- Reverted the row-arity fix locally and confirmed that the two
pruned-field regression tests fail.
- Restored the fix and reran the same test class: 3 tests, 0 failures, 0
errors.
- Ran all Paimon scanner test classes with Maven build caching disabled:
15 tests, 0 failures, 0 errors.
- Checkstyle passed for the affected reactor modules.
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.

3 participants