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 5a7454e8ab0 [fix](Nerieds) using join bugs (#48030)
5a7454e8ab0 is described below

commit 5a7454e8ab0452967ed6eb9f735b4e5dffac05a0
Author: morrySnow <zhangwen...@selectdb.com>
AuthorDate: Fri Feb 21 20:17:42 2025 +0800

    [fix](Nerieds) using join bugs (#48030)
    
    ### What problem does this PR solve?
    
    Related PR: #15311
    
    Problem Summary:
    
    1. select * should only return using columns from left relation
    2. bind expression on using join should not do distinct slot by name on
    using join's output
    
    
    ### Release note
    
    change the return columns when select asterisk from using join.
    before return key column from both side. now only return key column
    from left side.
---
 .../org/apache/doris/nereids/analyzer/Scope.java   |  40 +++-
 .../doris/nereids/parser/LogicalPlanBuilder.java   |   5 +-
 .../nereids/properties/LogicalProperties.java      |  37 +++-
 .../nereids/rules/analysis/BindExpression.java     |  44 +++--
 .../nereids/rules/analysis/ExpressionAnalyzer.java |  10 +-
 .../nereids/rules/analysis/SubExprAnalyzer.java    |   3 +-
 .../doris/nereids/trees/plans/AbstractPlan.java    |   9 +-
 .../nereids/trees/plans/DiffOutputInAsterisk.java  |  39 ++++
 .../apache/doris/nereids/trees/plans/FakePlan.java |   2 +-
 .../org/apache/doris/nereids/trees/plans/Plan.java |   8 +
 .../trees/plans/logical/LogicalAssertNumRows.java  |   9 +-
 .../nereids/trees/plans/logical/LogicalFilter.java |   9 +-
 .../trees/plans/logical/LogicalGenerate.java       |  12 +-
 .../nereids/trees/plans/logical/LogicalJoin.java   | 111 +++++++----
 .../trees/plans/logical/LogicalSelectHint.java     |   8 +-
 .../trees/plans/logical/LogicalSubQueryAlias.java  |  15 +-
 .../trees/plans/logical/LogicalUsingJoin.java      | 149 ++++++++++++++
 .../nereids/trees/plans/logical/UsingJoin.java     | 217 ---------------------
 .../trees/plans/physical/PhysicalSqlCache.java     |   2 +-
 .../org/apache/doris/nereids/util/JoinUtils.java   |  36 +++-
 .../org/apache/doris/nereids/util/PlanUtils.java   |  24 +++
 .../rules/analysis/BindSlotReferenceTest.java      |  19 +-
 .../data/nereids_p0/join/test_join2.out            | Bin 1907 -> 1697 bytes
 .../data/nereids_p0/join/test_join3.out            | Bin 408 -> 351 bytes
 .../data/nereids_syntax_p0/test_join3.out          | Bin 408 -> 351 bytes
 .../data/nereids_syntax_p0/using_join.out          | Bin 127 -> 2193 bytes
 regression-test/data/query_p0/join/test_join2.out  | Bin 1907 -> 1697 bytes
 regression-test/data/query_p0/join/test_join3.out  | Bin 408 -> 351 bytes
 .../suites/nereids_p0/join/test_join2.groovy       |  20 +-
 .../suites/nereids_syntax_p0/using_join.groovy     | 150 ++++++++++----
 30 files changed, 608 insertions(+), 370 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java
index 7c77c680ff2..cb74698a62b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java
@@ -61,27 +61,44 @@ public class Scope {
 
     private final Optional<Scope> outerScope;
     private final List<Slot> slots;
+    private final List<Slot> asteriskSlots;
     private final Set<Slot> correlatedSlots;
     private final boolean buildNameToSlot;
     private final Supplier<ListMultimap<String, Slot>> nameToSlot;
+    private final Supplier<ListMultimap<String, Slot>> nameToAsteriskSlot;
 
-    public Scope(List<? extends Slot> slots) {
+    public Scope(List<Slot> slots) {
         this(Optional.empty(), slots);
     }
 
+    public Scope(Optional<Scope> outerScope, List<Slot> slots) {
+        this(outerScope, slots, slots);
+    }
+
+    public Scope(List<Slot> slots, List<Slot> asteriskSlots) {
+        this(Optional.empty(), slots, asteriskSlots);
+    }
+
     /** Scope */
-    public Scope(Optional<Scope> outerScope, List<? extends Slot> slots) {
+    public Scope(Optional<Scope> outerScope, List<Slot> slots, List<Slot> 
asteriskSlots) {
         this.outerScope = Objects.requireNonNull(outerScope, "outerScope can 
not be null");
         this.slots = Utils.fastToImmutableList(Objects.requireNonNull(slots, 
"slots can not be null"));
         this.correlatedSlots = Sets.newLinkedHashSet();
         this.buildNameToSlot = slots.size() > 500;
         this.nameToSlot = buildNameToSlot ? 
Suppliers.memoize(this::buildNameToSlot) : null;
+        this.nameToAsteriskSlot = buildNameToSlot ? 
Suppliers.memoize(this::buildNameToAsteriskSlot) : null;
+        this.asteriskSlots = Utils.fastToImmutableList(
+                Objects.requireNonNull(asteriskSlots, "asteriskSlots can not 
be null"));
     }
 
     public List<Slot> getSlots() {
         return slots;
     }
 
+    public List<Slot> getAsteriskSlots() {
+        return asteriskSlots;
+    }
+
     public Optional<Scope> getOuterScope() {
         return outerScope;
     }
@@ -91,17 +108,18 @@ public class Scope {
     }
 
     /** findSlotIgnoreCase */
-    public List<Slot> findSlotIgnoreCase(String slotName) {
+    public List<Slot> findSlotIgnoreCase(String slotName, boolean all) {
+        List<Slot> slots = all ? this.slots : this.asteriskSlots;
+        Supplier<ListMultimap<String, Slot>> nameToSlot = all ? 
this.nameToSlot : this.nameToAsteriskSlot;
         if (!buildNameToSlot) {
-            Object[] array = new Object[slots.size()];
+            Slot[] array = new Slot[slots.size()];
             int filterIndex = 0;
-            for (int i = 0; i < slots.size(); i++) {
-                Slot slot = slots.get(i);
+            for (Slot slot : slots) {
                 if (slot.getName().equalsIgnoreCase(slotName)) {
                     array[filterIndex++] = slot;
                 }
             }
-            return (List) Arrays.asList(array).subList(0, filterIndex);
+            return Arrays.asList(array).subList(0, filterIndex);
         } else {
             return nameToSlot.get().get(slotName.toUpperCase(Locale.ROOT));
         }
@@ -114,4 +132,12 @@ public class Scope {
         }
         return map;
     }
+
+    private ListMultimap<String, Slot> buildNameToAsteriskSlot() {
+        ListMultimap<String, Slot> map = 
LinkedListMultimap.create(asteriskSlots.size());
+        for (Slot slot : asteriskSlots) {
+            map.put(slot.getName().toUpperCase(Locale.ROOT), slot);
+        }
+        return map;
+    }
 }
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 c0ff406794a..0b56260042a 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
@@ -786,7 +786,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalSink;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
 import org.apache.doris.nereids.trees.plans.logical.LogicalUnion;
-import org.apache.doris.nereids.trees.plans.logical.UsingJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalUsingJoin;
 import org.apache.doris.nereids.types.AggStateType;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.BigIntType;
@@ -3604,8 +3604,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
                         last,
                         plan(join.relationPrimary()), null);
             } else {
-                last = new UsingJoin<>(joinType, last,
-                        plan(join.relationPrimary()), ImmutableList.of(), ids, 
distributeHint);
+                last = new LogicalUsingJoin<>(joinType, last, 
plan(join.relationPrimary()), ids, distributeHint);
 
             }
             if (distributeHint.distributeType != DistributeType.NONE
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java
index 3ac5a38c914..6383918ced7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java
@@ -37,27 +37,38 @@ import java.util.Set;
  */
 public class LogicalProperties {
     protected final Supplier<List<Slot>> outputSupplier;
-    protected final Supplier<List<Id>> outputExprIdsSupplier;
+    protected final Supplier<List<Id<?>>> outputExprIdsSupplier;
     protected final Supplier<Set<Slot>> outputSetSupplier;
     protected final Supplier<Map<Slot, Slot>> outputMapSupplier;
     protected final Supplier<Set<ExprId>> outputExprIdSetSupplier;
+    protected final Supplier<List<Slot>> asteriskOutputSupplier;
     protected final Supplier<DataTrait> dataTraitSupplier;
     private Integer hashCode = null;
 
+    /**
+     * constructor when output same as asterisk's output.
+     */
+    public LogicalProperties(Supplier<List<Slot>> outputSupplier, 
Supplier<DataTrait> dataTraitSupplier) {
+        // the second parameters should be null to reuse memorized output 
supplier
+        this(outputSupplier, null, dataTraitSupplier);
+    }
+
     /**
      * constructor of LogicalProperties.
      *
      * @param outputSupplier provide the output. Supplier can lazy compute 
output without
      *                       throw exception for which children have 
UnboundRelation
+     * @param asteriskOutputSupplier provide the output when do select *.
+     * @param dataTraitSupplier provide the data trait.
      */
-    public LogicalProperties(Supplier<List<Slot>> outputSupplier,
+    public LogicalProperties(Supplier<List<Slot>> outputSupplier, 
Supplier<List<Slot>> asteriskOutputSupplier,
             Supplier<DataTrait> dataTraitSupplier) {
         this.outputSupplier = Suppliers.memoize(
                 Objects.requireNonNull(outputSupplier, "outputSupplier can not 
be null")
         );
         this.outputExprIdsSupplier = Suppliers.memoize(() -> {
             List<Slot> output = this.outputSupplier.get();
-            ImmutableList.Builder<Id> exprIdSet
+            ImmutableList.Builder<Id<?>> exprIdSet
                     = ImmutableList.builderWithExpectedSize(output.size());
             for (Slot slot : output) {
                 exprIdSet.add(slot.getExprId());
@@ -65,7 +76,7 @@ public class LogicalProperties {
             return exprIdSet.build();
         });
         this.outputSetSupplier = Suppliers.memoize(() -> {
-            List<Slot> output = outputSupplier.get();
+            List<Slot> output = this.outputSupplier.get();
             ImmutableSet.Builder<Slot> slots = 
ImmutableSet.builderWithExpectedSize(output.size());
             for (Slot slot : output) {
                 slots.add(slot);
@@ -73,7 +84,7 @@ public class LogicalProperties {
             return slots.build();
         });
         this.outputMapSupplier = Suppliers.memoize(() -> {
-            Set<Slot> slots = outputSetSupplier.get();
+            Set<Slot> slots = this.outputSetSupplier.get();
             ImmutableMap.Builder<Slot, Slot> map = 
ImmutableMap.builderWithExpectedSize(slots.size());
             for (Slot slot : slots) {
                 map.put(slot, slot);
@@ -89,6 +100,9 @@ public class LogicalProperties {
             }
             return exprIdSet.build();
         });
+        this.asteriskOutputSupplier = asteriskOutputSupplier == null ? 
this.outputSupplier : Suppliers.memoize(
+                Objects.requireNonNull(asteriskOutputSupplier, 
"asteriskOutputSupplier can not be null")
+        );
         this.dataTraitSupplier = Suppliers.memoize(
                 Objects.requireNonNull(dataTraitSupplier, "Data Trait can not 
be null")
         );
@@ -110,12 +124,16 @@ public class LogicalProperties {
         return outputExprIdSetSupplier.get();
     }
 
-    public DataTrait getTrait() {
-        return dataTraitSupplier.get();
+    public List<Id<?>> getOutputExprIds() {
+        return outputExprIdsSupplier.get();
     }
 
-    public List<Id> getOutputExprIds() {
-        return outputExprIdsSupplier.get();
+    public List<Slot> getAsteriskOutput() {
+        return asteriskOutputSupplier.get();
+    }
+
+    public DataTrait getTrait() {
+        return dataTraitSupplier.get();
     }
 
     @Override
@@ -126,6 +144,7 @@ public class LogicalProperties {
                 + "\noutputSetSupplier=" + outputSetSupplier.get()
                 + "\noutputMapSupplier=" + outputMapSupplier.get()
                 + "\noutputExprIdSetSupplier=" + outputExprIdSetSupplier.get()
+                + "\nasteriskOutputSupplier=" + asteriskOutputSupplier.get()
                 + "\nhashCode=" + hashCode
                 + '}';
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java
index c308a1e7e79..029d44b8ed7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java
@@ -21,7 +21,6 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.FunctionRegistry;
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.CascadesContext;
-import org.apache.doris.nereids.NereidsPlanner;
 import org.apache.doris.nereids.SqlCacheContext;
 import org.apache.doris.nereids.StatementContext;
 import org.apache.doris.nereids.analyzer.MappingSlot;
@@ -88,7 +87,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalSink;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
 import org.apache.doris.nereids.trees.plans.logical.LogicalTVFRelation;
-import org.apache.doris.nereids.trees.plans.logical.UsingJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalUsingJoin;
 import org.apache.doris.nereids.trees.plans.visitor.InferPlanOutputAlias;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.StructField;
@@ -130,7 +129,7 @@ import java.util.stream.Collectors;
  */
 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
 public class BindExpression implements AnalysisRuleFactory {
-    public static final Logger LOG = 
LogManager.getLogger(NereidsPlanner.class);
+    public static final Logger LOG = 
LogManager.getLogger(BindExpression.class);
 
     @Override
     public List<Rule> buildRules() {
@@ -161,7 +160,7 @@ public class BindExpression implements AnalysisRuleFactory {
                 logicalFilter().thenApply(this::bindFilter)
             ),
             RuleType.BINDING_USING_JOIN_SLOT.build(
-                usingJoin().thenApply(this::bindUsingJoin)
+                logicalUsingJoin().thenApply(this::bindUsingJoin)
             ),
             RuleType.BINDING_JOIN_SLOT.build(
                 logicalJoin().thenApply(this::bindJoin)
@@ -546,7 +545,7 @@ public class BindExpression implements AnalysisRuleFactory {
 
         return new LogicalJoin<>(join.getJoinType(),
                 hashJoinConjuncts.build(), otherJoinConjuncts.build(),
-                join.getDistributeHint(), join.getMarkJoinSlotReference(),
+                join.getDistributeHint(), join.getMarkJoinSlotReference(), 
join.getExceptAsteriskOutputs(),
                 join.children(), null);
     }
 
@@ -591,16 +590,17 @@ public class BindExpression implements 
AnalysisRuleFactory {
         }
     }
 
-    private LogicalJoin<Plan, Plan> 
bindUsingJoin(MatchingContext<UsingJoin<Plan, Plan>> ctx) {
-        UsingJoin<Plan, Plan> using = ctx.root;
+    private LogicalPlan bindUsingJoin(MatchingContext<LogicalUsingJoin<Plan, 
Plan>> ctx) {
+        LogicalUsingJoin<Plan, Plan> using = ctx.root;
         CascadesContext cascadesContext = ctx.cascadesContext;
-        List<Expression> unboundHashJoinConjunct = 
using.getHashJoinConjuncts();
+        List<Expression> unboundHashJoinConjunct = using.getUsingSlots();
 
-        Scope leftScope = toScope(cascadesContext, 
ExpressionUtils.distinctSlotByName(using.left().getOutput()));
-        Scope rightScope = toScope(cascadesContext, 
ExpressionUtils.distinctSlotByName(using.right().getOutput()));
+        Scope leftScope = toScope(cascadesContext, using.left().getOutput(), 
using.left().getAsteriskOutput());
+        Scope rightScope = toScope(cascadesContext, using.right().getOutput(), 
using.right().getAsteriskOutput());
         ExpressionRewriteContext rewriteContext = new 
ExpressionRewriteContext(cascadesContext);
 
         Builder<Expression> hashEqExprs = 
ImmutableList.builderWithExpectedSize(unboundHashJoinConjunct.size());
+        List<Slot> rightConjunctsSlots = Lists.newArrayList();
         for (Expression usingColumn : unboundHashJoinConjunct) {
             ExpressionAnalyzer leftExprAnalyzer = new ExpressionAnalyzer(
                     using, leftScope, cascadesContext, true, false);
@@ -609,13 +609,14 @@ public class BindExpression implements 
AnalysisRuleFactory {
             ExpressionAnalyzer rightExprAnalyzer = new ExpressionAnalyzer(
                     using, rightScope, cascadesContext, true, false);
             Expression usingRightSlot = rightExprAnalyzer.analyze(usingColumn, 
rewriteContext);
+            rightConjunctsSlots.add((Slot) usingRightSlot);
             hashEqExprs.add(new EqualTo(usingLeftSlot, usingRightSlot));
         }
 
         return new LogicalJoin<>(
                 using.getJoinType() == JoinType.CROSS_JOIN ? 
JoinType.INNER_JOIN : using.getJoinType(),
-                hashEqExprs.build(), using.getOtherJoinConjuncts(),
-                using.getDistributeHint(), using.getMarkJoinSlotReference(),
+                hashEqExprs.build(), ImmutableList.of(),
+                using.getDistributeHint(), Optional.empty(), 
rightConjunctsSlots,
                 using.children(), null);
     }
 
@@ -1035,11 +1036,11 @@ public class BindExpression implements 
AnalysisRuleFactory {
     private Supplier<Scope> buildAggOutputScopeWithoutAggFun(
             List<? extends NamedExpression> boundAggOutput, CascadesContext 
cascadesContext) {
         return Suppliers.memoize(() -> {
-            Builder<MappingSlot> nonAggFunOutput = 
ImmutableList.builderWithExpectedSize(boundAggOutput.size());
+            Builder<Slot> nonAggFunOutput = 
ImmutableList.builderWithExpectedSize(boundAggOutput.size());
             for (NamedExpression output : boundAggOutput) {
                 if (!output.containsType(AggregateFunction.class)) {
                     Slot outputSlot = output.toSlot();
-                    MappingSlot mappingSlot = new MappingSlot(outputSlot,
+                    Slot mappingSlot = new MappingSlot(outputSlot,
                             output instanceof Alias ? output.child(0) : 
output);
                     nonAggFunOutput.add(mappingSlot);
                 }
@@ -1226,7 +1227,7 @@ public class BindExpression implements 
AnalysisRuleFactory {
         return expression;
     }
 
-    private Scope toScope(CascadesContext cascadesContext, List<? extends 
Slot> slots) {
+    private Scope toScope(CascadesContext cascadesContext, List<Slot> slots) {
         Optional<Scope> outerScope = cascadesContext.getOuterScope();
         if (outerScope.isPresent()) {
             return new Scope(outerScope, slots);
@@ -1235,11 +1236,20 @@ public class BindExpression implements 
AnalysisRuleFactory {
         }
     }
 
+    private Scope toScope(CascadesContext cascadesContext, List<Slot> slots, 
List<Slot> asteriskSlots) {
+        Optional<Scope> outerScope = cascadesContext.getOuterScope();
+        if (outerScope.isPresent()) {
+            return new Scope(outerScope, slots, asteriskSlots);
+        } else {
+            return new Scope(slots, asteriskSlots);
+        }
+    }
+
     private SimpleExprAnalyzer buildSimpleExprAnalyzer(
             Plan currentPlan, CascadesContext cascadesContext, List<Plan> 
children,
             boolean enableExactMatch, boolean bindSlotInOuterScope) {
-        List<Slot> childrenOutputs = 
PlanUtils.fastGetChildrenOutputs(children);
-        Scope scope = toScope(cascadesContext, childrenOutputs);
+        Scope scope = toScope(cascadesContext, 
PlanUtils.fastGetChildrenOutputs(children),
+                PlanUtils.fastGetChildrenAsteriskOutputs(children));
         return buildSimpleExprAnalyzer(currentPlan, cascadesContext, scope, 
enableExactMatch, bindSlotInOuterScope);
     }
 
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 05d3804df2b..d7f0f637250 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
@@ -345,7 +345,7 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
     public Expression visitUnboundStar(UnboundStar unboundStar, 
ExpressionRewriteContext context) {
         List<String> qualifier = unboundStar.getQualifier();
         boolean showHidden = Util.showHiddenColumns();
-        List<Slot> slots = getScope().getSlots()
+        List<Slot> slots = getScope().getAsteriskSlots()
                 .stream()
                 .filter(slot -> !(slot instanceof SlotReference)
                         || (((SlotReference) slot).isVisible()) || showHidden)
@@ -920,7 +920,7 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
     private List<Slot> bindSingleSlotByName(String name, Scope scope) {
         int namePartSize = 1;
         Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1);
-        for (Slot boundSlot : scope.findSlotIgnoreCase(name)) {
+        for (Slot boundSlot : scope.findSlotIgnoreCase(name, false)) {
             if (!shouldBindSlotBy(namePartSize, boundSlot)) {
                 continue;
             }
@@ -933,7 +933,7 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
     private List<Slot> bindSingleSlotByTable(String table, String name, Scope 
scope) {
         int namePartSize = 2;
         Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1);
-        for (Slot boundSlot : scope.findSlotIgnoreCase(name)) {
+        for (Slot boundSlot : scope.findSlotIgnoreCase(name, true)) {
             if (!shouldBindSlotBy(namePartSize, boundSlot)) {
                 continue;
             }
@@ -951,7 +951,7 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
     private List<Slot> bindSingleSlotByDb(String db, String table, String 
name, Scope scope) {
         int namePartSize = 3;
         Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1);
-        for (Slot boundSlot : scope.findSlotIgnoreCase(name)) {
+        for (Slot boundSlot : scope.findSlotIgnoreCase(name, true)) {
             if (!shouldBindSlotBy(namePartSize, boundSlot)) {
                 continue;
             }
@@ -970,7 +970,7 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
     private List<Slot> bindSingleSlotByCatalog(String catalog, String db, 
String table, String name, Scope scope) {
         int namePartSize = 4;
         Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1);
-        for (Slot boundSlot : scope.findSlotIgnoreCase(name)) {
+        for (Slot boundSlot : scope.findSlotIgnoreCase(name, true)) {
             if (!shouldBindSlotBy(namePartSize, boundSlot)) {
                 continue;
             }
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 9a70ce24afb..3d6ff95f809 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
@@ -206,7 +206,8 @@ class SubExprAnalyzer<T> extends 
DefaultExpressionRewriter<T> {
                 cascadesContext, expr.getQueryPlan(), 
cascadesContext.getCteContext());
         // don't use `getScope()` because we only need 
`getScope().getOuterScope()` and `getScope().getSlots()`
         // otherwise unexpected errors may occur
-        Scope subqueryScope = new Scope(getScope().getOuterScope(), 
getScope().getSlots());
+        Scope subqueryScope = new Scope(getScope().getOuterScope(),
+                getScope().getSlots(), getScope().getAsteriskSlots());
         subqueryContext.setOuterScope(subqueryScope);
         subqueryContext.newAnalyzer().analyze();
         return new AnalyzedResult((LogicalPlan) 
subqueryContext.getRewritePlan(),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
index 5b08bdd2e5b..0436f1c3182 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
@@ -19,7 +19,6 @@ package org.apache.doris.nereids.trees.plans;
 
 import org.apache.doris.nereids.analyzer.Unbound;
 import org.apache.doris.nereids.memo.GroupExpression;
-import org.apache.doris.nereids.properties.DataTrait;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.properties.UnboundLogicalProperties;
 import org.apache.doris.nereids.trees.AbstractTreeNode;
@@ -200,9 +199,11 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
         if (hasUnboundChild || hasUnboundExpression()) {
             return UnboundLogicalProperties.INSTANCE;
         } else {
-            Supplier<List<Slot>> outputSupplier = 
Suppliers.memoize(this::computeOutput);
-            Supplier<DataTrait> fdSupplier = () -> computeDataTrait();
-            return new LogicalProperties(outputSupplier, fdSupplier);
+            if (this instanceof DiffOutputInAsterisk) {
+                return new LogicalProperties(this::computeOutput, 
this::computeAsteriskOutput, this::computeDataTrait);
+            } else {
+                return new LogicalProperties(this::computeOutput, 
this::computeDataTrait);
+            }
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/DiffOutputInAsterisk.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/DiffOutputInAsterisk.java
new file mode 100644
index 00000000000..ddce0226e64
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/DiffOutputInAsterisk.java
@@ -0,0 +1,39 @@
+// 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.plans;
+
+import org.apache.doris.nereids.trees.expressions.Slot;
+
+import java.util.List;
+
+/**
+ * trait for plan that output in Asterisk does not contain all slot which 
could output, such as, UsingJoin.
+ */
+public interface DiffOutputInAsterisk extends Plan {
+    @Override
+    default List<Slot> getAsteriskOutput() {
+        boolean outputMayDiff = false;
+        for (Plan child : children()) {
+            if (child instanceof DiffOutputInAsterisk) {
+                outputMayDiff = true;
+                break;
+            }
+        }
+        return outputMayDiff ? getLogicalProperties().getAsteriskOutput() : 
getLogicalProperties().getOutput();
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java
index 39c546cdb19..ae17a9719bf 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java
@@ -82,7 +82,7 @@ public class FakePlan implements Plan, 
BlockFuncDepsPropagation {
 
     @Override
     public LogicalProperties getLogicalProperties() {
-        return new LogicalProperties(ArrayList::new, () -> 
DataTrait.EMPTY_TRAIT);
+        return new LogicalProperties(ImmutableList::of, () -> 
DataTrait.EMPTY_TRAIT);
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
index 402ad046d91..5336cf5478c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
@@ -98,6 +98,10 @@ public interface Plan extends TreeNode<Plan> {
      */
     List<Slot> getOutput();
 
+    default List<Slot> getAsteriskOutput() {
+        return getOutput();
+    }
+
     /**
      * Get output slot set of the plan.
      */
@@ -159,6 +163,10 @@ public interface Plan extends TreeNode<Plan> {
         throw new IllegalStateException("Not support compute output for " + 
getClass().getName());
     }
 
+    default List<Slot> computeAsteriskOutput() {
+        throw new IllegalStateException("Not support compute output for " + 
getClass().getName());
+    }
+
     /**
      * Get the input relation ids set of the plan.
      * @return The result is collected from all inputs relations
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
index ca2a9ff7c7d..f78b41d7bdd 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
@@ -25,6 +25,7 @@ import 
org.apache.doris.nereids.trees.expressions.AssertNumRowsElement;
 import 
org.apache.doris.nereids.trees.expressions.AssertNumRowsElement.Assertion;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
@@ -44,7 +45,8 @@ import java.util.stream.Collectors;
  * If the number of rows is more than the desired num of rows, the query will 
be cancelled.
  * The cancelled reason will be reported by Backend and displayed back to the 
user.
  */
-public class LogicalAssertNumRows<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE> {
+public class LogicalAssertNumRows<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE>
+        implements DiffOutputInAsterisk {
 
     private final AssertNumRowsElement assertNumRowsElement;
 
@@ -120,6 +122,11 @@ public class LogicalAssertNumRows<CHILD_TYPE extends Plan> 
extends LogicalUnary<
         return child().getOutput().stream().map(o -> 
o.withNullable(true)).collect(Collectors.toList());
     }
 
+    @Override
+    public List<Slot> computeAsteriskOutput() {
+        return child().getAsteriskOutput().stream().map(o -> 
o.withNullable(true)).collect(Collectors.toList());
+    }
+
     @Override
     public void computeUnique(Builder builder) {
         if (assertNumRowsElement.getDesiredNumOfRows() == 1
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
index efd7e90c136..d502f8c5a2a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
@@ -24,6 +24,7 @@ import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SubqueryExpr;
+import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.algebra.Filter;
@@ -47,7 +48,8 @@ import java.util.stream.Stream;
 /**
  * Logical filter plan.
  */
-public class LogicalFilter<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE> implements Filter {
+public class LogicalFilter<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE>
+        implements Filter, DiffOutputInAsterisk {
 
     private final Set<Expression> conjuncts;
 
@@ -86,6 +88,11 @@ public class LogicalFilter<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_T
         return child().getOutput();
     }
 
+    @Override
+    public List<Slot> computeAsteriskOutput() {
+        return child().getAsteriskOutput();
+    }
+
     @Override
     public String toString() {
         return Utils.toSqlString("LogicalFilter[" + id.asInt() + "]",
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java
index 3dc0577779c..6856f4a129d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java
@@ -24,6 +24,7 @@ import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.functions.Function;
+import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.algebra.Generate;
@@ -41,7 +42,8 @@ import java.util.Optional;
 /**
  * plan for table generator, the statement like: SELECT * FROM tbl LATERAL 
VIEW EXPLODE(c1) g as (gc1);
  */
-public class LogicalGenerate<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE> implements Generate {
+public class LogicalGenerate<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE>
+        implements Generate, DiffOutputInAsterisk {
 
     private final List<Function> generators;
     private final List<Slot> generatorOutput;
@@ -128,6 +130,14 @@ public class LogicalGenerate<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHILD
                 .build();
     }
 
+    @Override
+    public List<Slot> computeAsteriskOutput() {
+        return ImmutableList.<Slot>builder()
+                .addAll(child().getAsteriskOutput())
+                .addAll(generatorOutput)
+                .build();
+    }
+
     @Override
     public String toString() {
         return Utils.toSqlString("LogicalGenerate",
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
index c583360c3d8..fe4f1eed64f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
@@ -30,6 +30,7 @@ import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference;
 import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk;
 import org.apache.doris.nereids.trees.plans.DistributeType;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -60,12 +61,13 @@ import javax.annotation.Nullable;
  * Logical join plan.
  */
 public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE 
extends Plan>
-        extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements 
Join {
+        extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements 
Join, DiffOutputInAsterisk {
 
     private final JoinType joinType;
     private final List<Expression> otherJoinConjuncts;
     private final List<Expression> hashJoinConjuncts;
     private final List<Expression> markJoinConjuncts;
+    private final List<Slot> exceptAsteriskOutputs;
 
     // When the predicate condition contains subqueries and disjunctions, the 
join will be marked as MarkJoin.
     private final Optional<MarkJoinSlotReference> markJoinSlotReference;
@@ -134,6 +136,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
                 markJoinSlotReference, Optional.empty(), Optional.empty(), 
children, otherJoinReorderContext);
     }
 
+    public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts,
+            List<Expression> otherJoinConjuncts, DistributeHint hint,
+            Optional<MarkJoinSlotReference> markJoinSlotReference, List<Slot> 
exceptAsteriskOutputs,
+            List<Plan> children, JoinReorderContext otherJoinReorderContext) {
+        this(joinType, hashJoinConjuncts, otherJoinConjuncts, 
ExpressionUtils.EMPTY_CONDITION, hint,
+                markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), children, 
otherJoinReorderContext);
+    }
+
     public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts,
                        List<Expression> otherJoinConjuncts, List<Expression> 
markJoinConjuncts, DistributeHint hint,
                        Optional<MarkJoinSlotReference> markJoinSlotReference, 
List<Plan> children,
@@ -148,6 +159,18 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
             Optional<GroupExpression> groupExpression,
             Optional<LogicalProperties> logicalProperties, List<Plan> children,
             JoinReorderContext joinReorderContext) {
+        this(joinType, hashJoinConjuncts, otherJoinConjuncts, 
markJoinConjuncts, hint,
+                markJoinSlotReference, ImmutableList.of(),
+                groupExpression, logicalProperties, children, 
joinReorderContext);
+    }
+
+    private LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts,
+            List<Expression> otherJoinConjuncts, List<Expression> 
markJoinConjuncts,
+            DistributeHint hint, Optional<MarkJoinSlotReference> 
markJoinSlotReference,
+            List<Slot> exceptAsteriskOutputs,
+            Optional<GroupExpression> groupExpression,
+            Optional<LogicalProperties> logicalProperties, List<Plan> children,
+            JoinReorderContext joinReorderContext) {
         // Just use in withXXX method. Don't need check/copyOf()
         super(PlanType.LOGICAL_JOIN, groupExpression, logicalProperties, 
children);
         this.joinType = Objects.requireNonNull(joinType, "joinType can not be 
null");
@@ -159,6 +182,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
             this.joinReorderContext.copyFrom(joinReorderContext);
         }
         this.markJoinSlotReference = markJoinSlotReference;
+        this.exceptAsteriskOutputs = exceptAsteriskOutputs;
     }
 
     public LogicalJoin<? extends Plan, ? extends Plan> swap() {
@@ -257,6 +281,23 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
                 .build();
     }
 
+    @Override
+    public List<Slot> computeAsteriskOutput() {
+        List<Slot> output = 
Lists.newArrayList(JoinUtils.getJoinOutput(joinType, left(), right(), true));
+        if (isMarkJoin()) {
+            output.add(markJoinSlotReference.get());
+        }
+        output.removeAll(exceptAsteriskOutputs);
+        return output;
+    }
+
+    @Override
+    public List<Slot> getAsteriskOutput() {
+        boolean outputIsDiff = !exceptAsteriskOutputs.isEmpty();
+        return outputIsDiff ? getLogicalProperties().getAsteriskOutput()
+                : DiffOutputInAsterisk.super.getAsteriskOutput();
+    }
+
     @Override
     public String toString() {
         List<Object> args = Lists.newArrayList(
@@ -286,12 +327,14 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
                 && hashJoinConjuncts.equals(that.hashJoinConjuncts)
                 && otherJoinConjuncts.equals(that.otherJoinConjuncts)
                 && markJoinConjuncts.equals(that.markJoinConjuncts)
+                && exceptAsteriskOutputs.equals(that.exceptAsteriskOutputs)
                 && Objects.equals(markJoinSlotReference, 
that.markJoinSlotReference);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(joinType, hashJoinConjuncts, otherJoinConjuncts, 
markJoinConjuncts, markJoinSlotReference);
+        return Objects.hash(joinType, hashJoinConjuncts, otherJoinConjuncts,
+                markJoinConjuncts, markJoinSlotReference, 
exceptAsteriskOutputs);
     }
 
     @Override
@@ -312,6 +355,10 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
         return markJoinSlotReference;
     }
 
+    public List<Slot> getExceptAsteriskOutputs() {
+        return exceptAsteriskOutputs;
+    }
+
     public long getBitmap() {
         return bitmap;
     }
@@ -334,15 +381,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
     public LogicalJoin<Plan, Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 2);
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(), children,
-                joinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), children, 
joinReorderContext);
     }
 
     @Override
     public LogicalJoin<Plan, Plan> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, groupExpression, 
Optional.of(getLogicalProperties()),
-                children, joinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                groupExpression, Optional.of(getLogicalProperties()), 
children, joinReorderContext);
     }
 
     @Override
@@ -350,15 +397,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
             Optional<LogicalProperties> logicalProperties, List<Plan> 
children) {
         Preconditions.checkArgument(children.size() == 2);
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, groupExpression, 
logicalProperties, children,
-                joinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                groupExpression, logicalProperties, children, 
joinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withChildrenNoContext(Plan left, Plan right,
                                                          JoinReorderContext 
otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                ImmutableList.of(left, right), otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), ImmutableList.of(left, 
right), otherJoinReorderContext);
     }
 
     /**
@@ -367,61 +414,59 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
     public LogicalJoin<Plan, Plan> withJoinConjuncts(List<Expression> 
hashJoinConjuncts,
             List<Expression> otherJoinConjuncts, JoinReorderContext 
otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                children, otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), children, 
otherJoinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withJoinConjuncts(List<Expression> 
hashJoinConjuncts,
-                                                     List<Expression> 
otherJoinConjuncts,
-                                                     List<Expression> 
markJoinConjuncts,
-                                                     JoinReorderContext 
otherJoinReorderContext) {
+            List<Expression> otherJoinConjuncts, List<Expression> 
markJoinConjuncts,
+            JoinReorderContext otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.of(getLogicalProperties()),
-                children, otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.of(getLogicalProperties()), 
children, otherJoinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withHashJoinConjunctsAndChildren(
             List<Expression> hashJoinConjuncts, Plan left, Plan right, 
JoinReorderContext otherJoinReorderContext) {
         Preconditions.checkArgument(children.size() == 2);
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                ImmutableList.of(left, right), otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), ImmutableList.of(left, 
right), otherJoinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withConjunctsChildren(List<Expression> 
hashJoinConjuncts,
             List<Expression> otherJoinConjuncts, Plan left, Plan right, 
JoinReorderContext otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                ImmutableList.of(left, right), otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), ImmutableList.of(left, 
right), otherJoinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withConjunctsChildren(List<Expression> 
hashJoinConjuncts,
-                                                         List<Expression> 
otherJoinConjuncts,
-                                                         List<Expression> 
markJoinConjuncts, Plan left, Plan right,
-                                                         JoinReorderContext 
otherJoinReorderContext) {
+            List<Expression> otherJoinConjuncts, List<Expression> 
markJoinConjuncts, Plan left, Plan right,
+            JoinReorderContext otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                ImmutableList.of(left, right), otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), ImmutableList.of(left, 
right), otherJoinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withJoinType(JoinType joinType) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, groupExpression, 
Optional.of(getLogicalProperties()),
-                children, joinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                groupExpression, Optional.of(getLogicalProperties()), 
children, joinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withJoinTypeAndContext(JoinType joinType,
             JoinReorderContext otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                children, otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), children, 
otherJoinReorderContext);
     }
 
     public LogicalJoin<Plan, Plan> withTypeChildren(JoinType joinType, Plan 
left, Plan right,
-                                                    JoinReorderContext 
otherJoinReorderContext) {
+            JoinReorderContext otherJoinReorderContext) {
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinConjuncts, markJoinConjuncts,
-                hint, markJoinSlotReference, Optional.empty(), 
Optional.empty(),
-                ImmutableList.of(left, right), otherJoinReorderContext);
+                hint, markJoinSlotReference, exceptAsteriskOutputs,
+                Optional.empty(), Optional.empty(), ImmutableList.of(left, 
right), otherJoinReorderContext);
     }
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
index a33e2194131..10b67a84f4e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
@@ -23,6 +23,7 @@ import org.apache.doris.nereids.properties.SelectHint;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.BlockFuncDepsPropagation;
+import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
@@ -40,7 +41,7 @@ import java.util.stream.Collectors;
  * e.g. LogicalSelectHint (set_var(query_timeout='1800', 
exec_mem_limit='2147483648'))
  */
 public class LogicalSelectHint<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE>
-        implements BlockFuncDepsPropagation {
+        implements BlockFuncDepsPropagation, DiffOutputInAsterisk {
 
     private final ImmutableList<SelectHint> hints;
 
@@ -113,6 +114,11 @@ public class LogicalSelectHint<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHI
         return child().getOutput();
     }
 
+    @Override
+    public List<Slot> computeAsteriskOutput() {
+        return child().getAsteriskOutput();
+    }
+
     @Override
     public String toString() {
         String hintStr = this.hints
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
index 331ceda3159..adedc0343a8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.properties.DataTrait;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.RelationId;
@@ -47,7 +48,8 @@ import java.util.Set;
  *
  * @param <CHILD_TYPE> param
  */
-public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE> {
+public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYPE>
+        implements DiffOutputInAsterisk {
 
     protected RelationId relationId;
     private final List<String> qualifier;
@@ -79,7 +81,16 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> 
extends LogicalUnary<
 
     @Override
     public List<Slot> computeOutput() {
-        List<Slot> childOutput = child().getOutput();
+        return computeOutputInternal(false);
+    }
+
+    @Override
+    public List<Slot> computeAsteriskOutput() {
+        return computeOutputInternal(true);
+    }
+
+    private List<Slot> computeOutputInternal(boolean asteriskOutput) {
+        List<Slot> childOutput = asteriskOutput ? child().getAsteriskOutput() 
: child().getOutput();
         List<String> columnAliases = 
this.columnAliases.orElseGet(ImmutableList::of);
         ImmutableList.Builder<Slot> currentOutput = ImmutableList.builder();
         for (int i = 0; i < childOutput.size(); i++) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUsingJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUsingJoin.java
new file mode 100644
index 00000000000..1d2b3c077df
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUsingJoin.java
@@ -0,0 +1,149 @@
+// 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.plans.logical;
+
+import org.apache.doris.nereids.hint.DistributeHint;
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.BlockFuncDepsPropagation;
+import org.apache.doris.nereids.trees.plans.DistributeType;
+import org.apache.doris.nereids.trees.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.nereids.util.JoinUtils;
+import org.apache.doris.nereids.util.Utils;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * select col1 from t1 join t2 using(col1);
+ */
+public class LogicalUsingJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE 
extends Plan>
+        extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements 
BlockFuncDepsPropagation {
+
+    private final JoinType joinType;
+    private final ImmutableList<Expression> usingSlots;
+    private final DistributeHint hint;
+
+    public LogicalUsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, 
RIGHT_CHILD_TYPE rightChild,
+            List<Expression> usingSlots, DistributeHint hint) {
+        this(joinType, leftChild, rightChild, usingSlots, Optional.empty(), 
Optional.empty(), hint);
+    }
+
+    /**
+     * Constructor.
+     */
+    public LogicalUsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, 
RIGHT_CHILD_TYPE rightChild,
+            List<Expression> usingSlots, Optional<GroupExpression> 
groupExpression,
+            Optional<LogicalProperties> logicalProperties, DistributeHint 
hint) {
+        super(PlanType.LOGICAL_USING_JOIN, groupExpression, logicalProperties, 
leftChild, rightChild);
+        this.joinType = joinType;
+        this.usingSlots = ImmutableList.copyOf(usingSlots);
+        this.hint = hint;
+    }
+
+    @Override
+    public List<Slot> computeOutput() {
+        return JoinUtils.getJoinOutput(joinType, left(), right());
+    }
+
+    @Override
+    public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
+        return new LogicalUsingJoin<>(joinType, child(0), child(1),
+                usingSlots, groupExpression, 
Optional.of(getLogicalProperties()), hint);
+    }
+
+    @Override
+    public Plan withGroupExprLogicalPropChildren(Optional<GroupExpression> 
groupExpression,
+            Optional<LogicalProperties> logicalProperties, List<Plan> 
children) {
+        return new LogicalUsingJoin<>(joinType, children.get(0), 
children.get(1),
+                usingSlots, groupExpression, logicalProperties, hint);
+    }
+
+    @Override
+    public Plan withChildren(List<Plan> children) {
+        return new LogicalUsingJoin<>(joinType, children.get(0), 
children.get(1),
+                usingSlots, groupExpression, 
Optional.of(getLogicalProperties()), hint);
+    }
+
+    @Override
+    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+        return visitor.visit(this, context);
+    }
+
+    @Override
+    public List<? extends Expression> getExpressions() {
+        return usingSlots;
+    }
+
+    public JoinType getJoinType() {
+        return joinType;
+    }
+
+    public List<Expression> getUsingSlots() {
+        return usingSlots;
+    }
+
+    public DistributeHint getDistributeHint() {
+        return hint;
+    }
+
+    public List<Expression> getMarkJoinConjuncts() {
+        return ExpressionUtils.EMPTY_CONDITION;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LogicalUsingJoin<?, ?> usingJoin = (LogicalUsingJoin<?, ?>) o;
+        return joinType == usingJoin.joinType
+                && Objects.equals(usingSlots, usingJoin.usingSlots)
+                && Objects.equals(hint, usingJoin.hint);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(joinType, usingSlots, hint);
+    }
+
+    @Override
+    public String toString() {
+        List<Object> args = Lists.newArrayList(
+                "type", joinType,
+                "usingSlots", usingSlots);
+        if (hint.distributeType != DistributeType.NONE) {
+            args.add("hint");
+            args.add(hint.getExplainString());
+        }
+        return Utils.toSqlString("UsingJoin[" + id.asInt() + "]", 
args.toArray());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/UsingJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/UsingJoin.java
deleted file mode 100644
index 62cb542e78a..00000000000
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/UsingJoin.java
+++ /dev/null
@@ -1,217 +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.plans.logical;
-
-import org.apache.doris.nereids.hint.DistributeHint;
-import org.apache.doris.nereids.memo.GroupExpression;
-import org.apache.doris.nereids.properties.LogicalProperties;
-import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference;
-import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.plans.BlockFuncDepsPropagation;
-import org.apache.doris.nereids.trees.plans.DistributeType;
-import org.apache.doris.nereids.trees.plans.JoinType;
-import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.algebra.Join;
-import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
-import org.apache.doris.nereids.util.ExpressionUtils;
-import org.apache.doris.nereids.util.Utils;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.collect.Lists;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-
-/**
- * select col1 from t1 join t2 using(col1);
- */
-public class UsingJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends 
Plan>
-        extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements 
Join, BlockFuncDepsPropagation {
-
-    private final JoinType joinType;
-    private final ImmutableList<Expression> otherJoinConjuncts;
-    private final ImmutableList<Expression> hashJoinConjuncts;
-    private final DistributeHint hint;
-
-    public UsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, 
RIGHT_CHILD_TYPE rightChild,
-            List<Expression> expressions, List<Expression> hashJoinConjuncts,
-            DistributeHint hint) {
-        this(joinType, leftChild, rightChild, expressions,
-                hashJoinConjuncts, Optional.empty(), Optional.empty(), hint);
-    }
-
-    /**
-     * Constructor.
-     */
-    public UsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, 
RIGHT_CHILD_TYPE rightChild,
-            List<Expression> expressions, List<Expression> hashJoinConjuncts, 
Optional<GroupExpression> groupExpression,
-            Optional<LogicalProperties> logicalProperties,
-            DistributeHint hint) {
-        super(PlanType.LOGICAL_USING_JOIN, groupExpression, logicalProperties, 
leftChild, rightChild);
-        this.joinType = joinType;
-        this.otherJoinConjuncts = ImmutableList.copyOf(expressions);
-        this.hashJoinConjuncts = ImmutableList.copyOf(hashJoinConjuncts);
-        this.hint = hint;
-    }
-
-    @Override
-    public List<Slot> computeOutput() {
-
-        List<Slot> newLeftOutput = left().getOutput().stream().map(o -> 
o.withNullable(true))
-                .collect(ImmutableList.toImmutableList());
-
-        List<Slot> newRightOutput = right().getOutput().stream().map(o -> 
o.withNullable(true))
-                .collect(ImmutableList.toImmutableList());
-
-        switch (joinType) {
-            case LEFT_SEMI_JOIN:
-            case LEFT_ANTI_JOIN:
-                return ImmutableList.copyOf(left().getOutput());
-            case RIGHT_SEMI_JOIN:
-            case RIGHT_ANTI_JOIN:
-                return ImmutableList.copyOf(right().getOutput());
-            case LEFT_OUTER_JOIN:
-                return ImmutableList.<Slot>builder()
-                        .addAll(left().getOutput())
-                        .addAll(newRightOutput)
-                        .build();
-            case RIGHT_OUTER_JOIN:
-                return ImmutableList.<Slot>builder()
-                        .addAll(newLeftOutput)
-                        .addAll(right().getOutput())
-                        .build();
-            case FULL_OUTER_JOIN:
-                return ImmutableList.<Slot>builder()
-                        .addAll(newLeftOutput)
-                        .addAll(newRightOutput)
-                        .build();
-            default:
-                return ImmutableList.<Slot>builder()
-                        .addAll(left().getOutput())
-                        .addAll(right().getOutput())
-                        .build();
-        }
-    }
-
-    @Override
-    public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new UsingJoin(joinType, child(0), child(1), otherJoinConjuncts,
-                hashJoinConjuncts, groupExpression, 
Optional.of(getLogicalProperties()), hint);
-    }
-
-    @Override
-    public Plan withGroupExprLogicalPropChildren(Optional<GroupExpression> 
groupExpression,
-            Optional<LogicalProperties> logicalProperties, List<Plan> 
children) {
-        return new UsingJoin(joinType, children.get(0), children.get(1), 
otherJoinConjuncts,
-                hashJoinConjuncts, groupExpression, logicalProperties, hint);
-    }
-
-    @Override
-    public Plan withChildren(List<Plan> children) {
-        return new UsingJoin(joinType, children.get(0), children.get(1), 
otherJoinConjuncts,
-                hashJoinConjuncts, groupExpression, 
Optional.of(getLogicalProperties()), hint);
-    }
-
-    @Override
-    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
-        return visitor.visit(this, context);
-    }
-
-    @Override
-    public List<? extends Expression> getExpressions() {
-        return new Builder<Expression>()
-                .addAll(hashJoinConjuncts)
-                .addAll(otherJoinConjuncts)
-                .build();
-    }
-
-    public JoinType getJoinType() {
-        return joinType;
-    }
-
-    public List<Expression> getOtherJoinConjuncts() {
-        return otherJoinConjuncts;
-    }
-
-    public List<Expression> getHashJoinConjuncts() {
-        return hashJoinConjuncts;
-    }
-
-    public DistributeHint getDistributeHint() {
-        return hint;
-    }
-
-    public boolean isMarkJoin() {
-        return false;
-    }
-
-    public Optional<MarkJoinSlotReference> getMarkJoinSlotReference() {
-        return Optional.empty();
-    }
-
-    public List<Expression> getMarkJoinConjuncts() {
-        return ExpressionUtils.EMPTY_CONDITION;
-    }
-
-    @Override
-    public Optional<Expression> getOnClauseCondition() {
-        return ExpressionUtils.optionalAnd(hashJoinConjuncts, 
otherJoinConjuncts);
-    }
-
-    @Override
-    public boolean hasDistributeHint() {
-        return hint != null;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        UsingJoin<?, ?> usingJoin = (UsingJoin<?, ?>) o;
-        return joinType == usingJoin.joinType
-                && Objects.equals(otherJoinConjuncts, 
usingJoin.otherJoinConjuncts)
-                && Objects.equals(hashJoinConjuncts, 
usingJoin.hashJoinConjuncts)
-                && Objects.equals(hint, usingJoin.hint);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(joinType, otherJoinConjuncts, hashJoinConjuncts, 
hint);
-    }
-
-    @Override
-    public String toString() {
-        List<Object> args = Lists.newArrayList(
-                "type", joinType,
-                "hashJoinConjuncts", hashJoinConjuncts,
-                "otherJoinConjuncts", otherJoinConjuncts);
-        if (hint.distributeType != DistributeType.NONE) {
-            args.add("hint");
-            args.add(hint.getExplainString());
-        }
-        return Utils.toSqlString("UsingJoin[" + id.asInt() + "]", 
args.toArray());
-    }
-}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java
index 2b2c7ac0428..afba3add8d7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java
@@ -66,7 +66,7 @@ public class PhysicalSqlCache extends PhysicalLeaf
             Optional<ResultSet> resultSet, List<InternalService.PCacheValue> 
cacheValues,
             String backendAddress, String planBody) {
         super(PlanType.PHYSICAL_SQL_CACHE, Optional.empty(),
-                new LogicalProperties(() -> ImmutableList.of(), () -> 
DataTrait.EMPTY_TRAIT));
+                new LogicalProperties(ImmutableList::of, () -> 
DataTrait.EMPTY_TRAIT));
         this.queryId = Objects.requireNonNull(queryId, "queryId can not be 
null");
         this.columnLabels = Objects.requireNonNull(columnLabels, "colNames can 
not be null");
         this.fieldInfos = Objects.requireNonNull(fieldInfos, "fieldInfos can 
not be null");
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
index 770905bf199..863f9f92ab2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
@@ -420,33 +420,49 @@ public class JoinUtils {
      * @return return the output slots
      */
     public static List<Slot> getJoinOutput(JoinType joinType, Plan left, Plan 
right) {
+        return getJoinOutput(joinType, left, right, false);
+    }
+
+    /**
+     * calculate the output slot of a join operator according join type and 
its children
+     *
+     * @param joinType the type of join operator
+     * @param left left child
+     * @param right right child
+     * @param asteriskOutput when true, return output for asterisk
+     *
+     * @return return the output slots
+     */
+    public static List<Slot> getJoinOutput(JoinType joinType, Plan left, Plan 
right, boolean asteriskOutput) {
+        List<Slot> leftOutput = asteriskOutput ? left.getAsteriskOutput() : 
left.getOutput();
+        List<Slot> rightOutput = asteriskOutput ? right.getAsteriskOutput() : 
right.getOutput();
         switch (joinType) {
             case LEFT_SEMI_JOIN:
             case LEFT_ANTI_JOIN:
             case NULL_AWARE_LEFT_ANTI_JOIN:
-                return ImmutableList.copyOf(left.getOutput());
+                return ImmutableList.copyOf(leftOutput);
             case RIGHT_SEMI_JOIN:
             case RIGHT_ANTI_JOIN:
-                return ImmutableList.copyOf(right.getOutput());
+                return ImmutableList.copyOf(rightOutput);
             case LEFT_OUTER_JOIN:
                 return ImmutableList.<Slot>builder()
-                        .addAll(left.getOutput())
-                        .addAll(applyNullable(right.getOutput(), true))
+                        .addAll(leftOutput)
+                        .addAll(applyNullable(rightOutput, true))
                         .build();
             case RIGHT_OUTER_JOIN:
                 return ImmutableList.<Slot>builder()
-                        .addAll(applyNullable(left.getOutput(), true))
-                        .addAll(right.getOutput())
+                        .addAll(applyNullable(leftOutput, true))
+                        .addAll(rightOutput)
                         .build();
             case FULL_OUTER_JOIN:
                 return ImmutableList.<Slot>builder()
-                        .addAll(applyNullable(left.getOutput(), true))
-                        .addAll(applyNullable(right.getOutput(), true))
+                        .addAll(applyNullable(leftOutput, true))
+                        .addAll(applyNullable(rightOutput, true))
                         .build();
             default:
                 return ImmutableList.<Slot>builder()
-                        .addAll(left.getOutput())
-                        .addAll(right.getOutput())
+                        .addAll(leftOutput)
+                        .addAll(rightOutput)
                         .build();
         }
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java
index 28f7cda427e..7438e46ddc7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java
@@ -179,6 +179,30 @@ public class PlanUtils {
         return output.build();
     }
 
+    /** fastGetChildrenOutput */
+    public static List<Slot> fastGetChildrenAsteriskOutputs(List<Plan> 
children) {
+        switch (children.size()) {
+            case 1: return children.get(0).getAsteriskOutput();
+            case 0: return ImmutableList.of();
+            default: {
+            }
+        }
+
+        int outputNum = 0;
+        // child.output is cached by AbstractPlan.logicalProperties,
+        // we can compute output num without the overhead of re-compute output
+        for (Plan child : children) {
+            List<Slot> output = child.getAsteriskOutput();
+            outputNum += output.size();
+        }
+        // generate output list only copy once and without resize the list
+        Builder<Slot> output = 
ImmutableList.builderWithExpectedSize(outputNum);
+        for (Plan child : children) {
+            output.addAll(child.getAsteriskOutput());
+        }
+        return output.build();
+    }
+
     /** fastGetInputSlots */
     public static Set<Slot> fastGetInputSlots(List<? extends Expression> 
expressions) {
         switch (expressions.size()) {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java
index 8e790dcf0e7..63fa700f23c 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java
@@ -34,7 +34,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
-import org.apache.doris.nereids.trees.plans.logical.UsingJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalUsingJoin;
 import org.apache.doris.nereids.util.MemoPatternMatchSupported;
 import org.apache.doris.nereids.util.MemoTestUtils;
 import org.apache.doris.nereids.util.PlanChecker;
@@ -159,15 +159,14 @@ class BindSlotReferenceTest implements 
MemoPatternMatchSupported {
         LogicalSubQueryAlias<LogicalOlapScan> sub3 = new 
LogicalSubQueryAlias<>("t3", scan3);
 
         DistributeHint hint = new DistributeHint(DistributeType.NONE);
-        UsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, 
LogicalSubQueryAlias<LogicalOlapScan>>
-                using1 = new UsingJoin<>(JoinType.LEFT_OUTER_JOIN, sub1,
-                sub2, ImmutableList.of(), ImmutableList.of(new 
UnboundSlot("id")), hint);
-
-        UsingJoin<UsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, 
LogicalSubQueryAlias<LogicalOlapScan>>,
-                    LogicalSubQueryAlias<LogicalOlapScan>> using2
-                = new UsingJoin<>(
-                        JoinType.LEFT_OUTER_JOIN, using1, sub3, 
ImmutableList.of(),
-                        ImmutableList.of(new UnboundSlot("id")), hint);
+        LogicalUsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, 
LogicalSubQueryAlias<LogicalOlapScan>>
+                using1 = new LogicalUsingJoin<>(JoinType.LEFT_OUTER_JOIN, sub1,
+                sub2, ImmutableList.of(new UnboundSlot("id")), hint);
+
+        
LogicalUsingJoin<LogicalUsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, 
LogicalSubQueryAlias<LogicalOlapScan>>,
+                            LogicalSubQueryAlias<LogicalOlapScan>> using2 = 
new LogicalUsingJoin<>(
+                                    JoinType.LEFT_OUTER_JOIN, using1, sub3,
+                ImmutableList.of(new UnboundSlot("id")), hint);
 
         PlanChecker.from(MemoTestUtils.createConnectContext())
                 .analyze(using2)
diff --git a/regression-test/data/nereids_p0/join/test_join2.out 
b/regression-test/data/nereids_p0/join/test_join2.out
index 13b0f74dc79..23b5592ae72 100644
Binary files a/regression-test/data/nereids_p0/join/test_join2.out and 
b/regression-test/data/nereids_p0/join/test_join2.out differ
diff --git a/regression-test/data/nereids_p0/join/test_join3.out 
b/regression-test/data/nereids_p0/join/test_join3.out
index 54eb521e21f..a85be3f68b7 100644
Binary files a/regression-test/data/nereids_p0/join/test_join3.out and 
b/regression-test/data/nereids_p0/join/test_join3.out differ
diff --git a/regression-test/data/nereids_syntax_p0/test_join3.out 
b/regression-test/data/nereids_syntax_p0/test_join3.out
index 54eb521e21f..a85be3f68b7 100644
Binary files a/regression-test/data/nereids_syntax_p0/test_join3.out and 
b/regression-test/data/nereids_syntax_p0/test_join3.out differ
diff --git a/regression-test/data/nereids_syntax_p0/using_join.out 
b/regression-test/data/nereids_syntax_p0/using_join.out
index 577c514b37d..4b034542dc5 100644
Binary files a/regression-test/data/nereids_syntax_p0/using_join.out and 
b/regression-test/data/nereids_syntax_p0/using_join.out differ
diff --git a/regression-test/data/query_p0/join/test_join2.out 
b/regression-test/data/query_p0/join/test_join2.out
index 13b0f74dc79..23b5592ae72 100644
Binary files a/regression-test/data/query_p0/join/test_join2.out and 
b/regression-test/data/query_p0/join/test_join2.out differ
diff --git a/regression-test/data/query_p0/join/test_join3.out 
b/regression-test/data/query_p0/join/test_join3.out
index 54eb521e21f..a85be3f68b7 100644
Binary files a/regression-test/data/query_p0/join/test_join3.out and 
b/regression-test/data/query_p0/join/test_join3.out differ
diff --git a/regression-test/suites/nereids_p0/join/test_join2.groovy 
b/regression-test/suites/nereids_p0/join/test_join2.groovy
index 2e17d5c8db1..abb1744430d 100644
--- a/regression-test/suites/nereids_p0/join/test_join2.groovy
+++ b/regression-test/suites/nereids_p0/join/test_join2.groovy
@@ -70,14 +70,14 @@ suite("test_join2", "query,p0") {
             SELECT '' AS "xxx", *
             FROM ${TBname1}
             INNER JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join2 """
             SELECT '' AS "xxx", *
             FROM ${TBname1}
             JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     test {
@@ -116,52 +116,52 @@ suite("test_join2", "query,p0") {
     qt_join6 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} LEFT OUTER JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join7 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} LEFT JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join8 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} RIGHT
             OUTER JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join9 """
             SELECT '' AS "xxx", *
             FROM ${TBname1}
             RIGHT JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
     qt_join10 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} FULL OUTER JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join11 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} FULL JOIN ${TBname2} USING (i)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join12 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} LEFT JOIN ${TBname2} USING (i)
             WHERE (k = 1)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     qt_join13 """
             SELECT '' AS "xxx", *
             FROM ${TBname1} LEFT JOIN ${TBname2} USING (i)
             WHERE (${TBname1}.i = 1)
-            ORDER BY 1,2,3,4,5,6;
+            ORDER BY 1,2,3,4,5;
         """
 
     sql "DROP TABLE IF EXISTS ${TBname1};"
diff --git a/regression-test/suites/nereids_syntax_p0/using_join.groovy 
b/regression-test/suites/nereids_syntax_p0/using_join.groovy
index 795dc07b483..bb9d1500f60 100644
--- a/regression-test/suites/nereids_syntax_p0/using_join.groovy
+++ b/regression-test/suites/nereids_syntax_p0/using_join.groovy
@@ -16,62 +16,140 @@
 // under the License.
 
 suite("nereids_using_join") {
+    sql """DROP TABLE IF EXISTS nereids_using_join_t1"""
+    sql """DROP TABLE IF EXISTS nereids_using_join_t2"""
+    sql """DROP TABLE IF EXISTS nereids_using_join_t3"""
+    sql """DROP TABLE IF EXISTS nereids_using_join_t4"""
+
     sql """
-        SET enable_fallback_to_original_planner=false
+        CREATE TABLE `nereids_using_join_t1` (
+            `c1` int,
+            `c2` int,
+            `c3` int,
+            `c4` array<int>,
+            `v1` int
+        )
+        PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1"
+        );
     """
 
     sql """
-        SET enable_nereids_planner=true
+        CREATE TABLE `nereids_using_join_t2` (
+            `c1` int,
+            `c2` int,
+            `v2` int
+        )
+        PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1"
+        );
     """
 
-    sql """DROP TABLE IF EXISTS nereids_using_join_t1"""
-
     sql """
-        CREATE TABLE `nereids_using_join_t1` (
-            `col1` varchar(4) NULL,
-            `col2` int(11) NULL,
-            `col3` int(11) NULL
-        ) ENGINE=OLAP
-        DUPLICATE KEY(`col1`)
-        COMMENT 'OLAP'
-        DISTRIBUTED BY HASH(`col3`) BUCKETS 1
+        CREATE TABLE `nereids_using_join_t3` (
+            `c1` int,
+            `v3` int
+        )
         PROPERTIES (
-        "replication_allocation" = "tag.location.default: 1"
+            "replication_allocation" = "tag.location.default: 1"
         );
     """
 
-    sql """DROP TABLE IF EXISTS nereids_using_join_t2"""
-
     sql """
-        CREATE TABLE `nereids_using_join_t2` (
-            `col1` varchar(4) NULL,
-            `col2` int(11) NULL,
-            `col3` int(11) NULL
-        ) ENGINE=OLAP
-        DUPLICATE KEY(`col1`)
-        COMMENT 'OLAP'
-        DISTRIBUTED BY HASH(`col3`) BUCKETS 1
+        CREATE TABLE `nereids_using_join_t4` (
+            `c1` int,
+            `c5` int,
+            `v4` int
+        )
         PROPERTIES (
-        "replication_allocation" = "tag.location.default: 1"
+            "replication_allocation" = "tag.location.default: 1"
         );
     """
 
-    sql """INSERT INTO nereids_using_join_t1 VALUES('1', 1, 1)"""
-    sql """INSERT INTO nereids_using_join_t1 VALUES('2', 2, 1)"""
-    sql """INSERT INTO nereids_using_join_t1 VALUES('3', 3, 1)"""
-    sql """INSERT INTO nereids_using_join_t1 VALUES('4', 4, 1)"""
+    sql """INSERT INTO nereids_using_join_t1 VALUES(1, 1, 1, [1, 2, 3, 4], 
11)"""
+    sql """INSERT INTO nereids_using_join_t1 VALUES(2, 3, 4, [5, 6, 7, 8], 
12)"""
+    sql """INSERT INTO nereids_using_join_t2 VALUES(1, 1, 21)"""
+    sql """INSERT INTO nereids_using_join_t2 VALUES(1, 2, 22)"""
+    sql """INSERT INTO nereids_using_join_t2 VALUES(1, 3, 23)"""
+    sql """INSERT INTO nereids_using_join_t3 VALUES(1, 31)"""
+    sql """INSERT INTO nereids_using_join_t3 VALUES(2, 32)"""
+    sql """INSERT INTO nereids_using_join_t3 VALUES(3, 33)"""
+    sql """INSERT INTO nereids_using_join_t3 VALUES(4, 34)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 1, 41)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 2, 42)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 3, 43)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 4, 44)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 5, 45)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 6, 46)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 7, 47)"""
+    sql """INSERT INTO nereids_using_join_t4 VALUES(1, 8, 48)"""
+
+    order_qt_two_relations """
+        select * from nereids_using_join_t1 join nereids_using_join_t2 using 
(c1);
+    """
+
+    order_qt_two_relations_by_two_slot """
+        select * from nereids_using_join_t1 join nereids_using_join_t2 using 
(c1, c2);
+    """
+
+    order_qt_two_relations_with_right_slot """
+        select *, nereids_using_join_t2.c1 from nereids_using_join_t1 join 
nereids_using_join_t2 using (c1);
+    """
+
+    order_qt_two_relations_with_alias """
+        select * from nereids_using_join_t1 a join nereids_using_join_t2 b 
using (c1);
+    """
+
+    order_qt_three_relations """
+        select * from nereids_using_join_t1 join nereids_using_join_t3 using 
(c1) join nereids_using_join_t2 using (c2);
+    """
+
+    order_qt_one_plus_two_relations """
+        select * from nereids_using_join_t2 join (nereids_using_join_t1 join 
nereids_using_join_t3 using (c1)) using (c1);
+    """
+
+    order_qt_one_plus_two_cross_join """
+        select * from nereids_using_join_t1 join (nereids_using_join_t2, 
nereids_using_join_t3) using (c2);
+    """
+
+    order_qt_one_cross_join_with_two """
+        select * from nereids_using_join_t1, nereids_using_join_t2 join 
nereids_using_join_t3 using (c1);
+    """
+
+    order_qt_with_lateral_view """
+        select * from nereids_using_join_t1 lateral view explode(c4) tmp as c5 
join nereids_using_join_t3 using (c1) join nereids_using_join_t2 using (c2) 
join nereids_using_join_t4 using(c5);
+    """
 
-    sql """INSERT INTO nereids_using_join_t2 VALUES('1', 1, 1)"""
-    sql """INSERT INTO nereids_using_join_t2 VALUES('2', 2, 1)"""
-    sql """INSERT INTO nereids_using_join_t2 VALUES('6', 3, 1)"""
-    sql """INSERT INTO nereids_using_join_t2 VALUES('7', 4, 1)"""
+    order_qt_with_aggregate_project """
+        select * from (select c3, sum(nereids_using_join_t2.c2) from 
nereids_using_join_t1 join nereids_using_join_t2 using (c1) group by c3) t      
 
+    """
+
+    order_qt_with_aggregate_by_right_slot_project """
+        select * from (select nereids_using_join_t2.c1, 
sum(nereids_using_join_t2.c2) from nereids_using_join_t1 join 
nereids_using_join_t2 using (c1) group by nereids_using_join_t2.c1) t       
+    """
+
+    order_qt_with_project_aggregate """
+        select c1, sum(c3) from (select * from nereids_using_join_t1 join 
nereids_using_join_t3 using (c1)) t group by c1
+    """
+
+    order_qt_with_extend_aggregate """
+        select c1, c2, c3, sum(c3) from (select * from nereids_using_join_t1 
join nereids_using_join_t3 using (c1)) t group by grouping sets ((c1), (c2), 
(c3))
+    """
+
+    order_qt_with_order_by """
+        select * from (select * from nereids_using_join_t1 join 
nereids_using_join_t3 using (c1) order by c1) t join nereids_using_join_t2 
using (c1) order by c1;
+    """
+
+    order_qt_with_limit """
+        select * from (select * from nereids_using_join_t1 join 
nereids_using_join_t3 using (c1) limit 10) t join nereids_using_join_t2 using 
(c1) limit 5;
+    """
 
-    order_qt_sql """
-        SELECT nereids_using_join_t1.col1 FROM nereids_using_join_t1 JOIN 
nereids_using_join_t2 USING (col1)
+    order_qt_with_union_all """
+        select * from (select * from nereids_using_join_t1 join 
nereids_using_join_t3 using (c1) union all select * from nereids_using_join_t1 
join nereids_using_join_t3 using (c1)) t
     """
 
-    order_qt_sql """
-        SELECT nereids_using_join_t1.col1 FROM nereids_using_join_t1 JOIN 
nereids_using_join_t2 USING (col1, col2)
+    order_qt_with_filter """
+        select * from nereids_using_join_t1 join nereids_using_join_t2 using 
(c1) where c1 < 3;
     """
 
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org


Reply via email to