Skip to content

[fix](fe) Resolve DEFAULT(column) on Iceberg tables from the write schema - #69488

Open
morningman wants to merge 4 commits into
apache:masterfrom
morningman:b2m-t35j-iceberg-default-col-write-target
Open

morningman wants to merge 4 commits into
apache:masterfrom
morningman:b2m-t35j-iceberg-default-col-write-target

Conversation

@morningman

@morningman morningman commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: #66538, #57531, #65851

Problem Summary:

In short. On an Iceberg table, DEFAULT(column) anywhere except UPDATE ... SET and MERGE ... VALUES reads the default from the read schema, which carries no Iceberg write-default. This PR resolves it against the write schema that the statement pinned for its target, as branch-4.1 and branch-4.2 do.

Background. An Iceberg write-default applies to rows written after it is set. So it lives in the writer schema that a write statement pins (IcebergWriteSchemaContext), not in the columns of the read schema. #65851 resolves DEFAULT(column) against that pinned schema in UPDATE ... SET, MERGE ... UPDATE SET and MERGE ... INSERT VALUES (ConnectorWriteSchemaUtils). Every other DEFAULT(column) either fails at binding or reaches RewriteDefaultExpression (#57531), which reads the default from the bound column. branch-4.1 #66538, also in branch-4.2, resolves these against the pinned write target too. It rejects DEFAULT(column) on an Iceberg column in a statement that does not write the table.

The problem, and what it cost. Reproduced on a local cluster with a file:// format-version 3 table: CREATE TABLE t (id INT, c INT), ALTER TABLE t ADD COLUMN d INT DEFAULT 42, one row (0, 0), so d = 42.

Statement Master today After this PR (same as branch-4.2)
INSERT INTO t (id, c, d) VALUES (1, 1, DEFAULT(d)) Unknown column 'd' in 'table list' writes 42
INSERT INTO t (id, c, d) SELECT 2, 2, DEFAULT(d) FROM t WHERE id = 0 writes NULL writes 42
INSERT INTO t (id, c, d) SELECT 3, 3, DEFAULT(d) Unknown column 'd' writes 42
UPDATE t SET c = 100 WHERE d = DEFAULT(d) updates nothing: d = NULL makes the plan an empty set updates every row, d = 42 is pushed down to the scan
MERGE INTO t USING (SELECT 0 AS id) s ON t.id = s.id AND t.d = DEFAULT(t.d) WHEN MATCHED THEN UPDATE SET c = 300 matches nothing updates row 0
SELECT DEFAULT(d) FROM t NULL DEFAULT(d) must reference a column of the table that this statement writes

The UPDATE and MERGE cases fail silently: the statement succeeds and changes nothing.

