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

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


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 7e9fb782675 branch-3.1: [refactor](Nereids) remove ListQuery 
expression #50894 (#57709)
7e9fb782675 is described below

commit 7e9fb782675ad1340e96809de3c6004ce75a47eb
Author: morrySnow <[email protected]>
AuthorDate: Thu Nov 6 11:57:46 2025 +0800

    branch-3.1: [refactor](Nereids) remove ListQuery expression #50894 (#57709)
    
    picked from #50894
---
 .../doris/nereids/parser/LogicalPlanBuilder.java   |  3 +-
 .../nereids/rules/analysis/CheckAfterBind.java     |  2 +-
 .../nereids/rules/analysis/ExpressionAnalyzer.java | 19 +++---
 .../nereids/rules/analysis/SubExprAnalyzer.java    |  5 +-
 .../nereids/rules/analysis/SubqueryToApply.java    | 15 ++---
 .../nereids/trees/copier/ExpressionDeepCopier.java | 16 +----
 .../doris/nereids/trees/expressions/Exists.java    |  7 +-
 .../nereids/trees/expressions/InSubquery.java      | 73 ++++++++-------------
 .../doris/nereids/trees/expressions/ListQuery.java | 76 ----------------------
 .../nereids/trees/expressions/SubqueryExpr.java    | 26 +++-----
 .../expressions/visitor/ExpressionVisitor.java     |  5 --
 .../doris/nereids/util/TypeCoercionUtils.java      |  8 +--
 .../subquery/test_subquery_in_project.groovy       |  5 ++
 13 files changed, 69 insertions(+), 191 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index a01b73ec9af..ce8fb4314f1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -275,7 +275,6 @@ import org.apache.doris.nereids.trees.expressions.IsNull;
 import org.apache.doris.nereids.trees.expressions.LessThan;
 import org.apache.doris.nereids.trees.expressions.LessThanEqual;
 import org.apache.doris.nereids.trees.expressions.Like;
-import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.MatchAll;
 import org.apache.doris.nereids.trees.expressions.MatchAny;
 import org.apache.doris.nereids.trees.expressions.MatchPhrase;
