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

mymeiyi 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 c5324805b53 [fix](audit) Fix SET_VAR leakage after INSERT audit 
logging (#67786)
c5324805b53 is described below

commit c5324805b53f412434bcb609e0e61a6a73ca73e9
Author: meiyi <[email protected]>
AuthorDate: Wed Sep 16 15:34:21 2026 +0800

    [fix](audit) Fix SET_VAR leakage after INSERT audit logging (#67786)
    
    Problem Summary: After an INSERT containing a table-valued function
    finishes, audit logging reparses its SQL for redaction. This runs after
    StmtExecutor has restored session variables, but the redaction parser
    applies SET_VAR again. For example, an INSERT using numbers() with
    query_timeout=1 and insert_timeout=1 leaves both session values at 1,
    causing the next unhinted INSERT to time out.
    
    Pass an empty hint map to the redaction plan builder so it does not
    apply execution hints. The redacted SQL still preserves the original
    hint text and masks sensitive properties. This also applies to other
    callers of the shared redaction parser, including FE logging and
    streaming-job SQL display.
---
 .../apache/doris/nereids/parser/NereidsParser.java |  5 +-
 .../parser/AuditEncryptionSessionVariableTest.java | 63 ++++++++++++++++++++++
 .../test_set_var_hint_restore.groovy               | 44 +++++++++++++++
 3 files changed, 111 insertions(+), 1 deletion(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
index 4184c0f421c..539a05ef867 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
@@ -362,11 +362,14 @@ public class NereidsParser {
         return (LogicalPlan) realLogicalPlanBuilder.visit(tree);
     }
 
+    /** Parse SQL for masking without applying execution hints to the session. 
*/
     public LogicalPlan parseForEncryption(String sql, Map<Pair<Integer, 
Integer>, String> indexInSqlToString) {
         CommonTokenStream tokenStream = parseLeanTokens(sql);
         ParserRuleContext tree = toAst(tokenStream, 
DorisParser::singleStatement);
+        // SQL masking must not apply SET_VAR hints to the current session.
+        // The original SQL, including its hints, is preserved by the property 
replacements.
         LogicalPlanBuilder realLogicalPlanBuilder = new 
LogicalPlanBuilderForEncryption(
-                getHintMap(sql, tokenStream, DorisParser::selectHint), 
indexInSqlToString);
+                ImmutableMap.of(), indexInSqlToString);
         return (LogicalPlan) realLogicalPlanBuilder.visit(tree);
     }
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/AuditEncryptionSessionVariableTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/AuditEncryptionSessionVariableTest.java
new file mode 100644
index 00000000000..58004fa4534
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/AuditEncryptionSessionVariableTest.java
@@ -0,0 +1,63 @@
+// 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.
+
+package org.apache.doris.nereids.parser;
+
+import org.apache.doris.common.Pair;
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.trees.plans.commands.info.BaseViewInfo;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.SessionVariable;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.TreeMap;
+
+public class AuditEncryptionSessionVariableTest {
+    @Test
+    public void testAuditParsingDoesNotApplySetVar() {
+        ConnectContext ctx = new ConnectContext();
+        ctx.setDatabase("test");
+        ctx.setStatementContext(new StatementContext(ctx, null));
+        ctx.setThreadLocalInfo();
+        try {
+            SessionVariable session = ctx.getSessionVariable();
+            session.setQueryTimeoutS(1800);
+            session.setInsertTimeoutS(14400);
+            String hint = "/*+ SET_VAR(query_timeout=1, insert_timeout=1) */";
+            String[] sources = {
+                    "numbers(\"number\"=\"1\")",
+                    "S3('uri'='s3://bucket/data.parquet', 'format'='parquet', 
's3.secret_key'='test-secret')"
+            };
+            for (String source : sources) {
+                String sql = "INSERT INTO t SELECT " + hint + " * FROM " + 
source;
+                TreeMap<Pair<Integer, Integer>, String> replacements = new 
TreeMap<>(new Pair.PairComparator<>());
+                new NereidsParser().parseForEncryption(sql, replacements);
+                Assertions.assertEquals(1800, session.getQueryTimeoutS());
+                Assertions.assertEquals(14400, session.getInsertTimeoutS());
+                Assertions.assertFalse(session.getIsSingleSetVar());
+                
Assertions.assertTrue(session.getSessionOriginValue().isEmpty());
+                String masked = BaseViewInfo.rewriteSql(replacements, sql);
+                Assertions.assertTrue(masked.contains(hint));
+                Assertions.assertFalse(masked.contains("test-secret"));
+            }
+        } finally {
+            ConnectContext.remove();
+        }
+    }
+}
diff --git 
a/regression-test/suites/query_p0/session_variable/test_set_var_hint_restore.groovy
 
b/regression-test/suites/query_p0/session_variable/test_set_var_hint_restore.groovy
new file mode 100644
index 00000000000..52fd39e99c4
--- /dev/null
+++ 
b/regression-test/suites/query_p0/session_variable/test_set_var_hint_restore.groovy
@@ -0,0 +1,44 @@
+// 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_set_var_hint_restore") {
+    sql "DROP TABLE IF EXISTS test_set_var_hint_restore"
+    sql """
+        CREATE TABLE test_set_var_hint_restore (
+            k INT NOT NULL,
+            v BIGINT NOT NULL
+        ) ENGINE=OLAP
+        DUPLICATE KEY(k)
+        DISTRIBUTED BY HASH(k) BUCKETS 6
+        PROPERTIES ("replication_num"="1")
+    """
+
+    def timeoutsBeforeInsert = sql "SELECT @@query_timeout, @@insert_timeout"
+    test {
+        sql """
+            INSERT INTO test_set_var_hint_restore
+            SELECT /*+ SET_VAR(query_timeout=1, insert_timeout=1) */
+                   41, SUM(CRC32(CAST(number AS STRING)))
+            FROM numbers("number"="1000000000")
+        """
+        exception "timeout"
+    }
+
+    // Read immediately: another statement could restore values leaked by 
audit SQL parsing.
+    def timeoutsAfterInsert = sql "SELECT @@query_timeout, @@insert_timeout"
+    assertEquals(timeoutsBeforeInsert, timeoutsAfterInsert)
+}


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

Reply via email to