Skip to content

[fix](variant) Recognize nullable array elements as NestedGroup types - #66196

Merged
eldenmoon merged 1 commit into
apache:masterfrom
eldenmoon:branch-fix-ng-nullable-classifier
Jul 29, 2026
Merged

[fix](variant) Recognize nullable array elements as NestedGroup types#66196
eldenmoon merged 1 commit into
apache:masterfrom
eldenmoon:branch-fix-ng-nullable-classifier

Conversation

@eldenmoon

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: None

Related PR: #63088

Problem Summary:

Array elements are nullable after #63088. get_base_type_of_array() therefore returns Nullable<Variant> for the NestedGroup physical type, but is_nested_group_type() directly casts that wrapper to DataTypeVariant. The false negative bypasses the NestedGroup-specific type-conflict policy during Variant merge/compaction.

This PR unwraps the nullable base type only when the input has an Array dimension. It recognizes Array<Nullable<Variant>> as NestedGroup while preserving the existing classifications of scalar Variant and Nullable<Variant>.

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
      • GLIBC_COMPATIBILITY=OFF ./run-be-ut.sh --run --filter=ColumnVariantNestedGroupTypeTest.nullable_array_element_is_recognized
      • GLIBC_COMPATIBILITY=OFF ./run-be-ut.sh --run --filter='ColumnVariantTest.*' (91 tests passed)
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes. Arrays whose innermost element is Nullable<Variant> are now recognized as NestedGroup and use its intended conflict-resolution policy.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

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

@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17586	4037	4033	4033
q2	2046	321	196	196
q3	10330	1494	823	823
q4	4709	477	339	339
q5	7630	875	554	554
q6	197	171	137	137
q7	769	798	607	607
q8	9913	1648	1670	1648
q9	6080	4335	4376	4335
q10	6785	1731	1481	1481
q11	507	350	331	331
q12	711	578	455	455
q13	18105	3376	2765	2765
q14	276	265	240	240
q15	q16	792	792	723	723
q17	987	1032	1030	1030
q18	7234	5880	5844	5844
q19	2574	1285	1058	1058
q20	803	645	592	592
q21	6074	2721	2436	2436
q22	432	358	301	301
Total cold run time: 104540 ms
Total hot run time: 29928 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4401	4283	4291	4283
q2	296	325	216	216
q3	4595	4967	4381	4381
q4	2075	2170	1386	1386
q5	4405	4321	4286	4286
q6	381	224	151	151
q7	2205	1899	1644	1644
q8	2484	2253	2246	2246
q9	8342	7834	7738	7738
q10	4731	4704	4169	4169
q11	584	400	404	400
q12	755	754	528	528
q13	3267	3652	2952	2952
q14	291	302	291	291
q15	q16	722	748	633	633
q17	1347	1326	1464	1326
q18	7802	7336	7246	7246
q19	1193	1125	1115	1115
q20	2208	2190	1930	1930
q21	5261	4534	4387	4387
q22	529	444	407	407
Total cold run time: 57874 ms
Total hot run time: 51715 ms

@hello-stephen

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

