[opt](nereids) infer result column name in ctas and query stmt (#26055)
Infer name if it is an expression and doesn't alias artificially when create or select stmt in nereids. The infer name strategy is the same as #24990
This commit is contained in:
@ -554,12 +554,8 @@ public class SelectStmt extends QueryStmt {
|
||||
}
|
||||
resultExprs.add(rewriteQueryExprByMvColumnExpr(item.getExpr(), analyzer));
|
||||
String columnLabel = null;
|
||||
Class<? extends StatementBase> statementClazz = analyzer.getRootStatementClazz();
|
||||
if (statementClazz != null
|
||||
&& (!QueryStmt.class.isAssignableFrom(statementClazz) || hasOutFileClause())) {
|
||||
// Infer column name when item is expr
|
||||
columnLabel = item.toColumnLabel(i);
|
||||
}
|
||||
// Infer column name when item is expr, both query and ddl
|
||||
columnLabel = item.toColumnLabel(i);
|
||||
if (columnLabel == null) {
|
||||
// column label without position is applicative for query and do not infer
|
||||
// column name when item is expr
|
||||
|
||||
@ -62,7 +62,7 @@ public class UnboundFunction extends Function implements Unbound, PropagateNulla
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME);
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@ import org.apache.doris.nereids.trees.UnaryNode;
|
||||
import org.apache.doris.nereids.trees.expressions.Alias;
|
||||
import org.apache.doris.nereids.trees.expressions.BoundStar;
|
||||
import org.apache.doris.nereids.trees.expressions.EqualTo;
|
||||
import org.apache.doris.nereids.trees.expressions.ExprId;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.NamedExpression;
|
||||
import org.apache.doris.nereids.trees.expressions.Properties;
|
||||
@ -72,12 +73,14 @@ 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.visitor.InferPlanOutputAlias;
|
||||
import org.apache.doris.nereids.util.TypeCoercionUtils;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -564,10 +567,16 @@ public class BindExpression implements AnalysisRuleFactory {
|
||||
),
|
||||
RuleType.BINDING_RESULT_SINK.build(
|
||||
unboundResultSink().then(sink -> {
|
||||
List<NamedExpression> outputExprs = sink.child().getOutput().stream()
|
||||
.map(NamedExpression.class::cast)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
return new LogicalResultSink<>(outputExprs, sink.child());
|
||||
|
||||
final ImmutableListMultimap.Builder<ExprId, Integer> exprIdToIndexMapBuilder =
|
||||
ImmutableListMultimap.builder();
|
||||
List<Slot> childOutput = sink.child().getOutput();
|
||||
for (int index = 0; index < childOutput.size(); index++) {
|
||||
exprIdToIndexMapBuilder.put(childOutput.get(index).getExprId(), index);
|
||||
}
|
||||
InferPlanOutputAlias aliasInfer = new InferPlanOutputAlias(childOutput);
|
||||
sink.child().accept(aliasInfer, exprIdToIndexMapBuilder.build());
|
||||
return new LogicalResultSink<>(aliasInfer.getOutputs(), sink.child());
|
||||
})
|
||||
)
|
||||
).stream().map(ruleCondition).collect(ImmutableList.toImmutableList());
|
||||
|
||||
@ -119,7 +119,7 @@ public class AggregateExpression extends Expression implements UnaryExpression {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return Utils.normalizeName(function.getName(), DEFAULT_EXPRESSION_NAME);
|
||||
}
|
||||
|
||||
|
||||
@ -146,4 +146,8 @@ public class Alias extends NamedExpression implements UnaryExpression {
|
||||
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
|
||||
return visitor.visitAlias(this, context);
|
||||
}
|
||||
|
||||
public boolean isNameFromChild() {
|
||||
return nameFromChild;
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ public class AssertNumRowsElement extends Expression implements LeafExpression,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return assertion.name().toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ public abstract class Expression extends AbstractTreeNode<Expression> implements
|
||||
|
||||
// Name of expr, this is used by generating column name automatically when there is no
|
||||
// alias
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return this.exprName;
|
||||
}
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ public abstract class NamedExpression extends Expression {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ public abstract class SubqueryExpr extends Expression implements LeafExpression
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return "subquery";
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ public abstract class BoundFunction extends Function implements ComputeSignature
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME);
|
||||
}
|
||||
|
||||
|
||||
@ -132,7 +132,7 @@ public abstract class Literal extends Expression implements LeafExpression, Comp
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpressionName() {
|
||||
public String getExpressionName() {
|
||||
return "literal";
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
// 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.visitor;
|
||||
|
||||
import org.apache.doris.nereids.trees.expressions.Alias;
|
||||
import org.apache.doris.nereids.trees.expressions.ExprId;
|
||||
import org.apache.doris.nereids.trees.expressions.NamedExpression;
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
import org.apache.doris.nereids.trees.plans.Plan;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Infer output column name when it refers an expression and not has an alias manually.
|
||||
*/
|
||||
public class InferPlanOutputAlias extends DefaultPlanVisitor<Void, ImmutableMultimap<ExprId, Integer>> {
|
||||
|
||||
private final List<Slot> currentOutputs;
|
||||
private final List<NamedExpression> finalOutputs;
|
||||
|
||||
public InferPlanOutputAlias(List<Slot> currentOutputs) {
|
||||
this.currentOutputs = currentOutputs;
|
||||
this.finalOutputs = new ArrayList<>(currentOutputs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Plan plan, ImmutableMultimap<ExprId, Integer> currentExprIdAndIndexMap) {
|
||||
|
||||
List<Alias> aliasProjects = plan.getExpressions().stream()
|
||||
.filter(expression -> expression instanceof Alias)
|
||||
.map(Alias.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ImmutableSet<ExprId> currentOutputExprIdSet = currentExprIdAndIndexMap.keySet();
|
||||
for (Alias projectItem : aliasProjects) {
|
||||
ExprId exprId = projectItem.getExprId();
|
||||
// Infer name when alias child is expression and alias's name is from child
|
||||
if (currentOutputExprIdSet.contains(projectItem.getExprId())
|
||||
&& projectItem.isNameFromChild()) {
|
||||
String inferredAliasName = projectItem.child().getExpressionName();
|
||||
ImmutableCollection<Integer> outPutExprIndexes = currentExprIdAndIndexMap.get(exprId);
|
||||
// replace output name by inferred name
|
||||
outPutExprIndexes.forEach(index -> {
|
||||
Slot slot = currentOutputs.get(index);
|
||||
finalOutputs.set(index, slot.withName("__" + inferredAliasName + "_" + index));
|
||||
});
|
||||
}
|
||||
}
|
||||
return super.visit(plan, currentExprIdAndIndexMap);
|
||||
}
|
||||
|
||||
public List<NamedExpression> getOutputs() {
|
||||
return finalOutputs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user