How this PR fixes it.

  • fe-core cannot tell from a column whether its connector keeps defaults in the read schema. Hive does: an HMS default shows up in both schemas. Iceberg does not. The new connector capability SUPPORTS_WRITE_ONLY_DEFAULTS says which kind a table is. The Iceberg connector declares it. The Hive connector passes it on to iceberg-on-HMS tables, like the other per-table capabilities.
  • For a target that declares it, InsertUtils.normalizePlan resolves DEFAULT(column) in INSERT ... VALUES and in the select lists of INSERT ... SELECT against the pinned write schema. It does this by name, before the source relations are bound, so the name always refers to a target column, as in branch-4.2. In MySQL, DEFAULT(column) in a SELECT refers to a source column instead.
  • RewriteDefaultExpression takes the default for a DEFAULT(column) bound to such a table from the pinned write column with the same field id. That covers the WHERE of UPDATE and the ON of MERGE. If the statement pinned no write schema for that table, it fails.
  • A resolved default is cast to the type of its writer column before the expression around it is bound, as RewriteDefaultExpression already does for a bound DEFAULT(column). The parsed literal -1 is a TINYINT, so without the cast bit_count(DEFAULT(c)) on an INT column would count 8 bits instead of 32. The external UPDATE, MERGE and changelog paths use the same helper. RewriteDefaultExpression rejects a bound DEFAULT(column) whose writer column has another type than the read column the statement was bound with, which happens only when the table changed outside Doris after Doris cached it, and asks to refresh the table: the expressions around it were bound against the read type.
  • Hive, Paimon and internal tables do not declare the capability, so they behave as before.
  • The new enum constant changes the connector plugin API surface, so connector.plugin.api.version goes from 20.0 to 21.0, as for the other recent changes to that surface ([feature](iceberg) Support whole-file metadata delete for DELETE #69176 took 20.0).

Results.

  • Local cluster, with the table above: the table shows what each statement did before and after. EXPLAIN UPDATE t SET c = 5 WHERE d = DEFAULT(d) goes from an empty set to a scan with d = 42 pushed down to Iceberg.
  • Unit tests: 4 new tests in InsertUtilsTest and 5 in the new RewriteDefaultExpressionTest. They cover VALUES, and INSERT ... SELECT both from a staging relation whose own column is also name and without FROM: each resolves to the pinned default, and an unknown column fails. The pinned write column wins over the read column. A statement that writes nothing fails. A table without the capability is unchanged. With master's InsertUtils and RewriteDefaultExpression, the 4 tests of the fix fail and the 2 tests of the unchanged path pass. IcebergConnectorTest, HiveConnectorMetadataSiblingDelegationTest and ConnectorPluginSurfaceTest pass. So do the fe-core tests around the write schema: ConnectorWriteSchemaUtilsTest, ExternalRowLevelUpdatePlanBuilderTest, ExternalRowLevelMergePlanBuilderTest, ChangelogRowLevelDmlTransformTest and PluginDrivenExternalTableTest. Two of the tests pin the typing: bit_count(DEFAULT(bits)) gets the default as an INT in VALUES and in SELECT, and fails without the cast; a BIGINT writer column over an INT read column is rejected, directly and under an IF bound to INT.
  • Regression: test_iceberg_initial_defaults now writes rows 20 to 22 with DEFAULT(default_int) in VALUES and in INSERT ... SELECT with and without FROM. It then updates them with WHERE default_int = DEFAULT(default_int) and MERGE ... ON ... = DEFAULT(...), for Parquet and ORC, and checks the rows in the .out. A plain SELECT DEFAULT(default_int) must fail. The suite passes locally. With master's FE it fails at the first of these statements: Unknown column 'default_int' in 'table list'.

Release note

Fix: On Iceberg tables, DEFAULT(column) in INSERT ... VALUES, INSERT ... SELECT and the WHERE / ON conditions of UPDATE and MERGE now resolves to the column's write-default. Before, it failed, wrote NULL, or matched no row. SELECT DEFAULT(column) on an Iceberg table now fails instead of returning NULL.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
      On a local cluster with a file:// Iceberg catalog: CREATE TABLE t (id INT, c INT) PROPERTIES ('format-version'='3'), ALTER TABLE t ADD COLUMN d INT DEFAULT 42, then the statements in the table above.
    • 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.
      See the release note. INSERT ... SELECT DEFAULT(column) into an Iceberg table names a target column, even when the source has a column of that name.
  • 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?

@morningman

Copy link
Copy Markdown
Contributor Author

/review

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

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

Reviewed exact head bda3e28cdab081693dc2dd8d739d784005b7ce9d against the supplied authoritative aggregate patch. Five new verified findings: one P1 and four P2, all inline. No existing review threads or blocking comments were present on refreshed intake. No additional user focus was supplied.

Critical checkpoint conclusions:

  • Goal and proof: ordinary INSERT VALUES/SELECT and UPDATE/MERGE predicates now consult pinned write defaults; the inline findings show incorrect typed-expression results and uncovered statement/schema paths. Added tests exercise the ordinary cases but do not prove the broader behavior.
  • Scope, clarity, reuse: the capability-based change is focused and connector-agnostic. Reusing the default resolver loses referenced-column typing and reuses a narrower assignment-name validator.
  • Concurrency and locks: no new threads or locks. Existing table read-lock/finally-unlock structure remains. Independently cached read schemas versus live writer schemas expose the reported type-evolution issue; no separate lock-order/deadlock defect found.
  • Lifecycle and initialization: write schemas/identities remain statement-scoped; INSERT and row-level command pinning, retry/prepared-execution reset, plugin metadata scope and classloader boundaries were traced. No new lifetime/static-initialization defect found. Overwrite repinning behavior also exists for preexisting bare DEFAULT and is not a new finding here.
  • Configuration: no configuration items added.
  • Compatibility: the enum changes the plugin surface; the deliberate major API bump to 20.0, version pin and plugin-surface baseline agree. Metadata method signatures are unchanged. No new wire or storage format is introduced.
  • Thrift/protobuf IDs: no gensrc definitions changed; branch field-ID checks are not applicable.
  • Parallel paths: INSERT/OVERWRITE/EXPLAIN, UPDATE/MERGE/DELETE and CHANGELOG/POSITION_DELETE paths were traced. Row-level commands pin before planning. Aggregate/CTE/subquery normalization and snapshot Hive capability inheritance are incomplete as reported.
  • Conditional checks: capability gates preserve ordinary Hive/Paimon/internal behavior; table-ID plus field-ID matching is consistent. Fully qualified target names are wrongly rejected as reported. A differing source alias is not raised because the PR deliberately specifies target-name semantics.
  • Tests and modularity: added JUnit 5 cases cover direct VALUES/projection/no-FROM, unknown names, bound pin/absent pin, capability-disabled behavior and ordinary sibling delegation. Missing coverage includes typed nested expressions, grouped/nested queries, full qualification, evolved read/write types and snapshot sibling delegation.
  • Changed expected results: the ordered Parquet/ORC rows 20-22 and expected SELECT rejection match the added statements and existing default value 35. Result-file generation provenance was not independently verified.
  • Observability: existing analysis errors and statement tracing suffice for this planning change; no new distributed operation or metrics requirement identified.
  • Persistence and failover: no EditLog/replay or durable metadata mutation protocol changes.
  • Writes, atomicity and crashes: planning precedes existing writer transaction/finalization/commit fences. No new commit/rollback or crash-cleanup defect found; the P1 expression issue can persist the wrong computed value in an otherwise valid write.
  • FE/BE state: no new transmitted variables or serialization/send paths. Integer-width function semantics were cross-checked in FE and BE for the P1 finding.
  • Performance: traversal and default lookup add planning work proportional to query size and target width. No substantiated material CPU/memory regression or repeated external-I/O defect found.
  • Other invariants: no BE allocation ownership, partition visible-version, or MoW delete-bitmap changes. Errors propagate through existing analysis exceptions. Stable connector field IDs and writer metadata fences remain in place, with the reported default-type caveat.

Validation was static only, as required: all 15 changed files, related callers/control flow, tests and expected outputs were inspected; no build, runtime test, source change, or format rewrite was performed. No unresolved candidate or assigned static coverage gap remains. Runtime execution and output-generation provenance remain unverified. Convergence and review severity are reported separately by the delivery helper.

Review converged after 2 round(s).

if (!writeOnlyDefaultColumns.isPresent()) {
return value;
}
return (NamedExpression) ConnectorWriteSchemaUtils.resolveDefaultReferences(value,

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 the referenced column type before binding its consumers

For an Iceberg t(c INT) with write-default -1, INSERT INTO t(c) SELECT bit_count(DEFAULT(c)) should evaluate bit_count on an INT and write 32. This new route instead produces OneRow(bit_count(-1:TINYINT)): ConnectorWriteSchemaUtils.resolveDefaultReferences parses the default SQL without casting it to the referenced column type, and the parser chooses TINYINT for -1. BitCount has width-specific signatures, and both its FE evaluator and BE implementation return 8 for TINYINT -1, versus 32 for INT -1. Casting the completed expression to the sink's INT cannot restore the lost value; VALUES expressions have the same problem. Cast each substituted default to its referenced writer column's type before binding surrounding operators/functions, as the bound DEFAULT rewrite does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in cf75568. ConnectorWriteSchemaUtils.resolveDefaultReferences now casts each resolved default to the type of the writer column it references (TypeCoercionUtils.castUnbound) before the expression around it is bound, so bit_count(DEFAULT(c)) on an INT column with write-default -1 gets an INT -1 in VALUES and in SELECT. The external UPDATE / MERGE / changelog paths use the same helper and get the same typing. branch-4.2 is not affected: it builds write defaults as literals of the column type. Test: InsertUtilsTest#writeOnlyDefaultIsTypedAsItsColumnBeforeBinding (VALUES and SELECT); with the previous commit the argument of bit_count is TinyIntLiteral(-1).

*/
private static Plan resolveSelectDefaultReferences(Plan query, Optional<List<Column>> writeOnlyDefaultColumns,
TableIf table, List<String> targetNameParts) {
return query.rewriteUp(plan -> {

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] Normalize defaults in every SELECT output shape and nested query

With target t(c INT) having a write-default, INSERT INTO t(c) SELECT DEFAULT(c) FROM (SELECT 1 AS k) s GROUP BY k parses as Sink(t.c) -> Aggregate(groupBy=k, output=DEFAULT(c)) -> Alias(s) -> OneRow(k=1). The lambda handles only Project/OneRow outputs, so it leaves this DEFAULT untouched and binding fails with unknown column c against source s.k; removing GROUP BY resolves the same target reference successfully. CTE definitions and scalar-subquery plans also escape this traversal: command-level WITH is attached after normalization, CTE definitions are extraPlans(), and subquery plans are not expression children. Resolve target defaults in aggregate/repeat outputs and explicitly traverse these separately owned query plans, with grouped/CTE/subquery coverage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not changing this in this PR. The INSERT ... SELECT resolution covers the select lists of the main query (projects and the one-row relation), the same shapes as branch-4.2, which this PR ports (InsertUtils#resolveIcebergSelectDefaultReferences there). In an aggregate output, a WITH clause or a subquery, DEFAULT(c) keeps its meaning from before this PR and names a column of its own FROM clause, as in MySQL: with no such column the statement fails with an unknown-column error; a column of the target table itself gets the pinned writer default through the bound rewrite; a column of another Iceberg table now fails with "must reference a column of the table that this statement writes" instead of answering NULL; a column of a Hive or OLAP source gets that column's default, as before. Resolving target names in those shapes needs other analysis stages (the command-level WITH is attached after normalizePlan; CTE and subquery plans are not children of the project), so it would be a separate change.

return value;
}
return (NamedExpression) ConnectorWriteSchemaUtils.resolveDefaultReferences(value,
writeOnlyDefaultColumns.get(), (ExternalTable) table, ConnectContext.get(), targetNameParts, 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.

[P2] Accept fully qualified target column references

INSERT INTO ctl.db.t(c) SELECT DEFAULT(ctl.db.t.c) now reaches ConnectorWriteSchemaUtils.resolveDefaultReferences, which passes the four-part name to UpdateCommand.checkAssignmentColumn. That assignment-LHS validator accepts only one, two, or three name parts and throws column in assignment list is invalid for this unambiguous target reference. Ordinary Nereids column binding explicitly supports catalog.db.table.column, and this form should also resolve against the pinned target schema. Use qualification validation that includes the catalog component rather than applying the narrower UPDATE-assignment grammar; cover the fully qualified form in SELECT and VALUES.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not changing this here. DEFAULT(...) in VALUES / SELECT accepts the qualifications that the existing Iceberg UPDATE / MERGE DEFAULT handling accepts, through the same UpdateCommand.checkAssignmentColumn (branch-4.2 does the same): c, t.c, db.t.c. ctl.db.t.c fails with "column in assignment list is invalid" instead of resolving; it does not write a wrong value. Accepting catalog-qualified names would change the assignment-column rule of all DML paths, so it belongs in its own change.

if (originalTable.filter(PluginDrivenExternalTable.class::isInstance)
.filter(table -> ((PluginDrivenExternalTable) table).hasWriteOnlyDefaults())
.isPresent()) {
column = pinnedWriteColumn(context.cascadesContext.getStatementContext(), originalTable.get(), column)

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] Derive the result type after selecting the writer column

targetType is computed from the read column before this substitution and remains unchanged afterward. The read schema can still be cached as INT after an external Iceberg promotion to LONG, while pinAndGet independently loads current LONG writer columns and a new write-default such as 4900000001. Then UPDATE t SET other = 'x' WHERE DEFAULT(score) = 4900000001 produces Filter(CAST(4900000001 AS INT) = 4900000001) above the cached INT scan, instead of using the BIGINT writer default, causing overflow/error or an incorrect predicate. The writer fences compare the current writer columns/identity and do not validate this stale predicate type. Compute the type from the selected writer column and add a same-field-ID read-INT/write-BIGINT test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in cf75568. RewriteDefaultExpression now takes the result type from the pinned writer column, after the substitution. Test: RewriteDefaultExpressionTest#writeOnlyDefaultTakesTheTypeOfThePinnedWriterColumn pins a BIGINT writer column with default 4900000001 over an INT read column with the same field id and expects a BIGINT literal; with the previous commit the result is cast(4900000001 as INT).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Follow-up: superseded in 688e8d5 (see the newer thread on this file). Typing the substituted default as the writer column fixed the DEFAULT node itself but not the expressions bound around it against the read type, so a writer column whose type differs from the read column now fails with a refresh hint instead.

ConnectorCapability.SUPPORTS_STORAGE_PREDICATE_PRUNING,
ConnectorCapability.SUPPORTS_NESTED_COLUMN_SCHEMA_CHANGE));
ConnectorCapability.SUPPORTS_NESTED_COLUMN_SCHEMA_CHANGE,
ConnectorCapability.SUPPORTS_WRITE_ONLY_DEFAULTS));

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] Reflect this capability for snapshot schemas as well