@@ -3388,7 +3387,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
                     } else {
                         outExpression = new InSubquery(
                                 valueExpression,
-                                new ListQuery(typedVisit(ctx.query())),
+                                typedVisit(ctx.query()),
                                 ctx.NOT() != null
                         );
                     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAfterBind.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAfterBind.java
index e90e868a510..e0395668e7d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAfterBind.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckAfterBind.java
@@ -56,7 +56,7 @@ public class CheckAfterBind implements AnalysisRuleFactory {
         Set<Expression> havingConjuncts = having.getConjuncts();
         for (Expression predicate : havingConjuncts) {
             if (predicate instanceof InSubquery) {
-                if (((InSubquery) 
predicate).getListQuery().getDataType().isObjectType()) {
+                if (((InSubquery) 
predicate).getSubqueryOutput().getDataType().isObjectType()) {
                     throw new AnalysisException(Type.OnlyMetricTypeErrorMsg);
                 }
             }
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 51fee5c1bba..c2dce7f591e 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
@@ -55,7 +55,6 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.InPredicate;
 import org.apache.doris.nereids.trees.expressions.InSubquery;
 import org.apache.doris.nereids.trees.expressions.IntegralDivide;
-import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.Match;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Not;
@@ -747,17 +746,21 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
 
         // compareExpr already analyze when invoke super.visitInSubquery
         Expression newCompareExpr = inSubquery.getCompareExpr();
-        // but ListQuery does not analyze
-        Expression newListQuery = inSubquery.getListQuery().accept(this, 
context);
+        Optional<Expression> typeCoercionExpr = 
inSubquery.getTypeCoercionExpr();
 
-        ComparisonPredicate afterTypeCoercion = (ComparisonPredicate) 
TypeCoercionUtils.processComparisonPredicate(
-                new EqualTo(newCompareExpr, newListQuery));
-        if (newListQuery.getDataType().isBitmapType()) {
+        // ATTN: support a trick usage of Doris: integral type in bitmap union 
column. For example:
+        //   SELECT 1 IN (SELECT bitmap_empty() FROM DUAL);
+        if (inSubquery.getSubqueryOutput().getDataType().isBitmapType()) {
             if (!newCompareExpr.getDataType().isBigIntType()) {
                 newCompareExpr = new Cast(newCompareExpr, BigIntType.INSTANCE);
             }
         } else {
+            ComparisonPredicate afterTypeCoercion = (ComparisonPredicate) 
TypeCoercionUtils.processComparisonPredicate(
+                    new EqualTo(newCompareExpr, 
inSubquery.getSubqueryOutput()));
             newCompareExpr = afterTypeCoercion.left();
+            if (afterTypeCoercion.right() != inSubquery.getSubqueryOutput()) {
+                typeCoercionExpr = Optional.of(afterTypeCoercion.right());
+            }
         }
         if (getScope().getOuterScope().isPresent()) {
             Scope outerScope = getScope().getOuterScope().get();
@@ -769,8 +772,8 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
                 }
             }
         }
-        return new InSubquery(newCompareExpr, (ListQuery) 
afterTypeCoercion.right(),
-                inSubquery.getCorrelateSlots(), ((ListQuery) 
afterTypeCoercion.right()).getTypeCoercionExpr(),
+        return new InSubquery(newCompareExpr, inSubquery.getQueryPlan(),
+                inSubquery.getCorrelateSlots(), typeCoercionExpr,
                 inSubquery.isNot());
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java
index e0d809c9f1a..fb0b742f444 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java
@@ -24,7 +24,6 @@ import org.apache.doris.nereids.trees.expressions.Alias;
 import org.apache.doris.nereids.trees.expressions.Exists;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.InSubquery;
-import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.Not;
 import org.apache.doris.nereids.trees.expressions.ScalarSubquery;
 import org.apache.doris.nereids.trees.expressions.Slot;
@@ -75,7 +74,7 @@ class SubExprAnalyzer<T> extends DefaultExpressionRewriter<T> 
{
                     new Exists(((Exists) child).getQueryPlan(), true), 
context);
         } else if (child instanceof InSubquery) {
             return visitInSubquery(new InSubquery(((InSubquery) 
child).getCompareExpr(),
-                    ((InSubquery) child).getListQuery(), true), context);
+                    ((InSubquery) child).getQueryPlan(), true), context);
         }
         return visit(not, context);
     }
@@ -114,7 +113,7 @@ class SubExprAnalyzer<T> extends 
DefaultExpressionRewriter<T> {
 
         return new InSubquery(
                 expr.getCompareExpr().accept(this, context),
-                new ListQuery(analyzedResult.getLogicalPlan()),
+                analyzedResult.getLogicalPlan(),
                 analyzedResult.getCorrelatedSlots(), expr.isNot());
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java
index c0a62e0c991..2e41a88c62f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java
@@ -25,7 +25,6 @@ import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
 import 
org.apache.doris.nereids.rules.expression.rules.TrySimplifyPredicateWithMarkJoinSlot;
-import org.apache.doris.nereids.trees.TreeNode;
 import org.apache.doris.nereids.trees.expressions.Alias;
 import org.apache.doris.nereids.trees.expressions.CompoundPredicate;
 import org.apache.doris.nereids.trees.expressions.Exists;
@@ -33,7 +32,6 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.InSubquery;
 import org.apache.doris.nereids.trees.expressions.IsNull;
 import org.apache.doris.nereids.trees.expressions.LessThanEqual;
-import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Or;
@@ -226,7 +224,7 @@ public class SubqueryToApply implements AnalysisRuleFactory 
{
                     }
 
                     ImmutableList<Set<SubqueryExpr>> subqueryExprsList = 
subqueryConjuncts.stream()
-                            .<Set<SubqueryExpr>>map(e -> 
e.collect(SubqueryToApply::canConvertToSupply))
+                            .<Set<SubqueryExpr>>map(e -> 
e.collect(SubqueryExpr.class::isInstance))
                             .collect(ImmutableList.toImmutableList());
                     ImmutableList.Builder<Expression> newConjuncts = new 
ImmutableList.Builder<>();
                     LogicalPlan applyPlan;
@@ -286,16 +284,11 @@ public class SubqueryToApply implements 
AnalysisRuleFactory {
         );
     }
 
