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

morrySnow 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 09a22aaf3bb [fix](variable) Track user variables in SQL cache during 
binding (#67787)
09a22aaf3bb is described below

commit 09a22aaf3bbe5628d42616f828f98d52253f48e9
Author: morrySnow <[email protected]>
AuthorDate: Fri Sep 11 13:29:08 2026 +0800

    [fix](variable) Track user variables in SQL cache during binding (#67787)
    
    ### What problem does this PR solve?
    
    Related PR: #62524
    
    Problem Summary:
    
    User-variable dependencies were registered in the SQL cache context only
    by the late `ReplaceVariableByLiteral` rewrite. Function binding unwraps
    a direct `Variable` argument to its real expression before that rewrite,
    so expressions such as `ABS(@v)` lost the variable dependency. After
    `@v` changed, the same SQL could therefore reuse a stale
    `PhysicalSqlCache` result and return the old value.
    
    This PR records the complete variable dependency while binding
    `UnboundVariable`, then directly returns its real expression. It removes
    the now-redundant `VariableToLiteral` / `ReplaceVariableByLiteral` path
    and the `ExpressionTrait` variable special case. It also moves the
    generated-column variable check to the parsed expression so variables
    inside functions remain rejected.
---
 .../doris/nereids/jobs/executor/Analyzer.java      | 12 ---
 .../nereids/rules/analysis/ExpressionAnalyzer.java |  7 +-
 .../nereids/rules/analysis/VariableToLiteral.java  | 40 ----------
 .../rules/expression/ExpressionRuleType.java       |  1 -
 .../expression/rules/ReplaceVariableByLiteral.java | 53 -------------
 .../expressions/functions/ExpressionTrait.java     | 29 +-------
 .../trees/plans/commands/info/CreateTableInfo.java |  8 +-
 .../apache/doris/nereids/util/ExpressionUtils.java |  8 +-
 .../rules/analysis/UserVariableAnalysisTest.java   | 28 +++++++
 .../expressions/functions/ExpressionTraitTest.java | 86 ----------------------
 .../fault_tolerance_nereids.groovy                 | 12 ++-
 .../query_p0/cache/parse_sql_from_sql_cache.groovy | 23 ++++++
 12 files changed, 75 insertions(+), 232 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java
index 8e4dc6c63e1..db6ed38ac41 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java
@@ -52,7 +52,6 @@ import 
org.apache.doris.nereids.rules.analysis.ProjectWithDistinctToAggregate;
 import org.apache.doris.nereids.rules.analysis.QualifyToFilter;
 import org.apache.doris.nereids.rules.analysis.ReplaceExpressionByChildOutput;
 import org.apache.doris.nereids.rules.analysis.SubqueryToApply;
-import org.apache.doris.nereids.rules.analysis.VariableToLiteral;
 import org.apache.doris.nereids.rules.rewrite.AdjustNullable;
 import org.apache.doris.nereids.rules.rewrite.MergeFilters;
 import org.apache.doris.nereids.rules.rewrite.SimplifyAggGroupBy;
@@ -168,17 +167,6 @@ public class Analyzer extends AbstractBatchJobExecutor {
                     // LogicalProject for normalize. This rule depends on 
FillUpMissingSlots to fill up slots.
                     new NormalizeRepeat()
             ),
-            // consider sql with user defined var @t_zone
-            // set @t_zone='GMT';
-            // SELECT
-            //     DATE_FORMAT(convert_tz(dt, time_zone, @t_zone),'%Y-%m-%d') 
day
-            // FROM
-            //     t
-            // GROUP BY
-            //     1;
-            // @t_zone must be replaced as 'GMT' before 
EliminateGroupByConstant and NormalizeAggregate rule.
-            // So need run VariableToLiteral rule before the two rules.
-            topDown(new VariableToLiteral()),
             // run CheckSearchUsage before CheckAnalysis to detect search() in 
GROUP BY before it gets optimized
             bottomUp(new CheckSearchUsage()),
             // run CheckAnalysis before EliminateGroupByConstant in order to 
report error message correctly like bellow
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
index ebace17bca2..f8fd0910ae1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
@@ -225,7 +225,12 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
      * 
********************************************************************************************
 */
     @Override
     public Expression visitUnboundVariable(UnboundVariable unboundVariable, 
ExpressionRewriteContext context) {
-        return resolveUnboundVariable(unboundVariable);
+        Variable variable = resolveUnboundVariable(unboundVariable);
+        if (wantToParseSqlFromSqlCache) {
+            getCascadesContext().getStatementContext().getSqlCacheContext()
+                    .ifPresent(sqlCacheContext -> 
sqlCacheContext.addUsedVariable(variable));
+        }
+        return variable.getRealExpression();
     }
 
     /** resolveUnboundVariable */
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/VariableToLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/VariableToLiteral.java
deleted file mode 100644
index 3f9be8ed677..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/VariableToLiteral.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.rules.analysis;
-
-import org.apache.doris.nereids.rules.expression.ExpressionRewrite;
-import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
-import org.apache.doris.nereids.rules.expression.ExpressionRewriteRule;
-import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
-import 
org.apache.doris.nereids.rules.expression.rules.ReplaceVariableByLiteral;
-
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-
-/**
- * replace Variable To Literal
- */
-public class VariableToLiteral extends ExpressionRewrite {
-    public static final List<ExpressionRewriteRule<ExpressionRewriteContext>> 
NORMALIZE_REWRITE_RULES =
-            ImmutableList.of(bottomUp(ReplaceVariableByLiteral.INSTANCE));
-
-    public VariableToLiteral() {
-        super(new ExpressionRuleExecutor(NORMALIZE_REWRITE_RULES));
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
index a3409004ca7..7d4494da26a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java
@@ -50,7 +50,6 @@ public enum ExpressionRuleType {
     NORMALIZE_BINARY_PREDICATES,
     NULL_SAFE_EQUAL_TO_EQUAL,
     PUSH_INTO_CASE_WHEN_BRANCH,
-    REPLACE_VARIABLE_BY_LITERAL,
     SIMPLIFY_ARITHMETIC_COMPARISON,
     SIMPLIFY_ARITHMETIC,
     SIMPLIFY_CAST,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ReplaceVariableByLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ReplaceVariableByLiteral.java
deleted file mode 100644
index e800bf790c5..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ReplaceVariableByLiteral.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.rules.expression.rules;
-
-import org.apache.doris.nereids.SqlCacheContext;
-import org.apache.doris.nereids.StatementContext;
-import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher;
-import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory;
-import org.apache.doris.nereids.rules.expression.ExpressionRuleType;
-import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.Variable;
-
-import com.google.common.collect.ImmutableList;
-
-import java.util.List;
-import java.util.Optional;
-
-/**
- * replace varaible to real expression
- */
-public class ReplaceVariableByLiteral implements ExpressionPatternRuleFactory {
-    public static ReplaceVariableByLiteral INSTANCE = new 
ReplaceVariableByLiteral();
-
-    @Override
-    public List<ExpressionPatternMatcher<? extends Expression>> buildRules() {
-        return ImmutableList.of(
-            matchesType(Variable.class).thenApply(ctx -> {
-                StatementContext statementContext = 
ctx.cascadesContext.getStatementContext();
-                Variable variable = ctx.expr;
-                Optional<SqlCacheContext> sqlCacheContext = 
statementContext.getSqlCacheContext();
-                if (sqlCacheContext.isPresent()) {
-                    sqlCacheContext.get().addUsedVariable(variable);
-                }
-                return variable.getRealExpression();
-            }).toRule(ExpressionRuleType.REPLACE_VARIABLE_BY_LITERAL)
-        );
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java
index f382964bcaf..8740a200cd7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java
@@ -21,7 +21,6 @@ import org.apache.doris.nereids.annotation.Developing;
 import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.Variable;
 import org.apache.doris.nereids.trees.expressions.VolatileExpression;
 import org.apache.doris.nereids.types.DataType;
 
@@ -52,38 +51,14 @@ public interface ExpressionTrait extends 
TreeNode<Expression> {
      * getArguments.
      */
     default List<Expression> getArguments() {
-        boolean hasVariableArg = false;
-        for (Expression arg : children()) {
-            if (arg instanceof Variable) {
-                hasVariableArg = true;
-                break;
-            }
-        }
-        if (hasVariableArg) {
-            ImmutableList.Builder<Expression> arguments = 
ImmutableList.builder();
-            for (Expression arg : children()) {
-                if (arg instanceof Variable) {
-                    arguments.add(((Variable) arg).getRealExpression());
-                } else {
-                    arguments.add(arg);
-                }
-            }
-            return arguments.build();
-        } else {
-            return children();
-        }
+        return children();
     }
 
     /**
      * getArgument.
      */
     default Expression getArgument(int index) {
-        Expression arg = child(index);
-        if (arg instanceof Variable) {
-            return ((Variable) arg).getRealExpression();
-        } else {
-            return arg;
-        }
+        return child(index);
     }
 
     default List<DataType> getArgumentsTypes() {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
index ac39d7256a7..69357d6f39a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
@@ -56,6 +56,7 @@ import org.apache.doris.nereids.CascadesContext;
 import org.apache.doris.nereids.analyzer.Scope;
 import org.apache.doris.nereids.analyzer.UnboundFunction;
 import org.apache.doris.nereids.analyzer.UnboundSlot;
+import org.apache.doris.nereids.analyzer.UnboundVariable;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.glue.translator.ExpressionTranslator;
 import org.apache.doris.nereids.glue.translator.PlanTranslatorContext;
@@ -66,7 +67,6 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.SubqueryExpr;
-import org.apache.doris.nereids.trees.expressions.Variable;
 import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
 import org.apache.doris.nereids.trees.expressions.functions.Udf;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.GroupingScalarFunction;
@@ -1209,6 +1209,8 @@ public class CreateTableInfo {
                 throw new AnalysisException("Generated column does not support 
subquery.");
             } else if (e instanceof Lambda) {
                 throw new AnalysisException("Generated column does not support 
lambda.");
+            } else if (e instanceof UnboundVariable) {
+                throw new AnalysisException("Generated column expression 
cannot contain variable.");
             }
         });
     }
@@ -1216,9 +1218,7 @@ public class CreateTableInfo {
     void checkExpressionInGeneratedColumn(Expression expr, ColumnDefinition 
column,
             Map<String, ColumnDefinition> nameToColumnDefinition) {
         expr.foreach(e -> {
-            if (e instanceof Variable) {
-                throw new AnalysisException("Generated column expression 
cannot contain variable.");
-            } else if (e instanceof Slot && 
nameToColumnDefinition.containsKey(((Slot) e).getName())) {
+            if (e instanceof Slot && 
nameToColumnDefinition.containsKey(((Slot) e).getName())) {
                 ColumnDefinition columnDefinition = 
nameToColumnDefinition.get(((Slot) e).getName());
                 if (columnDefinition.getAutoIncInitValue() != -1) {
                     throw new AnalysisException(
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
index 984b74372fb..00f5caa8364 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
@@ -29,11 +29,8 @@ import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.properties.DataTrait;
 import org.apache.doris.nereids.properties.PhysicalProperties;
 import org.apache.doris.nereids.rules.analysis.ExpressionAnalyzer;
-import org.apache.doris.nereids.rules.expression.ExpressionRewrite;
 import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
-import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
 import org.apache.doris.nereids.rules.expression.rules.FoldConstantRule;
-import 
org.apache.doris.nereids.rules.expression.rules.ReplaceVariableByLiteral;
 import 
org.apache.doris.nereids.rules.expression.rules.TrySimplifyPredicateWithMarkJoinSlot;
 import org.apache.doris.nereids.trees.SuperClassId;
 import org.apache.doris.nereids.trees.TreeNode;
@@ -1504,10 +1501,7 @@ public class ExpressionUtils {
             throw new UserException(expression + " must be constant value");
         }
         ExpressionRewriteContext context = new 
ExpressionRewriteContext(cascadesContext);
-        ExpressionRuleExecutor executor = new 
ExpressionRuleExecutor(ImmutableList.of(
-                
ExpressionRewrite.bottomUp(ReplaceVariableByLiteral.INSTANCE)));
-        Expression rewrittenExpression = executor.rewrite(analyzedExpr, 
context);
-        Expression foldExpression = 
FoldConstantRule.evaluate(rewrittenExpression, context);
+        Expression foldExpression = FoldConstantRule.evaluate(analyzedExpr, 
context);
         if (foldExpression instanceof Literal) {
             return (Literal) foldExpression;
         } else {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserVariableAnalysisTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserVariableAnalysisTest.java
index 3ba8bcf22ab..688569121ad 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserVariableAnalysisTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/UserVariableAnalysisTest.java
@@ -22,6 +22,12 @@ import org.apache.doris.analysis.IntLiteral;
 import org.apache.doris.analysis.LargeIntLiteral;
 import org.apache.doris.analysis.TimeStampNsLiteral;
 import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.analyzer.Scope;
+import org.apache.doris.nereids.analyzer.UnboundVariable;
+import org.apache.doris.nereids.analyzer.UnboundVariable.VariableType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Variable;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.trees.expressions.literal.TimestampTzLiteral;
 import org.apache.doris.nereids.types.BigIntType;
@@ -34,9 +40,12 @@ import org.apache.doris.nereids.types.TinyIntType;
 import org.apache.doris.nereids.util.MemoTestUtils;
 import org.apache.doris.qe.ConnectContext;
 
+import com.google.common.collect.ImmutableList;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import java.util.List;
+
 /** Tests for user variable handling in expression analysis. */
 public class UserVariableAnalysisTest {
 
@@ -84,4 +93,23 @@ public class UserVariableAnalysisTest {
         Assertions.assertEquals(TimeStampNsType.INSTANCE, 
literal.getDataType());
         Assertions.assertEquals("2024-02-29 12:34:56.123456789", 
literal.getStringValue());
     }
+
+    @Test
+    public void 
testBindUserVariableToRealExpressionAndRecordSqlCacheDependency() {
+        ConnectContext ctx = MemoTestUtils.createConnectContext();
+        ctx.setUserVar("v", new IntLiteral(42));
+        CascadesContext cascadesContext = 
MemoTestUtils.createCascadesContext(ctx, "select @v");
+        ExpressionAnalyzer analyzer = new ExpressionAnalyzer(null, new 
Scope(ImmutableList.of()),
+                cascadesContext, false, false);
+
+        Expression analyzed = analyzer.analyze(new UnboundVariable("v", 
VariableType.USER));
+
+        Assertions.assertInstanceOf(Literal.class, analyzed);
+        List<Variable> usedVariables = 
cascadesContext.getStatementContext().getSqlCacheContext()
+                .orElseThrow().getUsedVariables();
+        Assertions.assertEquals(1, usedVariables.size());
+        Assertions.assertEquals("v", usedVariables.get(0).getName());
+        Assertions.assertEquals(VariableType.USER, 
usedVariables.get(0).getType());
+        Assertions.assertEquals(analyzed, 
usedVariables.get(0).getRealExpression());
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTraitTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTraitTest.java
deleted file mode 100644
index 03a36c2c927..00000000000
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTraitTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// 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.trees.expressions.functions;
-
-import org.apache.doris.nereids.analyzer.UnboundVariable.VariableType;
-import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.Variable;
-import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
-import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
-import org.apache.doris.nereids.types.DataType;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-import java.util.List;
-
-/**
- * Tests for ExpressionTrait behaviors when children are `Variable`.
- */
-public class ExpressionTraitTest {
-
-    static class DummyFunction extends Expression {
-        protected DummyFunction(List<Expression> children) {
-            super(children);
-        }
-
-        protected DummyFunction(Expression... children) {
-            super(children);
-        }
-
-        @Override
-        public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-            return null;
-        }
-
-        @Override
-        public Expression withChildren(List<Expression> children) {
-            return new DummyFunction(children);
-        }
-
-        @Override
-        protected String computeToSql() {
-            return "dummy";
-        }
-
-        @Override
-        public boolean nullable() {
-            return false;
-        }
-    }
-
-    @Test
-    public void testVariable() {
-        IntegerLiteral lit = new IntegerLiteral(42);
-        Variable var = new Variable("v", VariableType.USER, lit);
-
-        DummyFunction func = new DummyFunction(var);
-
-        List<Expression> args = func.getArguments();
-        Assertions.assertEquals(1, args.size());
-        Assertions.assertEquals(lit, args.get(0));
-
-        Assertions.assertEquals(lit, func.getArgument(0));
-
-        List<DataType> types = func.getArgumentsTypes();
-        Assertions.assertEquals(1, types.size());
-        Assertions.assertEquals(lit.getDataType(), types.get(0));
-
-        Assertions.assertEquals(lit.getDataType(), func.getArgumentType(0));
-    }
-}
diff --git 
a/regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy
 
b/regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy
index 02409621bdc..62d73edb653 100644
--- 
a/regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy
+++ 
b/regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy
@@ -68,6 +68,16 @@ suite("test_generated_column_fault_tolerance_nereids") {
         exception "Generated column expression cannot contain variable."
     }
 
+    // Variables are resolved to literals during binding, so generated columns 
must reject them before binding.
+    test {
+        sql """
+        create table test_gen_col_var_in_function(a int, c int generated 
always as (abs(@myvar)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Generated column expression cannot contain variable."
+    }
+
     test {
         sql """
         create table test_gen_col_auto_increment(a bigint not null 
auto_increment, b int, c int as (a*b)) 
@@ -200,4 +210,4 @@ suite("test_generated_column_fault_tolerance_nereids") {
     }
 
 
-}
\ No newline at end of file
+}
diff --git 
a/regression-test/suites/query_p0/cache/parse_sql_from_sql_cache.groovy 
b/regression-test/suites/query_p0/cache/parse_sql_from_sql_cache.groovy
index c12ccf50273..c90b755a48c 100644
--- a/regression-test/suites/query_p0/cache/parse_sql_from_sql_cache.groovy
+++ b/regression-test/suites/query_p0/cache/parse_sql_from_sql_cache.groovy
@@ -633,6 +633,29 @@ suite("parse_sql_from_sql_cache") {
                         def result1 = sql "select @custom_variable from 
test_use_plan_cache17 where id = 1 and value = 1"
                         assertTrue(result1.size() == 1 && 
result1[0][0].toString().toInteger() == 10)
 
+                        def functionVariableSql = "select 
abs(@custom_variable_in_function) " +
+                                "from test_use_plan_cache17 where id = 1 and 
value = 1"
+                        sql "set @custom_variable_in_function=-10"
+                        assertNoCache functionVariableSql
+                        def functionResult = sql functionVariableSql
+                        assertTrue(functionResult.size() == 1
+                                && functionResult[0][0].toString().toInteger() 
== 10)
+                        assertHasCache functionVariableSql
+
+                        sql "set @custom_variable_in_function=-20"
+                        assertNoCache functionVariableSql
+                        functionResult = sql functionVariableSql
+                        assertTrue(functionResult.size() == 1
+                                && functionResult[0][0].toString().toInteger() 
== 20)
+                        assertHasCache functionVariableSql
+
+                        // switch back to the original value and reuse its 
value-aware cache
+                        sql "set @custom_variable_in_function=-10"
+                        assertHasCache functionVariableSql
+                        functionResult = sql functionVariableSql
+                        assertTrue(functionResult.size() == 1
+                                && functionResult[0][0].toString().toInteger() 
== 10)
+
                         sql "set @custom_variable2=1"
                         assertNoCache "select * from test_use_plan_cache17 
where id = @custom_variable2 and value = 1"
                         def res = sql "select * from test_use_plan_cache17 
where id = @custom_variable2 and value = 1"


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

Reply via email to