Skip to content

[fix](generated column) Preserve generated column sessions in CREATE TABLE LIKE - #67809

Merged
CalvinKirs merged 3 commits into
apache:masterfrom
feiniaofeiafei:codex/fix-create-table-like-generated-session
Sep 18, 2026
Merged

CalvinKirs merged 3 commits into
apache:masterfrom
feiniaofeiafei:codex/fix-create-table-like-generated-session

Conversation

@feiniaofeiafei

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Problem Summary:

CREATE TABLE LIKE reconstructs generated columns from SQL using the caller's session settings, losing the expression settings saved in the source columns. For a generated expression a * b over DECIMAL(20,5) and DECIMAL(21,6), a source created with enable_decimal256=true produces 1.26212529751, but a clone created with the option disabled produces 1.26212530000 for the same input. SQL mode also affects parsing: a source expression a || 'x' created with PIPES_AS_CONCAT produces ax, while its clone can produce NULL under a different SQL mode.

Snapshot each generated column's session settings under the source table's read lock and carry them through GeneratedColumnDesc. Restore these settings temporarily when parsing and analyzing the cloned expression, then persist them in the new Column. The caller's session is restored after analysis, including on exceptions. Ordinary CREATE TABLE retains its existing session behavior.

Existing incorrectly created clones and stored data are not automatically repaired.

Release note

Fix CREATE TABLE LIKE changing generated column results when the caller's expression-related session settings differ from the source table's settings.

Check List (For Author)

  • Test

    • Regression test
      • Passed test_generated_column_like_session, test_generated_column, and test_generated_column_fault_tolerance_nereids on the final branch's FE.
      • New coverage includes both decimal256 setting directions, repeated LIKE, SQL mode, NULL values, and preservation of the caller's session. Expected output was generated by run-regression-test.sh and verified in subsequent runs.
    • Unit Test
      • All 11 CreateTableLikeTest tests passed via run-fe-ut.sh on the initial validation baseline with the same repair and test files.
      • The final upstream baseline has an unrelated test-compilation error in IvmNormalizeMTMVJoinTest (an outdated IvmRewriteContext constructor call). Final FE packaging therefore used DISABLE_BUILD_UI=ON MVN_OPT=-Dmaven.test.skip=true ./build.sh --fe. No unrelated test code was changed. Checkstyle passed.
    • Manual test (add detailed scripts or steps below)
      • Reproduced both precision and SQL mode differences before replacing FE libraries; verified correct results after replacement.
      • Restarted the final FE and cloned previously created fixed tables again, verifying persisted session settings and unchanged caller settings.
      • The test FE used be_exec_version=13 to match its existing BE.
    • No need to test or manual test. Explain why:
  • Behavior changed:

    • No.
    • Yes. Generated columns created through LIKE preserve the source columns' expression semantics.
  • 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?

@morrySnow morrySnow changed the title [fix](fe) Preserve generated column sessions in CREATE TABLE LIKE [fix](generated column) Preserve generated column sessions in CREATE TABLE LIKE Sep 11, 2026
@morrySnow

Copy link
Copy Markdown
Contributor

run buildall

### What problem does this PR solve?

Problem Summary: CREATE TABLE LIKE reconstructs generated columns from SQL
under the caller's session settings, losing the source columns' expression
settings. A decimal multiplication created with enable_decimal256=true can
therefore produce 1.26212530000 in a clone made with the option disabled,
instead of the source result 1.26212529751. Snapshot each generated column's
settings with its schema, use them when parsing and analyzing the cloned
expression, and preserve them in the new column metadata. Restore the caller's
session after analysis. Cover both decimal setting directions, repeated LIKE,
SQL mode, and session restoration.

### Release note

Fix CREATE TABLE LIKE changing generated column results when the caller's
expression-related session settings differ from the source table's settings.

### Check List (For Author)

- Test: Manual test reproduced the source/clone precision difference on dev.
    FE Checkstyle passed; FE compilation and added unit/regression tests pending.
- Behavior changed: Yes, cloned generated columns preserve source semantics.
- Does this need documentation: No
### What problem does this PR solve?