query5	4338	641	488	488
query6	466	222	205	205
query7	4885	588	330	330
query8	345	193	175	175
query9	8796	4044	4016	4016
query10	461	355	312	312
query11	5932	2339	2131	2131
query12	159	108	108	108
query13	1249	591	435	435
query14	6246	5228	4884	4884
query14_1	4235	4225	4230	4225
query15	221	207	178	178
query16	1046	499	445	445
query17	1112	706	556	556
query18	2518	460	353	353
query19	207	188	144	144
query20	111	108	104	104
query21	232	157	138	138
query22	13540	13524	13374	13374
query23	17382	16438	16167	16167
query23_1	16231	16262	16319	16262
query24	7541	1733	1250	1250
query24_1	1294	1288	1253	1253
query25	538	437	368	368
query26	1335	344	205	205
query27	2642	628	385	385
query28	4467	1989	1934	1934
query29	1049	628	476	476
query30	344	267	226	226
query31	1116	1083	982	982
query32	106	60	57	57
query33	514	314	253	253
query34	1155	1123	630	630
query35	769	776	683	683
query36	1042	1032	888	888
query37	160	119	96	96
query38	1900	1699	1645	1645
query39	885	914	836	836
query39_1	838	839	837	837
query40	250	168	146	146
query41	74	71	71	71
query42	97	93	93	93
query43	323	326	287	287
query44	1405	759	755	755
query45	200	187	176	176
query46	1045	1246	745	745
query47	2169	2139	2036	2036
query48	385	410	307	307
query49	608	438	314	314
query50	1001	436	362	362
query51	10535	10700	10652	10652
query52	89	92	81	81
query53	265	299	218	218
query54	301	248	241	241
query55	78	74	68	68
query56	317	340	300	300
query57	1328	1326	1223	1223
query58	311	276	272	272
query59	1562	1621	1431	1431
query60	332	289	270	270
query61	176	171	175	171
query62	544	501	442	442
query63	255	197	200	197
query64	2971	1091	853	853
query65	4694	4675	4601	4601
query66	1860	512	400	400
query67	28745	29244	28589	28589
query68	3203	1512	961	961
query69	407	326	271	271
query70	919	821	805	805
query71	367	343	320	320
query72	3033	2728	2332	2332
query73	852	750	440	440
query74	5053	4918	4732	4732
query75	2528	2510	2140	2140
query76	2309	1170	767	767
query77	351	382	287	287
query78	11953	11959	11366	11366
query79	1488	1200	770	770
query80	1287	572	459	459
query81	545	334	289	289
query82	666	160	119	119
query83	371	321	285	285
query84	289	162	130	130
query85	993	615	514	514
query86	405	273	233	233
query87	1834	1825	1738	1738
query88	3667	2774	2707	2707
query89	434	366	335	335
query90	1928	193	197	193
query91	198	190	166	166
query92	64	63	59	59
query93	1753	1444	920	920
query94	732	352	304	304
query95	771	584	486	486
query96	1032	787	360	360
query97	2647	2653	2499	2499
query98	214	204	203	203
query99	1082	1116	976	976
Total cold run time: 263153 ms
Total hot run time: 176430 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.13	0.05	0.04
query3	0.25	0.13	0.13
query4	1.60	0.14	0.13
query5	0.23	0.23	0.22
query6	1.29	1.04	1.03
query7	0.04	0.01	0.01
query8	0.06	0.03	0.03
query9	0.38	0.30	0.31
query10	0.55	0.54	0.56
query11	0.19	0.14	0.13
query12	0.18	0.14	0.13
query13	0.47	0.48	0.48
query14	1.02	1.01	1.01
query15	0.62	0.59	0.59
query16	0.31	0.31	0.31
query17	1.09	1.06	1.08
query18	0.22	0.21	0.21
query19	1.97	1.91	1.92
query20	0.02	0.01	0.02
query21	15.44	0.21	0.12
query22	4.83	0.05	0.05
query23	16.15	0.32	0.12
query24	2.99	0.43	0.31
query25	0.11	0.06	0.04
query26	0.76	0.22	0.14
query27	0.05	0.04	0.03
query28	3.44	0.92	0.52
query29	12.47	4.16	3.27
query30	0.28	0.16	0.15
query31	2.77	0.61	0.32
query32	3.22	0.61	0.48
query33	3.26	3.32	3.21
query34	15.56	4.17	3.54
query35	3.52	3.53	3.52
query36	0.56	0.44	0.43
query37	0.09	0.06	0.07
query38	0.06	0.04	0.04
query39	0.04	0.03	0.02
query40	0.17	0.17	0.16
query41	0.08	0.03	0.03
query42	0.04	0.03	0.04
query43	0.04	0.03	0.03
Total cold run time: 96.56 s
Total hot run time: 24.89 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.31% (31146/41356)
Line Coverage 59.83% (347050/580048)
Region Coverage 56.63% (292075/515798)
Branch Coverage 57.87% (130514/225547)

@eldenmoon
eldenmoon marked this pull request as ready for review July 29, 2026 01:33
Copilot AI review requested due to automatic review settings July 29, 2026 01:33
@eldenmoon

Copy link
Copy Markdown
Member Author

/review

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

@github-actions

Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

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

Request changes: the local nullable-element classification is correct, but the newly activated conflict path can silently lose regular-array values, and the added test does not exercise the production policy behavior.

