Skip to content

[feature](variant) Add variant_escape_dots_in_keys to keep dotted keys distinct - #69995

Open
eldenmoon wants to merge 32 commits into
apache:masterfrom
eldenmoon:branch-variant-escape-dots
Open

eldenmoon wants to merge 32 commits into
apache:masterfrom
eldenmoon:branch-variant-escape-dots

Conversation

@eldenmoon

@eldenmoon eldenmoon commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: N/A

Related PR: #70001

Problem Summary:

Legacy VARIANT stores {"a.b":1} and {"a":{"b":2}} in the same dotted path namespace. Literal dotted keys can become nested objects, and an object containing both shapes can fail with duplicated entry. This PR adds an opt-in, lossless storage encoding while retaining legacy behavior for existing tables.

Design

  • Add the immutable table property variant_escape_dots_in_keys, default false. It applies to every VARIANT column of the table and to all its indexes (rollups, synchronous MVs); columns added later inherit it.
  • Encode each stored key component once: % becomes %25, . becomes %2E. Decode when assembling objects. Logical paths remain component arrays throughout computation and slot identity.
Logical path Stored relative path
["a.b"] a%2Eb
["a","b"] a.b
["a%2Eb"] a%252Eb
  • Keep path statistics, sparse/DOC keys, bucket hashes, compaction schemas and index suffixes in storage syntax. Templates, field_pattern and SEARCH field syntax retain that storage-path contract. SQL subscripts use logical keys.
  • Each segment records a root marker (0 legacy, 1 escaped); readers decode by the marker and reject unknown markers. Rewrites decode and re-encode whole values. Physical index suffixes escape % only for escaped tables.
  • MATCH/SEARCH index metadata resolves through one catalog API that takes logical components and reads the flag from the table. BE scoring resolves the same encoded path as the scanner. Condition-cache digests distinguish logical components rather than flattened display names.

Table property

CREATE TABLE t (k INT, v VARIANT)
DUPLICATE KEY(k) DISTRIBUTED BY HASH(k) BUCKETS 1
PROPERTIES ("variant_escape_dots_in_keys" = "true");
  • Settable only at creation: CREATE TABLE, CTAS and async MV; CREATE TABLE LIKE copies it. ALTER TABLE ... SET rejects the key in any form. The column-level form VARIANT<PROPERTIES("variant_escape_dots_in_keys"=...)> is rejected with a message pointing to the table property.
  • Stored and shown in SHOW CREATE TABLE only when true, so other tables' DDL is unchanged.
  • An escaped table cannot enable NestedGroup on any column, whether set explicitly or through default_variant_enable_nested_group.
  • The flag is not part of the VARIANT type. Execution uses canonical VARIANT values, so scalar functions, common-type inference and recursive CTE compatibility have nothing to propagate.

Derived tables

  • CTAS into an internal OLAP table uses an explicit property when given. Otherwise the target is escaped when any OLAP table the statement uses is escaped, including tables reached through CTEs, views and subqueries. Counting a table that the query does not read only makes the target escaped, which is lossless.
  • An async MV must use the same value as its OLAP base tables that have VARIANT columns; it inherits that value, and creation fails when those base tables differ or an explicit value contradicts them. Query rewrite replaces base scans with MV scans, and v['a.b'] maps to different storage paths on legacy and escaped tables, so mismatched MVs are rejected rather than rewritten. Refresh keeps the value fixed at creation and fails, leaving the MV out of rewrite, if its base tables change (for example through ALTER VIEW) to a different value.
  • The decision lives in one PropertyAnalyzer helper, called by CTAS and by InternalCatalog.createOlapTable for async MVs. Escaped-table schema checks (no NestedGroup, valid template and field_pattern storage paths) run in one function at table creation, schema change and synchronous MV creation.

BE transport

The BE receives the flag only when a tablet is created (TTabletSchema 34, TabletSchemaPB 47, TabletSchemaCloudPB 48) and keeps it in the persisted tablet schema. Loads, scans, schema change, compaction and rowid fetch read it from there, so no load or scan protocol field is needed. On the FE, CreateReplicaTask and the cloud tablet meta builder take the flag as a required parameter. Escaped VARIANT columns do not use the shared column object pool, whose key is the column PB.

Compatibility

Enable the property only after every FE and BE is upgraded; mixed-version clusters are not supported for escaped tables, and downgrading after creating one is unsupported. Existing legacy tables and data are unchanged. Protocol fields are optional: TTabletSchema 34, TabletSchemaPB 47, TabletSchemaCloudPB 48 and ColumnMetaPB 28, checked as unused on master, branch-4.2, branch-4.1, branch-4.0 and branch-3.1. Extended DESC displays stored paths such as v.a%2Eb.

Release note

Add the table property variant_escape_dots_in_keys, which stores literal dotted VARIANT keys separately from nested paths. It is set at creation and inherited by CTAS and async MVs over escaped tables. Enable it only after all FE/BE nodes are upgraded.

Check List (For Author)

  • Test
    • Regression test
    • Unit Test
    • Manual test

Validation at f63f7fb5cf5, merged with master 4c63661f60f (ASAN BE+FE, FE fuzzy session variables on with fuzzy_test_type=p0 unless noted):

  • Full variant_p0: 210 suites, 209 passed, no .out regeneration. The only failure is outfile_csv_variant_doc_value with object storage HTTP 403 InvalidAccessKeyId, which also fails with fuzzy off. The local BE caps max_sys_mem_available_low_water_mark_bytes at 1 GiB because the shared 1.5 TB host otherwise derives a 151 GB warning water mark and cancels small queries with MEM_LIMIT_EXCEEDED.

  • BE UT: tablet schema, writer/reader (golden segment bytes, cross-encoding sink), binary extract iterator, shredder, pb_convert and rowid fetch: 195 passed, 2 skipped (NestedGroup writing is unavailable in this build). Earlier runs of the broader set (rowset builder, schema change, compaction): 577 passed. Cloud SchemaKVTest: 9 passed.

  • FE UT: 325 classes referencing the changed classes and methods, 3686 passed. The one failure, DiskReblanceWhenSchedulerIdle, asserts a tablet distribution after a fixed one-second wait on INT tables; the test and the scheduler code are unchanged from master.

  • Suite adjustments: dotted_key_escape_common_type and dotted_key_escape_score pin the doc mode (and, for score, subcolumn) defaults that fuzzy randomizes; a path that is not materialized scores 0 on both legacy and escaped tables.

  • New coverage: async MV inheritance, explicit true, rejected explicit false and rejected mixed VARIANT sources, int-only legacy join escaped table, refresh; CTAS inheritance through CTE/view/subquery/recursive CTE and explicit overrides; int-only CTAS followed by ADD COLUMN VARIANT; ALTER rejection; NestedGroup rejection (explicit and session default); rollup inheritance; row store with and without two-phase read; sparse path promotion during compaction (dotted_key_escape_sparse_promotion).

  • Recursive CTE mixing a legacy anchor with an escaped recursive branch (and the reverse) returns literal and nested keys correctly both directly and after CTAS.

  • Clang-format 16, clang-tidy on changed lines, FE Checkstyle and build hygiene passed.

  • Behavior changed: Yes; opt-in table property for lossless dotted keys.

  • Does this need documentation: Yes; website documentation follows the feature PR.

