Skip to content

[fix](be) Preserve dynamic defaults after schema change - #67334

Open
jacktengg wants to merge 2 commits into
apache:masterfrom
jacktengg:DORIS-28286
Open

[fix](be) Preserve dynamic defaults after schema change#67334
jacktengg wants to merge 2 commits into
apache:masterfrom
jacktengg:DORIS-28286

Conversation

@jacktengg

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:
Schema change evaluates dynamic column defaults once to obtain a fixed literal for historical-row backfill. FE previously sent only that literal to BE, so a partial update inserting a new key reused the schema-change timestamp instead of evaluating CURRENT_TIMESTAMP at statement time. Preserve the original default expression alongside the fixed backfill literal, persist both in tablet schema metadata, and use the expression only when partial update fills missing columns for a new row.

Release note

Fix partial updates to evaluate dynamic defaults at statement time after columns are added through schema change.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • 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.
  • 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

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Schema change evaluates dynamic column defaults once to obtain a fixed literal for historical-row backfill. FE previously sent only that literal to BE, so a partial update inserting a new key reused the schema-change timestamp instead of evaluating CURRENT_TIMESTAMP at statement time. Preserve the original default expression alongside the fixed backfill literal, persist both in tablet schema metadata, and use the expression only when partial update fills missing columns for a new row.

### Release note

Fix partial updates to evaluate dynamic defaults at statement time after columns are added through schema change.

### Check List (For Author)

- Test:
    - Unit Test: ./run-fe-ut.sh --run org.apache.doris.catalog.ColumnDefaultValueSerializationTest
    - Manual test: Compiled the modified BE production and unit-test sources with the ASAN_UT compilation database
    - Build: ./build.sh --fe -j 8
- Behavior changed: Yes. New rows inserted by partial update evaluate dynamic defaults at statement time while historical rows retain the fixed schema-change backfill value.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Add regression coverage for a partial update that inserts a new key after a schema change adds a DATETIMEV2(6) column with CURRENT_TIMESTAMP(6) as its default. The case preserves a historical row, waits two seconds after schema change, performs the partial insert, and verifies that the historical backfill and new-row default produce two distinct timestamps.

### Release note

None

### Check List (For Author)

- Test:
    - Regression test: ./run-regression-test.sh --run -f regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_schema_change_current_timestamp_default.groovy
- Behavior changed: No
- 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?

@jacktengg

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17583	3028	3022	3022
q2	2088	263	233	233
q3	10231	925	507	507
q4	4674	254	206	206
q5	7662	569	383	383
q6	135	116	94	94
q7	530	515	397	397
q8	9253	868	923	868
q9	3508	2424	2422	2422
q10	6521	855	749	749
q11	400	199	178	178
q12	611	262	203	203
q13	18133	1536	1164	1164
q14	162	153	137	137
q15	q16	449	396	369	369
q17	1377	874	821	821
q18	3159	2341	2312	2312
q19	1118	856	764	764
q20	362	273	200	200
q21	5219	1642	1849	1642
q22	326	262	227	227
Total cold run time: 93501 ms
Total hot run time: 16898 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3379	3299	3302	3299
q2	518	407	371	371
q3	2282	2389	2255	2255
q4	1204	1205	903	903
q5	2237	2161	2141	2141
q6	169	118	88	88
q7	1041	993	913	913
q8	1613	1417	1421	1417
q9	3248	3221	3205	3205
q10	1925	1844	1665	1665
q11	376	280	264	264
q12	459	441	352	352
q13	1504	1531	1173	1173
q14	186	167	163	163
q15	q16	394	410	357	357
q17	3668	3416	3280	3280
q18	4969	4547	4975	4547
q19	960	863	827	827
q20	1034	989	848	848
q21	3893	3209	3204	3204
q22	398	342	329	329
Total cold run time: 35457 ms
Total hot run time: 31601 ms

@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.96% (34436/45336)
Line Coverage 60.92% (387714/636428)
Region Coverage 56.92% (324619/570323)
Branch Coverage 57.87% (148421/256486)

@hello-stephen

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