The two-argument getTableSchema reflects this set, but the snapshot overload still returns the sibling schema directly. For SELECT DEFAULT(c) FROM hms_catalog.db.iceberg_t FOR VERSION AS OF <snapshot_id>, PluginDrivenMvccExternalTable.loadSnapshot publishes that unreflected historical schema. tableCapabilities() reads the ambient pinned schema, while the Hive catalog itself does not declare write-only defaults, so hasWriteOnlyDefaults() is false and the bound rewrite returns NULL for a nullable column instead of rejecting this read-only use. Direct Iceberg catalogs retain the guard through their connector-wide capability. Apply the same reflection to getTableSchema(session, handle, snapshot) and test that overload.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not in this PR. HiveConnectorMetadata#getTableSchema(session, handle, snapshot) returns the sibling's schema without reflectSiblingCapabilities for every inherited capability, not only this one (auto-analyze, Top-N lazy materialization, nested column prune, field-id access path, storage predicate pruning, nested column DDL); that predates this PR. So for a time-travel read of an iceberg-on-HMS table, SELECT DEFAULT(c) ... FOR VERSION AS OF keeps master's current answer (NULL) instead of the new error; nothing is written. Reflecting capabilities on the snapshot path changes scan planning for all of them and should come with its own tests, so it is left to a separate change.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17612	5322	5250	5250
q2	2178	335	301	301
q3	10106	1491	892	892
q4	4700	463	334	334
q5	7452	828	535	535
q6	207	205	157	157
q7	822	825	607	607
q8	9276	1525	1178	1178
q9	5788	4457	4406	4406
q10	6890	1305	1006	1006
q11	454	250	230	230
q12	641	435	290	290
q13	18096	3695	2996	2996
q14	282	275	254	254
q15	q16	746	726	670	670
q17	1347	784	593	593
q18	7049	6177	6116	6116
q19	1109	1097	638	638
q20	386	343	231	231
q21	5279	2190	2399	2190
q22	379	310	246	246
Total cold run time: 100799 ms
Total hot run time: 29120 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5957	5915	5940	5915
q2	717	552	536	536
q3	5220	5399	4946	4946
q4	2109	2251	1538	1538
q5	5283	5469	5817	5469
q6	297	212	155	155
q7	2366	2107	2032	2032
q8	3264	2760	2794	2760
q9	8169	7766	8066	7766
q10	3810	3672	3281	3281
q11	652	461	411	411
q12	719	725	507	507
q13	3628	3951	3227	3227
q14	315	326	283	283
q15	q16	692	738	625	625
q17	8439	7614	7323	7323
q18	13025	12263	12882	12263
q19	1047	863	868	863
q20	2150	2165	1908	1908
q21	5960	4779	4924	4779
q22	534	459	411	411
Total cold run time: 74353 ms
Total hot run time: 66998 ms

@hello-stephen

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

query5	4308	565	446	446
query6	428	209	210	209
query7	4836	470	217	217
query8	330	182	155	155
query9	8796	3115	3074	3074
query10	485	320	258	258
query11	5993	3838	3550	3550
query12	144	93	88	88
query13	1261	463	335	335
query14	6173	3911	3671	3671
query14_1	3405	3411	3392	3392
query15	208	198	195	195
query16	955	425	394	394
query17	867	674	530	530
query18	2433	425	318	318
query19	193	170	133	133
query20	84	84	82	82
query21	219	124	107	107
query22	12943	13066	12885	12885
query23	13519	12971	12586	12586
query23_1	12556	12532	12657	12532
query24	7372	830	463	463
query24_1	471	474	475	474
query25	545	431	386	386
query26	1273	271	144	144
query27	2772	439	270	270
query28	4635	1968	1981	1968
query29	1586	603	470	470
query30	315	230	181	181
query31	1019	929	812	812
query32	149	92	92	92
query33	532	307	254	254
query34	899	843	496	496
query35	760	750	640	640
query36	826	820	700	700
query37	125	101	100	100
query38	1783	1745	1669	1669
query39	792	769	750	750
query39_1	734	727	736	727
query40	221	118	103	103
query41	76	68	69	68
query42	86	92	85	85
query43	345	359	309	309
query44	1306	687	700	687
query45	188	178	166	166
query46	883	964	561	561
query47	3035	2936	2754	2754
query48	296	308	214	214
query49	570	392	311	311
query50	671	278	219	219
query51	10368	10400	10402	10400
query52	76	77	69	69
query53	183	204	164	164
query54	256	204	185	185
query55	74	66	61	61
query56	229	203	201	201
query57	1632	1626	1567	1567
query58	297	265	266	265
query59	2069	2163	1955	1955
query60	291	246	226	226
query61	149	143	145	143
query62	402	325	301	301
query63	211	159	154	154
query64	2763	979	754	754
query65	3306	3264	3268	3264
query66	1784	413	309	309
query67	20347	20068	19986	19986
query68	2965	1011	604	604
query69	373	295	259	259
query70	860	763	775	763
query71	296	228	208	208
query72	2734	2638	2337	2337
query73	510	521	294	294
query74	4674	4522	4331	4331
query75	2345	2254	1884	1884
query76	2316	1024	596	596
query77	347	362	278	278
query78	9941	9773	9249	9249
query79	1020	835	523	523
query80	1148	445	325	325
query81	587	318	276	276
query82	574	130	103	103
query83	307	194	189	189
query84	314	119	100	100
query85	862	416	369	369
query86	392	233	232	232
query87	2000	1960	1821	1821
query88	3624	2663	2646	2646
query89	353	272	242	242
query90	1874	162	161	161
query91	162	148	124	124
query92	96	89	80	80
query93	1000	987	576	576
query94	620	310	255	255
query95	560	394	303	303
query96	650	478	233	233
query97	2459	2461	2317	2317
query98	157	151	145	145
query99	774	769	645	645
Total cold run time: 235439 ms
Total hot run time: 151076 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.09	0.05	0.05
query3	0.26	0.08	0.09
query4	1.61	0.11	0.09
query5	0.26	0.26	0.25
query6	1.17	0.68	0.67
query7	0.04	0.00	0.00
query8	0.05	0.04	0.04
query9	0.42	0.33	0.34
query10	0.58	0.57	0.59
query11	0.20	0.15	0.15
query12	0.19	0.15	0.14
query13	0.49	0.49	0.50
query14	1.03	1.04	1.00
query15	0.63	0.62	0.60
query16	0.34	0.34	0.35
query17	1.16	1.14	1.10
query18	0.21	0.18	0.20
query19	2.14	2.03	2.04
query20	0.02	0.01	0.02
query21	15.48	0.21	0.13
query22	4.79	0.05	0.05
query23	16.25	0.31	0.12
query24	3.10	0.46	0.42
query25	0.10	0.07	0.05
query26	1.10	0.22	0.16
query27	0.06	0.05	0.05
query28	3.47	0.78	0.36
query29	12.50	4.21	3.25
query30	0.29	0.14	0.09
query31	2.77	0.55	0.33
query32	3.22	0.59	0.50
query33	3.24	3.17	3.21
query34	15.34	4.02	3.38
query35	3.32	3.32	3.35
query36	0.54	0.46	0.42
query37	0.10	0.06	0.07
query38	0.05	0.04	0.03
query39	0.04	0.04	0.03
query40	0.18	0.15	0.15
query41	0.08	0.02	0.02
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 97 s
Total hot run time: 24.29 s

