[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:
feiniaofeiafei
2024-07-19 00:56:26 +08:00
committed by GitHub
parent 5d17ff9d95
commit 301ff6af22
28 changed files with 793 additions and 113 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, "."));

View File

@ -95,7 +95,7 @@ public class Alias extends NamedExpression implements UnaryExpression {
internalName,
slotReference != null
? slotReference.getSubPath()
: ImmutableList.of()
: ImmutableList.of(), Optional.empty()
);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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