query5	4270	403	342	342
query6	385	143	141	141
query7	4941	422	241	241
query8	294	124	125	124
query9	8701	2879	2906	2879
query10	377	222	181	181
query11	5380	1079	943	943
query12	119	74	72	72
query13	1199	438	329	329
query14	6147	2261	2158	2158
query14_1	2041	2040	2027	2027
query15	180	126	113	113
query16	924	372	353	353
query17	1052	460	371	371
query18	2365	339	243	243
query19	171	138	117	117
query20	81	70	76	70
query21	205	104	88	88
query22	5487	5436	5436	5436
query23	6866	6485	6208	6208
query23_1	6441	6116	6373	6116
query24	7272	1093	756	756
query24_1	781	809	804	804
query25	447	310	273	273
query26	1235	243	134	134
query27	2768	411	260	260
query28	4661	1515	1492	1492
query29	960	446	371	371
query30	245	155	130	130
query31	819	413	348	348
query32	132	76	75	75
query33	467	220	188	188
query34	966	851	486	486
query35	410	417	349	349
query36	557	561	517	517
query37	126	85	70	70
query38	1014	874	838	838
query39	502	486	484	484
query39_1	502	452	463	452
query40	199	95	80	80
query41	58	58	56	56
query42	78	75	74	74
query43	240	242	217	217
query44	1054	545	544	544
query45	114	106	102	102
query46	772	814	542	542
query47	777	801	728	728
query48	315	285	231	231
query49	536	240	182	182
query50	727	251	196	196
query51	7963	8021	8061	8021
query52	69	88	80	80
query53	190	197	143	143
query54	211	183	174	174
query55	80	64	53	53
query56	175	165	156	156
query57	711	680	666	666
query58	195	166	162	162
query59	1276	1264	1173	1173
query60	241	182	170	170
query61	114	124	108	108
query62	343	203	181	181
query63	159	142	144	142
query64	2763	657	600	600
query65	1655	1705	1584	1584
query66	1758	251	201	201
query67	10348	9809	9865	9809
query68	3007	1248	741	741
query69	356	218	186	186
query70	663	618	614	614
query71	247	172	164	164
query72	2340	1771	1580	1580
query73	646	585	348	348
query74	2016	1246	1161	1161
query75	1204	1149	975	975
query76	2388	733	539	539
query77	261	253	209	209
query78	4212	3886	3388	3388
query79	2364	883	583	583
query80	1592	311	272	272
query81	500	161	137	137
query82	616	117	97	97
query83	279	208	198	198
query84	243	107	87	87
query85	787	349	294	294
query86	389	174	177	174
query87	1026	979	918	918
query88	2775	2125	2100	2100
query89	273	197	176	176
query90	1991	133	123	123
query91	130	119	98	98
query92	77	70	71	70
query93	1563	1043	665	665
query94	633	247	249	247
query95	543	282	313	282
query96	798	571	272	272
query97	1122	1092	1063	1063
query98	158	141	132	132
query99	429	353	311	311
Total cold run time: 179658 ms
Total hot run time: 83331 ms

@hello-stephen

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

query1	0.00	0.01	0.00
query2	0.07	0.03	0.03
query3	0.24	0.11	0.12
query4	1.60	0.10	0.09
query5	0.17	0.16	0.16
query6	1.25	0.66	0.67
query7	0.03	0.00	0.01
query8	0.05	0.03	0.03
query9	0.29	0.22	0.22
query10	0.35	0.38	0.35
query11	0.17	0.11	0.12
query12	0.16	0.12	0.13
query13	0.30	0.31	0.31
query14	0.46	0.47	0.45
query15	0.36	0.35	0.35
query16	0.23	0.22	0.23
query17	0.69	0.72	0.65
query18	0.19	0.17	0.17
query19	1.15	1.26	1.14
query20	0.02	0.01	0.00
query21	15.44	0.15	0.11
query22	5.07	0.04	0.05
query23	16.19	0.25	0.10
query24	3.04	0.29	0.24
query25	0.11	0.04	0.03
query26	0.79	0.17	0.13
query27	0.04	0.03	0.03
query28	3.65	0.57	0.29
query29	12.42	3.19	2.55
query30	0.24	0.13	0.11
query31	2.76	0.36	0.18
query32	3.53	0.33	0.24
query33	1.60	1.49	1.56
query34	15.39	2.23	1.78
query35	1.76	1.77	1.77
query36	0.45	0.30	0.28
query37	0.06	0.04	0.04
query38	0.05	0.03	0.03
query39	0.03	0.02	0.03
query40	0.11	0.08	0.08
query41	0.07	0.03	0.02
query42	0.03	0.02	0.02
query43	0.03	0.02	0.02
Total cold run time: 90.64 s
Total hot run time: 14.77 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 1.00% (4/401) 🎉
Increment coverage report
Complete coverage report