@morningman
morningman force-pushed the b2m-t35j-iceberg-default-col-write-target branch from bda3e28 to cf75568 Compare October 23, 2026 08:28
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman

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.

Static review of all 16 changed paths at cf75568, including related binding, writer-schema, capability, and commit paths. One new P2 finding: the bound DEFAULT rewrite can widen its result after an enclosing IF has retained an INT signature, causing a valid BIGINT default to become NULL or overflow during folding.

The existing P1 4355508072 (parsed default width before binding) and the direct DEFAULT result-type instance in P2 4355508096 are fixed at this head. No existing P0/P1 remains applicable. Qualification (4355508088), grouped/CTE/subquery traversal (4355508080), and HMS historical-schema capability reflection (4355508100) remain covered by their existing threads and replies; they are not reposted. The new finding concerns a different narrowing cast synthesized later by the enclosing IF consumer.

Critical checkpoint conclusions:

  • Goal and proof: writer-only defaults now use the target's pinned schema in the covered INSERT and row-level paths, and read-only use is rejected. Added tests cover these cases, but the enclosing-consumer promotion case in the inline finding remains incorrect.
  • Scope and clarity: changes are localized and reuse the capability accessor, statement schema pin, and shared default resolver.
  • Concurrency and locks: no new threads, shared mutators, locks, or lock order; existing statement ownership and connector generation fences remain in use. No new heavy work inside a newly introduced lock was found.
  • Lifecycle and initialization: writer columns/identity are pinned before normalization or synthesis, selected by target table and field ID, and cleared across retries/executions. Branch selection remains in the existing writer scope. No static initialization dependency is introduced.
  • Configuration: no configuration item is added.
  • Compatibility: connector API major and test pin move from 20.0 to 21.0 with the new enum surface entry. Metadata method surface is unchanged. No storage-format or FE/BE protocol change.
  • Thrift/protobuf: no gensrc definitions are changed.
  • Parallel paths: inspected VALUES, SELECT projects/one-row plans, INSERT OVERWRITE, UPDATE/MERGE assignments and predicates, changelog helper consumers, and direct/HMS Iceberg delegation. Existing traversal/qualification/snapshot limits are identified above.
  • Conditions and errors: capability gates preserve other connectors' behavior; absent matching target/field and invalid references fail explicitly. Optional absent Iceberg defaults serialize as SQL NULL; required absent defaults fail.
  • Test coverage: positive/negative FE tests, capability/SPI tests, and Parquet/ORC regression additions cover the intended paths. Consumer binding plus rewrite under a stale read type needs coverage as requested inline. Tests were inspected, not executed.
  • Expected results: both new ordered regression blocks match rows 20-22, default35, UPDATE labels and the MERGE change to row22. Result-generation provenance was not independently verified.
  • Observability: existing analysis errors identify the DEFAULT reference/column; no new operational metric or log is needed for these local substitutions.
  • Transactions and persistence: no EditLog, replay, failover or persistence algorithm changes; existing writer schema/identity checks and commit fences remain responsible for remote metadata races.
  • Writes and atomicity: existing row-level transaction/commit machinery is reused. The inline finding concerns an incorrect pre-write predicate or analysis failure; no new crash/resource/partial-commit mechanism was identified.
  • FE/BE variables: no new transported variable or sending path.
  • Performance and memory: planning work is linear in visited plan/expressions with a writer-column lookup per DEFAULT; no new per-row runtime work or substantiated performance defect. No BE memory ownership, partition visible-version or MoW delete-bitmap code changes.
  • Other issues and user focus: no additional user focus was supplied. All initial risks and candidates are accepted, duplicate-fenced or dismissed with recorded evidence.

Coverage limits: static inspection only, as required; no builds, unit/regression execution, live external-cluster behavior, or output-generation provenance were validated. No unresolved static candidate or unreviewed changed path remains. Convergence is reported separately by the delivery metadata.

Review converged after 2 round(s).

}
// The pinned writer column can be wider than the read column the slot was bound with, e.g. after a type
// promotion committed outside Doris, and the default is a value of the writer column.
DataType targetType = DataType.fromCatalogType(column.getType());

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] Bind enclosing consumers against the writer column type

With a cached read score INT and a same-field-ID writer score BIGINT whose write-default is 4900000001, consider:

UPDATE t SET score = DEFAULT(score)
WHERE IF(TRUE, DEFAULT(score), 0) = 4900000001;

Binding produces Filter(CAST(IF(TRUE, DEFAULT(score:INT), 0):INT AS BIGINT) = 4900000001) -> Scan(score:INT). This rewrite correctly replaces DEFAULT with a BIGINT literal, but Rewriter preserves function signatures, so If.withChildren/FunctionParams retain IF's INT result. FoldConstantRuleOnFE.visitIf then calls ensureSameResultType on the true branch and synthesizes CAST(4900000001 AS INT): loose casting yields NULL and updates no rows, while strict casting throws overflow. The predicate should be true for every row.

The earlier direct DEFAULT result-type issue is fixed here; this narrowing cast is created separately by the already-bound IF consumer. Resolve the pinned writer type before binding its consumers, or rebind their signatures/coercions after substitution, and cover an enclosing IF through both analysis and rewrite.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 688e8d5. Agreed: once IF, CASE or COALESCE have been bound against the read type, a wider writer-typed default cannot be substituted from the DEFAULT node, because the rewriter keeps their signatures and constant folding narrows the value back. The read and writer types of one field only differ while Doris's cached read schema predates a type change committed outside Doris (reads go through the table cache, the writer schema is loaded for the statement), so the bound rewrite now fails such a DEFAULT and asks to refresh the table instead of retyping its consumers. When the two types agree, which is every case without an outside type change, nothing changes. DEFAULT in VALUES, in INSERT ... SELECT projections and in UPDATE SET is resolved against the writer schema before binding, so its consumers already bind against the writer type. RewriteDefaultExpressionTest covers a direct DEFAULT and one under an IF bound to INT; both are rejected.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17605	5165	5047	5047
q2	2155	309	243	243
q3	10236	1388	818	818
q4	4680	460	336	336
q5	7428	790	540	540
q6	178	185	147	147
q7	748	786	591	591
q8	9254	1340	1060	1060
q9	5631	4200	4188	4188
q10	6831	1292	1041	1041
q11	423	243	235	235
q12	654	401	286	286
q13	18092	4119	3029	3029
q14	264	276	246	246
q15	q16	728	723	647	647
q17	1200	744	567	567
q18	6940	6198	6111	6111
q19	1245	973	596	596
q20	379	338	233	233
q21	5155	2123	2298	2123
q22	349	305	247	247
Total cold run time: 100175 ms
Total hot run time: 28331 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5615	5608	5583	5583
q2	698	556	540	540
q3	5232	5362	4942	4942
q4	1982	2149	1547	1547
q5	5244	5195	5679	5195
q6	264	201	155	155
q7	2338	2123	1869	1869
q8	3063	2814	2671	2671
q9	7994	8083	8074	8074
q10	3744	3675	3269	3269
q11	621	430	415	415
q12	681	710	529	529
q13	3526	4014	3180	3180
q14	302	298	283	283
q15	q16	709	703	627	627
q17	8270	7515	7426	7426
q18	12988	12184	12919	12184
q19	909	768	772	768
q20	2128	2142	1948	1948
q21	5546	4581	4641	4581
q22	514	463	397	397
Total cold run time: 72368 ms
Total hot run time: 66183 ms

@hello-stephen

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