Check List (For Reviewer who merge this PR)

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

🤖 Generated with Claude Code

eldenmoon and others added 2 commits November 2, 2026 19:31
### What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary:

Add the legacy semantics and rewrite suites, with their generated outputs, before the opt-in feature. They establish a pristine-master baseline and ensure that columns without the new property retain their existing behavior.

Lock dotted-key flattening and the difference between pushed-down access and in-memory element_at: {"a.b":1} reads back as {"a":{"b":1}}, both pushed-down paths return 1, and exact in-memory element_at(v, 'a.b') returns NULL. Also lock ancestor hiding for {"a":5,"a.b":6}, the legacy inverted-index duplicate-directory error, and index-on/off results across separate segments.

Use extended DESC to distinguish physical ancestor retention from visibility: INSERT SELECT, heavy schema change and whole-value compaction remove the hidden v.a path, while per-path vertical compaction retains it. Pin Variant layout properties and order query results so the outputs remain stable.

### Release note

None

### Check List (For Author)

- Test: Regression test. dotted_key_legacy_semantics and dotted_key_legacy_rewrite passed on pristine master (49bfbde) and on the final feature binary with -parallel 1. Their outputs remained byte-identical; duplicate_json_path also passed as a sanity check.
- Behavior changed: No. This commit records current behavior without changing the implementation.
- Does this need documentation: No. Test coverage only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s distinct

### What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary:

Variant V2 stores `{"a.b":1}` and `{"a":{"b":2}}` under the same storage path `a.b`, so a dotted key cannot be told apart from the nested path: `{"a.b":1}` reads back as `{"a":{"b":1}}`, and putting both shapes in one object fails the load with `may contains duplicated entry` (locked by the legacy suites and `duplicate_json_path`).

Add the creation-time Variant property variant_escape_dots_in_keys, default false, to preserve dotted keys independently of nested paths. Encode percent and dot characters per key component, persist a segment-root encoding marker, and decode strictly when the assembler emits object keys. Keep per-path storage machinery in storage syntax and reject incompatible segment markers, ALTER changes in either direction, and NestedGroup combinations.

Plumb the property through FE, optional protocol fields and TabletColumn. Encode logical scan and rowid paths once, key CAST pushdown types by storage column names, and use injective index suffixes only for escaped columns. Write escaped sparse keys in byte order for binary-search lookup. Preserve all keys through whole-value rewrites and retain legacy behavior for columns without the property.

The optional field ids are ColumnPB 36, ColumnMetaPB 28 and TColumn 31, checked against every supported release branch. The pre-existing sparse ordering issue for legacy keys with bytes below '.' is handled by a separate PR.

### Release note

Add the opt-in Variant property variant_escape_dots_in_keys to keep dotted keys distinct from nested paths. Enable it only after every FE and BE is upgraded; tables using it cannot be downgraded.

### Check List (For Author)

- Test: Regression test and Unit Test.
  - ASAN BE referenced tests: 1,616 passed, 5 skipped; final focused tests: 203 passed, 2 skipped.
  - FE: 817 tests across 40 classes passed after the final FE change.
  - New semantics/rewrite suites passed output generation, output review and reruns. Both legacy suites and duplicate_json_path passed; all five targeted suites passed on the final binary, and legacy outputs stayed byte-identical.
  - Full variant_p0: 176 of 186 suites passed initially. All 10 failures were rerun separately with -parallel 1; 8 passed after enabling debug points. Remaining failures were OSS InvalidAccessKeyId and an existing schema-change baseline expecting integer 1 instead of boolean true. The HEAD V2 counterpart expects true and passed; no separate pristine-master rebuild was run for this baseline comparison.
  - ASAN product builds, formatting and build hygiene passed. Final clang-tidy diagnostics on added lines: zero; existing diagnostics were retained.
- Behavior changed: Yes. New opt-in column property; default behavior is unchanged.
- Does this need documentation: Yes. Document PR to follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eldenmoon
eldenmoon requested a review from yiguolei as a code owner November 2, 2026 11:32
@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: 28717 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit ee387d6f506836205235007f490be88415e04a87, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17407	5145	5073	5073
q2	2128	306	246	246
q3	10172	1382	844	844
q4	4683	467	334	334
q5	7448	811	542	542
q6	189	187	155	155
q7	761	804	606	606
q8	9267	1396	1168	1168
q9	5559	4220	4216	4216
q10	6823	1288	1023	1023
q11	451	263	228	228
q12	638	410	290	290
q13	18080	3686	3041	3041
q14	279	277	255	255
q15	q16	724	718	656	656
q17	1182	763	584	584
q18	7061	6163	6085	6085
q19	1111	970	631	631
q20	398	347	228	228
q21	5093	2246	2441	2246
q22	355	305	266	266
Total cold run time: 99809 ms
Total hot run time: 28717 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5643	5635	5618	5618
q2	690	574	515	515
q3	5142	5376	4887	4887
q4	2021	2175	1597	1597
q5	5251	5152	5706	5152
q6	260	204	157	157
q7	2354	2073	1849	1849
q8	3132	2820	2733	2733
q9	8056	7967	7926	7926
q10	4054	3683	3283	3283
q11	655	452	429	429
q12	700	694	535	535
q13	3688	3999	3312	3312
q14	313	315	286	286
q15	q16	674	715	633	633
q17	8018	7062	6952	6952
q18	12995	12231	12976	12231
q19	936	826	825	825
q20	2144	2174	1932	1932
q21	5948	4969	5025	4969
q22	499	450	413	413
Total cold run time: 73173 ms
Total hot run time: 66234 ms