@jacktengg

Copy link
Copy Markdown
Contributor Author

run buildall

@jacktengg

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.

Automated review — changes requested

Review status: complete after two convergence rounds on head 9da15ebc2ba7ecd9a11069795859c49a1b6654a5. Two distinct P1 correctness issues are attached inline.

Critical checkpoint conclusions:

  • Goal and proof: the local DATETIMEV2/CURRENT_TIMESTAMP path is implemented and covered by unit plus regression tests, but the goal is not complete because cloud shadow schemas lose the fixed backfill value and legacy DATETIME partial updates now consume an unevaluated expression.
  • Scope and clarity: the patch is focused on dual default-value transport and persistence; no unrelated changes were found.
  • Concurrency and lifecycle: no new threads, shared mutable state, lock ordering, static initialization, or ownership lifecycle is introduced.
  • Configuration: no configuration item is added or changed.
  • Compatibility and persistence: the appended optional Thrift/protobuf fields are wire-compatible; TabletColumn protobuf round-trip, equality, current-schema overlay, and schema-cache identity were traced without another issue. The cloud protobuf value mismatch is the remaining parallel-path defect.
  • FE/BE variable passing and parallel paths: the local Thrift path carries the literal/expression pair, but the cloud protobuf path writes the expression into both fields.
  • Conditions, error handling, and nullability: the new evaluator branches cover DATETIMEV2/TIMESTAMPTZ but omit reachable V1 DATETIME; NOT NULL writes fail and nullable writes can silently receive NULL.
  • Tests and results: the new BE/FE tests are build-discovered and the regression result matches its query, but there is no cloud heavy-schema-change assertion or legacy-DATETIME fixed/flexible coverage. Builds and tests were not run because this review environment explicitly prohibits them.
  • Observability, transactions, and data writes: existing schema-change and load diagnostics are sufficient; no new metric is required. The two inline issues nevertheless affect write correctness and historical backfill data.
  • Performance and memory: no material CPU, allocation, or memory-safety concern was found beyond small per-column strings.
  • Additional focus: no user-specific focus was supplied. A final sweep of all 13 changed paths and all candidates found no further distinct issue.

for (unsigned int cur_cid : missing_cids) {
const auto& column = tablet_schema.column(cur_cid);
if (column.has_default_value()) {
const auto& default_value_expr = column.default_value_for_partial_update();

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] Evaluate legacy DATETIME before preferring the expression

FE still permits CURRENT_TIMESTAMP on DATETIME, and those V1 schemas remain reachable. Before this change the frozen timestamp literal parsed successfully; now default_value_for_partial_update() selects CURRENT_TIMESTAMP, but the branches below handle only DATETIMEV2/TIMESTAMPTZ. The V1 literal SerDe rejects the expression, so a NOT NULL partial update fails and a nullable column can silently become NULL. Please evaluate OLAP_FIELD_TYPE_DATETIME too and add legacy fixed/flexible coverage.

if (column.getDefaultValue() != null) {
builder.setDefaultValue(ByteString.copyFrom(column.getDefaultValue().getBytes()));
}
if (column.getDefaultValueExprDef() != null) {

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] Keep the frozen cloud backfill literal in default_value

For a schema-change Column, getDefaultValue() is CURRENT_TIMESTAMP(6) while getRealDefaultValue() is the DDL-time literal. createTabletMetaBuilder uses this protobuf for cloud shadow tablets, and SchemaChangeJob later parses new_column.default_value() as a literal. This stores the expression in both fields; DATETIMEV2 conversion swallows the invalid literal and substitutes MIN_DATETIME_V2, so historical rows get corrupted instead of receiving the DDL-time value. Please mirror ColumnToThrift for default_value and assert the frozen value in the protobuf test, with cloud heavy-schema-change coverage.

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 100.00% (9/9) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 62.86% (29473/46889)
Line Coverage 47.85% (308390/644433)
Region Coverage 43.47% (249092/573082)
Branch Coverage 45.03% (115946/257496)

@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.94% (34483/45409)
Line Coverage 60.91% (388010/637056)
Region Coverage 56.90% (324844/570890)
Branch Coverage 57.83% (148489/256759)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants