Skip to content

[fix](binlog) Align row binlog after schema with before values - #65438

Merged
morrySnow merged 1 commit into
apache:masterfrom
yujun777:sync-column-after-nullable
Jul 10, 2026
Merged

morrySnow merged 1 commit into
apache:masterfrom
yujun777:sync-column-after-nullable

Conversation

@yujun777

@yujun777 yujun777 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: #65418

Related PR: None

Problem Summary:
Row binlog MIN_DELTA does not output separate schemas for update-before rows and update-after rows. Instead, it materializes both row kinds through one unified output schema, which is the generated after/output value schema.

That means an update-before row also has to be written into the after value slots. For MoW row binlog queries with historical values enabled, the before values come from the nullable __DORIS_BEFORE_* mirror columns. Before this change, FE generated after value columns by copying the user column definition directly. When the user column was a complex NOT NULL type such as BITMAP, the after/output slot stayed non-nullable, but MIN_DELTA still had to write the nullable before value into that same slot.

This schema mismatch could crash BE during MIN_DELTA row materialization with a bad cast from ColumnNullable to ColumnComplexType<BITMAP>. The fix is to make generated after value columns follow the same nullable and default-cleared contract as before value columns, so the unified MIN_DELTA output schema can safely carry both before rows and after rows.

This PR also adds FE unit coverage for row binlog schema generation and a normal row binlog regression case that reproduces the crash with a BITMAP NOT NULL column on MIN_DELTA.

Release note

None

Check List (For Author)

  • Test: FE UT + Regression test
    • FE Unit Test: ./run-fe-ut.sh --run org.apache.doris.catalog.OlapTableRowBinlogSchemaTest
    • Regression test: ./run-regression-test.sh --run -d row_binlog_p0 -s test_binlog_changes_syntax -forceGenOut
    • Repro check: temporarily reverted the Column.java change, rebuilt FE, reran ./run-regression-test.sh --run -d row_binlog_p0 -s test_binlog_changes_syntax, and reproduced F20260710 11:13:48.523105 ... Bad cast from type:doris::ColumnNullable to doris::ColumnComplexType<(doris::PrimitiveType)22> in be.out
  • Behavior changed: Yes (row binlog generated after value columns now match the unified MIN_DELTA output schema used by both before rows and after rows)
  • Does this need documentation: No

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Row binlog MIN_DELTA outputs update_before and update_after rows through one unified output schema. Before this change, FE generated the after value column by copying the base value column definition directly. When the base column was NOT NULL and complex-typed, the update_before row still came from the nullable `__BEFORE__` mirror column but had to be written into the non-nullable after slot. That schema mismatch could crash BE during MIN_DELTA row materialization with a bad cast from `ColumnNullable` to the target complex column type. This change makes generated after value columns follow the same nullable/default-cleared contract as before value columns, adds FE unit coverage for row binlog schema generation, and adds a regression case that reproduces the scenario with a normal row binlog MIN_DELTA query on a `BITMAP NOT NULL` MoW table.

### Release note

None

### Check List (For Author)

- Test: FE UT + Regression test
    - FE Unit Test: `./run-fe-ut.sh --run org.apache.doris.catalog.OlapTableRowBinlogSchemaTest`
    - Regression test: `./run-regression-test.sh --run -d row_binlog_p0 -s test_binlog_changes_syntax -forceGenOut`
- Behavior changed: Yes (row binlog generated after value columns are now nullable and have cleared defaults to match MIN_DELTA unified output schema)
- 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?

@yujun777 yujun777 changed the title [fix](fe) Align row binlog after schema with before values [fix](binlog) Align row binlog after schema with before values Jul 10, 2026
@yujun777

Copy link
Copy Markdown
Contributor Author

run buildall

@morrySnow

Copy link
Copy Markdown
Contributor

/review

@github-actions

Copy link
Copy Markdown
Contributor

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

@github-actions github-actions Bot added approved Indicates a PR has been approved by one committer. reviewed labels Jul 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

yujun777 added a commit to yujun777/doris that referenced this pull request Jul 10, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65438

Problem Summary: Row binlog MIN_DELTA materializes update-before rows and update-after rows through one unified output schema. Before this change, FE generated the after value column by copying the user column definition directly. When the user column was a complex NOT NULL type such as BITMAP, the update-before row still came from the nullable __DORIS_BEFORE__ mirror column but had to be written into the non-nullable after slot. That schema mismatch could crash BE during MIN_DELTA row materialization with a bad cast from ColumnNullable to the target complex column type. This change makes generated after value columns follow the same nullable and default-cleared contract as before value columns so the unified MIN_DELTA output schema can safely carry both before rows and after rows.

### Release note

None

### Check List (For Author)

