This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.2 by this push:
     new 297e628a74d branch-4.2: [fix](analyzer) Preserve bound signatures 
during insert folding (#68154) (#69103)
297e628a74d is described below

commit 297e628a74d3f719e27be7010187fb587d14720a
Author: morrySnow <[email protected]>
AuthorDate: Fri Oct 16 14:13:27 2026 +0800

    branch-4.2: [fix](analyzer) Preserve bound signatures during insert folding 
(#68154) (#69103)
    
    ### What problem does this PR solve?
    
    Issue Number: N/A
    Related PR: https://github.com/apache/doris/pull/68154
    
    Problem Summary: Post-bind INSERT constant folding could recompute
    nested field nullability while surrounding bound expressions kept their
    original layout, causing BE crashes for arrays of structs. Preserve
    bound signatures in normal and fast INSERT analysis. Place regression
    cases under the branch-4.2 nereids_p0 directory.
    
    ### Release note
    
    Fix BE crashes when inserting arrays of structs containing foldable
    nullable functions.
    
    ### Backport validation
    
    - Test: Unit Test: InsertUtilsTest; FE Checkstyle (0 violations).
    - Combined eight-backport validation: 283 tests across 13 classes, 0
    failures/errors after correcting identity-cast assertions. This
    standalone backport has not had a separate unit-test run.
    - Targeted regression: test_insert_array_struct_function_signature
    passed through run-regression-test.sh on the combined eight-backport
    ASAN deployment. This standalone branch and the full regression suite
    were not tested separately.
    - Full build.sh --fe and ASAN build.sh --be succeeded on the combined
    eight-backport tree; deployment smoke validation passed.
    - Behavior changed: Yes (post-bind INSERT rewrites preserve bound
    function signatures)
    - Does this need documentation: No
    
    (cherry picked from commit 3e878ed06764c53f6f1af3573a8de0b4fc8f5fa8)
    
    ### Scope
    
    This is an independent backport of #68154 onto branch-4.2.
    The branch contains one commit and does not include the other seven
    picks.
    The 283-test result above was obtained from the combined backport tree;
    this standalone branch has not had a separate unit-test run.
    
    ### Check List (For Author)
    
    - Test:
    - [x] Unit Test: 283 targeted tests passed on the combined backport
    tree.
    - [x] Manual test: standalone patch matches the validated pick; FE
    Checkstyle passed on the combined tree.
    - [x] Regression test: test_insert_array_struct_function_signature
    passed on the combined eight-backport ASAN deployment; this standalone
    branch was not tested separately. The full regression suite was not run.
    - Behavior changed: see the backport validation details above.
    - Does this need documentation: No.
---
 .../jobs/executor/AbstractBatchJobExecutor.java    |  7 ++-
 .../commands/insert/InsertIntoValuesAnalyzer.java  | 36 ++++++++++++---
 .../trees/plans/commands/insert/InsertUtils.java   | 11 ++++-
 ...test_insert_array_struct_function_signature.out |  5 +++
 ...t_insert_array_struct_function_signature.groovy | 52 ++++++++++++++++++++++
 5 files changed, 103 insertions(+), 8 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/AbstractBatchJobExecutor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/AbstractBatchJobExecutor.java
index 8cd266e3b73..f0c7515834f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/AbstractBatchJobExecutor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/AbstractBatchJobExecutor.java
@@ -142,7 +142,12 @@ public abstract class AbstractBatchJobExecutor {
      * execute.
      */
     public void execute() {
-        List<RewriteJob> jobs = Lists.newArrayList(getJobs());
+        executeJobs(getJobs());
+    }
+
+    /** Execute the specified rewrite jobs. */
+    protected void executeJobs(List<RewriteJob> rewriteJobs) {
+        List<RewriteJob> jobs = Lists.newArrayList(rewriteJobs);
         for (int i = 0; i < jobs.size(); i++) {
             JobContext jobContext = cascadesContext.getCurrentJobContext();
             RewriteJob currentJob = jobs.get(i);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertIntoValuesAnalyzer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertIntoValuesAnalyzer.java
index 772f0c5f001..aee33ba5774 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertIntoValuesAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertIntoValuesAnalyzer.java
@@ -39,6 +39,7 @@ import 
org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier;
 import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation;
 import org.apache.doris.nereids.trees.plans.logical.LogicalUnion;
 import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.util.MoreFieldsThread;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -47,10 +48,15 @@ import java.util.List;
 
 /** InsertIntoValuesAnalyzer */
 public class InsertIntoValuesAnalyzer extends AbstractBatchJobExecutor {
-    public static final List<RewriteJob> INSERT_JOBS = jobs(
+    private static final List<RewriteJob> BINDING_JOBS = jobs(
             bottomUp(
                     new InlineTableToUnionOrOneRowRelation(),
-                    new BindSink(),
+                    new BindSink()
+            )
+    );
+
+    private static final List<RewriteJob> POST_BIND_JOBS = jobs(
+            bottomUp(
                     new MergeProjectable(),
                     // after bind olap table sink, the LogicalProject will be 
generated under LogicalOlapTableSink,
                     // we should convert the agg state function in the 
project, and evaluate some env parameters
@@ -63,10 +69,8 @@ public class InsertIntoValuesAnalyzer extends 
AbstractBatchJobExecutor {
             )
     );
 
-    public static final List<RewriteJob> BATCH_INSERT_JOBS = jobs(
+    private static final List<RewriteJob> BATCH_INSERT_POST_BIND_JOBS = jobs(
             bottomUp(
-                    new InlineTableToUnionOrOneRowRelation(),
-                    new BindSink(),
                     new MergeProjectable(),
 
                     // the BatchInsertIntoTableCommand need send StringLiteral 
to backend,
@@ -84,6 +88,12 @@ public class InsertIntoValuesAnalyzer extends 
AbstractBatchJobExecutor {
             )
     );
 
+    public static final List<RewriteJob> INSERT_JOBS = 
ImmutableList.<RewriteJob>builder()
+            .addAll(BINDING_JOBS).addAll(POST_BIND_JOBS).build();
+
+    public static final List<RewriteJob> BATCH_INSERT_JOBS = 
ImmutableList.<RewriteJob>builder()
+            .addAll(BINDING_JOBS).addAll(BATCH_INSERT_POST_BIND_JOBS).build();
+
     private final boolean batchInsert;
 
     public InsertIntoValuesAnalyzer(CascadesContext cascadesContext, boolean 
batchInsert) {
@@ -96,6 +106,22 @@ public class InsertIntoValuesAnalyzer extends 
AbstractBatchJobExecutor {
         return batchInsert ? BATCH_INSERT_JOBS : INSERT_JOBS;
     }
 
+    @Override
+    public void execute() {
+        MoreFieldsThread.keepFunctionSignature(false, () -> {
+            executeJobs(BINDING_JOBS);
+            return null;
+        });
+        MoreFieldsThread.keepFunctionSignature(() -> {
+            executeJobs(getPostBindJobs());
+            return null;
+        });
+    }
+
+    private List<RewriteJob> getPostBindJobs() {
+        return batchInsert ? BATCH_INSERT_POST_BIND_JOBS : POST_BIND_JOBS;
+    }
+
     private static class RewriteInsertIntoExpressions extends 
ExpressionRewrite {
         public RewriteInsertIntoExpressions(ExpressionRewriteRule... rules) {
             super(rules);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java
index c488fdd4029..6b6c484fcb3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java
@@ -81,6 +81,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.UnboundLogicalSink;
 import org.apache.doris.nereids.types.AggStateType;
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.VarcharType;
+import org.apache.doris.nereids.util.MoreFieldsThread;
 import org.apache.doris.nereids.util.RelationUtil;
 import org.apache.doris.nereids.util.TypeCoercionUtils;
 import org.apache.doris.proto.InternalService;
@@ -691,7 +692,7 @@ public class InsertUtils {
                     if (expr.child(0).getDataType() instanceof AggStateType) {
                         expr = ConvertAggStateCast.convert((Cast) expr);
                     } else {
-                        expr = FoldConstantRuleOnFE.evaluate(expr, context);
+                        expr = foldConstantAfterBind(expr, context);
                     }
                 }
                 return expr;
@@ -768,11 +769,17 @@ public class InsertUtils {
             );
             value = rewriteContext == null
                     ? value
-                    : (NamedExpression) FoldConstantRuleOnFE.evaluate(value, 
rewriteContext);
+                    : (NamedExpression) foldConstantAfterBind(value, 
rewriteContext);
         }
         optimizedRowConstructor.add(value);
     }
 
+    private static Expression foldConstantAfterBind(
+            Expression expression, ExpressionRewriteContext rewriteContext) {
+        return MoreFieldsThread.keepFunctionSignature(
+                () -> FoldConstantRuleOnFE.evaluate(expression, 
rewriteContext));
+    }
+
     private static NamedExpression castValue(Expression value, DataType 
targetType) {
         if (value instanceof Alias) {
             Expression oldChild = value.child(0);
diff --git 
a/regression-test/data/nereids_p0/insert_into_table/test_insert_array_struct_function_signature.out
 
b/regression-test/data/nereids_p0/insert_into_table/test_insert_array_struct_function_signature.out
new file mode 100644
index 00000000000..0ebc86a88c6
--- /dev/null
+++ 
b/regression-test/data/nereids_p0/insert_into_table/test_insert_array_struct_function_signature.out
@@ -0,0 +1,5 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !array_struct_function_signature --
+1      [{"i":100, "s":"xx"}, {"i":200, "s":"yy"}]
+2      [{"i":100, "s":"xx"}, {"i":200, "s":"yy"}]
+
diff --git 
a/regression-test/suites/nereids_p0/insert_into_table/test_insert_array_struct_function_signature.groovy
 
b/regression-test/suites/nereids_p0/insert_into_table/test_insert_array_struct_function_signature.groovy
new file mode 100644
index 00000000000..370b4b750a1
--- /dev/null
+++ 
b/regression-test/suites/nereids_p0/insert_into_table/test_insert_array_struct_function_signature.groovy
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_insert_array_struct_function_signature") {
+    sql "drop table if exists array_struct_function_signature"
+    sql """
+        create table array_struct_function_signature (
+            id int,
+            a array<struct<i: int, s: varchar(16)>>
+        ) duplicate key(id)
+        distributed by hash(id) buckets 1
+        properties("replication_num" = "1")
+    """
+
+    sql "set enable_fast_analyze_into_values = true"
+    sql """
+        insert into array_struct_function_signature values (
+            1,
+            array(
+                struct(100, repeat('x', 2)),
+                struct(200, repeat('y', 2))
+            )
+        )
+    """
+
+    sql "set enable_fast_analyze_into_values = false"
+    sql """
+        insert into array_struct_function_signature values (
+            2,
+            array(
+                struct(100, repeat('x', 2)),
+                struct(200, repeat('y', 2))
+            )
+        )
+    """
+
+    order_qt_array_struct_function_signature "select * from 
array_struct_function_signature"
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to