@hello-stephen

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

query5	4317	575	443	443
query6	433	207	190	190
query7	4806	448	222	222
query8	335	162	154	154
query9	8806	3153	3162	3153
query10	484	310	259	259
query11	6019	3847	3571	3571
query12	147	88	84	84
query13	1254	451	324	324
query14	6102	3961	3633	3633
query14_1	3443	3455	3424	3424
query15	205	200	179	179
query16	937	429	408	408
query17	849	682	544	544
query18	2417	418	312	312
query19	202	170	137	137
query20	89	85	84	84
query21	214	137	105	105
query22	13044	13071	13079	13071
query23	13534	12944	12481	12481
query23_1	12602	12455	12506	12455
query24	7298	864	473	473
query24_1	498	487	482	482
query25	533	421	369	369
query26	1261	264	141	141
query27	2766	444	280	280
query28	4599	2036	2039	2036
query29	1561	599	448	448
query30	306	226	191	191
query31	1005	933	816	816
query32	141	93	97	93
query33	530	304	245	245
query34	924	852	500	500
query35	740	758	647	647
query36	842	820	786	786
query37	123	94	87	87
query38	1765	1746	1705	1705
query39	792	786	745	745
query39_1	724	727	733	727
query40	222	118	100	100
query41	74	70	67	67
query42	90	83	81	81
query43	351	369	309	309
query44	1299	698	717	698
query45	183	174	163	163
query46	873	981	576	576
query47	2940	2903	2796	2796
query48	308	360	215	215
query49	573	389	288	288
query50	665	279	202	202
query51	10647	10704	10445	10445
query52	77	86	69	69
query53	185	214	153	153
query54	233	189	171	171
query55	73	67	64	64
query56	222	228	219	219
query57	1671	1636	1554	1554
query58	282	265	253	253
query59	2154	2172	1951	1951
query60	281	249	229	229
query61	152	147	145	145
query62	379	333	276	276
query63	189	158	159	158
query64	2739	993	779	779
query65	3326	3266	3286	3266
query66	1784	414	298	298
query67	20302	20148	20254	20148
query68	3041	990	635	635
query69	396	284	254	254
query70	842	775	777	775
query71	290	233	202	202
query72	2779	2596	2299	2299
query73	515	522	302	302
query74	4600	4525	4335	4335
query75	2285	2291	1920	1920
query76	2276	1006	586	586
query77	330	373	276	276
query78	9681	9817	9137	9137
query79	1002	928	539	539
query80	698	409	356	356
query81	558	325	273	273
query82	564	131	104	104
query83	272	198	199	198
query84	309	120	97	97
query85	902	428	374	374
query86	318	247	231	231
query87	1984	1971	1843	1843
query88	3769	2782	2767	2767
query89	327	282	239	239
query90	1803	176	166	166
query91	162	152	128	128
query92	94	94	80	80
query93	1030	1019	571	571
query94	464	298	269	269
query95	573	379	294	294
query96	677	487	240	240
query97	2434	2452	2325	2325
query98	165	154	151	151
query99	776	755	633	633
Total cold run time: 234690 ms
Total hot run time: 151673 ms

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#69995

Problem Summary:

The shredder assertion cannot fire because encode_variant_path_component replaces every dot with %2E. The compaction assertion cannot fire because PathInData's string constructor already splits on dots, so no resulting component can contain one. Remove the per-key rescan and redundant temporary path parsing; retain the reader's segment marker checks and the compaction encoding gate.

### Release note

None

### Check List (For Author)

- Test: Unit Test and Regression test.
  - ASAN BE build and clang-format passed; clang-tidy reported no diagnostics on changed lines in either file.
  - BE UT: 139 tests across 6 suites, 137 passed, 2 skipped, 0 failed. Covered PathInDataTest, SchemaUtilTest, VariantCompactionPathsTest, IndexStorageVariantCompactionSchemaTest, VariantColumnWriterReaderTest and VariantShredderTest.
  - dotted_key_escape_semantics, dotted_key_escape_rewrite, dotted_key_legacy_semantics, dotted_key_legacy_rewrite and duplicate_json_path all passed with -parallel 1, without -genOut. All five output files remained byte-identical.
- Behavior changed: No. Remove assertions whose predicates are guaranteed by the codec or parser.
- Does this need documentation: No.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@eldenmoon

Copy link
Copy Markdown
Member Author

Review:兼容性、性能、可维护性与冗余

审查提交:ee6ce712a0381422bc44e4d8d27490cf66f32464;比较基线为 merge base 49bfbdecffb5b37aeadb0982700533e8daf7768d。

按 doris-repo-review 工作流进行了两轮静态交叉审查,覆盖全部 59 个变更文件及相关调用链。结论:REQUEST_CHANGES,1 项 Major、2 项 Minor。建议先修复 F-01。 本轮未编译、未运行测试;下列触发场景与影响来自源码追踪,PR 描述中的测试结果不作为本轮实测。

F-01 · Major:类型 SQL 往返丢失显式 nested_group=false,使合法表的 CREATE TABLE LIKE 失败

位置:catalog VariantType.toSql、Nereids VariantType.toSql。

两处 serializer 会输出 variant_escape_dots_in_keys=true,但只在 nested group 为 true 时输出该属性。对新功能而言,显式的 variant_enable_nested_group=false 是合法配置的重要组成部分,省略它会让重新解析依赖当前会话默认值。

具体场景:

  1. 设置 default_variant_enable_nested_group=true。
  2. 创建源表,Variant 列显式配置 variant_escape_dots_in_keys=true、variant_enable_nested_group=false。
  3. 执行 CREATE TABLE dst LIKE src。

CREATE TABLE LIKE 经 Env.getCreateTableLikeStmt → Column.toSql → VariantType.toSql 生成 SQL,再在当前会话中重新解析。生成的 SQL 缺少 nested=false,因此 LogicalPlanBuilder 从会话补成 true,最终因 escape=true 与 nested=true 的互斥检查而拒绝。在该会话下重放 SHOW CREATE 输出也有相同问题。这里确认的是合法 DDL 无法往返,没有证据表明会损坏已有数据。

建议: 两处 SQL renderer 都在 enableNestedGroup || escapeDotsInKeys 时显式输出 nested group 的实际布尔值。开启 escaping 时必须保留 false。补上“会话默认 true + 源列显式 false”的类型解析往返、CREATE TABLE LIKE 和 SHOW CREATE 重放测试,同时保留旧模式的序列化基线。