Problem Summary: Record automatically generated regression results for
CREATE TABLE LIKE preserving generated-column expression settings, and use
the current ExprToSqlVisitor API in the metadata unit test.

### Release note

None

### Check List (For Author)

- Test: Unit Test - all 11 CreateTableLikeTest tests passed via run-fe-ut.sh.
    Regression test - test_generated_column_like_session,
    test_generated_column, and test_generated_column_fault_tolerance_nereids
    passed. Output generated with run-regression-test.sh and then verified.
    FE build and Checkstyle passed with DISABLE_BUILD_UI=ON ./build.sh --fe.
    Manual test verified decimal precision and SQL mode after replacing FE lib.
- Behavior changed: No
- Does this need documentation: No
@feiniaofeiafei
feiniaofeiafei force-pushed the codex/fix-create-table-like-generated-session branch from 96f85b0 to cde9763 Compare September 11, 2026 09:53
@feiniaofeiafei

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 86.49% (32/37) 🎉
Increment coverage report
Complete coverage report

@feiniaofeiafei

Copy link
Copy Markdown
Collaborator 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.

Requesting changes for two production-reachable correctness gaps:

  • The source session map is attached only after the rendered CREATE statement is parsed, so an expression whose tokenization depends on NO_BACKSLASH_ESCAPES can still make CREATE TABLE LIKE fail before the guarded reparse.
  • Generated columns from metadata predating persisted session maps are reparsed from raw SQL under the caller's mode, although the source continues using its serialized analyzed expression; the clone can therefore silently change semantics.

Review checkpoint conclusions:

  • Goal and behavior: the positive nonlegacy decimal and PIPES_AS_CONCAT cases are addressed, including repeated LIKE and success-path caller-session restoration, but the two cases above keep the change from being correct end to end.
  • Scope and architecture: the change is focused and reuses the existing Column.sv persistence plus AutoCloseSessionVariable; no unrelated API, configuration, or BE/protocol changes were introduced.
  • Concurrency and lifecycle: source DDL and maps are captured under the same table read lock, and the per-column resource scope restores the exact caller session on analysis failures. The initial whole-DDL parse remains outside that scope.
  • Compatibility and persistence: the existing serialized format is reused, but an absent map from older generated-column metadata is normalized to empty and must retain the persisted analyzed expression's behavior.
  • Parallel paths and conditions: ordinary CREATE remains unchanged, ALTER ADD generated columns is unsupported, and current insert binding uses the persisted analyzed expression plus session guards. The unsafe branches are the pre-guard parse and the distinction between an absent/empty legacy map and a usable saved map.
  • Tests: the added unit and regression coverage is deterministic and exercises successful mode transfer in both decimal directions, repeated cloning, NULLs, and PIPES_AS_CONCAT. It does not cover a mode-dependent lexer boundary or legacy empty-map replay.
  • Operations and performance: no new operational surface, observability requirement, or material hot-path cost was found. No other distinct issue remained after three bounded review rounds.

Validation is static only: the review contract prohibited builds and tests, so author/CI test claims were not independently executed.

createTableCommand = new CreateTableCommand(createTableCommand.getCtasQuery(),
createTableInfo.withTableNameAndIfNotExists(createTableLikeInfo.getTableName(),
createTableLikeInfo.isIfNotExists()));
for (ColumnDefinition column : createTableInfo.getColumnDefinitions()) {

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] Apply the source SQL mode before the first DDL parse

These saved settings are attached only after parseSingle has already lexed the rendered CREATE statement under the caller's sql_mode. Column.toSql emits GeneratedColumnInfo.exprSql verbatim, so a source created with NO_BACKSLASH_ESCAPES can validly store concat(a, 'C:\'); after the caller clears that mode, the first parse treats the backslash as escaping the closing quote and fails before this loop or GeneratedColumnDesc.getExpression() can run. The lexer test for a trailing backslash already demonstrates this token-boundary split. Please make the initial synthetic-DDL parse independent of the caller mode (or activate the saved mode before it), and cover this opposite-mode literal case.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

