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]