F-02 · Minor:compaction 的预校验会在 segment cache miss 时重复初始化 Segment / column reader

位置:variant_util.cpp:764–770,以及后续 schema 汇总加载路径。

新校验阶段加载 segment 并初始化 root reader,但局部 handle 在该 rowset 检查结束后释放。未命中 segment cache、且不向该缓存插入的路径上,后续 schema 汇总又加载同一批 segment/root reader,产生重复的对象和元数据初始化。

建议: 让校验与 schema 汇总共用已加载的 handle,或在汇总遍历中完成校验;没有 schema 汇总的 compaction 模式仍须保留校验。

这里不能把 marker 校验本身删掉:缓存 reader 之前校验的是所属 rowset 的 schema,目标 compaction schema 仍须独立验证。也不能直接声称磁盘 I/O 翻倍:独立的 footer/page cache 可能避免重复读取,热 segment cache 也可复用对象。本项仅报告源码可证明的重复初始化,未测量耗时退化。

F-03 · Minor:显示名仍合并两种逻辑路径,导致部分 CAST 标量下推和剪枝能力丢失

位置:olap_scanner.cpp:639–642。

BE 最终改用 storage column name 是必要的,但上游 FE 仍把 ['a.b'] 与 ['a','b'] 都展开为显示名 v.a.b,CAST 收集也仍按该名称分组并要求恰好一个 CAST。新功能已经把它们保存为不同物理子列,这层分组身份却没有同步区分。

例如在两个路径均已提取为 BIGINT 子列的 escaped 表上,同时使用:

CAST(v['a.b'] AS BIGINT) = 1
AND CAST(v['a']['b'] AS BIGINT) = 2

两条路径的 CAST 会混在同一组,不能分别进入标量 range 路径;当父 Variant 配置 Bloom filter、两个已提取子列具备相应 Bloom 索引时,会损失这条标量谓词路径的 Bloom 剪枝机会。

影响边界: slot ID 检查仍阻止谓词被错误应用到另一列;common-expression fallback 仍可使用倒排索引和 zone map。因此本项是可选的性能改进,不是已确认的错误结果,也不等于所有索引失效或必然全表扫描。

建议: CAST 收集与 range 初始化按 slot ID 保持身份,再从各 slot 的完整路径生成 storage name;补一条同时引用 dotted literal 与 nested path 的组合用例,检查两条标量下推路径都能建立。

兼容性与冗余结论

  • 本轮没有确认默认关闭时的旧表行为回归;以上三项均为新 opt-in 功能上的缺口或优化机会,Regression: no。
  • % → %25 与 . → %2E 的组合、持久化 marker、property/marker 一致性检查,以及 escaped sparse key 的字节排序都有实际用途,应保留。尤其稀疏排序服务于读取端二分查找,不是多余排序。
  • FE 中 parser、直接构造的 CTAS ColumnDefinition、CREATE/ALTER INDEX 的校验覆盖不同入口,不能因条件相似就直接去掉其中一处。
  • 优先简化的是 F-02 的重复加载/初始化,以及 F-03 分散的显示名/存储名身份转换。
  • 混合版本启用和降级仍属于 PR 明确排除的使用方式。新属性应在全部 FE/BE 升级后启用;本次没有把可选字段的默认值兼容等同于混合版本安全。

完整覆盖已在第二轮收敛;没有确认新的数据丢失、错误结果或旧模式回归。建议修复 F-01 后再合入,F-02/F-03 可作为后续性能与维护性改进。

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	16534	5286	5025	5025
q2	2133	315	245	245
q3	9854	1401	809	809
q4	4555	474	336	336
q5	7308	797	529	529
q6	188	184	150	150
q7	732	782	596	596
q8	9427	1338	1014	1014
q9	5563	4191	4172	4172
q10	6815	1276	1021	1021
q11	412	251	229	229
q12	636	391	285	285
q13	17893	3571	3063	3063
q14	277	272	249	249
q15	q16	729	723	675	675
q17	1202	736	599	599
q18	7051	6141	6076	6076
q19	1106	965	610	610
q20	374	333	224	224
q21	4753	2135	2286	2135
q22	343	297	263	263
Total cold run time: 97885 ms
Total hot run time: 28305 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5608	5560	5600	5560
q2	693	578	555	555
q3	5159	5383	4903	4903
q4	1964	2122	1545	1545
q5	5217	5058	5125	5058
q6	236	187	147	147
q7	2504	2039	1937	1937
q8	3027	2654	2688	2654
q9	8043	7926	7882	7882
q10	3731	3664	3253	3253
q11	766	451	445	445
q12	700	679	523	523
q13	3552	3834	3255	3255
q14	331	327	310	310
q15	q16	711	734	648	648
q17	8304	7249	6865	6865
q18	12971	12164	12916	12164
q19	897	815	802	802
q20	2151	2135	1924	1924
q21	5572	4564	4652	4564
q22	488	457	413	413
Total cold run time: 72625 ms
Total hot run time: 65407 ms

@hello-stephen

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