query5	4312	576	441	441
query6	422	214	191	191
query7	4809	451	227	227
query8	318	159	160	159
query9	8790	3097	3114	3097
query10	478	308	260	260
query11	5976	3867	3562	3562
query12	147	89	86	86
query13	1247	442	329	329
query14	6088	3901	3632	3632
query14_1	3448	3400	3414	3400
query15	205	199	178	178
query16	939	418	412	412
query17	887	666	545	545
query18	2425	443	313	313
query19	205	167	140	140
query20	84	84	85	84
query21	212	128	107	107
query22	12898	13161	12788	12788
query23	13447	12913	12399	12399
query23_1	12660	12672	12634	12634
query24	7394	827	460	460
query24_1	483	479	483	479
query25	540	424	372	372
query26	1268	266	144	144
query27	2764	444	272	272
query28	4621	1959	1941	1941
query29	1560	615	460	460
query30	303	226	183	183
query31	1022	918	822	822
query32	141	94	97	94
query33	537	332	226	226
query34	889	864	488	488
query35	723	749	635	635
query36	818	857	708	708
query37	127	95	84	84
query38	1760	1718	1645	1645
query39	783	788	744	744
query39_1	725	722	747	722
query40	224	112	97	97
query41	67	64	62	62
query42	85	85	84	84
query43	343	355	302	302
query44	1301	681	688	681
query45	184	171	167	167
query46	822	979	561	561
query47	2872	2955	2663	2663
query48	291	300	220	220
query49	581	404	294	294
query50	668	270	206	206
query51	10383	10363	10404	10363
query52	76	79	67	67
query53	192	209	156	156
query54	243	202	198	198
query55	71	64	63	63
query56	233	208	216	208
query57	1674	1595	1588	1588
query58	289	260	274	260
query59	2086	2123	1947	1947
query60	270	240	228	228
query61	150	139	143	139
query62	386	337	281	281
query63	189	157	157	157
query64	2744	926	778	778
query65	3316	3259	3273	3259
query66	1765	428	302	302
query67	20048	20244	20072	20072
query68	3114	991	609	609
query69	399	282	249	249
query70	824	747	763	747
query71	300	236	207	207
query72	2727	2565	2272	2272
query73	502	524	294	294
query74	4583	4490	4320	4320
query75	2326	2311	1898	1898
query76	2315	1013	598	598
query77	347	373	266	266
query78	9774	9633	9104	9104
query79	1041	832	514	514
query80	525	434	398	398
query81	519	319	274	274
query82	571	130	104	104
query83	300	209	180	180
query84	316	121	103	103
query85	819	429	366	366
query86	321	246	232	232
query87	2017	1936	1792	1792
query88	3619	2673	2683	2673
query89	346	283	245	245
query90	1893	169	164	164
query91	163	159	131	131
query92	97	85	89	85
query93	1002	998	589	589
query94	434	319	284	284
query95	566	395	292	292
query96	653	489	233	233
query97	2495	2440	2286	2286
query98	160	153	148	148
query99	752	769	647	647
Total cold run time: 233786 ms
Total hot run time: 150589 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.27	0.09	0.09
query4	1.61	0.08	0.10
query5	0.22	0.24	0.24
query6	1.17	0.68	0.67
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.39	0.34	0.35
query10	0.57	0.59	0.57
query11	0.20	0.14	0.14
query12	0.19	0.15	0.15
query13	0.52	0.50	0.49
query14	1.03	1.02	1.03
query15	0.64	0.59	0.60
query16	0.34	0.34	0.34
query17	1.15	1.10	1.12
query18	0.20	0.18	0.19
query19	2.10	1.97	1.99
query20	0.02	0.01	0.01
query21	15.51	0.19	0.14
query22	4.96	0.05	0.05
query23	16.24	0.32	0.13
query24	3.10	0.58	0.69
query25	0.12	0.07	0.04
query26	1.64	0.21	0.16
query27	0.05	0.05	0.03
query28	3.39	0.71	0.35
query29	12.48	4.10	3.27
query30	0.29	0.12	0.10
query31	2.79	0.55	0.33
query32	3.22	0.59	0.52
query33	3.24	3.17	3.28
query34	15.42	3.96	3.36
query35	3.36	3.36	3.34
query36	0.54	0.45	0.42
query37	0.09	0.06	0.06
query38	0.06	0.04	0.03
query39	0.04	0.03	0.03
query40	0.16	0.15	0.15
query41	0.09	0.03	0.02
query42	0.03	0.04	0.04
query43	0.05	0.04	0.03
Total cold run time: 97.69 s
Total hot run time: 24.43 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 95.74% (45/47) 🎉
Increment coverage report
Complete coverage report

@morningman
morningman force-pushed the b2m-t35j-iceberg-default-col-write-target branch from cf75568 to f1287fd Compare October 23, 2026 14:26
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17603	5135	5068	5068
q2	2151	302	263	263
q3	10261	1362	849	849
q4	4677	461	331	331
q5	7445	798	540	540
q6	181	184	161	161
q7	756	798	603	603
q8	9259	1317	1101	1101
q9	5410	4150	4164	4150
q10	6816	1285	1027	1027
q11	429	251	231	231
q12	634	410	303	303
q13	18075	3506	3029	3029
q14	271	278	251	251
q15	q16	717	718	662	662
q17	1179	744	586	586
q18	6928	6135	6119	6119
q19	1104	945	599	599
q20	377	344	225	225
q21	4869	2197	2335	2197
q22	352	306	264	264
Total cold run time: 99494 ms
Total hot run time: 28559 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5616	5619	5632	5619
q2	671	570	545	545
q3	5174	5391	4906	4906
q4	2016	2170	1610	1610
q5	5254	5160	5440	5160
q6	251	201	162	162
q7	2338	1991	1888	1888
q8	3067	2661	2754	2661
q9	8004	8011	7865	7865
q10	3711	3689	3264	3264
q11	624	466	428	428
q12	663	715	649	649
q13	3567	3936	3295	3295
q14	299	309	289	289
q15	q16	710	722	693	693
q17	8288	7724	7015	7015
q18	13013	12157	12869	12157
q19	907	834	829	829
q20	2150	2155	1909	1909
q21	5902	4906	5091	4906
q22	483	493	415	415
Total cold run time: 72708 ms
Total hot run time: 66265 ms

@hello-stephen

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