- Test: Manual test
    - Reproduced the BE crash by temporarily reverting this change and rerunning the row binlog MIN_DELTA bitmap regression in doris-test
- Behavior changed: Yes (row binlog generated after value columns now match the unified MIN_DELTA output schema used by both before rows and after rows)
- Does this need documentation: No

@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 conclusion: request changes.

Critical checkpoints:

  • Goal/test: the fresh-schema path is covered by the new FE unit assertions and bitmap regression case, but the fix does not cover existing persisted row-binlog metadata after upgrade.
  • Scope/focus: the code change is small and focused; the missing compatibility path is the blocking gap.
  • Concurrency/lifecycle: no new concurrency or locking path is introduced. The relevant lifecycle issue is FE metadata load/replay of persisted row-binlog index schemas.
  • Configuration/compatibility: no new config is added. Compatibility is affected because old row-binlog after-value columns can remain non-null/default-carrying in MaterializedIndexMeta.
  • Parallel paths: new row-binlog schema creation and add-column paths use the helper; metadata-load compatibility does not.
  • Tests: existing tests exercise fresh metadata and a new bitmap MIN_DELTA case, but not legacy persisted metadata normalization. I did not run FE/regression tests locally because this checkout is missing thirdparty/installed/bin/protoc.
  • Observability/performance/transactions: no new logging, hot-path performance, transaction, or persistence-write concerns beyond the metadata compatibility issue.

User focus: no additional user-provided review focus was supplied.

Subagent conclusions: optimizer-rewrite found no valuable optimizer/rewrite issue. tests-session-config proposed TSC-1, which was accepted as M-1 and submitted as the inline comment. No candidates were dismissed as duplicates; existing inline threads were empty. Convergence round C1 ended with both live subagents replying NO_NEW_VALUABLE_FINDINGS for the same one-comment final set.

Comment thread fe/fe-catalog/src/main/java/org/apache/doris/catalog/Column.java
@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: 30134 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 049e33f130dea772db6db5ca2214757507ec1433, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17608	4027	4029	4027
q2	2036	335	202	202
q3	10254	1478	868	868
q4	4682	476	345	345
q5	7524	902	601	601
q6	188	183	143	143
q7	796	825	638	638
q8	9350	1662	1581	1581
q9	6293	4427	4412	4412
q10	6815	1810	1515	1515
q11	516	341	317	317
q12	730	554	426	426
q13	18319	3386	2795	2795
q14	265	265	244	244
q15	q16	800	777	717	717
q17	997	966	1144	966
q18	7030	5771	5643	5643
q19	1337	1290	1079	1079
q20	774	649	595	595
q21	6568	2932	2688	2688
q22	475	385	332	332
Total cold run time: 103357 ms
Total hot run time: 30134 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5414	5177	4816	4816
q2	304	371	240	240
q3	4968	5341	4661	4661
q4	2094	2144	1393	1393
q5	4901	4775	4718	4718
q6	242	193	137	137
q7	1882	1778	1554	1554
q8	2567	2296	2240	2240
q9	7864	7264	7286	7264
q10	4699	4602	4161	4161
q11	542	392	386	386
q12	741	737	531	531
q13	2960	3405	2744	2744
q14	274	275	256	256
q15	q16	675	696	618	618
q17	1284	1270	1262	1262
q18	7632	6883	6996	6883
q19	1109	1044	1113	1044
q20	2212	2225	1936	1936
q21	5309	4741	4577	4577
q22	530	489	416	416
Total cold run time: 58203 ms
Total hot run time: 51837 ms

@hello-stephen

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