public Expression getExpression() {
return expression;
// CREATE TABLE LIKE must also parse the expression under its original session settings.
return sessionVariables.isPresent() ? new NereidsParser().parseExpression(exprSql) : expression;

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 legacy generated expressions without a session map

Generated columns existed before Column.sessionVariables, and replay normalizes those missing maps to empty. CREATE LIKE makes that empty map present, AutoCloseSessionVariable applies no override, and this line reparses raw exprSql under the caller. A legacy source created with PIPES_AS_CONCAT can therefore keep executing its serialized analyzed concat expression in BindSink, while LIKE under the default mode reparses a || 'x' as OR and silently creates a different target. For an empty legacy map, please derive the clone from the persisted analyzed expression (or a mode-neutral canonical rendering) and add an upgrade-compatibility test.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to processed because in old version , user hardly use Generated columns.

### What problem does this PR solve?

Related PR: apache#67809

Problem Summary: The initial synthetic CREATE TABLE parse uses the caller's SQL
mode before saved generated-column settings are restored. A trailing backslash
literal created under NO_BACKSLASH_ESCAPES can therefore prevent CREATE TABLE
LIKE from reaching the guarded expression analysis. Snapshot original expression
SQL together with the saved settings under the source read lock, use AS (NULL)
only in internal LIKE DDL, and restore deferred descriptors before running the
create command. Ordinary DDL rendering remains unchanged. Legacy empty session
maps are outside this change.

### Release note

Fix CREATE TABLE LIKE failing to clone generated columns whose string literals
require the source SQL mode during the initial DDL parse.

### Check List (For Author)

- Test: Unit Test
    - Added opposite backslash modes, repeated LIKE, dependent generated columns,
      unchanged DDL rendering, and session restoration on analysis failure.
    - All 13 CreateTableLikeTest cases passed for this implementation on the
      previous validation branch, commit 00df0febb96.
    - On this target branch, run-fe-ut.sh --run org.apache.doris.catalog.CreateTableLikeTest
      passed production compilation but was blocked during test compilation by
      the existing IvmNormalizeMTMVJoinTest.java:1053 IvmRewriteContext constructor
      mismatch. No unrelated test source was modified.
    - Checkstyle passed for fe-core and fe-catalog; git diff --check passed.
    - No live-cluster regression test was run for this incremental change.
- Behavior changed: Yes; generated expressions are parsed under saved source settings.
- Does this need documentation: No
@feiniaofeiafei

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17668	3811	3768	3768
q2	2252	322	284	284
q3	10059	1407	786	786
q4	4678	483	346	346
q5	7469	827	574	574
q6	183	177	135	135
q7	724	827	594	594
q8	9339	1337	1453	1337
q9	5449	4197	4164	4164
q10	6743	1633	1354	1354
q11	417	261	239	239
q12	640	416	296	296
q13	18067	2647	2016	2016
q14	258	259	232	232
q15	q16	734	720	663	663
q17	1723	1091	953	953
q18	6491	5607	5540	5540
q19	1165	1185	1082	1082
q20	492	383	271	271
q21	5481	2719	2499	2499
q22	438	361	303	303
Total cold run time: 100470 ms
Total hot run time: 27436 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4517	4450	4371	4371
q2	771	630	572	572
q3	4867	5166	4870	4870
q4	2311	2325	1467	1467
q5	4602	4501	4394	4394
q6	240	178	130	130
q7	1834	1769	1532	1532
q8	2352	2068	2019	2019
q9	7363	7114	6840	6840
q10	4259	4191	3788	3788
q11	517	371	341	341
q12	694	704	500	500
q13	2320	2613	2016	2016
q14	274	291	241	241
q15	q16	661	703	614	614
q17	7251	6747	6661	6661
q18	11894	11073	11760	11073
q19	1116	1020	1053	1020
q20	2202	2220	1898	1898
q21	5389	4442	4622	4442
q22	496	434	396	396
Total cold run time: 65930 ms
Total hot run time: 59185 ms

@hello-stephen

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

query5	4321	576	445	445
query6	434	195	170	170
query7	4804	547	275	275
query8	338	185	164	164
query9	8740	4017	4011	4011
query10	465	296	257	257
query11	5813	2143	2004	2004
query12	160	96	96	96
query13	1270	595	421	421
query14	6520	4540	4217	4217
query14_1	4001	3956	4001	3956
query15	201	197	182	182
query16	966	454	433	433
query17	910	665	532	532
query18	2468	456	349	349
query19	207	192	146	146
query20	105	102	102	102
query21	224	133	114	114
query22	13076	13025	12778	12778
query23	15499	14496	14030	14030
query23_1	14020	14175	14206	14175
query24	7610	1682	1238	1238
query24_1	1232	1218	1215	1215
query25	528	438	363	363
query26	1251	317	168	168
query27	2667	543	337	337
query28	4517	1951	1967	1951
query29	1072	600	478	478
query30	317	238	205	205
query31	901	748	635	635
query32	154	99	97	97
query33	529	315	250	250
query34	1164	1081	626	626
query35	714	752	649	649
query36	789	803	695	695
query37	150	108	91	91
query38	1828	1767	1680	1680
query39	671	686	650	650
query39_1	650	626	646	626
query40	224	122	100	100
query41	72	71	68	68
query42	96	93	90	90
query43	345	341	306	306
query44	1360	712	714	712
query45	191	183	172	172
query46	1094	1187	708	708
query47	1490	1502	1396	1396
query48	388	376	293	293
query49	587	404	291	291
query50	975	335	254	254
query51	10466	10417	10286	10286
query52	83	88	72	72
query53	236	258	176	176
query54	252	213	179	179
query55	81	78	67	67
query56	224	227	222	222
query57	1465	1406	1277	1277
query58	227	211	205	205
query59	1980	2049	1791	1791
query60	283	243	216	216
query61	135	142	144	142
query62	394	315	267	267
query63	219	178	180	178
query64	2643	999	780	780
query65	3984	4000	3929	3929
query66	1783	409	303	303
query67	20068	19774	25996	19774
query68	3197	1557	836	836
query69	397	289	260	260
query70	954	871	852	852
query71	314	231	212	212
query72	2898	2482	2205	2205
query73	816	783	448	448
query74	4616	4478	4304	4304
query75	2277	2261	1935	1935
query76	2327	1071	723	723
query77	357	383	298	298
query78	9063	9059	8391	8391
query79	1378	1196	741	741
query80	738	446	355	355
query81	502	276	237	237
query82	626	171	120	120
query83	347	273	241	241
query84	311	140	112	112
query85	864	464	381	381
query86	379	242	226	226
query87	2013	1966	1812	1812
query88	3615	2762	2734	2734
query89	358	282	244	244
query90	1824	180	174	174
query91	167	154	127	127
query92	101	90	88	88
query93	1409	1442	893	893
query94	606	352	302	302
query95	653	380	438	380
query96	1064	882	330	330
query97	2442	2448	2345	2345
query98	194	185	180	180
query99	742	720	609	609
Total cold run time: 240284 ms
Total hot run time: 153342 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.10	0.05	0.05
query3	0.25	0.14	0.14
query4	1.61	0.14	0.14
query5	0.24	0.22	0.22
query6	1.16	0.95	0.90
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.38	0.34	0.34
query10	0.53	0.55	0.53
query11	0.21	0.14	0.13
query12	0.18	0.15	0.14
query13	0.46	0.46	0.47
query14	0.96	0.95	0.96
query15	0.60	0.59	0.58
query16	0.34	0.32	0.34
query17	1.10	1.13	1.09
query18	0.22	0.20	0.20
query19	1.93	1.97	1.92
query20	0.02	0.02	0.01
query21	15.44	0.21	0.15
query22	4.93	0.05	0.04
query23	16.14	0.31	0.13
query24	2.96	0.42	0.33
query25	0.11	0.04	0.04
query26	0.72	0.20	0.16
query27	0.05	0.04	0.04
query28	3.56	0.75	0.34
query29	12.49	4.01	3.22
query30	0.28	0.15	0.17
query31	2.77	0.58	0.31
query32	3.22	0.58	0.49
query33	3.13	3.21	3.14
query34	15.75	3.85	3.28
query35	3.26	3.27	3.25
query36	0.54	0.42	0.43
query37	0.08	0.06	0.07
query38	0.04	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.15	0.14
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.24 s
Total hot run time: 24.01 s

@feiniaofeiafei

Copy link
Copy Markdown
Collaborator Author

/review

@feiniaofeiafei

Copy link
Copy Markdown
Collaborator Author

run feut

@feiniaofeiafei

Copy link
Copy Markdown
Collaborator Author

run cloud_p0

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

Static review result: REQUEST_CHANGES.

I found one distinct blocking correctness issue: copied-schema Decimal256 validation still runs under the caller's setting before the source generated-column setting is applied. The inline comment contains the reproducer and requested regression coverage.

Checkpoint conclusions:

  • Correctness and goal: placeholder reconstruction now avoids caller-SQL-mode tokenization for current managed-table metadata, and nonempty per-column maps flow through analysis, persistence, and later BindSink rebinding. The goal is still incomplete for declared or nested Decimal256 types above precision 38; the already-open legacy empty-map issue was not duplicated.
  • Scope and parallel paths: placeholder rendering is confined to the sole managed CREATE TABLE LIKE reconstruction call. Ordinary SHOW/CREATE/ALTER and external rendering retain their prior paths.
  • Concurrency and lifecycle: source descriptors are copied under the table read lock, then used locally; try-with-resources restores the exact caller session on success and failure. No new shared-state or lock-order issue was found, but the scope begins too late for copied type validation.
  • Configuration, compatibility, and persistence: no new configuration, FE-BE protocol, or storage-format field is introduced. Existing nonempty session maps are defensively copied and persisted; upgrade-era absent/empty maps remain covered by an existing review thread.
  • Tests: the added unit/regression cases are deterministic and cover both backslash modes, repeated LIKE, caller restoration, runtime decimal-derived semantics, and PIPES_AS_CONCAT. They omit a declared precision-above-38 case, which would expose the inline issue. This review was static-only; no build or tests were run under the review contract.
  • Error handling, data safety, performance, and observability: failures abort before publication and restore caller state; no transaction or data-write path changes. The cold-DDL work is linear in schema size with small map copies, and no material performance or observability concern was found.

User focus: no additional user-provided review focus was specified. The review converged after two rounds with no unresolved candidates beyond the submitted issue and the existing duplicate-fenced threads.

Expr e = expr.accept(translator, planTranslatorContext);
info.get().setExpr(e);
exprAndNames.add(new ExprAndName(e.clone(), column.getName()));
try (AutoCloseSessionVariable autoClose = new AutoCloseSessionVariable(ctx,

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] Validate reconstructed Decimal256 types independently of the caller

This scope starts only inside generatedColumnCheck, after validate() has already called ColumnDefinition.validate for every copied column. A source created with enable_decimal256=true, for example (k INT, g DECIMAL(40,0) AS (k)), is rendered and parsed successfully as decimal(40,0) AS (NULL); however, with the caller setting disabled, type.validateDataType() rejects that declared Decimal256 type before execution reaches this saved-session scope. This is distinct from the existing raw-expression lexer thread because the placeholder parse succeeds and the failure occurs later during schema validation. Please make validation of reconstructed catalog types independent of the caller, including recursively nested types, and add an opposite-setting case with declared precision above 38.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should report error for this "CREATE TABLE dst LIKE src; " in :

SET enable_decimal256 = true;
CREATE TABLE src (
    k INT,
    g DECIMAL(40,0) AS (k)
)
DISTRIBUTED BY HASH(k) BUCKETS 1
PROPERTIES ("replication_num" = "1");

SET enable_decimal256 = false;
CREATE TABLE dst LIKE src; 

@CalvinKirs
CalvinKirs merged commit d07e97b into apache:master Sep 18, 2026
40 of 41 checks passed
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.

5 participants