query5	4330	590	446	446
query6	425	227	191	191
query7	4793	438	240	240
query8	330	171	157	157
query9	8782	3142	3114	3114
query10	492	310	262	262
query11	6056	3833	3546	3546
query12	149	88	86	86
query13	1246	463	321	321
query14	6159	3992	3685	3685
query14_1	3407	3446	3412	3412
query15	206	197	182	182
query16	947	438	407	407
query17	850	669	549	549
query18	2418	431	322	322
query19	194	164	143	143
query20	86	88	84	84
query21	224	151	110	110
query22	13003	13100	12818	12818
query23	13428	12817	12513	12513
query23_1	12506	12567	12562	12562
query24	7383	848	459	459
query24_1	481	471	479	471
query25	572	416	352	352
query26	1270	257	146	146
query27	2756	440	273	273
query28	4658	1951	1959	1951
query29	1584	609	475	475
query30	309	213	187	187
query31	1018	923	831	831
query32	147	94	97	94
query33	538	303	243	243
query34	951	848	510	510
query35	756	763	653	653
query36	853	814	725	725
query37	129	113	80	80
query38	1794	1724	1685	1685
query39	808	817	792	792
query39_1	739	736	742	736
query40	221	127	100	100
query41	78	69	74	69
query42	92	88	86	86
query43	360	376	324	324
query44	1407	695	734	695
query45	184	187	170	170
query46	868	1023	597	597
query47	2761	3068	2909	2909
query48	304	318	225	225
query49	573	432	290	290
query50	714	290	217	217
query51	10262	10393	10477	10393
query52	81	84	72	72
query53	195	210	159	159
query54	237	209	183	183
query55	70	69	69	69
query56	265	213	205	205
query57	1655	1618	1571	1571
query58	291	263	275	263
query59	2084	2135	1941	1941
query60	299	252	230	230
query61	147	170	152	152
query62	390	335	275	275
query63	201	160	167	160
query64	2777	971	794	794
query65	3352	3296	3280	3280
query66	1784	412	296	296
query67	20051	20043	20079	20043
query68	2997	1025	613	613
query69	376	286	254	254
query70	867	792	794	792
query71	307	240	204	204
query72	2666	2532	2278	2278
query73	523	545	301	301
query74	4647	4486	4378	4378
query75	2340	2295	1916	1916
query76	2311	1022	617	617
query77	371	389	273	273
query78	9758	9657	9171	9171
query79	1356	867	520	520
query80	1236	427	360	360
query81	593	323	270	270
query82	572	135	106	106
query83	312	206	190	190
query84	314	132	107	107
query85	854	430	372	372
query86	398	239	229	229
query87	2001	1945	1817	1817
query88	3765	2690	2669	2669
query89	332	278	247	247
query90	1916	176	176	176
query91	168	154	129	129
query92	102	90	90	90
query93	1148	1050	577	577
query94	630	310	278	278
query95	585	345	377	345
query96	672	507	234	234
query97	2430	2429	2323	2323
query98	167	155	149	149
query99	771	753	625	625
Total cold run time: 235829 ms
Total hot run time: 151566 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.09	0.05	0.04
query3	0.25	0.09	0.09
query4	1.61	0.12	0.11
query5	0.25	0.24	0.25
query6	1.17	0.68	0.68
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.41	0.36	0.34
query10	0.58	0.62	0.59
query11	0.19	0.14	0.14
query12	0.18	0.15	0.15
query13	0.49	0.49	0.50
query14	1.03	1.01	1.01
query15	0.64	0.61	0.61
query16	0.36	0.37	0.36
query17	1.14	1.13	1.15
query18	0.21	0.21	0.21
query19	2.09	1.98	1.97
query20	0.02	0.01	0.01
query21	15.42	0.19	0.13
query22	5.03	0.05	0.05
query23	16.27	0.34	0.12
query24	2.67	0.47	0.50
query25	0.11	0.08	0.06
query26	1.59	0.22	0.15
query27	0.05	0.05	0.05
query28	3.80	0.82	0.37
query29	12.51	4.20	3.37
query30	0.28	0.13	0.09
query31	2.77	0.56	0.32
query32	3.22	0.59	0.50
query33	3.26	3.17	3.24
query34	15.30	4.01	3.41
query35	3.34	3.33	3.33
query36	0.54	0.44	0.43
query37	0.11	0.06	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.15	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 97.51 s
Total hot run time: 24.6 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 94.00% (47/50) 🎉
Increment coverage report
Complete coverage report

@morningman

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.

Reviewed exact head 688e8d59412ab4269516ff421a22015d5df4e281 across all 17 changed files and related planning/write paths. No new inline findings. Existing P1 #4355508072 is fixed: each substituted default is typed as its referenced writer column before consumer binding. Existing type-drift findings #4355508096 and #4358048801 are fixed by rejecting mismatched read/writer types with a refresh hint.

Known P2 limits remain covered by existing threads, without duplicate comments: #4355508080 (Aggregate/Repeat outputs and separately owned CTE/scalar-subquery plans), #4355508088 (four-part target qualification), and #4355508100 (historical Iceberg-on-HMS capability reflection). These are verified dispositions, with no unresolved new candidate. No existing P0/P1 finding still applies. No additional user focus was supplied.

Critical checkpoint conclusions:

  1. Purpose and proof: ordinary VALUES/SELECT projections and bound-target UPDATE WHERE/MERGE ON now use the pinned writer default. Inspected unit/regression additions cover these paths; the known scope limits above remain.
  2. Focus and reuse: the change is localized and reuses the capability union, pinned writer schema, shared DEFAULT resolver and coercion helpers; generic planning stays connector-agnostic.
  3. Concurrency and locks: no new threads, lock acquisitions or shared mutable state; rewriting consumes the existing statement pin in the established planning lock scope. No new lock-order or concurrency defect found.
  4. Lifecycle: INSERT, overwrite and row-level writes pin before normalization; branch selection survives overwrite's inner INSERT. Prepared execution/retry reset clears writer schemas and identities. No new static-initialization or resource lifecycle.
  5. Configuration: no configuration change.
  6. Compatibility: the added capability is recorded in the plugin surface and the API major is consistently 21.0. ConnectorMetadata methods and storage/wire formats are unchanged.
  7. Thrift/protobuf: no definitions changed; cross-branch field-ID comparison is inapplicable.
  8. Parallel paths: explicit/implicit VALUES columns, FROM/no-FROM projections, overwrite/EXPLAIN, UPDATE, MERGE and shared changelog callers were traced. Plain Hive/Paimon/internal paths retain their existing non-opt-in behavior.
  9. Conditions and failures: missing target fields and mismatched writer types fail with context. Stable field-ID lookup avoids selecting a replacement field solely by reused name; target-name SELECT semantics are explicit and tested.
  10. Test coverage: inspected positive/negative tests cover capability declaration/reflection, writer-versus-read defaults, unknown columns, non-target rejection, non-opt-in behavior, width-sensitive numeric typing, and direct/enclosing type drift. End-to-end additions cover Parquet and ORC.
  11. Expected results: the new ordered rows 20/21/22 with default_int=35 and UPDATE/MERGE strings agree with the fixture and statements by inspection. Output-generation provenance and runtime passing status were not independently verified.
  12. Observability: analysis errors identify the DEFAULT reference or conflicting types and refresh action. No new distributed operation needs additional metrics/logging.
  13. Persistence and failover: no EditLog, replay or transaction-state change; existing writer metadata-identity/schema fences and commit paths remain in use.
  14. Writes and atomicity: changed expressions flow into existing analyzed connector sinks; no new commit, crash cleanup or partial-write mechanism. No new atomicity issue found.
  15. FE/BE propagation: no new transmitted variable or operator.
  16. Performance: one plan traversal and bounded linear column lookup per DEFAULT; no new per-row evaluation or concrete significant regression found.
  17. Core invariants and remaining issues: no new visibility-version, delete-bitmap or native memory-ownership path; errors fail analysis before execution. Final recheck found no additional substantiated issue beyond the existing threads.

Validation was static-only: no builds, tests, cluster execution or source modifications. Runtime behavior, full plugin packaging and test-generation provenance remain outside this invocation's validation.

Review converged after 2 round(s).

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 90.00% (45/50) 🎉
Increment coverage report
Complete coverage report

hubgeter
hubgeter previously approved these changes Oct 24, 2026
…hema

### What problem does this PR solve?

Issue Number: None

Related PR: apache#66538, apache#57531, apache#65851