query5	4306	582	451	451
query6	427	222	190	190
query7	4805	438	224	224
query8	318	164	151	151
query9	8759	3228	3219	3219
query10	460	323	252	252
query11	6019	3849	3564	3564
query12	147	91	90	90
query13	1245	437	349	349
query14	6148	3943	3650	3650
query14_1	3430	3410	3366	3366
query15	204	201	182	182
query16	940	423	405	405
query17	848	668	559	559
query18	2425	412	303	303
query19	196	170	138	138
query20	83	84	81	81
query21	212	130	107	107
query22	13030	13157	12927	12927
query23	13403	12818	12351	12351
query23_1	12542	12518	12610	12518
query24	7182	838	512	512
query24_1	473	484	479	479
query25	515	395	328	328
query26	1251	250	132	132
query27	2790	440	269	269
query28	4520	2025	2021	2021
query29	1538	572	440	440
query30	305	229	180	180
query31	1012	926	817	817
query32	144	90	84	84
query33	517	294	237	237
query34	891	854	499	499
query35	721	743	655	655
query36	831	804	723	723
query37	124	99	82	82
query38	1809	1745	1664	1664
query39	789	795	743	743
query39_1	726	716	740	716
query40	219	112	93	93
query41	67	63	62	62
query42	82	84	79	79
query43	343	361	308	308
query44	1377	693	710	693
query45	170	174	163	163
query46	860	952	567	567
query47	2760	2927	2919	2919
query48	304	308	214	214
query49	568	401	288	288
query50	713	282	216	216
query51	10335	10365	10465	10365
query52	80	85	74	74
query53	191	203	153	153
query54	243	188	173	173
query55	70	67	69	67
query56	237	247	212	212
query57	1669	1633	1572	1572
query58	279	260	255	255
query59	2133	2149	1971	1971
query60	294	238	215	215
query61	145	145	142	142
query62	380	328	286	286
query63	193	159	159	159
query64	2689	932	745	745
query65	3364	3297	3291	3291
query66	1760	440	295	295
query67	20036	20184	20154	20154
query68	2946	1013	617	617
query69	390	290	244	244
query70	871	790	775	775
query71	300	235	207	207
query72	2686	2526	2265	2265
query73	509	545	301	301
query74	4629	4530	4316	4316
query75	2340	2260	1952	1952
query76	2110	1015	594	594
query77	344	372	285	285
query78	9820	9679	9207	9207
query79	903	874	566	566
query80	502	417	353	353
query81	519	322	272	272
query82	199	133	107	107
query83	191	197	179	179
query84	282	125	103	103
query85	754	400	369	369
query86	255	243	231	231
query87	1978	1965	1827	1827
query88	3728	2775	2762	2762
query89	322	292	236	236
query90	2004	173	169	169
query91	153	159	128	128
query92	96	85	88	85
query93	998	998	584	584
query94	467	303	270	270
query95	582	396	307	307
query96	708	506	236	236
query97	2427	2431	2288	2288
query98	162	151	146	146
query99	768	758	649	649
Total cold run time: 232372 ms
Total hot run time: 151432 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.14	0.08	0.09
query3	0.34	0.13	0.13
query4	1.61	0.14	0.14
query5	0.28	0.25	0.25
query6	1.15	0.66	0.64
query7	0.04	0.01	0.00
query8	0.09	0.08	0.07
query9	0.44	0.36	0.37
query10	0.62	0.63	0.63
query11	0.34	0.18	0.18
query12	0.31	0.19	0.19
query13	0.52	0.53	0.52
query14	0.93	0.94	0.97
query15	0.66	0.58	0.57
query16	0.36	0.37	0.38
query17	1.06	1.02	1.00
query18	0.28	0.26	0.28
query19	2.02	1.88	1.87
query20	0.03	0.01	0.02
query21	15.42	0.35	0.30
query22	4.93	0.13	0.14
query23	15.86	0.50	0.29
query24	2.00	0.52	0.40
query25	0.16	0.10	0.11
query26	0.76	0.26	0.20
query27	0.10	0.10	0.10
query28	3.50	0.80	0.38
query29	12.58	4.40	3.45
query30	0.33	0.16	0.14
query31	2.76	0.61	0.33
query32	3.23	0.60	0.49
query33	3.03	3.00	2.99
query34	15.87	4.09	3.45
query35	3.38	3.37	3.38
query36	0.58	0.53	0.49
query37	0.12	0.10	0.09
query38	0.07	0.07	0.07
query39	0.06	0.07	0.06
query40	0.18	0.16	0.16
query41	0.10	0.05	0.05
query42	0.06	0.06	0.06
query43	0.06	0.06	0.06
Total cold run time: 96.37 s
Total hot run time: 25.38 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 100.00% (5/5) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 67.18% (32036/47688)
Line Coverage 52.02% (336902/647603)
Region Coverage 47.56% (273833/575730)
Branch Coverage 49.40% (129099/261345)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 65.38% (51/78) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (5/5) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.65% (35876/46202)
Line Coverage 63.01% (403634/640537)
Region Coverage 59.66% (341867/573046)
Branch Coverage 60.76% (158217/260400)

@eldenmoon

Copy link
Copy Markdown
Member Author

/review 除了上面提到的问题,还有哪些问题?尤其注意兼容性

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41567386950

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@eldenmoon

Copy link
Copy Markdown
Member Author

Compaction 数据安全补充:F-04 / Blocker(既有缺陷,Regression: no)

对同一 head ee6ce712a0381422bc44e4d8d27490cf66f32464 重新做了两轮针对 compaction 的静态交叉核验后,需要修正上一条评审“未确认数据丢失”的结论:存在可使已存值消失的受支持路径。 本次没有编译或运行测试;以下是源码确认的机制与建议回归场景。

触发边界

普通 non-DOC Variant、variant_max_subcolumns_count=1、表属性 storage_format="V3",某个用户 JSON key 包含 __DORIS_VARIANT_SPARSE__,并在 full compaction 中从 sparse 提升为 materialized。

这里的 V3 是表的外置列元数据格式,FE 接受显式 V3,省略/default 则返回 V2;它与 ColumnVariantV2、倒排索引 V3 不是同一个配置。本例不需要索引、ALTER 或混合版本。

如何从“compaction 前可读”变成“之后丢值”

令 p="x__DORIS_VARIANT_SPARSE__y",使用三个独立输入 segment:

输入 两行内容 本地 materialized
A {p:701,hot_a:11};{hot_a:12} hot_a(2 > p 的 1)
B {p:702,hot_b:21};{hot_b:22} hot_b
C {p:703,hot_c:31};{hot_c:32} hot_c

所以 p 在所有输入中都是可读的 sparse 值。合并统计后 p=3,大于每个 hot 字段的2,top-N 选择会将 p 提升为 materialized。值先被正确读出;sparse merge随后按目标 selected set 排除 p,唯一输出副本交给新子列。

错误发生在 V3 元数据分类:

if (rel_path.find("__DORIS_VARIANT_SPARSE__") != std::string::npos) {
    classification.pending_sparse[root_uid].emplace_back(col);
}

该 substring 检查把普通用户子列 p 当成内部 sparse 列,嵌入 root.children_columns,而没有写普通子列的外部 path-index entry。读端只识别完整 sparse 标记或其 bucket 前缀;遍历 embedded children 时,p 的 handled=false 被直接忽略,没有普通子列回退。

第一次 full compaction 后:对应行的 v[p] 返回 NULL,整列重建遗漏 p;六行及 hot 字段都还在。p 的页面和错放元数据此时可能仍物理存在,不能说第一次就抹除了所有字节。再加入一个 rowset 并执行第二次 full rewrite 后,统计、子列树和 sparse map 都找不到 p,没有任何读取流复制这些值,新输出 segment 不再包含它们。