-    private static boolean canConvertToSupply(TreeNode<Expression> expression) 
{
-        // The subquery except ListQuery can be converted to Supply
-        return expression instanceof SubqueryExpr && !(expression instanceof 
ListQuery);
-    }
-
     private static boolean isValidSubqueryConjunct(Expression expression) {
         // only support 1 subquery expr in the expression
         // don't support expression like subquery1 or subquery2
         return expression
-                .collectToList(SubqueryToApply::canConvertToSupply)
+                .collectToList(SubqueryExpr.class::isInstance)
                 .size() == 1;
     }
 
@@ -322,7 +315,7 @@ public class SubqueryToApply implements AnalysisRuleFactory 
{
         Set<Slot> rightOutputSlots = rightChild.getOutputSet();
         for (int i = 0; i < size; ++i) {
             Expression expression = subqueryConjuncts.get(i);
-            List<SubqueryExpr> subqueryExprs = 
expression.collectToList(SubqueryToApply::canConvertToSupply);
+            List<SubqueryExpr> subqueryExprs = 
expression.collectToList(SubqueryExpr.class::isInstance);
             RelatedInfo relatedInfo = RelatedInfo.UnSupported;
             if (subqueryExprs.size() == 1) {
                 SubqueryExpr subqueryExpr = subqueryExprs.get(0);
@@ -748,7 +741,7 @@ public class SubqueryToApply implements AnalysisRuleFactory 
{
         boolean hasSubqueryExpr = false;
         ImmutableList.Builder<Set<SubqueryExpr>> subqueryExprsListBuilder = 
ImmutableList.builder();
         for (Expression expression : exprs) {
-            Set<SubqueryExpr> subqueries = 
expression.collect(SubqueryToApply::canConvertToSupply);
+            Set<SubqueryExpr> subqueries = 
expression.collect(SubqueryExpr.class::isInstance);
             hasSubqueryExpr |= !subqueries.isEmpty();
             subqueryExprsListBuilder.add(subqueries);
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/ExpressionDeepCopier.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/ExpressionDeepCopier.java
index 60a5603f9a2..db9f4306f16 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/ExpressionDeepCopier.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/ExpressionDeepCopier.java
@@ -23,7 +23,6 @@ import org.apache.doris.nereids.trees.expressions.Exists;
 import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.InSubquery;
-import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.ScalarSubquery;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
@@ -131,27 +130,16 @@ public class ExpressionDeepCopier extends 
DefaultExpressionRewriter<DeepCopierCo
         return new Exists(logicalPlan, correlateSlots, typeCoercionExpr, 
exists.isNot());
     }
 
-    @Override
-    public Expression visitListQuery(ListQuery listQuery, DeepCopierContext 
context) {
-        LogicalPlan logicalPlan = 
LogicalPlanDeepCopier.INSTANCE.deepCopy(listQuery.getQueryPlan(), context);
-        List<Slot> correlateSlots = listQuery.getCorrelateSlots().stream()
-                .map(s -> (Slot) s.accept(this, context))
-                .collect(Collectors.toList());
-        Optional<Expression> typeCoercionExpr = listQuery.getTypeCoercionExpr()
-                .map(c -> c.accept(this, context));
-        return new ListQuery(logicalPlan, correlateSlots, typeCoercionExpr);
-    }
-
     @Override
     public Expression visitInSubquery(InSubquery in, DeepCopierContext 
context) {
+        LogicalPlan logicalPlan = 
LogicalPlanDeepCopier.INSTANCE.deepCopy(in.getQueryPlan(), context);
         Expression compareExpr = in.getCompareExpr().accept(this, context);
         List<Slot> correlateSlots = in.getCorrelateSlots().stream()
                 .map(s -> (Slot) s.accept(this, context))
                 .collect(Collectors.toList());
         Optional<Expression> typeCoercionExpr = in.getTypeCoercionExpr()
                 .map(c -> c.accept(this, context));
-        ListQuery listQuery = (ListQuery) in.getListQuery().accept(this, 
context);
-        return new InSubquery(compareExpr, listQuery, correlateSlots, 
typeCoercionExpr, in.isNot());
+        return new InSubquery(compareExpr, logicalPlan, correlateSlots, 
typeCoercionExpr, in.isNot());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java
index dc5a348bec6..c95882a71e2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Exists.java
@@ -18,12 +18,14 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DataType;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 import java.util.Objects;
@@ -32,13 +34,12 @@ import java.util.Optional;
 /**
  * Exists subquery expression.
  */
-public class Exists extends SubqueryExpr {
+public class Exists extends SubqueryExpr implements LeafExpression {
 
     private final boolean isNot;
 
     public Exists(LogicalPlan subquery, boolean isNot) {
-        super(Objects.requireNonNull(subquery, "subquery can not be null"));
-        this.isNot = isNot;
+        this(subquery, ImmutableList.of(), Optional.empty(), isNot);
     }
 
     public Exists(LogicalPlan subquery, List<Slot> correlateSlots, boolean 
isNot) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java
index 89b51e37465..6b77700a4c8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/InSubquery.java
@@ -18,13 +18,14 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.expressions.shape.UnaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DataType;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 import java.util.Objects;
@@ -33,20 +34,15 @@ import java.util.Optional;
 /**
  * In predicate expression.
  */
-public class InSubquery extends SubqueryExpr {
+public class InSubquery extends SubqueryExpr implements UnaryExpression {
 
-    private final Expression compareExpr;
-    private final ListQuery listQuery;
     private final boolean isNot;
 
-    public InSubquery(Expression compareExpression, ListQuery listQuery, 
boolean isNot) {
-        super(Objects.requireNonNull(listQuery.getQueryPlan(), "subquery can 
not be null"));
-        this.compareExpr = Objects.requireNonNull(compareExpression, 
"compareExpr can not be null");
-        this.listQuery = Objects.requireNonNull(listQuery, "listQuery can not 
be null");
-        this.isNot = isNot;
+    public InSubquery(Expression compareExpression, LogicalPlan listQuery, 
boolean isNot) {
+        this(compareExpression, listQuery, ImmutableList.of(), 
Optional.empty(), isNot);
     }
 
-    public InSubquery(Expression compareExpr, ListQuery listQuery, List<Slot> 
correlateSlots, boolean isNot) {
+    public InSubquery(Expression compareExpr, LogicalPlan listQuery, 
List<Slot> correlateSlots, boolean isNot) {
         this(compareExpr, listQuery, correlateSlots, Optional.empty(), isNot);
     }
 
@@ -54,15 +50,11 @@ public class InSubquery extends SubqueryExpr {
      * InSubquery Constructor.
      */
     public InSubquery(Expression compareExpr,
-                      ListQuery listQuery,
-                      List<Slot> correlateSlots,
-                      Optional<Expression> typeCoercionExpr,
-                      boolean isNot) {
-        super(Objects.requireNonNull(listQuery.getQueryPlan(), "subquery can 
not be null"),
-                Objects.requireNonNull(correlateSlots, "correlateSlots can not 
be null"),
-                typeCoercionExpr);
-        this.compareExpr = Objects.requireNonNull(compareExpr, "compareExpr 
can not be null");
-        this.listQuery = Objects.requireNonNull(listQuery, "listQuery can not 
be null");
+            LogicalPlan listQuery,
+            List<Slot> correlateSlots,
+            Optional<Expression> typeCoercionExpr,
+            boolean isNot) {
+        super(listQuery, correlateSlots, typeCoercionExpr, compareExpr);
         this.isNot = isNot;
     }
 
@@ -73,17 +65,17 @@ public class InSubquery extends SubqueryExpr {
 
     @Override
     public boolean nullable() throws UnboundException {
-        return super.nullable() || this.compareExpr.nullable();
+        return super.nullable() || this.child().nullable();
     }
 
     @Override
     public String computeToSql() {
-        return this.compareExpr.toSql() + " IN (" + super.computeToSql() + ")";
+        return this.child().toSql() + " IN (" + super.computeToSql() + ")";
     }
 
     @Override
     public String toString() {
-        return this.compareExpr + " IN (INSUBQUERY) " + super.toString();
+        return this.child() + " IN (INSUBQUERY) " + super.toString();
     }
 
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
@@ -91,27 +83,17 @@ public class InSubquery extends SubqueryExpr {
     }
 
     public Expression getCompareExpr() {
-        return this.compareExpr;
+        return this.child();
     }
 
     public boolean isNot() {
         return isNot;
     }
 
-    public ListQuery getListQuery() {
-        return listQuery;
-    }
-
     @Override
     public InSubquery withChildren(List<Expression> children) {
-        Preconditions.checkArgument(children.size() == 2);
-        Preconditions.checkArgument(children.get(1) instanceof ListQuery);
-        return new InSubquery(children.get(0), (ListQuery) children.get(1), 
correlateSlots, typeCoercionExpr, isNot);
-    }
-
-    @Override
-    public List<Expression> children() {
-        return Lists.newArrayList(compareExpr, listQuery);
+        Preconditions.checkArgument(children.size() == 1);
+        return new InSubquery(children.get(0), queryPlan, correlateSlots, 
typeCoercionExpr, isNot);
     }
 
     @Override
@@ -119,29 +101,28 @@ public class InSubquery extends SubqueryExpr {
         if (!super.equals(o)) {
             return false;
         }
-        InSubquery inSubquery = (InSubquery) o;
-        return super.equals(inSubquery)
-                && Objects.equals(this.compareExpr, 
inSubquery.getCompareExpr())
-                && Objects.equals(this.listQuery, inSubquery.listQuery)
-                && this.isNot == inSubquery.isNot;
+        InSubquery other = (InSubquery) o;
+        return super.equals(other)
+                && Objects.equals(this.child(), other.getCompareExpr())
+                && this.isNot == other.isNot;
     }
 
     @Override
     public int computeHashCode() {
-        return Objects.hash(this.compareExpr, this.listQuery, this.isNot);
+        return Objects.hash(super.computeHashCode(), this.child(), this.isNot);
     }
 
     @Override
     public Expression withTypeCoercion(DataType dataType) {
-        return new InSubquery(compareExpr, listQuery, correlateSlots,
-            dataType == listQuery.queryPlan.getOutput().get(0).getDataType()
-                ? Optional.of(listQuery.queryPlan.getOutput().get(0))
-                : Optional.of(new Cast(listQuery.queryPlan.getOutput().get(0), 
dataType)),
+        return new InSubquery(child(), queryPlan, correlateSlots,
+            dataType.equals(queryPlan.getOutput().get(0).getDataType())
+                ? Optional.of(queryPlan.getOutput().get(0))
+                : Optional.of(new Cast(queryPlan.getOutput().get(0), 
dataType)),
             isNot);
     }
 
     @Override
     public InSubquery withSubquery(LogicalPlan subquery) {
-        return new InSubquery(compareExpr, listQuery.withSubquery(subquery), 
correlateSlots, typeCoercionExpr, isNot);
+        return new InSubquery(child(), subquery, correlateSlots, 
typeCoercionExpr, isNot);
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ListQuery.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ListQuery.java
deleted file mode 100644
index 16dade740b9..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ListQuery.java
+++ /dev/null
@@ -1,76 +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;
-
-import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
-import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
-import org.apache.doris.nereids.types.DataType;
-
-import com.google.common.base.Preconditions;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-
-/**
- * Encapsulate LogicalPlan as Expression.
- * just for subquery.
- */
-public class ListQuery extends SubqueryExpr {
-
-    public ListQuery(LogicalPlan subquery) {
-        super(Objects.requireNonNull(subquery, "subquery can not be null"));
-    }
-
-    public ListQuery(LogicalPlan subquery, List<Slot> correlateSlots, 
Optional<Expression> typeCoercionExpr) {
-        super(subquery, correlateSlots, typeCoercionExpr);
-    }
-
-    @Override
-    public DataType getDataType() {
-        Preconditions.checkArgument(queryPlan.getOutput().size() == 1);
-        return 
typeCoercionExpr.orElse(queryPlan.getOutput().get(0)).getDataType();
-    }
-
-    @Override
-    public String computeToSql() {
-        return " (LISTQUERY) " + super.computeToSql();
-    }
-
-    @Override
-    public String toString() {
-        return " (LISTQUERY) " + super.toString();
-    }
-
-    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitListQuery(this, context);
-    }
-
-    @Override
-    public Expression withTypeCoercion(DataType dataType) {
-        return new ListQuery(queryPlan, correlateSlots,
-                dataType == queryPlan.getOutput().get(0).getDataType()
-                    ? Optional.of(queryPlan.getOutput().get(0))
-                    : Optional.of(new Cast(queryPlan.getOutput().get(0), 
dataType)));
-    }
-
-    @Override
-    public ListQuery withSubquery(LogicalPlan subquery) {
-        return new ListQuery(subquery, correlateSlots, typeCoercionExpr);
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java
index 2011aa9607d..b0b59cf9148 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java
@@ -18,7 +18,6 @@
 package org.apache.doris.nereids.trees.expressions;
 
 import org.apache.doris.nereids.exceptions.UnboundException;
-import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.types.DataType;
@@ -33,21 +32,23 @@ import java.util.Optional;
 /**
  * Subquery Expression.
  */
-public abstract class SubqueryExpr extends Expression implements 
LeafExpression {
+public abstract class SubqueryExpr extends Expression {
 
     protected final LogicalPlan queryPlan;
     protected final List<Slot> correlateSlots;
     protected final Optional<Expression> typeCoercionExpr;
 
-    protected SubqueryExpr(LogicalPlan subquery) {
+    protected SubqueryExpr(LogicalPlan subquery, List<Slot> correlateSlots,
+            Optional<Expression> typeCoercionExpr) {
         super(ImmutableList.of());
         this.queryPlan = Objects.requireNonNull(subquery, "subquery can not be 
null");
-        this.correlateSlots = ImmutableList.of();
-        this.typeCoercionExpr = Optional.empty();
+        this.correlateSlots = ImmutableList.copyOf(correlateSlots);
+        this.typeCoercionExpr = typeCoercionExpr;
     }
 
-    protected SubqueryExpr(LogicalPlan subquery, List<Slot> correlateSlots, 
Optional<Expression> typeCoercionExpr) {
-        super(ImmutableList.of());
+    protected SubqueryExpr(LogicalPlan subquery, List<Slot> correlateSlots,
+            Optional<Expression> typeCoercionExpr, Expression child) {
+        super(ImmutableList.of(Objects.requireNonNull(child, "child can not be 
null")));
         this.queryPlan = Objects.requireNonNull(subquery, "subquery can not be 
null");
         this.correlateSlots = ImmutableList.copyOf(correlateSlots);
         this.typeCoercionExpr = typeCoercionExpr;
@@ -65,10 +66,6 @@ public abstract class SubqueryExpr extends Expression 
implements LeafExpression
         return typeCoercionExpr.orElseGet(() -> queryPlan.getOutput().get(0));
     }
 
-    public Expression getSubqueryOutput(LogicalPlan queryPlan) {
-        return typeCoercionExpr.orElseGet(() -> queryPlan.getOutput().get(0));
-    }
-
     @Override
     public DataType getDataType() throws UnboundException {
         throw new UnboundException("getDataType");
@@ -115,10 +112,7 @@ public abstract class SubqueryExpr extends Expression 
implements LeafExpression
 
     @Override
     public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
+        if (!super.equals(o)) {
             return false;
         }
         SubqueryExpr other = (SubqueryExpr) o;
@@ -129,7 +123,7 @@ public abstract class SubqueryExpr extends Expression 
implements LeafExpression
 
     @Override
     public int computeHashCode() {
-        return Objects.hash(queryPlan, correlateSlots, typeCoercionExpr);
+        return Objects.hash(super.computeHashCode(), queryPlan, 
correlateSlots, typeCoercionExpr);
     }
 
     public List<Slot> getOutput() {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
index 406d0835610..c159589e6db 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
@@ -52,7 +52,6 @@ import 
org.apache.doris.nereids.trees.expressions.IntegralDivide;
 import org.apache.doris.nereids.trees.expressions.IsNull;
 import org.apache.doris.nereids.trees.expressions.LessThan;
 import org.apache.doris.nereids.trees.expressions.LessThanEqual;
-import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference;
 import org.apache.doris.nereids.trees.expressions.Match;
 import org.apache.doris.nereids.trees.expressions.MatchAll;
@@ -429,10 +428,6 @@ public abstract class ExpressionVisitor<R, C>
         return visitSubqueryExpr(scalar, context);
     }
 
-    public R visitListQuery(ListQuery listQuery, C context) {
-        return visitSubqueryExpr(listQuery, context);
-    }
-
     public R visitGroupingScalarFunction(GroupingScalarFunction 
groupingScalarFunction, C context) {
         return visit(groupingScalarFunction, context);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
index fd98f2e02bb..0efaca36630 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java
@@ -450,7 +450,7 @@ public class TypeCoercionUtils {
     public static Expression castIfNotSameType(Expression input, DataType 
targetType) {
         if (input.isNullLiteral()) {
             return new NullLiteral(targetType);
-        } else if (input.getDataType().equals(targetType) || 
isSubqueryAndDataTypeIsBitmap(input)
+        } else if (input.getDataType().equals(targetType)
                 || (input.getDataType().isStringLikeType()) && 
targetType.isStringLikeType()) {
             return input;
         } else {
@@ -473,7 +473,7 @@ public class TypeCoercionUtils {
     public static Expression castIfNotSameTypeStrict(Expression input, 
DataType targetType) {
         if (input.isNullLiteral()) {
             return new NullLiteral(targetType);
-        } else if (input.getDataType().equals(targetType) || 
isSubqueryAndDataTypeIsBitmap(input)) {
+        } else if (input.getDataType().equals(targetType)) {
             return input;
         } else {
             checkCanCastTo(input.getDataType(), targetType);
@@ -481,10 +481,6 @@ public class TypeCoercionUtils {
         }
     }
 
-    private static boolean isSubqueryAndDataTypeIsBitmap(Expression input) {
-        return input instanceof SubqueryExpr && 
input.getDataType().isBitmapType();
-    }
-
     private static boolean canCastTo(DataType input, DataType target) {
         return Type.canCastTo(input.toCatalogDataType(), 
target.toCatalogDataType());
     }
diff --git 
a/regression-test/suites/nereids_p0/subquery/test_subquery_in_project.groovy 
b/regression-test/suites/nereids_p0/subquery/test_subquery_in_project.groovy
index 32802dbb7a1..e078081b079 100644
--- a/regression-test/suites/nereids_p0/subquery/test_subquery_in_project.groovy
+++ b/regression-test/suites/nereids_p0/subquery/test_subquery_in_project.groovy
@@ -41,6 +41,11 @@ suite("test_subquery_in_project") {
 
     sql """ insert into test_sql values (1,'2020-09-09',2,3);"""
 
+    // in subquery with normalize agg, cast(abs(age) as int) should extract 
from upper project.
+    sql """
+        SELECT CAST(abs(age) AS int) IN (SELECT age FROM test_sql) FROM 
test_sql GROUP BY CAST(abs(age) AS int);
+    """
+
     qt_sql1 """
         select (select age from test_sql) col from test_sql order by col; 
     """


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

Reply via email to