[Fix](nereids) add backquote and qualifier to udf, column, column alias and table alias when create view (#37237) (#37984)
cherry-pick #37237 to branch-2.1 --------- Co-authored-by: feiniaofeiafei <moailing@selectdb.com>
This commit is contained in:
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.analyzer;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.exceptions.UnboundException;
|
||||
import org.apache.doris.nereids.trees.expressions.ExprId;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
@ -25,6 +26,7 @@ import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.DataType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* MappingSlot.
|
||||
@ -36,6 +38,7 @@ public class MappingSlot extends Slot {
|
||||
private final Expression mappingExpression;
|
||||
|
||||
public MappingSlot(Slot slot, Expression mappingExpression) {
|
||||
super(Optional.empty());
|
||||
this.slot = slot;
|
||||
this.mappingExpression = mappingExpression;
|
||||
}
|
||||
@ -112,4 +115,9 @@ public class MappingSlot extends Slot {
|
||||
public Slot withQualifier(List<String> qualifier) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.analyzer;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.exceptions.UnboundException;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.Function;
|
||||
@ -37,23 +38,31 @@ import java.util.stream.Collectors;
|
||||
public class UnboundFunction extends Function implements Unbound, PropagateNullable {
|
||||
private final String dbName;
|
||||
private final boolean isDistinct;
|
||||
// for create view stmt, the start and end position of the function string in original sql
|
||||
private final Optional<Pair<Integer, Integer>> indexInSqlString;
|
||||
|
||||
public UnboundFunction(String name, List<Expression> arguments) {
|
||||
this(null, name, false, arguments);
|
||||
this(null, name, false, arguments, Optional.empty());
|
||||
}
|
||||
|
||||
public UnboundFunction(String dbName, String name, List<Expression> arguments) {
|
||||
this(dbName, name, false, arguments);
|
||||
this(dbName, name, false, arguments, Optional.empty());
|
||||
}
|
||||
|
||||
public UnboundFunction(String name, boolean isDistinct, List<Expression> arguments) {
|
||||
this(null, name, isDistinct, arguments);
|
||||
this(null, name, isDistinct, arguments, Optional.empty());
|
||||
}
|
||||
|
||||
public UnboundFunction(String dbName, String name, boolean isDistinct, List<Expression> arguments) {
|
||||
this(dbName, name, isDistinct, arguments, Optional.empty());
|
||||
}
|
||||
|
||||
public UnboundFunction(String dbName, String name, boolean isDistinct,
|
||||
List<Expression> arguments, Optional<Pair<Integer, Integer>> indexInSqlString) {
|
||||
super(name, arguments);
|
||||
this.dbName = dbName;
|
||||
this.isDistinct = isDistinct;
|
||||
this.indexInSqlString = indexInSqlString;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,7 +106,7 @@ public class UnboundFunction extends Function implements Unbound, PropagateNulla
|
||||
|
||||
@Override
|
||||
public UnboundFunction withChildren(List<Expression> children) {
|
||||
return new UnboundFunction(dbName, getName(), isDistinct, children);
|
||||
return new UnboundFunction(dbName, getName(), isDistinct, children, indexInSqlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -119,4 +128,12 @@ public class UnboundFunction extends Function implements Unbound, PropagateNulla
|
||||
public int hashCode() {
|
||||
return Objects.hash(getName(), isDistinct);
|
||||
}
|
||||
|
||||
public UnboundFunction withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return new UnboundFunction(dbName, getName(), isDistinct, children, Optional.ofNullable(index));
|
||||
}
|
||||
|
||||
public Optional<Pair<Integer, Integer>> getIndexInSqlString() {
|
||||
return indexInSqlString;
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,6 +152,12 @@ public class UnboundRelation extends LogicalRelation implements Unbound, BlockFu
|
||||
isTempPart, tabletIds, hints, tableSample, indexName, null, indexInSqlString, tableSnapshot);
|
||||
}
|
||||
|
||||
public UnboundRelation withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return new UnboundRelation(relationId, nameParts, groupExpression, Optional.of(getLogicalProperties()),
|
||||
partNames, isTempPart, tabletIds, hints, tableSample, indexName, null,
|
||||
Optional.of(index), tableSnapshot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnboundRelation withRelationId(RelationId relationId) {
|
||||
throw new UnboundException("should not call UnboundRelation's withRelationId method");
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.analyzer;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
@ -27,6 +28,7 @@ import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Slot has not been bound.
|
||||
@ -36,13 +38,23 @@ public class UnboundSlot extends Slot implements Unbound, PropagateNullable {
|
||||
private final List<String> nameParts;
|
||||
|
||||
public UnboundSlot(String... nameParts) {
|
||||
this(ImmutableList.copyOf(nameParts));
|
||||
this(ImmutableList.copyOf(nameParts), Optional.empty());
|
||||
}
|
||||
|
||||
public UnboundSlot(List<String> nameParts) {
|
||||
this(ImmutableList.copyOf(nameParts), Optional.empty());
|
||||
}
|
||||
|
||||
public UnboundSlot(List<String> nameParts, Optional<Pair<Integer, Integer>> indexInSqlString) {
|
||||
super(indexInSqlString);
|
||||
this.nameParts = ImmutableList.copyOf(Objects.requireNonNull(nameParts, "nameParts can not be null"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return new UnboundSlot(nameParts, Optional.ofNullable(index));
|
||||
}
|
||||
|
||||
public List<String> getNameParts() {
|
||||
return nameParts;
|
||||
}
|
||||
@ -74,7 +86,7 @@ public class UnboundSlot extends Slot implements Unbound, PropagateNullable {
|
||||
}
|
||||
|
||||
public static UnboundSlot quoted(String name) {
|
||||
return new UnboundSlot(Lists.newArrayList(name));
|
||||
return new UnboundSlot(Lists.newArrayList(name), Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -94,4 +94,8 @@ public class UnboundStar extends NamedExpression implements LeafExpression, Unbo
|
||||
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
|
||||
return visitor.visitUnboundStar(this, context);
|
||||
}
|
||||
|
||||
public UnboundStar withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return new UnboundStar(qualifier, Optional.ofNullable(index));
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,8 +490,6 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "OptionalGetWithoutIsPresent"})
|
||||
public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
private final boolean forCreateView;
|
||||
|
||||
// Sort the parameters with token position to keep the order with original placeholders
|
||||
// in prepared statement.Otherwise, the order maybe broken
|
||||
private final Map<Token, Placeholder> tokenPosToParameters = Maps.newTreeMap((pos1, pos2) -> {
|
||||
@ -502,14 +500,6 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
return pos1.getCharPositionInLine() - pos2.getCharPositionInLine();
|
||||
});
|
||||
|
||||
public LogicalPlanBuilder() {
|
||||
forCreateView = false;
|
||||
}
|
||||
|
||||
public LogicalPlanBuilder(boolean forCreateView) {
|
||||
this.forCreateView = forCreateView;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T typedVisit(ParseTree ctx) {
|
||||
return (T) ctx.accept(this);
|
||||
@ -854,9 +844,8 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
@Override
|
||||
public LogicalPlan visitAlterView(AlterViewContext ctx) {
|
||||
List<String> nameParts = visitMultipartIdentifier(ctx.name);
|
||||
LogicalPlan logicalPlan = visitQuery(ctx.query());
|
||||
String querySql = getOriginSql(ctx.query());
|
||||
AlterViewInfo info = new AlterViewInfo(new TableNameInfo(nameParts), logicalPlan, querySql,
|
||||
AlterViewInfo info = new AlterViewInfo(new TableNameInfo(nameParts), querySql,
|
||||
ctx.cols == null ? Lists.newArrayList() : visitSimpleColumnDefs(ctx.cols));
|
||||
return new AlterViewCommand(info);
|
||||
}
|
||||
@ -1356,7 +1345,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
/**
|
||||
* Create an aliased table reference. This is typically used in FROM clauses.
|
||||
*/
|
||||
private LogicalPlan withTableAlias(LogicalPlan plan, TableAliasContext ctx) {
|
||||
protected LogicalPlan withTableAlias(LogicalPlan plan, TableAliasContext ctx) {
|
||||
if (ctx.strictIdentifier() == null) {
|
||||
return plan;
|
||||
}
|
||||
@ -1418,14 +1407,8 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
MultipartIdentifierContext identifier = ctx.multipartIdentifier();
|
||||
TableSample tableSample = ctx.sample() == null ? null : (TableSample) visit(ctx.sample());
|
||||
UnboundRelation relation = forCreateView ? new UnboundRelation(StatementScopeIdGenerator.newRelationId(),
|
||||
tableId, partitionNames, isTempPart, tabletIdLists, relationHints,
|
||||
Optional.ofNullable(tableSample), indexName, scanParams,
|
||||
Optional.of(Pair.of(identifier.start.getStartIndex(), identifier.stop.getStopIndex())),
|
||||
Optional.ofNullable(tableSnapshot)) :
|
||||
new UnboundRelation(StatementScopeIdGenerator.newRelationId(),
|
||||
UnboundRelation relation = new UnboundRelation(StatementScopeIdGenerator.newRelationId(),
|
||||
tableId, partitionNames, isTempPart, tabletIdLists, relationHints,
|
||||
Optional.ofNullable(tableSample), indexName, scanParams, Optional.ofNullable(tableSnapshot));
|
||||
LogicalPlan checkedRelation = LogicalPlanBuilderAssistant.withCheckPolicy(relation);
|
||||
@ -1485,9 +1468,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
} else {
|
||||
target = ImmutableList.of();
|
||||
}
|
||||
return forCreateView
|
||||
? new UnboundStar(target, Optional.of(Pair.of(ctx.start.getStartIndex(), ctx.stop.getStopIndex())))
|
||||
: new UnboundStar(target);
|
||||
return new UnboundStar(target);
|
||||
});
|
||||
}
|
||||
|
||||
@ -2272,7 +2253,8 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
UnboundSlot unboundAttribute = (UnboundSlot) e;
|
||||
List<String> nameParts = Lists.newArrayList(unboundAttribute.getNameParts());
|
||||
nameParts.add(ctx.fieldName.getText());
|
||||
return new UnboundSlot(nameParts);
|
||||
UnboundSlot slot = new UnboundSlot(nameParts, Optional.empty());
|
||||
return slot;
|
||||
} else {
|
||||
// todo: base is an expression, may be not a table name.
|
||||
throw new ParseException("Unsupported dereference expression: " + ctx.getText(), ctx);
|
||||
@ -2484,7 +2466,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
|
||||
@Override
|
||||
public EqualTo visitUpdateAssignment(UpdateAssignmentContext ctx) {
|
||||
return new EqualTo(new UnboundSlot(visitMultipartIdentifier(ctx.multipartIdentifier())),
|
||||
return new EqualTo(new UnboundSlot(visitMultipartIdentifier(ctx.multipartIdentifier()), Optional.empty()),
|
||||
getExpression(ctx.expression()));
|
||||
}
|
||||
|
||||
@ -2531,10 +2513,9 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
List<String> nameParts = visitMultipartIdentifier(ctx.name);
|
||||
String comment = ctx.STRING_LITERAL() == null ? "" : LogicalPlanBuilderAssistant.escapeBackSlash(
|
||||
ctx.STRING_LITERAL().getText().substring(1, ctx.STRING_LITERAL().getText().length() - 1));
|
||||
LogicalPlan logicalPlan = visitQuery(ctx.query());
|
||||
String querySql = getOriginSql(ctx.query());
|
||||
CreateViewInfo info = new CreateViewInfo(ctx.EXISTS() != null, new TableNameInfo(nameParts),
|
||||
comment, logicalPlan, querySql,
|
||||
comment, querySql,
|
||||
ctx.cols == null ? Lists.newArrayList() : visitSimpleColumnDefs(ctx.cols));
|
||||
return new CreateViewCommand(info);
|
||||
}
|
||||
@ -2962,7 +2943,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
*
|
||||
* <p>Note that query hints are ignored (both by the parser and the builder).
|
||||
*/
|
||||
private LogicalPlan withSelectQuerySpecification(
|
||||
protected LogicalPlan withSelectQuerySpecification(
|
||||
ParserRuleContext ctx,
|
||||
LogicalPlan inputRelation,
|
||||
SelectClauseContext selectClause,
|
||||
@ -2984,10 +2965,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
if (!expressions.stream().allMatch(UnboundSlot.class::isInstance)) {
|
||||
throw new ParseException("only column name is supported in except clause", selectColumnCtx);
|
||||
}
|
||||
UnboundStar star = forCreateView ? new UnboundStar(ImmutableList.of(),
|
||||
Optional.of(Pair.of(selectColumnCtx.start.getStartIndex(),
|
||||
selectColumnCtx.stop.getStopIndex())))
|
||||
: new UnboundStar(ImmutableList.of());
|
||||
UnboundStar star = new UnboundStar(ImmutableList.of());
|
||||
project = new LogicalProject<>(ImmutableList.of(star), expressions, isDistinct, aggregate);
|
||||
} else {
|
||||
List<NamedExpression> projects = getNamedExpressions(selectColumnCtx.namedExpressionSeq());
|
||||
@ -3160,7 +3138,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
}
|
||||
|
||||
private LogicalPlan withProjection(LogicalPlan input, SelectColumnClauseContext selectCtx,
|
||||
protected LogicalPlan withProjection(LogicalPlan input, SelectColumnClauseContext selectCtx,
|
||||
Optional<AggClauseContext> aggCtx, boolean isDistinct) {
|
||||
return ParserUtils.withOrigin(selectCtx, () -> {
|
||||
if (aggCtx.isPresent()) {
|
||||
@ -3176,9 +3154,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
if (!expressions.stream().allMatch(UnboundSlot.class::isInstance)) {
|
||||
throw new ParseException("only column name is supported in except clause", selectCtx);
|
||||
}
|
||||
UnboundStar star = forCreateView ? new UnboundStar(ImmutableList.of(),
|
||||
Optional.of(Pair.of(selectCtx.start.getStartIndex(), selectCtx.stop.getStopIndex()))) :
|
||||
new UnboundStar(ImmutableList.of());
|
||||
UnboundStar star = new UnboundStar(ImmutableList.of());
|
||||
return new LogicalProject<>(ImmutableList.of(star), expressions, isDistinct, input);
|
||||
} else {
|
||||
List<NamedExpression> projects = getNamedExpressions(selectCtx.namedExpressionSeq());
|
||||
|
||||
@ -0,0 +1,209 @@
|
||||
// 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.parser;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.DorisParser;
|
||||
import org.apache.doris.nereids.DorisParser.AggClauseContext;
|
||||
import org.apache.doris.nereids.DorisParser.AliasQueryContext;
|
||||
import org.apache.doris.nereids.DorisParser.ColumnReferenceContext;
|
||||
import org.apache.doris.nereids.DorisParser.DereferenceContext;
|
||||
import org.apache.doris.nereids.DorisParser.GroupingElementContext;
|
||||
import org.apache.doris.nereids.DorisParser.HavingClauseContext;
|
||||
import org.apache.doris.nereids.DorisParser.IdentifierContext;
|
||||
import org.apache.doris.nereids.DorisParser.LateralViewContext;
|
||||
import org.apache.doris.nereids.DorisParser.MultipartIdentifierContext;
|
||||
import org.apache.doris.nereids.DorisParser.NamedExpressionContext;
|
||||
import org.apache.doris.nereids.DorisParser.SelectClauseContext;
|
||||
import org.apache.doris.nereids.DorisParser.SelectColumnClauseContext;
|
||||
import org.apache.doris.nereids.DorisParser.StarContext;
|
||||
import org.apache.doris.nereids.DorisParser.TableAliasContext;
|
||||
import org.apache.doris.nereids.DorisParser.TableNameContext;
|
||||
import org.apache.doris.nereids.DorisParser.WhereClauseContext;
|
||||
import org.apache.doris.nereids.analyzer.UnboundFunction;
|
||||
import org.apache.doris.nereids.analyzer.UnboundRelation;
|
||||
import org.apache.doris.nereids.analyzer.UnboundSlot;
|
||||
import org.apache.doris.nereids.analyzer.UnboundStar;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.NamedExpression;
|
||||
import org.apache.doris.nereids.trees.plans.Plan;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalHaving;
|
||||
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.util.Utils;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**LogicalPlanBuilderForCreateView*/
|
||||
public class LogicalPlanBuilderForCreateView extends LogicalPlanBuilder {
|
||||
@Override
|
||||
protected LogicalPlan withGenerate(LogicalPlan plan, LateralViewContext ctx) {
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
Pair.of(ctx.tableName.start.getStartIndex(),
|
||||
ctx.tableName.stop.getStopIndex()),
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(ctx.tableName.getText())));
|
||||
for (IdentifierContext colCtx : ctx.columnNames) {
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
Pair.of(colCtx.start.getStartIndex(),
|
||||
colCtx.stop.getStopIndex()),
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(colCtx.getText())));
|
||||
}
|
||||
return super.withGenerate(plan, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogicalSubQueryAlias<Plan> visitAliasQuery(AliasQueryContext ctx) {
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
Pair.of(ctx.identifier().start.getStartIndex(),
|
||||
ctx.identifier().stop.getStopIndex()),
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(ctx.identifier().getText())));
|
||||
if (ctx.columnAliases() != null) {
|
||||
for (IdentifierContext colCtx : ctx.columnAliases().identifier()) {
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
Pair.of(colCtx.start.getStartIndex(),
|
||||
colCtx.stop.getStopIndex()),
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(colCtx.getText())));
|
||||
}
|
||||
}
|
||||
return super.visitAliasQuery(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LogicalPlan withSelectQuerySpecification(
|
||||
ParserRuleContext ctx,
|
||||
LogicalPlan inputRelation,
|
||||
SelectClauseContext selectClause,
|
||||
Optional<WhereClauseContext> whereClause,
|
||||
Optional<AggClauseContext> aggClause,
|
||||
Optional<HavingClauseContext> havingClause) {
|
||||
LogicalPlan plan = super.withSelectQuerySpecification(ctx, inputRelation, selectClause, whereClause,
|
||||
aggClause, havingClause);
|
||||
SelectColumnClauseContext selectColumnCtx = selectClause.selectColumnClause();
|
||||
if ((!aggClause.isPresent() || isRepeat(aggClause.get())) && havingClause.isPresent()
|
||||
&& selectColumnCtx.EXCEPT() != null
|
||||
&& plan instanceof LogicalHaving && plan.child(0) instanceof LogicalProject) {
|
||||
LogicalHaving<LogicalProject<Plan>> having = (LogicalHaving) plan;
|
||||
LogicalProject<Plan> project = having.child();
|
||||
UnboundStar star = (UnboundStar) project.getProjects().get(0);
|
||||
star = star.withIndexInSql(Pair.of(selectColumnCtx.start.getStartIndex(),
|
||||
selectColumnCtx.stop.getStopIndex()));
|
||||
project = project.withProjects(ImmutableList.of(star));
|
||||
return (LogicalPlan) plan.withChildren(project);
|
||||
} else {
|
||||
return plan;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LogicalPlan withProjection(LogicalPlan input, SelectColumnClauseContext selectCtx,
|
||||
Optional<AggClauseContext> aggCtx, boolean isDistinct) {
|
||||
LogicalPlan plan = super.withProjection(input, selectCtx, aggCtx, isDistinct);
|
||||
if (!aggCtx.isPresent() && selectCtx.EXCEPT() != null && plan instanceof LogicalProject) {
|
||||
LogicalProject<Plan> project = (LogicalProject) plan;
|
||||
UnboundStar star = (UnboundStar) project.getProjects().get(0);
|
||||
star = star.withIndexInSql(Pair.of(selectCtx.start.getStartIndex(), selectCtx.stop.getStopIndex()));
|
||||
return project.withProjects(ImmutableList.of(star));
|
||||
} else {
|
||||
return plan;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LogicalPlan withTableAlias(LogicalPlan plan, TableAliasContext ctx) {
|
||||
if (ctx.strictIdentifier() == null) {
|
||||
return plan;
|
||||
}
|
||||
String alias = ctx.strictIdentifier().getText();
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
Pair.of(ctx.strictIdentifier().start.getStartIndex(),
|
||||
ctx.strictIdentifier().stop.getStopIndex()),
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(alias)));
|
||||
return super.withTableAlias(plan, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogicalPlan visitTableName(TableNameContext ctx) {
|
||||
LogicalPlan plan = super.visitTableName(ctx);
|
||||
MultipartIdentifierContext identifier = ctx.multipartIdentifier();
|
||||
return (LogicalPlan) plan.rewriteDownShortCircuit(node -> {
|
||||
if (node instanceof UnboundRelation) {
|
||||
UnboundRelation relation = (UnboundRelation) node;
|
||||
return relation.withIndexInSql(Pair.of(identifier.start.getStartIndex(),
|
||||
identifier.stop.getStopIndex()));
|
||||
}
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitStar(StarContext ctx) {
|
||||
Expression expr = super.visitStar(ctx);
|
||||
UnboundStar star = (UnboundStar) expr;
|
||||
return star.withIndexInSql(Pair.of(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedExpression visitNamedExpression(NamedExpressionContext ctx) {
|
||||
if (ctx.identifierOrText() != null) {
|
||||
String alias = visitIdentifierOrText(ctx.identifierOrText());
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
Pair.of(ctx.identifierOrText().start.getStartIndex(),
|
||||
ctx.identifierOrText().stop.getStopIndex()),
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(alias)));
|
||||
}
|
||||
return super.visitNamedExpression(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitFunctionCallExpression(DorisParser.FunctionCallExpressionContext ctx) {
|
||||
Expression expr = super.visitFunctionCallExpression(ctx);
|
||||
if (expr instanceof UnboundFunction) {
|
||||
UnboundFunction function = (UnboundFunction) expr;
|
||||
function = function.withIndexInSql(Pair.of(
|
||||
ctx.functionIdentifier().start.getStartIndex(),
|
||||
ctx.functionIdentifier().stop.getStopIndex()));
|
||||
return function;
|
||||
} else {
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitDereference(DereferenceContext ctx) {
|
||||
UnboundSlot slot = (UnboundSlot) super.visitDereference(ctx);
|
||||
return slot.withIndexInSql(Pair.of(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitColumnReference(ColumnReferenceContext ctx) {
|
||||
Expression expr = super.visitColumnReference(ctx);
|
||||
UnboundSlot slot = (UnboundSlot) expr;
|
||||
return slot.withIndexInSql(Pair.of(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
|
||||
}
|
||||
|
||||
private boolean isRepeat(AggClauseContext ctx) {
|
||||
GroupingElementContext groupingElementContext = ctx.groupingElement();
|
||||
return groupingElementContext.GROUPING() != null || groupingElementContext.CUBE() != null
|
||||
|| groupingElementContext.ROLLUP() != null;
|
||||
}
|
||||
}
|
||||
@ -278,15 +278,9 @@ public class NereidsParser {
|
||||
}
|
||||
|
||||
public LogicalPlan parseForCreateView(String sql) {
|
||||
return parseForCreateViewInternal(sql, null, DorisParser::singleStatement);
|
||||
}
|
||||
|
||||
private <T> T parseForCreateViewInternal(String sql, @Nullable LogicalPlanBuilder logicalPlanBuilder,
|
||||
Function<DorisParser, ParserRuleContext> parseFunction) {
|
||||
ParserRuleContext tree = toAst(sql, parseFunction);
|
||||
LogicalPlanBuilder realLogicalPlanBuilder = logicalPlanBuilder == null
|
||||
? new LogicalPlanBuilder(true) : logicalPlanBuilder;
|
||||
return (T) realLogicalPlanBuilder.visit(tree);
|
||||
ParserRuleContext tree = toAst(sql, DorisParser::singleStatement);
|
||||
LogicalPlanBuilder realLogicalPlanBuilder = new LogicalPlanBuilderForCreateView();
|
||||
return (LogicalPlan) realLogicalPlanBuilder.visit(tree);
|
||||
}
|
||||
|
||||
/** toAst */
|
||||
|
||||
@ -591,9 +591,9 @@ public class BindExpression implements AnalysisRuleFactory {
|
||||
// for create view stmt expand star
|
||||
List<Slot> slotsForLambda = slots;
|
||||
UnboundStar unboundStar = (UnboundStar) expression;
|
||||
unboundStar.getIndexInSqlString().ifPresent(pair ->
|
||||
statementContext.addIndexInSqlToString(pair, toSqlWithBackquote(slotsForLambda))
|
||||
);
|
||||
unboundStar.getIndexInSqlString().ifPresent(pair -> {
|
||||
statementContext.addIndexInSqlToString(pair, toSqlWithBackquote(slotsForLambda));
|
||||
});
|
||||
}
|
||||
}
|
||||
return project.withProjects(boundProjections.build());
|
||||
|
||||
@ -73,6 +73,7 @@ import org.apache.doris.nereids.trees.expressions.functions.scalar.Nvl;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.udf.AliasUdfBuilder;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.udf.JavaUdaf;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.udf.JavaUdf;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.udf.UdfBuilder;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.Literal;
|
||||
@ -378,7 +379,8 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext
|
||||
.build()
|
||||
: (List) unboundFunction.getArguments();
|
||||
|
||||
if (StringUtils.isEmpty(unboundFunction.getDbName())) {
|
||||
String dbName = unboundFunction.getDbName();
|
||||
if (StringUtils.isEmpty(dbName)) {
|
||||
// we will change arithmetic function like add(), subtract(), bitnot()
|
||||
// to the corresponding objects rather than BoundFunction.
|
||||
ArithmeticFunctionBinder functionBinder = new ArithmeticFunctionBinder();
|
||||
@ -390,7 +392,16 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext
|
||||
|
||||
String functionName = unboundFunction.getName();
|
||||
FunctionBuilder builder = functionRegistry.findFunctionBuilder(
|
||||
unboundFunction.getDbName(), functionName, arguments);
|
||||
dbName, functionName, arguments);
|
||||
// for create view stmt
|
||||
if (builder instanceof UdfBuilder) {
|
||||
unboundFunction.getIndexInSqlString().ifPresent(index -> {
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(index,
|
||||
Utils.qualifiedNameWithBackquote(ImmutableList.of(null == dbName
|
||||
? ConnectContext.get().getDatabase() : dbName, functionName)));
|
||||
});
|
||||
}
|
||||
|
||||
Pair<? extends Expression, ? extends BoundFunction> buildResult = builder.build(functionName, arguments);
|
||||
Optional<SqlCacheContext> sqlCacheContext = Optional.empty();
|
||||
if (wantToParseSqlFromSqlCache) {
|
||||
@ -716,27 +727,40 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext
|
||||
return !extractSlots.isEmpty() ? extractSlots : candidates;
|
||||
}
|
||||
|
||||
private List<Slot> addSqlIndexInfo(List<Slot> slots, Optional<Pair<Integer, Integer>> indexInSql) {
|
||||
if (!indexInSql.isPresent()) {
|
||||
return slots;
|
||||
}
|
||||
List<Slot> newSlots = new ArrayList<>();
|
||||
for (Slot slot : slots) {
|
||||
newSlots.add(slot.withIndexInSql(indexInSql.get()));
|
||||
}
|
||||
return newSlots;
|
||||
}
|
||||
|
||||
/** bindSlotByScope */
|
||||
public List<Slot> bindSlotByScope(UnboundSlot unboundSlot, Scope scope) {
|
||||
List<String> nameParts = unboundSlot.getNameParts();
|
||||
Optional<Pair<Integer, Integer>> idxInSql = unboundSlot.getIndexInSqlString();
|
||||
int namePartSize = nameParts.size();
|
||||
switch (namePartSize) {
|
||||
// column
|
||||
case 1: {
|
||||
return bindSingleSlotByName(nameParts.get(0), scope);
|
||||
return addSqlIndexInfo(bindSingleSlotByName(nameParts.get(0), scope), idxInSql);
|
||||
}
|
||||
// table.column
|
||||
case 2: {
|
||||
return bindSingleSlotByTable(nameParts.get(0), nameParts.get(1), scope);
|
||||
return addSqlIndexInfo(bindSingleSlotByTable(nameParts.get(0), nameParts.get(1), scope), idxInSql);
|
||||
}
|
||||
// db.table.column
|
||||
case 3: {
|
||||
return bindSingleSlotByDb(nameParts.get(0), nameParts.get(1), nameParts.get(2), scope);
|
||||
return addSqlIndexInfo(bindSingleSlotByDb(nameParts.get(0), nameParts.get(1), nameParts.get(2), scope),
|
||||
idxInSql);
|
||||
}
|
||||
// catalog.db.table.column
|
||||
case 4: {
|
||||
return bindSingleSlotByCatalog(
|
||||
nameParts.get(0), nameParts.get(1), nameParts.get(2), nameParts.get(3), scope);
|
||||
return addSqlIndexInfo(bindSingleSlotByCatalog(
|
||||
nameParts.get(0), nameParts.get(1), nameParts.get(2), nameParts.get(3), scope), idxInSql);
|
||||
}
|
||||
default: {
|
||||
throw new AnalysisException("Not supported name: " + StringUtils.join(nameParts, "."));
|
||||
|
||||
@ -95,7 +95,7 @@ public class Alias extends NamedExpression implements UnaryExpression {
|
||||
internalName,
|
||||
slotReference != null
|
||||
? slotReference.getSubPath()
|
||||
: ImmutableList.of()
|
||||
: ImmutableList.of(), Optional.empty()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.trees.expressions.typecoercion.ExpectsInputTypes;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.ArrayType;
|
||||
@ -161,6 +162,11 @@ public class ArrayItemReference extends NamedExpression implements ExpectsInputT
|
||||
return new ArrayItemSlot(exprId, name.get(), dataType, nullable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
|
||||
return visitor.visitArrayItemSlot(this, context);
|
||||
|
||||
@ -17,18 +17,21 @@
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.exceptions.UnboundException;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.DataType;
|
||||
import org.apache.doris.nereids.types.NullType;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* only use for insert into t values(DEFAULT, ...)
|
||||
*/
|
||||
public class DefaultValueSlot extends Slot {
|
||||
|
||||
public DefaultValueSlot() {
|
||||
super();
|
||||
super(Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,4 +63,8 @@ public class DefaultValueSlot extends Slot {
|
||||
public String toString() {
|
||||
return "DEFAULT_VALUE";
|
||||
}
|
||||
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.BooleanType;
|
||||
|
||||
@ -78,4 +79,9 @@ public class MarkJoinSlotReference extends SlotReference {
|
||||
public SlotReference withName(String name) {
|
||||
return new MarkJoinSlotReference(exprId, name, existsHasAgg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,19 +17,25 @@
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Abstract class for all slot in expression.
|
||||
*/
|
||||
public abstract class Slot extends NamedExpression implements LeafExpression {
|
||||
// for create view, the start and end position of the sql substring
|
||||
// (e.g. "col1", "t1.col1", "db1.t1.col1", "ctl1.db1.t1.col1")
|
||||
protected final Optional<Pair<Integer, Integer>> indexInSqlString;
|
||||
|
||||
protected Slot() {
|
||||
protected Slot(Optional<Pair<Integer, Integer>> indexInSqlString) {
|
||||
super(ImmutableList.of());
|
||||
this.indexInSqlString = indexInSqlString;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,4 +62,12 @@ public abstract class Slot extends NamedExpression implements LeafExpression {
|
||||
public String getInternalName() {
|
||||
throw new RuntimeException("Do not implement");
|
||||
}
|
||||
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
throw new RuntimeException("Do not implement");
|
||||
}
|
||||
|
||||
public Optional<Pair<Integer, Integer>> getIndexInSqlString() {
|
||||
return indexInSqlString;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
import org.apache.doris.catalog.Column;
|
||||
import org.apache.doris.catalog.TableIf;
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.exceptions.UnboundException;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.types.DataType;
|
||||
@ -89,7 +90,7 @@ public class SlotReference extends Slot {
|
||||
List<String> qualifier, @Nullable TableIf table, @Nullable Column column,
|
||||
Optional<String> internalName, List<String> subColLabels) {
|
||||
this(exprId, () -> name, dataType, nullable, qualifier, table, column,
|
||||
buildInternalName(() -> name, subColLabels, internalName), subColLabels);
|
||||
buildInternalName(() -> name, subColLabels, internalName), subColLabels, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +107,9 @@ public class SlotReference extends Slot {
|
||||
*/
|
||||
public SlotReference(ExprId exprId, Supplier<String> name, DataType dataType, boolean nullable,
|
||||
List<String> qualifier, @Nullable TableIf table, @Nullable Column column,
|
||||
Supplier<Optional<String>> internalName, List<String> subPath) {
|
||||
Supplier<Optional<String>> internalName, List<String> subPath,
|
||||
Optional<Pair<Integer, Integer>> indexInSql) {
|
||||
super(indexInSql);
|
||||
this.exprId = exprId;
|
||||
this.name = name;
|
||||
this.dataType = dataType;
|
||||
@ -132,7 +135,7 @@ public class SlotReference extends Slot {
|
||||
DataType dataType = DataType.fromCatalogType(column.getType());
|
||||
return new SlotReference(StatementScopeIdGenerator.newExprId(), column::getName, dataType,
|
||||
column.isAllowNull(), qualifier, table, column,
|
||||
() -> Optional.of(column.getName()), ImmutableList.of());
|
||||
() -> Optional.of(column.getName()), ImmutableList.of(), Optional.empty());
|
||||
}
|
||||
|
||||
public static SlotReference fromColumn(TableIf table, Column column, String name, List<String> qualifier) {
|
||||
@ -250,13 +253,15 @@ public class SlotReference extends Slot {
|
||||
if (this.nullable == newNullable) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return new SlotReference(exprId, name, dataType, newNullable,
|
||||
qualifier, table, column, internalName, subPath);
|
||||
qualifier, table, column, internalName, subPath, indexInSqlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotReference withQualifier(List<String> qualifier) {
|
||||
return new SlotReference(exprId, name, dataType, nullable, qualifier, table, column, internalName, subPath);
|
||||
return new SlotReference(exprId, name, dataType, nullable, qualifier, table, column, internalName, subPath,
|
||||
indexInSqlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -265,17 +270,25 @@ public class SlotReference extends Slot {
|
||||
return this;
|
||||
}
|
||||
return new SlotReference(
|
||||
exprId, () -> name, dataType, nullable, qualifier, table, column, internalName, subPath);
|
||||
exprId, () -> name, dataType, nullable, qualifier, table, column, internalName, subPath,
|
||||
indexInSqlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotReference withExprId(ExprId exprId) {
|
||||
return new SlotReference(exprId, name, dataType, nullable, qualifier, table, column, internalName, subPath);
|
||||
return new SlotReference(exprId, name, dataType, nullable, qualifier, table, column, internalName, subPath,
|
||||
indexInSqlString);
|
||||
}
|
||||
|
||||
public SlotReference withSubPath(List<String> subPath) {
|
||||
return new SlotReference(exprId, name, dataType, !subPath.isEmpty() || nullable,
|
||||
qualifier, table, column, internalName, subPath);
|
||||
qualifier, table, column, internalName, subPath, indexInSqlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return new SlotReference(exprId, name, dataType, nullable, qualifier, table, column, internalName, subPath,
|
||||
Optional.ofNullable(index));
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.nereids.trees.expressions;
|
||||
|
||||
import org.apache.doris.common.Pair;
|
||||
import org.apache.doris.nereids.trees.expressions.functions.scalar.GroupingScalarFunction;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
|
||||
import org.apache.doris.nereids.trees.plans.algebra.Repeat.GroupingSetShapes;
|
||||
@ -145,4 +146,9 @@ public class VirtualSlotReference extends SlotReference implements SlotNotFromCh
|
||||
return new VirtualSlotReference(exprId, name.get(), dataType, nullable, qualifier,
|
||||
originExpression, computeLongValueMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slot withIndexInSql(Pair<Integer, Integer> index) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,12 +33,9 @@ import org.apache.doris.common.util.Util;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.nereids.NereidsPlanner;
|
||||
import org.apache.doris.nereids.analyzer.UnboundResultSink;
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.nereids.properties.PhysicalProperties;
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalFileSink;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@ -50,12 +47,9 @@ import java.util.Set;
|
||||
/** AlterViewInfo */
|
||||
public class AlterViewInfo extends BaseViewInfo {
|
||||
/** constructor*/
|
||||
public AlterViewInfo(TableNameInfo viewName, LogicalPlan logicalQuery,
|
||||
public AlterViewInfo(TableNameInfo viewName,
|
||||
String querySql, List<SimpleColumnDefinition> simpleColumnDefinitions) {
|
||||
super(viewName, logicalQuery, querySql, simpleColumnDefinitions);
|
||||
if (logicalQuery instanceof LogicalFileSink) {
|
||||
throw new AnalysisException("Not support OUTFILE clause in ALTER VIEW statement");
|
||||
}
|
||||
super(viewName, querySql, simpleColumnDefinitions);
|
||||
}
|
||||
|
||||
/** init */
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
package org.apache.doris.nereids.trees.plans.commands.info;
|
||||
|
||||
import org.apache.doris.catalog.Column;
|
||||
import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.common.Pair;
|
||||
@ -31,18 +32,35 @@ import org.apache.doris.nereids.analyzer.UnboundResultSink;
|
||||
import org.apache.doris.nereids.jobs.executor.AbstractBatchJobExecutor;
|
||||
import org.apache.doris.nereids.jobs.rewrite.RewriteJob;
|
||||
import org.apache.doris.nereids.parser.NereidsParser;
|
||||
import org.apache.doris.nereids.properties.OrderKey;
|
||||
import org.apache.doris.nereids.properties.PhysicalProperties;
|
||||
import org.apache.doris.nereids.rules.analysis.AnalyzeCTE;
|
||||
import org.apache.doris.nereids.rules.analysis.BindExpression;
|
||||
import org.apache.doris.nereids.rules.analysis.BindRelation;
|
||||
import org.apache.doris.nereids.rules.analysis.CheckPolicy;
|
||||
import org.apache.doris.nereids.rules.analysis.EliminateLogicalSelectHint;
|
||||
import org.apache.doris.nereids.trees.expressions.Expression;
|
||||
import org.apache.doris.nereids.trees.expressions.NamedExpression;
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionVisitor;
|
||||
import org.apache.doris.nereids.trees.plans.Plan;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalCTEAnchor;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalCTEProducer;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalFileSink;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalGenerate;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalHaving;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
|
||||
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.LogicalRepeat;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalTopN;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalView;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
|
||||
import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
|
||||
import org.apache.doris.nereids.util.Utils;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@ -53,27 +71,31 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/** BaseViewInfo */
|
||||
public class BaseViewInfo {
|
||||
protected final TableNameInfo viewName;
|
||||
protected final LogicalPlan logicalQuery;
|
||||
protected LogicalPlan logicalQuery;
|
||||
protected final String querySql;
|
||||
protected final List<SimpleColumnDefinition> simpleColumnDefinitions;
|
||||
protected final List<Column> finalCols = Lists.newArrayList();
|
||||
protected Plan analyzedPlan;
|
||||
|
||||
public BaseViewInfo(TableNameInfo viewName, LogicalPlan logicalQuery,
|
||||
public BaseViewInfo(TableNameInfo viewName,
|
||||
String querySql, List<SimpleColumnDefinition> simpleColumnDefinitions) {
|
||||
this.viewName = viewName;
|
||||
this.logicalQuery = logicalQuery;
|
||||
this.querySql = querySql;
|
||||
this.simpleColumnDefinitions = simpleColumnDefinitions;
|
||||
}
|
||||
|
||||
protected void analyzeAndFillRewriteSqlMap(String sql, ConnectContext ctx) {
|
||||
protected void analyzeAndFillRewriteSqlMap(String sql, ConnectContext ctx) throws AnalysisException {
|
||||
StatementContext stmtCtx = ctx.getStatementContext();
|
||||
LogicalPlan parsedViewPlan = new NereidsParser().parseForCreateView(sql);
|
||||
logicalQuery = parsedViewPlan;
|
||||
if (logicalQuery instanceof LogicalFileSink) {
|
||||
throw new AnalysisException("Not support OUTFILE clause in CREATE VIEW statement");
|
||||
}
|
||||
if (parsedViewPlan instanceof UnboundResultSink) {
|
||||
parsedViewPlan = (LogicalPlan) ((UnboundResultSink<?>) parsedViewPlan).child();
|
||||
}
|
||||
@ -82,9 +104,12 @@ public class BaseViewInfo {
|
||||
AnalyzerForCreateView analyzerForStar = new AnalyzerForCreateView(viewContextForStar);
|
||||
analyzerForStar.analyze();
|
||||
analyzedPlan = viewContextForStar.getRewritePlan();
|
||||
// Traverse all slots in the plan, and add the slot's location information
|
||||
// and the fully qualified replacement string to the indexInSqlToString of the StatementContext.
|
||||
analyzedPlan.accept(PlanSlotFinder.INSTANCE, ctx.getStatementContext());
|
||||
}
|
||||
|
||||
protected String rewriteSql(Map<Pair<Integer, Integer>, String> indexStringSqlMap) {
|
||||
protected String rewriteSql(TreeMap<Pair<Integer, Integer>, String> indexStringSqlMap) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int beg = 0;
|
||||
for (Map.Entry<Pair<Integer, Integer>, String> entry : indexStringSqlMap.entrySet()) {
|
||||
@ -258,4 +283,117 @@ public class BaseViewInfo {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PlanSlotFinder extends DefaultPlanVisitor<Void, StatementContext> {
|
||||
private static PlanSlotFinder INSTANCE = new PlanSlotFinder();
|
||||
|
||||
@Override
|
||||
public Void visitLogicalView(LogicalView<? extends Plan> alias, StatementContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalAggregate(LogicalAggregate<? extends Plan> aggregate, StatementContext context) {
|
||||
for (Expression expr : aggregate.getGroupByExpressions()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
for (NamedExpression expr : aggregate.getOutputExpressions()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return aggregate.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalFilter(LogicalFilter<? extends Plan> filter, StatementContext context) {
|
||||
for (Expression expr : filter.getConjuncts()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return filter.child().accept(this, context);
|
||||
}
|
||||
|
||||
public Void visitLogicalGenerate(LogicalGenerate<? extends Plan> generate, StatementContext context) {
|
||||
for (Expression expr : generate.getGenerators()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return generate.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalHaving(LogicalHaving<? extends Plan> having, StatementContext context) {
|
||||
for (Expression expr : having.getConjuncts()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return having.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalJoin(LogicalJoin<? extends Plan, ? extends Plan> join, StatementContext context) {
|
||||
for (Expression expr : join.getOtherJoinConjuncts()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
for (Expression expr : join.getHashJoinConjuncts()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
join.child(0).accept(this, context);
|
||||
return join.child(1).accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalProject(LogicalProject<? extends Plan> project, StatementContext context) {
|
||||
for (Expression expr : project.getProjects()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return project.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalRepeat(LogicalRepeat<? extends Plan> repeat, StatementContext context) {
|
||||
for (Expression expr : repeat.getOutputExpressions()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
for (List<Expression> exprs : repeat.getGroupingSets()) {
|
||||
for (Expression expr : exprs) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
}
|
||||
return repeat.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalSort(LogicalSort<? extends Plan> sort, StatementContext context) {
|
||||
for (OrderKey key : sort.getOrderKeys()) {
|
||||
key.getExpr().accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return sort.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalTopN(LogicalTopN<? extends Plan> topN, StatementContext context) {
|
||||
for (OrderKey key : topN.getOrderKeys()) {
|
||||
key.getExpr().accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return topN.child().accept(this, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitLogicalWindow(LogicalWindow<? extends Plan> window, StatementContext context) {
|
||||
for (Expression expr : window.getWindowExpressions()) {
|
||||
expr.accept(SlotDealer.INSTANCE, context);
|
||||
}
|
||||
return window.child().accept(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SlotDealer extends DefaultExpressionVisitor<Void, StatementContext> {
|
||||
private static final SlotDealer INSTANCE = new SlotDealer();
|
||||
|
||||
@Override
|
||||
public Void visitSlot(Slot slot, StatementContext ctx) {
|
||||
slot.getIndexInSqlString().ifPresent(index ->
|
||||
ctx.addIndexInSqlToString(index,
|
||||
Utils.qualifiedNameWithBackquote(slot.getQualifier(), slot.getName()))
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,12 +30,9 @@ import org.apache.doris.common.util.Util;
|
||||
import org.apache.doris.mysql.privilege.PrivPredicate;
|
||||
import org.apache.doris.nereids.NereidsPlanner;
|
||||
import org.apache.doris.nereids.analyzer.UnboundResultSink;
|
||||
import org.apache.doris.nereids.exceptions.AnalysisException;
|
||||
import org.apache.doris.nereids.properties.PhysicalProperties;
|
||||
import org.apache.doris.nereids.trees.expressions.Slot;
|
||||
import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalFileSink;
|
||||
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@ -52,14 +49,11 @@ public class CreateViewInfo extends BaseViewInfo {
|
||||
private final String comment;
|
||||
|
||||
/** constructor*/
|
||||
public CreateViewInfo(boolean ifNotExists, TableNameInfo viewName, String comment, LogicalPlan logicalQuery,
|
||||
public CreateViewInfo(boolean ifNotExists, TableNameInfo viewName, String comment,
|
||||
String querySql, List<SimpleColumnDefinition> simpleColumnDefinitions) {
|
||||
super(viewName, logicalQuery, querySql, simpleColumnDefinitions);
|
||||
super(viewName, querySql, simpleColumnDefinitions);
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.comment = comment;
|
||||
if (logicalQuery instanceof LogicalFileSink) {
|
||||
throw new AnalysisException("Not support OUTFILE clause in CREATE VIEW statement");
|
||||
}
|
||||
}
|
||||
|
||||
/** init */
|
||||
|
||||
Reference in New Issue
Block a user