现有校验不会阻止此例:行数不变;check_path_stats只遍历 output paths,消失的 input-only p 根本不参加比较,其余 hot 计数仍相等。须使用 FULL compaction 验证,因为该类型会禁用 ordered 文件链接。列组宽度1/2、三个 sparse shard 均不消除此链路。

归因与修复

这是 Blocker / data-error:静默错误结果,后续重写还会丢掉剩余的有效值副本。但不是本 PR 新引入的 codec 回归:相关 classifier 在 merge base 49bfbdecffb5b37aeadb0982700533e8daf7768d 与 head 完全相同,读端遗漏也已存在;escaping 只处理点号/百分号,不能隔离这个内部名称。它仍影响本 PR 支持的 escaped Variant 表。

建议统一 writer/reader 的内部列身份判断,避免 substring 判定。完整路径语法和物理类型校验可修复本例,但 canonical-looking 用户 key 仍需明确的 synthetic-role 元数据或不相交的命名约定。只把 find 改成 starts_with 不是完整修复。对已经写出的异常 V3 segment,应能恢复可明确识别的普通 child,或在再次 compaction 前报错,不能继续静默忽略。

补上以上不同本地热度、两次真实 rewrite、逐行701/702/703和整列内容的回归,不能只检查 count(*)。统计完整且没有行过滤的 DUP 场景还应校验 input-only 路径遗漏;MOW/delete 场景须尊重 survivor 语义。

此前 F-01/F-02/F-03 保持;累计已确认 1 Blocker + 1 Major + 2 Minor,REQUEST_CHANGES。本轮其余普通路径迁移、编码/分片、root 属性传播和 doc 重建没有确认另一条独立丢值路径,但这不构成无条件安全保证。

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#69995

Problem Summary:

An escaped Variant column requires NestedGroup to be off, but both Variant type SQL serializers printed
variant_enable_nested_group only when it was true. Re-parsing fills a missing value from the session
(default_variant_enable_nested_group), so with that variable set to true, CREATE TABLE LIKE and replaying
SHOW CREATE TABLE rejected a valid escaped source table.

Print the actual NestedGroup value whenever escaping is enabled. The SQL of non-escaped columns is unchanged.

### Release note

None

### Check List (For Author)

- Test: Unit Test and Regression test.
  - FE UT: escaped type SQL round trip with and without a session that defaults NestedGroup to true, for both
    the catalog and Nereids types; legacy type SQL text unchanged. Added coverage for the escaped-Variant checks
    in IndexDefinition (CREATE and ALTER INDEX), ColumnDefinition, PropertyAnalyzer, ExpressionTranslator and
    ColumnToProtobuf. 40 related FE UT classes, 841 tests passed.
  - Regression: dotted_key_escape_semantics adds CREATE TABLE LIKE and SHOW CREATE TABLE replay under
    default_variant_enable_nested_group=true. In the semantics and rewrite outputs, only the DESC rows of escaped
    columns change, each by the added nested-group property. dotted_key_escape_{semantics,rewrite},
    dotted_key_legacy_{semantics,rewrite}, duplicate_json_path and eight existing SHOW CREATE / LIKE suites passed.
- Behavior changed: Yes. Escaped Variant type SQL now states variant_enable_nested_group = false.
- Does this need documentation: No.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eldenmoon

Copy link
Copy Markdown
Member Author

run cloud_p0

1 similar comment
@eldenmoon

Copy link
Copy Markdown
Member Author

run cloud_p0

@eldenmoon

Copy link
Copy Markdown
Member Author

run external

@eldenmoon

Copy link
Copy Markdown
Member Author

run vault_p0

@eldenmoon

Copy link
Copy Markdown
Member Author

run feut

@eldenmoon

Copy link
Copy Markdown
Member Author

run nonConcurrent

@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@eldenmoon

Copy link
Copy Markdown
Member Author

/review ignore above known issue

@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 of b1a24ab. One new P2 finding: the versioned DDL returned by ADMIN COPY TABLET omits the immutable Variant path policy and recreates escaped tables as legacy. The normal CREATE/scan/write/rewrite mechanisms otherwise match the intended lossless opt-in design under the supported fully upgraded deployment condition.

User focus: known issues were not duplicated. Existing P1 thread 4499322562 remains technically applicable: old BEs ignore the new optional tablet-schema flag, with no enablement/version gate. The author explicitly chose to ignore it and documents mixed-version use as unsupported; it is retained only as an existing blocker. The previous recursive-CTE flag, translated-slot fallback, external CTAS inheritance, and MV view-retarget refresh concerns no longer apply to this head.

Critical checkpoint conclusions (static inspection):

  1. Goal and proof: literal dotted/percent keys remain distinct from nested paths through canonical values and escaped storage. Unit/regression cases cover these paths; versioned copy-tablet DDL is the new exception and lacks coverage.
  2. Scope and reuse: changes are focused on table policy, path boundaries and associated tests. Shared PropertyAnalyzer and catalog index helpers avoid separate connector/planner implementations.
  3. Concurrency: no new threads or lock order; the policy is initialized before publication and cannot be altered. Escaped schema columns bypass the shared ColumnPB-only object pool.
  4. Lifetimes and initialization: decoded temporary keys are copied into builder-owned storage; schema/iterator ownership remains bounded. No new cross-translation-unit static initialization dependency found.
  5. Configuration: false remains the default; true is creation-only, persisted and shown. ALTER and NestedGroup incompatibilities fail explicitly.
  6. Compatibility: legacy marker/default and suffix behavior remain; unknown markers fail. Fully upgraded same-version paths preserve policy. The known mixed-version concern remains in thread 4499322562.
  7. Thrift/protobuf: read all touched definitions at HEAD and current master/branch-4.2/4.1/4.0/3.1. TTabletSchema 34, TabletSchemaPB 47, TabletSchemaCloudPB 48 and ColumnMetaPB 28 are optional and unused on those branch snapshots; no new ID collision found.
  8. Parallel paths: inspected local/cloud create, report, restore, rollup/schema change, V2/V3, sparse/DOC, horizontal/vertical compaction, rowstore/rowid, direct/fallback index lookup, CTAS and MV refresh. Versioned DDL is the verified omission.
  9. Conditions and errors: invalid booleans/escapes, incompatible MV sources, forbidden ALTER and NestedGroup layouts fail at explicit boundaries. Suspected cast-map alias leaves actual-slot residual evaluation and did not establish a correctness finding.
  10. Test coverage: inspected FE/BE units and all added regression suites, including negative, legacy, cache/index, layout transition, failure-before-publication and MV retargeting cases. The copy-tablet branch needs a focused DDL case.
  11. Expected results: inspected the changed golden outputs against suite queries and path semantics, including repeated sparse-promotion cases. Their generation provenance and runtime pass claims were not independently validated.
  12. Observability: existing DDL/task error propagation and corruption messages expose policy/layout failures; no new per-row logging or metrics required by the inspected change.
  13. Persistence/failover: serialized table properties rebuild the flag on Gson postprocessing; tablet schema and all cloud conversion directions retain it. Existing journal/state transitions remain unchanged; restore signature includes the policy.
  14. Writes and atomicity: compaction/schema-change continue existing publication and version/delete-bitmap lifecycles. Invalid-marker failure preserves input rowsets in the inspected test; no new transaction protocol found.
  15. FE/BE transport: all local CreateReplicaTask and cloud tablet-meta producers pass the required flag; scan/load consumers bind it from persisted tablet metadata.
  16. Performance: component work is cached during shredding and limited to metadata/lookup/reconstruction boundaries; no substantiated material new performance regression found. Display-name cast alias may miss pushdown but retains correctness.
  17. Other concerns: all initial risks and candidates have explicit accepted/dismissed/duplicate dispositions in the ledger; no unresolved code question or uncovered changed-file scope remains.