Problem Summary: An Iceberg write-default exists only in the writer schema
that a write statement pins (IcebergWriteSchemaContext); the columns of the
read schema carry no default. Master resolves DEFAULT(column) against that
writer schema only in UPDATE / MERGE SET and in MERGE INSERT VALUES, and
everywhere else falls back to the read column. On a v3 table whose column d
has write-default 42, INSERT ... VALUES (DEFAULT(d)) and INSERT ... SELECT
DEFAULT(d) without FROM fail with "Unknown column", INSERT ... SELECT
DEFAULT(d) FROM t writes NULL, UPDATE ... WHERE d = DEFAULT(d) and MERGE
... ON ... d = DEFAULT(d) compare d with NULL and silently match no row, and
SELECT DEFAULT(d) FROM t returns NULL. branch-4.1 and branch-4.2 (apache#66538)
resolve all of these against the pinned write target, by name against the
target in INSERT ... SELECT, and reject DEFAULT(column) on an Iceberg column
in a statement that does not write the table.

This change adds the connector capability SUPPORTS_WRITE_ONLY_DEFAULTS,
declared by the Iceberg connector and inherited by iceberg-on-HMS tables.
For a table that declares it, InsertUtils resolves DEFAULT(column) in INSERT
VALUES and in the select lists of INSERT ... SELECT by name against the
pinned writer schema, and RewriteDefaultExpression takes the default of a
DEFAULT(column) bound to the table from the pinned writer column with the
same field id, which covers the UPDATE and MERGE conditions, and rejects it
when the statement pinned no writer schema for the table. Hive, Paimon and
OLAP tables keep the current behavior. The new enum constant changes the
connector plugin API surface, so the plugin API version goes from 20.0 to
21.0.

### Release note

Fix: On Iceberg tables, DEFAULT(column) in INSERT VALUES, INSERT ... SELECT
and the WHERE / ON conditions of UPDATE and MERGE now resolves to the
column's write-default. Before, it failed, wrote NULL, or matched no row.
SELECT DEFAULT(column) on an Iceberg table now fails instead of returning
NULL.

### Check List (For Author)

- Test: Regression test / Unit Test
    - test_iceberg_initial_defaults: writes rows 20-22 with
      DEFAULT(default_int) in VALUES and in INSERT ... SELECT with and
      without FROM, then updates them with UPDATE ... WHERE default_int =
      DEFAULT(default_int) and MERGE ... ON ... = DEFAULT(...), for Parquet
      and ORC; SELECT DEFAULT(default_int) must fail. Passes locally; with
      master's FE it fails at the first INSERT with "Unknown column
      'default_int'"
    - InsertUtilsTest: VALUES and INSERT ... SELECT (from a staging relation
      and without FROM) resolve against the pinned writer schema; unknown
      column fails; a table without the capability is unchanged
    - RewriteDefaultExpressionTest: pinned writer column wins, no pinned
      schema fails, a table without the capability keeps the read default
    - IcebergConnectorTest, HiveConnectorMetadataSiblingDelegationTest,
      ConnectorPluginSurfaceTest
- Behavior changed: Yes. See the release note.
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66538

Problem Summary: Two review findings on the previous commit.

ConnectorWriteSchemaUtils.resolveDefaultReferences parsed the default SQL
of a writer column and substituted it without a cast, so the default kept
the type the parser gives the literal: -1 is a TINYINT. For an INT column
with write-default -1, INSERT INTO t(c) VALUES (bit_count(DEFAULT(c))) and
INSERT INTO t(c) SELECT bit_count(DEFAULT(c)) evaluated bit_count on a
TINYINT and wrote 8 instead of 32; casting the finished value to INT cannot
restore that. The external UPDATE, MERGE and changelog paths use the same
helper and typed DEFAULT(column) the same way. The resolved default is now
cast to its column's type before the expression around it is bound, as
RewriteDefaultExpression does for a bound DEFAULT(column). branch-4.2
builds write defaults as literals of the column type and is not affected.

RewriteDefaultExpression took the result type from the read column before
substituting the pinned writer column. After a type promotion committed
outside Doris, the read schema can still hold an INT column while the
writer column is a BIGINT whose default an INT cannot hold, such as
4900000001, and the default was cast to INT. The type now comes from the
writer column the default is taken from.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - InsertUtilsTest#writeOnlyDefaultIsTypedAsItsColumnBeforeBinding:
      VALUES and SELECT pass DEFAULT(bits) to bit_count as an INT; with
      the previous commit it is a TINYINT
    - RewriteDefaultExpressionTest#writeOnlyDefaultTakesTheTypeOfThePinned
      WriterColumn: an INT read column with a BIGINT pinned writer column
      gives the BIGINT default; with the previous commit it is
      cast(4900000001 as INT)
    - InsertUtilsTest, RewriteDefaultExpressionTest,
      ConnectorWriteSchemaUtilsTest, ConnectorChangelogPlanBuilderTest,
      ChangelogRowLevelDmlTransformTest,
      ExternalRowLevelUpdatePlanBuilderTest,
      ExternalRowLevelMergePlanBuilderTest, PluginDrivenExternalTableTest:
      93 tests pass
- Behavior changed: No. DEFAULT(column) inside an expression of an
  external UPDATE / MERGE / changelog assignment now has the column's
  type, which is the type a bound DEFAULT(column) already had.
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
### What problem does this PR solve?

Issue Number: None

Related PR: apache#66538

Problem Summary: apache#69394 added two ConnectorWriteSchemaUtilsTest cases that
expect resolveDefaultReferences to return the default with the type the
parser gives its literal (9 is a TINYINT). The previous commit casts the
resolved default to its writer column's type, so for the INT test column the
result is now an INT literal 9, and both cases failed in FE UT once this
branch met master. The two expectations now use the column's type.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ConnectorWriteSchemaUtilsTest, RewriteDefaultExpressionTest, InsertUtilsTest
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… read type

### What problem does this PR solve?

Issue Number: None

Related PR: apache#66538

Problem Summary: Review follow-up. The previous commits typed the default
that replaces a bound DEFAULT(column) as its pinned writer column. That type
differs from the read column's only when the table changed outside Doris
after Doris cached its read schema, e.g. an INT column promoted to BIGINT
whose new write-default is 4900000001. The expressions around
DEFAULT(column) were already bound against the read type and the rewriter
keeps their signatures, so in

    UPDATE t SET ... WHERE IF(TRUE, DEFAULT(score), 0) = 4900000001

the IF keeps its INT result type and constant folding casts 4900000001 back
to INT: NULL in non-strict mode, so no row matches, and an overflow error in
strict mode. A substituted value cannot repair the types its consumers were
bound with, so the rewrite now fails such a DEFAULT and asks to refresh the
table. When the two types agree, which is every case without a type change
made outside Doris, nothing changes.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - RewriteDefaultExpressionTest: a DEFAULT whose writer type differs is rejected, directly and under an IF bound to the read type
    - ConnectorWriteSchemaUtilsTest, InsertUtilsTest, ExternalRowLevelUpdatePlanBuilderTest, ExternalRowLevelMergePlanBuilderTest, ChangelogRowLevelDmlTransformTest, PluginDrivenExternalTableTest
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@morningman
morningman force-pushed the b2m-t35j-iceberg-default-col-write-target branch from 688e8d5 to 676a924 Compare October 25, 2026 08:31
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman

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.

Request changes: one new P1 finding. INSERT ... SELECT normalization crosses a FROM-derived query boundary and can silently write the target default in place of the source default. The inline comment includes the concrete SQL and reduced plan. All 17 changed files and their relevant upstream/downstream paths were reviewed statically.

Critical checkpoint conclusions:

  1. Goal/data correctness: pinned writer defaults fix the covered simple INSERT, UPDATE and MERGE cases, but the derived-source regression prevents full correctness.
  2. Scope/clarity/reuse: the capability and shared resolver keep the change focused and connector-agnostic.
  3. Concurrency/locks: no new thread, lock or shared mutable global; statement pins and existing generation fences remain in use. No new locking defect found.
  4. Lifecycle/static initialization: writer columns remain statement-owned and are cleared before retry/re-execution; connector resources close through existing scope cleanup. No new ownership or static-order issue.
  5. Configuration: none added.
  6. Compatibility: the appended SPI capability is recorded in the plugin surface; API property and test both advance to 21.0. No metadata-method signature or storage-format change.
  7. Thrift/protobuf: no changes.
  8. Parallel paths: checked explicit/implicit VALUES, SELECT, overwrite/retry/EXPLAIN, UPDATE, MERGE, DELETE and shared changelog callers; direct Iceberg and ordinary HMS delegation are covered. Known historical HMS limitation remains as noted below.
  9. Conditional checks/error handling: missing writer pins/fields and read/write type mismatches fail analysis; capability guards have concrete purpose. The accepted source-scope defect bypasses the intended source interpretation.
  10. Tests: new unit/regression cases cover typed substitution, unknown columns, capability opt-out, stale types, Parquet/ORC writes and read-only rejection; derived-source defaults lack coverage.
  11. Expected results: new output rows are consistent with the SQL on static inspection; output generation and runtime success were not independently verified.
  12. Observability: existing analysis errors carry the DEFAULT expression and type/refresh context; no additional long-lived operation requires metrics.
  13. Persistence/failover: no new edit-log or persistence path; existing Iceberg identity/schema/spec/order fences remain unchanged.
  14. Writes/atomicity: existing connector commit/abort machinery is reused; the new P1 concerns the value supplied to an otherwise atomic write.
  15. FE/BE variables: none added; existing expression serialization is reused.
  16. Performance: work is proportional to plan/expression size and schema lookup width during planning; no new per-row execution work or substantiated performance regression.
  17. Additional concerns/focus: no additional user focus was supplied; all initial risk questions have explicit dispositions and no new candidate remains unresolved.

Existing-thread dispositions: P1 r4355508072 is fixed by casting each default to its referenced writer-column type before binding, so existing_blocking_comment_ids is empty. P2 r4355508096 and r4358048801 are fixed by rejecting a writer/read type mismatch before substitution. The aggregate/CTE/scalar-subquery limitation (r4355508080), four-part qualification limitation (r4355508088), and historical HMS capability-reflection limitation (r4355508100) remain already-reported P2 concerns and are not reposted. The new finding is the opposite scope failure: traversal enters a FROM-derived query and captures a valid source reference.

Review converged after three rounds over the frozen finding set, with complete assigned static coverage. No builds or tests were run, as required by this review environment; runtime behavior and generated-output provenance remain outside this static review's validation scope.

Review converged after 3 round(s).

*/
private static Plan resolveSelectDefaultReferences(Plan query, Optional<List<Column>> writeOnlyDefaultColumns,
TableIf table, List<String> targetNameParts) {
return query.rewriteUp(plan -> {

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 source defaults across derived-query boundaries

Let OLAP src(c INT DEFAULT 7) contain one row and Iceberg target t(c INT) have pinned write-default 9:

INSERT INTO t(c)
SELECT v FROM (SELECT DEFAULT(c) AS v FROM src) q;

The reduced input plan is Sink(t.c) -> Project(v) -> SubQueryAlias(q) -> Project(DEFAULT(c) AS v) -> Scan(src.c). query.rewriteUp descends through q and resolves the inner projection against the outer writer columns before source binding, producing Project(9:INT AS v) and silently writing 9 instead of the source default 7. Writing DEFAULT(src.c) makes the same valid source query fail instead: checkAssignmentColumn compares src with target t. This is distinct from the existing unvisited aggregate/CTE/scalar-subquery issue: here an independently scoped FROM query is traversed and its source reference is overwritten. Stop target-default substitution at derived-query boundaries while retaining the outer query's output/set-operation handling, and cover both the qualified source reference and different source/target defaults.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17610	5228	5087	5087
q2	2124	295	249	249
q3	10256	1366	817	817
q4	4676	453	336	336
q5	7449	786	511	511
q6	182	186	153	153
q7	738	790	590	590
q8	9243	1307	1039	1039
q9	5444	4146	4170	4146
q10	6802	1276	1041	1041
q11	409	247	221	221
q12	634	393	272	272
q13	18096	3444	2967	2967
q14	270	273	251	251
q15	q16	708	718	675	675
q17	1193	743	577	577
q18	6988	6155	6110	6110
q19	1100	951	567	567
q20	380	338	220	220
q21	4174	2072	2245	2072
q22	339	294	251	251
Total cold run time: 98815 ms
Total hot run time: 28152 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5618	5578	5555	5555
q2	664	572	537	537
q3	5202	5348	4966	4966
q4	1982	2153	1523	1523
q5	5275	5178	5129	5129
q6	230	196	197	196
q7	2439	2029	1885	1885
q8	2958	2613	2627	2613
q9	8039	7970	7973	7970
q10	3731	3623	3276	3276
q11	616	431	393	393
q12	852	760	542	542
q13	3371	3963	3174	3174
q14	308	324	283	283
q15	q16	700	726	672	672
q17	8162	7488	6805	6805
q18	12948	12141	12776	12141
q19	897	765	773	765
q20	2147	2143	1892	1892
q21	5521	4710	4685	4685
q22	500	473	397	397
Total cold run time: 72160 ms
Total hot run time: 65399 ms

@hello-stephen

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

query5	4308	574	433	433
query6	415	201	187	187
query7	4794	443	225	225
query8	317	172	155	155
query9	8767	3029	3052	3029
query10	469	305	246	246
query11	6046	3841	3558	3558
query12	143	93	85	85
query13	1244	441	319	319
query14	6122	3929	3662	3662
query14_1	3422	3391	3348	3348
query15	206	196	180	180
query16	940	450	395	395
query17	846	658	538	538
query18	2428	441	298	298
query19	185	151	125	125
query20	81	80	81	80
query21	210	125	101	101
query22	12975	12951	12845	12845
query23	13425	12675	12497	12497
query23_1	12524	12433	12453	12433
query24	7369	794	452	452
query24_1	465	453	472	453
query25	512	393	338	338
query26	1269	256	137	137
query27	2782	437	266	266
query28	4628	1904	1908	1904
query29	1556	587	410	410
query30	296	220	191	191
query31	1003	929	815	815
query32	146	91	89	89
query33	506	286	235	235
query34	887	843	480	480
query35	725	734	640	640
query36	828	796	694	694
query37	121	102	82	82
query38	1766	1740	1693	1693
query39	793	797	744	744
query39_1	753	737	754	737
query40	234	114	92	92
query41	69	68	65	65
query42	87	92	82	82
query43	348	371	312	312
query44	1317	700	703	700
query45	181	180	172	172
query46	844	963	579	579
query47	3037	2817	2661	2661
query48	299	314	229	229
query49	579	403	288	288
query50	671	267	205	205
query51	10459	10313	10402	10313
query52	78	83	72	72
query53	186	209	151	151
query54	246	223	183	183
query55	80	69	64	64
query56	240	222	235	222
query57	1642	1606	1538	1538
query58	300	263	253	253
query59	2108	2121	1959	1959
query60	295	254	236	236
query61	174	162	167	162
query62	395	353	284	284
query63	193	158	161	158
query64	2870	1061	887	887
query65	3440	3327	3254	3254
query66	1772	409	293	293
query67	20116	20155	19920	19920
query68	2946	987	598	598
query69	387	283	236	236
query70	815	813	760	760
query71	288	240	212	212
query72	2696	2555	2323	2323
query73	500	520	288	288
query74	4595	4493	4345	4345
query75	2321	2290	1910	1910
query76	2318	1003	602	602
query77	341	366	263	263
query78	9716	9825	9258	9258
query79	959	902	506	506
query80	1052	435	352	352
query81	580	311	277	277
query82	575	130	106	106
query83	277	197	174	174
query84	304	121	105	105
query85	1008	433	361	361
query86	352	247	223	223
query87	2018	1969	1814	1814
query88	3663	2676	2633	2633
query89	326	291	255	255
query90	1712	163	162	162
query91	159	141	127	127
query92	95	86	86	86
query93	977	993	567	567
query94	529	314	267	267
query95	569	327	362	327
query96	657	481	231	231
query97	2445	2431	2297	2297
query98	165	153	142	142
query99	762	757	673	673
Total cold run time: 234274 ms
Total hot run time: 150311 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.09	0.05	0.06
query3	0.27	0.10	0.09
query4	1.61	0.11	0.09
query5	0.23	0.24	0.23
query6	1.17	0.68	0.69
query7	0.04	0.00	0.00
query8	0.05	0.04	0.03
query9	0.39	0.34	0.36
query10	0.58	0.58	0.57
query11	0.20	0.14	0.14
query12	0.18	0.14	0.15
query13	0.49	0.49	0.48
query14	1.03	1.00	1.00
query15	0.63	0.63	0.61
query16	0.36	0.35	0.33
query17	1.12	1.10	1.15
query18	0.21	0.21	0.19
query19	2.08	2.00	1.99
query20	0.02	0.01	0.01
query21	15.48	0.18	0.14
query22	4.92	0.05	0.06
query23	16.25	0.33	0.12
query24	3.12	0.44	0.47
query25	0.12	0.06	0.06
query26	1.21	0.20	0.16
query27	0.05	0.05	0.04
query28	3.57	0.76	0.36
query29	12.51	4.15	3.24
query30	0.29	0.14	0.10
query31	2.77	0.55	0.32
query32	3.22	0.61	0.50
query33	3.12	3.26	3.22
query34	15.27	4.01	3.38
query35	3.34	3.33	3.36
query36	0.55	0.47	0.41
query37	0.09	0.07	0.06
query38	0.06	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.15	0.14
query41	0.09	0.03	0.02
query42	0.04	0.03	0.03
query43	0.04	0.03	0.03
Total cold run time: 97.08 s
Total hot run time: 24.29 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 90.00% (45/50) 🎉
Increment coverage report
Complete coverage report

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.

3 participants