[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:
seawinde
2023-11-08 11:28:48 +08:00
committed by GitHub
parent f4cbbe6429
commit 7bad2e1d9f
29 changed files with 2181 additions and 29 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -88,7 +88,7 @@ public class AssertNumRowsElement extends Expression implements LeafExpression,
}
@Override
protected String getExpressionName() {
public String getExpressionName() {
return assertion.name().toLowerCase();
}

View File

@ -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;
}

View File

@ -58,7 +58,7 @@ public abstract class NamedExpression extends Expression {
}
@Override
protected String getExpressionName() {
public String getExpressionName() {
return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME);
}
}

View File

@ -85,7 +85,7 @@ public abstract class SubqueryExpr extends Expression implements LeafExpression
}
@Override
protected String getExpressionName() {
public String getExpressionName() {
return "subquery";
}

View File

@ -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);
}

View File

@ -132,7 +132,7 @@ public abstract class Literal extends Expression implements LeafExpression, Comp
}
@Override
protected String getExpressionName() {
public String getExpressionName() {
return "literal";
}

View File

@ -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;
}
}