Review scope is static only: no builds, tests, benchmarks or runtime reproduction were run. Those prohibited activities are not claimed as validation.

Review converged after 2 round(s).

Existing P0/P1 findings confirmed for this head: #69995 (comment)


if (olapTable.getVariantEscapeDotsInKeys()) {
sb.append(",\n\"").append(PropertyAnalyzer.PROPERTIES_VARIANT_ESCAPE_DOTS_IN_KEYS)
.append("\" = \"true\"");

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] Preserve the policy in copy-tablet DDL too

ADMIN COPY TABLET calls getDdlStmt with a concrete replica version. Its specificVersion != -1 branch emits only replication_num/version_info and returns before this renderer, so the returned CreateTableStmt recreates an escaped source with the default legacy policy. Replaying that DDL and inserting parse_to_variant('{"a.b":1}') stores {"a":{"b":1}}, preventing faithful reproduction. Emit this immutable property in the versioned DDL branch as well and cover getDdlStmt with specificVersion set.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ignore at present

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Review recovery stopped: Final review author, head, timestamp, state or summary did not match
Workflow run: https://github.com/apache/doris/actions/runs/43147301860

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

### Background

ADMIN COPY TABLET generates a CREATE TABLE statement for reading a tablet snapshot at a specific version. The debug table must retain the source table's VARIANT key encoding.

### What problem does this PR solve?

Issue Number: None
Related PR: apache#69995
PR Type: Bugfix

Problem Summary:

Both specific-version DDL paths returned before emitting variant_escape_dots_in_keys. Reuse the normal DDL property renderer in both paths so debug tables preserve dotted-key lookup semantics.

### Details

- **Frequency:** Copying a tablet from a table with variant_escape_dots_in_keys=true.
- **Root cause:** The specific-version branches emit a reduced property list and bypass normal OLAP properties.
- **Why existing tests missed it:** Copy-tablet DDL was not covered by the escaped-table property tests.
- **Fix:** Share the opt-in property renderer across normal DDL and both specific-version branches.
- **Other paths and branches:** Cover getDdlStmt and getCreateTableLikeStmt; preserve default-false DDL and snapshot version output.

### Testing

- Both new copy-tablet tests fail before the fix on the missing property.
- 13 affected FE test classes: 223 passed, 1 existing @disabled test skipped, zero failures or errors.
- Both entry points cover true/false, single-bucket DDL, replication count, snapshot version, and executing the generated DDL to restore the encoding and visible version.
- FE Checkstyle passed with zero violations.

### Release note

ADMIN COPY TABLET preserves variant_escape_dots_in_keys in generated debug-table DDL.

### Check List (For Author)

- Behavior changed: Yes (copy-tablet DDL preserves the source encoding).
- Does this need documentation: No.
- Pre-submission status: Ready.

### AI Disclosure

- Tool: OpenAI Codex.
- Generated: Code, tests, and commit description.
- Human review: Pending.
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

1 similar comment
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

@eldenmoon

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

Static review of PR #69995 at 3265322, covering all 122 changed paths. One new P2 is reported inline: automatic CTAS codec inheritance can invalidate a retained legacy VARIANT template. The existing rolling-upgrade P1 (4499322562) still applies and is retained without a duplicate inline. The author documents mixed-version escaped tables as unsupported, but creation is not capability-gated, so old BEs can silently write the legacy namespace. Recommendation: request changes.

The review converged after two rounds: all three reviewers returned NO_NEW_VALUABLE_FINDINGS in round 2, coverage is complete, and every candidate and initial risk has an evidence-backed disposition. No additional user focus was supplied.