query5	4326	624	490	490
query6	466	232	203	203
query7	4850	587	328	328
query8	337	187	170	170
query9	8763	4042	4068	4042
query10	462	342	299	299
query11	5902	2371	2195	2195
query12	154	110	100	100
query13	1305	634	450	450
query14	6288	5297	4972	4972
query14_1	4288	4297	4318	4297
query15	223	211	182	182
query16	1088	476	448	448
query17	1154	737	587	587
query18	2683	447	351	351
query19	212	193	151	151
query20	145	111	109	109
query21	244	156	127	127
query22	13625	13608	13405	13405
query23	17529	16587	16241	16241
query23_1	16390	16205	16345	16205
query24	7704	1779	1302	1302
query24_1	1307	1293	1312	1293
query25	563	479	395	395
query26	1352	343	209	209
query27	2588	605	383	383
query28	4431	2032	2014	2014
query29	1110	622	512	512
query30	329	265	223	223
query31	1117	1116	983	983
query32	117	63	64	63
query33	537	324	265	265
query34	1166	1165	662	662
query35	778	797	685	685
query36	1394	1346	1254	1254
query37	160	110	94	94
query38	1891	1709	1677	1677
query39	926	949	911	911
query39_1	881	878	870	870
query40	241	160	138	138
query41	65	64	61	61
query42	93	91	92	91
query43	321	323	280	280
query44	1415	776	754	754
query45	194	189	176	176
query46	1081	1215	754	754
query47	2348	2323	2272	2272
query48	405	417	285	285
query49	594	413	309	309
query50	991	425	338	338
query51	10782	10888	10771	10771
query52	86	84	71	71
query53	258	270	215	215
query54	278	239	208	208
query55	74	69	64	64
query56	288	270	297	270
query57	1444	1389	1305	1305
query58	314	275	248	248
query59	1595	1650	1415	1415
query60	296	263	242	242
query61	145	146	149	146
query62	690	649	578	578
query63	249	206	205	205
query64	2767	1031	881	881
query65	4859	4806	4798	4798
query66	1783	503	417	417
query67	29553	29493	29317	29317
query68	3261	1677	954	954
query69	413	304	264	264
query70	1056	963	944	944
query71	325	324	287	287
query72	3099	2724	2430	2430
query73	830	762	410	410
query74	5109	4925	4758	4758
query75	2633	2588	2218	2218
query76	2339	1158	794	794
query77	355	376	283	283
query78	12386	12310	11693	11693
query79	1382	1202	772	772
query80	1298	550	459	459
query81	534	322	282	282
query82	984	159	124	124
query83	389	322	304	304
query84	275	158	129	129
query85	1007	600	514	514
query86	437	292	255	255
query87	1829	1827	1751	1751
query88	3707	2806	2775	2775
query89	460	405	356	356
query90	1913	198	192	192
query91	199	190	160	160
query92	63	58	57	57
query93	1713	1566	1010	1010
query94	828	364	315	315
query95	787	587	463	463
query96	1101	779	376	376
query97	2676	2677	2525	2525
query98	216	202	202	202
query99	1161	1179	1033	1033
Total cold run time: 267105 ms
Total hot run time: 179837 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 049e33f130dea772db6db5ca2214757507ec1433, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.05
query3	0.26	0.13	0.14
query4	1.61	0.14	0.14
query5	0.26	0.23	0.22
query6	1.27	1.07	1.04
query7	0.05	0.01	0.00
query8	0.06	0.04	0.04
query9	0.37	0.31	0.32
query10	0.56	0.58	0.57
query11	0.20	0.14	0.14
query12	0.18	0.14	0.15
query13	0.47	0.48	0.49
query14	1.04	1.01	1.00
query15	0.61	0.59	0.60
query16	0.31	0.31	0.34
query17	1.12	1.11	1.15
query18	0.24	0.20	0.20
query19	2.09	2.00	1.90
query20	0.01	0.01	0.01
query21	15.47	0.21	0.13
query22	4.87	0.05	0.05
query23	16.11	0.31	0.12
query24	2.99	0.41	0.33
query25	0.10	0.04	0.06
query26	0.72	0.21	0.15
query27	0.05	0.04	0.03
query28	3.47	0.93	0.54
query29	12.53	4.01	3.21
query30	0.28	0.15	0.15
query31	2.78	0.57	0.30
query32	3.22	0.60	0.49
query33	3.08	3.19	3.20
query34	15.56	4.20	3.55
query35	3.52	3.53	3.55
query36	0.56	0.43	0.41
query37	0.09	0.06	0.06
query38	0.06	0.04	0.04
query39	0.04	0.03	0.04
query40	0.18	0.15	0.15
query41	0.09	0.04	0.04
query42	0.04	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.67 s
Total hot run time: 24.99 s

yujun777 added a commit to yujun777/doris that referenced this pull request Jul 10, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65438

Problem Summary: Row binlog MIN_DELTA materializes update-before rows and update-after rows through one unified output schema. Before this change, FE generated the after value column by copying the user column definition directly. When the user column was a complex NOT NULL type such as BITMAP, the update-before row still came from the nullable __DORIS_BEFORE__ mirror column but had to be written into the non-nullable after slot. That schema mismatch could crash BE during MIN_DELTA row materialization with a bad cast from ColumnNullable to the target complex column type. This change makes generated after value columns follow the same nullable and default-cleared contract as before value columns so the unified MIN_DELTA output schema can safely carry both before rows and after rows.

### Release note

None

### Check List (For Author)

- Test: Manual test
    - Reproduced the BE crash by temporarily reverting this change and rerunning the row binlog MIN_DELTA bitmap regression in doris-test
- Behavior changed: Yes (row binlog generated after value columns now match the unified MIN_DELTA output schema used by both before rows and after rows)
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

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

@morrySnow
morrySnow merged commit 44aaa1e into apache:master Jul 10, 2026
36 checks passed
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. binlog reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants