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

hello-stephen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 6b547727f9d [fix](point-query) Skip nested pruning for short-circuit 
query (#65051)
6b547727f9d is described below

commit 6b547727f9dc628741edfa16509f22ef29dc66d3
Author: Jerry Hu <[email protected]>
AuthorDate: Fri Jul 3 11:18:11 2026 +0800

    [fix](point-query) Skip nested pruning for short-circuit query (#65051)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Problem Summary:
    
    Short-circuit point queries on row-store Unique Key MOW tables read
    row-store complex column payloads with the original full schema. Nested
    column pruning can narrow complex slot types and attach all/predicate
    access paths before the short-circuit request is serialized. That
    descriptor is incompatible with the point-query row-store
    materialization path and may crash the backend while evaluating nested
    struct/map/string fields.
    
    This change skips nested column pruning for FE short-circuit point
    queries, so complex slot types and access paths stay unchanged on this
    path. The BE point-query initialization path also rejects descriptors
    that still carry all/predicate access paths and returns a clear error
    asking the user to upgrade FE, preventing mixed-version or stale FE
    contexts from reaching row-store materialization. Regression coverage is
    added for a nested complex row-store point query and compares the normal
    path with repeated short-circuit executions.
---
 be/src/service/point_query_executor.cpp            |   9 ++
 .../nereids/rules/rewrite/NestedColumnPruning.java |   5 +
 .../test_short_circuit_rowstore_nested_complex.out |   9 ++
 ...st_short_circuit_rowstore_nested_complex.groovy | 131 +++++++++++++++++++++
 4 files changed, 154 insertions(+)

diff --git a/be/src/service/point_query_executor.cpp 
b/be/src/service/point_query_executor.cpp
index 8e3e83cfd46..8b9e36f08db 100644
--- a/be/src/service/point_query_executor.cpp
+++ b/be/src/service/point_query_executor.cpp
@@ -133,6 +133,15 @@ Status Reusable::init(const TDescriptorTable& t_desc_tbl, 
const std::vector<TExp
     _runtime_state->set_query_options(query_options);
     RETURN_IF_ERROR(DescriptorTbl::create(_runtime_state->obj_pool(), 
t_desc_tbl, &_desc_tbl));
     _runtime_state->set_desc_tbl(_desc_tbl);
+    for (const auto* slot : tuple_desc()->slots()) {
+        if (!slot->all_access_paths().empty() || 
!slot->predicate_access_paths().empty()) {
+            return Status::InternalError(
+                    "Short-circuit point query does not support nested column 
access paths, "
+                    "slot: {}. Please upgrade FE to disable nested column 
pruning for "
+                    "short-circuit point queries.",
+                    slot->col_name());
+        }
+    }
     _block_pool.resize(block_size);
     for (auto& i : _block_pool) {
         i = Block::create_unique(tuple_desc()->slots(), 2);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/NestedColumnPruning.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/NestedColumnPruning.java
index 086d1b7bae1..6ae6ef2b1ab 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/NestedColumnPruning.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/NestedColumnPruning.java
@@ -82,6 +82,11 @@ public class NestedColumnPruning implements CustomRewriter {
     public Plan rewriteRoot(Plan plan, JobContext jobContext) {
         try {
             StatementContext statementContext = 
jobContext.getCascadesContext().getStatementContext();
+            // Short-circuit point queries read row-store payloads with the 
original full schema.
+            // Keep complex slot types and access paths unchanged for this 
path.
+            if (statementContext.isShortCircuitQuery()) {
+                return plan;
+            }
             SessionVariable sessionVariable = 
statementContext.getConnectContext().getSessionVariable();
             if (!sessionVariable.enablePruneNestedColumns
                     || (!statementContext.hasNestedColumns()
diff --git 
a/regression-test/data/point_query_p0/test_short_circuit_rowstore_nested_complex.out
 
b/regression-test/data/point_query_p0/test_short_circuit_rowstore_nested_complex.out
new file mode 100644
index 00000000000..edc32152a8f
--- /dev/null
+++ 
b/regression-test/data/point_query_p0/test_short_circuit_rowstore_nested_complex.out
@@ -0,0 +1,9 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !normal_path --
+5      8       8       \N      \N      3       false
+
+-- !short_circuit_path --
+5      8       8       \N      \N      3       false
+
+-- !short_circuit_path_repeat --
+5      8       8       \N      \N      3       false
diff --git 
a/regression-test/suites/point_query_p0/test_short_circuit_rowstore_nested_complex.groovy
 
b/regression-test/suites/point_query_p0/test_short_circuit_rowstore_nested_complex.groovy
new file mode 100644
index 00000000000..d9425a6a3b0
--- /dev/null
+++ 
b/regression-test/suites/point_query_p0/test_short_circuit_rowstore_nested_complex.groovy
@@ -0,0 +1,131 @@
+// 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_short_circuit_rowstore_nested_complex", "p0,nonConcurrent") {
+    def backendId_to_backendIP = [:]
+    def backendId_to_backendHttpPort = [:]
+    getBackendIpHttpPort(backendId_to_backendIP, backendId_to_backendHttpPort)
+    def set_be_config = { key, value ->
+        for (String backend_id : backendId_to_backendIP.keySet()) {
+            def (code, out, err) = 
update_be_config(backendId_to_backendIP.get(backend_id),
+                    backendId_to_backendHttpPort.get(backend_id), key, value)
+            logger.info("update config: code=" + code + ", out=" + out + ", 
err=" + err)
+        }
+    }
+
+    try {
+        set_be_config.call("disable_storage_row_cache", "false")
+
+        sql "SET enable_nereids_planner=true"
+        sql "SET enable_sql_cache=false"
+        sql "SET enable_snapshot_point_query=true"
+        sql "SET enable_short_circuit_query_access_column_store=true"
+
+        sql "DROP TABLE IF EXISTS short_circuit_rowstore_nested_complex"
+        sql """
+            CREATE TABLE short_circuit_rowstore_nested_complex (
+                pk INT,
+                deep STRUCT<
+                    nested_str: VARCHAR(64),
+                    inner_s: STRUCT<deep_str: VARCHAR(64), flag: BOOLEAN, 
deep_char: CHAR(8)>,
+                    deep_arr: ARRAY<STRUCT<verified: BOOLEAN, txt: 
VARCHAR(64), char_tag: CHAR(8)>>,
+                    deep_map: MAP<VARCHAR(32), STRUCT<leaf: VARCHAR(64), n: 
INT, char_leaf: CHAR(8)>>
+                > NULL,
+                s STRUCT<str: VARCHAR(64), char_leaf: CHAR(8), num: INT, 
sibling: VARCHAR(64)> NULL
+            ) ENGINE = OLAP
+            UNIQUE KEY(pk)
+            DISTRIBUTED BY HASH(pk) BUCKETS 1
+            PROPERTIES (
+                "replication_allocation" = "tag.location.default: 1",
+                "enable_unique_key_merge_on_write" = "true",
+                "light_schema_change" = "true",
+                "store_row_column" = "true",
+                "row_store_page_size" = "16384"
+            )
+        """
+
+        sql """
+            INSERT INTO short_circuit_rowstore_nested_complex VALUES
+                (5,
+                 named_struct(
+                     'nested_str', 'b-deep-5',
+                     'inner_s', named_struct('deep_str', 'b-inner-5', 'flag', 
true, 'deep_char', 'bd5'),
+                     'deep_arr', array(named_struct('verified', false, 'txt', 
'b-deep-arr-5', 'char_tag', 'bt5')),
+                     'deep_map', map('b_key', named_struct('leaf', 'b-leaf-5', 
'n', -5, 'char_leaf', 'bl5'))),
+                 named_struct('str', 'b-s-5', 'char_leaf', 'bc5', 'num', -35, 
'sibling', 'b-sib-5'))
+        """
+        sql "SYNC"
+
+        sql "SET enable_short_circuit_query=false"
+        order_qt_normal_path """
+            SELECT /*+ SET_VAR(enable_nereids_planner=true) */
+                   pk,
+                   CHAR_LENGTH(struct_element(element_at(struct_element(deep, 
'deep_map'), 'b_key'), 'leaf')) AS hit_char_len,
+                   LENGTH(LOWER(struct_element(element_at(struct_element(deep, 
'deep_map'), 'b_key'), 'leaf'))) AS hit_lower_len,
+                   CHAR_LENGTH(struct_element(element_at(struct_element(deep, 
'deep_map'), 'dense'), 'leaf')) AS miss_char_len,
+                   LENGTH(LOWER(struct_element(element_at(struct_element(deep, 
'deep_map'), 'dense'), 'leaf'))) AS miss_lower_len,
+                   LENGTH(struct_element(struct_element(deep, 'inner_s'), 
'deep_char')) AS char_storage_len,
+                   ((struct_element(s, 'num') + 1) IS NULL) AS expr_is_null
+            FROM short_circuit_rowstore_nested_complex
+            WHERE pk = 5
+        """
+
+        sql "SET enable_short_circuit_query=true"
+        explain {
+            sql """
+                SELECT /*+ SET_VAR(enable_nereids_planner=true) */
+                       pk,
+                       
CHAR_LENGTH(struct_element(element_at(struct_element(deep, 'deep_map'), 
'b_key'), 'leaf')) AS hit_char_len,
+                       
LENGTH(LOWER(struct_element(element_at(struct_element(deep, 'deep_map'), 
'b_key'), 'leaf'))) AS hit_lower_len,
+                       
CHAR_LENGTH(struct_element(element_at(struct_element(deep, 'deep_map'), 
'dense'), 'leaf')) AS miss_char_len,
+                       
LENGTH(LOWER(struct_element(element_at(struct_element(deep, 'deep_map'), 
'dense'), 'leaf'))) AS miss_lower_len,
+                       LENGTH(struct_element(struct_element(deep, 'inner_s'), 
'deep_char')) AS char_storage_len,
+                       ((struct_element(s, 'num') + 1) IS NULL) AS expr_is_null
+                FROM short_circuit_rowstore_nested_complex
+                WHERE pk = 5
+            """
+            contains "SHORT-CIRCUIT"
+        }
+        order_qt_short_circuit_path """
+            SELECT /*+ SET_VAR(enable_nereids_planner=true) */
+                   pk,
+                   CHAR_LENGTH(struct_element(element_at(struct_element(deep, 
'deep_map'), 'b_key'), 'leaf')) AS hit_char_len,
+                   LENGTH(LOWER(struct_element(element_at(struct_element(deep, 
'deep_map'), 'b_key'), 'leaf'))) AS hit_lower_len,
+                   CHAR_LENGTH(struct_element(element_at(struct_element(deep, 
'deep_map'), 'dense'), 'leaf')) AS miss_char_len,
+                   LENGTH(LOWER(struct_element(element_at(struct_element(deep, 
'deep_map'), 'dense'), 'leaf'))) AS miss_lower_len,
+                   LENGTH(struct_element(struct_element(deep, 'inner_s'), 
'deep_char')) AS char_storage_len,
+                   ((struct_element(s, 'num') + 1) IS NULL) AS expr_is_null
+            FROM short_circuit_rowstore_nested_complex
+            WHERE pk = 5
+        """
+
+        order_qt_short_circuit_path_repeat """
+            SELECT /*+ SET_VAR(enable_nereids_planner=true) */
+                   pk,
+                   CHAR_LENGTH(struct_element(element_at(struct_element(deep, 
'deep_map'), 'b_key'), 'leaf')) AS hit_char_len,
+                   LENGTH(LOWER(struct_element(element_at(struct_element(deep, 
'deep_map'), 'b_key'), 'leaf'))) AS hit_lower_len,
+                   CHAR_LENGTH(struct_element(element_at(struct_element(deep, 
'deep_map'), 'dense'), 'leaf')) AS miss_char_len,
+                   LENGTH(LOWER(struct_element(element_at(struct_element(deep, 
'deep_map'), 'dense'), 'leaf'))) AS miss_lower_len,
+                   LENGTH(struct_element(struct_element(deep, 'inner_s'), 
'deep_char')) AS char_storage_len,
+                   ((struct_element(s, 'num') + 1) IS NULL) AS expr_is_null
+            FROM short_circuit_rowstore_nested_complex
+            WHERE pk = 5
+        """
+    } finally {
+        set_be_config.call("disable_storage_row_cache", "true")
+    }
+}


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

Reply via email to