Critical checkpoint conclusions:

  1. Goal/data correctness: the storage-boundary codec separates literal dotted, nested and percent keys; CTAS inferred-template adaptation remains incomplete as described inline. Relevant unit and regression cases exist, but omit this mixed-source typed-template case.
  2. Scope/reuse: changes are focused on immutable table metadata, storage paths and index identity; shared helpers centralize policy and encoding.
  3. Concurrency: no new thread or lock order is introduced. Escaped columns bypass the shared column pool before per-schema policy binding; no additional race or deadlock was established.
  4. Lifecycle/static initialization: builder metadata owns decoded key bytes, canonical finalization sorts children, and cloned slot digests preserve identity. No new ownership cycle or cross-translation-unit initialization dependency was found.
  5. Configuration: the table property defaults false, persists true, and intentionally rejects ALTER and column-level syntax; dynamic updates are not supported.
  6. Compatibility: legacy defaults and markers are preserved, unknown markers fail explicitly, and execution values remain canonical. The existing mixed-version P1 remains. Runtime downgrade and final ELF/glibc compatibility were not validated in this static review; no new libc API or dependency change was identified.
  7. Thrift/protobuf: complete touched definitions were compared on HEAD and live master, branch-4.2, branch-4.1, branch-4.0 and branch-3.1. Added IDs TTabletSchema34, TabletSchemaPB47, TabletSchemaCloudPB48 and ColumnMetaPB28 are optional and unused on those branches; no new collision was found.
  8. Parallel paths: local/cloud creation, schema change, rollup, restore and repair carry the policy. Normal/vertical writers, sparse/DOC reconstruction, compaction, scanner, rowid/rowstore and scoring/index paths were covered.
  9. Conditions/error handling: malformed properties, invalid escapes, NestedGroup conflicts and unknown markers fail through existing error boundaries. Decoder exceptions are converted before publishing assembled output; no new ignored Status was found.
  10. Test coverage: tests cover positive/negative DDL, codec/golden bytes, schema copies, V2/V3, layout thresholds, promotion/demotion, failed compaction, MoW, MVs, indexes and two-phase reads. Tests were inspected only; no builds or tests ran.
  11. Expected results: all added regression suites and expected blocks were inspected. Identical blocks were compared and JSON-shaped cells across 287 blocks/1453 rows parsed without malformed cells. Actual executions and output-generation provenance were not independently verified.
  12. Observability: validation errors identify codec/property conflicts; existing path diagnostics, SHOW CREATE and extended DESC expose relevant state. No additional metric requirement was identified.
  13. Persistence/failover: TableProperty replay reconstructs the flag, tablet/cloud PB conversions preserve it, and segments persist their marker. Existing journal and visible-version transitions are unchanged.
  14. Writes/atomicity: new read errors propagate before output publication; restore rejects incompatible signatures or uses atomic replacement, and MV refresh validates fixed policy before insertion. Rowset/delete-bitmap publication algorithms are unchanged; failure fixtures check retained authoritative inputs.
  15. FE-BE propagation: all five local replica-task and four cloud tablet-builder production callers pass policy. Canonical compute values need no additional scan/function flag; storage paths bind policy from tablet schema.
  16. Performance: metadata caches and existing iteration structure remain; percent decoding is conditional and pool bypass is restricted to escaped columns. Display-name cast collisions can miss pushdown, but SlotId checks and expression fallback prevent the suspected wrong filtering; no separate substantiated performance finding was accepted.
  17. Other concerns/final sweep: previous copy-tablet DDL, external CTAS, changed-view MV refresh and translated-slot index issues are fixed; the recursive-CTE type concern is obsolete because storage policy is absent from compute types. No unresolved candidate or uncovered changed-file scope remains within the authorized static review. Runtime tests, benchmarks and executable ABI inspection remain outside that scope.

Review converged after 2 round(s).

Existing P0/P1 findings confirmed for this head: #69995 (comment)

@eldenmoon

Copy link
Copy Markdown
Member Author

run cloudut

@eldenmoon

Copy link
Copy Markdown
Member Author

Local pipeline review — ✅ PASS

schema: doris-repo-review/v1
status: PASS
pr: apache/doris#69995
commit: 326532285e5b7bd942eef91521ef1c0014ed98fb
base: 9e598d38789571a7fc30652aa054f035bd4f1184
reviewed_at: 2026-11-12T16:01+08:00
reviewer: eldenmoon
model: gpt-6-astra
effort: xhigh
findings: {blocker: 0, major: 0, minor: 0, nit: 0}
rounds: 1
converged: true

Notes for maintainers

  • The previous F-01 is fixed: both versioned DDL branches preserve the source policy through the shared helper (Env.java:4524, Env.java:4880); legacy/default-false output is unchanged.
  • VariantEscapeTableTest.java:47-86 covers both renderers with true/false and recreates catalog tables from emitted DDL, asserting the retained policy and snapshot version. Full snapshot-import/SEARCH execution is not covered by these tests.
  • Incremental follow-up to b1a24ab: the new head is its direct child; whole-tree comparison proves only Env.java and VariantEscapeTableTest.java changed. The earlier full review and 17 dismissals were inherited after content verification.
  • Static source/test review only; no builds or tests were run locally. Exact-head TeamCity compile/feut/beut/cloudut remain pending; this PASS does not certify CI completion.

Reviewed locally with the doris-repo-review pipeline. Repository policy may accept this receipt for the matching commit; it is not a human Apache approval.

@eldenmoon

Copy link
Copy Markdown
Member Author

run compile

@eldenmoon

Copy link
Copy Markdown
Member Author

run feut

@eldenmoon

Copy link
Copy Markdown
Member Author

run p0

Comment thread be/src/storage/tablet/tablet_schema.h Outdated
int32_t doc_hash_shard_count = 64;

bool enable_nested_group = false;
bool escape_dots_in_keys = false;

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.

这个属性放在 TabletSchema 里面了,还有必要在 TabletColumn 存一份吗

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

removed

Comment thread be/src/exec/scan/olap_scanner.cpp Outdated
const auto& column = tablet_schema->column(index);
auto* olap_local_state = static_cast<OlapScanLocalState*>(_local_state);
const auto& cast_types = olap_local_state->_cast_types_for_variants;
if (auto it = cast_types.find(slot->col_name()); it != cast_types.end()) {

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.

如果FE 把Slot 里面的path改写了,be 这些都不动了

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.

查询路径上可以都不用动,FE escape一下path

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done

@eldenmoon

Copy link
Copy Markdown
Member Author

run external

@eldenmoon

Copy link
Copy Markdown
Member Author

run beut

airborne12
airborne12 previously approved these changes Nov 13, 2026

@airborne12 airborne12 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

…e paths from FE

### What problem does this PR solve?

Issue Number: apache#69995

Related PR: apache#69995

Problem Summary: Address review comments on the escaped Variant key property.

1. The escape flag lives only on TabletSchema. Remove the TabletColumn copy, its
   propagation into derived subcolumns, and the TabletColumnObjectPool bypass.
   inherit_index now takes the owning schema's flag as a required argument.
2. FE translates Variant slot sub paths of escaped OLAP tables into storage
   spelling in PlanTranslatorContext.createSlotDesc. BE query code
   (olap_scanner, segment, predicate_collector, rowid_fetcher, vslot_ref)
   returns to master; make_variant_storage_path is removed. This also keeps
   query-cache normalization distinct for v['a.b'] and v['a']['b'].

### Release note

None

### Check List (For Author)

- Test: BE UT (TabletSchemaTest, schema_util, collection statistics, snii routing,
  path_in_data, VariantColumnWriterReaderTest), FE UT (VariantEscapeTableTest,
  QueryCacheNormalizerTest, DescriptorToThriftConverterTest, CreateTableCommandTest,
  MTMVPlanUtilTest, PropertyAnalyzerTest), variant_p0 and dotted_key_* with fuzzy
  session variables.
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eldenmoon

Copy link
Copy Markdown
Member Author

run buildall

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.

5 participants