Critical checkpoint conclusions:

  • Goal and correctness: Array<Nullable<Variant>> is now recognized while scalar Variant and Nullable<Variant> retain their prior classifications. However, a regular mixed Array<Jsonb> merged before NESTED_TYPE is later defaulted during finalization; reversing the order preserves it. The PR therefore does not yet safely accomplish its merge/compaction goal.
  • Scope and design: the two-file, three-line production change is small and focused. The defect is in the interaction with the existing NG conflict resolver/finalizer, not in the nullable unwrapping itself.
  • Concurrency and lifecycle: the helper is stateless and adds no locks, atomics, threads, static-initialization dependency, ownership cycle, or release-order concern.
  • Configuration, conditions, and error handling: no new config is added. Under the existing ERROR policy, the same classifier also rejects a compatible non-scalar regular array before the intended array-cast path. No new ignored Status was found.
  • Compatibility and persistence: there is no serialized-layout, storage-format, FE/BE protocol, EditLog, transaction-metadata, or rolling-upgrade field change.
  • Parallel paths and data writes: hierarchical reconstruction and the persistent materialized writer append into an existing ColumnVariant, making the order-dependent value loss production-reachable. The streaming writer uses a fresh chunk per append and does not independently create this cross-chunk ordering. No version/delete-bitmap protocol changes are involved.
  • Tests: the new unit test proves only the private predicate. No unit or regression test covers populated NG/scalar merges in both orders or variant_nested_group_discard_scalar_on_conflict=false; the regular-array ordering defect is likewise uncovered. The author reports the focused test and 91 ColumnVariantTest.* cases passing, and current CI is green. Tests were not rerun here because the review prompt prohibits builds and this worktree lacks .worktree_initialized and thirdparty/installed.
  • Memory, COW, performance, and observability: no ownership or tracked-allocation behavior changes. The extra type-depth walk is allocation-free O(depth). Existing exceptions include both types, but the default-policy failure silently substitutes defaults, which is the blocking observability/data-correctness concern.
  • User focus: no additional focus was provided; the entire PR was reviewed.

Review completion: the authoritative two-file diff was fully reviewed, all candidates were resolved, and two convergence rounds ended with every Round 2 full/risk reviewer returning NO_NEW_VALUABLE_FINDINGS against this exact two-comment set.

// which indicates NG-originated array<object> data.
bool is_nested_group_type(const DataTypePtr& type) {
auto base = get_base_type_of_array(type);
if (get_number_of_dimensions(*type) > 0) {

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 regular-array rows when the NG type becomes the LCT. If the destination already contains a mixed Array<Jsonb> and the source is NESTED_TYPE, this newly true result makes resolve_ng_type_conflict() select the NG type and leave the old array part in place; Subcolumn::finalize() then sees an NG/non-NG mismatch and inserts defaults for every old row. Reversing the inputs instead reaches the same-dimensional array cast at lines 392-424 and preserves the values, so hierarchical/materialized merges become order-dependent. Distinguish genuine scalar conflicts from regular arrays during resolution/finalization, and cover both input orders.

array_subcolumn.finalize();
}

TEST(ColumnVariantNestedGroupTypeTest, nullable_array_element_is_recognized) {

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] Please exercise the conflict-policy behavior, not only the helper. The reported regression is that this predicate used to bypass Subcolumn::insert_range_from/finalize, but this test would still pass if the merge kept the wrong LCT, discarded the NestedGroup row, or ignored the ERROR policy. Add a focused merge test with an actual NESTED_TYPE value and a scalar in both source/destination orders, asserting that the default policy preserves the NestedGroup value and defaults only the scalar; also cover variant_nested_group_discard_scalar_on_conflict=false throwing in both orders.

@eldenmoon
eldenmoon merged commit 8e3c5bb into apache:master Jul 29, 2026
36 checks passed
github-actions Bot pushed a commit that referenced this pull request Jul 29, 2026
…#66196)

Related PR: #63088

Problem Summary:

Array elements are nullable after #63088. `get_base_type_of_array()`
therefore returns `Nullable<Variant>` for the NestedGroup physical type,
but `is_nested_group_type()` directly casts that wrapper to
`DataTypeVariant`. The false negative bypasses the NestedGroup-specific
type-conflict policy during Variant merge/compaction.

This PR unwraps the nullable base type only when the input has an Array
dimension. It recognizes `Array<Nullable<Variant>>` as NestedGroup while
preserving the existing classifications of scalar `Variant` and
`Nullable<Variant>`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/4.1.x reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants